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 * Elaine Wang <elaine.wang (at) intel.com> 27 * Zeng Li <zeng.li (at) intel.com> 28 * 29 */ 30 31 32 #include <errno.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <stdint.h> 36 #include <string.h> 37 38 #include "psb_def.h" 39 #include "psb_drv_debug.h" 40 #include "psb_surface.h" 41 #include "psb_cmdbuf.h" 42 #include "pnw_hostcode.h" 43 #include "pnw_H264ES.h" 44 #include "pnw_hostheader.h" 45 #include "va/va_enc_h264.h" 46 #define TOPAZ_H264_MAX_BITRATE 50000000 47 48 #define INIT_CONTEXT_H264ES context_ENC_p ctx = (context_ENC_p) obj_context->format_data 49 #define SURFACE(id) ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id )) 50 #define BUFFER(id) ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id )) 51 static void pnw_H264ES_QueryConfigAttributes( 52 VAProfile __maybe_unused profile, 53 VAEntrypoint __maybe_unused entrypoint, 54 VAConfigAttrib *attrib_list, 55 int num_attribs) 56 { 57 int i; 58 59 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_QueryConfigAttributes\n"); 60 61 /* RateControl attributes */ 62 for (i = 0; i < num_attribs; i++) { 63 switch (attrib_list[i].type) { 64 case VAConfigAttribRTFormat: 65 break; 66 67 case VAConfigAttribRateControl: 68 attrib_list[i].value = VA_RC_NONE | VA_RC_CBR | VA_RC_VBR | VA_RC_VCM; 69 break; 70 71 case VAConfigAttribEncMaxRefFrames: 72 attrib_list[i].value = 1; 73 break; 74 75 default: 76 attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED; 77 break; 78 } 79 } 80 } 81 82 83 static VAStatus pnw_H264ES_ValidateConfig( 84 object_config_p obj_config) 85 { 86 int i; 87 /* Check all attributes */ 88 for (i = 0; i < obj_config->attrib_count; i++) { 89 switch (obj_config->attrib_list[i].type) { 90 case VAConfigAttribRTFormat: 91 /* Ignore */ 92 break; 93 case VAConfigAttribRateControl: 94 break; 95 default: 96 return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED; 97 } 98 } 99 100 return VA_STATUS_SUCCESS; 101 } 102 103 104 static VAStatus pnw_H264ES_CreateContext( 105 object_context_p obj_context, 106 object_config_p obj_config) 107 { 108 VAStatus vaStatus = VA_STATUS_SUCCESS; 109 context_ENC_p ctx; 110 int i; 111 unsigned int eRCmode; 112 113 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_CreateContext\n"); 114 115 vaStatus = pnw_CreateContext(obj_context, obj_config, 0); 116 117 if (VA_STATUS_SUCCESS != vaStatus) 118 return VA_STATUS_ERROR_ALLOCATION_FAILED; 119 120 ctx = (context_ENC_p) obj_context->format_data; 121 122 for (i = 0; i < obj_config->attrib_count; i++) { 123 if (obj_config->attrib_list[i].type == VAConfigAttribRateControl) 124 break; 125 } 126 127 if (i >= obj_config->attrib_count) 128 eRCmode = VA_RC_NONE; 129 else 130 eRCmode = obj_config->attrib_list[i].value; 131 132 133 if (eRCmode == VA_RC_VBR) { 134 ctx->eCodec = IMG_CODEC_H264_VBR; 135 ctx->sRCParams.RCEnable = IMG_TRUE; 136 ctx->sRCParams.bDisableBitStuffing = IMG_FALSE; 137 } else if (eRCmode == VA_RC_CBR) { 138 ctx->eCodec = IMG_CODEC_H264_CBR; 139 ctx->sRCParams.RCEnable = IMG_TRUE; 140 ctx->sRCParams.bDisableBitStuffing = IMG_TRUE; 141 } else if (eRCmode == VA_RC_NONE) { 142 ctx->eCodec = IMG_CODEC_H264_NO_RC; 143 ctx->sRCParams.RCEnable = IMG_FALSE; 144 ctx->sRCParams.bDisableBitStuffing = IMG_FALSE; 145 } else if (eRCmode == VA_RC_VCM) { 146 ctx->eCodec = IMG_CODEC_H264_VCM; 147 ctx->sRCParams.RCEnable = IMG_TRUE; 148 ctx->sRCParams.bDisableBitStuffing = IMG_FALSE; 149 } else 150 return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT; 151 152 drv_debug_msg(VIDEO_DEBUG_GENERAL, "eCodec is %d\n", ctx->eCodec); 153 ctx->eFormat = IMG_CODEC_PL12; /* use default */ 154 155 ctx->Slices = 1; 156 ctx->idr_pic_id = 1; 157 ctx->buffer_size = 0; 158 ctx->initial_buffer_fullness = 0; 159 //initialize the frame_rate and qp 160 ctx->sRCParams.FrameRate = 30; 161 162 if (getenv("PSB_VIDEO_SIG_CORE") == NULL) { 163 ctx->Slices = 2; 164 ctx->NumCores = 2; 165 } 166 167 ctx->ParallelCores = min(ctx->NumCores, ctx->Slices); 168 169 ctx->IPEControl = pnw__get_ipe_control(ctx->eCodec); 170 171 switch (obj_config->profile) { 172 case VAProfileH264Baseline: 173 ctx->profile_idc = 5; 174 break; 175 case VAProfileH264Main: 176 ctx->profile_idc = 6; 177 break; 178 default: 179 ctx->profile_idc = 6; 180 break; 181 } 182 183 return vaStatus; 184 } 185 186 static void pnw_H264ES_DestroyContext( 187 object_context_p obj_context) 188 { 189 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_DestroyPicture\n"); 190 191 pnw_DestroyContext(obj_context); 192 } 193 194 static VAStatus pnw_H264ES_BeginPicture( 195 object_context_p obj_context) 196 { 197 INIT_CONTEXT_H264ES; 198 VAStatus vaStatus = VA_STATUS_SUCCESS; 199 200 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_BeginPicture\n"); 201 202 vaStatus = pnw_BeginPicture(ctx); 203 204 return vaStatus; 205 } 206 207 static VAStatus pnw__H264ES_process_sequence_param(context_ENC_p ctx, object_buffer_p obj_buffer) 208 { 209 VAEncSequenceParameterBufferH264 *pSequenceParams; 210 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 211 H264_VUI_PARAMS *pVUI_Params = &(ctx->VUI_Params); 212 H264_CROP_PARAMS sCrop; 213 int i; 214 unsigned int frame_size; 215 unsigned int max_bps; 216 217 ASSERT(obj_buffer->type == VAEncSequenceParameterBufferType); 218 ASSERT(obj_buffer->num_elements == 1); 219 ASSERT(obj_buffer->size == sizeof(VAEncSequenceParameterBufferH264)); 220 221 if ((obj_buffer->num_elements != 1) || 222 (obj_buffer->size != sizeof(VAEncSequenceParameterBufferH264))) { 223 return VA_STATUS_ERROR_UNKNOWN; 224 } 225 226 if(ctx->sRCParams.FrameRate == 0) 227 ctx->sRCParams.FrameRate = 30; 228 ctx->obj_context->frame_count = 0; 229 230 pSequenceParams = (VAEncSequenceParameterBufferH264 *) obj_buffer->buffer_data; 231 obj_buffer->buffer_data = NULL; 232 obj_buffer->size = 0; 233 234 if (!pSequenceParams->bits_per_second) { 235 pSequenceParams->bits_per_second = ctx->Height * ctx->Width * 30 * 12; 236 drv_debug_msg(VIDEO_DEBUG_GENERAL, "bits_per_second is 0, set to %d\n", 237 pSequenceParams->bits_per_second); 238 } 239 ctx->sRCParams.bBitrateChanged = 240 (pSequenceParams->bits_per_second == ctx->sRCParams.BitsPerSecond ? 241 IMG_FALSE : IMG_TRUE); 242 243 if (pSequenceParams->bits_per_second > TOPAZ_H264_MAX_BITRATE) { 244 ctx->sRCParams.BitsPerSecond = TOPAZ_H264_MAX_BITRATE; 245 drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \ 246 the maximum bitrate, set it with %d\n", 247 pSequenceParams->bits_per_second, 248 TOPAZ_H264_MAX_BITRATE); 249 } 250 251 /* According to Table A-1 Level limits, if resolution is bigger than 625SD, 252 min compression ratio is 4, otherwise min compression ratio is 2 */ 253 max_bps = (ctx->Width * ctx->Height * 3 / 2 ) * 8 * ctx->sRCParams.FrameRate; 254 if (ctx->Width > 720) 255 max_bps /= 4; 256 else 257 max_bps /= 2; 258 259 drv_debug_msg(VIDEO_DEBUG_GENERAL, " width %d height %d, frame rate %d\n", 260 ctx->Width, ctx->Height, ctx->sRCParams.FrameRate); 261 if (pSequenceParams->bits_per_second > max_bps) { 262 drv_debug_msg(VIDEO_DEBUG_ERROR, 263 "Invalid bitrate %d, violate ITU-T Rec. H.264 (03/2005) A.3.1" 264 "\n clip to %d bps\n", pSequenceParams->bits_per_second, max_bps); 265 ctx->sRCParams.BitsPerSecond = max_bps; 266 } else { 267 /* See 110% target bitrate for VCM. Otherwise, the resulted bitrate is much lower 268 than target bitrate */ 269 if (ctx->eCodec == IMG_CODEC_H264_VCM) 270 pSequenceParams->bits_per_second = 271 pSequenceParams->bits_per_second / 100 * 110; 272 273 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Bitrate is set to %d\n", 274 pSequenceParams->bits_per_second); 275 ctx->sRCParams.BitsPerSecond = pSequenceParams->bits_per_second; 276 } 277 278 /*if (ctx->sRCParams.IntraFreq != pSequenceParams->intra_period) 279 ctx->sRCParams.bBitrateChanged = IMG_TRUE;*/ 280 ctx->sRCParams.IDRFreq = pSequenceParams->intra_idr_period; 281 282 ctx->sRCParams.Slices = ctx->Slices; 283 ctx->sRCParams.QCPOffset = 0; 284 285 if (ctx->sRCParams.IntraFreq != pSequenceParams->intra_period 286 && ctx->raw_frame_count != 0 287 && ctx->sRCParams.IntraFreq != 0 288 && ((ctx->obj_context->frame_count + 1) % ctx->sRCParams.IntraFreq) != 0 289 && (!ctx->sRCParams.bDisableFrameSkipping)) { 290 drv_debug_msg(VIDEO_DEBUG_ERROR, 291 "Changing intra period value in the middle of a GOP is\n" 292 "not allowed if frame skip isn't disabled.\n" 293 "it can cause I frame been skipped\n"); 294 free(pSequenceParams); 295 return VA_STATUS_ERROR_INVALID_PARAMETER; 296 } 297 else 298 ctx->sRCParams.IntraFreq = pSequenceParams->intra_period; 299 300 frame_size = ctx->sRCParams.BitsPerSecond / ctx->sRCParams.FrameRate; 301 302 if (ctx->bInserHRDParams && 303 ctx->buffer_size != 0 && ctx->initial_buffer_fullness != 0) { 304 ctx->sRCParams.BufferSize = ctx->buffer_size; 305 ctx->sRCParams.InitialLevel = ctx->buffer_size - ctx->initial_buffer_fullness; 306 ctx->sRCParams.InitialDelay = ctx->initial_buffer_fullness; 307 } 308 else { 309 ctx->buffer_size = ctx->sRCParams.BitsPerSecond; 310 ctx->initial_buffer_fullness = ctx->sRCParams.BitsPerSecond; 311 ctx->sRCParams.BufferSize = ctx->buffer_size; 312 ctx->sRCParams.InitialLevel = (3 * ctx->sRCParams.BufferSize) >> 4; 313 /* Aligned with target frame size */ 314 ctx->sRCParams.InitialLevel += (frame_size / 2); 315 ctx->sRCParams.InitialLevel /= frame_size; 316 ctx->sRCParams.InitialLevel *= frame_size; 317 ctx->sRCParams.InitialDelay = ctx->buffer_size - ctx->sRCParams.InitialLevel; 318 } 319 320 if (ctx->raw_frame_count == 0) { 321 for (i = (ctx->ParallelCores - 1); i >= 0; i--) 322 pnw_set_bias(ctx, i); 323 } 324 325 pVUI_Params->bit_rate_value_minus1 = ctx->sRCParams.BitsPerSecond / 64 - 1; 326 pVUI_Params->cbp_size_value_minus1 = ctx->sRCParams.BufferSize / 64 - 1; 327 if (IMG_CODEC_H264_CBR != ctx->eCodec || 328 ctx->sRCParams.bDisableBitStuffing || 329 ctx->sRCParams.bDisableFrameSkipping) 330 pVUI_Params->CBR = 0; 331 else 332 pVUI_Params->CBR = 1; 333 334 pVUI_Params->initial_cpb_removal_delay_length_minus1 = BPH_SEI_NAL_INITIAL_CPB_REMOVAL_DELAY_SIZE - 1; 335 pVUI_Params->cpb_removal_delay_length_minus1 = PTH_SEI_NAL_CPB_REMOVAL_DELAY_SIZE - 1; 336 pVUI_Params->dpb_output_delay_length_minus1 = PTH_SEI_NAL_DPB_OUTPUT_DELAY_SIZE - 1; 337 pVUI_Params->time_offset_length = 24; 338 ctx->bInsertVUI = pSequenceParams->vui_parameters_present_flag ? IMG_TRUE: IMG_FALSE; 339 if (ctx->bInsertVUI) { 340 if (pSequenceParams->num_units_in_tick !=0 && pSequenceParams->time_scale !=0 341 && (pSequenceParams->time_scale > pSequenceParams->num_units_in_tick) ) { 342 pVUI_Params->Time_Scale = pSequenceParams->time_scale; 343 pVUI_Params->num_units_in_tick = pSequenceParams->num_units_in_tick; 344 } 345 else { 346 pVUI_Params->num_units_in_tick = 1; 347 pVUI_Params->Time_Scale = ctx->sRCParams.FrameRate * 2; 348 } 349 } 350 351 if (ctx->bInsertVUI && pSequenceParams->vui_fields.bits.aspect_ratio_info_present_flag && 352 (pSequenceParams->aspect_ratio_idc == 0xff /* Extended_SAR */)) { 353 pVUI_Params->aspect_ratio_info_present_flag = IMG_TRUE; 354 pVUI_Params->aspect_ratio_idc = 0xff; 355 pVUI_Params->sar_width = pSequenceParams->sar_width; 356 pVUI_Params->sar_height = pSequenceParams->sar_height; 357 } 358 359 sCrop.bClip = pSequenceParams->frame_cropping_flag; 360 sCrop.LeftCropOffset = 0; 361 sCrop.RightCropOffset = 0; 362 sCrop.TopCropOffset = 0; 363 sCrop.BottomCropOffset = 0; 364 365 if (!sCrop.bClip) { 366 if (ctx->RawHeight & 0xf) { 367 sCrop.bClip = IMG_TRUE; 368 sCrop.BottomCropOffset = (((ctx->RawHeight + 0xf) & (~0xf)) - ctx->RawHeight) / 2; 369 } 370 if (ctx->RawWidth & 0xf) { 371 sCrop.bClip = IMG_TRUE; 372 sCrop.RightCropOffset = (((ctx->RawWidth + 0xf) & (~0xf)) - ctx->RawWidth) / 2; 373 } 374 } else { 375 sCrop.LeftCropOffset = pSequenceParams->frame_crop_left_offset; 376 sCrop.RightCropOffset = pSequenceParams->frame_crop_right_offset; 377 sCrop.TopCropOffset = pSequenceParams->frame_crop_top_offset; 378 sCrop.BottomCropOffset = pSequenceParams->frame_crop_bottom_offset; 379 } 380 /* sequence header is always inserted */ 381 382 memset(cmdbuf->header_mem_p + ctx->seq_header_ofs, 383 0, 384 HEADER_SIZE); 385 386 /* 387 if (ctx->bInserHRDParams) { 388 memset(cmdbuf->header_mem_p + ctx->aud_header_ofs, 389 0, 390 HEADER_SIZE); 391 392 pnw__H264_prepare_AUD_header(cmdbuf->header_mem_p + ctx->aud_header_ofs); 393 pnw_cmdbuf_insert_command_package(ctx->obj_context, 394 ctx->ParallelCores - 1, 395 MTX_CMDID_DO_HEADER, 396 &cmdbuf->header_mem, 397 ctx->aud_header_ofs); 398 } 399 */ 400 if (ctx->eCodec == IMG_CODEC_H264_NO_RC) 401 pnw__H264_prepare_sequence_header(cmdbuf->header_mem_p + ctx->seq_header_ofs, 402 pSequenceParams->picture_width_in_mbs, 403 pSequenceParams->picture_height_in_mbs, 404 pSequenceParams->vui_parameters_present_flag, 405 pSequenceParams->vui_parameters_present_flag ? (pVUI_Params) : NULL, 406 &sCrop, 407 pSequenceParams->level_idc, ctx->profile_idc); 408 else 409 pnw__H264_prepare_sequence_header(cmdbuf->header_mem_p + ctx->seq_header_ofs, 410 pSequenceParams->picture_width_in_mbs, 411 pSequenceParams->picture_height_in_mbs, 412 pSequenceParams->vui_parameters_present_flag, 413 pSequenceParams->vui_parameters_present_flag ? (pVUI_Params) : NULL, 414 &sCrop, 415 pSequenceParams->level_idc, ctx->profile_idc); 416 417 /*Periodic IDR need SPS. We save the sequence header here*/ 418 if (ctx->sRCParams.IDRFreq != 0) { 419 if (NULL == ctx->save_seq_header_p) { 420 ctx->save_seq_header_p = malloc(HEADER_SIZE); 421 if (NULL == ctx->save_seq_header_p) { 422 drv_debug_msg(VIDEO_DEBUG_ERROR, "Ran out of memory!\n"); 423 free(pSequenceParams); 424 return VA_STATUS_ERROR_ALLOCATION_FAILED; 425 } 426 memcpy((unsigned char *)ctx->save_seq_header_p, 427 (unsigned char *)(cmdbuf->header_mem_p + ctx->seq_header_ofs), 428 HEADER_SIZE); 429 } 430 } 431 ctx->none_vcl_nal++; 432 cmdbuf->cmd_idx_saved[PNW_CMDBUF_SEQ_HEADER_IDX] = cmdbuf->cmd_idx; 433 /* Send to the last core as this will complete first */ 434 pnw_cmdbuf_insert_command_package(ctx->obj_context, 435 ctx->ParallelCores - 1, 436 MTX_CMDID_DO_HEADER, 437 &cmdbuf->header_mem, 438 ctx->seq_header_ofs); 439 free(pSequenceParams); 440 441 return VA_STATUS_SUCCESS; 442 } 443 444 445 static VAStatus pnw__H264ES_insert_SEI_buffer_period(context_ENC_p ctx) 446 { 447 unsigned int ui32nal_initial_cpb_removal_delay; 448 unsigned int ui32nal_initial_cpb_removal_delay_offset; 449 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 450 451 ui32nal_initial_cpb_removal_delay = 452 90000 * (1.0 * ctx->sRCParams.InitialDelay / ctx->sRCParams.BitsPerSecond); 453 ui32nal_initial_cpb_removal_delay_offset = 454 90000 * (1.0 * ctx->buffer_size / ctx->sRCParams.BitsPerSecond) 455 - ui32nal_initial_cpb_removal_delay; 456 457 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Insert SEI buffer period message with " 458 "ui32nal_initial_cpb_removal_delay(%d) and " 459 "ui32nal_initial_cpb_removal_delay_offset(%d)\n", 460 ui32nal_initial_cpb_removal_delay, 461 ui32nal_initial_cpb_removal_delay_offset); 462 463 memset(cmdbuf->header_mem_p + ctx->sei_buf_prd_ofs, 464 0, 465 HEADER_SIZE); 466 467 pnw__H264_prepare_SEI_buffering_period_header( 468 (MTX_HEADER_PARAMS *)(cmdbuf->header_mem_p + ctx->sei_buf_prd_ofs), 469 1, //ui8NalHrdBpPresentFlag, 470 0, //ui8nal_cpb_cnt_minus1, 471 1 + ctx->VUI_Params.initial_cpb_removal_delay_length_minus1, //ui8nal_initial_cpb_removal_delay_length, 472 ui32nal_initial_cpb_removal_delay, //ui32nal_initial_cpb_removal_delay, 473 ui32nal_initial_cpb_removal_delay_offset, //ui32nal_initial_cpb_removal_delay_offset, 474 0, //ui8VclHrdBpPresentFlag, 475 NOT_USED_BY_TOPAZ, //ui8vcl_cpb_cnt_minus1, 476 0, //ui32vcl_initial_cpb_removal_delay, 477 0 //ui32vcl_initial_cpb_removal_delay_offset 478 ); 479 cmdbuf->cmd_idx_saved[PNW_CMDBUF_SEI_BUF_PERIOD_IDX] = cmdbuf->cmd_idx; 480 pnw_cmdbuf_insert_command_package(ctx->obj_context, 481 ctx->ParallelCores - 1, 482 MTX_CMDID_DO_HEADER, 483 &cmdbuf->header_mem, 484 ctx->sei_buf_prd_ofs); 485 486 ctx->none_vcl_nal++; 487 return VA_STATUS_SUCCESS; 488 } 489 490 491 static VAStatus pnw__H264ES_insert_SEI_pic_timing(context_ENC_p ctx) 492 { 493 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 494 uint32_t ui32cpb_removal_delay; 495 496 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Insert SEI picture timing message. \n"); 497 498 memset(cmdbuf->header_mem_p + ctx->sei_pic_tm_ofs, 499 0, 500 HEADER_SIZE); 501 502 /* ui32cpb_removal_delay is zero for 1st frame and will be reset 503 * after a IDR frame */ 504 if (ctx->obj_context->frame_count == 0) { 505 if (ctx->raw_frame_count == 0) 506 ui32cpb_removal_delay = 0; 507 else 508 ui32cpb_removal_delay = 509 ctx->sRCParams.IDRFreq * ctx->sRCParams.IntraFreq * 2; 510 } else 511 ui32cpb_removal_delay = 2 * ctx->obj_context->frame_count; 512 513 pnw__H264_prepare_SEI_picture_timing_header( 514 (MTX_HEADER_PARAMS *)(cmdbuf->header_mem_p + ctx->sei_pic_tm_ofs), 515 1, 516 ctx->VUI_Params.cpb_removal_delay_length_minus1, 517 ctx->VUI_Params.dpb_output_delay_length_minus1, 518 ui32cpb_removal_delay, //ui32cpb_removal_delay, 519 2, //ui32dpb_output_delay, 520 0, //ui8pic_struct_present_flag, 521 0, //ui8pic_struct, 522 0, //ui8NumClockTS, 523 0, //*aui8clock_timestamp_flag, 524 0, //ui8full_timestamp_flag, 525 0, //ui8seconds_flag, 526 0, //ui8minutes_flag, 527 0, //ui8hours_flag, 528 0, //ui8seconds_value, 529 0, //ui8minutes_value, 530 0, //ui8hours_value, 531 0, //ui8ct_type, 532 0, //ui8nuit_field_based_flag, 533 0, //ui8counting_type, 534 0, //ui8discontinuity_flag, 535 0, //ui8cnt_dropped_flag, 536 0, //ui8n_frames, 537 0, //ui8time_offset_length, 538 0 //i32time_offset) 539 ); 540 541 cmdbuf->cmd_idx_saved[PNW_CMDBUF_SEI_PIC_TIMING_IDX] = cmdbuf->cmd_idx; 542 pnw_cmdbuf_insert_command_package(ctx->obj_context, 543 ctx->ParallelCores - 1, 544 MTX_CMDID_DO_HEADER, 545 &cmdbuf->header_mem, 546 ctx->sei_pic_tm_ofs); 547 548 ctx->none_vcl_nal++; 549 return VA_STATUS_SUCCESS; 550 } 551 552 #if PSB_MFLD_DUMMY_CODE 553 static VAStatus pnw__H264ES_insert_SEI_FPA_param(context_ENC_p ctx, object_buffer_p obj_buffer) 554 { 555 VAStatus vaStatus = VA_STATUS_SUCCESS; 556 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 557 VAEncPackedHeaderParameterBuffer *sei_param_buf = (VAEncPackedHeaderParameterBuffer *)obj_buffer->buffer_data; 558 559 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Insert SEI frame packing arrangement message. \n"); 560 ctx->sei_pic_data_size = sei_param_buf->bit_length/8; 561 562 return VA_STATUS_SUCCESS; 563 } 564 565 static VAStatus pnw__H264ES_insert_SEI_FPA_data(context_ENC_p ctx, object_buffer_p obj_buffer) 566 { 567 VAStatus vaStatus = VA_STATUS_SUCCESS; 568 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 569 char *sei_data_buf; 570 571 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Insert SEI frame packing arrangement message. \n"); 572 573 memset(cmdbuf->header_mem_p + ctx->sei_pic_fpa_ofs, 574 0, 575 HEADER_SIZE); 576 sei_data_buf = (char *)obj_buffer->buffer_data; 577 578 pnw__H264_prepare_SEI_FPA_header((MTX_HEADER_PARAMS *)(cmdbuf->header_mem_p + ctx->sei_pic_fpa_ofs), sei_data_buf, ctx->sei_pic_data_size); 579 pnw_cmdbuf_insert_command_package(ctx->obj_context, 580 ctx->ParallelCores - 1, 581 MTX_CMDID_DO_HEADER, 582 &cmdbuf->header_mem, 583 ctx->sei_pic_fpa_ofs); 584 585 return VA_STATUS_SUCCESS; 586 } 587 #endif 588 589 static VAStatus pnw__H264ES_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer) 590 { 591 VAStatus vaStatus = VA_STATUS_SUCCESS; 592 int i; 593 VAEncPictureParameterBufferH264 *pBuffer; 594 int need_sps = 0; 595 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 596 597 ASSERT(obj_buffer->type == VAEncPictureParameterBufferType); 598 599 if ((obj_buffer->num_elements != 1) || 600 (obj_buffer->size != sizeof(VAEncPictureParameterBufferH264))) { 601 return VA_STATUS_ERROR_UNKNOWN; 602 } 603 604 /* Transfer ownership of VAEncPictureParameterBufferH264 data */ 605 pBuffer = (VAEncPictureParameterBufferH264 *) obj_buffer->buffer_data; 606 obj_buffer->buffer_data = NULL; 607 obj_buffer->size = 0; 608 609 ctx->ref_surface = SURFACE(pBuffer->ReferenceFrames[0].picture_id); 610 ctx->dest_surface = SURFACE(pBuffer->CurrPic.picture_id); 611 ctx->coded_buf = BUFFER(pBuffer->coded_buf); 612 613 //ASSERT(ctx->Width == pBuffer->picture_width); 614 //ASSERT(ctx->Height == pBuffer->picture_height); 615 616 if (NULL == ctx->coded_buf) { 617 drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__); 618 free(pBuffer); 619 return VA_STATUS_ERROR_INVALID_BUFFER; 620 } 621 if ((ctx->sRCParams.IntraFreq != 0) && (ctx->sRCParams.IDRFreq != 0)) { /* period IDR is desired */ 622 unsigned int is_intra = 0; 623 unsigned int intra_cnt = 0; 624 625 ctx->force_idr_h264 = 0; 626 627 if ((ctx->obj_context->frame_count % ctx->sRCParams.IntraFreq) == 0) { 628 is_intra = 1; /* suppose current frame is I frame */ 629 intra_cnt = ctx->obj_context->frame_count / ctx->sRCParams.IntraFreq; 630 } 631 632 /* current frame is I frame (suppose), and an IDR frame is desired*/ 633 if ((is_intra) && ((intra_cnt % ctx->sRCParams.IDRFreq) == 0)) { 634 ctx->force_idr_h264 = 1; 635 /*When two consecutive access units in decoding order are both IDR access 636 * units, the value of idr_pic_id in the slices of the first such IDR 637 * access unit shall differ from the idr_pic_id in the second such IDR 638 * access unit. We set it with 1 or 0 alternately.*/ 639 ctx->idr_pic_id = 1 - ctx->idr_pic_id; 640 641 /* it is periodic IDR in the middle of one sequence encoding, need SPS */ 642 if (ctx->obj_context->frame_count > 0) 643 need_sps = 1; 644 645 ctx->obj_context->frame_count = 0; 646 } 647 } 648 649 /* If VUI header isn't enabled, we'll igore the request for HRD header insertion */ 650 if (ctx->bInserHRDParams) 651 ctx->bInserHRDParams = ctx->bInsertVUI; 652 653 /* For H264, PicHeader only needed in the first picture*/ 654 if (!(ctx->obj_context->frame_count)) { 655 cmdbuf = ctx->obj_context->pnw_cmdbuf; 656 657 if (need_sps) { 658 drv_debug_msg(VIDEO_DEBUG_GENERAL, "TOPAZ: insert a SPS before IDR frame\n"); 659 /* reuse the previous SPS */ 660 memcpy((unsigned char *)(cmdbuf->header_mem_p + ctx->seq_header_ofs), 661 (unsigned char *)ctx->save_seq_header_p, 662 HEADER_SIZE); 663 664 cmdbuf->cmd_idx_saved[PNW_CMDBUF_SEQ_HEADER_IDX] = cmdbuf->cmd_idx; 665 /* Send to the last core as this will complete first */ 666 pnw_cmdbuf_insert_command_package(ctx->obj_context, 667 ctx->ParallelCores - 1, 668 MTX_CMDID_DO_HEADER, 669 &cmdbuf->header_mem, 670 ctx->seq_header_ofs); 671 ctx->none_vcl_nal++; 672 } 673 674 if (ctx->bInserHRDParams) { 675 pnw__H264ES_insert_SEI_buffer_period(ctx); 676 pnw__H264ES_insert_SEI_pic_timing(ctx); 677 } 678 679 pnw__H264_prepare_picture_header(cmdbuf->header_mem_p + ctx->pic_header_ofs, IMG_FALSE, ctx->sRCParams.QCPOffset); 680 681 cmdbuf->cmd_idx_saved[PNW_CMDBUF_PIC_HEADER_IDX] = cmdbuf->cmd_idx; 682 /* Send to the last core as this will complete first */ 683 pnw_cmdbuf_insert_command_package(ctx->obj_context, 684 ctx->ParallelCores - 1, 685 MTX_CMDID_DO_HEADER, 686 &cmdbuf->header_mem, 687 ctx->pic_header_ofs); 688 ctx->none_vcl_nal++; 689 } 690 else if (ctx->bInserHRDParams) 691 pnw__H264ES_insert_SEI_pic_timing(ctx); 692 693 if (ctx->ParallelCores == 1) { 694 ctx->coded_buf_per_slice = 0; 695 drv_debug_msg(VIDEO_DEBUG_GENERAL, "TOPAZ: won't splite coded buffer(%d) since only one slice being encoded\n", 696 ctx->coded_buf->size); 697 } else { 698 /*Make sure DMA start is 128bits alignment*/ 699 ctx->coded_buf_per_slice = (ctx->coded_buf->size / ctx->ParallelCores) & (~0xf) ; 700 drv_debug_msg(VIDEO_DEBUG_GENERAL, "TOPAZ: the size of coded_buf per slice %d( Total %d) \n", ctx->coded_buf_per_slice, 701 ctx->coded_buf->size); 702 } 703 704 /* Prepare START_PICTURE params */ 705 /* FIXME is really need multiple picParams? Need multiple calculate for each? */ 706 for (i = (ctx->ParallelCores - 1); i >= 0; i--) 707 vaStatus = pnw_RenderPictureParameter(ctx, i); 708 709 free(pBuffer); 710 return vaStatus; 711 } 712 713 static VAStatus pnw__H264ES_encode_one_slice(context_ENC_p ctx, 714 VAEncSliceParameterBuffer *pBuffer) 715 { 716 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 717 unsigned int MBSkipRun, FirstMBAddress; 718 unsigned char deblock_idc; 719 unsigned char is_intra = 0; 720 int slice_param_idx; 721 PIC_PARAMS *psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p); 722 VAStatus vaStatus = VA_STATUS_SUCCESS; 723 724 /*Slice encoding Order: 725 *1.Insert Do header command 726 *2.setup InRowParams 727 *3.setup Slice params 728 *4.Insert Do slice command 729 * */ 730 731 if (pBuffer->slice_height > (ctx->Height / 16) || 732 pBuffer->start_row_number > (ctx->Height / 16) || 733 (pBuffer->slice_height + pBuffer->start_row_number) > (ctx->Height / 16)) { 734 drv_debug_msg(VIDEO_DEBUG_ERROR, "slice height %d or start row number %d is too large", 735 pBuffer->slice_height, pBuffer->start_row_number); 736 return VA_STATUS_ERROR_INVALID_PARAMETER; 737 } 738 MBSkipRun = (pBuffer->slice_height * ctx->Width) / 16; 739 deblock_idc = pBuffer->slice_flags.bits.disable_deblocking_filter_idc; 740 741 /*If the frame is skipped, it shouldn't be a I frame*/ 742 if (ctx->force_idr_h264 || (ctx->obj_context->frame_count == 0)) { 743 is_intra = 1; 744 } else 745 is_intra = (ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip) ? 0 : pBuffer->slice_flags.bits.is_intra; 746 747 FirstMBAddress = (pBuffer->start_row_number * ctx->Width) / 16; 748 749 memset(cmdbuf->header_mem_p + ctx->slice_header_ofs 750 + ctx->obj_context->slice_count * HEADER_SIZE, 751 0, 752 HEADER_SIZE); 753 754 /* Insert Do Header command, relocation is needed */ 755 pnw__H264_prepare_slice_header(cmdbuf->header_mem_p + ctx->slice_header_ofs 756 + ctx->obj_context->slice_count * HEADER_SIZE, 757 is_intra, 758 pBuffer->slice_flags.bits.disable_deblocking_filter_idc, 759 ctx->obj_context->frame_count, 760 FirstMBAddress, 761 MBSkipRun, 762 0, 763 ctx->force_idr_h264, 764 IMG_FALSE, 765 IMG_FALSE, 766 ctx->idr_pic_id); 767 768 /* ensure that this slice is consequtive to that last processed by the target core */ 769 /* 770 ASSERT( -1 == ctx->LastSliceNum[ctx->SliceToCore] 771 || ctx->obj_context->slice_count == 1 + ctx->LastSliceNum[ctx->SliceToCore] ); 772 */ 773 /* note the slice number the target core is now processing */ 774 ctx->LastSliceNum[ctx->SliceToCore] = ctx->obj_context->slice_count; 775 776 pnw_cmdbuf_insert_command_package(ctx->obj_context, 777 ctx->SliceToCore, 778 MTX_CMDID_DO_HEADER, 779 &cmdbuf->header_mem, 780 ctx->slice_header_ofs + ctx->obj_context->slice_count * HEADER_SIZE); 781 if (!(ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip)) { 782 /*Only reset on the first frame. It's more effective than DDK. Have confirmed with IMG*/ 783 if (ctx->obj_context->frame_count == 0) 784 pnw_reset_encoder_params(ctx); 785 if ((pBuffer->start_row_number == 0) && pBuffer->slice_flags.bits.is_intra) { 786 ctx->BelowParamsBufIdx = (ctx->BelowParamsBufIdx + 1) & 0x1; 787 } 788 789 slice_param_idx = (pBuffer->slice_flags.bits.is_intra ? 0 : 1) * ctx->slice_param_num 790 + ctx->obj_context->slice_count; 791 if (VAEncSliceParameter_Equal(&ctx->slice_param_cache[slice_param_idx], pBuffer) == 0) { 792 /* cache current param parameters */ 793 memcpy(&ctx->slice_param_cache[slice_param_idx], 794 pBuffer, sizeof(VAEncSliceParameterBuffer)); 795 796 /* Setup InParams value*/ 797 pnw_setup_slice_params(ctx, 798 pBuffer->start_row_number * 16, 799 pBuffer->slice_height * 16, 800 pBuffer->slice_flags.bits.is_intra, 801 ctx->obj_context->frame_count > 0, 802 psPicParams->sInParams.SeInitQP); 803 } 804 805 /* Insert do slice command and setup related buffer value */ 806 pnw__send_encode_slice_params(ctx, 807 pBuffer->slice_flags.bits.is_intra, 808 pBuffer->start_row_number * 16, 809 deblock_idc, 810 ctx->obj_context->frame_count, 811 pBuffer->slice_height * 16, 812 ctx->obj_context->slice_count); 813 814 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Now frame_count/slice_count is %d/%d\n", 815 ctx->obj_context->frame_count, ctx->obj_context->slice_count); 816 } 817 ctx->obj_context->slice_count++; 818 819 return vaStatus; 820 } 821 822 /* convert from VAEncSliceParameterBufferH264 to VAEncSliceParameterBuffer */ 823 static VAStatus pnw__convert_sliceparameter_buffer(VAEncSliceParameterBufferH264 *pBufferH264, 824 VAEncSliceParameterBuffer *pBuffer, 825 int picture_width_in_mbs, 826 unsigned int num_elemenent) 827 { 828 unsigned int i; 829 830 for (i = 0; i < num_elemenent; i++) { 831 pBuffer->start_row_number = pBufferH264->macroblock_address / picture_width_in_mbs; 832 pBuffer->slice_height = pBufferH264->num_macroblocks / picture_width_in_mbs; 833 pBuffer->slice_flags.bits.is_intra = 834 (((pBufferH264->slice_type == 2) || (pBufferH264->slice_type == 7)) ? 1 : 0); 835 pBuffer->slice_flags.bits.disable_deblocking_filter_idc = pBufferH264->disable_deblocking_filter_idc; 836 837 /* next conversion */ 838 pBuffer++; 839 pBufferH264++; 840 } 841 842 return 0; 843 } 844 845 static VAStatus pnw__H264ES_process_slice_param(context_ENC_p ctx, object_buffer_p obj_buffer) 846 { 847 /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */ 848 VAEncSliceParameterBuffer *pBuf_per_core, *pBuffer; 849 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 850 PIC_PARAMS *psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p); 851 unsigned int i, j, slice_per_core; 852 VAStatus vaStatus = VA_STATUS_SUCCESS; 853 854 ASSERT(obj_buffer->type == VAEncSliceParameterBufferType); 855 856 if (obj_buffer->num_elements > (ctx->Height / 16)) { 857 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 858 goto out2; 859 } 860 cmdbuf = ctx->obj_context->pnw_cmdbuf; 861 psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p; 862 863 /* Transfer ownership of VAEncPictureParameterBuffer data */ 864 if (obj_buffer->size == sizeof(VAEncSliceParameterBufferH264)) { 865 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Receive VAEncSliceParameterBufferH264 buffer"); 866 pBuffer = calloc(obj_buffer->num_elements, sizeof(VAEncSliceParameterBuffer)); 867 868 if (pBuffer == NULL) { 869 drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n"); 870 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; 871 goto out2; 872 } 873 874 pnw__convert_sliceparameter_buffer((VAEncSliceParameterBufferH264 *)obj_buffer->buffer_data, 875 pBuffer, 876 ctx->Width / 16, 877 obj_buffer->num_elements); 878 } else if (obj_buffer->size == sizeof(VAEncSliceParameterBuffer)) { 879 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Receive VAEncSliceParameterBuffer buffer"); 880 pBuffer = (VAEncSliceParameterBuffer *) obj_buffer->buffer_data; 881 } else { 882 drv_debug_msg(VIDEO_DEBUG_ERROR, "Buffer size(%d) is wrong. It should be %d or %d\n", 883 obj_buffer->size, sizeof(VAEncSliceParameterBuffer), 884 sizeof(VAEncSliceParameterBufferH264)); 885 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 886 goto out2; 887 } 888 889 obj_buffer->size = 0; 890 891 /*In case the slice number changes*/ 892 if ((ctx->slice_param_cache != NULL) && (obj_buffer->num_elements != ctx->slice_param_num)) { 893 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Slice number changes. Previous value is %d. Now it's %d\n", 894 ctx->slice_param_num, obj_buffer->num_elements); 895 free(ctx->slice_param_cache); 896 ctx->slice_param_cache = NULL; 897 ctx->slice_param_num = 0; 898 } 899 900 if (NULL == ctx->slice_param_cache) { 901 ctx->slice_param_num = obj_buffer->num_elements; 902 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Allocate %d VAEncSliceParameterBuffer cache buffers\n", 2 * ctx->slice_param_num); 903 ctx->slice_param_cache = calloc(2 * ctx->slice_param_num, sizeof(VAEncSliceParameterBuffer)); 904 if (NULL == ctx->slice_param_cache) { 905 drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n"); 906 907 /* free the converted VAEncSliceParameterBuffer */ 908 if (obj_buffer->size == sizeof(VAEncSliceParameterBufferH264)) 909 free(pBuffer); 910 free(obj_buffer->buffer_data); 911 return VA_STATUS_ERROR_ALLOCATION_FAILED; 912 } 913 } 914 915 ctx->sRCParams.Slices = obj_buffer->num_elements; 916 if (getenv("PSB_VIDEO_SIG_CORE") == NULL) { 917 if ((ctx->ParallelCores == 2) && (obj_buffer->num_elements == 1)) { 918 /*Need to replace unneccesary MTX_CMDID_STARTPICs with MTX_CMDID_PAD*/ 919 for (i = 0; i < (ctx->ParallelCores - 1); i++) { 920 *(cmdbuf->cmd_idx_saved[PNW_CMDBUF_START_PIC_IDX] + i * 4) &= (~MTX_CMDWORD_ID_MASK); 921 *(cmdbuf->cmd_idx_saved[PNW_CMDBUF_START_PIC_IDX] + i * 4) |= MTX_CMDID_PAD; 922 } 923 drv_debug_msg(VIDEO_DEBUG_GENERAL, " Remove unneccesary %d MTX_CMDID_STARTPIC commands from cmdbuf\n", 924 ctx->ParallelCores - obj_buffer->num_elements); 925 ctx->ParallelCores = obj_buffer->num_elements; 926 927 /* All header generation commands should be send to core 0*/ 928 for (i = PNW_CMDBUF_SEQ_HEADER_IDX; i < PNW_CMDBUF_SAVING_MAX; i++) { 929 if (cmdbuf->cmd_idx_saved[i] != 0) 930 *(cmdbuf->cmd_idx_saved[i]) &= 931 ~(MTX_CMDWORD_CORE_MASK << MTX_CMDWORD_CORE_SHIFT); 932 } 933 934 ctx->SliceToCore = ctx->ParallelCores - 1; 935 } 936 } 937 938 slice_per_core = obj_buffer->num_elements / ctx->ParallelCores; 939 pBuf_per_core = pBuffer; 940 for (i = 0; i < slice_per_core; i++) { 941 pBuffer = pBuf_per_core; 942 for (j = 0; j < ctx->ParallelCores; j++) { 943 vaStatus = pnw__H264ES_encode_one_slice(ctx, pBuffer); 944 if (vaStatus != VA_STATUS_SUCCESS) 945 goto out1; 946 if (0 == ctx->SliceToCore) { 947 ctx->SliceToCore = ctx->ParallelCores; 948 } 949 ctx->SliceToCore--; 950 951 ASSERT(ctx->obj_context->slice_count < MAX_SLICES_PER_PICTURE); 952 /*Move to the next buffer which will be sent to core j*/ 953 pBuffer += slice_per_core; 954 } 955 pBuf_per_core++; /* Move to the next buffer */ 956 } 957 958 /*Cope with last slice when slice number is odd and parallelCores is even*/ 959 if (obj_buffer->num_elements > (slice_per_core * ctx->ParallelCores)) { 960 ctx->SliceToCore = 0; 961 pBuffer -= slice_per_core; 962 pBuffer ++; 963 vaStatus = pnw__H264ES_encode_one_slice(ctx, pBuffer); 964 } 965 out1: 966 /* free the converted VAEncSliceParameterBuffer */ 967 if (obj_buffer->size == sizeof(VAEncSliceParameterBufferH264)) 968 free(pBuffer); 969 970 out2: 971 free(obj_buffer->buffer_data); 972 obj_buffer->buffer_data = NULL; 973 974 return vaStatus; 975 } 976 977 static VAStatus pnw__H264ES_process_misc_param(context_ENC_p ctx, object_buffer_p obj_buffer) 978 { 979 /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */ 980 VAEncMiscParameterBuffer *pBuffer; 981 VAEncMiscParameterRateControl *rate_control_param; 982 VAEncMiscParameterAIR *air_param; 983 VAEncMiscParameterMaxSliceSize *max_slice_size_param; 984 VAEncMiscParameterFrameRate *frame_rate_param; 985 VAEncMiscParameterHRD *hrd_param; 986 VAStatus vaStatus = VA_STATUS_SUCCESS; 987 unsigned int max_bps; 988 unsigned int frame_size; 989 990 ASSERT(obj_buffer->type == VAEncMiscParameterBufferType); 991 992 993 /* Transfer ownership of VAEncMiscParameterBuffer data */ 994 pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data; 995 obj_buffer->size = 0; 996 997 if (ctx->eCodec != IMG_CODEC_H264_VCM 998 && (pBuffer->type != VAEncMiscParameterTypeHRD 999 && pBuffer->type != VAEncMiscParameterTypeRateControl 1000 && pBuffer->type != VAEncMiscParameterTypeFrameRate)) { 1001 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Buffer type %d isn't supported in none VCM mode.\n", 1002 pBuffer->type); 1003 free(obj_buffer->buffer_data); 1004 obj_buffer->buffer_data = NULL; 1005 return VA_STATUS_SUCCESS; 1006 } 1007 1008 switch (pBuffer->type) { 1009 case VAEncMiscParameterTypeFrameRate: 1010 frame_rate_param = (VAEncMiscParameterFrameRate *)pBuffer->data; 1011 1012 if (frame_rate_param->framerate < 1 || frame_rate_param->framerate > 65535) { 1013 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1014 break; 1015 } 1016 1017 if (ctx->sRCParams.FrameRate == frame_rate_param->framerate) 1018 break; 1019 1020 drv_debug_msg(VIDEO_DEBUG_GENERAL, "frame rate changed from %d to %d\n", 1021 ctx->sRCParams.FrameRate, 1022 frame_rate_param->framerate); 1023 ctx->sRCParams.FrameRate = frame_rate_param->framerate; 1024 ctx->sRCParams.bBitrateChanged = IMG_TRUE; 1025 1026 ctx->sRCParams.FrameRate = (frame_rate_param->framerate < 1) ? 1 : 1027 ((65535 < frame_rate_param->framerate) ? 65535 : frame_rate_param->framerate); 1028 break; 1029 1030 case VAEncMiscParameterTypeRateControl: 1031 rate_control_param = (VAEncMiscParameterRateControl *)pBuffer->data; 1032 1033 /* Currently, none VCM mode only supports frame skip and bit stuffing 1034 * disable flag and doesn't accept other parameters in 1035 * buffer of VAEncMiscParameterTypeRateControl type */ 1036 if (rate_control_param->rc_flags.value != 0 || ctx->raw_frame_count == 0) { 1037 if (rate_control_param->rc_flags.bits.disable_frame_skip) 1038 ctx->sRCParams.bDisableFrameSkipping = IMG_TRUE; 1039 if (rate_control_param->rc_flags.bits.disable_bit_stuffing) 1040 ctx->sRCParams.bDisableBitStuffing = IMG_TRUE; 1041 drv_debug_msg(VIDEO_DEBUG_GENERAL, 1042 "bDisableFrameSkipping is %d and bDisableBitStuffing is %d\n", 1043 ctx->sRCParams.bDisableFrameSkipping, ctx->sRCParams.bDisableBitStuffing); 1044 } 1045 1046 if (rate_control_param->initial_qp > 51 || 1047 rate_control_param->min_qp > 51) { 1048 drv_debug_msg(VIDEO_DEBUG_ERROR, "Initial_qp(%d) and min_qpinitial_qp(%d) " 1049 "are invalid.\nQP shouldn't be larger than 51 for H264\n", 1050 rate_control_param->initial_qp, rate_control_param->min_qp); 1051 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1052 break; 1053 } 1054 1055 if (rate_control_param->window_size > 2000) { 1056 drv_debug_msg(VIDEO_DEBUG_ERROR, "window_size is too much!\n"); 1057 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1058 break; 1059 } 1060 1061 /* Check if any none-zero RC parameter is changed*/ 1062 if ((rate_control_param->bits_per_second == 0 || 1063 rate_control_param->bits_per_second == ctx->sRCParams.BitsPerSecond) && 1064 (rate_control_param->window_size == 0 || 1065 ctx->sRCParams.BufferSize == ctx->sRCParams.BitsPerSecond / 1000 * rate_control_param->window_size) && 1066 (ctx->sRCParams.MinQP == rate_control_param->min_qp) && 1067 (ctx->sRCParams.InitialQp == rate_control_param->initial_qp) && 1068 (rate_control_param->basic_unit_size == 0 || 1069 ctx->sRCParams.BUSize == rate_control_param->basic_unit_size)) { 1070 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s No RC parameter is changed\n", 1071 __FUNCTION__); 1072 break; 1073 } 1074 else if (ctx->raw_frame_count != 0 || ctx->eCodec == IMG_CODEC_H264_VCM) 1075 ctx->sRCParams.bBitrateChanged = IMG_TRUE; 1076 1077 /* The initial target bitrate is set by Sequence parameter buffer. 1078 Here is for changed bitrate only */ 1079 if (rate_control_param->bits_per_second > TOPAZ_H264_MAX_BITRATE) { 1080 drv_debug_msg(VIDEO_DEBUG_ERROR, " bits_per_second(%d) exceeds \ 1081 the maximum bitrate, set it with %d\n", 1082 rate_control_param->bits_per_second, 1083 TOPAZ_H264_MAX_BITRATE); 1084 break; 1085 } 1086 /* The initial target bitrate is set by Sequence parameter buffer. 1087 Here is for changed bitrate only */ 1088 if (rate_control_param->bits_per_second != 0 && 1089 ctx->raw_frame_count != 0) { 1090 drv_debug_msg(VIDEO_DEBUG_GENERAL, 1091 "bitrate is changed from %d to %d on frame %d\n", 1092 ctx->sRCParams.BitsPerSecond, 1093 rate_control_param->bits_per_second, 1094 ctx->raw_frame_count); 1095 max_bps = (ctx->Width * ctx->Height * 3 / 2 ) * 8 * ctx->sRCParams.FrameRate; 1096 if (ctx->Width > 720) 1097 max_bps /= 4; 1098 else 1099 max_bps /= 2; 1100 1101 drv_debug_msg(VIDEO_DEBUG_GENERAL, " width %d height %d, frame rate %d\n", 1102 ctx->Width, ctx->Height, ctx->sRCParams.FrameRate); 1103 if (rate_control_param->bits_per_second > max_bps) { 1104 drv_debug_msg(VIDEO_DEBUG_ERROR, 1105 "Invalid bitrate %d, violate ITU-T Rec. H.264 (03/2005) A.3.1" 1106 "\n clip to %d bps\n", rate_control_param->bits_per_second, max_bps); 1107 ctx->sRCParams.BitsPerSecond = max_bps; 1108 } else { 1109 /* See 110% target bitrate for VCM. Otherwise, the resulted bitrate is much lower 1110 than target bitrate */ 1111 if (ctx->eCodec == IMG_CODEC_H264_VCM) 1112 rate_control_param->bits_per_second = 1113 rate_control_param->bits_per_second / 100 * 110; 1114 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Bitrate is set to %d\n", 1115 rate_control_param->bits_per_second); 1116 ctx->sRCParams.BitsPerSecond = rate_control_param->bits_per_second; 1117 } 1118 } 1119 1120 if (rate_control_param->min_qp != 0) 1121 ctx->sRCParams.MinQP = rate_control_param->min_qp; 1122 if (rate_control_param->window_size != 0) { 1123 ctx->sRCParams.BufferSize = 1124 ctx->sRCParams.BitsPerSecond / 1000 * rate_control_param->window_size; 1125 if (ctx->sRCParams.FrameRate == 0) { 1126 drv_debug_msg(VIDEO_DEBUG_ERROR, "frame rate can't be zero. Set it to 30"); 1127 ctx->sRCParams.FrameRate = 30; 1128 } 1129 1130 frame_size = ctx->sRCParams.BitsPerSecond / ctx->sRCParams.FrameRate; 1131 if (frame_size == 0) { 1132 drv_debug_msg(VIDEO_DEBUG_ERROR, "Bitrate is too low %d\n", 1133 ctx->sRCParams.BitsPerSecond); 1134 break; 1135 } 1136 ctx->sRCParams.InitialLevel = (3 * ctx->sRCParams.BufferSize) >> 4; 1137 ctx->sRCParams.InitialLevel += (frame_size / 2); 1138 ctx->sRCParams.InitialLevel /= frame_size; 1139 ctx->sRCParams.InitialLevel *= frame_size; 1140 ctx->sRCParams.InitialDelay = 1141 ctx->sRCParams.BufferSize - ctx->sRCParams.InitialLevel; 1142 } 1143 1144 if (rate_control_param->initial_qp != 0) 1145 ctx->sRCParams.InitialQp = rate_control_param->initial_qp; 1146 if (rate_control_param->basic_unit_size != 0) 1147 ctx->sRCParams.BUSize = rate_control_param->basic_unit_size; 1148 1149 drv_debug_msg(VIDEO_DEBUG_GENERAL, 1150 "Set Misc parameters(frame %d): window_size %d, initial qp %d\n" \ 1151 "\tmin qp %d, bunit size %d\n", 1152 ctx->raw_frame_count, 1153 rate_control_param->window_size, 1154 rate_control_param->initial_qp, 1155 rate_control_param->min_qp, 1156 rate_control_param->basic_unit_size); 1157 break; 1158 1159 case VAEncMiscParameterTypeMaxSliceSize: 1160 max_slice_size_param = (VAEncMiscParameterMaxSliceSize *)pBuffer->data; 1161 1162 /*The max slice size should not be bigger than 1920x1080x1.5x8 */ 1163 if (max_slice_size_param->max_slice_size > 24883200) { 1164 drv_debug_msg(VIDEO_DEBUG_ERROR,"Invalid max_slice_size. It should be 1~ 24883200.\n"); 1165 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1166 break; 1167 } 1168 1169 if (ctx->max_slice_size == max_slice_size_param->max_slice_size) 1170 break; 1171 1172 drv_debug_msg(VIDEO_DEBUG_GENERAL, "max slice size changed to %d\n", 1173 max_slice_size_param->max_slice_size); 1174 1175 ctx->max_slice_size = max_slice_size_param->max_slice_size; 1176 1177 break; 1178 1179 case VAEncMiscParameterTypeAIR: 1180 air_param = (VAEncMiscParameterAIR *)pBuffer->data; 1181 1182 if (air_param->air_num_mbs > 65535 || 1183 air_param->air_threshold > 65535) { 1184 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1185 break; 1186 } 1187 1188 drv_debug_msg(VIDEO_DEBUG_GENERAL,"air slice size changed to num_air_mbs %d " 1189 "air_threshold %d, air_auto %d\n", 1190 air_param->air_num_mbs, air_param->air_threshold, 1191 air_param->air_auto); 1192 1193 if (((ctx->Height * ctx->Width) >> 8) < (int)air_param->air_num_mbs) 1194 air_param->air_num_mbs = ((ctx->Height * ctx->Width) >> 8); 1195 if (air_param->air_threshold == 0) 1196 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: air threshold is set to zero\n", 1197 __func__); 1198 ctx->num_air_mbs = air_param->air_num_mbs; 1199 ctx->air_threshold = air_param->air_threshold; 1200 //ctx->autotune_air_flag = air_param->air_auto; 1201 1202 break; 1203 1204 case VAEncMiscParameterTypeHRD: 1205 hrd_param = (VAEncMiscParameterHRD *)pBuffer->data; 1206 1207 if (hrd_param->buffer_size == 0 1208 || hrd_param->initial_buffer_fullness == 0) 1209 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Find zero value for buffer_size " 1210 "and initial_buffer_fullness.\n" 1211 "Will assign default value to them later \n"); 1212 1213 if (ctx->initial_buffer_fullness > ctx->buffer_size) { 1214 drv_debug_msg(VIDEO_DEBUG_ERROR, "initial_buffer_fullnessi(%d) shouldn't be" 1215 " larger that buffer_size(%d)!\n", 1216 hrd_param->initial_buffer_fullness, 1217 hrd_param->buffer_size); 1218 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1219 break; 1220 } 1221 1222 if (!ctx->sRCParams.RCEnable) { 1223 drv_debug_msg(VIDEO_DEBUG_ERROR, "Only when rate control is enabled," 1224 " VAEncMiscParameterTypeHRD will take effect.\n"); 1225 break; 1226 } 1227 1228 ctx->buffer_size = hrd_param->buffer_size; 1229 ctx->initial_buffer_fullness = hrd_param->initial_buffer_fullness; 1230 ctx->bInserHRDParams = IMG_TRUE; 1231 drv_debug_msg(VIDEO_DEBUG_GENERAL, "hrd param buffer_size set to %d " 1232 "initial buffer fullness set to %d\n", 1233 ctx->buffer_size, ctx->initial_buffer_fullness); 1234 1235 break; 1236 1237 default: 1238 vaStatus = VA_STATUS_ERROR_UNKNOWN; 1239 DEBUG_FAILURE; 1240 break; 1241 } 1242 1243 free(obj_buffer->buffer_data); 1244 obj_buffer->buffer_data = NULL; 1245 1246 return vaStatus; 1247 } 1248 1249 1250 1251 static VAStatus pnw_H264ES_RenderPicture( 1252 object_context_p obj_context, 1253 object_buffer_p *buffers, 1254 int num_buffers) 1255 { 1256 INIT_CONTEXT_H264ES; 1257 VAStatus vaStatus = VA_STATUS_SUCCESS; 1258 int i; 1259 1260 drv_debug_msg(VIDEO_DEBUG_GENERAL,"pnw_H264ES_RenderPicture\n"); 1261 1262 for (i = 0; i < num_buffers; i++) { 1263 object_buffer_p obj_buffer = buffers[i]; 1264 1265 switch (obj_buffer->type) { 1266 case VAEncSequenceParameterBufferType: 1267 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncSequenceParameterBufferType\n"); 1268 vaStatus = pnw__H264ES_process_sequence_param(ctx, obj_buffer); 1269 DEBUG_FAILURE; 1270 break; 1271 1272 case VAEncPictureParameterBufferType: 1273 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPictureParameterBuffer\n"); 1274 vaStatus = pnw__H264ES_process_picture_param(ctx, obj_buffer); 1275 DEBUG_FAILURE; 1276 break; 1277 1278 case VAEncSliceParameterBufferType: 1279 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncSliceParameterBufferType\n"); 1280 vaStatus = pnw__H264ES_process_slice_param(ctx, obj_buffer); 1281 DEBUG_FAILURE; 1282 break; 1283 1284 case VAEncMiscParameterBufferType: 1285 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncMiscParameterBufferType\n"); 1286 vaStatus = pnw__H264ES_process_misc_param(ctx, obj_buffer); 1287 DEBUG_FAILURE; 1288 break; 1289 #if PSB_MFLD_DUMMY_CODE 1290 case VAEncPackedHeaderParameterBufferType: 1291 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPackedHeaderParameterBufferType\n"); 1292 vaStatus = pnw__H264ES_insert_SEI_FPA_param(ctx, obj_buffer); 1293 DEBUG_FAILURE; 1294 break; 1295 case VAEncPackedHeaderDataBufferType: 1296 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPackedHeaderDataBufferType\n"); 1297 vaStatus = pnw__H264ES_insert_SEI_FPA_data(ctx, obj_buffer); 1298 DEBUG_FAILURE; 1299 break; 1300 #endif 1301 1302 default: 1303 vaStatus = VA_STATUS_ERROR_UNKNOWN; 1304 DEBUG_FAILURE; 1305 } 1306 if (vaStatus != VA_STATUS_SUCCESS) { 1307 break; 1308 } 1309 } 1310 1311 return vaStatus; 1312 } 1313 1314 static VAStatus pnw_H264ES_EndPicture( 1315 object_context_p obj_context) 1316 { 1317 INIT_CONTEXT_H264ES; 1318 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 1319 PIC_PARAMS *psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p; 1320 VAStatus vaStatus = VA_STATUS_SUCCESS; 1321 unsigned char core = 0; 1322 1323 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_EndPicture\n"); 1324 1325 /* Unlike MPEG4 and H263, slices number is defined by user */ 1326 for (core = 0; core < ctx->ParallelCores; core++) { 1327 psPicParams = (PIC_PARAMS *) 1328 (cmdbuf->pic_params_p + ctx->pic_params_size * core); 1329 psPicParams->NumSlices = ctx->sRCParams.Slices; 1330 } 1331 1332 vaStatus = pnw_EndPicture(ctx); 1333 1334 return vaStatus; 1335 } 1336 1337 1338 struct format_vtable_s pnw_H264ES_vtable = { 1339 queryConfigAttributes: 1340 pnw_H264ES_QueryConfigAttributes, 1341 validateConfig: 1342 pnw_H264ES_ValidateConfig, 1343 createContext: 1344 pnw_H264ES_CreateContext, 1345 destroyContext: 1346 pnw_H264ES_DestroyContext, 1347 beginPicture: 1348 pnw_H264ES_BeginPicture, 1349 renderPicture: 1350 pnw_H264ES_RenderPicture, 1351 endPicture: 1352 pnw_H264ES_EndPicture 1353 }; 1354 1355 VAStatus pnw_set_frame_skip_flag( 1356 object_context_p obj_context) 1357 { 1358 INIT_CONTEXT_H264ES; 1359 VAStatus vaStatus = VA_STATUS_SUCCESS; 1360 1361 1362 if (ctx && ctx->previous_src_surface) { 1363 SET_SURFACE_INFO_skipped_flag(ctx->previous_src_surface->psb_surface, 1); 1364 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Detected a skipped frame for surface 0x%08x.\n", 1365 ctx->previous_src_surface->psb_surface); 1366 } 1367 1368 return vaStatus; 1369 } 1370 1371 1372