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