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 * Edward Lin <edward.lin (at) intel.com> 29 * Zhaohan Ren <zhaohan.ren (at) intel.com> 30 * 31 */ 32 33 34 #include <errno.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <stdint.h> 38 #include <string.h> 39 40 #include "psb_def.h" 41 #include "psb_surface.h" 42 #include "tng_cmdbuf.h" 43 #include "tng_hostcode.h" 44 #include "tng_hostheader.h" 45 #include "tng_MPEG4ES.h" 46 #include "psb_drv_debug.h" 47 48 #include "hwdefs/coreflags.h" 49 #include "hwdefs/topaz_vlc_regs.h" 50 #include "hwdefs/topaz_db_regs.h" 51 #include "hwdefs/topazhp_default_params.h" 52 53 #define TOPAZ_MPEG4_MAX_BITRATE 16000000 54 55 #define INIT_CONTEXT_MPEG4ES context_ENC_p ctx = (context_ENC_p) obj_context->format_data 56 #define SURFACE(id) ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id )) 57 #define BUFFER(id) ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id )) 58 59 static void tng_MPEG4ES_QueryConfigAttributes( 60 VAProfile __maybe_unused profile, 61 VAEntrypoint __maybe_unused entrypoint, 62 VAConfigAttrib *attrib_list, 63 int num_attribs) 64 { 65 int i; 66 67 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s\n", __FUNCTION__); 68 69 /* RateControl attributes */ 70 for (i = 0; i < num_attribs; i++) { 71 switch (attrib_list[i].type) { 72 case VAConfigAttribRTFormat: 73 break; 74 75 case VAConfigAttribEncAutoReference: 76 attrib_list[i].value = 1; 77 break; 78 79 case VAConfigAttribEncMaxRefFrames: 80 attrib_list[i].value = 2; 81 break; 82 83 case VAConfigAttribRateControl: 84 attrib_list[i].value = VA_RC_NONE | VA_RC_CBR | VA_RC_VBR; 85 break; 86 87 default: 88 attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED; 89 break; 90 } 91 } 92 } 93 94 95 static VAStatus tng_MPEG4ES_ValidateConfig( 96 object_config_p obj_config) 97 { 98 int i; 99 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s\n", __FUNCTION__); 100 /* Check all attributes */ 101 for (i = 0; i < obj_config->attrib_count; i++) { 102 switch (obj_config->attrib_list[i].type) { 103 case VAConfigAttribRTFormat: 104 /* Ignore */ 105 break; 106 case VAConfigAttribRateControl: 107 break; 108 case VAConfigAttribEncAutoReference: 109 break; 110 case VAConfigAttribEncMaxRefFrames: 111 break; 112 default: 113 return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED; 114 } 115 } 116 117 return VA_STATUS_SUCCESS; 118 } 119 120 static VAStatus tng_MPEG4ES_CreateContext( 121 object_context_p obj_context, 122 object_config_p obj_config) 123 { 124 VAStatus vaStatus = VA_STATUS_SUCCESS; 125 context_ENC_p ctx; 126 unsigned int eRCMode; 127 128 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s\n", __FUNCTION__); 129 130 vaStatus = tng_CreateContext(obj_context, obj_config, 0); 131 132 if (VA_STATUS_SUCCESS != vaStatus) 133 return VA_STATUS_ERROR_ALLOCATION_FAILED; 134 135 ctx = (context_ENC_p) obj_context->format_data; 136 ctx->eStandard = IMG_STANDARD_MPEG4; 137 ctx->eFormat = IMG_CODEC_PL12; // use default 138 139 switch(ctx->sRCParams.eRCMode) { 140 case IMG_RCMODE_NONE: 141 ctx->eCodec = IMG_CODEC_MPEG4_NO_RC; 142 break; 143 case IMG_RCMODE_VBR: 144 ctx->eCodec = IMG_CODEC_MPEG4_VBR; 145 break; 146 case IMG_RCMODE_CBR: 147 ctx->eCodec = IMG_CODEC_MPEG4_CBR; 148 break; 149 default: 150 drv_debug_msg(VIDEO_DEBUG_ERROR, "Unknown RCMode %08x\n", ctx->sRCParams.eRCMode); 151 break; 152 } 153 154 ctx->bIsInterlaced = IMG_FALSE; 155 ctx->bIsInterleaved = IMG_FALSE; 156 ctx->ui16PictureHeight = ctx->ui16FrameHeight; 157 158 ctx->bVPAdaptiveRoundingDisable = IMG_TRUE; 159 160 /* TopazHP only support Simple Profile */ 161 switch (obj_config->profile) { 162 case VAProfileMPEG4Simple: 163 ctx->ui8ProfileIdc = SP; 164 break; 165 default: 166 ctx->ui8ProfileIdc = SP; 167 break; 168 } 169 170 //This parameter need not be exposed 171 ctx->ui8InterIntraIndex = 3; 172 ctx->ui8CodedSkippedIndex = 3; 173 ctx->bEnableHostQP = IMG_FALSE; 174 ctx->uMaxChunks = 0xA0; 175 ctx->uChunksPerMb = 0x40; 176 ctx->uPriorityChunks = (0xA0 - 0x60); 177 ctx->ui32FCode = 4; 178 ctx->iFineYSearchSize = 2; 179 180 //This parameter need not be exposed 181 //host to control the encoding process 182 ctx->bEnableInpCtrl = IMG_FALSE; 183 ctx->bEnableHostBias = IMG_FALSE; 184 //By default false Newly Added 185 ctx->bEnableCumulativeBiases = IMG_FALSE; 186 187 //Weighted Prediction is not supported in TopazHP Version 3.0 188 ctx->bWeightedPrediction = IMG_FALSE; 189 ctx->ui8VPWeightedImplicitBiPred = 0; 190 ctx->bInsertHRDParams = 0; 191 192 193 ctx->bArbitrarySO = IMG_FALSE; 194 ctx->ui32BasicUnit = 0; 195 196 return vaStatus; 197 } 198 199 static void tng_MPEG4ES_DestroyContext( 200 object_context_p obj_context) 201 { 202 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s\n", __FUNCTION__); 203 tng_DestroyContext(obj_context, 0); 204 } 205 206 static VAStatus tng_MPEG4ES_BeginPicture( 207 object_context_p obj_context) 208 { 209 INIT_CONTEXT_MPEG4ES; 210 tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf; 211 context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]); 212 VAStatus vaStatus = VA_STATUS_SUCCESS; 213 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s start\n", __FUNCTION__); 214 vaStatus = tng_BeginPicture(ctx); 215 216 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s end\n", __FUNCTION__); 217 return vaStatus; 218 } 219 220 static VAStatus tng__MPEG4ES_process_sequence_param(context_ENC_p ctx, object_buffer_p obj_buffer) 221 { 222 context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]); 223 VAEncSequenceParameterBufferMPEG4 *psSeqParams; 224 tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf; 225 IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams); 226 227 ASSERT(obj_buffer->type == VAEncSequenceParameterBufferType); 228 ASSERT(obj_buffer->size == sizeof(VAEncSequenceParameterBufferMPEG4)); 229 230 if (obj_buffer->size != sizeof(VAEncSequenceParameterBufferMPEG4)) { 231 return VA_STATUS_ERROR_UNKNOWN; 232 } 233 234 ctx->obj_context->frame_count = 0; 235 psSeqParams = (VAEncSequenceParameterBufferMPEG4 *) obj_buffer->buffer_data; 236 obj_buffer->buffer_data = NULL; 237 obj_buffer->size = 0; 238 239 ctx->ui32IdrPeriod = psSeqParams->intra_period; 240 ctx->ui32IntraCnt = psSeqParams->intra_period; 241 242 if (ctx->ui32IntraCnt == 0) { 243 ctx->ui32IntraCnt = INT_MAX; 244 ctx->ui32IdrPeriod = 1; 245 drv_debug_msg(VIDEO_DEBUG_GENERAL, 246 "%s: only ONE I frame in the sequence, %d\n", 247 __FUNCTION__, ctx->ui32IdrPeriod); 248 } 249 250 ctx->bCustomScaling = IMG_FALSE; 251 ctx->bUseDefaultScalingList = IMG_FALSE; 252 253 //set MV limit infor 254 ctx->ui32VertMVLimit = 255 ;//(63.75 in qpel increments) 255 ctx->bLimitNumVectors = IMG_TRUE; 256 257 ctx->ui8LevelIdc = psSeqParams->profile_and_level_indication; 258 259 /**************set rc params ****************/ 260 if (psSeqParams->bits_per_second > TOPAZ_MPEG4_MAX_BITRATE) { 261 ctx->sRCParams.ui32BitsPerSecond = TOPAZ_MPEG4_MAX_BITRATE; 262 drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \ 263 the maximum bitrate, set it with %d\n", 264 psSeqParams->bits_per_second, 265 TOPAZ_MPEG4_MAX_BITRATE); 266 } else 267 ctx->sRCParams.ui32BitsPerSecond = psSeqParams->bits_per_second; 268 269 //FIXME: Zhaohan, this should be figured out in testsuite? 270 if (!ctx->uiCbrBufferTenths) 271 ctx->uiCbrBufferTenths = TOPAZHP_DEFAULT_uiCbrBufferTenths; 272 273 if (ctx->uiCbrBufferTenths) { 274 psRCParams->ui32BufferSize = (IMG_UINT32)(psRCParams->ui32BitsPerSecond * ctx->uiCbrBufferTenths / 10.0); 275 } else { 276 if (psRCParams->ui32BitsPerSecond < 256000) 277 psRCParams->ui32BufferSize = ((9 * psRCParams->ui32BitsPerSecond) >> 1); 278 else 279 psRCParams->ui32BufferSize = ((5 * psRCParams->ui32BitsPerSecond) >> 1); 280 } 281 282 psRCParams->i32InitialDelay = (13 * psRCParams->ui32BufferSize) >> 4; 283 psRCParams->i32InitialLevel = (3 * psRCParams->ui32BufferSize) >> 4; 284 psRCParams->ui32IntraFreq = psSeqParams->intra_period; 285 286 psRCParams->ui32InitialQp = psSeqParams->initial_qp; 287 psRCParams->iMinQP = psSeqParams->min_qp; 288 ctx->ui32BasicUnit = psSeqParams->min_qp; 289 //psRCParams->ui32BUSize = psSeqParams->basic_unit_size; 290 //ctx->ui32KickSize = psRCParams->ui32BUSize; 291 psRCParams->ui32FrameRate = psSeqParams->frame_rate; 292 293 //B-frames are not supported for non-H.264 streams 294 ctx->sRCParams.ui16BFrames = 0; 295 ctx->ui8SlotsInUse = psRCParams->ui16BFrames + 2; 296 297 #if HEADERS_VERBOSE_OUTPUT 298 drv_debug_msg(VIDEO_DEBUG_GENERAL, "\n\n**********************************************************************\n"); 299 drv_debug_msg(VIDEO_DEBUG_GENERAL, "******** HOST FIRMWARE ROUTINES TO PASS HEADERS AND TOKENS TO MTX******\n"); 300 drv_debug_msg(VIDEO_DEBUG_GENERAL, "**********************************************************************\n\n"); 301 #endif 302 303 free(psSeqParams); 304 305 return VA_STATUS_SUCCESS; 306 } 307 308 static VAStatus tng__MPEG4ES_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer) 309 { 310 VAStatus vaStatus = VA_STATUS_SUCCESS; 311 context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]); 312 context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf); 313 VAEncPictureParameterBufferMPEG4 *psPicParams; 314 IMG_BOOL bDepViewPPS = IMG_FALSE; 315 void* pTmpBuf = NULL; 316 317 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: start\n",__FUNCTION__); 318 ASSERT(obj_buffer->type == VAEncPictureParameterBufferType); 319 if (obj_buffer->size != sizeof(VAEncPictureParameterBufferMPEG4)) { 320 drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__); 321 return VA_STATUS_ERROR_UNKNOWN; 322 } 323 324 /* Transfer ownership of VAEncPictureParameterBufferMPEG4 data */ 325 psPicParams = (VAEncPictureParameterBufferMPEG4 *) obj_buffer->buffer_data; 326 obj_buffer->buffer_data = NULL; 327 obj_buffer->size = 0; 328 329 ASSERT(ctx->ui16Width == psPicParams->picture_width); 330 ASSERT(ctx->ui16PictureHeight == psPicParams->picture_height); 331 #ifndef _TNG_FRAMES_ 332 ps_buf->ref_surface[0] = ps_buf->ref_surface[2] = SURFACE(psPicParams->reference_picture); 333 ps_buf->ref_surface[1] = ps_buf->ref_surface[3] = SURFACE(psPicParams->reconstructed_picture); 334 335 ps_buf->ref_surface[0]->is_ref_surface = ps_buf->ref_surface[2]->is_ref_surface = 1; 336 ps_buf->ref_surface[1]->is_ref_surface = ps_buf->ref_surface[3]->is_ref_surface = 1; 337 #else 338 ps_buf->ref_surface = SURFACE(psPicParams->reference_picture); 339 ps_buf->rec_surface = SURFACE(psPicParams->reconstructed_picture); 340 #endif 341 ps_buf->coded_buf = BUFFER(psPicParams->coded_buf); 342 343 if (NULL == ps_buf->coded_buf) { 344 drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__); 345 free(psPicParams); 346 return VA_STATUS_ERROR_INVALID_BUFFER; 347 } 348 349 free(psPicParams); 350 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: end\n",__FUNCTION__); 351 352 return vaStatus; 353 } 354 355 static VAStatus tng__MPEG4ES_process_slice_param(context_ENC_p ctx, object_buffer_p obj_buffer) 356 { 357 VAStatus vaStatus = VA_STATUS_SUCCESS; 358 VAEncSliceParameterBuffer *psSliceParams; 359 360 ASSERT(obj_buffer->type == VAEncSliceParameterBufferType); 361 /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */ 362 363 /* Transfer ownership of VAEncPictureParameterBufferMPEG4 data */ 364 psSliceParams = (VAEncSliceParameterBuffer*) obj_buffer->buffer_data; 365 obj_buffer->size = 0; 366 367 //deblocking behaviour 368 ctx->bArbitrarySO = IMG_FALSE; 369 ctx->ui8DeblockIDC = psSliceParams->slice_flags.bits.disable_deblocking_filter_idc; 370 ++ctx->ui8SlicesPerPicture; 371 return vaStatus; 372 } 373 374 static VAStatus tng__MPEG4ES_process_misc_param(context_ENC_p ctx, object_buffer_p obj_buffer) 375 { 376 VAStatus vaStatus = VA_STATUS_SUCCESS; 377 VAEncMiscParameterBuffer *pBuffer; 378 VAEncMiscParameterFrameRate *frame_rate_param; 379 VAEncMiscParameterRateControl *rate_control_param; 380 IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams); 381 382 ASSERT(obj_buffer->type == VAEncMiscParameterBufferType); 383 384 /* Transfer ownership of VAEncMiscParameterBuffer data */ 385 pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data; 386 obj_buffer->size = 0; 387 388 switch (pBuffer->type) { 389 case VAEncMiscParameterTypeRateControl: 390 rate_control_param = (VAEncMiscParameterRateControl *)pBuffer->data; 391 392 if (rate_control_param->initial_qp > 51 || rate_control_param->min_qp > 51) { 393 drv_debug_msg(VIDEO_DEBUG_ERROR, "Initial_qp(%d) and min_qpinitial_qp(%d) " 394 "are invalid.\nQP shouldn't be larger than 51 for MPEG4\n", 395 rate_control_param->initial_qp, rate_control_param->min_qp); 396 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; 397 break; 398 } 399 400 drv_debug_msg(VIDEO_DEBUG_GENERAL, "rate control changed from %d to %d\n", 401 psRCParams->ui32BitsPerSecond, 402 rate_control_param->bits_per_second); 403 404 if ((rate_control_param->bits_per_second == psRCParams->ui32BitsPerSecond) && 405 (psRCParams->ui32BufferSize == psRCParams->ui32BitsPerSecond / 1000 * rate_control_param->window_size) && 406 (psRCParams->iMinQP == rate_control_param->min_qp) && 407 (psRCParams->ui32InitialQp == rate_control_param->initial_qp)) 408 break; 409 410 if (rate_control_param->bits_per_second > TOPAZ_MPEG4_MAX_BITRATE) { 411 psRCParams->ui32BitsPerSecond = TOPAZ_MPEG4_MAX_BITRATE; 412 drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \ 413 the maximum bitrate, set it with %d\n", 414 rate_control_param->bits_per_second, 415 TOPAZ_MPEG4_MAX_BITRATE); 416 } else 417 psRCParams->ui32BitsPerSecond = rate_control_param->bits_per_second; 418 419 if (rate_control_param->window_size != 0) 420 psRCParams->ui32BufferSize = psRCParams->ui32BitsPerSecond * rate_control_param->window_size / 1000; 421 if (rate_control_param->initial_qp != 0) 422 psRCParams->ui32InitialQp = rate_control_param->initial_qp; 423 if (rate_control_param->min_qp != 0) 424 psRCParams->iMinQP = rate_control_param->min_qp; 425 break; 426 default: 427 break; 428 } 429 430 return vaStatus; 431 } 432 433 static VAStatus tng_MPEG4ES_RenderPicture( 434 object_context_p obj_context, 435 object_buffer_p *buffers, 436 int num_buffers) 437 { 438 INIT_CONTEXT_MPEG4ES; 439 VAStatus vaStatus = VA_STATUS_SUCCESS; 440 int i; 441 442 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: start\n", __FUNCTION__); 443 for (i = 0; i < num_buffers; i++) { 444 object_buffer_p obj_buffer = buffers[i]; 445 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: type = %d, num = %d\n", __FUNCTION__, obj_buffer->type, num_buffers); 446 447 switch (obj_buffer->type) { 448 case VAEncSequenceParameterBufferType: 449 drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_MPEG4_RenderPicture got VAEncSequenceParameterBufferType\n"); 450 vaStatus = tng__MPEG4ES_process_sequence_param(ctx, obj_buffer); 451 DEBUG_FAILURE; 452 break; 453 case VAEncPictureParameterBufferType: 454 drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_MPEG4_RenderPicture got VAEncPictureParameterBuffer\n"); 455 vaStatus = tng__MPEG4ES_process_picture_param(ctx, obj_buffer); 456 DEBUG_FAILURE; 457 break; 458 459 case VAEncSliceParameterBufferType: 460 drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_MPEG4_RenderPicture got VAEncSliceParameterBufferType\n"); 461 vaStatus = tng__MPEG4ES_process_slice_param(ctx, obj_buffer); 462 DEBUG_FAILURE; 463 break; 464 465 case VAEncMiscParameterBufferType: 466 drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_MPEG4_RenderPicture got VAEncMiscParameterBufferType\n"); 467 vaStatus = tng__MPEG4ES_process_misc_param(ctx, obj_buffer); 468 DEBUG_FAILURE; 469 break; 470 default: 471 vaStatus = VA_STATUS_ERROR_UNKNOWN; 472 DEBUG_FAILURE; 473 } 474 if (vaStatus != VA_STATUS_SUCCESS) { 475 break; 476 } 477 } 478 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: end\n", __FUNCTION__); 479 480 return vaStatus; 481 } 482 483 static VAStatus tng_MPEG4ES_EndPicture( 484 object_context_p obj_context) 485 { 486 INIT_CONTEXT_MPEG4ES; 487 VAStatus vaStatus = VA_STATUS_SUCCESS; 488 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s start\n", __FUNCTION__); 489 vaStatus = tng_EndPicture(ctx); 490 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s end\n", __FUNCTION__); 491 492 return vaStatus; 493 } 494 495 struct format_vtable_s tng_MPEG4ES_vtable = { 496 queryConfigAttributes: 497 tng_MPEG4ES_QueryConfigAttributes, 498 validateConfig: 499 tng_MPEG4ES_ValidateConfig, 500 createContext: 501 tng_MPEG4ES_CreateContext, 502 destroyContext: 503 tng_MPEG4ES_DestroyContext, 504 beginPicture: 505 tng_MPEG4ES_BeginPicture, 506 renderPicture: 507 tng_MPEG4ES_RenderPicture, 508 endPicture: 509 tng_MPEG4ES_EndPicture 510 }; 511 512 /*EOF*/ 513