C++程序  |  882行  |  32.74 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:
 *    Zeng Li <zeng.li@intel.com>
 *    Shengquan Yuan  <shengquan.yuan@intel.com>
 *    Binglin Chen <binglin.chen@intel.com>
 *
 */


#include "psb_def.h"
#include "psb_surface.h"
#include "psb_cmdbuf.h"
#include "lnc_hostcode.h"
#include "lnc_H264ES.h"
#include "lnc_hostheader.h"
#include "va/va_enc_h264.h"
#include "psb_drv_debug.h"

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>


#define TOPAZ_H264_MAX_BITRATE 14000000 /* FIXME ?? */
#define WORST_CASE_SLICE_HEADER_SIZE 200

#define INIT_CONTEXT_H264ES     context_ENC_p ctx = (context_ENC_p) obj_context->format_data
#define SURFACE(id)    ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id ))
#define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id ))



static void lnc_H264ES_QueryConfigAttributes(
    VAProfile profile,
    VAEntrypoint entrypoint,
    VAConfigAttrib *attrib_list,
    int num_attribs)
{
    int i;

    drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_QueryConfigAttributes\n");

    /* RateControl attributes */
    for (i = 0; i < num_attribs; i++) {
        switch (attrib_list[i].type) {
        case VAConfigAttribRTFormat:
            break;

        case VAConfigAttribRateControl:
            attrib_list[i].value = VA_RC_NONE | VA_RC_CBR | VA_RC_VBR | VA_RC_VCM;
            break;
#if 0
        case VAConfigAttribEncMaxSliceSize:
            attrib_list[i].value = 0;
            break;
#endif
        default:
            attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
            break;
        }
    }
}


static VAStatus lnc_H264ES_ValidateConfig(
    object_config_p obj_config)
{
    int i;
    /* Check all attributes */
    for (i = 0; i < obj_config->attrib_count; i++) {
        switch (obj_config->attrib_list[i].type) {
        case VAConfigAttribRTFormat:
            /* Ignore */
            break;
        case VAConfigAttribRateControl:
            break;
        default:
            return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
        }
    }

    return VA_STATUS_SUCCESS;
}


static VAStatus lnc_H264ES_CreateContext(
    object_context_p obj_context,
    object_config_p obj_config)
{
    VAStatus vaStatus = VA_STATUS_SUCCESS;
    context_ENC_p ctx;
    int i;
    unsigned int eRCmode = 0;

    drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_CreateContext\n");

    vaStatus = lnc_CreateContext(obj_context, obj_config);

    if (VA_STATUS_SUCCESS != vaStatus)
        return VA_STATUS_ERROR_ALLOCATION_FAILED;

    ctx = (context_ENC_p) obj_context->format_data;

    ctx->max_slice_size = 0;
    ctx->delta_change = 1;
    eRCMode = VA_RC_NONE;
    for (i = 0; i < obj_config->attrib_count; i++) {
#if 0
        if (obj_config->attrib_list[i].type == VAConfigAttribEncMaxSliceSize)
            ctx->max_slice_size = obj_config->attrib_list[i].value;
        else if (obj_config->attrib_list[i].type == VAConfigAttribRateControl)
            eRCmode = obj_config->attrib_list[i].value;
#else
        if (obj_config->attrib_list[i].type == VAConfigAttribRateControl)
            eRCmode = obj_config->attrib_list[i].value;
#endif
    }

    drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_CreateContext: max slice size %d\n", ctx->max_slice_size);

    if (eRCmode == VA_RC_VBR) {
        ctx->eCodec = IMG_CODEC_H264_VBR;
        ctx->sRCParams.RCEnable = IMG_TRUE;
    } else if (eRCmode == VA_RC_CBR) {
        ctx->eCodec = IMG_CODEC_H264_CBR;
        ctx->sRCParams.RCEnable = IMG_TRUE;
    } else if (eRCmode == VA_RC_VCM) {
        ctx->eCodec = IMG_CODEC_H264_VCM;
        ctx->sRCParams.RCEnable = IMG_TRUE;
    } else if (eRCmode == VA_RC_NONE) {
        ctx->eCodec = IMG_CODEC_H264_NO_RC;
        ctx->sRCParams.RCEnable = IMG_FALSE;
    } else
        return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
    ctx->eFormat = IMG_CODEC_PL12;      /* use default */

    ctx->IPEControl = lnc__get_ipe_control(ctx->eCodec);
    ctx->idr_pic_id = 1;

    switch (obj_config->profile) {
    case VAProfileH264Baseline:
        ctx->profile_idc = 5;
        break;
    case VAProfileH264Main:
        ctx->profile_idc = 6;
        break;
    default:
        ctx->profile_idc = 6;
        break;
    }

    return vaStatus;
}


static void lnc_H264ES_DestroyContext(
    object_context_p obj_context)
{
    struct coded_buf_aux_info *p_aux_info;
    INIT_CONTEXT_H264ES;
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_DestroyPicture\n");

    while (ctx->p_coded_buf_info != NULL) {
        p_aux_info = ctx->p_coded_buf_info->next;
        free(ctx->p_coded_buf_info);
        ctx->p_coded_buf_info = p_aux_info;
    }
    lnc_DestroyContext(obj_context);
}

static VAStatus lnc_H264ES_BeginPicture(
    object_context_p obj_context)
{
    INIT_CONTEXT_H264ES;
    VAStatus vaStatus = VA_STATUS_SUCCESS;

    drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_BeginPicture\n");

    vaStatus = lnc_BeginPicture(ctx);

    return vaStatus;
}

static VAStatus lnc__H264ES_process_sequence_param(context_ENC_p ctx, object_buffer_p obj_buffer)
{
    VAEncSequenceParameterBufferH264 *pSequenceParams;
    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
    H264_VUI_PARAMS VUI_Params;
    H264_CROP_PARAMS sCrop;
    char hardcoded_qp[4];

    ASSERT(obj_buffer->type == VAEncSequenceParameterBufferType);
    ASSERT(obj_buffer->num_elements == 1);
    ASSERT(obj_buffer->size == sizeof(VAEncSequenceParameterBufferH264));

    if ((obj_buffer->num_elements != 1) ||
        (obj_buffer->size != sizeof(VAEncSequenceParameterBufferH264))) {
        return VA_STATUS_ERROR_UNKNOWN;
    }

    ctx->obj_context->frame_count = 0;

    pSequenceParams = (VAEncSequenceParameterBufferH264 *) obj_buffer->buffer_data;
    obj_buffer->buffer_data = NULL;
    obj_buffer->size = 0;

    if ((ctx->obj_context->frame_count != 0) &&
        (ctx->sRCParams.BitsPerSecond != pSequenceParams->bits_per_second))
        ctx->update_rc_control = 1;

    /* a new sequence and IDR need reset frame_count */
    ctx->obj_context->frame_count = 0;

    if (pSequenceParams->bits_per_second > TOPAZ_H264_MAX_BITRATE) {
        ctx->sRCParams.BitsPerSecond = TOPAZ_H264_MAX_BITRATE;
        drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \
		the maximum bitrate, set it with %d\n",
                                 pSequenceParams->bits_per_second,
                                 TOPAZ_H264_MAX_BITRATE);
    } else
        ctx->sRCParams.BitsPerSecond = pSequenceParams->bits_per_second;

    ctx->sRCParams.Slices = 1;

    ctx->sRCParams.IntraFreq = pSequenceParams->intra_period;
    if (ctx->sRCParams.IntraFreq == 0)
        ctx->sRCParams.IntraFreq = 1000;

    ctx->sRCParams.IDRFreq = pSequenceParams->intra_idr_period;
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "IntraFreq: %d\n, intra_idr_period: %d\n",
                             ctx->sRCParams.IntraFreq, ctx->sRCParams.IDRFreq);

    VUI_Params.Time_Scale = ctx->sRCParams.FrameRate * 2;
    VUI_Params.bit_rate_value_minus1 = ctx->sRCParams.BitsPerSecond / 64 - 1;
    VUI_Params.cbp_size_value_minus1 = ctx->sRCParams.BufferSize / 64 - 1;
    VUI_Params.CBR = 1;
    VUI_Params.initial_cpb_removal_delay_length_minus1 = 0;
    VUI_Params.cpb_removal_delay_length_minus1 = 0;
    VUI_Params.dpb_output_delay_length_minus1 = 0;
    VUI_Params.time_offset_length = 0;

    sCrop.bClip = IMG_FALSE;
    sCrop.LeftCropOffset = 0;
    sCrop.RightCropOffset = 0;
    sCrop.TopCropOffset = 0;
    sCrop.BottomCropOffset = 0;

    if (ctx->RawHeight & 0xf) {
        sCrop.bClip = IMG_TRUE;
        sCrop.BottomCropOffset = (((ctx->RawHeight + 0xf) & (~0xf)) - ctx->RawHeight) / 2;
    }
    if (ctx->RawWidth & 0xf) {
        sCrop.bClip = IMG_TRUE;
        sCrop.RightCropOffset = (((ctx->RawWidth + 0xf) & (~0xf)) - ctx->RawWidth) / 2;
    }

    /* sequence header is always inserted */
    if (ctx->eCodec == IMG_CODEC_H264_NO_RC)
        VUI_Params.CBR = 0;

    lnc__H264_prepare_sequence_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->seq_header_ofs), pSequenceParams->max_num_ref_frames,
                                      pSequenceParams->picture_width_in_mbs,
                                      pSequenceParams->picture_height_in_mbs,
                                      pSequenceParams->vui_parameters_present_flag,
                                      pSequenceParams->vui_parameters_present_flag ? (&VUI_Params) : NULL,
                                      &sCrop,
                                      pSequenceParams->level_idc, ctx->profile_idc);

    lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, 0); /* sequence header */
    RELOC_CMDBUF(cmdbuf->cmd_idx++, ctx->seq_header_ofs, &cmdbuf->header_mem);

    if (0 != ctx->sRCParams.IDRFreq) {
        if (NULL == ctx->save_seq_header_p) {
            ctx->save_seq_header_p = malloc(HEADER_SIZE);
            if (NULL == ctx->save_seq_header_p) {
                drv_debug_msg(VIDEO_DEBUG_ERROR, "Ran out of memory!\n");
                free(pSequenceParams);
                return VA_STATUS_ERROR_ALLOCATION_FAILED;
            }
            memcpy((unsigned char *)ctx->save_seq_header_p,
                   (unsigned char *)(cmdbuf->header_mem_p + ctx->seq_header_ofs),
                   HEADER_SIZE);
        }
    }
    free(pSequenceParams);

    return VA_STATUS_SUCCESS;
}

static VAStatus lnc__H264ES_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer)
{
    VAStatus vaStatus;
    VAEncPictureParameterBufferH264 *pBuffer;
    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
    struct coded_buf_aux_info *p_aux_info;
    int need_sps = 0;

    ASSERT(obj_buffer->type == VAEncPictureParameterBufferType);

    if ((obj_buffer->num_elements != 1) ||
        (obj_buffer->size != sizeof(VAEncPictureParameterBufferH264))) {
        return VA_STATUS_ERROR_UNKNOWN;
    }

    /* Transfer ownership of VAEncPictureParameterBufferH264 data */
    pBuffer = (VAEncPictureParameterBufferH264 *) obj_buffer->buffer_data;
    obj_buffer->buffer_data = NULL;
    obj_buffer->size = 0;

	ctx->ref_surface = SURFACE(pBuffer->ReferenceFrames[0].picture_id);
    ctx->dest_surface = SURFACE(pBuffer->CurrPic.picture_id);
    ctx->coded_buf = BUFFER(pBuffer->coded_buf);

    //ASSERT(ctx->Width == pBuffer->picture_width);
    //ASSERT(ctx->Height == pBuffer->picture_height);

    if ((ctx->sRCParams.IntraFreq != 0) && (ctx->sRCParams.IDRFreq != 0)) { /* period IDR is desired */
        unsigned int is_intra = 0;
        unsigned int intra_cnt = 0;

        ctx->force_idr_h264 = 0;

        if ((ctx->obj_context->frame_count % ctx->sRCParams.IntraFreq) == 0) {
            is_intra = 1; /* suppose current frame is I frame */
            intra_cnt = ctx->obj_context->frame_count / ctx->sRCParams.IntraFreq;
        }

        /* current frame is I frame (suppose), and an IDR frame is desired*/
        if ((is_intra) && ((intra_cnt % ctx->sRCParams.IDRFreq) == 0)) {
            ctx->force_idr_h264 = 1;
            /*When two consecutive access units in decoding order are both IDR access
            * units, the value of idr_pic_id in the slices of the first such IDR
            * access unit shall differ from the idr_pic_id in the second such IDR
            * access unit. We set it with 1 or 0 alternately.*/
            ctx->idr_pic_id = 1 - ctx->idr_pic_id;

            /* it is periodic IDR in the middle of one sequence encoding, need SPS */
            if (ctx->obj_context->frame_count > 0)
                need_sps = 1;

            ctx->obj_context->frame_count = 0;
        }
    }

    /* For H264, PicHeader only needed in the first picture*/
    if (!ctx->obj_context->frame_count) {
        cmdbuf = ctx->obj_context->lnc_cmdbuf;

        if (need_sps) {
            /* reuse the previous SPS */
            drv_debug_msg(VIDEO_DEBUG_GENERAL, "TOPAZ: insert a SPS before IDR frame\n");
            memcpy((unsigned char *)(cmdbuf->header_mem_p + ctx->seq_header_ofs),
                   (unsigned char *)ctx->save_seq_header_p,
                   HEADER_SIZE);

            lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, 0); /* sequence header */
            RELOC_CMDBUF(cmdbuf->cmd_idx++, ctx->seq_header_ofs, &cmdbuf->header_mem);
        }

        lnc__H264_prepare_picture_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->pic_header_ofs));

        lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, 1);/* picture header */
        RELOC_CMDBUF(cmdbuf->cmd_idx++, ctx->pic_header_ofs, &cmdbuf->header_mem);
    }

    /*Record if EOSEQ or EOSTREAM should be appended to the coded buffer.*/
    if (0 != pBuffer->last_picture) {
        drv_debug_msg(VIDEO_DEBUG_GENERAL, "It's the last picture in sequence or stream."
                                 " Will append EOSEQ/EOSTREAM to the coded buffer.\n");
        p_aux_info = calloc(1, sizeof(struct coded_buf_aux_info));
        if (NULL == p_aux_info) {
            free(pBuffer);
            return VA_STATUS_ERROR_ALLOCATION_FAILED;
        }
        p_aux_info->buf = ctx->coded_buf;
        p_aux_info->aux_flag = pBuffer->last_picture;
        if (NULL != ctx->p_coded_buf_info)
            p_aux_info->next = ctx->p_coded_buf_info;
        else
            p_aux_info->next = NULL;

        ctx->p_coded_buf_info = p_aux_info;
    }

    vaStatus = lnc_RenderPictureParameter(ctx);

    free(pBuffer);
    return vaStatus;
}

static VAStatus lnc__H264ES_process_slice_param(context_ENC_p ctx, object_buffer_p obj_buffer)
{
    /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */
    VAEncSliceParameterBuffer *pBuffer;
    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
    unsigned int MBSkipRun, FirstMBAddress;
    PIC_PARAMS *psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p);
    unsigned int i;
    int slice_param_idx;

    ASSERT(obj_buffer->type == VAEncSliceParameterBufferType);

    cmdbuf = ctx->obj_context->lnc_cmdbuf;
    psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;

    /* Transfer ownership of VAEncPictureParameterBufferH264 data */
    pBuffer = (VAEncSliceParameterBuffer *) obj_buffer->buffer_data;
    obj_buffer->size = 0;

    /* save current cmdbuf write pointer for H264 frameskip redo
     * for H264, only slice header need to repatch
     */
    cmdbuf->cmd_idx_saved_frameskip = cmdbuf->cmd_idx;

    if (0 == pBuffer->start_row_number) {
        if (pBuffer->slice_flags.bits.is_intra)
            RELOC_PIC_PARAMS(&psPicParams->InParamsBase, ctx->in_params_ofs, cmdbuf->topaz_in_params_I);
        else
            RELOC_PIC_PARAMS(&psPicParams->InParamsBase, ctx->in_params_ofs, cmdbuf->topaz_in_params_P);
    }

    /*In case the slice number changes*/
    if ((ctx->slice_param_cache != NULL) && (obj_buffer->num_elements != ctx->slice_param_num)) {
        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Slice number changes. Previous value is %d. Now it's %d\n",
                                 ctx->slice_param_num, obj_buffer->num_elements);
        free(ctx->slice_param_cache);
        ctx->slice_param_cache = NULL;
        ctx->slice_param_num = 0;
    }

    if (NULL == ctx->slice_param_cache) {
        ctx->slice_param_num = obj_buffer->num_elements;
        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Allocate %d VAEncSliceParameterBuffer cache buffers\n", 2 * ctx->slice_param_num);
        ctx->slice_param_cache = calloc(2 * ctx->slice_param_num, sizeof(VAEncSliceParameterBuffer));
        if (NULL == ctx->slice_param_cache) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n");
            free(obj_buffer->buffer_data);
            return VA_STATUS_ERROR_ALLOCATION_FAILED;
        }
    }

    for (i = 0; i < obj_buffer->num_elements; i++) {
        /*Todo list:
         *1.Insert Do header command
         *2.setup InRowParams
         *3.setup Slice params
         *4.Insert Do slice command
         * */
        int deblock_on, force_idr = 0;

        if ((pBuffer->slice_height == 0) || (pBuffer->start_row_number >= ctx->Height)) {
            drv_debug_msg(VIDEO_DEBUG_GENERAL, "slice number is %d, but it seems the last %d buffers are empty\n",
                                     obj_buffer->num_elements, obj_buffer->num_elements - i);
            free(obj_buffer->buffer_data);
            obj_buffer->buffer_data = NULL;
            return VA_STATUS_SUCCESS;
        }

        /* set to INTRA frame */
        if (ctx->force_idr_h264 || (ctx->obj_context->frame_count == 0)) {
            force_idr = 1;
            pBuffer->slice_flags.bits.is_intra = 1;
        }

        if ((pBuffer->slice_flags.bits.disable_deblocking_filter_idc == 0)
            || (pBuffer->slice_flags.bits.disable_deblocking_filter_idc == 2))
            deblock_on = IMG_TRUE;
        else
            deblock_on = IMG_FALSE;

        if (ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip)
            MBSkipRun = (ctx->Width * ctx->Height) / 256;
        else
            MBSkipRun = 0;

        FirstMBAddress = (pBuffer->start_row_number * ctx->Width) / 16;
        /* Insert Do Header command, relocation is needed */
        lnc__H264_prepare_slice_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->slice_header_ofs + ctx->obj_context->slice_count * HEADER_SIZE),
                                       pBuffer->slice_flags.bits.is_intra,
                                       pBuffer->slice_flags.bits.disable_deblocking_filter_idc,
                                       ctx->obj_context->frame_count,
                                       FirstMBAddress,
                                       MBSkipRun, force_idr,
                                       pBuffer->slice_flags.bits.uses_long_term_ref,
                                       pBuffer->slice_flags.bits.is_long_term_ref,
                                       ctx->idr_pic_id);

        lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, (ctx->obj_context->slice_count << 2) | 2);
        RELOC_CMDBUF(cmdbuf->cmd_idx++,
                     ctx->slice_header_ofs + ctx->obj_context->slice_count * HEADER_SIZE,
                     &cmdbuf->header_mem);

        if (!(ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip)) {
            if ((ctx->obj_context->frame_count == 0) && (pBuffer->start_row_number == 0) && pBuffer->slice_flags.bits.is_intra)
                lnc_reset_encoder_params(ctx);

            /*The corresponding slice buffer cache*/
            slice_param_idx = (pBuffer->slice_flags.bits.is_intra ? 0 : 1) * ctx->slice_param_num + i;

            if (VAEncSliceParameter_Equal(&ctx->slice_param_cache[slice_param_idx], pBuffer) == 0) {
                drv_debug_msg(VIDEO_DEBUG_GENERAL, "Cache slice%d's parameter buffer at index %d\n", i, slice_param_idx);

                /* cache current param parameters */
                memcpy(&ctx->slice_param_cache[slice_param_idx],
                       pBuffer, sizeof(VAEncSliceParameterBuffer));

                /* Setup InParams value*/
                lnc_setup_slice_params(ctx,
                                       pBuffer->start_row_number * 16,
                                       pBuffer->slice_height * 16,
                                       pBuffer->slice_flags.bits.is_intra,
                                       ctx->obj_context->frame_count > 0,
                                       psPicParams->sInParams.SeInitQP);
            }

            /* Insert do slice command and setup related buffer value */
            lnc__send_encode_slice_params(ctx,
                                          pBuffer->slice_flags.bits.is_intra,
                                          pBuffer->start_row_number * 16,
                                          deblock_on,
                                          ctx->obj_context->frame_count,
                                          pBuffer->slice_height * 16,
                                          ctx->obj_context->slice_count, ctx->max_slice_size);

            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Now frame_count/slice_count is %d/%d\n",
                                     ctx->obj_context->frame_count, ctx->obj_context->slice_count);
        }
        ctx->obj_context->slice_count++;
        pBuffer++; /* Move to the next buffer */

        ASSERT(ctx->obj_context->slice_count < MAX_SLICES_PER_PICTURE);
    }

    free(obj_buffer->buffer_data);
    obj_buffer->buffer_data = NULL;

    return VA_STATUS_SUCCESS;
}

static VAStatus lnc__H264ES_process_misc_param(context_ENC_p ctx, object_buffer_p obj_buffer)
{
    /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */
    VAEncMiscParameterBuffer *pBuffer;
    VAEncMiscParameterRateControl *rate_control_param;
    VAEncMiscParameterAIR *air_param;
    VAEncMiscParameterMaxSliceSize *max_slice_size_param;
    VAEncMiscParameterFrameRate *frame_rate_param;
    unsigned int bit_rate;
    char hardcoded_qp[4];

    VAStatus vaStatus = VA_STATUS_SUCCESS;

    ASSERT(obj_buffer->type == VAEncMiscParameterBufferType);

    /* Transfer ownership of VAEncMiscParameterBuffer data */
    pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data;
    obj_buffer->size = 0;

	//initialize the frame_rate and qp
	rate_control_param->initial_qp=26;
	rate_control_param->min_qp=3;
	frame_rate_param->framerate=30;
	
    switch (pBuffer->type) {
    case VAEncMiscParameterTypeFrameRate:
        frame_rate_param = (VAEncMiscParameterFrameRate *)pBuffer->data;

        if (frame_rate_param->framerate > 65535) {
            vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
            break;
        }

        drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: frame rate changed to %d\n", __FUNCTION__,
                                 frame_rate_param->framerate);

        if (ctx->sRCParams.FrameRate == frame_rate_param->framerate)
            break;

        ctx->sRCParams.FrameRate = frame_rate_param->framerate;
        ctx->sRCParams.BitsPerSecond += ctx->delta_change;
        ctx->delta_change *= -1;
        ctx->update_rc_control = 1;

        break;

    case VAEncMiscParameterTypeRateControl:
        rate_control_param = (VAEncMiscParameterRateControl *)pBuffer->data;

        if (psb_parse_config("PSB_VIDEO_IQP", hardcoded_qp) == 0)
            rate_control_param->initial_qp = atoi(hardcoded_qp);

        if (psb_parse_config("PSB_VIDEO_MQP", hardcoded_qp) == 0)
            rate_control_param->min_qp = atoi(hardcoded_qp);

        if (rate_control_param->initial_qp > 65535 ||
            rate_control_param->min_qp > 65535 ||
            rate_control_param->target_percentage > 65535) {
            vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
            break;
        }

        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Rate control parameter initial_qp=%d, min_qp=%d\n",
                                 rate_control_param->initial_qp,
                                 rate_control_param->min_qp);

        if (rate_control_param->bits_per_second > TOPAZ_H264_MAX_BITRATE) {
            bit_rate = TOPAZ_H264_MAX_BITRATE;
            drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \
                                             the maximum bitrate, set it with %d\n",
                                     rate_control_param->bits_per_second,
                                     TOPAZ_H264_MAX_BITRATE);
        } else {
            bit_rate = rate_control_param->bits_per_second;
        }

        drv_debug_msg(VIDEO_DEBUG_GENERAL, "rate control changed to %d\n",
                                 rate_control_param->bits_per_second);

        if ((rate_control_param->bits_per_second == ctx->sRCParams.BitsPerSecond) &&
            (ctx->sRCParams.VCMBitrateMargin == rate_control_param->target_percentage * 128 / 100) &&
            (ctx->sRCParams.BufferSize == ctx->sRCParams.BitsPerSecond / 1000 * rate_control_param->window_size) &&
            (ctx->sRCParams.MinQP == rate_control_param->min_qp) &&
            (ctx->sRCParams.InitialQp == rate_control_param->initial_qp))
            break;
        else
            ctx->update_rc_control = 1;

        if (rate_control_param->target_percentage != 0)
            ctx->sRCParams.VCMBitrateMargin = rate_control_param->target_percentage * 128 / 100;
        if (rate_control_param->window_size != 0)
            ctx->sRCParams.BufferSize = ctx->sRCParams.BitsPerSecond * rate_control_param->window_size / 1000;
        if (rate_control_param->initial_qp != 0)
            ctx->sRCParams.InitialQp = rate_control_param->initial_qp;
        if (rate_control_param->min_qp != 0)
            ctx->sRCParams.MinQP = rate_control_param->min_qp;

        if ((bit_rate == ctx->sRCParams.BitsPerSecond) || (bit_rate == 0)) {
            ctx->sRCParams.BitsPerSecond += ctx->delta_change;
            ctx->delta_change *= -1;
        } else {
            ctx->sRCParams.BitsPerSecond = bit_rate;
        }

        break;

    case VAEncMiscParameterTypeMaxSliceSize:
        max_slice_size_param = (VAEncMiscParameterMaxSliceSize *)pBuffer->data;

        if (max_slice_size_param->max_slice_size > INT_MAX ||
            (max_slice_size_param->max_slice_size != 0 &&
             max_slice_size_param->max_slice_size < WORST_CASE_SLICE_HEADER_SIZE)) {
            vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
            break;
        }

        if (max_slice_size_param->max_slice_size != 0)
            max_slice_size_param->max_slice_size -= WORST_CASE_SLICE_HEADER_SIZE;

        if (ctx->max_slice_size == max_slice_size_param->max_slice_size)
            break;

        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Max slice size changed to %d\n",
                                 max_slice_size_param->max_slice_size);

        ctx->max_slice_size = max_slice_size_param->max_slice_size;

        break;

    case VAEncMiscParameterTypeAIR:
        air_param = (VAEncMiscParameterAIR *)pBuffer->data;

        if (air_param->air_num_mbs > 65535 ||
            air_param->air_threshold > 65535) {
            vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
            break;
        }

        drv_debug_msg(VIDEO_DEBUG_GENERAL, "air slice size changed to num_air_mbs %d "
                                 "air_threshold %d, air_auto %d\n",
                                 air_param->air_num_mbs, air_param->air_threshold,
                                 air_param->air_auto);

        if (((ctx->Height * ctx->Width) >> 8) < air_param->air_num_mbs)
            air_param->air_num_mbs = ((ctx->Height * ctx->Width) >> 8);
        if (air_param->air_threshold == 0)
            drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: air threshold is set to zero\n",
                                     __FUNCTION__);
        ctx->num_air_mbs = air_param->air_num_mbs;
        ctx->air_threshold = air_param->air_threshold;
        ctx->autotune_air_flag = air_param->air_auto;

        break;

    default:
        vaStatus = VA_STATUS_ERROR_UNKNOWN;
        DEBUG_FAILURE;
        break;
    }

    free(obj_buffer->buffer_data);
    obj_buffer->buffer_data = NULL;

    return vaStatus;
}

static VAStatus lnc_H264ES_RenderPicture(
    object_context_p obj_context,
    object_buffer_p *buffers,
    int num_buffers)
{
    INIT_CONTEXT_H264ES;
    VAStatus vaStatus = VA_STATUS_SUCCESS;
    int i;

    drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_RenderPicture\n");

    for (i = 0; i < num_buffers; i++) {
        object_buffer_p obj_buffer = buffers[i];

        switch (obj_buffer->type) {
        case VAEncSequenceParameterBufferType:
            drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264_RenderPicture got VAEncSequenceParameterBufferType\n");
            vaStatus = lnc__H264ES_process_sequence_param(ctx, obj_buffer);
            DEBUG_FAILURE;
            break;

        case VAEncPictureParameterBufferType:
            drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264_RenderPicture got VAEncPictureParameterBuffer\n");
            vaStatus = lnc__H264ES_process_picture_param(ctx, obj_buffer);
            DEBUG_FAILURE;
            break;

        case VAEncSliceParameterBufferType:
            drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264_RenderPicture got VAEncSliceParameterBufferType\n");
            vaStatus = lnc__H264ES_process_slice_param(ctx, obj_buffer);
            DEBUG_FAILURE;
            break;

        case VAEncMiscParameterBufferType:
            drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264_RenderPicture got VAEncMiscParameterBufferType\n");
            vaStatus = lnc__H264ES_process_misc_param(ctx, obj_buffer);
            DEBUG_FAILURE;
            break;

        default:
            vaStatus = VA_STATUS_ERROR_UNKNOWN;
            DEBUG_FAILURE;
        }
        if (vaStatus != VA_STATUS_SUCCESS) {
            break;
        }
    }

    return vaStatus;
}

static VAStatus lnc_H264ES_EndPicture(
    object_context_p obj_context)
{
    INIT_CONTEXT_H264ES;
    VAStatus vaStatus = VA_STATUS_SUCCESS;

    drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_EndPicture\n");

    vaStatus = lnc_EndPicture(ctx);

    return vaStatus;
}


struct format_vtable_s lnc_H264ES_vtable = {
queryConfigAttributes:
    lnc_H264ES_QueryConfigAttributes,
validateConfig:
    lnc_H264ES_ValidateConfig,
createContext:
    lnc_H264ES_CreateContext,
destroyContext:
    lnc_H264ES_DestroyContext,
beginPicture:
    lnc_H264ES_BeginPicture,
renderPicture:
    lnc_H264ES_RenderPicture,
endPicture:
    lnc_H264ES_EndPicture
};

static inline void lnc_H264_append_EOSEQ(unsigned char *p_buf, unsigned int *p_size)
{
    /*nal_ref_idc should be 0 and nal_ref_idc should be 10 for End of Sequence RBSP*/
    const unsigned char EOSEQ[] = {0x00, 0x00, 0x00, 0x01, 0xa};
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Append %d bytes of End of Sequence RBSP at offset %d\n",
                             sizeof(EOSEQ), *p_size);
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Previous 4 bytes: %x %x %x %x\n", *(p_buf - 3), *(p_buf - 2), *(p_buf - 1), *(p_buf));
    p_buf += *p_size;
    memcpy(p_buf, &EOSEQ[0], sizeof(EOSEQ));
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "After 4 bytes: %x %x %x %x\n", *(p_buf + 1), *(p_buf + 2), *(p_buf + 3), *(p_buf + 4));
    *p_size += sizeof(EOSEQ);
}

static inline void lnc_H264_append_EOSTREAM(unsigned char *p_buf, unsigned int *p_size)
{
    /*nal_ref_idc should be 0 and nal_ref_idc should be 11 for End of Stream RBSP*/
    const unsigned char EOSTREAM[] = {0x00, 0x00, 0x00, 0x01, 0xb};
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Append %d bytes of End of Stream RBSP.\n",
                             sizeof(EOSTREAM));
    p_buf += *p_size;
    memcpy(p_buf, EOSTREAM, sizeof(EOSTREAM));
    *p_size += sizeof(EOSTREAM);
}

VAStatus lnc_H264_append_aux_info(object_context_p obj_context,
                                  object_buffer_p obj_buffer,
                                  unsigned char *buf,
                                  unsigned int *p_size)
{
    INIT_CONTEXT_H264ES;
    struct coded_buf_aux_info *p_aux_info;
    struct coded_buf_aux_info *p_prev_aux_info;

    if (NULL == ctx->p_coded_buf_info ||
        (ctx->eCodec != IMG_CODEC_H264_VBR
         && ctx->eCodec != IMG_CODEC_H264_CBR
         && ctx->eCodec != IMG_CODEC_H264_NO_RC))
        return VA_STATUS_SUCCESS;

    ASSERT(obj_buffer);
    ASSERT(buf);
    ASSERT(p_size);

    p_aux_info = ctx->p_coded_buf_info;
    p_prev_aux_info = ctx->p_coded_buf_info;
    while (p_aux_info != NULL) {
        /*Check if we need to append NAL to this coded buffer*/
        if (p_aux_info->buf == obj_buffer)
            break;
        p_prev_aux_info = p_aux_info;
        p_aux_info = p_aux_info->next;
    }

    if (NULL != p_aux_info) {
        drv_debug_msg(VIDEO_DEBUG_GENERAL, "coded_buf_aux_info 0x%08x\n", p_aux_info->aux_flag);
        if (0 != (p_aux_info->aux_flag & CODED_BUFFER_EOSEQ_FLAG))
            lnc_H264_append_EOSEQ(buf, p_size);

        if (0 != (p_aux_info->aux_flag & CODED_BUFFER_EOSTREAM_FLAG))
            lnc_H264_append_EOSTREAM(buf, p_size);

        if (p_aux_info == ctx->p_coded_buf_info)
            ctx->p_coded_buf_info = p_aux_info->next;
        else
            p_prev_aux_info->next = p_aux_info->next;

        free(p_aux_info);
    }
    return VA_STATUS_SUCCESS;
}