C++程序  |  2042行  |  79.29 KB

/*
 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
 * Copyright (c) Imagination Technologies Limited, UK
 *
 * 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, sub license, 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 (including the
 * next paragraph) 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 NON-INFRINGEMENT.
 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
 *
 * Authors:
 *    Elaine Wang <elaine.wang@intel.com>
 *    Zeng Li <zeng.li@intel.com>
 *
 */


#include "psb_drv_video.h"

//#include "pnw_H263ES.h"
#include "pnw_hostcode.h"
#include "hwdefs/topazSC_defs.h"
#include "psb_def.h"
#include "psb_drv_debug.h"
#include "psb_cmdbuf.h"
#include <stdio.h>
#include "psb_output.h"
#include <wsbm/wsbm_manager.h>
#include "pnw_hostheader.h"

#define ALIGN_TO(value, align) ((value + align - 1) & ~(align - 1))
#define PAGE_ALIGN(value) ALIGN_TO(value, 4096)

/*static VAStatus pnw_DetectFrameSkip(context_ENC_p ctx);*/

static void pnw__update_rcdata(
    context_ENC_p psContext,
    PIC_PARAMS *psPicParams,
    IMG_RC_PARAMS *psRCParams);

IMG_UINT32 MVEARegBase[4] = {0x13000, 0x23000, 0x33000, 0x43000}; /* From TopazSC TRM */

/* H264 Zero bias */
//#define ZERO_BIAS

static const IMG_INT8 H263_QPLAMBDA_MAP[31] = {
    0, 0, 1, 1, 2,
    2, 3, 3, 4, 4,
    4, 5, 5, 5, 6,
    6, 6, 7, 7, 7,
    7, 8, 8, 8, 8,
    9, 9, 9, 9, 10, 10
};

// New MP4 Lambda table
static const  IMG_INT8 MPEG4_QPLAMBDA_MAP[31] = {
    0,  0,  1,  2,  3,
    3,  4,  4,  5,  5,
    6,  6,  7,  7,  8,
    8,  9,  9,  10, 10,
    11, 11, 11, 11, 12,
    12, 12, 12, 13, 13, 13
};

// new H.264 Lambda
static const IMG_INT8 H264_QPLAMBDA_MAP[40] = {
    2, 2, 2, 2, 3, 3, 4, 4,
    4, 5, 5, 5, 5, 5, 6, 6,
    6, 7, 7, 7, 8, 8, 9, 11,
    13, 14, 15, 17, 20, 23, 27, 31,
    36, 41, 51, 62, 74, 79, 85, 91
};

static const IMG_INT16 H264_InterIntraBias[27] =
{
    20,20,20,20,20,20,50,
    20,20,20,20,20,20,
    20,25,30,45,80,140,
    200,300,400,500,550,
    600,650,700
};

/*static IMG_INT16 H264InterBias(IMG_INT8 i8QP)
{
    if (i8QP >= 44)
        return 600;
    else if (i8QP <= 35)
        return 20;

    return (70 * (i8QP - 35));
}*/
static IMG_INT16 H264InterBias(IMG_INT8 i8QP)
{
    if (i8QP > 1)
         i8QP = 1;
    else if (i8QP > 51)
        return 51;

    return H264_InterIntraBias[(i8QP + 1)>>1];
}


static IMG_INT16 H264SkipBias(IMG_INT8 i8QP, TH_SKIP_SCALE eSkipScale)
{
    IMG_INT16 i16Lambda;

    // pull out lambda from the table
    i16Lambda = i8QP - 12;
    i16Lambda = (i16Lambda < 0) ? 0 : i16Lambda;
    i16Lambda = H264_QPLAMBDA_MAP[i16Lambda];

    // now do the multiplication to avoid using the actual multiply we will do this with shifts and adds/subtractions it is probable that the compiler would
    // pick up the multiply and optimise appropriatly but we aren't sure
    // * 12 = 8 + *4
    switch (eSkipScale) {
    default:
    case TH_SKIP_0:
        i16Lambda = 0;
        break;
    case TH_SKIP_24:                /* iLambda * 24 == iLambda * 2 * 12   */
        i16Lambda <<= 1;
        /* break deliberatly not used as we want to apply skip12 to skip24*/
    case TH_SKIP_12: /*    iLambda * 12 == iLambda * (8 + 4) == (iLambda * 8) + (iLambda * 4)  == (iLambda << 3) + (iLambda <<2)   */
        i16Lambda = (i16Lambda << 3) + (i16Lambda << 2);
    }
    return i16Lambda;
}

static IMG_INT16 H264Intra4x4Bias(IMG_INT8 i8QP)
{
    IMG_INT16 i16Lambda;

    // pull out lambda from the table
    i16Lambda = i8QP - 12;
    i16Lambda = (i16Lambda < 0) ? 0 : i16Lambda;
    i16Lambda = H264_QPLAMBDA_MAP[i16Lambda];

    i16Lambda *= 120;
    return i16Lambda;
}

static int CalculateDCScaler(IMG_INT iQP, IMG_BOOL bChroma)
{
    IMG_INT     iDCScaler;
    if (!bChroma) {
        if (iQP > 0 && iQP < 5) {
            iDCScaler = 8;
        } else if (iQP > 4 &&     iQP     < 9) {
            iDCScaler = 2 * iQP;
        } else if (iQP > 8 &&     iQP     < 25) {
            iDCScaler = iQP + 8;
        } else {
            iDCScaler = 2 * iQP - 16;
        }
    } else {
        if (iQP > 0 && iQP < 5) {
            iDCScaler = 8;
        } else if (iQP > 4 &&     iQP     < 25) {
            iDCScaler = (iQP + 13) / 2;
        } else {
            iDCScaler = iQP - 6;
        }
    }
    return iDCScaler;
}

static void LoadMPEG4Bias(
    pnw_cmdbuf_p cmdbuf,
    IMG_INT32 i32Core,
    IMG_UINT8 __maybe_unused ui8THSkip
)
{
    IMG_INT16 n;
    IMG_INT16 iX;
    IMG_UINT32 ui32RegVal;
    IMG_UINT8                       uiDCScaleL, uiDCScaleC, uiLambda;
    IMG_INT32 uIPESkipVecBias, iInterMBBias, uSPESkipVecBias, iIntra16Bias;
    IMG_UINT32 count = 0, cmd_word = 0;
    uint32_t *pCount;

    cmd_word = ((MTX_CMDID_SW_WRITEREG & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) |
               ((i32Core & MTX_CMDWORD_CORE_MASK) <<  MTX_CMDWORD_CORE_SHIFT);
    *cmdbuf->cmd_idx++ = cmd_word;
    pCount = cmdbuf->cmd_idx;
    cmdbuf->cmd_idx++;

    // this should be done for each core....
    pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_ZERO_THRESH, SPE_ZERO_THRESHOLD);
    for (n = 31; n > 0; n--) {
        iX = n - 12;
        if (iX < 0) {
            iX = 0;
        }
        // Dont Write QP Values To ESB -- IPE will write these values
        // Update the quantization parameter which includes doing Lamda and the Chroma QP

        uiDCScaleL      = CalculateDCScaler(n, IMG_FALSE);
        uiDCScaleC      = CalculateDCScaler(n, IMG_TRUE);
        uiLambda        = MPEG4_QPLAMBDA_MAP[n - 1];

        ui32RegVal = uiDCScaleL;
        ui32RegVal |= (uiDCScaleC) << 8;
        ui32RegVal |= (uiLambda) << 16;
        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_LAMBDA_TABLE, ui32RegVal);


        uIPESkipVecBias = TH_SKIP_IPE * uiLambda;
        iInterMBBias            = TH_INTER * (n - TH_INTER_QP);
        if (iInterMBBias < 0)
            iInterMBBias    = 0;
        if (iInterMBBias > TH_INTER_MAX_LEVEL)
            iInterMBBias    = TH_INTER_MAX_LEVEL;
        uSPESkipVecBias = TH_SKIP_SPE * uiLambda;
        iIntra16Bias = 0;

        if (n & 1) {
            pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_MV_BIAS_TABLE, uIPESkipVecBias);
            pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_PRED_VECTOR_BIAS_TABLE, uIPESkipVecBias);
            pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTRA16_BIAS_TABLE, iIntra16Bias);
            pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTER_BIAS_TABLE, iInterMBBias);
        }
    }
    *pCount = count;
}

static void LoadH263Bias(
    pnw_cmdbuf_p cmdbuf, IMG_INT32 i32Core, IMG_UINT8 __maybe_unused ui8THSkip)
{
    IMG_INT16 n;
    IMG_INT16 iX;
    IMG_UINT32 ui32RegVal;
    IMG_UINT8                       uiDCScaleL, uiDCScaleC, uiLambda;
    IMG_INT32 uIPESkipVecBias, iInterMBBias, uSPESkipVecBias, iIntra16Bias;
    IMG_UINT32 count = 0, cmd_word = 0;
    uint32_t *pCount;

    cmd_word = ((MTX_CMDID_SW_WRITEREG & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) |
               ((i32Core & MTX_CMDWORD_CORE_MASK) <<  MTX_CMDWORD_CORE_SHIFT);
    *cmdbuf->cmd_idx++ = cmd_word;
    pCount = cmdbuf->cmd_idx;
    cmdbuf->cmd_idx++;


    // this should be done for each core....
    pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_ZERO_THRESH, SPE_ZERO_THRESHOLD);
    for (n = 31; n > 0; n--) {
        iX = n - 12;
        if (iX < 0) {
            iX = 0;
        }
        // Dont Write QP Values To ESB -- IPE will write these values
        // Update the quantization parameter which includes doing Lamda and the Chroma QP

        uiDCScaleL      = CalculateDCScaler(n, IMG_FALSE);
        uiDCScaleC      = CalculateDCScaler(n, IMG_TRUE);
        uiLambda        = H263_QPLAMBDA_MAP[n - 1];

        ui32RegVal = uiDCScaleL;
        ui32RegVal |= (uiDCScaleC) << 8;
        ui32RegVal |= (uiLambda) << 16;

        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_LAMBDA_TABLE, ui32RegVal);


        uIPESkipVecBias = TH_SKIP_IPE * uiLambda;
        iInterMBBias            = TH_INTER * (n - TH_INTER_QP);
        if (iInterMBBias < 0)
            iInterMBBias    = 0;
        if (iInterMBBias > TH_INTER_MAX_LEVEL)
            iInterMBBias    = TH_INTER_MAX_LEVEL;
        uSPESkipVecBias = TH_SKIP_SPE * uiLambda;
        iIntra16Bias = 0;
        //
        if (n & 1) {
            pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_MV_BIAS_TABLE, uIPESkipVecBias);
            pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_PRED_VECTOR_BIAS_TABLE, uIPESkipVecBias);
            pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTRA16_BIAS_TABLE, iIntra16Bias);
            pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTER_BIAS_TABLE, iInterMBBias);
        }
    }
    *pCount = count;
}

static void LoadH264Bias(
    pnw_cmdbuf_p cmdbuf, IMG_INT32 i32Core, IMG_UINT8 ui8THSkip, IMG_INT8 i8QpOff)
{
    IMG_INT8 n;
    IMG_INT8 iX;
    IMG_UINT32 ui32RegVal;
    IMG_UINT32 uIPESkipVecBias, iInterMBBias, uSPESkipVecBias, iIntra16Bias;
    IMG_UINT32 count = 0, cmd_word = 0;
    uint32_t *pCount;

    cmd_word = ((MTX_CMDID_SW_WRITEREG & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) |
               ((i32Core & MTX_CMDWORD_CORE_MASK) <<  MTX_CMDWORD_CORE_SHIFT);
    *cmdbuf->cmd_idx++ = cmd_word;
    pCount = cmdbuf->cmd_idx;
    cmdbuf->cmd_idx++;


    IMG_BYTE PVR_QP_SCALE_CR[76] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
        12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
        28, 29, 29, 30, 31, 32, 32, 33, 34, 34, 35, 35, 36, 36, 37, 37,
        37, 38, 38, 38, 39, 39, 39, 39,
        39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
    };

    for (n = 51; n >= 0; n--) {

        iX = n - 12;
        if (iX < 0)
            iX = 0;

        // Dont Write QP Values To ESB -- IPE will write these values
        // Update the quantization parameter which includes doing Lamda and the Chroma QP
        ui32RegVal = PVR_QP_SCALE_CR[n + 12 + i8QpOff ];
        ui32RegVal |= ((H264_QPLAMBDA_MAP[iX] * 24) / 16) << 8;
        ui32RegVal |= (H264_QPLAMBDA_MAP[iX]) << 16;

#ifdef ZERO_BIAS
        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_LAMBDA_TABLE, (2 << 16) | F_ENCODE(3, MVEA_CR_IPE_ALPHA_OR_DC_SCALE_CHR_TABLE) | F_ENCODE(PVR_QP_SCALE_CR[n], MVEA_CR_IPE_QPC_OR_DC_SCALE_LUMA_TABLE));
#else
        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_LAMBDA_TABLE, ui32RegVal);
#endif

    }
    for (n = 52; n >= 0; n -= 2) {
        IMG_INT8 qp = n;
        if (qp > 51) qp = 51;

        uIPESkipVecBias = H264SkipBias(qp, ui8THSkip);
        iInterMBBias    = H264InterBias(qp);
        uSPESkipVecBias = H264SkipBias(qp, ui8THSkip);
        iIntra16Bias    = H264Intra4x4Bias(qp);

#ifdef ZERO_BIAS
        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_MV_BIAS_TABLE, 0);
        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_PRED_VECTOR_BIAS_TABLE, 0);
        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTRA16_BIAS_TABLE, 0);
        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTER_BIAS_TABLE, 0);
#else
        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_MV_BIAS_TABLE, uIPESkipVecBias);
        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_PRED_VECTOR_BIAS_TABLE, uIPESkipVecBias);
        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTRA16_BIAS_TABLE, iIntra16Bias);
        pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTER_BIAS_TABLE, iInterMBBias);
#endif

    }

    pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_ZERO_THRESH, 0);
    *pCount = count;
}


static VAStatus pnw__alloc_context_buffer(context_ENC_p ctx, unsigned char is_JPEG)
{
    int width, height;
    VAStatus vaStatus = VA_STATUS_SUCCESS;

    /* width and height should be source surface's w and h or ?? */
    width = ctx->obj_context->picture_width;
    height = ctx->obj_context->picture_height;

    if (is_JPEG == 0) {
        ctx->pic_params_size  = 256;

        ctx->header_buffer_size = 8 * HEADER_SIZE + MAX_SLICES_PER_PICTURE * HEADER_SIZE;

        ctx->seq_header_ofs = 0;
        ctx->pic_header_ofs = HEADER_SIZE;
        ctx->eoseq_header_ofs = 2 * HEADER_SIZE;
        ctx->eostream_header_ofs = 3 * HEADER_SIZE;
        ctx->aud_header_ofs = 4 * HEADER_SIZE;
        ctx->sei_buf_prd_ofs = 5 * HEADER_SIZE;
        ctx->sei_pic_tm_ofs = 6 * HEADER_SIZE;
        ctx->sei_pic_fpa_ofs = 7 * HEADER_SIZE;
        ctx->slice_header_ofs = 8 * HEADER_SIZE;
        ctx->in_params_ofs = 0;

        ctx->sliceparam_buffer_size = ((sizeof(SLICE_PARAMS) + 15) & 0xfff0) * MAX_SLICES_PER_PICTURE;
        /* All frame share same MTX_CURRENT_IN_PARAMS and above/bellow param
         * create MTX_CURRENT_IN_PARAMS buffer seperately
         * every MB has one MTX_CURRENT_IN_PARAMS structure, and the (N+1) frame can
         * reuse (N) frame's structure
         */
        ctx->in_params_size = ((~0xf) & (15 + 1 + (width + 15) * (height + 15) / (16 * 16))) * sizeof(MTX_CURRENT_IN_PARAMS);
        ctx->below_params_size = ((BELOW_PARAMS_SIZE * width * height / (16 * 16)) + 0xf) & (~0xf);
        ctx->above_params_size = ((width / 16) * 128 + 15) & (~0xf) ;

        vaStatus = psb_buffer_create(ctx->obj_context->driver_data, ctx->in_params_size, psb_bt_cpu_vpu, &ctx->topaz_in_params_I);
        if (VA_STATUS_SUCCESS != vaStatus) {
            return vaStatus;
        }

        vaStatus = psb_buffer_create(ctx->obj_context->driver_data, ctx->in_params_size, psb_bt_cpu_vpu, &ctx->topaz_in_params_P);
        if (VA_STATUS_SUCCESS != vaStatus) {
            psb_buffer_destroy(&ctx->topaz_in_params_I);
            return vaStatus;
        }

        vaStatus = psb_buffer_create(ctx->obj_context->driver_data, ctx->below_params_size * 4, psb_bt_cpu_vpu, &ctx->topaz_below_params);
        if (VA_STATUS_SUCCESS != vaStatus) {
            psb_buffer_destroy(&ctx->topaz_in_params_P);
            psb_buffer_destroy(&ctx->topaz_in_params_I);
            return vaStatus;
        }

        vaStatus = psb_buffer_create(ctx->obj_context->driver_data, ctx->above_params_size * 4, psb_bt_cpu_vpu, &ctx->topaz_above_params);
        if (VA_STATUS_SUCCESS != vaStatus) {
            psb_buffer_destroy(&ctx->topaz_in_params_P);
            psb_buffer_destroy(&ctx->topaz_in_params_I);
            psb_buffer_destroy(&ctx->topaz_below_params);
            return vaStatus;
        }
        ctx->below_params_ofs = 0;
        ctx->above_params_ofs = 0;
    } else {
        /*JPEG encode need three kinds of buffer but doesn't need above/below buffers.*/
        ctx->pic_params_size = (sizeof(JPEG_MTX_QUANT_TABLE) + 0xf) & (~0xf);

        ctx->header_buffer_size = (sizeof(JPEG_MTX_DMA_SETUP) + 0xf) & (~0xf);
        ctx->sliceparam_buffer_size =  16; /* Not used*/
    }
    return vaStatus;
}

unsigned int pnw__get_ipe_control(enum drm_pnw_topaz_codec  eEncodingFormat)
{
    unsigned int RegVal = 0;

    RegVal = F_ENCODE(2, MVEA_CR_IPE_GRID_FINE_SEARCH) |
             F_ENCODE(0, MVEA_CR_IPE_GRID_SEARCH_SIZE) |
             F_ENCODE(1, MVEA_CR_IPE_Y_FINE_SEARCH);

    switch (eEncodingFormat) {
    case IMG_CODEC_H263_NO_RC:
    case IMG_CODEC_H263_VBR:
    case IMG_CODEC_H263_CBR:
        RegVal |= F_ENCODE(0, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(0, MVEA_CR_IPE_ENCODING_FORMAT);
        break;
    case IMG_CODEC_MPEG4_NO_RC:
    case IMG_CODEC_MPEG4_VBR:
    case IMG_CODEC_MPEG4_CBR:
        RegVal |= F_ENCODE(1, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(1, MVEA_CR_IPE_ENCODING_FORMAT);
    default:
        break;
    case IMG_CODEC_H264_NO_RC:
    case IMG_CODEC_H264_VBR:
    case IMG_CODEC_H264_CBR:
    case IMG_CODEC_H264_VCM:
        RegVal |= F_ENCODE(2, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(2, MVEA_CR_IPE_ENCODING_FORMAT);
        break;
    }
    RegVal |= F_ENCODE(6, MVEA_CR_IPE_Y_CANDIDATE_NUM);
    return RegVal;
}


void pnw_DestroyContext(object_context_p obj_context)
{
    context_ENC_p ctx;
    ctx = (context_ENC_p)obj_context->format_data;

    psb_buffer_destroy(&ctx->topaz_in_params_P);
    psb_buffer_destroy(&ctx->topaz_in_params_I);
    psb_buffer_destroy(&ctx->topaz_below_params);
    psb_buffer_destroy(&ctx->topaz_above_params);

    if (NULL != ctx->slice_param_cache)
        free(ctx->slice_param_cache);
    if (NULL == ctx->save_seq_header_p)
        free(ctx->save_seq_header_p);
    free(obj_context->format_data);
    obj_context->format_data = NULL;
}

VAStatus pnw_CreateContext(
    object_context_p obj_context,
    object_config_p __maybe_unused obj_config,
    unsigned char is_JPEG)
{
    int width, height;
    int i;
    unsigned short SearchWidth, SearchHeight, SearchLeftOffset, SearchTopOffset;
    context_ENC_p ctx;
    VAStatus vaStatus;

    width = obj_context->picture_width;
    height = obj_context->picture_height;
    ctx = (context_ENC_p) calloc(1, sizeof(struct context_ENC_s));
    CHECK_ALLOCATION(ctx);

    obj_context->format_data = (void*) ctx;
    ctx->obj_context = obj_context;

    ctx->RawWidth = (unsigned short) width;
    ctx->RawHeight = (unsigned short) height;

    if (is_JPEG == 0) {
        ctx->Width = (unsigned short)(~0xf & (width + 0xf));
        ctx->Height = (unsigned short)(~0xf & (height + 0xf));
    } else {
        /*JPEG only require them are even*/
        ctx->Width = (unsigned short)(~0x1 & (width + 0x1));
        ctx->Height = (unsigned short)(~0x1 & (height + 0x1));
    }

    /* pre-calculated values based on other stream properties */
    SearchHeight = min(MVEA_LRB_SEARCH_HEIGHT, ctx->Height);
    SearchWidth = min(MVEA_LRB_SEARCH_WIDTH, ctx->Width);
    SearchLeftOffset = (((SearchWidth / 2) / 16) * 16);
    SearchTopOffset = (((SearchHeight / 2) / 16) * 16);

    ctx->HeightMinus16MinusLRBTopOffset        = ctx->Height - (SearchTopOffset + 16);
    ctx->HeightMinus32MinusLRBTopOffset        = ctx->Height - (SearchTopOffset + 32);
    ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16     = ctx->Height - (SearchTopOffset + SearchTopOffset + 16);
    ctx->HeightMinusLRBSearchHeight    = ctx->Height - SearchHeight;

    ctx->FCode = 0;

    ctx->NumCores = 2; /* FIXME Assume there is two encode cores in Penwell, precise value should read from HW */

    ctx->BelowParamsBufIdx = 0;
    ctx->AccessUnitNum = 0;
    ctx->SyncSequencer = 0; /* FIXME Refer to DDK */
    ctx->SliceToCore =  -1;
    ctx->CmdCount = 0xa5a5a5a5 % MAX_TOPAZ_CMD_COUNT;
    ctx->FrmIdx = 0;

    for (i = 0; i < MAX_TOPAZ_CORES; i++) {
        ctx->LastSliceNum[i] = -1;
        ctx->LastSync[0][i] = ~0;
        ctx->LastSync[1][i] = ~0;
    }

    for (i = 0; i < MAX_SLICES_PER_PICTURE; i++) {
        ctx->SliceHeaderReady[i] = IMG_FALSE;
    }

    vaStatus = pnw__alloc_context_buffer(ctx, is_JPEG);

    return vaStatus;
}

VAStatus pnw_BeginPicture(context_ENC_p ctx)
{
    VAStatus vaStatus = VA_STATUS_SUCCESS;
    pnw_cmdbuf_p cmdbuf;
    int ret, i;

    if (ctx->raw_frame_count != 0)
        ctx->previous_src_surface = ctx->src_surface;
    ctx->src_surface = ctx->obj_context->current_render_target;

    /* clear frameskip flag to 0 */
    CLEAR_SURFACE_INFO_skipped_flag(ctx->src_surface->psb_surface);
    ctx->none_vcl_nal = 0;

    /*if (ctx->sRCParams.RCEnable == IMG_TRUE)
     {
     pnw_DetectFrameSkip(ctx);
     if (0 != (GET_SURFACE_INFO_skipped_flag(ctx->src_surface->psb_surface)
            & SURFACE_INFO_SKIP_FLAG_SETTLED))
         ctx->sRCParams.FrameSkip = IMG_TRUE;
     else
         ctx->sRCParams.FrameSkip = IMG_FALSE;
     }*/

    /* Initialise the command buffer */
    ret = pnw_context_get_next_cmdbuf(ctx->obj_context);
    if (ret) {
        drv_debug_msg(VIDEO_DEBUG_GENERAL, "get next cmdbuf fail\n");
        vaStatus = VA_STATUS_ERROR_UNKNOWN;
        return vaStatus;
    }
    cmdbuf = ctx->obj_context->pnw_cmdbuf;
    memset(cmdbuf->cmd_idx_saved, 0, sizeof(cmdbuf->cmd_idx_saved));


    /* map start_pic param */
    vaStatus = psb_buffer_map(&cmdbuf->pic_params, &cmdbuf->pic_params_p);
    if (vaStatus) {
        return vaStatus;
    }
    vaStatus = psb_buffer_map(&cmdbuf->header_mem, &cmdbuf->header_mem_p);
    if (vaStatus) {
        psb_buffer_unmap(&cmdbuf->pic_params);
        return vaStatus;
    }

    vaStatus = psb_buffer_map(&cmdbuf->slice_params, &cmdbuf->slice_params_p);
    if (vaStatus) {
        psb_buffer_unmap(&cmdbuf->pic_params);
        psb_buffer_unmap(&cmdbuf->header_mem);
        return vaStatus;
    }

    /* only map topaz param when necessary */
    cmdbuf->topaz_above_params_p = NULL;
    cmdbuf->topaz_below_params_p = NULL;
    cmdbuf->topaz_in_params_I_p = NULL;
    cmdbuf->topaz_in_params_P_p = NULL;

    if (ctx->obj_context->frame_count == 0) { /* first picture */

        psb_driver_data_p driver_data = ctx->obj_context->driver_data;

        *cmdbuf->cmd_idx++ = ((MTX_CMDID_SW_NEW_CODEC & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) |
                             (((driver_data->drm_context & MTX_CMDWORD_COUNT_MASK) << MTX_CMDWORD_COUNT_SHIFT));
        pnw_cmdbuf_insert_command_param(ctx->eCodec);
        pnw_cmdbuf_insert_command_param((ctx->Width << 16) | ctx->Height);
    }

    ctx->FrmIdx++;
    ctx->SliceToCore = ctx->ParallelCores - 1;
    /* ctx->AccessUnitNum++;    Move this back to pnw_EndPicture */
    ctx->sRCParams.bBitrateChanged = IMG_FALSE;

    for (i = 0; i < MAX_TOPAZ_CORES; i++)
        ctx->LastSliceNum[i] = -1;

    for (i = 0; i < MAX_SLICES_PER_PICTURE; i++)
        ctx->SliceHeaderReady[i] = IMG_FALSE;

    /*If ParallelCores > 1(H264) and encode one slice per frame, the unnecessary start picture
    *commands will be replaced with MTX_CMDID_PAD and ignored by kernel*/
    cmdbuf->cmd_idx_saved[PNW_CMDBUF_START_PIC_IDX] = cmdbuf->cmd_idx;

    /* insert START_PIC command for each core */
    /* ensure that the master (core #0) will be last to complete this batch */
    for (i = (ctx->ParallelCores - 1); i >= 0; i--) {

        /*
         * the content of PIC_PARAMS is filled when RenderPicture(...,VAEncPictureParameterBufferXXX)
         */
        pnw_cmdbuf_insert_command_package(ctx->obj_context,
                                          i,
                                          MTX_CMDID_START_PIC,
                                          &cmdbuf->pic_params,
                                          i * ctx->pic_params_size);

        /* no RC paramter provided in vaBeginPicture
         * so delay RC param setup into vaRenderPicture(SequenceHeader...)
         */
    }

    ctx->obj_context->slice_count = 0;
    return 0;
}


VAStatus pnw_set_bias(context_ENC_p ctx, int core)
{
    pnw_cmdbuf_p cmdbuf = (pnw_cmdbuf_p)ctx->obj_context->pnw_cmdbuf;
    double flBpp;
    IMG_UINT8 THSkip;

    if (ctx->sRCParams.RCEnable) {
        flBpp = 1.0 * ctx->sRCParams.BitsPerSecond /
                (ctx->sRCParams.FrameRate * ctx->Width * ctx->Height);
    } else {
        flBpp =  0.14;
    }

    if (flBpp <= 0.07) {
        THSkip = TH_SKIP_24;
    } else if (flBpp <= 0.14) {
        THSkip = TH_SKIP_12;
    } else {
        THSkip = TH_SKIP_0;
    }
    switch (ctx->eCodec) {
    case IMG_CODEC_H264_VBR:
    case IMG_CODEC_H264_CBR:
    case IMG_CODEC_H264_VCM:
    case IMG_CODEC_H264_NO_RC:
        LoadH264Bias(cmdbuf, core, THSkip, ctx->sRCParams.QCPOffset);
        break;
    case IMG_CODEC_H263_CBR:
    case IMG_CODEC_H263_NO_RC:
    case IMG_CODEC_H263_VBR:
        LoadH263Bias(cmdbuf, core, THSkip);
        break;
    case IMG_CODEC_MPEG4_NO_RC:
    case IMG_CODEC_MPEG4_CBR:
    case IMG_CODEC_MPEG4_VBR:
        LoadMPEG4Bias(cmdbuf, core, THSkip);
        break;
    default:
        return -1;
        break;
    }
    return 0;
}

VAStatus pnw_RenderPictureParameter(context_ENC_p ctx, int core)
{
    PIC_PARAMS *psPicParams;    /* PIC_PARAMS has been put in pnw_hostcode.h */
    object_surface_p src_surface;
    unsigned int srf_buf_offset;
    object_surface_p rec_surface;
    object_surface_p ref_surface;
    pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
    VAStatus vaStatus = VA_STATUS_ERROR_UNKNOWN;

    psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p + ctx->pic_params_size * core);

    memset(psPicParams, 0, sizeof(PIC_PARAMS));
    /* second frame will reuse some rate control parameters (IN_PARAMS_MP4)
     * so only memset picture parames except IN_PARAMS
     * BUT now IN_RC_PARAMS was reload from the cache, so it now can
     * memset entirE PIC_PARAMS
     */

    /*
    memset(psPicParams, 0, (int)((unsigned char *)&psPicParams->sInParams - (unsigned char *)psPicParams));
    */

    src_surface = ctx->src_surface;
    CHECK_SURFACE(src_surface);

    rec_surface = ctx->dest_surface;
    CHECK_SURFACE(rec_surface);

    /*The fisrt frame always is I frame and the content of reference frame wouldn't be used.
     * But the heights of ref and dest frame should be the same.
     * That allows Topaz to keep its motion vectors up to date, which helps maintain performance */
    if (ctx->obj_context->frame_count == 0)
        ctx->ref_surface = ctx->dest_surface;

    ref_surface = ctx->ref_surface;
    CHECK_SURFACE(rec_surface);

    /* clear frameskip flag */
    CLEAR_SURFACE_INFO_skipped_flag(rec_surface->psb_surface);
    CLEAR_SURFACE_INFO_skipped_flag(ref_surface->psb_surface);

    /* Write video data byte offset into Coded buffer
     * If it is here, it will be a SYNC point, which have performance impact
     * Move to psb__CreateBuffer
     vaStatus = psb_buffer_map(ctx->coded_buf->psb_buffer, &pBuffer);
     if(vaStatus) {
     DEBUG_FAILURE;
     return vaStatus;
     }
     *(IMG_UINT32 *)(pBuffer+8) = 16;
     psb_buffer_unmap(ctx->coded_buf->psb_buffer);
    */

    psPicParams->SrcYStride = src_surface->psb_surface->stride;
    switch (ctx->eFormat) {
    case IMG_CODEC_IYUV:        /* IYUV */
    case IMG_CODEC_PL8:
        psPicParams->SrcUVStride = src_surface->psb_surface->stride / 2;
        psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 8 / 2;
        break;
    case IMG_CODEC_IMC2:    /* IMC2 */
    case IMG_CODEC_PL12:
        psPicParams->SrcUVStride = src_surface->psb_surface->stride;
        psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 8;
        break;
    default:
        break;
    }
    psPicParams->SrcYRowStride    = src_surface->psb_surface->stride * 16;
    /* psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 16 / 2; */

    /* Dest(rec) stride
     * The are now literally Dst stride (not equivalent to 'offset to next row')
     */
#ifdef VA_EMULATOR
    /* only for simulator, va-emulator needs the actually stride for
     * reconstructed frame transfer (va-emulator->driver)
     */
    psPicParams->DstYStride = rec_surface->psb_surface->stride;
    psPicParams->DstUVStride = rec_surface->psb_surface->stride;
#else
    psPicParams->DstYStride = rec_surface->psb_surface->stride;
    psPicParams->DstUVStride = rec_surface->psb_surface->stride;
#endif

    psPicParams->Width  = ctx->Width;
    psPicParams->Height = ctx->Height;
    psPicParams->NumSlices = ctx->sRCParams.Slices;

    psPicParams->IsPerSliceOutput = IMG_FALSE;
    psPicParams->SearchHeight = min(MVEA_LRB_SEARCH_HEIGHT, psPicParams->Height);
    psPicParams->SearchWidth = min(MVEA_LRB_SEARCH_WIDTH, psPicParams->Width);

    /* not sure why we are setting this up here... */
    psPicParams->Flags = 0;
    switch (ctx->eCodec) {
    case IMG_CODEC_H264_NO_RC:
    case IMG_CODEC_H264_VBR:
    case IMG_CODEC_H264_CBR:
    case IMG_CODEC_H264_VCM:
        psPicParams->Flags |= ISH264_FLAGS;
        break;
    case IMG_CODEC_H263_VBR:
    case IMG_CODEC_H263_CBR:
    case IMG_CODEC_H263_NO_RC:
        psPicParams->Flags |= ISH263_FLAGS;
        break;
    case IMG_CODEC_MPEG4_NO_RC:
    case IMG_CODEC_MPEG4_VBR:
    case IMG_CODEC_MPEG4_CBR:
        psPicParams->Flags |= ISMPEG4_FLAGS;
        break;
    default:
        return VA_STATUS_ERROR_UNKNOWN;
    }

    switch (ctx->eCodec) {
    case IMG_CODEC_H264_VBR:
    case IMG_CODEC_MPEG4_VBR:
    case IMG_CODEC_H263_VBR:
        psPicParams->Flags |= ISVBR_FLAGS;
        break;
    case IMG_CODEC_H264_VCM:
        psPicParams->Flags |= (ISVCM_FLAGS | ISCBR_FLAGS);
        break;
    case IMG_CODEC_H263_CBR:
    case IMG_CODEC_H264_CBR:
    case IMG_CODEC_MPEG4_CBR:
        psPicParams->Flags |= ISCBR_FLAGS;
        break;
    case IMG_CODEC_MPEG4_NO_RC:
    case IMG_CODEC_H263_NO_RC:
    case IMG_CODEC_H264_NO_RC:
        break;
    default:
        return VA_STATUS_ERROR_UNKNOWN;
    }

#if 0
    if (ctx->SyncSequencer)
        psPicParams->Flags |= SYNC_SEQUENCER;
#endif

    if (ctx->sRCParams.RCEnable) {
        if (ctx->sRCParams.bDisableFrameSkipping) {
            psPicParams->Flags |= DISABLE_FRAME_SKIPPING;
            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Frame skip is disabled.\n");
        }

        if (ctx->sRCParams.bDisableBitStuffing && IS_H264_ENC(ctx->eCodec)) {
            psPicParams->Flags |= DISABLE_BIT_STUFFING;
            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Bit stuffing is disabled.\n");
        }


        /* for the first frame, will setup RC params in EndPicture */
        if (ctx->raw_frame_count > 0) { /* reuse in_params parameter */
            /* In case, it's changed in a new sequence */
            if (ctx->obj_context->frame_count == 0
               && ctx->in_params_cache.IntraPeriod != ctx->sRCParams.IntraFreq) {
               drv_debug_msg(VIDEO_DEBUG_ERROR,
               "On frame %d, Intra period is changed from %d to %d\n",
               ctx->raw_frame_count, ctx->in_params_cache.IntraPeriod,
               ctx->sRCParams.IntraFreq);
               ctx->in_params_cache.IntraPeriod =  ctx->sRCParams.IntraFreq;
               ctx->in_params_cache.BitsPerGOP =
                    (ctx->sRCParams.BitsPerSecond / ctx->sRCParams.FrameRate)
                    * ctx->sRCParams.IntraFreq;
            }

            psPicParams->Flags &= ~FIRST_FRAME;
            /* reload IN_RC_PARAMS from cache */
            memcpy(&psPicParams->sInParams, &ctx->in_params_cache, sizeof(IN_RC_PARAMS));
        } else {
            psPicParams->Flags |= ISRC_FLAGS;
            psPicParams->Flags |= FIRST_FRAME;
        }
    } else
        psPicParams->sInParams.SeInitQP = ctx->sRCParams.InitialQp;

    /* some relocations have to been done here */
    srf_buf_offset = src_surface->psb_surface->buf.buffer_ofs;
    if (src_surface->psb_surface->buf.type == psb_bt_camera)
        drv_debug_msg(VIDEO_DEBUG_GENERAL, "src surface GPU offset 0x%08x, luma offset 0x%08x\n",
                                 wsbmBOOffsetHint(src_surface->psb_surface->buf.drm_buf), srf_buf_offset);

    RELOC_PIC_PARAMS_PNW(&psPicParams->SrcYBase, srf_buf_offset, &src_surface->psb_surface->buf);
    switch (ctx->eFormat) {
    case IMG_CODEC_IYUV:
    case IMG_CODEC_PL8:
    case IMG_CODEC_PL12:
        RELOC_PIC_PARAMS_PNW(&psPicParams->SrcUBase,
                             srf_buf_offset + src_surface->psb_surface->chroma_offset,
                             &src_surface->psb_surface->buf);

        RELOC_PIC_PARAMS_PNW(&psPicParams->SrcVBase,
                             srf_buf_offset + src_surface->psb_surface->chroma_offset * 5 / 4,
                             &src_surface->psb_surface->buf);

        break;
    case IMG_CODEC_IMC2:
    case IMG_CODEC_NV12:
    default:
        break;
    }

    RELOC_PIC_PARAMS_PNW(&psPicParams->DstYBase, 0, &rec_surface->psb_surface->buf);

    RELOC_PIC_PARAMS_PNW(&psPicParams->DstUVBase,
                         rec_surface->psb_surface->stride * rec_surface->height,
                         &rec_surface->psb_surface->buf);

    RELOC_PIC_PARAMS_PNW(&psPicParams->BelowParamsInBase,
                         ctx->below_params_ofs + ctx->below_params_size *(((ctx->AccessUnitNum) & 0x1)),
                         cmdbuf->topaz_below_params);

    RELOC_PIC_PARAMS_PNW(&psPicParams->BelowParamsOutBase,
                         ctx->below_params_ofs + ctx->below_params_size *(((ctx->AccessUnitNum + 1) & 0x1)),
                         cmdbuf->topaz_below_params);

    RELOC_PIC_PARAMS_PNW(&psPicParams->AboveParamsBase,
                         ctx->above_params_ofs + ctx->above_params_size *(core * 2 + (ctx->AccessUnitNum & 0x1)),
                         cmdbuf->topaz_above_params);

    RELOC_PIC_PARAMS_PNW(&psPicParams->CodedBase, ctx->coded_buf_per_slice * core, ctx->coded_buf->psb_buffer);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "For core %d, above_parmas_off %x\n", core, ctx->above_params_ofs + ctx->above_params_size *(core * 2 + ((ctx->AccessUnitNum) & 0x1)));

   return VA_STATUS_SUCCESS;
}

static VAStatus pnw_SetupRCParam(context_ENC_p ctx)
{
    pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
    PIC_PARAMS  *psPicParams = (PIC_PARAMS  *)cmdbuf->pic_params_p;
    PIC_PARAMS  *psPicParamsTmp;
    int origin_qp, i;/* in DDK setup_rc will change qp strangly,
                   * just for keep same with DDK
                   */

    origin_qp = ctx->sRCParams.InitialQp;

    psPicParams->Flags |= ISRC_FLAGS;
    pnw__setup_rcdata(ctx, psPicParams, &ctx->sRCParams);

    /* restore it, just keep same with DDK */
    ctx->sRCParams.InitialQp = origin_qp;

    /* Assume IN_RC_PARAMS for each core is identical, and copy for each */
    for (i = (ctx->ParallelCores - 1); i > 0; i--) {
        psPicParamsTmp = (PIC_PARAMS  *)(cmdbuf->pic_params_p + ctx->pic_params_size * i);
        memcpy((unsigned char *)&psPicParamsTmp->sInParams,
               (unsigned char *)&psPicParams->sInParams,
               sizeof(IN_RC_PARAMS));
        psPicParamsTmp->Flags |= psPicParams->Flags;
    }

    /* save IN_RC_PARAMS into the cache */
    memcpy(&ctx->in_params_cache, (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS));
    return VA_STATUS_SUCCESS;
}

VAStatus pnw_EndPicture(context_ENC_p ctx)
{
    VAStatus vaStatus = VA_STATUS_SUCCESS;
    unsigned int i;
    int index;
    pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
    PIC_PARAMS *psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
    PIC_PARAMS *psPicParamsSlave = NULL;
    unsigned int val = 0;

    ctx->AccessUnitNum++;

    if (ctx->sRCParams.RCEnable) {
        if (ctx->raw_frame_count == 0)
            pnw_SetupRCParam(ctx);
        else  if (ctx->sRCParams.bBitrateChanged) {
            /* Toggle the last bit to make sure encoder firmare recalculate the
               RC params even if the target bitrate isn't changed.*/
            val = ~(ctx->sRCParams.BitsPerSecond & 0x1);
            ctx->sRCParams.BitsPerSecond &= ~1;
            ctx->sRCParams.BitsPerSecond |= (val & 1);

            drv_debug_msg(VIDEO_DEBUG_GENERAL, "bitrate is changed to %d, "
                    "update the rc data accordingly\n", ctx->sRCParams.BitsPerSecond);
            pnw__update_rcdata(ctx, psPicParams, &ctx->sRCParams);
            if (ctx->sRCParams.MinQP)
                psPicParams->sInParams.MinQPVal = ctx->sRCParams.MinQP;
            memcpy(&ctx->in_params_cache, (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS));
            /* Save rate control info in slave core as well */
            for (i = 1; i < ctx->ParallelCores; i++) {
                psPicParamsSlave = (PIC_PARAMS *)(cmdbuf->pic_params_p + ctx->pic_params_size * i);
                memcpy((unsigned char *)&psPicParamsSlave->sInParams,
                        (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS));
	    }
        }
    }

#if TOPAZ_PIC_PARAMS_VERBOSE
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "End Picture for frame %d\n", ctx->raw_frame_count);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "sizeof PIC_PARAMS %d\n", sizeof(PIC_PARAMS));
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "sizeof in_params %d\n", sizeof(psPicParams->sInParams));
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcYBase  0x%08x\n", psPicParams->SrcYBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcUBase 0x%08x\n", psPicParams->SrcUBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcVBase 0x%08x\n", psPicParams->SrcVBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->DstYBase 0x%08x\n", psPicParams->DstYBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->DstUVBase 0x%08x\n", psPicParams->DstUVBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcYStride 0x%08x\n", psPicParams->SrcYStride);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcUVStride 0x%08x\n", psPicParams->SrcUVStride);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcYRowStride 0x%08x\n", psPicParams->SrcYRowStride);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcUVRowStride 0x%08x\n", psPicParams->SrcUVRowStride);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->DstYStride 0x%08x\n", psPicParams->DstYStride);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->DstUVStride 0x%08x\n", psPicParams->DstUVStride);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->CodedBase 0x%08x\n", psPicParams->CodedBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->BelowParamsInBase 0x%08x\n", psPicParams->BelowParamsInBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->BelowParamsOutBase 0x%08x\n", psPicParams->BelowParamsOutBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->AboveParamsBase 0x%08x\n", psPicParams->AboveParamsBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->Width 0x%08x\n", psPicParams->Width);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->Height 0x%08x\n", psPicParams->Height);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->Flags 0x%08x\n", psPicParams->Flags);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SerachWidth 0x%08x\n", psPicParams->SearchWidth);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SearchHeight 0x%08x\n", psPicParams->SearchHeight);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->NumSlices 0x%08x\n", psPicParams->NumSlices);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->ClockDivBitrate %lld\n", psPicParams->ClockDivBitrate);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->MaxBufferMultClockDivBitrate %d\n",
                             psPicParams->MaxBufferMultClockDivBitrate);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.SeInitQP %d\n", psPicParams->sInParams.SeInitQP);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MinQPVal %d\n", psPicParams->sInParams.MinQPVal);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MaxQPVal %d\n", psPicParams->sInParams.MaxQPVal);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MBPerRow %d\n", psPicParams->sInParams.MBPerRow);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MBPerFrm %d\n", psPicParams->sInParams.MBPerFrm);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MBPerBU %d\n", psPicParams->sInParams.MBPerBU);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BUPerFrm %d\n", psPicParams->sInParams.BUPerFrm);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.IntraPeriod %d\n", psPicParams->sInParams.IntraPeriod);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BitsPerFrm %d\n", psPicParams->sInParams.BitsPerFrm);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BitsPerBU %d\n", psPicParams->sInParams.BitsPerBU);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BitsPerMB %d\n", psPicParams->sInParams.BitsPerMB);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BitRate %d\n", psPicParams->sInParams.BitRate);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BufferSize %d\n", psPicParams->sInParams.BufferSize);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.InitialLevel %d\n", psPicParams->sInParams.InitialLevel);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.InitialDelay %d\n", psPicParams->sInParams.InitialDelay);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.ScaleFactor %d\n", psPicParams->sInParams.ScaleFactor);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.VCMBitrateMargin %d\n", psPicParams->sInParams.VCMBitrateMargin);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.HalfFrameRate %d\n", psPicParams->sInParams.HalfFrameRate);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.FCode %d\n", psPicParams->sInParams.FCode);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BitsPerGOP %d\n", psPicParams->sInParams.BitsPerGOP);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.AvQPVal %d\n", psPicParams->sInParams.AvQPVal);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MyInitQP %d\n", psPicParams->sInParams.MyInitQP);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.ForeceSkipMargin %d\n", psPicParams->sInParams.ForeceSkipMargin);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.RCScaleFactor %d\n", psPicParams->sInParams.RCScaleFactor);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.TransferRate %d\n", psPicParams->sInParams.TransferRate);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MaxFrameSize %d\n", psPicParams->sInParams.MaxFrameSize);
#endif
    /* save current settings */
    ctx->previous_ref_surface = ctx->ref_surface;
    ctx->previous_dest_surface = ctx->dest_surface; /* reconstructed surface */
    SET_CODEDBUF_INFO(SLICE_NUM, ctx->coded_buf->codedbuf_aux_info,
        ctx->obj_context->slice_count);
    SET_CODEDBUF_INFO(NONE_VCL_NUM, ctx->coded_buf->codedbuf_aux_info,
        ctx->none_vcl_nal);

    for (index = (ctx->ParallelCores - 1); index >= 0; index--) {
        pnw_cmdbuf_insert_command_package(ctx->obj_context,
                                          index,
                                          MTX_CMDID_END_PIC,
                                          NULL,
                                          0);
    }
    psb_buffer_unmap(&cmdbuf->pic_params);
    psb_buffer_unmap(&cmdbuf->header_mem);
    psb_buffer_unmap(&cmdbuf->slice_params);

    /* unmap MTX_CURRENT_IN_PARAMS buffer only when it is mapped */
    if (cmdbuf->topaz_in_params_I_p != NULL) {
        psb_buffer_unmap(cmdbuf->topaz_in_params_I);
        cmdbuf->topaz_in_params_I_p = NULL;
    }

    if (cmdbuf->topaz_in_params_P_p != NULL) {
        psb_buffer_unmap(cmdbuf->topaz_in_params_P);
        cmdbuf->topaz_in_params_P_p = NULL;
    }

    if (cmdbuf->topaz_above_params_p != NULL) {
        psb_buffer_unmap(cmdbuf->topaz_above_params);
        cmdbuf->topaz_above_params_p = NULL;
    }

    if (cmdbuf->topaz_below_params_p != NULL) {
        psb_buffer_unmap(cmdbuf->topaz_below_params);
        cmdbuf->topaz_below_params_p = NULL;
    }

    if (pnw_context_flush_cmdbuf(ctx->obj_context)) {
        vaStatus = VA_STATUS_ERROR_UNKNOWN;
    }
    ctx->raw_frame_count++;
    return vaStatus;
}

static void pnw__setup_busize(context_ENC_p ctx)
{
    unsigned int old_busize = ctx->sRCParams.BUSize;
    int slices = ctx->obj_context->slice_count;

    /* it is called at EndPicture, we should now the Slice number */
    //ctx->Slices = ctx->obj_context->slice_count;

    /* if no BU size is given then pick one ourselves */
    if (ctx->sRCParams.BUSize != 0)  { /* application provided BUSize */
        IMG_UINT32 MBs, MBsperSlice, MBsLastSlice;
        IMG_UINT32 BUs;
        IMG_INT32  SliceHeight;
        IMG_UINT32 MaxSlicesPerPipe, MaxMBsPerPipe, MaxBUsPerPipe;

        MBs     = ctx->Height * ctx->Width / (16 * 16);

        SliceHeight     = ctx->Height / slices;
        /* SliceHeight += 15; */
        SliceHeight &= ~15;

        MBsperSlice     = (SliceHeight * ctx->Width) / (16 * 16);
        MBsLastSlice    = MBs - (MBsperSlice * (slices - 1));

        /* they have given us a basic unit so validate it */
        if (ctx->sRCParams.BUSize < 6) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too small, must be greater than 6\n");
            ctx->sRCParams.BUSize = 0; /* need repatch */;
        }
        if (ctx->sRCParams.BUSize > MBsperSlice) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too large, must be less than the number of macroblocks in a slice\n");
            ctx->sRCParams.BUSize = 0; /* need repatch */;
        }
        if (ctx->sRCParams.BUSize > MBsLastSlice) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too large, must be less than number of macroblocks in the last slice\n");
            ctx->sRCParams.BUSize = 0; /* need repatch */;
        }

        if (ctx->sRCParams.BUSize != 0) {
            BUs = MBsperSlice / ctx->sRCParams.BUSize;
            if ((BUs * ctx->sRCParams.BUSize) != MBsperSlice)   {
                drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size not an integer divisor of MB's in a slice");
                ctx->sRCParams.BUSize = 0; /* need repatch */;
            }
        }
        if (ctx->sRCParams.BUSize != 0) {
            BUs = MBsLastSlice / ctx->sRCParams.BUSize;
            if ((BUs * ctx->sRCParams.BUSize) != MBsLastSlice)   {
                drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size not an integer divisor of MB's in a slice");
                ctx->sRCParams.BUSize = 0; /* need repatch */;
            }
        }

        if (ctx->sRCParams.BUSize != 0) {
            // check if the number of BUs per pipe is greater than 200
            MaxSlicesPerPipe = (slices + ctx->ParallelCores - 1) / ctx->ParallelCores;
            MaxMBsPerPipe = (MBsperSlice * (MaxSlicesPerPipe - 1)) + MBsLastSlice;
            MaxBUsPerPipe = (MaxMBsPerPipe + ctx->sRCParams.BUSize - 1) / ctx->sRCParams.BUSize;
            if (MaxBUsPerPipe > 200) {
                drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too small. There must be less than 200 basic units per slice");
                ctx->sRCParams.BUSize = 0; /* need repatch */;
            }
        }
    }

    if (ctx->sRCParams.BUSize == 0)  {
        IMG_UINT32 MBs, MBsperSlice, MBsLastSlice;
        IMG_UINT32 BUsperSlice, BUsLastSlice;
        IMG_UINT32 MaxSlicesPerPipe, MaxMBsPerPipe, MaxBUsPerPipe;
        IMG_INT32  SliceHeight;
        IMG_UINT32 BUSize = 6;

        MBs     = ctx->Height * ctx->Width / (16 * 16);

        SliceHeight     = ctx->Height / slices;
        /* SliceHeight += 15; */
        SliceHeight &= ~15;

        MBsperSlice     = (SliceHeight * ctx->Width) / (16 * 16);
        MBsLastSlice = MBs - (MBsperSlice * (slices - 1));

        /* Check number of BUs to be encoded on one pipe is less than maximum number allowed 200  */
        MaxSlicesPerPipe = (slices + ctx->ParallelCores - 1) / ctx->ParallelCores;
        MaxMBsPerPipe = (MBsperSlice * (MaxSlicesPerPipe - 1)) + MBsLastSlice;
        MaxBUsPerPipe = (MaxMBsPerPipe + BUSize - 1) / BUSize;

        while (MaxBUsPerPipe > 200)  {
            BUSize++;
            MaxBUsPerPipe = (MaxMBsPerPipe + BUSize - 1) / BUSize;
        }

        /* Check whether there are integeral number of BUs in the slices  */
        BUsperSlice = MBsperSlice / BUSize;
        BUsLastSlice = MBsLastSlice / BUSize;
        while ((BUsperSlice*BUSize != MBsperSlice) ||
               (BUsLastSlice*BUSize != MBsLastSlice)) {
            BUSize++;
            BUsperSlice = MBsperSlice / BUSize;
            BUsLastSlice = MBsLastSlice / BUSize;
        }

        ctx->sRCParams.BUSize = BUSize;
    /*
        ctx->sRCParams.InitialLevel = (3 * ctx->sRCParams.BufferSize) >> 4;
        ctx->sRCParams.InitialDelay = (13 * ctx->sRCParams.BufferSize) >> 4;
    */
    }

    if (ctx->sRCParams.BUSize != old_busize)
        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Patched Basic unit to %d (original=%d)\n", ctx->sRCParams.BUSize, old_busize);
}


static void pnw__update_rcdata(
    context_ENC_p psContext,
    PIC_PARAMS *psPicParams,
    IMG_RC_PARAMS *psRCParams)
{
    double      L1, L2, L3, L4, L5, L6, flBpp;
    IMG_INT16           i16TempQP;
    IMG_INT32   i32BufferSizeInFrames = 0;

    flBpp = 1.0 * psRCParams->BitsPerSecond
            / (psRCParams->FrameRate * psContext->Width * psContext->Height);

    if (psContext->Width <= 176) {
        /* for very small franes we need to adjust the calculations */
        flBpp = flBpp / 2.0;
    }

    psPicParams->sInParams.IntraPeriod =  psRCParams->IntraFreq;
    psPicParams->sInParams.BitRate = psRCParams->BitsPerSecond;
    psPicParams->sInParams.BitsPerFrm = (psRCParams->BitsPerSecond + psRCParams->FrameRate / 2) / psRCParams->FrameRate;
    psPicParams->sInParams.BitsPerGOP = (psRCParams->BitsPerSecond / psRCParams->FrameRate) * psRCParams->IntraFreq;
    psPicParams->sInParams.BitsPerBU    = psPicParams->sInParams.BitsPerFrm / (4 * psPicParams->sInParams.BUPerFrm);
    psPicParams->sInParams.BitsPerMB    = psPicParams->sInParams.BitsPerBU / psRCParams->BUSize;
    psPicParams->sInParams.TransferRate = psRCParams->BitsPerSecond / psRCParams->FrameRate;

    i32BufferSizeInFrames = psRCParams->BufferSize / psPicParams->sInParams.BitsPerFrm;

    /* select thresholds and initial Qps etc that are codec dependent */
    switch (psContext->eCodec) {
    case IMG_CODEC_H264_CBR:
    case IMG_CODEC_H264_VCM:
    case IMG_CODEC_H264_VBR:
        L1 = 0.1;
        L2 = 0.15;
        L3 = 0.2;

        /* Set MaxQP to avoid blocky image in low bitrate */
        /* RCScaleFactor indicates the size of GOP for rate control */
        if (psContext->eCodec == IMG_CODEC_H264_VCM) {
            psPicParams->sInParams.MaxQPVal = 51;
            psPicParams->sInParams.RCScaleFactor = 16;
        }
        else {
            psPicParams->sInParams.MaxQPVal = 51;
            psPicParams->sInParams.RCScaleFactor = 16;
        }

        /* Setup MAX and MIN Quant Values */
        if (flBpp >= 0.50)
            i16TempQP = 4;
        else
            i16TempQP = (unsigned int)(26 - (40 * flBpp));

        psPicParams->sInParams.MinQPVal = (max(min(psPicParams->sInParams.MaxQPVal, i16TempQP), 0));

        L1 = 0.050568;
        L2 = 0.202272;
        L3 = 0.40454321;
        L4 = 0.80908642;
        L5 = 1.011358025;
        if (flBpp < L1)
            psPicParams->sInParams.SeInitQP = (IMG_UINT8)(47 - 78.10 * flBpp);

        else if (flBpp >= L1 && flBpp < L2)
            psPicParams->sInParams.SeInitQP = (IMG_UINT8)(45 - 66.67 * flBpp);

        else if (flBpp >= L2 && flBpp < L3)
            psPicParams->sInParams.SeInitQP = (IMG_UINT8)(36 - 24.72 * flBpp);

        else if (flBpp >= L3 && flBpp < L4)
            psPicParams->sInParams.SeInitQP = (IMG_UINT8)(34 - 19.78 * flBpp);

        else if (flBpp >= L4 && flBpp < L5)
            psPicParams->sInParams.SeInitQP = (IMG_UINT8)(27 - 9.89 * flBpp);

        else if (flBpp >= L5 && flBpp < 4)
            psPicParams->sInParams.SeInitQP = (IMG_UINT8)(20 - 4.95 * flBpp);
        else
            psPicParams->sInParams.SeInitQP = psPicParams->sInParams.MinQPVal;

        if (psPicParams->sInParams.SeInitQP < psPicParams->sInParams.MinQPVal)
            psPicParams->sInParams.SeInitQP = psPicParams->sInParams.MinQPVal;

        break;

    case IMG_CODEC_MPEG4_CBR:
    case IMG_CODEC_MPEG4_VBR:
    case IMG_CODEC_H263_CBR:
    case IMG_CODEC_H263_VBR:
        psPicParams->sInParams.RCScaleFactor = 16;
        psPicParams->sInParams.MaxQPVal  = 31;

        if (psContext->Width <= 176) {
            L1 = 0.043;
            L2 = 0.085;
            L3 = 0.126;
            L4 = 0.168;
            L5 = 0.336;
            L6 = 0.505;
        } else if (psContext->Width == 352) {
            L1 = 0.065;
            L2 = 0.085;
            L3 = 0.106;
            L4 = 0.126;
            L5 = 0.168 ;
            L6 = 0.210;
        } else {
            L1 = 0.051;
            L2 = 0.0770;
            L3 = 0.096;
            L4 = 0.145;
            L5 = 0.193;
            L6 = 0.289;
        }

        /* Calculate Initial QP if it has not been specified */
        if (flBpp < L1)
            psPicParams->sInParams.SeInitQP = 31;

        else if (flBpp >= L1 && flBpp < L2)
            psPicParams->sInParams.SeInitQP = 26;

        else if (flBpp >= L2 && flBpp < L3)
            psPicParams->sInParams.SeInitQP = 22;

        else if (flBpp >= L3 && flBpp < L4)
            psPicParams->sInParams.SeInitQP = 18;

        else if (flBpp >= L4 && flBpp < L5)
            psPicParams->sInParams.SeInitQP = 14;

        else if (flBpp >= L5 && flBpp < L6)
            psPicParams->sInParams.SeInitQP = 10;
        else
            psPicParams->sInParams.SeInitQP = 8;

        psPicParams->sInParams.AvQPVal =  psPicParams->sInParams.SeInitQP;

        if (flBpp >= 0.25
                && (psContext->eCodec == IMG_CODEC_MPEG4_CBR ||
                    psContext->eCodec == IMG_CODEC_MPEG4_VBR)) {
            psPicParams->sInParams.MinQPVal = 1;
        } else {
            psPicParams->sInParams.MinQPVal = 4;
        }
        break;

    default:
        /* the NO RC cases will fall here */
        break;
    }

    /* Set up Input Parameters that are mode dependent */
    switch (psContext->eCodec) {
    case IMG_CODEC_H264_NO_RC:
    case IMG_CODEC_H263_NO_RC:
    case IMG_CODEC_MPEG4_NO_RC:
        return ;

    case IMG_CODEC_H264_VCM:
        psPicParams->Flags      |= (ISVCM_FLAGS | ISCBR_FLAGS);
        if (psContext->Height >= 480) {
            /* for SD and above we can target 95% (122/128) of maximum bitrate */
            psPicParams->sInParams.VCMBitrateMargin = 122;
        } else {
            /* for less and SD we target 99% of maximum bitrate */
            psPicParams->sInParams.VCMBitrateMargin = 127;
        }
        if (i32BufferSizeInFrames < 15) {
            /* when we have a very small window size we reduce the target
             * further to avoid too much skipping */
            psPicParams->sInParams.VCMBitrateMargin -= 5;
        }
        psPicParams->sInParams.ForeceSkipMargin = 0; /* start skipping MBs when within 500 bits of slice or frame limit */
        if (psRCParams->BitsPerSecond < 1000000) {      // 1 Mbits/s
            psPicParams->sInParams.ScaleFactor = 0;
        } else if (psRCParams->BitsPerSecond < 2000000) { // 2 Mbits/s
            psPicParams->sInParams.ScaleFactor = 1;
        } else if (psRCParams->BitsPerSecond < 4000000) { // 4 Mbits/s
            psPicParams->sInParams.ScaleFactor = 2;
        } else if (psRCParams->BitsPerSecond < 8000000) { // 8 Mbits/s
            psPicParams->sInParams.ScaleFactor = 3;
        } else {
            psPicParams->sInParams.ScaleFactor = 4;
        }

        psPicParams->sInParams.BufferSize = i32BufferSizeInFrames;

        break;
    case IMG_CODEC_H264_CBR:
        psPicParams->Flags |= ISCBR_FLAGS;
        /* ------------------- H264 CBR RC ------------------- */
        /* Initialize the parameters of fluid flow traffic model. */
        psPicParams->sInParams.BufferSize = psRCParams->BufferSize;

        /* HRD consideration - These values are used by H.264 reference code. */
        if (psRCParams->BitsPerSecond < 1000000) {      /* 1 Mbits/s */
            psPicParams->sInParams.ScaleFactor = 0;
        } else if (psRCParams->BitsPerSecond < 2000000) { /* 2 Mbits/s */
            psPicParams->sInParams.ScaleFactor = 1;
        } else if (psRCParams->BitsPerSecond < 4000000) { /* 4 Mbits/s */
            psPicParams->sInParams.ScaleFactor = 2;
        } else if (psRCParams->BitsPerSecond < 8000000) { /* 8 Mbits/s */
            psPicParams->sInParams.ScaleFactor = 3;
        } else {
            psPicParams->sInParams.ScaleFactor = 4;
        }
        break;

    case IMG_CODEC_MPEG4_CBR:
    case IMG_CODEC_H263_CBR:
        psPicParams->Flags |= ISCBR_FLAGS;

        flBpp  = 256 * (psRCParams->BitsPerSecond / psContext->Width);
        flBpp /= (psContext->Height * psRCParams->FrameRate);

        if ((psPicParams->sInParams.MBPerFrm > 1024 && flBpp < 16) || (psPicParams->sInParams.MBPerFrm <= 1024 && flBpp < 24))
            psPicParams->sInParams.HalfFrameRate = 1;
        else
            psPicParams->sInParams.HalfFrameRate = 0;

        if (psPicParams->sInParams.HalfFrameRate >= 1) {
            psPicParams->sInParams.SeInitQP = 31;
            psPicParams->sInParams.AvQPVal = 31;
            psPicParams->sInParams.MyInitQP = 31;
        }

        psPicParams->sInParams.BufferSize = psRCParams->BufferSize;
        if (psPicParams->sInParams.BufferSize > 112 * 16384) // Simple Profile L5 Constraints
            psPicParams->sInParams.BufferSize = 112 * 16384;
        break;

    case IMG_CODEC_MPEG4_VBR:
    case IMG_CODEC_H263_VBR:
    case IMG_CODEC_H264_VBR:
        psPicParams->Flags |= ISVBR_FLAGS;

        psPicParams->sInParams.MBPerBU  = psPicParams->sInParams.MBPerFrm;
        psPicParams->sInParams.BUPerFrm = 1;

        /* Initialize the parameters of fluid flow traffic model. */
        psPicParams->sInParams.BufferSize = psRCParams->BufferSize;

        if (psContext->eCodec != IMG_CODEC_H264_VBR) {
            if (psPicParams->sInParams.BufferSize >  112 * 16384)
                psPicParams->sInParams.BufferSize = 112 * 16384; // Simple Profile L5 Constraints
        }

        /* These scale factor are used only for rate control to avoid overflow */
        /* in fixed-point calculation these scale factors are decided by bit rate */
        if (psRCParams->BitsPerSecond < 640000) {
            psPicParams->sInParams.ScaleFactor  = 2;                                            /* related to complexity */
        } else if (psRCParams->BitsPerSecond < 2000000) {
            psPicParams->sInParams.ScaleFactor  = 4;
        } else {
            psPicParams->sInParams.ScaleFactor  = 6;
        }
        break;
    default:
        break;
    }

    psPicParams->sInParams.MyInitQP     = psPicParams->sInParams.SeInitQP;

#if 0
    if (psContext->SyncSequencer)
        psPicParams->Flags |= SYNC_SEQUENCER;
#endif

    psPicParams->sInParams.InitialDelay = psRCParams->InitialDelay;
    psPicParams->sInParams.InitialLevel = psRCParams->InitialLevel;
    psRCParams->InitialQp = psPicParams->sInParams.SeInitQP;

    drv_debug_msg(VIDEO_DEBUG_GENERAL, "InitQP %d, minQP %d, maxQP %d\n",
            psPicParams->sInParams.SeInitQP,
            psPicParams->sInParams.MinQPVal,
            psPicParams->sInParams.MaxQPVal);

    /* The rate control uses this value to adjust the reaction rate
       to larger than expected frames in long GOPS*/

    return;
}


/***********************************************************************************
 * Function Name      : SetupRCData
 * Inputs             :
 * Outputs            :
 * Returns            :
 * Description        : Sets up RC Data
 ************************************************************************************/
void pnw__setup_rcdata(
    context_ENC_p psContext,
    PIC_PARAMS *psPicParams,
    IMG_RC_PARAMS *psRCParams)
{
    IMG_UINT8   ui8InitialSeInitQP;

    /* frameskip is always cleared, specially handled at vaEndPicture */
    psRCParams->FrameSkip = 0;

    if (!psRCParams->BitsPerSecond)
        psRCParams->BitsPerSecond = 64000;
    /*
        if (psRCParams->BitsPerSecond > max_bitrate)
            psRCParams->BitsPerSecond = max_bitrate;
    */
    if (!psRCParams->FrameRate)
        psRCParams->FrameRate = 30;

    pnw__setup_busize(psContext); /* calculate BasicUnitSize */

    psPicParams->sInParams.SeInitQP = psRCParams->InitialQp;

    psPicParams->sInParams.MBPerRow = (psContext->Width >> 4);
    psPicParams->sInParams.MBPerBU = psRCParams->BUSize;
    psPicParams->sInParams.MBPerFrm     = (psContext->Width >> 4) * (psContext->Height >> 4);
    psPicParams->sInParams.BUPerFrm     = (psPicParams->sInParams.MBPerFrm) / psRCParams->BUSize;
    psPicParams->sInParams.AvQPVal = psRCParams->InitialQp;
    psPicParams->sInParams.MyInitQP     = psRCParams->InitialQp;
    psPicParams->sInParams.MaxFrameSize = psRCParams->BitsPerSecond / psRCParams->FrameRate;

    ui8InitialSeInitQP = psPicParams->sInParams.SeInitQP;

    pnw__update_rcdata(psContext, psPicParams, psRCParams);

    /*If MinQP has been set, restore this value rather than
     *the calculated value set by UpdateRCData()*/
    if (psRCParams->MinQP) {
        psPicParams->sInParams.MinQPVal = (IMG_UINT8)psRCParams->MinQP;
    }

    /*If SeInitQP has been set, restore this value and other
     * dependant variables rather than the calculated values set by UpdateRCData()*/
    if (ui8InitialSeInitQP) {
        psPicParams->sInParams.SeInitQP = ui8InitialSeInitQP;
        psPicParams->sInParams.MyInitQP = ui8InitialSeInitQP;
        psRCParams->InitialQp = ui8InitialSeInitQP;
    }

    /* HRD parameters are meaningless without a bitrate
     * HRD parameters are not supported in VCM mode */
    if (psRCParams->BitsPerSecond == 0 || psContext->eCodec == IMG_CODEC_H264_VCM)
         psContext->bInserHRDParams = IMG_FALSE;

    if (psContext->bInserHRDParams) {
        psPicParams->ClockDivBitrate = (90000 * 0x100000000LL);
        psPicParams->ClockDivBitrate /= psRCParams->BitsPerSecond;
        psPicParams->MaxBufferMultClockDivBitrate = (IMG_UINT32)
                (((IMG_UINT64)(psRCParams->BufferSize) * (IMG_UINT64) 90000)
                 / (IMG_UINT64) psRCParams->BitsPerSecond);
    }
    return ;
}

static void pnw__setup_qpvalue_h264(
    MTX_CURRENT_IN_PARAMS * psCurrent,
    IMG_BYTE bySliceQP)
{
    /* H.264 QP scaling tables */
    IMG_BYTE HOST_PVR_QP_SCALE_CR[52] = {
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
        12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
        28, 29, 29, 30, 31, 32, 32, 33, 34, 34, 35, 35, 36, 36, 37, 37,
        37, 38, 38, 38, 39, 39, 39, 39
    };

    psCurrent->bySliceQP = bySliceQP;
    psCurrent->bySliceQPC = HOST_PVR_QP_SCALE_CR[psCurrent->bySliceQP];
}


static void pnw__setup_qpvalues_mpeg4(
    MTX_CURRENT_IN_PARAMS * psCurrent,
    IMG_BYTE bySliceQP)
{
    psCurrent->bySliceQP =      bySliceQP;
}

static void pnw__setup_slice_row_params(
    context_ENC_p ctx,
    IMG_BOOL IsIntra,
    IMG_UINT16 CurrentRowY,
    IMG_INT16 SliceStartRowY,
    IMG_INT16 SliceHeight,
    IMG_BOOL VectorsValid,
    int bySliceQP)
{
    /* Note: CurrentRowY and SliceStartRowY are now in pixels (not MacroBlocks)
     * - saves needless multiplications and divisions
     */
    MTX_CURRENT_IN_PARAMS *psCurrent;
    pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;

    IMG_INT16   iPos, iYPos, srcY;
    IMG_UINT16  ui16tmp;
    IMG_UINT16 ui16SearchWidth, ui16SearchHeight, ui16SearchLeftOffset, ui16SearchTopOffset, ui16CurBlockX;

    if (IsIntra && cmdbuf->topaz_in_params_I_p == NULL) {
        VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_in_params_I, &cmdbuf->topaz_in_params_I_p);
        if (vaStatus != VA_STATUS_SUCCESS) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
            return;
        }
    }

    if ((!IsIntra) && cmdbuf->topaz_in_params_P_p == NULL) {
        VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_in_params_P, &cmdbuf->topaz_in_params_P_p);
        if (vaStatus != VA_STATUS_SUCCESS) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
            return;
        }
    }

    if (IsIntra)
        psCurrent = (MTX_CURRENT_IN_PARAMS*)(cmdbuf->topaz_in_params_I_p + ctx->in_params_ofs);
    else
        psCurrent = (MTX_CURRENT_IN_PARAMS*)(cmdbuf->topaz_in_params_P_p + ctx->in_params_ofs);

    psCurrent += (CurrentRowY  * (ctx->Width) / 256);

    // Note: CurrentRowY and iSliceStartRowY are now in pixels (not MacroBlocks) - saves needless multiplications and divisions

    ui16SearchHeight = min(MVEA_LRB_SEARCH_HEIGHT, ctx->Height);
    ui16SearchWidth = min(MVEA_LRB_SEARCH_WIDTH, ctx->Width);
    ui16SearchLeftOffset = (((ui16SearchWidth / 2) / 16) * 16); // this is the amount of data that gets preloaded
    ui16SearchTopOffset = (((ui16SearchHeight / 2) / 16) * 16);
    ui16CurBlockX = MVEA_LRB_SEARCH_WIDTH - (ui16SearchLeftOffset + 16); // this is our block position relative to the start of the LRB

    if ((iYPos = srcY = CurrentRowY - ui16SearchTopOffset) < 0)
        srcY = 0;
    else if (iYPos > ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16)
        srcY = ctx->HeightMinusLRBSearchHeight;


    /*DDK 243 removed this block of code.*/
    /*if((ctx->eCodec==IMG_CODEC_H263_NO_RC)||(ctx->eCodec==IMG_CODEC_H263_CBR)||(ctx->eCodec==IMG_CODEC_H263_VBR))
      ui16tmp = CurrentRowY;
      else*/
    ui16tmp = (CurrentRowY != SliceStartRowY);

    for (iPos = 0; iPos < ctx->Width; iPos += 16, psCurrent++) {
        memset(psCurrent, 0, sizeof(MTX_CURRENT_IN_PARAMS));
        psCurrent->MVValid = 0;
        psCurrent->ParamsValid = 0;

        if (SliceStartRowY) {
            psCurrent->MVValid = VECTORS_ABOVE_VALID;
        }
        /* Setup the parameters and motion vectors*/
        if (ui16tmp) {
            psCurrent->MVValid = VECTORS_ABOVE_VALID | DO_INTRA_PRED;
            psCurrent->ParamsValid |= PARAMS_ABOVE_VALID;

            if (iPos + 16 < ctx->Width) {
                psCurrent->ParamsValid |= PARAMS_ABOVER_VALID;
                psCurrent->MVValid |= /*VECTORS_LEFT_VALID; //*/(1 << 2); /* Vectors left valid define looks wrong*/
            }

            if (iPos > 0 && (iPos < ctx->Width)) {
                psCurrent->ParamsValid |= PARAMS_ABOVEL_VALID;
                psCurrent->MVValid |= VECTORS_ABOVE_LEFT_VALID; //(1<<0)
            }
        } else {
            // are we the first MB in a new slice?
            if (iPos == 0) {
                if ((ctx->eCodec == IMG_CODEC_H263_NO_RC) || (ctx->eCodec == IMG_CODEC_H263_CBR) || (ctx->eCodec == IMG_CODEC_H263_VBR)) {
                    if (iYPos == -ui16SearchTopOffset)
                        psCurrent->ParamsValid |= MB_START_OF_SLICE;// OPTI?
                } else {
                    psCurrent->ParamsValid |= MB_START_OF_SLICE;// OPTI?
                }
            }
        }
        /*DDK 243 removed this block of code.*/
        /*if((ctx->eCodec==IMG_CODEC_H263_NO_RC) || (ctx->eCodec==IMG_CODEC_H263_CBR)||(ctx->eCodec==IMG_CODEC_H263_VBR))
          {
        // clear the above params valid bits
        psCurrent->ParamsValid &=~(PARAMS_ABOVEL_VALID|PARAMS_ABOVER_VALID|PARAMS_ABOVE_VALID); // OPTI
        }*/
        // Have to fill in the right hand row of 4x4 vectors into the the left block
        if (iPos) {
            psCurrent->MVValid |= DO_INTRA_PRED | (1 << 3); /*MV_VALID define looks wrong?! so use hard coded value for now*/
            psCurrent->ParamsValid |= 8; //(1<<3)
        }
        if (iPos == ctx->Width - 16) {
            // indicate the last MB in a row
            psCurrent->ParamsValid |= MB_END_OF_ROW;
            // are we the last mb in the slice?
            if (iYPos == (SliceStartRowY + SliceHeight - (ui16SearchTopOffset + 16))) {
                psCurrent->ParamsValid |= MB_END_OF_SLICE;
                if (iYPos == ctx->HeightMinus16MinusLRBTopOffset) {
                    psCurrent->ParamsValid |= MB_END_OF_PICTURE;
                }
            }
        }
        // And now the below block
        // should do some kind of check to see if we are the first inter block, as otherwise the vectors will be invalid!
        if (VectorsValid) {
            if (iYPos < ctx->HeightMinus16MinusLRBTopOffset) {
                psCurrent->MVValid |= VECTORS_BELOW_VALID; //(1<<4)

                if (iYPos < ctx->HeightMinus32MinusLRBTopOffset) {
                    psCurrent->MVValid |= VECTORS_2BELOW_VALID; //(1<<5)
                }
            }
        }

        /*Set up IPEMin and Max for coordinate X in the search reference region*/
        /*And set up flags in SPEMax when needed*/
        if (iPos <= ui16SearchLeftOffset) {
            psCurrent->IPEMin[0] = ui16CurBlockX - iPos;
            psCurrent->RealEdge |= SPE_EDGE_LEFT;
        } else {
            psCurrent->IPEMin[0] = ui16CurBlockX / 16;
        }

        if ((iPos + ui16SearchLeftOffset + 16) > ctx->Width) {
            psCurrent->IPEMax[0] = (ui16CurBlockX - 1 + ctx->Width) - iPos; //(112 - 1) - ((iPos + 48+16) - ctx->psVideo->ui16Width);
            psCurrent->RealEdge |= SPE_EDGE_RIGHT;
        } else {
            psCurrent->IPEMax[0] = (ui16CurBlockX + 16 + ui16SearchLeftOffset) - 1 - 3; //(112 - 1) - 3;
        }

        /*Set up IPEMin and Max for Y coordinate in the search reference region*/
        /*And set up flags in SPEMax when needed*/
        if (iYPos <= 0) {
            psCurrent->IPEMin[1] = 0;
            psCurrent->RealEdge |= SPE_EDGE_TOP;
        } else {
            psCurrent->IPEMin[1] = 3;
        }

        //Max Y
        if (iYPos > ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16) {
            psCurrent->IPEMax[1] = ui16SearchHeight - 1;
            psCurrent->RealEdge |= ui16SearchHeight - 4;
        } else {
            psCurrent->IPEMax[1] = ui16SearchHeight - 4;
        }

        psCurrent->CurBlockAddr = ((ui16CurBlockX) / 16);
        psCurrent->CurBlockAddr |= ((IMG_UINT8)(((iYPos + ui16SearchTopOffset) - srcY) / 16) << 4);

        /* Setup the control register values
           These will get setup and transferred to a different location within the macroblock parameter structure.
           They are then read out of the esb by the mtx and used to control the hardware units
           */
        psCurrent->IPEControl = ctx->IPEControl;

        switch (ctx->eCodec) {
        case IMG_CODEC_H263_NO_RC:
        case IMG_CODEC_H263_VBR:
        case IMG_CODEC_H263_CBR:
            pnw__setup_qpvalues_mpeg4(psCurrent, bySliceQP);
            psCurrent->JMCompControl = F_ENCODE(2, MVEA_CR_JMCOMP_MODE);
            psCurrent->VLCControl = F_ENCODE(3, TOPAZ_VLC_CR_CODEC) | F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
            break;
        case IMG_CODEC_MPEG4_NO_RC:
        case IMG_CODEC_MPEG4_VBR:
        case IMG_CODEC_MPEG4_CBR:
            pnw__setup_qpvalues_mpeg4(psCurrent, bySliceQP);
            psCurrent->JMCompControl = F_ENCODE(1, MVEA_CR_JMCOMP_MODE) | F_ENCODE(1, MVEA_CR_JMCOMP_AC_ENABLE);
            psCurrent->VLCControl = F_ENCODE(2, TOPAZ_VLC_CR_CODEC) | F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
            break;
        default:
        case IMG_CODEC_H264_NO_RC:
        case IMG_CODEC_H264_VBR:
        case IMG_CODEC_H264_CBR:
        case IMG_CODEC_H264_VCM:
            pnw__setup_qpvalue_h264(psCurrent, bySliceQP);
            psCurrent->JMCompControl = F_ENCODE(0, MVEA_CR_JMCOMP_MODE);
            psCurrent->VLCControl = F_ENCODE(1, TOPAZ_VLC_CR_CODEC) | F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
            break;
        }
    }

    // now setup the dummy end of frame macroblock.
    if ((CurrentRowY + 16) >= ctx->Height) {
        memset(psCurrent, 0, sizeof(MTX_CURRENT_IN_PARAMS));
        psCurrent->MVValid = DO_INTRA_PRED;
        psCurrent->ParamsValid = 0;
        psCurrent->RealEdge = 0;
    }
}

void pnw_setup_slice_params(
    context_ENC_p  ctx,
    IMG_UINT16 YSliceStartPos,
    IMG_UINT16 SliceHeight,
    IMG_BOOL IsIntra,
    IMG_BOOL  VectorsValid,
    int bySliceQP)
{
    IMG_UINT16 Rows, CurrentRowY;

    Rows = SliceHeight / 16;
    CurrentRowY = YSliceStartPos;

    while (Rows) {
        pnw__setup_slice_row_params(
            ctx,
            IsIntra,
            CurrentRowY,
            YSliceStartPos,
            SliceHeight,
            VectorsValid, bySliceQP);

        CurrentRowY += 16;
        Rows--;
    }

}



IMG_UINT32 pnw__send_encode_slice_params(
    context_ENC_p ctx,
    IMG_BOOL IsIntra,
    IMG_UINT16 CurrentRow,
    IMG_UINT8  DeblockIDC,
    IMG_UINT32 FrameNum,
    IMG_UINT16 SliceHeight,
    IMG_UINT16 CurrentSlice)
{
    SLICE_PARAMS *psSliceParams;
    IMG_INT16 RowOffset;
    IMG_UINT16 SearchHeight, SearchTopOffset;

    psb_buffer_p psCoded;
    object_surface_p ref_surface;
    psb_buffer_p psRef;
    pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;


    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Send encode slice parmas, Is Intra:%d, CurrentRow:%d" \
                             "DeblockIDC:%d, FrameNum:%d, SliceHeight:%d, CurrentSlice:%d\n",
                             IsIntra, CurrentRow, DeblockIDC, FrameNum, SliceHeight, CurrentSlice);

    ref_surface = ctx->ref_surface;
    psRef = &ctx->ref_surface->psb_surface->buf;
    psCoded = ctx->coded_buf->psb_buffer;

    psSliceParams = (SLICE_PARAMS *)(cmdbuf->slice_params_p +
                                     CurrentSlice * ((sizeof(SLICE_PARAMS) + 15) & 0xfff0));

    psSliceParams->SliceHeight = SliceHeight;
    psSliceParams->SliceStartRowNum = CurrentRow / 16;
    psSliceParams->ScanningIntraParams = (1 << SCANNING_INTRA_WIDTH_SHIFT) |
        (1 << SCANNING_INTRA_STEP_SHIFT);

    /* We want multiple ones of these so we can submit multiple slices without having to wait for the next */
    psSliceParams->Flags = 0;
    psSliceParams->HostCtx = 0xdafed123;

#ifdef VA_EMULATOR
    psSliceParams->RefYStride = ref_surface->psb_surface->stride;
    psSliceParams->RefUVStride = ref_surface->psb_surface->stride;
    psSliceParams->RefYRowStride =  ref_surface->psb_surface->stride * 16;
    psSliceParams->RefUVRowStride = ref_surface->psb_surface->stride * 16 / 2;
#else
    psSliceParams->RefYStride = ref_surface->psb_surface->stride;
    psSliceParams->RefUVStride = ref_surface->psb_surface->stride;
    psSliceParams->RefYRowStride =  ref_surface->psb_surface->stride * 16;
    psSliceParams->RefUVRowStride = ref_surface->psb_surface->stride * 16 / 2;
#endif
    psSliceParams->NumAirMBs = ctx->num_air_mbs;
    psSliceParams->AirThreshold = ctx->air_threshold;

    if (ctx->eCodec == IMG_CODEC_H264_VCM && ctx->max_slice_size == 0)
        psSliceParams->MaxSliceSize = ctx->Width * ctx->Height * 12 / 2;
    else
        psSliceParams->MaxSliceSize = ctx->max_slice_size;
    psSliceParams->FCode = ctx->FCode;/* Not clear yet, This field is not appare in firmware doc */

    SearchHeight = min(MVEA_LRB_SEARCH_HEIGHT, ctx->Height);
    SearchTopOffset = (((SearchHeight / 2) / 16) * 16);

    RowOffset = CurrentRow - SearchTopOffset;
    if (RowOffset <= 0)
        RowOffset = 0;
    if (RowOffset > (ctx->Height - SearchHeight))
        RowOffset = (ctx->Height - SearchHeight);
    if (!IsIntra) {
        psSliceParams->Flags |= ISINTER_FLAGS;
    }

    switch (DeblockIDC) {
    case 0:
        psSliceParams->Flags |= DEBLOCK_FRAME;
        break;
    case 2:
        psSliceParams->Flags |= DEBLOCK_SLICE;
        break;
    case 1:
    default:
        // do nothing
        break;
    }

    switch (ctx->eCodec) {
    case IMG_CODEC_H263_NO_RC:
    case IMG_CODEC_H263_VBR:
    case IMG_CODEC_H263_CBR:
        psSliceParams->Flags |= ISH263_FLAGS;
        break;
    case IMG_CODEC_MPEG4_NO_RC:
    case IMG_CODEC_MPEG4_VBR:
    case IMG_CODEC_MPEG4_CBR:
        psSliceParams->Flags |= ISMPEG4_FLAGS;
        break;
    case IMG_CODEC_H264_NO_RC:
    case IMG_CODEC_H264_CBR:
    case IMG_CODEC_H264_VCM:
    case IMG_CODEC_H264_VBR:
        psSliceParams->Flags |= ISH264_FLAGS;
        break;
    default:
        psSliceParams->Flags |= ISH264_FLAGS;
        printf("No format specified defaulting to h.264\n");
        break;
    }
    /* we should also setup the interleaving requirements based on the source format */
    if (ctx->eFormat == IMG_CODEC_PL12) /* FIXME contrary with old DDK, take notice */
        psSliceParams->Flags |= INTERLEAVE_TARGET;

    cmdbuf = ctx->obj_context->pnw_cmdbuf;

    RELOC_SLICE_PARAMS_PNW(&(psSliceParams->RefYBase), 256 * RowOffset / 16, psRef);
    RELOC_SLICE_PARAMS_PNW(&(psSliceParams->RefUVBase),
                           ref_surface->psb_surface->stride * ref_surface->height + (RowOffset * 128 / 16),
                           psRef);
    if (IsIntra)
        RELOC_SLICE_PARAMS_PNW(&(psSliceParams->InParamsBase),
                               ctx->in_params_ofs,
                               //((CurrentRow * (ctx->Width)) / 256 + ctx->obj_context->slice_count) * sizeof(MTX_CURRENT_IN_PARAMS),
                               cmdbuf->topaz_in_params_I);
    else
        RELOC_SLICE_PARAMS_PNW(&(psSliceParams->InParamsBase),
                               ctx->in_params_ofs,
                               //((CurrentRow * (ctx->Width)) / 256 + ctx->obj_context->slice_count) * sizeof(MTX_CURRENT_IN_PARAMS),
                               cmdbuf->topaz_in_params_P);

#if  TOPAZ_PIC_PARAMS_VERBOSE
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "sizeof psSliceParams %d\n", sizeof(*psSliceParams));
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "sizeof MTX_CURRENT_IN_PARAMS %d\n", sizeof(MTX_CURRENT_IN_PARAMS));
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->SliceStartRowNum %d\n", psSliceParams->SliceStartRowNum);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->SliceHeight %d\n", psSliceParams->SliceHeight);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefYBase %x\n", psSliceParams->RefYBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefUVBase %x\n", psSliceParams->RefUVBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefYStride %d\n", psSliceParams->RefYStride);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefUVStride %d\n", psSliceParams->RefUVStride);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefYRowStride %d\n", psSliceParams->RefYRowStride);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefUVRowStride %d\n", psSliceParams->RefUVRowStride);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->HostCtx %x\n", psSliceParams->HostCtx);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->Flags %x\n", psSliceParams->Flags);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->MaxSliceSize %d\n",  psSliceParams->MaxSliceSize);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->FCode %x\n", psSliceParams->FCode);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->InParamsBase %x\n", psSliceParams->InParamsBase);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->NumAirMBs %d\n", psSliceParams->NumAirMBs);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->AirThreshold %x\n", psSliceParams->AirThreshold);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->ScanningIntraParams %x\n", psSliceParams->ScanningIntraParams);
#endif

    pnw_cmdbuf_insert_command_package(ctx->obj_context,
                                      ctx->SliceToCore,
                                      MTX_CMDID_ENCODE_SLICE,
                                      &cmdbuf->slice_params,
                                      CurrentSlice *((sizeof(SLICE_PARAMS) + 15) & 0xfff0));


    return 0;
}



/*
 * Function Name      : Reset_EncoderParams
 * Description        : Reset Above & Below Params at the Start of Intra frame
 */
void pnw_reset_encoder_params(context_ENC_p ctx)
{
    unsigned char *Add_Below, *Add_Above;
    pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;

    /* all frames share the same Topaz param, in_param/aboveparam/bellow
     * map it only when necessary
     */
    if (cmdbuf->topaz_above_params_p == NULL) {
        VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_above_params, &cmdbuf->topaz_above_params_p);
        if (vaStatus != VA_STATUS_SUCCESS) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
            return;
        }
    }

    if (cmdbuf->topaz_below_params_p == NULL) {
        VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_below_params, &cmdbuf->topaz_below_params_p);
        if (vaStatus != VA_STATUS_SUCCESS) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
            return;
        }
    }

    Add_Below = cmdbuf->topaz_below_params_p +
                ctx->below_params_ofs;

    memset(Add_Below, 0, ctx->below_params_size * 4);

    Add_Above = cmdbuf->topaz_above_params_p + ctx->above_params_ofs;
    memset(Add_Above, 0, ctx->above_params_size * MAX_TOPAZ_CORES);
}