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