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 #include "psb_def.h" 32 #include "psb_drv_debug.h" 33 #include "psb_surface.h" 34 #include "psb_cmdbuf.h" 35 #include "pnw_MPEG4ES.h" 36 #include "pnw_hostcode.h" 37 #include "pnw_hostheader.h" 38 39 #include <stdlib.h> 40 #include <stdint.h> 41 #include <string.h> 42 43 44 #define TOPAZ_MPEG4_MAX_BITRATE 16000000 45 46 #define INIT_CONTEXT_MPEG4ES context_ENC_p ctx = (context_ENC_p) obj_context->format_data 47 #define SURFACE(id) ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id )) 48 #define BUFFER(id) ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id )) 49 50 51 52 static void pnw_MPEG4ES_QueryConfigAttributes( 53 VAProfile __maybe_unused profile, 54 VAEntrypoint __maybe_unused entrypoint, 55 VAConfigAttrib * attrib_list, 56 int num_attribs) 57 { 58 int i; 59 60 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_MPEG4ES_QueryConfigAttributes\n"); 61 62 /* RateControl attributes */ 63 for (i = 0; i < num_attribs; i++) { 64 switch (attrib_list[i].type) { 65 case VAConfigAttribRTFormat: 66 break; 67 68 case VAConfigAttribRateControl: 69 attrib_list[i].value = VA_RC_NONE | VA_RC_CBR | VA_RC_VBR; 70 break; 71 72 default: 73 attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED; 74 break; 75 } 76 } 77 78 return; 79 } 80 81 82 static VAStatus pnw_MPEG4ES_ValidateConfig( 83 object_config_p obj_config) 84 { 85 int i; 86 /* Check all attributes */ 87 for (i = 0; i < obj_config->attrib_count; i++) { 88 switch (obj_config->attrib_list[i].type) { 89 case VAConfigAttribRTFormat: 90 /* Ignore */ 91 break; 92 case VAConfigAttribRateControl: 93 break; 94 default: 95 return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED; 96 } 97 } 98 99 return VA_STATUS_SUCCESS; 100 } 101 102 103 static VAStatus pnw_MPEG4ES_CreateContext( 104 object_context_p obj_context, 105 object_config_p obj_config) 106 { 107 VAStatus vaStatus = VA_STATUS_SUCCESS; 108 context_ENC_p ctx; 109 int i; 110 unsigned int eRCmode; 111 112 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_MPEG4ES_CreateContext\n"); 113 114 vaStatus = pnw_CreateContext(obj_context, obj_config, 0); 115 if (VA_STATUS_SUCCESS != vaStatus) 116 return VA_STATUS_ERROR_ALLOCATION_FAILED; 117 118 ctx = (context_ENC_p) obj_context->format_data; 119 120 for (i = 0; i < obj_config->attrib_count; i++) { 121 if (obj_config->attrib_list[i].type == VAConfigAttribRateControl) 122 break; 123 } 124 125 if (i >= obj_config->attrib_count) 126 eRCmode = VA_RC_NONE; 127 else 128 eRCmode = obj_config->attrib_list[i].value; 129 130 131 if (eRCmode == VA_RC_VBR) { 132 ctx->eCodec = IMG_CODEC_MPEG4_VBR; 133 ctx->sRCParams.RCEnable = IMG_TRUE; 134 } else if (eRCmode == VA_RC_CBR) { 135 ctx->eCodec = IMG_CODEC_MPEG4_CBR; 136 ctx->sRCParams.RCEnable = IMG_TRUE; 137 } else if (eRCmode == VA_RC_NONE) { 138 ctx->eCodec = IMG_CODEC_MPEG4_NO_RC; 139 ctx->sRCParams.RCEnable = IMG_FALSE; 140 } else 141 return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT; 142 ctx->eFormat = IMG_CODEC_PL12; 143 144 ctx->Slices = 1; 145 ctx->ParallelCores = 1; 146 147 ctx->IPEControl = pnw__get_ipe_control(ctx->eCodec); 148 149 switch (obj_config->profile) { 150 case VAProfileMPEG4Simple: 151 ctx->profile_idc = 2; 152 break; 153 case VAProfileMPEG4AdvancedSimple: 154 ctx->profile_idc = 3; 155 break; 156 default: 157 ctx->profile_idc = 2; 158 break; 159 } 160 161 return vaStatus; 162 } 163 164 165 static void pnw_MPEG4ES_DestroyContext( 166 object_context_p obj_context) 167 { 168 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_MPEG4ES_DestroyPicture\n"); 169 170 pnw_DestroyContext(obj_context); 171 } 172 173 static VAStatus pnw_MPEG4ES_BeginPicture( 174 object_context_p obj_context) 175 { 176 INIT_CONTEXT_MPEG4ES; 177 VAStatus vaStatus = VA_STATUS_SUCCESS; 178 179 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_MPEG4ES_BeginPicture\n"); 180 181 vaStatus = pnw_BeginPicture(ctx); 182 183 return vaStatus; 184 } 185 186 static VAStatus pnw__MPEG4ES_process_sequence_param(context_ENC_p ctx, object_buffer_p obj_buffer) 187 { 188 VAStatus vaStatus = VA_STATUS_SUCCESS; 189 VAEncSequenceParameterBufferMPEG4 *seq_params; 190 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 191 MPEG4_PROFILE_TYPE profile; 192 int i, vop_time_increment_resolution; 193 unsigned frame_size; 194 195 ASSERT(obj_buffer->type == VAEncSequenceParameterBufferType); 196 ASSERT(obj_buffer->num_elements == 1); 197 ASSERT(obj_buffer->size == sizeof(VAEncSequenceParameterBufferMPEG4)); 198 199 //initialize the frame_rate and qp 200 ctx->sRCParams.InitialQp = 15; 201 ctx->sRCParams.MinQP = 1; 202 ctx->sRCParams.FrameRate = 30; 203 204 if ((obj_buffer->num_elements != 1) || 205 (obj_buffer->size != sizeof(VAEncSequenceParameterBufferMPEG4))) { 206 return VA_STATUS_ERROR_UNKNOWN; 207 } 208 209 seq_params = (VAEncSequenceParameterBufferMPEG4 *) obj_buffer->buffer_data; 210 obj_buffer->buffer_data = NULL; 211 obj_buffer->size = 0; 212 213 if (seq_params->bits_per_second > TOPAZ_MPEG4_MAX_BITRATE) { 214 ctx->sRCParams.BitsPerSecond = TOPAZ_MPEG4_MAX_BITRATE; 215 drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \ 216 the maximum bitrate, set it with %d\n", 217 seq_params->bits_per_second, 218 TOPAZ_MPEG4_MAX_BITRATE); 219 } else 220 ctx->sRCParams.BitsPerSecond = seq_params->bits_per_second; 221 222 ctx->sRCParams.FrameRate = (seq_params->frame_rate < 1) ? 223 1 : ((65535 < seq_params->frame_rate) ? 65535 : seq_params->frame_rate); 224 ctx->sRCParams.InitialQp = seq_params->initial_qp; 225 ctx->sRCParams.MinQP = seq_params->min_qp; 226 ctx->sRCParams.BUSize = 0; /* default 0, and will be set in pnw__setup_busize */ 227 228 ctx->sRCParams.Slices = 1; 229 ctx->sRCParams.QCPOffset = 0;/* FIXME */ 230 231 if (ctx->sRCParams.IntraFreq != seq_params->intra_period 232 && ctx->raw_frame_count != 0 233 && ctx->sRCParams.IntraFreq != 0 234 && ((ctx->obj_context->frame_count + 1) % ctx->sRCParams.IntraFreq) != 0 235 && (!ctx->sRCParams.bDisableFrameSkipping)) { 236 drv_debug_msg(VIDEO_DEBUG_ERROR, 237 "Changing intra period value in the middle of a GOP is\n" 238 "not allowed if frame skip isn't disabled.\n" 239 "it can cause I frame been skipped\n"); 240 free(seq_params); 241 return VA_STATUS_ERROR_INVALID_PARAMETER; 242 } 243 else 244 ctx->sRCParams.IntraFreq = seq_params->intra_period; 245 246 ctx->sRCParams.IntraFreq = seq_params->intra_period; 247 248 frame_size = ctx->sRCParams.BitsPerSecond / ctx->sRCParams.FrameRate; 249 250 ctx->sRCParams.BufferSize = ctx->sRCParams.BitsPerSecond; 251 /* Header buffersize is specified in 16384 units, so ensure conformance 252 of parameters. InitialLevel in units of 64, assured by this */ 253 254 ctx->sRCParams.BufferSize /= 16384; 255 ctx->sRCParams.BufferSize *= 16384; 256 257 ctx->sRCParams.InitialLevel = (3 * ctx->sRCParams.BufferSize) >> 4; 258 /* Aligned with target frame size */ 259 ctx->sRCParams.InitialLevel += (frame_size / 2); 260 ctx->sRCParams.InitialLevel /= frame_size; 261 ctx->sRCParams.InitialLevel *= frame_size; 262 ctx->sRCParams.InitialDelay = ctx->sRCParams.BufferSize - ctx->sRCParams.InitialLevel; 263 ctx->buffer_size = ctx->sRCParams.BufferSize; 264 265 if (ctx->raw_frame_count == 0) { /* Add Register IO behind begin Picture */ 266 for (i = (ctx->ParallelCores - 1); i >= 0; i--) 267 pnw_set_bias(ctx, i); 268 } 269 270 cmdbuf = ctx->obj_context->pnw_cmdbuf; 271 272 switch (ctx->profile_idc) { 273 case 2: 274 profile = SP; 275 break; 276 case 3: 277 profile = ASP; 278 break; 279 default: 280 profile = SP; 281 break; 282 } 283 284 memset(cmdbuf->header_mem_p + ctx->seq_header_ofs, 285 0, 286 HEADER_SIZE); 287 288 vop_time_increment_resolution = (seq_params->vop_time_increment_resolution < 1) ? 1 : 289 ((65535 < seq_params->vop_time_increment_resolution) ? 65535 : seq_params->vop_time_increment_resolution); 290 pnw__MPEG4_prepare_sequence_header( 291 cmdbuf->header_mem_p + ctx->seq_header_ofs, 292 0, /* BFrame? */ 293 profile, /* sProfile */ 294 seq_params->profile_and_level_indication, /* */ 295 seq_params->fixed_vop_time_increment, /*3,*/ /* sFixed_vop_time_increment */ 296 seq_params->video_object_layer_width,/* Picture_Width_Pixels */ 297 seq_params->video_object_layer_height, /* Picture_Height_Pixels */ 298 NULL, 299 vop_time_increment_resolution); /* VopTimeResolution */ 300 301 ctx->MPEG4_vop_time_increment_resolution = vop_time_increment_resolution; 302 303 pnw_cmdbuf_insert_command_package(ctx->obj_context, 304 ctx->ParallelCores - 1, /* Send to the last core as this will complete first */ 305 MTX_CMDID_DO_HEADER, 306 &cmdbuf->header_mem, 307 ctx->seq_header_ofs); 308 309 free(seq_params); 310 return vaStatus; 311 } 312 313 314 static VAStatus pnw__MPEG4ES_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer) 315 { 316 VAStatus vaStatus = VA_STATUS_SUCCESS; 317 VAEncPictureParameterBufferMPEG4 *pBuffer; 318 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 319 unsigned int *pPictureHeaderMem; 320 MTX_HEADER_PARAMS *psPicHeader; 321 int i; 322 IMG_BOOL bIsVOPCoded = IMG_TRUE; 323 324 ASSERT(obj_buffer->type == VAEncPictureParameterBufferType); 325 326 if ((obj_buffer->num_elements != 1) || 327 (obj_buffer->size != sizeof(VAEncPictureParameterBufferMPEG4))) { 328 return VA_STATUS_ERROR_UNKNOWN; 329 } 330 331 /* Transfer ownership of VAEncPictureParameterBufferMPEG4 data */ 332 pBuffer = (VAEncPictureParameterBufferMPEG4 *) obj_buffer->buffer_data; 333 obj_buffer->buffer_data = NULL; 334 obj_buffer->size = 0; 335 336 ctx->ref_surface = SURFACE(pBuffer->reference_picture); 337 ctx->dest_surface = SURFACE(pBuffer->reconstructed_picture); 338 ctx->coded_buf = BUFFER(pBuffer->coded_buf); 339 340 ASSERT(ctx->Width == pBuffer->picture_width); 341 ASSERT(ctx->Height == pBuffer->picture_height); 342 343 /*if (ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip) 344 bIsVOPCoded = IMG_FALSE;*/ 345 346 ctx->FCode = 4 - 1; /* 4 is default value of "ui8Search_range" */ 347 348 pPictureHeaderMem = (unsigned int *)(cmdbuf->header_mem_p + ctx->pic_header_ofs); 349 psPicHeader = (MTX_HEADER_PARAMS *)pPictureHeaderMem; 350 351 memset(pPictureHeaderMem, 0, HEADER_SIZE); 352 353 pnw__MPEG4_prepare_vop_header((unsigned char *)pPictureHeaderMem, 354 bIsVOPCoded, 355 pBuffer->vop_time_increment, /* In testbench, this should be FrameNum */ 356 4,/* default value is 4,search range */ 357 pBuffer->picture_type, 358 ctx->MPEG4_vop_time_increment_resolution/* defaule value */); 359 360 /* Mark this header as a complex header */ 361 psPicHeader->Elements |= 0x100; 362 pPictureHeaderMem += ((HEADER_SIZE) >> 3); 363 364 pnw__MPEG4_prepare_vop_header((unsigned char *)pPictureHeaderMem, 365 IMG_FALSE, 366 pBuffer->vop_time_increment, /* In testbench, this should be FrameNum */ 367 4,/* default value is 4,search range */ 368 pBuffer->picture_type, 369 ctx->MPEG4_vop_time_increment_resolution/* defaule value */); 370 371 pnw_cmdbuf_insert_command_package(ctx->obj_context, 372 ctx->ParallelCores - 1, /* Send to the last core as this will complete first */ 373 MTX_CMDID_DO_HEADER, 374 &cmdbuf->header_mem, 375 ctx->pic_header_ofs); 376 377 /* Prepare START_PICTURE params */ 378 for (i = (ctx->ParallelCores - 1); i >= 0; i--) 379 vaStatus = pnw_RenderPictureParameter(ctx, i); 380 381 free(pBuffer); 382 return vaStatus; 383 } 384 385 static VAStatus pnw__MPEG4ES_process_slice_param(context_ENC_p ctx, object_buffer_p obj_buffer) 386 { 387 VAStatus vaStatus = VA_STATUS_SUCCESS; 388 VAEncSliceParameterBuffer *pBuffer; 389 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; 390 PIC_PARAMS *psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p); 391 unsigned int i; 392 int slice_param_idx; 393 394 ASSERT(obj_buffer->type == VAEncSliceParameterBufferType); 395 396 pBuffer = (VAEncSliceParameterBuffer *) obj_buffer->buffer_data; 397 398 /*In case the slice number changes*/ 399 if ((ctx->slice_param_cache != NULL) && (obj_buffer->num_elements != ctx->slice_param_num)) { 400 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Slice number changes. Previous value is %d. Now it's %d\n", 401 ctx->slice_param_num, obj_buffer->num_elements); 402 free(ctx->slice_param_cache); 403 ctx->slice_param_cache = NULL; 404 ctx->slice_param_num = 0; 405 } 406 407 if (NULL == ctx->slice_param_cache) { 408 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Allocate %d VAEncSliceParameterBuffer cache buffers\n", 2 * ctx->slice_param_num); 409 ctx->slice_param_num = obj_buffer->num_elements; 410 ctx->slice_param_cache = calloc(2 * ctx->slice_param_num, sizeof(VAEncSliceParameterBuffer)); 411 if (NULL == ctx->slice_param_cache) { 412 drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n"); 413 free(obj_buffer->buffer_data); 414 return VA_STATUS_ERROR_ALLOCATION_FAILED; 415 } 416 } 417 418 419 for (i = 0; i < obj_buffer->num_elements; i++) { 420 421 unsigned char deblock_idc; 422 423 deblock_idc = pBuffer->slice_flags.bits.disable_deblocking_filter_idc; 424 425 if ((pBuffer->start_row_number == 0) && pBuffer->slice_flags.bits.is_intra) { 426 pnw_reset_encoder_params(ctx); 427 ctx->BelowParamsBufIdx = (ctx->BelowParamsBufIdx + 1) & 0x1; 428 } 429 430 /*The corresponding slice buffer cache*/ 431 slice_param_idx = (pBuffer->slice_flags.bits.is_intra ? 0 : 1) * ctx->slice_param_num + i; 432 433 if (VAEncSliceParameter_Equal(&ctx->slice_param_cache[slice_param_idx], pBuffer) == 0) { 434 /* cache current param parameters */ 435 memcpy(&ctx->slice_param_cache[slice_param_idx], 436 pBuffer, sizeof(VAEncSliceParameterBuffer)); 437 438 /* Setup InParams value*/ 439 pnw_setup_slice_params(ctx, 440 pBuffer->start_row_number * 16, 441 pBuffer->slice_height * 16, 442 pBuffer->slice_flags.bits.is_intra, 443 ctx->obj_context->frame_count > 0, 444 psPicParams->sInParams.SeInitQP); 445 } 446 447 pnw__send_encode_slice_params(ctx, 448 pBuffer->slice_flags.bits.is_intra, 449 pBuffer->start_row_number * 16, 450 deblock_idc, 451 ctx->obj_context->frame_count, 452 pBuffer->slice_height * 16, 453 ctx->obj_context->slice_count); 454 455 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Now frame_count/slice_count is %d/%d\n", 456 ctx->obj_context->frame_count, ctx->obj_context->slice_count); 457 458 ctx->obj_context->slice_count++; 459 pBuffer++; 460 461 ASSERT(ctx->obj_context->slice_count < MAX_SLICES_PER_PICTURE); 462 } 463 464 free(obj_buffer->buffer_data); 465 obj_buffer->buffer_data = NULL; 466 467 return vaStatus; 468 } 469 470 471 static VAStatus pnw_MPEG4ES_RenderPicture( 472 object_context_p obj_context, 473 object_buffer_p *buffers, 474 int num_buffers) 475 { 476 INIT_CONTEXT_MPEG4ES; 477 VAStatus vaStatus = VA_STATUS_SUCCESS; 478 int i; 479 480 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_MPEG4ES_RenderPicture\n"); 481 482 for (i = 0; i < num_buffers; i++) { 483 object_buffer_p obj_buffer = buffers[i]; 484 485 switch (obj_buffer->type) { 486 case VAEncSequenceParameterBufferType: 487 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_MPEG4ES_RenderPicture got VAEncSequenceParameterBufferType\n"); 488 vaStatus = pnw__MPEG4ES_process_sequence_param(ctx, obj_buffer); 489 DEBUG_FAILURE; 490 break; 491 492 case VAEncPictureParameterBufferType: 493 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_MPEG4ES_RenderPicture got VAEncPictureParameterBufferType\n"); 494 vaStatus = pnw__MPEG4ES_process_picture_param(ctx, obj_buffer); 495 DEBUG_FAILURE; 496 break; 497 498 case VAEncSliceParameterBufferType: 499 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_MPEG4ES_RenderPicture got VAEncSliceParameterBufferType\n"); 500 vaStatus = pnw__MPEG4ES_process_slice_param(ctx, obj_buffer); 501 DEBUG_FAILURE; 502 break; 503 default: 504 vaStatus = VA_STATUS_ERROR_UNKNOWN; 505 DEBUG_FAILURE; 506 } 507 } 508 509 return vaStatus; 510 } 511 512 static VAStatus pnw_MPEG4ES_EndPicture( 513 object_context_p obj_context) 514 { 515 INIT_CONTEXT_MPEG4ES; 516 517 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_MPEG4ES_EndPicture\n"); 518 return pnw_EndPicture(ctx); 519 } 520 521 522 struct format_vtable_s pnw_MPEG4ES_vtable = { 523 queryConfigAttributes: 524 pnw_MPEG4ES_QueryConfigAttributes, 525 validateConfig: 526 pnw_MPEG4ES_ValidateConfig, 527 createContext: 528 pnw_MPEG4ES_CreateContext, 529 destroyContext: 530 pnw_MPEG4ES_DestroyContext, 531 beginPicture: 532 pnw_MPEG4ES_BeginPicture, 533 renderPicture: 534 pnw_MPEG4ES_RenderPicture, 535 endPicture: 536 pnw_MPEG4ES_EndPicture 537 }; 538