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 
lnc_H264ES_QueryConfigAttributes(VAProfile profile,VAEntrypoint entrypoint,VAConfigAttrib * attrib_list,int num_attribs)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 
lnc_H264ES_ValidateConfig(object_config_p obj_config)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 
lnc_H264ES_CreateContext(object_context_p obj_context,object_config_p obj_config)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 
lnc_H264ES_DestroyContext(object_context_p obj_context)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 
lnc_H264ES_BeginPicture(object_context_p obj_context)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 
lnc__H264ES_process_sequence_param(context_ENC_p ctx,object_buffer_p obj_buffer)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 
lnc__H264ES_process_picture_param(context_ENC_p ctx,object_buffer_p obj_buffer)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 
lnc__H264ES_process_slice_param(context_ENC_p ctx,object_buffer_p obj_buffer)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 
lnc__H264ES_process_misc_param(context_ENC_p ctx,object_buffer_p obj_buffer)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 
lnc_H264ES_RenderPicture(object_context_p obj_context,object_buffer_p * buffers,int num_buffers)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 
lnc_H264ES_EndPicture(object_context_p obj_context)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 
lnc_H264_append_EOSEQ(unsigned char * p_buf,unsigned int * p_size)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 
lnc_H264_append_EOSTREAM(unsigned char * p_buf,unsigned int * p_size)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 
lnc_H264_append_aux_info(object_context_p obj_context,object_buffer_p obj_buffer,unsigned char * buf,unsigned int * p_size)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