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