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@intel.com>
27 *    Shengquan Yuan  <shengquan.yuan@intel.com>
28 *    Binglin Chen <binglin.chen@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
57static 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
89static 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
110static 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
180static 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
195static 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
208static 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
314static 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
415static 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
564static 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
730static 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
781static 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
795struct format_vtable_s lnc_H264ES_vtable = {
796queryConfigAttributes:
797    lnc_H264ES_QueryConfigAttributes,
798validateConfig:
799    lnc_H264ES_ValidateConfig,
800createContext:
801    lnc_H264ES_CreateContext,
802destroyContext:
803    lnc_H264ES_DestroyContext,
804beginPicture:
805    lnc_H264ES_BeginPicture,
806renderPicture:
807    lnc_H264ES_RenderPicture,
808endPicture:
809    lnc_H264ES_EndPicture
810};
811
812static 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
825static 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
836VAStatus 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