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 = NULL, *pBuffer = NULL; 849 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 850 PIC_PARAMS *psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p); 851 bool pBufferAlloced = false; 852 unsigned int i, j, slice_per_core; 853 VAStatus vaStatus = VA_STATUS_SUCCESS; 854 855 ASSERT(obj_buffer->type == VAEncSliceParameterBufferType); 856 857 if (obj_buffer->num_elements > (ctx->Height / 16)) { 858 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 859 goto out2; 860 } 861 cmdbuf = ctx->obj_context->pnw_cmdbuf; 862 psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p; 863 864 /* Transfer ownership of VAEncPictureParameterBuffer data */ 865 if (obj_buffer->size == sizeof(VAEncSliceParameterBufferH264)) { 866 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Receive VAEncSliceParameterBufferH264 buffer"); 867 pBuffer = calloc(obj_buffer->num_elements, sizeof(VAEncSliceParameterBuffer)); 868 869 if (pBuffer == NULL) { 870 drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n"); 871 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; 872 goto out2; 873 } 874 875 pBufferAlloced = true; 876 877 pnw__convert_sliceparameter_buffer((VAEncSliceParameterBufferH264 *)obj_buffer->buffer_data, 878 pBuffer, 879 ctx->Width / 16, 880 obj_buffer->num_elements); 881 } else if (obj_buffer->size == sizeof(VAEncSliceParameterBuffer)) { 882 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Receive VAEncSliceParameterBuffer buffer"); 883 pBuffer = (VAEncSliceParameterBuffer *) obj_buffer->buffer_data; 884 } else { 885 drv_debug_msg(VIDEO_DEBUG_ERROR, "Buffer size(%d) is wrong. It should be %d or %d\n", 886 obj_buffer->size, sizeof(VAEncSliceParameterBuffer), 887 sizeof(VAEncSliceParameterBufferH264)); 888 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 889 goto out2; 890 } 891 892 obj_buffer->size = 0; 893 894 /*In case the slice number changes*/ 895 if ((ctx->slice_param_cache != NULL) && (obj_buffer->num_elements != ctx->slice_param_num)) { 896 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Slice number changes. Previous value is %d. Now it's %d\n", 897 ctx->slice_param_num, obj_buffer->num_elements); 898 free(ctx->slice_param_cache); 899 ctx->slice_param_cache = NULL; 900 ctx->slice_param_num = 0; 901 } 902 903 if (NULL == ctx->slice_param_cache) { 904 ctx->slice_param_num = obj_buffer->num_elements; 905 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Allocate %d VAEncSliceParameterBuffer cache buffers\n", 2 * ctx->slice_param_num); 906 ctx->slice_param_cache = calloc(2 * ctx->slice_param_num, sizeof(VAEncSliceParameterBuffer)); 907 if (NULL == ctx->slice_param_cache) { 908 drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n"); 909 910 /* free the converted VAEncSliceParameterBuffer */ 911 if (pBufferAlloced) 912 free(pBuffer); 913 free(obj_buffer->buffer_data); 914 return VA_STATUS_ERROR_ALLOCATION_FAILED; 915 } 916 } 917 918 ctx->sRCParams.Slices = obj_buffer->num_elements; 919 if (getenv("PSB_VIDEO_SIG_CORE") == NULL) { 920 if ((ctx->ParallelCores == 2) && (obj_buffer->num_elements == 1)) { 921 /*Need to replace unneccesary MTX_CMDID_STARTPICs with MTX_CMDID_PAD*/ 922 for (i = 0; i < (ctx->ParallelCores - 1); i++) { 923 *(cmdbuf->cmd_idx_saved[PNW_CMDBUF_START_PIC_IDX] + i * 4) &= (~MTX_CMDWORD_ID_MASK); 924 *(cmdbuf->cmd_idx_saved[PNW_CMDBUF_START_PIC_IDX] + i * 4) |= MTX_CMDID_PAD; 925 } 926 drv_debug_msg(VIDEO_DEBUG_GENERAL, " Remove unneccesary %d MTX_CMDID_STARTPIC commands from cmdbuf\n", 927 ctx->ParallelCores - obj_buffer->num_elements); 928 ctx->ParallelCores = obj_buffer->num_elements; 929 930 /* All header generation commands should be send to core 0*/ 931 for (i = PNW_CMDBUF_SEQ_HEADER_IDX; i < PNW_CMDBUF_SAVING_MAX; i++) { 932 if (cmdbuf->cmd_idx_saved[i] != 0) 933 *(cmdbuf->cmd_idx_saved[i]) &= 934 ~(MTX_CMDWORD_CORE_MASK << MTX_CMDWORD_CORE_SHIFT); 935 } 936 937 ctx->SliceToCore = ctx->ParallelCores - 1; 938 } 939 } 940 941 slice_per_core = obj_buffer->num_elements / ctx->ParallelCores; 942 pBuf_per_core = pBuffer; 943 for (i = 0; i < slice_per_core; i++) { 944 pBuffer = pBuf_per_core; 945 for (j = 0; j < ctx->ParallelCores; j++) { 946 vaStatus = pnw__H264ES_encode_one_slice(ctx, pBuffer); 947 if (vaStatus != VA_STATUS_SUCCESS) 948 goto out1; 949 if (0 == ctx->SliceToCore) { 950 ctx->SliceToCore = ctx->ParallelCores; 951 } 952 ctx->SliceToCore--; 953 954 ASSERT(ctx->obj_context->slice_count < MAX_SLICES_PER_PICTURE); 955 /*Move to the next buffer which will be sent to core j*/ 956 pBuffer += slice_per_core; 957 } 958 pBuf_per_core++; /* Move to the next buffer */ 959 } 960 961 /*Cope with last slice when slice number is odd and parallelCores is even*/ 962 if (obj_buffer->num_elements > (slice_per_core * ctx->ParallelCores)) { 963 ctx->SliceToCore = 0; 964 pBuffer -= slice_per_core; 965 pBuffer ++; 966 vaStatus = pnw__H264ES_encode_one_slice(ctx, pBuffer); 967 } 968 out1: 969 /* free the converted VAEncSliceParameterBuffer */ 970 if (pBufferAlloced) 971 free(pBuffer); 972 973 out2: 974 free(obj_buffer->buffer_data); 975 obj_buffer->buffer_data = NULL; 976 977 return vaStatus; 978 } 979 980 static VAStatus pnw__H264ES_process_misc_param(context_ENC_p ctx, object_buffer_p obj_buffer) 981 { 982 /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */ 983 VAEncMiscParameterBuffer *pBuffer; 984 VAEncMiscParameterRateControl *rate_control_param; 985 VAEncMiscParameterAIR *air_param; 986 VAEncMiscParameterMaxSliceSize *max_slice_size_param; 987 VAEncMiscParameterFrameRate *frame_rate_param; 988 VAEncMiscParameterHRD *hrd_param; 989 VAStatus vaStatus = VA_STATUS_SUCCESS; 990 unsigned int max_bps; 991 unsigned int frame_size; 992 993 ASSERT(obj_buffer->type == VAEncMiscParameterBufferType); 994 995 996 /* Transfer ownership of VAEncMiscParameterBuffer data */ 997 pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data; 998 obj_buffer->size = 0; 999 1000 if (ctx->eCodec != IMG_CODEC_H264_VCM 1001 && (pBuffer->type != VAEncMiscParameterTypeHRD 1002 && pBuffer->type != VAEncMiscParameterTypeRateControl 1003 && pBuffer->type != VAEncMiscParameterTypeFrameRate)) { 1004 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Buffer type %d isn't supported in none VCM mode.\n", 1005 pBuffer->type); 1006 free(obj_buffer->buffer_data); 1007 obj_buffer->buffer_data = NULL; 1008 return VA_STATUS_SUCCESS; 1009 } 1010 1011 switch (pBuffer->type) { 1012 case VAEncMiscParameterTypeFrameRate: 1013 frame_rate_param = (VAEncMiscParameterFrameRate *)pBuffer->data; 1014 1015 if (frame_rate_param->framerate < 1 || frame_rate_param->framerate > 65535) { 1016 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1017 break; 1018 } 1019 1020 if (ctx->sRCParams.FrameRate == frame_rate_param->framerate) 1021 break; 1022 1023 drv_debug_msg(VIDEO_DEBUG_GENERAL, "frame rate changed from %d to %d\n", 1024 ctx->sRCParams.FrameRate, 1025 frame_rate_param->framerate); 1026 ctx->sRCParams.FrameRate = frame_rate_param->framerate; 1027 ctx->sRCParams.bBitrateChanged = IMG_TRUE; 1028 1029 ctx->sRCParams.FrameRate = (frame_rate_param->framerate < 1) ? 1 : 1030 ((65535 < frame_rate_param->framerate) ? 65535 : frame_rate_param->framerate); 1031 break; 1032 1033 case VAEncMiscParameterTypeRateControl: 1034 rate_control_param = (VAEncMiscParameterRateControl *)pBuffer->data; 1035 1036 /* Currently, none VCM mode only supports frame skip and bit stuffing 1037 * disable flag and doesn't accept other parameters in 1038 * buffer of VAEncMiscParameterTypeRateControl type */ 1039 if (rate_control_param->rc_flags.value != 0 || ctx->raw_frame_count == 0) { 1040 if (rate_control_param->rc_flags.bits.disable_frame_skip) 1041 ctx->sRCParams.bDisableFrameSkipping = IMG_TRUE; 1042 if (rate_control_param->rc_flags.bits.disable_bit_stuffing) 1043 ctx->sRCParams.bDisableBitStuffing = IMG_TRUE; 1044 drv_debug_msg(VIDEO_DEBUG_GENERAL, 1045 "bDisableFrameSkipping is %d and bDisableBitStuffing is %d\n", 1046 ctx->sRCParams.bDisableFrameSkipping, ctx->sRCParams.bDisableBitStuffing); 1047 } 1048 1049 if (rate_control_param->initial_qp > 51 || 1050 rate_control_param->min_qp > 51) { 1051 drv_debug_msg(VIDEO_DEBUG_ERROR, "Initial_qp(%d) and min_qpinitial_qp(%d) " 1052 "are invalid.\nQP shouldn't be larger than 51 for H264\n", 1053 rate_control_param->initial_qp, rate_control_param->min_qp); 1054 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1055 break; 1056 } 1057 1058 if (rate_control_param->window_size > 2000) { 1059 drv_debug_msg(VIDEO_DEBUG_ERROR, "window_size is too much!\n"); 1060 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1061 break; 1062 } 1063 1064 /* Check if any none-zero RC parameter is changed*/ 1065 if ((rate_control_param->bits_per_second == 0 || 1066 rate_control_param->bits_per_second == ctx->sRCParams.BitsPerSecond) && 1067 (rate_control_param->window_size == 0 || 1068 ctx->sRCParams.BufferSize == ctx->sRCParams.BitsPerSecond / 1000 * rate_control_param->window_size) && 1069 (ctx->sRCParams.MinQP == rate_control_param->min_qp) && 1070 (ctx->sRCParams.InitialQp == rate_control_param->initial_qp) && 1071 (rate_control_param->basic_unit_size == 0 || 1072 ctx->sRCParams.BUSize == rate_control_param->basic_unit_size)) { 1073 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s No RC parameter is changed\n", 1074 __FUNCTION__); 1075 break; 1076 } 1077 else if (ctx->raw_frame_count != 0 || ctx->eCodec == IMG_CODEC_H264_VCM) 1078 ctx->sRCParams.bBitrateChanged = IMG_TRUE; 1079 1080 /* The initial target bitrate is set by Sequence parameter buffer. 1081 Here is for changed bitrate only */ 1082 if (rate_control_param->bits_per_second > TOPAZ_H264_MAX_BITRATE) { 1083 drv_debug_msg(VIDEO_DEBUG_ERROR, " bits_per_second(%d) exceeds \ 1084 the maximum bitrate, set it with %d\n", 1085 rate_control_param->bits_per_second, 1086 TOPAZ_H264_MAX_BITRATE); 1087 break; 1088 } 1089 /* The initial target bitrate is set by Sequence parameter buffer. 1090 Here is for changed bitrate only */ 1091 if (rate_control_param->bits_per_second != 0 && 1092 ctx->raw_frame_count != 0) { 1093 drv_debug_msg(VIDEO_DEBUG_GENERAL, 1094 "bitrate is changed from %d to %d on frame %d\n", 1095 ctx->sRCParams.BitsPerSecond, 1096 rate_control_param->bits_per_second, 1097 ctx->raw_frame_count); 1098 max_bps = (ctx->Width * ctx->Height * 3 / 2 ) * 8 * ctx->sRCParams.FrameRate; 1099 if (ctx->Width > 720) 1100 max_bps /= 4; 1101 else 1102 max_bps /= 2; 1103 1104 drv_debug_msg(VIDEO_DEBUG_GENERAL, " width %d height %d, frame rate %d\n", 1105 ctx->Width, ctx->Height, ctx->sRCParams.FrameRate); 1106 if (rate_control_param->bits_per_second > max_bps) { 1107 drv_debug_msg(VIDEO_DEBUG_ERROR, 1108 "Invalid bitrate %d, violate ITU-T Rec. H.264 (03/2005) A.3.1" 1109 "\n clip to %d bps\n", rate_control_param->bits_per_second, max_bps); 1110 ctx->sRCParams.BitsPerSecond = max_bps; 1111 } else { 1112 /* See 110% target bitrate for VCM. Otherwise, the resulted bitrate is much lower 1113 than target bitrate */ 1114 if (ctx->eCodec == IMG_CODEC_H264_VCM) 1115 rate_control_param->bits_per_second = 1116 rate_control_param->bits_per_second / 100 * 110; 1117 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Bitrate is set to %d\n", 1118 rate_control_param->bits_per_second); 1119 ctx->sRCParams.BitsPerSecond = rate_control_param->bits_per_second; 1120 } 1121 } 1122 1123 if (rate_control_param->min_qp != 0) 1124 ctx->sRCParams.MinQP = rate_control_param->min_qp; 1125 if (rate_control_param->window_size != 0) { 1126 ctx->sRCParams.BufferSize = 1127 ctx->sRCParams.BitsPerSecond / 1000 * rate_control_param->window_size; 1128 if (ctx->sRCParams.FrameRate == 0) { 1129 drv_debug_msg(VIDEO_DEBUG_ERROR, "frame rate can't be zero. Set it to 30"); 1130 ctx->sRCParams.FrameRate = 30; 1131 } 1132 1133 frame_size = ctx->sRCParams.BitsPerSecond / ctx->sRCParams.FrameRate; 1134 if (frame_size == 0) { 1135 drv_debug_msg(VIDEO_DEBUG_ERROR, "Bitrate is too low %d\n", 1136 ctx->sRCParams.BitsPerSecond); 1137 break; 1138 } 1139 ctx->sRCParams.InitialLevel = (3 * ctx->sRCParams.BufferSize) >> 4; 1140 ctx->sRCParams.InitialLevel += (frame_size / 2); 1141 ctx->sRCParams.InitialLevel /= frame_size; 1142 ctx->sRCParams.InitialLevel *= frame_size; 1143 ctx->sRCParams.InitialDelay = 1144 ctx->sRCParams.BufferSize - ctx->sRCParams.InitialLevel; 1145 } 1146 1147 if (rate_control_param->initial_qp != 0) 1148 ctx->sRCParams.InitialQp = rate_control_param->initial_qp; 1149 if (rate_control_param->basic_unit_size != 0) 1150 ctx->sRCParams.BUSize = rate_control_param->basic_unit_size; 1151 1152 drv_debug_msg(VIDEO_DEBUG_GENERAL, 1153 "Set Misc parameters(frame %d): window_size %d, initial qp %d\n" \ 1154 "\tmin qp %d, bunit size %d\n", 1155 ctx->raw_frame_count, 1156 rate_control_param->window_size, 1157 rate_control_param->initial_qp, 1158 rate_control_param->min_qp, 1159 rate_control_param->basic_unit_size); 1160 break; 1161 1162 case VAEncMiscParameterTypeMaxSliceSize: 1163 max_slice_size_param = (VAEncMiscParameterMaxSliceSize *)pBuffer->data; 1164 1165 /*The max slice size should not be bigger than 1920x1080x1.5x8 */ 1166 if (max_slice_size_param->max_slice_size > 24883200) { 1167 drv_debug_msg(VIDEO_DEBUG_ERROR,"Invalid max_slice_size. It should be 1~ 24883200.\n"); 1168 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1169 break; 1170 } 1171 1172 if (ctx->max_slice_size == max_slice_size_param->max_slice_size) 1173 break; 1174 1175 drv_debug_msg(VIDEO_DEBUG_GENERAL, "max slice size changed to %d\n", 1176 max_slice_size_param->max_slice_size); 1177 1178 ctx->max_slice_size = max_slice_size_param->max_slice_size; 1179 1180 break; 1181 1182 case VAEncMiscParameterTypeAIR: 1183 air_param = (VAEncMiscParameterAIR *)pBuffer->data; 1184 1185 if (air_param->air_num_mbs > 65535 || 1186 air_param->air_threshold > 65535) { 1187 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1188 break; 1189 } 1190 1191 drv_debug_msg(VIDEO_DEBUG_GENERAL,"air slice size changed to num_air_mbs %d " 1192 "air_threshold %d, air_auto %d\n", 1193 air_param->air_num_mbs, air_param->air_threshold, 1194 air_param->air_auto); 1195 1196 if (((ctx->Height * ctx->Width) >> 8) < (int)air_param->air_num_mbs) 1197 air_param->air_num_mbs = ((ctx->Height * ctx->Width) >> 8); 1198 if (air_param->air_threshold == 0) 1199 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: air threshold is set to zero\n", 1200 __func__); 1201 ctx->num_air_mbs = air_param->air_num_mbs; 1202 ctx->air_threshold = air_param->air_threshold; 1203 //ctx->autotune_air_flag = air_param->air_auto; 1204 1205 break; 1206 1207 case VAEncMiscParameterTypeHRD: 1208 hrd_param = (VAEncMiscParameterHRD *)pBuffer->data; 1209 1210 if (hrd_param->buffer_size == 0 1211 || hrd_param->initial_buffer_fullness == 0) 1212 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Find zero value for buffer_size " 1213 "and initial_buffer_fullness.\n" 1214 "Will assign default value to them later \n"); 1215 1216 if (ctx->initial_buffer_fullness > ctx->buffer_size) { 1217 drv_debug_msg(VIDEO_DEBUG_ERROR, "initial_buffer_fullnessi(%d) shouldn't be" 1218 " larger that buffer_size(%d)!\n", 1219 hrd_param->initial_buffer_fullness, 1220 hrd_param->buffer_size); 1221 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 1222 break; 1223 } 1224 1225 if (!ctx->sRCParams.RCEnable) { 1226 drv_debug_msg(VIDEO_DEBUG_ERROR, "Only when rate control is enabled," 1227 " VAEncMiscParameterTypeHRD will take effect.\n"); 1228 break; 1229 } 1230 1231 ctx->buffer_size = hrd_param->buffer_size; 1232 ctx->initial_buffer_fullness = hrd_param->initial_buffer_fullness; 1233 ctx->bInserHRDParams = IMG_TRUE; 1234 drv_debug_msg(VIDEO_DEBUG_GENERAL, "hrd param buffer_size set to %d " 1235 "initial buffer fullness set to %d\n", 1236 ctx->buffer_size, ctx->initial_buffer_fullness); 1237 1238 break; 1239 1240 default: 1241 vaStatus = VA_STATUS_ERROR_UNKNOWN; 1242 DEBUG_FAILURE; 1243 break; 1244 } 1245 1246 free(obj_buffer->buffer_data); 1247 obj_buffer->buffer_data = NULL; 1248 1249 return vaStatus; 1250 } 1251 1252 1253 1254 static VAStatus pnw_H264ES_RenderPicture( 1255 object_context_p obj_context, 1256 object_buffer_p *buffers, 1257 int num_buffers) 1258 { 1259 INIT_CONTEXT_H264ES; 1260 VAStatus vaStatus = VA_STATUS_SUCCESS; 1261 int i; 1262 1263 drv_debug_msg(VIDEO_DEBUG_GENERAL,"pnw_H264ES_RenderPicture\n"); 1264 1265 for (i = 0; i < num_buffers; i++) { 1266 object_buffer_p obj_buffer = buffers[i]; 1267 1268 switch (obj_buffer->type) { 1269 case VAEncSequenceParameterBufferType: 1270 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncSequenceParameterBufferType\n"); 1271 vaStatus = pnw__H264ES_process_sequence_param(ctx, obj_buffer); 1272 DEBUG_FAILURE; 1273 break; 1274 1275 case VAEncPictureParameterBufferType: 1276 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPictureParameterBuffer\n"); 1277 vaStatus = pnw__H264ES_process_picture_param(ctx, obj_buffer); 1278 DEBUG_FAILURE; 1279 break; 1280 1281 case VAEncSliceParameterBufferType: 1282 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncSliceParameterBufferType\n"); 1283 vaStatus = pnw__H264ES_process_slice_param(ctx, obj_buffer); 1284 DEBUG_FAILURE; 1285 break; 1286 1287 case VAEncMiscParameterBufferType: 1288 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncMiscParameterBufferType\n"); 1289 vaStatus = pnw__H264ES_process_misc_param(ctx, obj_buffer); 1290 DEBUG_FAILURE; 1291 break; 1292 #if PSB_MFLD_DUMMY_CODE 1293 case VAEncPackedHeaderParameterBufferType: 1294 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPackedHeaderParameterBufferType\n"); 1295 vaStatus = pnw__H264ES_insert_SEI_FPA_param(ctx, obj_buffer); 1296 DEBUG_FAILURE; 1297 break; 1298 case VAEncPackedHeaderDataBufferType: 1299 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPackedHeaderDataBufferType\n"); 1300 vaStatus = pnw__H264ES_insert_SEI_FPA_data(ctx, obj_buffer); 1301 DEBUG_FAILURE; 1302 break; 1303 #endif 1304 1305 default: 1306 vaStatus = VA_STATUS_ERROR_UNKNOWN; 1307 DEBUG_FAILURE; 1308 } 1309 if (vaStatus != VA_STATUS_SUCCESS) { 1310 break; 1311 } 1312 } 1313 1314 return vaStatus; 1315 } 1316 1317 static VAStatus pnw_H264ES_EndPicture( 1318 object_context_p obj_context) 1319 { 1320 INIT_CONTEXT_H264ES; 1321 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 1322 PIC_PARAMS *psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p; 1323 VAStatus vaStatus = VA_STATUS_SUCCESS; 1324 unsigned char core = 0; 1325 1326 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_EndPicture\n"); 1327 1328 /* Unlike MPEG4 and H263, slices number is defined by user */ 1329 for (core = 0; core < ctx->ParallelCores; core++) { 1330 psPicParams = (PIC_PARAMS *) 1331 (cmdbuf->pic_params_p + ctx->pic_params_size * core); 1332 psPicParams->NumSlices = ctx->sRCParams.Slices; 1333 } 1334 1335 vaStatus = pnw_EndPicture(ctx); 1336 1337 return vaStatus; 1338 } 1339 1340 1341 struct format_vtable_s pnw_H264ES_vtable = { 1342 queryConfigAttributes: 1343 pnw_H264ES_QueryConfigAttributes, 1344 validateConfig: 1345 pnw_H264ES_ValidateConfig, 1346 createContext: 1347 pnw_H264ES_CreateContext, 1348 destroyContext: 1349 pnw_H264ES_DestroyContext, 1350 beginPicture: 1351 pnw_H264ES_BeginPicture, 1352 renderPicture: 1353 pnw_H264ES_RenderPicture, 1354 endPicture: 1355 pnw_H264ES_EndPicture 1356 }; 1357 1358 VAStatus pnw_set_frame_skip_flag( 1359 object_context_p obj_context) 1360 { 1361 INIT_CONTEXT_H264ES; 1362 VAStatus vaStatus = VA_STATUS_SUCCESS; 1363 1364 1365 if (ctx && ctx->previous_src_surface) { 1366 SET_SURFACE_INFO_skipped_flag(ctx->previous_src_surface->psb_surface, 1); 1367 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Detected a skipped frame for surface 0x%08x.\n", 1368 ctx->previous_src_surface->psb_surface); 1369 } 1370 1371 return vaStatus; 1372 } 1373 1374 1375