Home | History | Annotate | Download | only in mrst
      1 /*
      2  * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
      3  * Copyright (c) Imagination Technologies Limited, UK
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the
      7  * "Software"), to deal in the Software without restriction, including
      8  * without limitation the rights to use, copy, modify, merge, publish,
      9  * distribute, sub license, and/or sell copies of the Software, and to
     10  * permit persons to whom the Software is furnished to do so, subject to
     11  * the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the
     14  * next paragraph) shall be included in all copies or substantial portions
     15  * of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     20  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
     21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  * Authors:
     26  *    Zeng Li <zeng.li (at) intel.com>
     27  *    Shengquan Yuan  <shengquan.yuan (at) intel.com>
     28  *    Binglin Chen <binglin.chen (at) intel.com>
     29  *
     30  */
     31 
     32 
     33 #include "psb_def.h"
     34 #include "psb_surface.h"
     35 #include "psb_cmdbuf.h"
     36 #include "lnc_hostcode.h"
     37 #include "lnc_H264ES.h"
     38 #include "lnc_hostheader.h"
     39 #include "va/va_enc_h264.h"
     40 #include "psb_drv_debug.h"
     41 
     42 #include <stdlib.h>
     43 #include <stdint.h>
     44 #include <string.h>
     45 #include <limits.h>
     46 
     47 
     48 #define TOPAZ_H264_MAX_BITRATE 14000000 /* FIXME ?? */
     49 #define WORST_CASE_SLICE_HEADER_SIZE 200
     50 
     51 #define INIT_CONTEXT_H264ES     context_ENC_p ctx = (context_ENC_p) obj_context->format_data
     52 #define SURFACE(id)    ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id ))
     53 #define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id ))
     54 
     55 
     56 
     57 static void lnc_H264ES_QueryConfigAttributes(
     58     VAProfile profile,
     59     VAEntrypoint entrypoint,
     60     VAConfigAttrib *attrib_list,
     61     int num_attribs)
     62 {
     63     int i;
     64 
     65     drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_QueryConfigAttributes\n");
     66 
     67     /* RateControl attributes */
     68     for (i = 0; i < num_attribs; i++) {
     69         switch (attrib_list[i].type) {
     70         case VAConfigAttribRTFormat:
     71             break;
     72 
     73         case VAConfigAttribRateControl:
     74             attrib_list[i].value = VA_RC_NONE | VA_RC_CBR | VA_RC_VBR | VA_RC_VCM;
     75             break;
     76 #if 0
     77         case VAConfigAttribEncMaxSliceSize:
     78             attrib_list[i].value = 0;
     79             break;
     80 #endif
     81         default:
     82             attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
     83             break;
     84         }
     85     }
     86 }
     87 
     88 
     89 static VAStatus lnc_H264ES_ValidateConfig(
     90     object_config_p obj_config)
     91 {
     92     int i;
     93     /* Check all attributes */
     94     for (i = 0; i < obj_config->attrib_count; i++) {
     95         switch (obj_config->attrib_list[i].type) {
     96         case VAConfigAttribRTFormat:
     97             /* Ignore */
     98             break;
     99         case VAConfigAttribRateControl:
    100             break;
    101         default:
    102             return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
    103         }
    104     }
    105 
    106     return VA_STATUS_SUCCESS;
    107 }
    108 
    109 
    110 static VAStatus lnc_H264ES_CreateContext(
    111     object_context_p obj_context,
    112     object_config_p obj_config)
    113 {
    114     VAStatus vaStatus = VA_STATUS_SUCCESS;
    115     context_ENC_p ctx;
    116     int i;
    117     unsigned int eRCmode = 0;
    118 
    119     drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_CreateContext\n");
    120 
    121     vaStatus = lnc_CreateContext(obj_context, obj_config);
    122 
    123     if (VA_STATUS_SUCCESS != vaStatus)
    124         return VA_STATUS_ERROR_ALLOCATION_FAILED;
    125 
    126     ctx = (context_ENC_p) obj_context->format_data;
    127 
    128     ctx->max_slice_size = 0;
    129     ctx->delta_change = 1;
    130     eRCMode = VA_RC_NONE;
    131     for (i = 0; i < obj_config->attrib_count; i++) {
    132 #if 0
    133         if (obj_config->attrib_list[i].type == VAConfigAttribEncMaxSliceSize)
    134             ctx->max_slice_size = obj_config->attrib_list[i].value;
    135         else if (obj_config->attrib_list[i].type == VAConfigAttribRateControl)
    136             eRCmode = obj_config->attrib_list[i].value;
    137 #else
    138         if (obj_config->attrib_list[i].type == VAConfigAttribRateControl)
    139             eRCmode = obj_config->attrib_list[i].value;
    140 #endif
    141     }
    142 
    143     drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_CreateContext: max slice size %d\n", ctx->max_slice_size);
    144 
    145     if (eRCmode == VA_RC_VBR) {
    146         ctx->eCodec = IMG_CODEC_H264_VBR;
    147         ctx->sRCParams.RCEnable = IMG_TRUE;
    148     } else if (eRCmode == VA_RC_CBR) {
    149         ctx->eCodec = IMG_CODEC_H264_CBR;
    150         ctx->sRCParams.RCEnable = IMG_TRUE;
    151     } else if (eRCmode == VA_RC_VCM) {
    152         ctx->eCodec = IMG_CODEC_H264_VCM;
    153         ctx->sRCParams.RCEnable = IMG_TRUE;
    154     } else if (eRCmode == VA_RC_NONE) {
    155         ctx->eCodec = IMG_CODEC_H264_NO_RC;
    156         ctx->sRCParams.RCEnable = IMG_FALSE;
    157     } else
    158         return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
    159     ctx->eFormat = IMG_CODEC_PL12;      /* use default */
    160 
    161     ctx->IPEControl = lnc__get_ipe_control(ctx->eCodec);
    162     ctx->idr_pic_id = 1;
    163 
    164     switch (obj_config->profile) {
    165     case VAProfileH264Baseline:
    166         ctx->profile_idc = 5;
    167         break;
    168     case VAProfileH264Main:
    169         ctx->profile_idc = 6;
    170         break;
    171     default:
    172         ctx->profile_idc = 6;
    173         break;
    174     }
    175 
    176     return vaStatus;
    177 }
    178 
    179 
    180 static void lnc_H264ES_DestroyContext(
    181     object_context_p obj_context)
    182 {
    183     struct coded_buf_aux_info *p_aux_info;
    184     INIT_CONTEXT_H264ES;
    185     drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_DestroyPicture\n");
    186 
    187     while (ctx->p_coded_buf_info != NULL) {
    188         p_aux_info = ctx->p_coded_buf_info->next;
    189         free(ctx->p_coded_buf_info);
    190         ctx->p_coded_buf_info = p_aux_info;
    191     }
    192     lnc_DestroyContext(obj_context);
    193 }
    194 
    195 static VAStatus lnc_H264ES_BeginPicture(
    196     object_context_p obj_context)
    197 {
    198     INIT_CONTEXT_H264ES;
    199     VAStatus vaStatus = VA_STATUS_SUCCESS;
    200 
    201     drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_BeginPicture\n");
    202 
    203     vaStatus = lnc_BeginPicture(ctx);
    204 
    205     return vaStatus;
    206 }
    207 
    208 static VAStatus lnc__H264ES_process_sequence_param(context_ENC_p ctx, object_buffer_p obj_buffer)
    209 {
    210     VAEncSequenceParameterBufferH264 *pSequenceParams;
    211     lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
    212     H264_VUI_PARAMS VUI_Params;
    213     H264_CROP_PARAMS sCrop;
    214     char hardcoded_qp[4];
    215 
    216     ASSERT(obj_buffer->type == VAEncSequenceParameterBufferType);
    217     ASSERT(obj_buffer->num_elements == 1);
    218     ASSERT(obj_buffer->size == sizeof(VAEncSequenceParameterBufferH264));
    219 
    220     if ((obj_buffer->num_elements != 1) ||
    221         (obj_buffer->size != sizeof(VAEncSequenceParameterBufferH264))) {
    222         return VA_STATUS_ERROR_UNKNOWN;
    223     }
    224 
    225     ctx->obj_context->frame_count = 0;
    226 
    227     pSequenceParams = (VAEncSequenceParameterBufferH264 *) obj_buffer->buffer_data;
    228     obj_buffer->buffer_data = NULL;
    229     obj_buffer->size = 0;
    230 
    231     if ((ctx->obj_context->frame_count != 0) &&
    232         (ctx->sRCParams.BitsPerSecond != pSequenceParams->bits_per_second))
    233         ctx->update_rc_control = 1;
    234 
    235     /* a new sequence and IDR need reset frame_count */
    236     ctx->obj_context->frame_count = 0;
    237 
    238     if (pSequenceParams->bits_per_second > TOPAZ_H264_MAX_BITRATE) {
    239         ctx->sRCParams.BitsPerSecond = TOPAZ_H264_MAX_BITRATE;
    240         drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \
    241 		the maximum bitrate, set it with %d\n",
    242                                  pSequenceParams->bits_per_second,
    243                                  TOPAZ_H264_MAX_BITRATE);
    244     } else
    245         ctx->sRCParams.BitsPerSecond = pSequenceParams->bits_per_second;
    246 
    247     ctx->sRCParams.Slices = 1;
    248 
    249     ctx->sRCParams.IntraFreq = pSequenceParams->intra_period;
    250     if (ctx->sRCParams.IntraFreq == 0)
    251         ctx->sRCParams.IntraFreq = 1000;
    252 
    253     ctx->sRCParams.IDRFreq = pSequenceParams->intra_idr_period;
    254     drv_debug_msg(VIDEO_DEBUG_GENERAL, "IntraFreq: %d\n, intra_idr_period: %d\n",
    255                              ctx->sRCParams.IntraFreq, ctx->sRCParams.IDRFreq);
    256 
    257     VUI_Params.Time_Scale = ctx->sRCParams.FrameRate * 2;
    258     VUI_Params.bit_rate_value_minus1 = ctx->sRCParams.BitsPerSecond / 64 - 1;
    259     VUI_Params.cbp_size_value_minus1 = ctx->sRCParams.BufferSize / 64 - 1;
    260     VUI_Params.CBR = 1;
    261     VUI_Params.initial_cpb_removal_delay_length_minus1 = 0;
    262     VUI_Params.cpb_removal_delay_length_minus1 = 0;
    263     VUI_Params.dpb_output_delay_length_minus1 = 0;
    264     VUI_Params.time_offset_length = 0;
    265 
    266     sCrop.bClip = IMG_FALSE;
    267     sCrop.LeftCropOffset = 0;
    268     sCrop.RightCropOffset = 0;
    269     sCrop.TopCropOffset = 0;
    270     sCrop.BottomCropOffset = 0;
    271 
    272     if (ctx->RawHeight & 0xf) {
    273         sCrop.bClip = IMG_TRUE;
    274         sCrop.BottomCropOffset = (((ctx->RawHeight + 0xf) & (~0xf)) - ctx->RawHeight) / 2;
    275     }
    276     if (ctx->RawWidth & 0xf) {
    277         sCrop.bClip = IMG_TRUE;
    278         sCrop.RightCropOffset = (((ctx->RawWidth + 0xf) & (~0xf)) - ctx->RawWidth) / 2;
    279     }
    280 
    281     /* sequence header is always inserted */
    282     if (ctx->eCodec == IMG_CODEC_H264_NO_RC)
    283         VUI_Params.CBR = 0;
    284 
    285     lnc__H264_prepare_sequence_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->seq_header_ofs), pSequenceParams->max_num_ref_frames,
    286                                       pSequenceParams->picture_width_in_mbs,
    287                                       pSequenceParams->picture_height_in_mbs,
    288                                       pSequenceParams->vui_parameters_present_flag,
    289                                       pSequenceParams->vui_parameters_present_flag ? (&VUI_Params) : NULL,
    290                                       &sCrop,
    291                                       pSequenceParams->level_idc, ctx->profile_idc);
    292 
    293     lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, 0); /* sequence header */
    294     RELOC_CMDBUF(cmdbuf->cmd_idx++, ctx->seq_header_ofs, &cmdbuf->header_mem);
    295 
    296     if (0 != ctx->sRCParams.IDRFreq) {
    297         if (NULL == ctx->save_seq_header_p) {
    298             ctx->save_seq_header_p = malloc(HEADER_SIZE);
    299             if (NULL == ctx->save_seq_header_p) {
    300                 drv_debug_msg(VIDEO_DEBUG_ERROR, "Ran out of memory!\n");
    301                 free(pSequenceParams);
    302                 return VA_STATUS_ERROR_ALLOCATION_FAILED;
    303             }
    304             memcpy((unsigned char *)ctx->save_seq_header_p,
    305                    (unsigned char *)(cmdbuf->header_mem_p + ctx->seq_header_ofs),
    306                    HEADER_SIZE);
    307         }
    308     }
    309     free(pSequenceParams);
    310 
    311     return VA_STATUS_SUCCESS;
    312 }
    313 
    314 static VAStatus lnc__H264ES_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer)
    315 {
    316     VAStatus vaStatus;
    317     VAEncPictureParameterBufferH264 *pBuffer;
    318     lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
    319     struct coded_buf_aux_info *p_aux_info;
    320     int need_sps = 0;
    321 
    322     ASSERT(obj_buffer->type == VAEncPictureParameterBufferType);
    323 
    324     if ((obj_buffer->num_elements != 1) ||
    325         (obj_buffer->size != sizeof(VAEncPictureParameterBufferH264))) {
    326         return VA_STATUS_ERROR_UNKNOWN;
    327     }
    328 
    329     /* Transfer ownership of VAEncPictureParameterBufferH264 data */
    330     pBuffer = (VAEncPictureParameterBufferH264 *) obj_buffer->buffer_data;
    331     obj_buffer->buffer_data = NULL;
    332     obj_buffer->size = 0;
    333 
    334 	ctx->ref_surface = SURFACE(pBuffer->ReferenceFrames[0].picture_id);
    335     ctx->dest_surface = SURFACE(pBuffer->CurrPic.picture_id);
    336     ctx->coded_buf = BUFFER(pBuffer->coded_buf);
    337 
    338     //ASSERT(ctx->Width == pBuffer->picture_width);
    339     //ASSERT(ctx->Height == pBuffer->picture_height);
    340 
    341     if ((ctx->sRCParams.IntraFreq != 0) && (ctx->sRCParams.IDRFreq != 0)) { /* period IDR is desired */
    342         unsigned int is_intra = 0;
    343         unsigned int intra_cnt = 0;
    344 
    345         ctx->force_idr_h264 = 0;
    346 
    347         if ((ctx->obj_context->frame_count % ctx->sRCParams.IntraFreq) == 0) {
    348             is_intra = 1; /* suppose current frame is I frame */
    349             intra_cnt = ctx->obj_context->frame_count / ctx->sRCParams.IntraFreq;
    350         }
    351 
    352         /* current frame is I frame (suppose), and an IDR frame is desired*/
    353         if ((is_intra) && ((intra_cnt % ctx->sRCParams.IDRFreq) == 0)) {
    354             ctx->force_idr_h264 = 1;
    355             /*When two consecutive access units in decoding order are both IDR access
    356             * units, the value of idr_pic_id in the slices of the first such IDR
    357             * access unit shall differ from the idr_pic_id in the second such IDR
    358             * access unit. We set it with 1 or 0 alternately.*/
    359             ctx->idr_pic_id = 1 - ctx->idr_pic_id;
    360 
    361             /* it is periodic IDR in the middle of one sequence encoding, need SPS */
    362             if (ctx->obj_context->frame_count > 0)
    363                 need_sps = 1;
    364 
    365             ctx->obj_context->frame_count = 0;
    366         }
    367     }
    368 
    369     /* For H264, PicHeader only needed in the first picture*/
    370     if (!ctx->obj_context->frame_count) {
    371         cmdbuf = ctx->obj_context->lnc_cmdbuf;
    372 
    373         if (need_sps) {
    374             /* reuse the previous SPS */
    375             drv_debug_msg(VIDEO_DEBUG_GENERAL, "TOPAZ: insert a SPS before IDR frame\n");
    376             memcpy((unsigned char *)(cmdbuf->header_mem_p + ctx->seq_header_ofs),
    377                    (unsigned char *)ctx->save_seq_header_p,
    378                    HEADER_SIZE);
    379 
    380             lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, 0); /* sequence header */
    381             RELOC_CMDBUF(cmdbuf->cmd_idx++, ctx->seq_header_ofs, &cmdbuf->header_mem);
    382         }
    383 
    384         lnc__H264_prepare_picture_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->pic_header_ofs));
    385 
    386         lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, 1);/* picture header */
    387         RELOC_CMDBUF(cmdbuf->cmd_idx++, ctx->pic_header_ofs, &cmdbuf->header_mem);
    388     }
    389 
    390     /*Record if EOSEQ or EOSTREAM should be appended to the coded buffer.*/
    391     if (0 != pBuffer->last_picture) {
    392         drv_debug_msg(VIDEO_DEBUG_GENERAL, "It's the last picture in sequence or stream."
    393                                  " Will append EOSEQ/EOSTREAM to the coded buffer.\n");
    394         p_aux_info = calloc(1, sizeof(struct coded_buf_aux_info));
    395         if (NULL == p_aux_info) {
    396             free(pBuffer);
    397             return VA_STATUS_ERROR_ALLOCATION_FAILED;
    398         }
    399         p_aux_info->buf = ctx->coded_buf;
    400         p_aux_info->aux_flag = pBuffer->last_picture;
    401         if (NULL != ctx->p_coded_buf_info)
    402             p_aux_info->next = ctx->p_coded_buf_info;
    403         else
    404             p_aux_info->next = NULL;
    405 
    406         ctx->p_coded_buf_info = p_aux_info;
    407     }
    408 
    409     vaStatus = lnc_RenderPictureParameter(ctx);
    410 
    411     free(pBuffer);
    412     return vaStatus;
    413 }
    414 
    415 static VAStatus lnc__H264ES_process_slice_param(context_ENC_p ctx, object_buffer_p obj_buffer)
    416 {
    417     /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */
    418     VAEncSliceParameterBuffer *pBuffer;
    419     lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
    420     unsigned int MBSkipRun, FirstMBAddress;
    421     PIC_PARAMS *psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p);
    422     unsigned int i;
    423     int slice_param_idx;
    424 
    425     ASSERT(obj_buffer->type == VAEncSliceParameterBufferType);
    426 
    427     cmdbuf = ctx->obj_context->lnc_cmdbuf;
    428     psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
    429 
    430     /* Transfer ownership of VAEncPictureParameterBufferH264 data */
    431     pBuffer = (VAEncSliceParameterBuffer *) obj_buffer->buffer_data;
    432     obj_buffer->size = 0;
    433 
    434     /* save current cmdbuf write pointer for H264 frameskip redo
    435      * for H264, only slice header need to repatch
    436      */
    437     cmdbuf->cmd_idx_saved_frameskip = cmdbuf->cmd_idx;
    438 
    439     if (0 == pBuffer->start_row_number) {
    440         if (pBuffer->slice_flags.bits.is_intra)
    441             RELOC_PIC_PARAMS(&psPicParams->InParamsBase, ctx->in_params_ofs, cmdbuf->topaz_in_params_I);
    442         else
    443             RELOC_PIC_PARAMS(&psPicParams->InParamsBase, ctx->in_params_ofs, cmdbuf->topaz_in_params_P);
    444     }
    445 
    446     /*In case the slice number changes*/
    447     if ((ctx->slice_param_cache != NULL) && (obj_buffer->num_elements != ctx->slice_param_num)) {
    448         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Slice number changes. Previous value is %d. Now it's %d\n",
    449                                  ctx->slice_param_num, obj_buffer->num_elements);
    450         free(ctx->slice_param_cache);
    451         ctx->slice_param_cache = NULL;
    452         ctx->slice_param_num = 0;
    453     }
    454 
    455     if (NULL == ctx->slice_param_cache) {
    456         ctx->slice_param_num = obj_buffer->num_elements;
    457         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Allocate %d VAEncSliceParameterBuffer cache buffers\n", 2 * ctx->slice_param_num);
    458         ctx->slice_param_cache = calloc(2 * ctx->slice_param_num, sizeof(VAEncSliceParameterBuffer));
    459         if (NULL == ctx->slice_param_cache) {
    460             drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n");
    461             free(obj_buffer->buffer_data);
    462             return VA_STATUS_ERROR_ALLOCATION_FAILED;
    463         }
    464     }
    465 
    466     for (i = 0; i < obj_buffer->num_elements; i++) {
    467         /*Todo list:
    468          *1.Insert Do header command
    469          *2.setup InRowParams
    470          *3.setup Slice params
    471          *4.Insert Do slice command
    472          * */
    473         int deblock_on, force_idr = 0;
    474 
    475         if ((pBuffer->slice_height == 0) || (pBuffer->start_row_number >= ctx->Height)) {
    476             drv_debug_msg(VIDEO_DEBUG_GENERAL, "slice number is %d, but it seems the last %d buffers are empty\n",
    477                                      obj_buffer->num_elements, obj_buffer->num_elements - i);
    478             free(obj_buffer->buffer_data);
    479             obj_buffer->buffer_data = NULL;
    480             return VA_STATUS_SUCCESS;
    481         }
    482 
    483         /* set to INTRA frame */
    484         if (ctx->force_idr_h264 || (ctx->obj_context->frame_count == 0)) {
    485             force_idr = 1;
    486             pBuffer->slice_flags.bits.is_intra = 1;
    487         }
    488 
    489         if ((pBuffer->slice_flags.bits.disable_deblocking_filter_idc == 0)
    490             || (pBuffer->slice_flags.bits.disable_deblocking_filter_idc == 2))
    491             deblock_on = IMG_TRUE;
    492         else
    493             deblock_on = IMG_FALSE;
    494 
    495         if (ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip)
    496             MBSkipRun = (ctx->Width * ctx->Height) / 256;
    497         else
    498             MBSkipRun = 0;
    499 
    500         FirstMBAddress = (pBuffer->start_row_number * ctx->Width) / 16;
    501         /* Insert Do Header command, relocation is needed */
    502         lnc__H264_prepare_slice_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->slice_header_ofs + ctx->obj_context->slice_count * HEADER_SIZE),
    503                                        pBuffer->slice_flags.bits.is_intra,
    504                                        pBuffer->slice_flags.bits.disable_deblocking_filter_idc,
    505                                        ctx->obj_context->frame_count,
    506                                        FirstMBAddress,
    507                                        MBSkipRun, force_idr,
    508                                        pBuffer->slice_flags.bits.uses_long_term_ref,
    509                                        pBuffer->slice_flags.bits.is_long_term_ref,
    510                                        ctx->idr_pic_id);
    511 
    512         lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, (ctx->obj_context->slice_count << 2) | 2);
    513         RELOC_CMDBUF(cmdbuf->cmd_idx++,
    514                      ctx->slice_header_ofs + ctx->obj_context->slice_count * HEADER_SIZE,
    515                      &cmdbuf->header_mem);
    516 
    517         if (!(ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip)) {
    518             if ((ctx->obj_context->frame_count == 0) && (pBuffer->start_row_number == 0) && pBuffer->slice_flags.bits.is_intra)
    519                 lnc_reset_encoder_params(ctx);
    520 
    521             /*The corresponding slice buffer cache*/
    522             slice_param_idx = (pBuffer->slice_flags.bits.is_intra ? 0 : 1) * ctx->slice_param_num + i;
    523 
    524             if (VAEncSliceParameter_Equal(&ctx->slice_param_cache[slice_param_idx], pBuffer) == 0) {
    525                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Cache slice%d's parameter buffer at index %d\n", i, slice_param_idx);
    526 
    527                 /* cache current param parameters */
    528                 memcpy(&ctx->slice_param_cache[slice_param_idx],
    529                        pBuffer, sizeof(VAEncSliceParameterBuffer));
    530 
    531                 /* Setup InParams value*/
    532                 lnc_setup_slice_params(ctx,
    533                                        pBuffer->start_row_number * 16,
    534                                        pBuffer->slice_height * 16,
    535                                        pBuffer->slice_flags.bits.is_intra,
    536                                        ctx->obj_context->frame_count > 0,
    537                                        psPicParams->sInParams.SeInitQP);
    538             }
    539 
    540             /* Insert do slice command and setup related buffer value */
    541             lnc__send_encode_slice_params(ctx,
    542                                           pBuffer->slice_flags.bits.is_intra,
    543                                           pBuffer->start_row_number * 16,
    544                                           deblock_on,
    545                                           ctx->obj_context->frame_count,
    546                                           pBuffer->slice_height * 16,
    547                                           ctx->obj_context->slice_count, ctx->max_slice_size);
    548 
    549             drv_debug_msg(VIDEO_DEBUG_GENERAL, "Now frame_count/slice_count is %d/%d\n",
    550                                      ctx->obj_context->frame_count, ctx->obj_context->slice_count);
    551         }
    552         ctx->obj_context->slice_count++;
    553         pBuffer++; /* Move to the next buffer */
    554 
    555         ASSERT(ctx->obj_context->slice_count < MAX_SLICES_PER_PICTURE);
    556     }
    557 
    558     free(obj_buffer->buffer_data);
    559     obj_buffer->buffer_data = NULL;
    560 
    561     return VA_STATUS_SUCCESS;
    562 }
    563 
    564 static VAStatus lnc__H264ES_process_misc_param(context_ENC_p ctx, object_buffer_p obj_buffer)
    565 {
    566     /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */
    567     VAEncMiscParameterBuffer *pBuffer;
    568     VAEncMiscParameterRateControl *rate_control_param;
    569     VAEncMiscParameterAIR *air_param;
    570     VAEncMiscParameterMaxSliceSize *max_slice_size_param;
    571     VAEncMiscParameterFrameRate *frame_rate_param;
    572     unsigned int bit_rate;
    573     char hardcoded_qp[4];
    574 
    575     VAStatus vaStatus = VA_STATUS_SUCCESS;
    576 
    577     ASSERT(obj_buffer->type == VAEncMiscParameterBufferType);
    578 
    579     /* Transfer ownership of VAEncMiscParameterBuffer data */
    580     pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data;
    581     obj_buffer->size = 0;
    582 
    583 	//initialize the frame_rate and qp
    584 	rate_control_param->initial_qp=26;
    585 	rate_control_param->min_qp=3;
    586 	frame_rate_param->framerate=30;
    587 
    588     switch (pBuffer->type) {
    589     case VAEncMiscParameterTypeFrameRate:
    590         frame_rate_param = (VAEncMiscParameterFrameRate *)pBuffer->data;
    591 
    592         if (frame_rate_param->framerate > 65535) {
    593             vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
    594             break;
    595         }
    596 
    597         drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: frame rate changed to %d\n", __FUNCTION__,
    598                                  frame_rate_param->framerate);
    599 
    600         if (ctx->sRCParams.FrameRate == frame_rate_param->framerate)
    601             break;
    602 
    603         ctx->sRCParams.FrameRate = frame_rate_param->framerate;
    604         ctx->sRCParams.BitsPerSecond += ctx->delta_change;
    605         ctx->delta_change *= -1;
    606         ctx->update_rc_control = 1;
    607 
    608         break;
    609 
    610     case VAEncMiscParameterTypeRateControl:
    611         rate_control_param = (VAEncMiscParameterRateControl *)pBuffer->data;
    612 
    613         if (psb_parse_config("PSB_VIDEO_IQP", hardcoded_qp) == 0)
    614             rate_control_param->initial_qp = atoi(hardcoded_qp);
    615 
    616         if (psb_parse_config("PSB_VIDEO_MQP", hardcoded_qp) == 0)
    617             rate_control_param->min_qp = atoi(hardcoded_qp);
    618 
    619         if (rate_control_param->initial_qp > 65535 ||
    620             rate_control_param->min_qp > 65535 ||
    621             rate_control_param->target_percentage > 65535) {
    622             vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
    623             break;
    624         }
    625 
    626         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Rate control parameter initial_qp=%d, min_qp=%d\n",
    627                                  rate_control_param->initial_qp,
    628                                  rate_control_param->min_qp);
    629 
    630         if (rate_control_param->bits_per_second > TOPAZ_H264_MAX_BITRATE) {
    631             bit_rate = TOPAZ_H264_MAX_BITRATE;
    632             drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \
    633                                              the maximum bitrate, set it with %d\n",
    634                                      rate_control_param->bits_per_second,
    635                                      TOPAZ_H264_MAX_BITRATE);
    636         } else {
    637             bit_rate = rate_control_param->bits_per_second;
    638         }
    639 
    640         drv_debug_msg(VIDEO_DEBUG_GENERAL, "rate control changed to %d\n",
    641                                  rate_control_param->bits_per_second);
    642 
    643         if ((rate_control_param->bits_per_second == ctx->sRCParams.BitsPerSecond) &&
    644             (ctx->sRCParams.VCMBitrateMargin == rate_control_param->target_percentage * 128 / 100) &&
    645             (ctx->sRCParams.BufferSize == ctx->sRCParams.BitsPerSecond / 1000 * rate_control_param->window_size) &&
    646             (ctx->sRCParams.MinQP == rate_control_param->min_qp) &&
    647             (ctx->sRCParams.InitialQp == rate_control_param->initial_qp))
    648             break;
    649         else
    650             ctx->update_rc_control = 1;
    651 
    652         if (rate_control_param->target_percentage != 0)
    653             ctx->sRCParams.VCMBitrateMargin = rate_control_param->target_percentage * 128 / 100;
    654         if (rate_control_param->window_size != 0)
    655             ctx->sRCParams.BufferSize = ctx->sRCParams.BitsPerSecond * rate_control_param->window_size / 1000;
    656         if (rate_control_param->initial_qp != 0)
    657             ctx->sRCParams.InitialQp = rate_control_param->initial_qp;
    658         if (rate_control_param->min_qp != 0)
    659             ctx->sRCParams.MinQP = rate_control_param->min_qp;
    660 
    661         if ((bit_rate == ctx->sRCParams.BitsPerSecond) || (bit_rate == 0)) {
    662             ctx->sRCParams.BitsPerSecond += ctx->delta_change;
    663             ctx->delta_change *= -1;
    664         } else {
    665             ctx->sRCParams.BitsPerSecond = bit_rate;
    666         }
    667 
    668         break;
    669 
    670     case VAEncMiscParameterTypeMaxSliceSize:
    671         max_slice_size_param = (VAEncMiscParameterMaxSliceSize *)pBuffer->data;
    672 
    673         if (max_slice_size_param->max_slice_size > INT_MAX ||
    674             (max_slice_size_param->max_slice_size != 0 &&
    675              max_slice_size_param->max_slice_size < WORST_CASE_SLICE_HEADER_SIZE)) {
    676             vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
    677             break;
    678         }
    679 
    680         if (max_slice_size_param->max_slice_size != 0)
    681             max_slice_size_param->max_slice_size -= WORST_CASE_SLICE_HEADER_SIZE;
    682 
    683         if (ctx->max_slice_size == max_slice_size_param->max_slice_size)
    684             break;
    685 
    686         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Max slice size changed to %d\n",
    687                                  max_slice_size_param->max_slice_size);
    688 
    689         ctx->max_slice_size = max_slice_size_param->max_slice_size;
    690 
    691         break;
    692 
    693     case VAEncMiscParameterTypeAIR:
    694         air_param = (VAEncMiscParameterAIR *)pBuffer->data;
    695 
    696         if (air_param->air_num_mbs > 65535 ||
    697             air_param->air_threshold > 65535) {
    698             vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
    699             break;
    700         }
    701 
    702         drv_debug_msg(VIDEO_DEBUG_GENERAL, "air slice size changed to num_air_mbs %d "
    703                                  "air_threshold %d, air_auto %d\n",
    704                                  air_param->air_num_mbs, air_param->air_threshold,
    705                                  air_param->air_auto);
    706 
    707         if (((ctx->Height * ctx->Width) >> 8) < air_param->air_num_mbs)
    708             air_param->air_num_mbs = ((ctx->Height * ctx->Width) >> 8);
    709         if (air_param->air_threshold == 0)
    710             drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: air threshold is set to zero\n",
    711                                      __FUNCTION__);
    712         ctx->num_air_mbs = air_param->air_num_mbs;
    713         ctx->air_threshold = air_param->air_threshold;
    714         ctx->autotune_air_flag = air_param->air_auto;
    715 
    716         break;
    717 
    718     default:
    719         vaStatus = VA_STATUS_ERROR_UNKNOWN;
    720         DEBUG_FAILURE;
    721         break;
    722     }
    723 
    724     free(obj_buffer->buffer_data);
    725     obj_buffer->buffer_data = NULL;
    726 
    727     return vaStatus;
    728 }
    729 
    730 static VAStatus lnc_H264ES_RenderPicture(
    731     object_context_p obj_context,
    732     object_buffer_p *buffers,
    733     int num_buffers)
    734 {
    735     INIT_CONTEXT_H264ES;
    736     VAStatus vaStatus = VA_STATUS_SUCCESS;
    737     int i;
    738 
    739     drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_RenderPicture\n");
    740 
    741     for (i = 0; i < num_buffers; i++) {
    742         object_buffer_p obj_buffer = buffers[i];
    743 
    744         switch (obj_buffer->type) {
    745         case VAEncSequenceParameterBufferType:
    746             drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264_RenderPicture got VAEncSequenceParameterBufferType\n");
    747             vaStatus = lnc__H264ES_process_sequence_param(ctx, obj_buffer);
    748             DEBUG_FAILURE;
    749             break;
    750 
    751         case VAEncPictureParameterBufferType:
    752             drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264_RenderPicture got VAEncPictureParameterBuffer\n");
    753             vaStatus = lnc__H264ES_process_picture_param(ctx, obj_buffer);
    754             DEBUG_FAILURE;
    755             break;
    756 
    757         case VAEncSliceParameterBufferType:
    758             drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264_RenderPicture got VAEncSliceParameterBufferType\n");
    759             vaStatus = lnc__H264ES_process_slice_param(ctx, obj_buffer);
    760             DEBUG_FAILURE;
    761             break;
    762 
    763         case VAEncMiscParameterBufferType:
    764             drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264_RenderPicture got VAEncMiscParameterBufferType\n");
    765             vaStatus = lnc__H264ES_process_misc_param(ctx, obj_buffer);
    766             DEBUG_FAILURE;
    767             break;
    768 
    769         default:
    770             vaStatus = VA_STATUS_ERROR_UNKNOWN;
    771             DEBUG_FAILURE;
    772         }
    773         if (vaStatus != VA_STATUS_SUCCESS) {
    774             break;
    775         }
    776     }
    777 
    778     return vaStatus;
    779 }
    780 
    781 static VAStatus lnc_H264ES_EndPicture(
    782     object_context_p obj_context)
    783 {
    784     INIT_CONTEXT_H264ES;
    785     VAStatus vaStatus = VA_STATUS_SUCCESS;
    786 
    787     drv_debug_msg(VIDEO_DEBUG_GENERAL, "lnc_H264ES_EndPicture\n");
    788 
    789     vaStatus = lnc_EndPicture(ctx);
    790 
    791     return vaStatus;
    792 }
    793 
    794 
    795 struct format_vtable_s lnc_H264ES_vtable = {
    796 queryConfigAttributes:
    797     lnc_H264ES_QueryConfigAttributes,
    798 validateConfig:
    799     lnc_H264ES_ValidateConfig,
    800 createContext:
    801     lnc_H264ES_CreateContext,
    802 destroyContext:
    803     lnc_H264ES_DestroyContext,
    804 beginPicture:
    805     lnc_H264ES_BeginPicture,
    806 renderPicture:
    807     lnc_H264ES_RenderPicture,
    808 endPicture:
    809     lnc_H264ES_EndPicture
    810 };
    811 
    812 static inline void lnc_H264_append_EOSEQ(unsigned char *p_buf, unsigned int *p_size)
    813 {
    814     /*nal_ref_idc should be 0 and nal_ref_idc should be 10 for End of Sequence RBSP*/
    815     const unsigned char EOSEQ[] = {0x00, 0x00, 0x00, 0x01, 0xa};
    816     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Append %d bytes of End of Sequence RBSP at offset %d\n",
    817                              sizeof(EOSEQ), *p_size);
    818     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));
    819     p_buf += *p_size;
    820     memcpy(p_buf, &EOSEQ[0], sizeof(EOSEQ));
    821     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));
    822     *p_size += sizeof(EOSEQ);
    823 }
    824 
    825 static inline void lnc_H264_append_EOSTREAM(unsigned char *p_buf, unsigned int *p_size)
    826 {
    827     /*nal_ref_idc should be 0 and nal_ref_idc should be 11 for End of Stream RBSP*/
    828     const unsigned char EOSTREAM[] = {0x00, 0x00, 0x00, 0x01, 0xb};
    829     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Append %d bytes of End of Stream RBSP.\n",
    830                              sizeof(EOSTREAM));
    831     p_buf += *p_size;
    832     memcpy(p_buf, EOSTREAM, sizeof(EOSTREAM));
    833     *p_size += sizeof(EOSTREAM);
    834 }
    835 
    836 VAStatus lnc_H264_append_aux_info(object_context_p obj_context,
    837                                   object_buffer_p obj_buffer,
    838                                   unsigned char *buf,
    839                                   unsigned int *p_size)
    840 {
    841     INIT_CONTEXT_H264ES;
    842     struct coded_buf_aux_info *p_aux_info;
    843     struct coded_buf_aux_info *p_prev_aux_info;
    844 
    845     if (NULL == ctx->p_coded_buf_info ||
    846         (ctx->eCodec != IMG_CODEC_H264_VBR
    847          && ctx->eCodec != IMG_CODEC_H264_CBR
    848          && ctx->eCodec != IMG_CODEC_H264_NO_RC))
    849         return VA_STATUS_SUCCESS;
    850 
    851     ASSERT(obj_buffer);
    852     ASSERT(buf);
    853     ASSERT(p_size);
    854 
    855     p_aux_info = ctx->p_coded_buf_info;
    856     p_prev_aux_info = ctx->p_coded_buf_info;
    857     while (p_aux_info != NULL) {
    858         /*Check if we need to append NAL to this coded buffer*/
    859         if (p_aux_info->buf == obj_buffer)
    860             break;
    861         p_prev_aux_info = p_aux_info;
    862         p_aux_info = p_aux_info->next;
    863     }
    864 
    865     if (NULL != p_aux_info) {
    866         drv_debug_msg(VIDEO_DEBUG_GENERAL, "coded_buf_aux_info 0x%08x\n", p_aux_info->aux_flag);
    867         if (0 != (p_aux_info->aux_flag & CODED_BUFFER_EOSEQ_FLAG))
    868             lnc_H264_append_EOSEQ(buf, p_size);
    869 
    870         if (0 != (p_aux_info->aux_flag & CODED_BUFFER_EOSTREAM_FLAG))
    871             lnc_H264_append_EOSTREAM(buf, p_size);
    872 
    873         if (p_aux_info == ctx->p_coded_buf_info)
    874             ctx->p_coded_buf_info = p_aux_info->next;
    875         else
    876             p_prev_aux_info->next = p_aux_info->next;
    877 
    878         free(p_aux_info);
    879     }
    880     return VA_STATUS_SUCCESS;
    881 }
    882