C++程序  |  918行  |  35.64 KB

/*
 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
 *
 * 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:
 *    Zhangfei Zhang <zhangfei.zhang@intel.com>
 *    Mingruo Sun <mingruo.sun@intel.com>
 *
 */
#include "vsp_VPP.h"
#include "vsp_vp8.h"
#include "psb_buffer.h"
#include "psb_surface.h"
#include "vsp_cmdbuf.h"
#include "psb_drv_debug.h"
#include "va/va_enc_vp8.h"

#define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
#define INIT_CONTEXT_VPP    context_VPP_p ctx = (context_VPP_p) obj_context->format_data;
#define CONFIG(id)  ((object_config_p) object_heap_lookup( &driver_data->config_heap, id ))
#define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
#define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &driver_data->buffer_heap, id ))

#define SURFACE(id)    ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id ))

#define KB 1024
#define MB (KB * KB)
#define VSP_VP8ENC_STATE_SIZE (1*MB)

#define ALIGN_TO_128(value) ((value + 128 - 1) & ~(128 - 1))

#define REF_FRAME_WIDTH  1920
#define REF_FRAME_HEIGHT 1088
#define REF_FRAME_BORDER   32

#define VP8_ENC_CBR 0
#define VP8_ENC_CBR_HRD 1

#define XMEM_FRAME_BUFFER_SIZE_IN_BYTE ((REF_FRAME_WIDTH + 2 * REF_FRAME_BORDER) * (REF_FRAME_HEIGHT + 2 * REF_FRAME_BORDER) + \
        2 * ((REF_FRAME_WIDTH + 2 * REF_FRAME_BORDER) >> 1) * (REF_FRAME_HEIGHT / 2 + REF_FRAME_BORDER)) // Allocated for HD

enum filter_status {
    FILTER_DISABLED = 0,
    FILTER_ENABLED
};

typedef struct _Ref_frame_surface {
    struct VssProcPictureVP8 ref_frame_buffers[4];
} ref_frame_surface;

#define FUNCTION_NAME \
    printf("ENTER %s.\n",__FUNCTION__);

#define EXIT_FUNCTION_NAME \
    printf("EXIT %s.\n",__FUNCTION__);


typedef union {
    struct {
        /* force this frame to be a keyframe */
        unsigned int force_kf                       : 1;
        /* don't reference the last frame */
        unsigned int no_ref_last                    : 1;
        /* don't reference the golden frame */
        unsigned int no_ref_gf                      : 1;
        /* don't reference the alternate reference frame */
        unsigned int no_ref_arf                     : 1;

        unsigned int upd_last                     : 1;
        unsigned int upd_gf                     : 2;
        unsigned int upd_arf                     : 2;
        unsigned int no_upd_last                     : 1;
        unsigned int no_upd_gf                     : 1;
        unsigned int no_upd_arf                     : 1;
        unsigned int upd_entropy                     : 1;
    } bits;
    unsigned int value;
} vp8_fw_pic_flags;


static void vsp_VP8_DestroyContext(object_context_p obj_context);

static VAStatus vsp__VP8_check_legal_picture(object_context_p obj_context, object_config_p obj_config);

static void vsp_VP8_QueryConfigAttributes(
    VAProfile __maybe_unused profile,
    VAEntrypoint __maybe_unused entrypoint,
    VAConfigAttrib *attrib_list,
    int num_attribs)
{
    int i;
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s\n", __FUNCTION__);

    for (i = 0; i < num_attribs; i++) {
        switch (attrib_list[i].type) {
        case VAConfigAttribRTFormat:
            break;
        case VAConfigAttribRateControl:
            attrib_list[i].value = VA_RC_CBR | VA_RC_VCM | VA_RC_VBR;
            break;
        case VAConfigAttribEncAutoReference:
            attrib_list[i].value = 1;
            break;
        case VAConfigAttribEncMaxRefFrames:
            attrib_list[i].value = 4;
            break;
        case VAConfigAttribEncRateControlExt:
            attrib_list[i].value = 3;
            break;

        default:
            attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
            break;
        }
    }
}

static VAStatus vsp_VP8_ValidateConfig(
    object_config_p obj_config)
{
    int i;
    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s\n", __FUNCTION__);

    /* 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;
        case VAConfigAttribEncAutoReference:
            break;
        case VAConfigAttribEncMaxRefFrames:
            break;
        case VAConfigAttribEncRateControlExt:
            break;

        default:
            return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
        }
    }

    return VA_STATUS_SUCCESS;
}

void vsp_VP8_set_default_params(struct VssVp8encSequenceParameterBuffer *vp8_seq)
{

    vp8_seq->frame_width = 1280;
    vp8_seq->frame_height = 720;
    vp8_seq->frame_rate = 30;
    vp8_seq->error_resilient = 0;
    vp8_seq->num_token_partitions = 2;
    vp8_seq->kf_mode = 1;
    vp8_seq->kf_min_dist = 0;
    vp8_seq->kf_max_dist = 30;
    vp8_seq->rc_target_bitrate = 2000;
    vp8_seq->rc_min_quantizer = 4;
    vp8_seq->rc_max_quantizer = 63;
    vp8_seq->rc_undershoot_pct = 100;
    vp8_seq->rc_overshoot_pct = 100;
    vp8_seq->rc_end_usage = VP8_ENC_CBR;
    vp8_seq->rc_buf_sz = 6000;
    vp8_seq->rc_buf_initial_sz = 4000;
    vp8_seq->rc_buf_optimal_sz = 5000;
    vp8_seq->max_intra_rate = 0;
    vp8_seq->cyclic_intra_refresh = 0;
    vp8_seq->concatenate_partitions = 1;
    vp8_seq->recon_buffer_mode = vss_vp8enc_seq_param_recon_buffer_mode_per_seq;
    vp8_seq->ts_number_layers = 1;
    vp8_seq->ts_layer_id[0] = 0;
    vp8_seq->ts_rate_decimator[0] = 0;
    vp8_seq->ts_periodicity = 0;
    vp8_seq->ts_target_bitrate[0] = 0;
}

static VAStatus vsp_VP8_CreateContext(
    object_context_p obj_context,
    object_config_p obj_config)
{
    VAStatus vaStatus = VA_STATUS_SUCCESS;
    /* currently vp8 will use vpp's context since they will use the same cmdbuf */
    context_VPP_p ctx;
    int i;

    ctx = (context_VPP_p) calloc(1, sizeof(struct context_VPP_s));
    if (NULL == ctx) {
        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
        DEBUG_FAILURE;
        return vaStatus;
    }

    //set default VP8 sequence params
    vsp_VP8_set_default_params(&ctx->vp8_seq_param);
    ctx->temporal_layer_number = 1;

    for (i = 0; i < obj_config->attrib_count; i++) {
        if (obj_config->attrib_list[i].type == VAConfigAttribRateControl) {
            if (obj_config->attrib_list[i].value == VA_RC_VCM)
               ctx->vp8_seq_param.rc_end_usage = VP8_ENC_CBR_HRD;
            else
               ctx->vp8_seq_param.rc_end_usage = VP8_ENC_CBR;
        }
    }

    /* set size */
    ctx->param_sz = 0;
    ctx->pic_param_sz = ALIGN_TO_128(sizeof(struct VssVp8encPictureParameterBuffer));
    ctx->param_sz += ctx->pic_param_sz;
    ctx->seq_param_sz = ALIGN_TO_128(sizeof(struct VssVp8encSequenceParameterBuffer));
    ctx->param_sz += ctx->seq_param_sz;
    ctx->ref_param_sz = ALIGN_TO_128(sizeof(ref_frame_surface));
    ctx->param_sz += ctx->ref_param_sz;

    /* set offset */
    ctx->pic_param_offset = 0;
    ctx->seq_param_offset = ctx->pic_param_sz;
    ctx->ref_param_offset = ctx->pic_param_sz + ctx->seq_param_sz;


    ctx->context_buf = (psb_buffer_p) calloc(1, sizeof(struct psb_buffer_s));
    if (NULL == ctx->context_buf) {
        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
        DEBUG_FAILURE;
        goto out;
    }

    vaStatus = psb_buffer_create(obj_context->driver_data, VSP_VP8ENC_STATE_SIZE, psb_bt_vpu_only, ctx->context_buf);

    if (VA_STATUS_SUCCESS != vaStatus) {
        goto out;
    }

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

    return vaStatus;

out:
    vsp_VP8_DestroyContext(obj_context);

    if (ctx) {
        if(ctx->context_buf != NULL)
            free(ctx->context_buf);
        free(ctx);
        ctx = NULL;
    }

    return vaStatus;
}

static void vsp_VP8_DestroyContext(
    object_context_p obj_context)
{
    INIT_CONTEXT_VPP;

    if (ctx->context_buf) {
        psb_buffer_destroy(ctx->context_buf);
        free(ctx->context_buf);
        ctx->context_buf = NULL;
    }

    if (ctx->filters) {
        free(ctx->filters);
        ctx->num_filters = 0;
    }

    free(obj_context->format_data);
    obj_context->format_data = NULL;
}

static VAStatus vsp_vp8_process_seqence_param(
    psb_driver_data_p driver_data,
    context_VPP_p ctx,
    object_buffer_p obj_buffer)
{

    VAStatus vaStatus = VA_STATUS_SUCCESS;
    vsp_cmdbuf_p cmdbuf = ctx->obj_context->vsp_cmdbuf;
    int i;
    int ref_frame_width, ref_frame_height, ref_chroma_height, ref_size;

    VAEncSequenceParameterBufferVP8 *va_seq =
        (VAEncSequenceParameterBufferVP8 *) obj_buffer->buffer_data;
    struct VssVp8encSequenceParameterBuffer *seq = &ctx->vp8_seq_param;
    struct VssVp8encSequenceParameterBuffer *seq_to_firmware =
        (struct VssVp8encSequenceParameterBuffer *)cmdbuf->seq_param_p;

    struct ref_frame_surface *ref =
        (struct ref_frame_surface*)cmdbuf->ref_param_p;

    seq->frame_width       = va_seq->frame_width;
    seq->frame_height      = va_seq->frame_height;
    seq->rc_target_bitrate = va_seq->bits_per_second / 1000;
    seq->max_intra_rate    = 100 * ctx->max_frame_size /
                             (va_seq->bits_per_second / seq->frame_rate);
    /* FIXME: API doc says max 5000, but for current default test vector we still use 6000 */
    seq->kf_mode           = va_seq->kf_auto;   /* AUTO */
    seq->kf_max_dist       = va_seq->kf_max_dist;
    seq->kf_min_dist       = va_seq->kf_min_dist;
    seq->error_resilient   = va_seq->error_resilient;

    ref_frame_width = (seq->frame_width + 2 * 32 + 63) & (~63);
    ref_frame_height = (seq->frame_height + 2 * 32 + 63) & (~63);
    ref_chroma_height = (ref_frame_height / 2 + 63) & (~63);
    ref_size = ref_frame_width * (ref_frame_height + ref_chroma_height);

    for (i = 0; i < 4; i++) {
        seq->ref_frame_buffers[i].surface_id = va_seq->reference_frames[i];
        seq->ref_frame_buffers[i].width = ref_frame_width;
        seq->ref_frame_buffers[i].height = ref_frame_height;
    }

    for (i = 0; i < 4; i++) {
        object_surface_p ref_surf = SURFACE(va_seq->reference_frames[i]);
        if (!ref_surf)
            return VA_STATUS_ERROR_UNKNOWN;

        ref_surf->is_ref_surface = 2;

        if (ref_surf->psb_surface->size < ref_size) {
            /* re-alloc buffer */
            ref_surf->psb_surface->size = ref_size;
            psb_buffer_destroy(&ref_surf->psb_surface->buf);
            vaStatus = psb_buffer_create(driver_data, ref_surf->psb_surface->size, psb_bt_surface, &ref_surf->psb_surface->buf);
            if (VA_STATUS_SUCCESS != vaStatus)
                return VA_STATUS_ERROR_ALLOCATION_FAILED;
        }

        vsp_cmdbuf_reloc_pic_param(&(seq->ref_frame_buffers[i].base),
                                   0,
                                   &(ref_surf->psb_surface->buf),
                                   cmdbuf->param_mem_loc, seq);
    }

    *seq_to_firmware = *seq;

    vsp_cmdbuf_insert_command(cmdbuf, CONTEXT_VP8_ID, &cmdbuf->param_mem,
                              VssVp8encSetSequenceParametersCommand,
                              ctx->seq_param_offset,
                              sizeof(struct VssVp8encSequenceParameterBuffer));
    ctx->vp8_seq_cmd_send = 1;

    return vaStatus;
}

static VAStatus vsp_vp8_process_dynamic_seqence_param(
    context_VPP_p ctx)
{

    VAStatus vaStatus = VA_STATUS_SUCCESS;
    vsp_cmdbuf_p cmdbuf = ctx->obj_context->vsp_cmdbuf;
    int ref_frame_width, ref_frame_height;

    struct VssVp8encSequenceParameterBuffer *seq =
        (struct VssVp8encSequenceParameterBuffer *)cmdbuf->seq_param_p;

    *seq = ctx->vp8_seq_param ;
    seq->max_intra_rate    = 100 * ctx->max_frame_size /
                             (seq->rc_target_bitrate * 1000 / seq->frame_rate);

    if (!ctx->vp8_seq_cmd_send) {
        vsp_cmdbuf_insert_command(cmdbuf, CONTEXT_VP8_ID, &cmdbuf->param_mem,
                                  VssVp8encSetSequenceParametersCommand,
                                  ctx->seq_param_offset,
                                  sizeof(struct VssVp8encSequenceParameterBuffer));
    }

    return vaStatus;
}


static VAStatus vsp_vp8_process_picture_param(
    psb_driver_data_p driver_data,
    context_VPP_p ctx,
    object_buffer_p obj_buffer,
    VASurfaceID surface_id)

{
    VAStatus vaStatus = VA_STATUS_SUCCESS;
    vsp_cmdbuf_p cmdbuf = ctx->obj_context->vsp_cmdbuf;

    VAEncPictureParameterBufferVP8 *va_pic =
        (VAEncPictureParameterBufferVP8 *) obj_buffer->buffer_data;
    struct VssVp8encPictureParameterBuffer *pic =
        (struct VssVp8encPictureParameterBuffer *)cmdbuf->pic_param_p;
    struct VssVp8encSequenceParameterBuffer *seq =
        (struct VssVp8encSequenceParameterBuffer *)cmdbuf->seq_param_p;
    int ref_frame_width, ref_frame_height;
    vp8_fw_pic_flags flags;

    ref_frame_width = (ctx->vp8_seq_param.frame_width + 2 * 32 + 63) & (~63);
    ref_frame_height = (ctx->vp8_seq_param.frame_height + 2 * 32 + 63) & (~63);

    //map parameters
    object_buffer_p pObj = BUFFER(va_pic->coded_buf); //tobe modified
    if (!pObj)
        return VA_STATUS_ERROR_UNKNOWN;

    object_surface_p src_surface = SURFACE(surface_id);

    pic->input_frame.surface_id = surface_id;
    pic->input_frame.irq        = 1;
    pic->input_frame.height     = ctx->vp8_seq_param.frame_height;
    pic->input_frame.width      = ctx->vp8_seq_param.frame_width;
    /* NOTE: In VIED API doc, stride must be the nearest integer multiple of 32 */
    /* use vaCreateSurfaceWithAttribute with VAExternalMemoryNULL to create surface*/
    //pic->input_frame.stride     = (ctx->frame_width + 31) & (~31);
    pic->input_frame.stride     = ctx->obj_context->current_render_target->psb_surface->stride;
    pic->input_frame.format     = 0; /* TODO: Specify NV12 = 0 */

    pic->recon_frame.irq = 0;
    pic->recon_frame.width = ref_frame_width;
    pic->recon_frame.height = ref_frame_height;

    pic->version = 0;

    flags.value = 0;
    flags.bits.force_kf = va_pic->ref_flags.bits.force_kf;
    flags.bits.no_ref_last = va_pic->ref_flags.bits.no_ref_last;
    flags.bits.no_ref_gf = va_pic->ref_flags.bits.no_ref_gf;
    flags.bits.no_ref_arf = va_pic->ref_flags.bits.no_ref_arf;
    flags.bits.upd_last  = va_pic->pic_flags.bits.refresh_last;
    flags.bits.upd_gf  = va_pic->pic_flags.bits.copy_buffer_to_golden;
    flags.bits.upd_arf  = va_pic->pic_flags.bits.copy_buffer_to_alternate;
    flags.bits.no_upd_last  = !va_pic->pic_flags.bits.refresh_last;
    flags.bits.no_upd_gf  = !va_pic->pic_flags.bits.refresh_golden_frame;
    flags.bits.no_upd_arf  = !va_pic->pic_flags.bits.refresh_alternate_frame;
    flags.bits.upd_entropy  = va_pic->pic_flags.bits.refresh_entropy_probs;
    if (ctx->temporal_layer_number > 1)
        flags.bits.upd_entropy = 0;
    pic->pic_flags = flags.value;

    pic->prev_frame_dropped = 0; /* Not yet used */
    pic->cpuused            = 5;
    pic->sharpness          = va_pic->sharpness_level;
    pic->num_token_partitions = va_pic->pic_flags.bits.num_token_partitions; /* 2^2 = 4 partitions */
    pic->encoded_frame_size = pObj->size & ~31;
    pic->encoded_frame_base = (uint32_t)pObj->buffer_data;

    {
        vsp_cmdbuf_reloc_pic_param(&(pic->encoded_frame_base),
                                   ctx->pic_param_offset, pObj->psb_buffer,
                                   cmdbuf->param_mem_loc, pic);
    }

    {
        object_surface_p cur_surf = SURFACE(surface_id);
        if (!cur_surf)
            return VA_STATUS_ERROR_UNKNOWN;

        vsp_cmdbuf_reloc_pic_param(&(pic->input_frame.base),
                                   0, &(cur_surf->psb_surface->buf),
                                   cmdbuf->param_mem_loc, pic);
        vsp_cmdbuf_reloc_pic_param(&(pic->input_frame.base_uv),
                                   pic->input_frame.stride * ctx->obj_context->current_render_target->height,
                                   &(cur_surf->psb_surface->buf),
                                   cmdbuf->param_mem_loc, pic);
    }

    *cmdbuf->cmd_idx++ = CONTEXT_VP8_ID;
    *cmdbuf->cmd_idx++ = VssVp8encEncodeFrameCommand;
    VSP_RELOC_CMDBUF(cmdbuf->cmd_idx++, ctx->pic_param_offset, &cmdbuf->param_mem);
    *cmdbuf->cmd_idx++ = sizeof(struct VssVp8encPictureParameterBuffer);
    *cmdbuf->cmd_idx++ = 0;
    *cmdbuf->cmd_idx++ = 0;
    *cmdbuf->cmd_idx++ = wsbmKBufHandle(wsbmKBuf(pObj->psb_buffer->drm_buf)) ;
    *cmdbuf->cmd_idx++ = wsbmKBufHandle(wsbmKBuf((&cmdbuf->param_mem)->drm_buf));

    return vaStatus;
}

static VAStatus vsp_vp8_process_misc_param(context_VPP_p ctx, object_buffer_p obj_buffer)
{
    VAEncMiscParameterBuffer *pBuffer;
    VAEncMiscParameterAIR *air_param;
    VAEncMiscParameterBufferMaxFrameSize *max_frame_size_param;
    VAEncMiscParameterFrameRate *frame_rate_param;
    VAEncMiscParameterRateControl *rate_control_param;
    VAEncMiscParameterHRD *hrd_param;
    VAEncMiscParameterTemporalLayerStructure* tslayer_param;
    struct VssVp8encSequenceParameterBuffer *seq = &ctx->vp8_seq_param;
    VAStatus vaStatus = VA_STATUS_SUCCESS;
    uint32_t layer_id, i;

    ASSERT(obj_buffer->type == VAEncMiscParameterBufferType);
    pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data;
    obj_buffer->size = 0;

    switch (pBuffer->type) {
    case VAEncMiscParameterTypeTemporalLayerStructure:
        tslayer_param = (VAEncMiscParameterTemporalLayerStructure *)pBuffer->data;
        //verify parameter
        if (tslayer_param->number_of_layers < 2 && tslayer_param->number_of_layers > 3) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "Temporal Layer Number should be 2 or 3\n");
            vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
            break;
        }

        if (tslayer_param->periodicity > 32 || tslayer_param->periodicity < 1) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "ts_periodicity shoulde be 1 - 32\n");
            vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
            break;
        }

        for (i = 0; i < tslayer_param->periodicity; i++) {
            layer_id = tslayer_param->layer_id[i];
            if (layer_id > (tslayer_param->number_of_layers - 1)) {
                drv_debug_msg(VIDEO_DEBUG_ERROR, "layer_id shoulde be 0 - %d\n",
                              tslayer_param->number_of_layers - 1);
                vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
                break;
            }
        }

        if (vaStatus == VA_STATUS_ERROR_INVALID_PARAMETER)
            break;

        seq->ts_number_layers = tslayer_param->number_of_layers;
        ctx->temporal_layer_number = tslayer_param->number_of_layers;
        seq->ts_periodicity = tslayer_param->periodicity;

        for (i = 0; i < seq->ts_periodicity; i++)
            seq->ts_layer_id[i] = tslayer_param->layer_id[i];

        //set default bitrate and framerate
        if (seq->ts_number_layers == 2) {
            seq->ts_target_bitrate[0] = seq->rc_target_bitrate * 6 / 10;
            seq->ts_target_bitrate[1] = seq->rc_target_bitrate ;
            seq->ts_rate_decimator[0] = 2;
            seq->ts_rate_decimator[1] = 1;
        }
        if (seq->ts_number_layers == 3) {
            seq->ts_target_bitrate[0] = seq->rc_target_bitrate * 4 / 10;
            seq->ts_target_bitrate[1] = seq->rc_target_bitrate * 6 / 10;
            seq->ts_target_bitrate[2] = seq->rc_target_bitrate ;
            seq->ts_rate_decimator[0] = 4;
            seq->ts_rate_decimator[1] = 2;
            seq->ts_rate_decimator[2] = 1;
        }

        ctx->re_send_seq_params = 1;
        break;
    case VAEncMiscParameterTypeFrameRate:
        frame_rate_param = (VAEncMiscParameterFrameRate *)pBuffer->data;
        if (frame_rate_param->framerate > 120) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%d is invalid."
                          "framerate could not be larger than 120\n",
                          frame_rate_param->framerate);
            frame_rate_param->framerate = 120;
        }
        if (frame_rate_param->framerate < 1) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%d is invalid."
                          "framerate could not be smaller than 1\n",
                          frame_rate_param->framerate);
            frame_rate_param->framerate = 1;
        }

        if (ctx->temporal_layer_number == 1) {
            if (seq->frame_rate != frame_rate_param->framerate) {
                drv_debug_msg(VIDEO_DEBUG_GENERAL, "frame rate changed from %d to %d\n",
                              seq->frame_rate,
                              frame_rate_param->framerate);
                seq->frame_rate = frame_rate_param->framerate;
                ctx->re_send_seq_params = 1;
            }
        } else {
            layer_id = frame_rate_param->framerate_flags.bits.temporal_id % 3;
            if (ctx->frame_rate[layer_id] != frame_rate_param->framerate) {
                drv_debug_msg(VIDEO_DEBUG_GENERAL, "frame rate of layer %d will be changed from %d to %d\n",
                              layer_id, ctx->frame_rate[layer_id], frame_rate_param->framerate);
                ctx->frame_rate[layer_id] = frame_rate_param->framerate;
                if (layer_id == ctx->temporal_layer_number - 1) { //top layer
                    seq->frame_rate = ctx->frame_rate[layer_id];
                }
                ctx->re_send_seq_params = 1 ;
            }
        }
        break;
    case VAEncMiscParameterTypeRateControl:
        rate_control_param = (VAEncMiscParameterRateControl *)pBuffer->data;
        if (rate_control_param->max_qp > 63 ||
            rate_control_param->min_qp > 63) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "max_qp(%d) and min_qp(%d) "
                          "are invalid.\nQP shouldn't be larger than 63 for VP8\n",
                          rate_control_param->max_qp, rate_control_param->min_qp);
            rate_control_param->max_qp = 63;
            rate_control_param->min_qp = rate_control_param->max_qp;
        }

        if (rate_control_param->min_qp != seq->rc_min_quantizer) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "min_qp was changed from %d to %d\n",
                          seq->rc_min_quantizer, rate_control_param->min_qp);
            seq->rc_min_quantizer = rate_control_param->min_qp;
        }

        if (rate_control_param->max_qp != seq->rc_max_quantizer) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "max_qp was changed from %d to %d\n",
                          seq->rc_max_quantizer, rate_control_param->max_qp);
            seq->rc_max_quantizer = rate_control_param->max_qp;
        }

        // no initial qp for vp8

        if (rate_control_param->target_percentage != seq->rc_undershoot_pct) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "rc_undershoot was changed from %d to %d\n",
                          seq->rc_undershoot_pct, rate_control_param->target_percentage);
            seq->rc_undershoot_pct = rate_control_param->target_percentage;
        }

        if (rate_control_param->bits_per_second / 1000 > 20000) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%d is invalid."
                          "bitrate could not be larger than 20000\n",
                          rate_control_param->bits_per_second / 1000);
            rate_control_param->bits_per_second = 20000000;
        }

        if (ctx->temporal_layer_number == 1) {
            if (rate_control_param->bits_per_second / 1000 != seq->rc_target_bitrate) {
                drv_debug_msg(VIDEO_DEBUG_ERROR, "bitrate was changed from %dkbps to %dkbps\n",
                              seq->rc_target_bitrate, rate_control_param->bits_per_second / 1000);
                seq->rc_target_bitrate = rate_control_param->bits_per_second / 1000;
                seq->ts_target_bitrate[0] = rate_control_param->bits_per_second / 1000;

            }
        } else {
            layer_id = rate_control_param->rc_flags.bits.temporal_id % 3;
            if (rate_control_param->bits_per_second / 1000 != seq->ts_target_bitrate[layer_id]) {
                drv_debug_msg(VIDEO_DEBUG_ERROR, "bitrate was changed from %dkbps to %dkbps\n",
                              seq->ts_target_bitrate[layer_id], rate_control_param->bits_per_second / 1000);
                seq->ts_target_bitrate[layer_id] = rate_control_param->bits_per_second / 1000;
            }
        }

        ctx->re_send_seq_params = 1;
        break;
    case VAEncMiscParameterTypeMaxFrameSize:
        max_frame_size_param = (VAEncMiscParameterBufferMaxFrameSize *)pBuffer->data;
        if (ctx->max_frame_size == max_frame_size_param->max_frame_size)
            break;

        drv_debug_msg(VIDEO_DEBUG_ERROR, "max frame size changed from %d to %d\n",
                      ctx->max_frame_size, max_frame_size_param->max_frame_size);
        ctx->max_frame_size = max_frame_size_param->max_frame_size ;
        ctx->re_send_seq_params = 1 ;
        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);
        seq->cyclic_intra_refresh = air_param->air_threshold;
        break;
    case VAEncMiscParameterTypeHRD:
        hrd_param = (VAEncMiscParameterHRD *)pBuffer->data;
        seq->rc_buf_sz = hrd_param->buffer_size;
        seq->rc_buf_initial_sz = hrd_param->initial_buffer_fullness;
        seq->rc_buf_optimal_sz = hrd_param->optimal_buffer_fullness;
        ctx->re_send_seq_params = 1;
        break;
    case VAEncMiscParameterTypeQualityLevel:
        break;

    default:
        vaStatus = VA_STATUS_ERROR_UNKNOWN;
        DEBUG_FAILURE;
        break;
    }

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

    return vaStatus;
}
static VAStatus vsp_VP8_RenderPicture(
    object_context_p obj_context,
    object_buffer_p *buffers,
    int num_buffers)
{

    int i;
    psb_driver_data_p driver_data = obj_context->driver_data;
    INIT_CONTEXT_VPP;
    VASurfaceID surface_id;
    VAStatus vaStatus = VA_STATUS_SUCCESS;

    for (i = 0; i < num_buffers; i++) {

        object_buffer_p obj_buffer = buffers[i];
        switch (obj_buffer->type) {
        case VAEncSequenceParameterBufferType:
            vaStatus = vsp_vp8_process_seqence_param(driver_data, ctx, obj_buffer);
            break;
        case VAEncPictureParameterBufferType:
            surface_id = obj_context->current_render_surface_id;
            vaStatus = vsp_vp8_process_picture_param(driver_data, ctx, obj_buffer, surface_id);
            break;
        case VAEncMiscParameterBufferType:
            vaStatus = vsp_vp8_process_misc_param(ctx, obj_buffer);
            break;
        default:
            vaStatus = VA_STATUS_SUCCESS;//VA_STATUS_ERROR_UNKNOWN;
            DEBUG_FAILURE;
        }

        if (vaStatus != VA_STATUS_SUCCESS) {
            break;
        }
    }

    return vaStatus;
}

static VAStatus vsp_VP8_BeginPicture(
    object_context_p obj_context)
{
    int ret;
    VAStatus vaStatus = VA_STATUS_SUCCESS;
    INIT_CONTEXT_VPP;
    vsp_cmdbuf_p cmdbuf;

    /* Initialise the command buffer */
    ret = vsp_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 = obj_context->vsp_cmdbuf;

    if (ctx->obj_context->frame_count == 0) { /* first picture */
        vsp_cmdbuf_insert_command(cmdbuf, CONTEXT_VP8_ID, ctx->context_buf, Vss_Sys_STATE_BUF_COMMAND,
                                  0, VSP_VP8ENC_STATE_SIZE);
    }

    /* map param mem */
    vaStatus = psb_buffer_map(&cmdbuf->param_mem, &cmdbuf->param_mem_p);
    if (vaStatus) {
        return vaStatus;
    }

    cmdbuf->pic_param_p = cmdbuf->param_mem_p;
    cmdbuf->seq_param_p = cmdbuf->param_mem_p + ctx->seq_param_offset;
    cmdbuf->ref_param_p = cmdbuf->param_mem_p + ctx->ref_param_offset;
    ctx->vp8_seq_cmd_send = 0;
    ctx->re_send_seq_params = 0;

    return VA_STATUS_SUCCESS;
}

static inline void  dump_vssporcPicture(struct VssProcPictureVP8 * frame)
{
    drv_debug_msg(VIDEO_ENCODE_DEBUG, "surface_id 0x%08x\n", frame->surface_id);
    drv_debug_msg(VIDEO_ENCODE_DEBUG, "irq %d\n", frame->irq);
    drv_debug_msg(VIDEO_ENCODE_DEBUG, "base 0x%08x\n", frame->base);
    drv_debug_msg(VIDEO_ENCODE_DEBUG, "base_uv 0x%08x\n", frame->base_uv);
    drv_debug_msg(VIDEO_ENCODE_DEBUG, "height %d\n", frame->height);
    drv_debug_msg(VIDEO_ENCODE_DEBUG, "width %d\n", frame->width);
    drv_debug_msg(VIDEO_ENCODE_DEBUG, "stride %d\n", frame->stride);
    drv_debug_msg(VIDEO_ENCODE_DEBUG, "format %d\n", frame->format);
}

static void vsp_vp8_dump_commands(vsp_cmdbuf_p cmdbuf)
{
    unsigned int i, cmd_idx;
    unsigned int cmdbuffer_size = (unsigned char *)cmdbuf->cmd_idx - cmdbuf->cmd_start; /* In bytes */
    unsigned int cmd_number = cmdbuffer_size / sizeof(struct vss_command_t);
    struct vss_command_t *cmd = (struct vss_command_t *)cmdbuf->cmd_start;
    struct VssVp8encPictureParameterBuffer *pic =
        (struct VssVp8encPictureParameterBuffer *)cmdbuf->pic_param_p;
    struct VssVp8encSequenceParameterBuffer *seq =
        (struct VssVp8encSequenceParameterBuffer *)cmdbuf->seq_param_p;

    for (cmd_idx = 0; cmd_idx < cmd_number; cmd_idx++) {
        drv_debug_msg(VIDEO_ENCODE_DEBUG, "\n============command start============\ncontext %d\ntype%d\n",
                      cmd[cmd_idx].context, cmd[cmd_idx].type);
        if (cmd[cmd_idx].type == VssVp8encEncodeFrameCommand) {
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "input frame\n");
            dump_vssporcPicture(&pic->input_frame);

            drv_debug_msg(VIDEO_ENCODE_DEBUG, "recon frame\n");
            dump_vssporcPicture(&pic->recon_frame);

            drv_debug_msg(VIDEO_ENCODE_DEBUG, "version %d\n", pic->version);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "pic_flags 0x%08x\n", pic->pic_flags);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "prev_frame_dropped %d\n", pic->prev_frame_dropped);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "cpuused %d\n", pic->cpuused);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "sharpness %d\n", pic->sharpness);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "num_token_partitions %d\n", pic->num_token_partitions);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "encoded_frame_size %d\n", pic->encoded_frame_size);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "encoded_frame_base 0x%08x\n", pic->encoded_frame_base);
        }

        if (cmd[cmd_idx].type == VssVp8encSetSequenceParametersCommand) {
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "frame_width %d\n", seq->frame_width);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "frame_height %d\n", seq->frame_height);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "frame_rate %d\n", seq->frame_rate);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "error_resilient %d\n", seq->error_resilient);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "num_token_partitions %d\n", seq->num_token_partitions);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "kf_mode %d\n", seq->kf_mode);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "kf_min_dist %d\n", seq->kf_min_dist);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "kf_max_dist %d\n", seq->kf_max_dist);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "rc_target_bitrate %d\n", seq->rc_target_bitrate);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "rc_min_quantizer %d\n", seq->rc_min_quantizer);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "rc_max_quantizer %d\n", seq->rc_max_quantizer);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "rc_undershoot_pct %d\n", seq->rc_undershoot_pct);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "rc_overshoot_pct %d\n", seq->rc_overshoot_pct);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "rc_end_usage %d\n", seq->rc_end_usage);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "rc_buf_sz %d\n", seq->rc_buf_sz);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "rc_buf_initial_sz %d\n", seq->rc_buf_initial_sz);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "rc_buf_optimal_sz %d\n", seq->rc_buf_optimal_sz);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "max_intra_rate %d\n", seq->max_intra_rate);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "cyclic_intra_refresh %d\n", seq->cyclic_intra_refresh);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "concatenate_partitions %d\n", seq->concatenate_partitions);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "recon_buffer_mode %d\n", seq->recon_buffer_mode);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "ts_number_layers %d\n", seq->ts_number_layers);

            for (i = 0; i < 3; i++)
                drv_debug_msg(VIDEO_ENCODE_DEBUG, "ts_target_bitrate[%d] %d\n", i, seq->ts_target_bitrate[i]);

            for (i = 0; i < 3; i++)
                drv_debug_msg(VIDEO_ENCODE_DEBUG, "ts_rate_decimator[%d] %d\n", i, seq->ts_rate_decimator[i]);
            drv_debug_msg(VIDEO_ENCODE_DEBUG, "ts_periodicity %d\n", seq->ts_periodicity);

            for (i = 0; i < seq->ts_periodicity; i++)
                drv_debug_msg(VIDEO_ENCODE_DEBUG, "ts_layer_id[%d] %d\n", i, seq->ts_layer_id[i]);

            for (i = 0; i < 4; i++) {
                drv_debug_msg(VIDEO_ENCODE_DEBUG, "ref_frame_buffer %d\n", i);
                dump_vssporcPicture(&seq->ref_frame_buffers[i]);
            }
        }

        drv_debug_msg(VIDEO_ENCODE_DEBUG, "============command end============\n");
    }
}


static VAStatus vsp_VP8_EndPicture(
    object_context_p obj_context)
{
    INIT_CONTEXT_VPP;
    psb_driver_data_p driver_data = obj_context->driver_data;
    vsp_cmdbuf_p cmdbuf = obj_context->vsp_cmdbuf;

    if (ctx->re_send_seq_params) {
        vsp_vp8_process_dynamic_seqence_param(ctx);
    }

    drv_debug_msg(VIDEO_ENCODE_DEBUG, "ctx->obj_context->frame_count=%d\n", ctx->obj_context->frame_count + 1);
    vsp_vp8_dump_commands(cmdbuf);

    if (cmdbuf->param_mem_p != NULL) {
        psb_buffer_unmap(&cmdbuf->param_mem);
        cmdbuf->param_mem_p = NULL;
        cmdbuf->pic_param_p = NULL;
        cmdbuf->end_param_p = NULL;
        cmdbuf->pipeline_param_p = NULL;
        cmdbuf->denoise_param_p = NULL;
        cmdbuf->enhancer_param_p = NULL;
        cmdbuf->sharpen_param_p = NULL;
        cmdbuf->frc_param_p = NULL;
        cmdbuf->ref_param_p = NULL;
    }

    if (vsp_context_flush_cmdbuf(ctx->obj_context)) {
        drv_debug_msg(VIDEO_DEBUG_GENERAL, "psb_VP8: flush deblock cmdbuf error\n");
        return VA_STATUS_ERROR_UNKNOWN;
    }

    return VA_STATUS_SUCCESS;
}

struct format_vtable_s vsp_VP8_vtable = {
queryConfigAttributes:
    vsp_VP8_QueryConfigAttributes,
validateConfig:
    vsp_VP8_ValidateConfig,
createContext:
    vsp_VP8_CreateContext,
destroyContext:
    vsp_VP8_DestroyContext,
beginPicture:
    vsp_VP8_BeginPicture,
renderPicture:
    vsp_VP8_RenderPicture,
endPicture:
    vsp_VP8_EndPicture
};