tng_hostair.c revision e26d82700f9514cc175d2b54733ebdeb8824922e
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 * Edward Lin <edward.lin@intel.com> 27 * 28 */ 29 30#include <unistd.h> 31#include <stdio.h> 32#include <memory.h> 33#include "psb_drv_video.h" 34#include "psb_drv_debug.h" 35#include "tng_hostdefs.h" 36#include "tng_hostcode.h" 37#include "tng_hostair.h" 38 39 40/*********************************************************************************** 41 * Function Name : functions of pi8AIR_Table table 42 ************************************************************************************/ 43VAStatus tng_air_buf_create(context_ENC_p ctx) 44{ 45 IMG_UINT32 ui32MbNum = (ctx->ui16PictureHeight * ctx->ui16Width) >> 8; 46 ctx->sAirInfo.pi8AIR_Table = (IMG_INT8 *)malloc(ui32MbNum); 47 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: ui32MbNum = %d\n", __FUNCTION__, ui32MbNum); 48 if (!ctx->sAirInfo.pi8AIR_Table) { 49 drv_debug_msg(VIDEO_DEBUG_ERROR, 50 "\nERROR: Error allocating Adaptive Intra Refresh table of Application context (APP_SetVideoParams)"); 51 return VA_STATUS_ERROR_ALLOCATION_FAILED; 52 } 53 memset(ctx->sAirInfo.pi8AIR_Table, 0, ui32MbNum); 54 return VA_STATUS_SUCCESS; 55} 56 57static void tng_air_buf_clear(context_ENC_p ctx) 58{ 59 IMG_UINT32 ui32MbNum = (ctx->ui16PictureHeight * ctx->ui16Width) >> 8; 60 drv_debug_msg(VIDEO_DEBUG_ERROR,"%s: ui32MbNum = %d, ctx->sAirInfo.pi8AIR_Table = 0x%08x\n", __FUNCTION__, ui32MbNum, ctx->sAirInfo.pi8AIR_Table); 61 memset(ctx->sAirInfo.pi8AIR_Table, 0, ui32MbNum); 62 drv_debug_msg(VIDEO_DEBUG_ERROR,"%s: ui32MbNum = %d, ctx->sAirInfo.pi8AIR_Table = 0x%08x\n", __FUNCTION__, ui32MbNum, ctx->sAirInfo.pi8AIR_Table); 63 return ; 64} 65 66void tng_air_buf_free(context_ENC_p ctx) 67{ 68 if (ctx->sAirInfo.pi8AIR_Table != NULL) 69 free(ctx->sAirInfo.pi8AIR_Table); 70 return ; 71} 72 73/*********************************************************************************** 74 * Function Name : functions for input control 75 ************************************************************************************/ 76static IMG_UINT16 tng__rand(context_ENC_p ctx) 77{ 78 IMG_UINT16 ui16ret = 0; 79 ctx->ui32pseudo_rand_seed = (IMG_UINT32) ((ctx->ui32pseudo_rand_seed * 1103515245 + 12345) & 0xffffffff); //Using mask, just in case 80 ui16ret = (IMG_UINT16)(ctx->ui32pseudo_rand_seed / 65536) % 32768; 81 return ui16ret; 82} 83 84//APP_FillSliceMap 85IMG_UINT32 tng_fill_slice_map(context_ENC_p ctx, IMG_INT32 i32SlotNum, IMG_UINT32 ui32StreamIndex) 86{ 87 context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamIndex]); 88 unsigned char *pvBuffer; 89 IMG_UINT8 ui8SlicesPerPicture; 90 IMG_UINT8 ui8HalfWaySlice; 91 IMG_UINT32 ui32HalfwayBU; 92 93 ui8SlicesPerPicture = ctx->ui8SlicesPerPicture; 94 ui32HalfwayBU = 0; 95 ui8HalfWaySlice=ui8SlicesPerPicture/2; 96#ifdef _PDUMP_FUNC_ 97 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: slot num = %d, aso = %d\n", __FUNCTION__, i32SlotNum, ctx->bArbitrarySO); 98 drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: stream id = %d, addr = 0x%x\n", __FUNCTION__, ui32StreamIndex, ps_mem->bufs_slice_map.virtual_addr); 99#endif 100 101#ifdef _TOPAZHP_VIR_ADDR_ 102 psb_buffer_map(&(ps_mem->bufs_slice_map), &(ps_mem->bufs_slice_map.virtual_addr)); 103#endif 104 pvBuffer = (unsigned char*)(ps_mem->bufs_slice_map.virtual_addr + (i32SlotNum * ctx->ctx_mem_size.slice_map)); 105 106 if (ctx->bArbitrarySO) { 107 IMG_UINT8 ui8Index; 108 IMG_UINT8 ui32FirstBUInSlice; 109 IMG_UINT8 ui8SizeInKicks; 110 IMG_UINT8 ui8TotalBUs; 111 IMG_UINT8 aui8SliceNumbers[MAX_SLICESPERPIC]; 112 113 ui8SlicesPerPicture = tng__rand(ctx) % ctx->ui8SlicesPerPicture + 1; 114 // Fill slice map 115 // Fill number of slices 116 * pvBuffer = ui8SlicesPerPicture; 117 pvBuffer++; 118 119 for (ui8Index = 0; ui8Index < ui8SlicesPerPicture; ui8Index++) 120 aui8SliceNumbers[ui8Index] = ui8Index; 121 122 // randomise slice numbers 123 for (ui8Index = 0; ui8Index < 20; ui8Index++) { 124 IMG_UINT8 ui8FirstCandidate; 125 IMG_UINT8 ui8SecondCandidate; 126 IMG_UINT8 ui8Temp; 127 128 ui8FirstCandidate = tng__rand(ctx) % ui8SlicesPerPicture; 129 ui8SecondCandidate = tng__rand(ctx) % ui8SlicesPerPicture; 130 131 ui8Temp = aui8SliceNumbers[ui8FirstCandidate]; 132 aui8SliceNumbers[ui8FirstCandidate] = aui8SliceNumbers[ui8SecondCandidate]; 133 aui8SliceNumbers[ui8SecondCandidate] = ui8Temp; 134 } 135 136 ui8TotalBUs = (ctx->ui16PictureHeight / 16) * (ctx->ui16Width / 16) / ctx->sRCParams.ui32BUSize; 137 138 ui32FirstBUInSlice = 0; 139 140 for (ui8Index = 0; ui8Index < ui8SlicesPerPicture - 1; ui8Index++) { 141 IMG_UINT32 ui32BUsCalc; 142 if (ui8Index==ui8HalfWaySlice) ui32HalfwayBU=ui32FirstBUInSlice; 143 144 ui32BUsCalc=(ui8TotalBUs - 1 * (ui8SlicesPerPicture - ui8Index)); 145 if(ui32BUsCalc) 146 ui8SizeInKicks = tng__rand(ctx) %ui32BUsCalc + 1; 147 else 148 ui8SizeInKicks = 1; 149 ui8TotalBUs -= ui8SizeInKicks; 150 151 // slice number 152 * pvBuffer = aui8SliceNumbers[ui8Index]; 153 pvBuffer++; 154 155 // SizeInKicks BU 156 * pvBuffer = ui8SizeInKicks; 157 pvBuffer++; 158 ui32FirstBUInSlice += (IMG_UINT32) ui8SizeInKicks; 159 } 160 ui8SizeInKicks = ui8TotalBUs; 161 // slice number 162 * pvBuffer = aui8SliceNumbers[ui8SlicesPerPicture - 1]; 163 pvBuffer++; 164 165 // last BU 166 * pvBuffer = ui8SizeInKicks; 167 pvBuffer++; 168 } else { 169 // Fill standard Slice Map (non arbitrary) 170 IMG_UINT8 ui8Index; 171 IMG_UINT8 ui8SliceNumber; 172 IMG_UINT8 ui32FirstBUInSlice; 173 IMG_UINT8 ui8SizeInKicks; 174 IMG_UINT32 ui32SliceHeight; 175 176 // Fill number of slices 177 * pvBuffer = ui8SlicesPerPicture; 178 pvBuffer++; 179 180 181 ui32SliceHeight = (ctx->ui16PictureHeight / ctx->ui8SlicesPerPicture) & ~15; 182 183 ui32FirstBUInSlice = 0; 184 ui8SliceNumber = 0; 185 for (ui8Index = 0; ui8Index < ui8SlicesPerPicture - 1; ui8Index++) { 186 if (ui8Index==ui8HalfWaySlice) ui32HalfwayBU=ui32FirstBUInSlice; 187 ui8SizeInKicks = ((ui32SliceHeight / 16)*(ctx->ui16Width/16))/ctx->sRCParams.ui32BUSize; 188 189 // slice number 190 * pvBuffer = ui8SliceNumber; 191 pvBuffer++; 192 // SizeInKicks BU 193 * pvBuffer = ui8SizeInKicks; 194 pvBuffer++; 195 196 ui8SliceNumber++; 197 ui32FirstBUInSlice += (IMG_UINT32) ui8SizeInKicks; 198 } 199 ui32SliceHeight = ctx->ui16PictureHeight - ui32SliceHeight * (ctx->ui8SlicesPerPicture - 1); 200 if (ui8Index==ui8HalfWaySlice) ui32HalfwayBU=ui32FirstBUInSlice; 201 ui8SizeInKicks = ((ui32SliceHeight / 16)*(ctx->ui16Width/16))/ctx->sRCParams.ui32BUSize; 202 203 // slice number 204 * pvBuffer = ui8SliceNumber; pvBuffer++; 205 // last BU 206 * pvBuffer = ui8SizeInKicks; pvBuffer++; 207 } 208#ifdef _TOPAZHP_VIR_ADDR_ 209 psb_buffer_unmap(&(ps_mem->bufs_slice_map)); 210#endif 211 ctx->ui32HalfWayBU[i32SlotNum] = ui32HalfwayBU; 212 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: ui32HalfWayBU = %d\n", __FUNCTION__, ctx->ui32HalfWayBU[i32SlotNum]); 213 return ui32HalfwayBU; 214} 215 216//IMG_V_GetInpCtrlBuf 217static VAStatus tng__map_inp_ctrl_buf( 218 context_ENC_p ctx, 219 IMG_UINT8 ui8SlotNumber, 220 IMG_UINT8 **ppsInpCtrlBuf) 221{ 222 VAStatus vaStatus = VA_STATUS_SUCCESS; 223 context_ENC_mem* ps_mem = &(ctx->ctx_mem[0]); 224 context_ENC_mem_size *ps_mem_size = &(ctx->ctx_mem_size); 225 226 // if enabled, return the input-control buffer corresponding to this slot 227 if (ctx->bEnableInpCtrl) { 228 psb_buffer_map(&(ps_mem->bufs_mb_ctrl_in_params), ppsInpCtrlBuf); 229 *ppsInpCtrlBuf += ui8SlotNumber * ps_mem_size->mb_ctrl_in_params; 230 } else { 231 *ppsInpCtrlBuf = NULL; // Not enabled 232 } 233 234 return vaStatus; 235} 236 237static VAStatus tng__unmap_inp_ctrl_buf( 238 context_ENC_p ctx, 239 IMG_UINT8 ui8SlotNumber, 240 IMG_UINT8 **ppsInpCtrlBuf) 241{ 242 VAStatus vaStatus = VA_STATUS_SUCCESS; 243 context_ENC_mem* ps_mem = &(ctx->ctx_mem[0]); 244 245 // if enabled, return the input-control buffer corresponding to this slot 246 if (*ppsInpCtrlBuf != NULL) { 247 psb_buffer_unmap(&(ps_mem->bufs_mb_ctrl_in_params)); 248 *ppsInpCtrlBuf = NULL; // Not enabled 249 } 250 return vaStatus; 251} 252 253//APP_FillInpCtrlBuf 254#define DEFAULT_INTER_INTRA_SCALE_TBL_IDX (0) 255#define DEFAULT_CODED_SKIPPED_SCALE_TBL_IDX (0) 256#define DEFAULT_INPUT_QP (0xF) 257#define SIZEOF_MB_IN_CTRL_PARAM (2) 258 259static void tng__fill_inp_ctrl_buf( 260 context_ENC_p ctx, 261 IMG_UINT8 *pInpCtrlBuf, 262 IMG_INT16 i16IntraRefresh, 263 IMG_INT8* pi8QP, 264 IMG_UINT32 ui32HalfWayBU) 265{ 266 IMG_PVOID pvBuffer; 267 IMG_UINT32 ui32MBFrameWidth; 268 IMG_UINT32 ui32MBPictureHeight; 269 IMG_UINT32 ui32MBSliceHeight; 270 IMG_UINT16 ui16DefaultParam; 271 IMG_UINT16 ui16IntraParam; 272 IMG_BOOL bRefresh=IMG_FALSE; 273 IMG_UINT32 ui32CurrentIndex; 274 IMG_UINT32 ui32MBx, ui32MBy; 275 IMG_UINT16 *pui16MBParam; 276 IMG_INT8 i8QPInit; 277 IMG_INT8 i8QP; 278 IMG_INT8 iMaxQP; 279#ifdef BRN_30324 280 IMG_UINT32 ui32HalfWayMB=ui32HalfWayBU * ctx->sRCParams.ui32BUSize; 281#endif 282 283 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: start QP = %d\n", __FUNCTION__, *pi8QP); 284 285 if (i16IntraRefresh > 0) { 286 bRefresh=IMG_TRUE; 287 } 288 289 iMaxQP = 31; 290 if (ctx->eStandard == IMG_STANDARD_H264) { 291 iMaxQP = 51; 292 } 293 if(pi8QP) { 294 i8QPInit = * pi8QP; 295 } else { 296 i8QPInit = DEFAULT_INPUT_QP; 297 } 298 // get the buffer 299 // IMG_C_GetBuffer(psActiveContext->hContext, pInpCtrlBuf, &pvBuffer,IMG_TRUE); 300 pvBuffer = (IMG_PVOID) pInpCtrlBuf; 301 302 //fill data 303 ui32MBFrameWidth = (ctx->ui16Width/16); 304 ui32MBPictureHeight = (ctx->ui16PictureHeight/16); 305 ui32MBSliceHeight = (ui32MBPictureHeight/ctx->ui8SlicesPerPicture); 306 307 pui16MBParam = (IMG_UINT16 *)pvBuffer; 308 ui32CurrentIndex=0; 309 310 for( ui32MBy = 0; ui32MBy < (IMG_UINT32)(ctx->ui16PictureHeight/16); ui32MBy++) { 311 for( ui32MBx=0; ui32MBx < ui32MBFrameWidth; ui32MBx++) { 312 IMG_UINT16 ui16MBParam = 0; 313 314#ifdef BRN_30324 315 if (ui32HalfWayMB && ui32CurrentIndex == ui32HalfWayMB) 316 if (ctx->ui8SlicesPerPicture > 1 && ctx->i32NumPipes > 1) { 317 ui32CurrentIndex=(((ui32CurrentIndex)+31)&(~31)); 318 } 319#endif 320 i8QP = i8QPInit + ((tng__rand(ctx)%6)-3); 321 i8QP = tng__max(tng__min(i8QP, iMaxQP), ctx->sRCParams.iMinQP); 322 323 ui16DefaultParam = ( i8QP<<10) | (3 <<7) |(3<<4); 324 ui16IntraParam = ( i8QP<<10) | (0 <<7) |(0<<4); 325 326 ui16MBParam = ui16DefaultParam; 327 if (bRefresh) { 328 if ((IMG_INT32)ui32CurrentIndex>ctx->i32LastCIRIndex) { 329 ctx->i32LastCIRIndex = ui32CurrentIndex; 330 ui16MBParam=ui16IntraParam; 331 i16IntraRefresh --; 332 if(i16IntraRefresh<=0) 333 bRefresh=IMG_FALSE; 334 } 335 } 336 pui16MBParam[ui32CurrentIndex++]=ui16MBParam; 337 } 338 } 339 340 if (bRefresh) { 341 ctx->i32LastCIRIndex=-1; 342 while (i16IntraRefresh) { 343 i8QP = i8QPInit + ((tng__rand(ctx)%6)-3); 344 i8QP = tng__max(tng__min(i8QP, iMaxQP), ctx->sRCParams.iMinQP); 345 ui16IntraParam = ( i8QP<<10) |(0 <<7) |(0<<4); 346 pui16MBParam[++ctx->i32LastCIRIndex]=ui16IntraParam; 347 i16IntraRefresh--; 348 } 349 } 350 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: end QP = %d\n", __FUNCTION__, *pi8QP); 351 //release buffer 352 //IMG_C_ReleaseBuffer(psActiveContext->hContext, pInpCtrlBuf,IMG_TRUE); 353 return ; 354} 355 356/*********************************************************************************** 357 * Function Name : APP_FillInputControl 358 * Inputs : psContext 359 * Description : Fills input control buffer for a given source picture 360 ************************************************************************************/ 361static void tng__fill_input_control( 362 context_ENC_p ctx, 363 IMG_UINT8 ui8SlotNum, 364 IMG_UINT32 ui32HalfWayBU) 365{ 366 IMG_UINT8 * pInpCtrlBuf = NULL; 367 IMG_INT8 i8InitialQp = ctx->sRCParams.ui32InitialQp; 368 // Get pointer to MB Control buffer for current source buffer (if input control is enabled, otherwise buffer is NULL) 369 tng__map_inp_ctrl_buf(ctx, ui8SlotNum, &pInpCtrlBuf); 370 if (pInpCtrlBuf!= IMG_NULL) { 371 tng__fill_inp_ctrl_buf(ctx, pInpCtrlBuf,(IMG_INT16)(ctx->ui16IntraRefresh), &i8InitialQp, ui32HalfWayBU); 372 } 373 tng__unmap_inp_ctrl_buf(ctx, ui8SlotNum, &pInpCtrlBuf); 374 return ; 375} 376 377static void tng__send_air_inp_ctrl_buf(context_ENC_p ctx, IMG_INT8 *pInpCtrlBuf) 378{ 379 //IMG_PVOID pvICBuffer; 380 IMG_UINT16 ui16IntraParam; 381 //IMG_BOOL bRefresh = IMG_FALSE; 382 IMG_UINT32 ui32CurrentCnt, ui32SentCnt; 383 IMG_UINT32 ui32MBMaxSize; 384 IMG_UINT16 *pui16MBParam; 385 IMG_UINT32 ui32NewScanPos, ui32Skip; 386 387#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 388 IMG_CHAR TmpOutputTble[396]; //Debug only 389#endif 390 ui16IntraParam = (0 << 7) | (0 << 4); 391 392 if (ctx->ui32FrameCount[0] < 1) 393 return; 394 395 // get the buffer 396 pui16MBParam = (IMG_UINT16 *) pInpCtrlBuf; 397 398 //fill data 399 ui32MBMaxSize = (IMG_UINT32)(ctx->ui16PictureHeight / 16) * (IMG_UINT32)(ctx->ui16Width / 16); 400 ui32CurrentCnt = 0; 401 if (ctx->sAirInfo.i16AIRSkipCnt >= 0) 402 ui32Skip = ctx->sAirInfo.i16AIRSkipCnt; 403 else 404 //ui32Skip=APP_Rand() % psActiveContext->sAirInfo.i32NumAIRSPerFrame; // Pseudorandom skip. 405 ui32Skip = (ctx->ui32FrameCount[0] & 0x7) + 1; // Pseudorandom skip. 406 407#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 408 { 409 IMG_UINT32 tsp; 410 if (fp) 411 { 412 fp = fopen("SADvals.txt", "a"); 413 } 414 else 415 { 416 fp = fopen("SADvals.txt", "w"); 417 } 418 419 fprintf(fp, "\n---------------------------------------------------------------------------\n"); 420 fprintf(fp, "SENDING SADvals (skip:%i)\n", ui32Skip); 421 422 for (tsp = 0; tsp < ui32MBMaxSize; tsp++) 423 { 424 if (ctx->sAirInfo.pi8AIR_Table[tsp] > 0) 425 { 426 TmpOutputTble[tsp] = 'x'; 427 } 428 else 429 { 430 TmpOutputTble[tsp] = 'o'; 431 } 432 } 433 } 434#endif 435 436 ui32NewScanPos = (IMG_UINT32) (ctx->sAirInfo.ui16AIRScanPos + ui32Skip) % ui32MBMaxSize; 437 ui32CurrentCnt = ui32SentCnt = 0; 438 439 while (ui32CurrentCnt < ui32MBMaxSize && 440 ((ctx->sAirInfo.i32NumAIRSPerFrame == 0) || 441 ui32SentCnt < (IMG_UINT32) ctx->sAirInfo.i32NumAIRSPerFrame)) { 442 IMG_UINT16 ui16MBParam; 443 444 if (ctx->sAirInfo.pi8AIR_Table[ui32NewScanPos] >= 0) { 445 // Mark the entry as 'touched' 446 ctx->sAirInfo.pi8AIR_Table[ui32NewScanPos] = -1 - ctx->sAirInfo.pi8AIR_Table[ui32NewScanPos]; 447 448 if (ctx->sAirInfo.pi8AIR_Table[ui32NewScanPos] < -1) { 449 ui16MBParam = pui16MBParam[ui32NewScanPos] & (0xFF << 10); 450 ui16MBParam |= ui16IntraParam; 451 pui16MBParam[ui32NewScanPos] = ui16MBParam; 452 ctx->sAirInfo.pi8AIR_Table[ui32NewScanPos]++; 453#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 454 TmpOutputTble[ui32NewScanPos]='I'; 455#endif 456 ui32NewScanPos += ui32Skip; 457 ui32SentCnt++; 458 } 459 ui32CurrentCnt++; 460 } 461 462 ui32NewScanPos++; 463 ui32NewScanPos = ui32NewScanPos % ui32MBMaxSize; 464 if (ui32NewScanPos == ctx->sAirInfo.ui16AIRScanPos) { 465 /* we have looped around */ 466 break; 467 } 468 } 469 470 ctx->sAirInfo.ui16AIRScanPos = ui32NewScanPos; 471 472#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 473 { 474 IMG_UINT32 tsp; 475 for (tsp = 0; tsp < ui32MBMaxSize; tsp++) 476 { 477 if (tsp % ((IMG_UINT32)(ctx->ui16Width/16)) == 0) 478 { 479 fprintf(fp, "\n%c", TmpOutputTble[tsp]); 480 } 481 else 482 { 483 fprintf(fp, "%c", TmpOutputTble[tsp]); 484 } 485 } 486 487 fprintf(fp, "\n---------------------------------------------------------------------------\n"); 488 fclose(fp); 489 } 490#endif 491 492 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: end\n", __FUNCTION__); 493 return ; 494} 495 496// Adaptive Intra Refresh (AIR) - send the AIR values to the next bufferk 497// APP_UpdateAdaptiveIntraRefresh_Send 498static void tng__update_air_send(context_ENC_p ctx, IMG_UINT8 ui8SlotNum) 499{ 500 IMG_UINT8 *pInpCtrlBuf = NULL; 501 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: start\n", __FUNCTION__); 502 // Get pointer to MB Control buffer for current source buffer (if input control is enabled, otherwise buffer is NULL) 503 tng__map_inp_ctrl_buf(ctx, ui8SlotNum, &pInpCtrlBuf); 504 if(pInpCtrlBuf!= IMG_NULL) { 505 tng__send_air_inp_ctrl_buf(ctx, (IMG_INT8 *)pInpCtrlBuf); 506 } 507 tng__unmap_inp_ctrl_buf(ctx, ui8SlotNum, &pInpCtrlBuf); 508 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: end\n", __FUNCTION__); 509 return ; 510} 511 512/*********************************************************************************** 513 * Function Name : functions for output control 514 ************************************************************************************/ 515//IMG_V_GetFirstPassOutBuf 516VAStatus tng__map_first_pass_out_buf( 517 context_ENC_p ctx, 518 IMG_UINT8 ui8SlotNumber, 519 IMG_UINT8 **ppsFirstPassOutBuf) 520{ 521 VAStatus vaStatus = VA_STATUS_SUCCESS; 522 context_ENC_mem* ps_mem = &(ctx->ctx_mem[0]); 523 524 // if enabled, return the input-control buffer corresponding to this slot 525 if (ctx->bEnableInpCtrl) 526 psb_buffer_map(&(ps_mem->bufs_first_pass_out_params), ppsFirstPassOutBuf); 527 else 528 *ppsFirstPassOutBuf = NULL; // Not enabled 529 530 return vaStatus; 531} 532 533VAStatus tng__unmap_first_pass_out_buf( 534 context_ENC_p ctx, 535 IMG_UINT8 ui8SlotNumber, 536 IMG_UINT8 **ppsFirstPassOutBuf) 537{ 538 VAStatus vaStatus = VA_STATUS_SUCCESS; 539 context_ENC_mem* ps_mem = &(ctx->ctx_mem[0]); 540 541 // if enabled, return the input-control buffer corresponding to this slot 542 if (*ppsFirstPassOutBuf != NULL) { 543 psb_buffer_unmap(&(ps_mem->bufs_first_pass_out_params)); 544 *ppsFirstPassOutBuf = NULL; // Not enabled 545 } 546 547 return vaStatus; 548} 549 550//IMG_V_GetBestMBDecisionOutBuf 551VAStatus tng__map_best_mb_decision_out_buf( 552 context_ENC_p ctx, 553 IMG_UINT8 ui8SlotNumber, 554 IMG_UINT8 **ppsBestMBDecisionOutBuf) 555{ 556 VAStatus vaStatus = VA_STATUS_SUCCESS; 557 context_ENC_mem* ps_mem = &(ctx->ctx_mem[0]); 558 559 // if enabled, return the input-control buffer corresponding to this slot 560 if (ctx->bEnableInpCtrl) 561 psb_buffer_map(&(ps_mem->bufs_first_pass_out_best_multipass_param), ppsBestMBDecisionOutBuf); 562 else 563 *ppsBestMBDecisionOutBuf = NULL; // Not enabled 564 565 return vaStatus; 566} 567 568VAStatus tng__unmap_best_mb_decision_out_buf( 569 context_ENC_p ctx, 570 IMG_UINT8 ui8SlotNumber, 571 IMG_UINT8 **ppsBestMBDecisionOutBuf) 572{ 573 VAStatus vaStatus = VA_STATUS_SUCCESS; 574 context_ENC_mem* ps_mem = &(ctx->ctx_mem[0]); 575 576 // if enabled, return the input-control buffer corresponding to this slot 577 if (*ppsBestMBDecisionOutBuf != NULL) { 578 psb_buffer_map(&(ps_mem->bufs_first_pass_out_best_multipass_param), ppsBestMBDecisionOutBuf); 579 *ppsBestMBDecisionOutBuf = NULL; // Not enabled 580 } 581 582 return vaStatus; 583} 584 585// Calculate Adaptive Intra Refresh (AIR) 586static void tng__calc_air_inp_ctrl_buf(context_ENC_p ctx, IMG_UINT8 *pFirstPassOutBuf, IMG_UINT8 *pBestMBDecisionCtrlBuf) 587{ 588 IMG_UINT8 *pSADPointer; 589 IMG_UINT8 *pvSADBuffer; 590 IMG_UINT8 ui8IsAlreadyIntra; 591 IMG_UINT32 ui32MBFrameWidth; 592 IMG_UINT32 ui32MBPictureHeight; 593 IMG_UINT16 ui16IntraParam; 594 IMG_UINT32 ui32MBx, ui32MBy; 595 IMG_UINT32 ui32SADParam; 596 IMG_UINT32 ui32tSAD_Threshold, ui32tSAD_ThresholdLo, ui32tSAD_ThresholdHi; 597 IMG_UINT32 ui32MaxMBs, ui32NumMBsOverThreshold, ui32NumMBsOverLo, ui32NumMBsOverHi; 598 IMG_BEST_MULTIPASS_MB_PARAMS *psBestMB_Params; 599 IMG_FIRST_STAGE_MB_PARAMS *psFirstMB_Params; 600 601 ui16IntraParam = (0 <<7)| (0<<4); 602 ui32NumMBsOverThreshold = ui32NumMBsOverLo = ui32NumMBsOverHi = 0; 603 //drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: start\n", __FUNCTION__); 604 605// if (psActiveContext->ui32EncodeSent < (IMG_UINT32)psActiveContext->ui8MaxSourceSlots + 1) 606// if (ctx->ui32FrameCount[0] < (IMG_UINT32)(ctx->ui8SlotsInUse + 1)) 607// return; 608 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: start\n", __FUNCTION__); 609 //fill data 610 ui32MBFrameWidth = (ctx->ui16Width/16); 611 ui32MBPictureHeight = (ctx->ui16PictureHeight/16); 612 613 614 // get the SAD results buffer (either IPE0 and IPE1 results or, preferably, the more accurate Best Multipass SAD results) 615 if (pBestMBDecisionCtrlBuf) { 616 pvSADBuffer = pBestMBDecisionCtrlBuf; 617 drv_debug_msg(VIDEO_DEBUG_GENERAL,"AIR active: Using Best Multipass SAD values "); 618 619//#ifdef MULTIPASS_MV_PLACEMENT_ISSUE_FIXED 620 if ((ctx->ui8EnableSelStatsFlags & ESF_MP_BEST_MOTION_VECTOR_STATS)) 621//#endif 622 { 623 // The actual Param structures (which contain SADs) are located after the Multipass Motion Vector entries 624 pvSADBuffer += (ui32MBPictureHeight * (ui32MBFrameWidth) * sizeof(IMG_BEST_MULTIPASS_MB_PARAMS_IPMV)); 625 } 626 } else { 627 pvSADBuffer = pFirstPassOutBuf; 628 drv_debug_msg(VIDEO_DEBUG_GENERAL,"AIR active: Using IPE SAD values "); 629 } 630 631 if (ctx->sAirInfo.i32NumAIRSPerFrame == 0) 632 ui32MaxMBs = ui32MBFrameWidth * ui32MBPictureHeight; // Default to ALL MB's in frame 633 else if (ctx->sAirInfo.i32NumAIRSPerFrame<0) 634 ctx->sAirInfo.i32NumAIRSPerFrame = ui32MaxMBs = ((ui32MBFrameWidth * ui32MBPictureHeight) + 99)/100; // Default to 1% of MB's in frame (min 1) 635 else 636 ui32MaxMBs = ctx->sAirInfo.i32NumAIRSPerFrame; 637 638 pSADPointer = (IMG_UINT8 *)pvSADBuffer; 639 640 if (ctx->sAirInfo.i32SAD_Threshold >= 0) 641 ui32tSAD_Threshold = (IMG_UINT16) ctx->sAirInfo.i32SAD_Threshold; 642 else { 643 // Running auto adjust threshold adjust mode 644 if (ctx->sAirInfo.i32SAD_Threshold == -1) { 645 // This will occur only the first time 646 if (pBestMBDecisionCtrlBuf) { 647 psBestMB_Params=(IMG_BEST_MULTIPASS_MB_PARAMS *) pSADPointer; // Auto seed the threshold with the first value 648 ui32SADParam = psBestMB_Params->ui32SAD_Inter_MBInfo & IMG_BEST_MULTIPASS_SAD_MASK; 649 } else { 650 psFirstMB_Params=(IMG_FIRST_STAGE_MB_PARAMS *) pSADPointer; // Auto seed the threshold with the first value 651 ui32SADParam = (IMG_UINT32) psFirstMB_Params->ui16Ipe0Sad; 652 } 653 ctx->sAirInfo.i32SAD_Threshold = -1-ui32SADParam; // Negative numbers indicate auto-adjusting threshold 654 } 655 ui32tSAD_Threshold = (IMG_UINT32) -(ctx->sAirInfo.i32SAD_Threshold+1); 656 } 657 658 ui32tSAD_ThresholdLo=ui32tSAD_Threshold/2; 659 ui32tSAD_ThresholdHi=ui32tSAD_Threshold + ui32tSAD_ThresholdLo; 660 661 drv_debug_msg(VIDEO_DEBUG_GENERAL,"Th:%u, MaxMbs:%u, Skp:%i\n", (unsigned int)ui32tSAD_Threshold, (unsigned int)ui32MaxMBs, ctx->sAirInfo.i16AIRSkipCnt); 662 663 664#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 665 if (fp) 666 fp=fopen("SADvals.txt","a"); 667 else 668 fp=fopen("SADvals.txt","w"); 669 670 if (ctx->sAirInfo.i32SAD_Threshold>=0) 671 if (ctx->sAirInfo.i32NumAIRSPerFrame>0) 672 fprintf(fp, "S_SADThreshold: %i MaxMBs: %i\n", ui32tSAD_Threshold, ui32MaxMBs); 673 else 674 fprintf(fp, "S_SADThreshold: %i MaxMBs: NA\n", ui32tSAD_Threshold, ui32MaxMBs); 675 else 676 fprintf(fp, "V_SADThreshold: %i MaxMBs: %i\n", ui32tSAD_Threshold, ui32MaxMBs); 677 678 if (pBestMBDecisionCtrlBuf) 679 fprintf(fp, "Using Best Multipass SAD values\n"); 680 else 681 fprintf(fp, "Using Motion Search Data IPE SAD values\n"); 682#endif 683 684 // This loop could be optimised to a single counter if necessary, retaining for clarity 685 for (ui32MBy = 0; ui32MBy < ui32MBPictureHeight; ui32MBy++) { 686 for( ui32MBx=0; ui32MBx<ui32MBFrameWidth; ui32MBx++) { 687#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 688 IMG_CHAR cMarked; 689 cMarked='_'; 690#endif 691 // Turn all negative table values to positive (reset 'touched' state of a block that may have been set in APP_SendAIRInpCtrlBuf()) 692 if (ctx->sAirInfo.pi8AIR_Table[ui32MBy * ui32MBFrameWidth + ui32MBx] < 0) 693 ctx->sAirInfo.pi8AIR_Table[ui32MBy * ui32MBFrameWidth + ui32MBx] = -1-ctx->sAirInfo.pi8AIR_Table[ui32MBy * ui32MBFrameWidth + ui32MBx]; 694 695 // This will read the SAD value from the buffer (either IPE0 SAD or the superior Best multipass parameter structure SAD value) 696 if (pBestMBDecisionCtrlBuf) { 697 psBestMB_Params=(IMG_BEST_MULTIPASS_MB_PARAMS *) pSADPointer; 698 ui32SADParam = psBestMB_Params->ui32SAD_Inter_MBInfo & IMG_BEST_MULTIPASS_SAD_MASK; 699 700 if ((psBestMB_Params->ui32SAD_Intra_MBInfo & IMG_BEST_MULTIPASS_MB_TYPE_MASK) >> IMG_BEST_MULTIPASS_MB_TYPE_SHIFT==1) 701 ui8IsAlreadyIntra=1; 702 else 703 ui8IsAlreadyIntra=0; 704 705 pSADPointer=(IMG_UINT8 *) &(psBestMB_Params[1]); 706 } else { 707 psFirstMB_Params=(IMG_FIRST_STAGE_MB_PARAMS *) pSADPointer; 708 ui32SADParam = (IMG_UINT32) psFirstMB_Params->ui16Ipe0Sad; 709 ui32SADParam += (IMG_UINT32) psFirstMB_Params->ui16Ipe1Sad; 710 ui32SADParam /= 2; 711 ui8IsAlreadyIntra = 0; // We don't have the information to determine this 712 pSADPointer=(IMG_UINT8 *) &(psFirstMB_Params[1]); 713 } 714 715 if (ui32SADParam >= ui32tSAD_ThresholdLo) { 716 ui32NumMBsOverLo++; 717 718 if (ui32SADParam >= ui32tSAD_Threshold) { 719#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 720 cMarked='i'; 721#endif 722 723 // if (!ui8IsAlreadyIntra) // Don't mark this block if it's just been encoded as an Intra block anyway 724 // (results seem better without this condition anyway) 725 { 726 ctx->sAirInfo.pi8AIR_Table[ui32MBy * ui32MBFrameWidth + ui32MBx]++; 727#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 728 cMarked='I'; 729#endif 730 } 731 ui32NumMBsOverThreshold++; 732 if (ui32SADParam >= ui32tSAD_ThresholdHi) 733 ui32NumMBsOverHi++; 734 } 735 } 736 737 738#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 739 fprintf(fp,"%4x[%i]%c, ",ui32SADParam, ctx->sAirInfo.pi8AIR_Table[ui32MBy * ui32MBFrameWidth + ui32MBx], cMarked); 740#endif 741 } 742 pSADPointer=(IMG_UINT8 *) ALIGN_64(((IMG_UINT32) pSADPointer)); 743#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 744 fprintf(fp,"\n"); 745#endif 746 } 747 748 // Test and process running adaptive threshold case 749 if (ctx->sAirInfo.i32SAD_Threshold<0) { 750 // Adjust our threshold (to indicate it's auto-adjustable store it as a negative value minus 1) 751 if (ui32NumMBsOverLo <= ui32MaxMBs) 752 ctx->sAirInfo.i32SAD_Threshold = (IMG_INT32) -((IMG_INT32)ui32tSAD_ThresholdLo)-1; 753 else 754 if (ui32NumMBsOverHi >= ui32MaxMBs) 755 ctx->sAirInfo.i32SAD_Threshold = (IMG_INT32) -((IMG_INT32)ui32tSAD_ThresholdHi)-1; 756 else { 757 if (ui32MaxMBs < ui32NumMBsOverThreshold) { 758 ctx->sAirInfo.i32SAD_Threshold = ((IMG_INT32) ui32tSAD_ThresholdHi-(IMG_INT32) ui32tSAD_Threshold); 759 ctx->sAirInfo.i32SAD_Threshold*=((IMG_INT32) ui32MaxMBs- (IMG_INT32) ui32NumMBsOverThreshold); 760 ctx->sAirInfo.i32SAD_Threshold/=((IMG_INT32) ui32NumMBsOverHi-(IMG_INT32) ui32NumMBsOverThreshold); 761 ctx->sAirInfo.i32SAD_Threshold += ui32tSAD_Threshold; 762 } else { 763 ctx->sAirInfo.i32SAD_Threshold = ((IMG_INT32) ui32tSAD_Threshold-(IMG_INT32) ui32tSAD_ThresholdLo); 764 ctx->sAirInfo.i32SAD_Threshold*=((IMG_INT32) ui32MaxMBs- (IMG_INT32) ui32NumMBsOverLo); 765 ctx->sAirInfo.i32SAD_Threshold/=((IMG_INT32) ui32NumMBsOverThreshold-(IMG_INT32) ui32NumMBsOverLo); 766 ctx->sAirInfo.i32SAD_Threshold += ui32tSAD_ThresholdLo; 767 } 768 ctx->sAirInfo.i32SAD_Threshold = -ctx->sAirInfo.i32SAD_Threshold-1; 769 } 770 771#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 772 fprintf(fp,"THRESHOLDS ADJUSTMENT\nThrLo:%i ThrMid:%i ThrHi:%i\nMBsLo:%i MBsMid:%i MBsHi:%i\n",ui32tSAD_ThresholdLo, ui32tSAD_Threshold, ui32tSAD_ThresholdHi, ui32NumMBsOverLo, ui32NumMBsOverThreshold, ui32NumMBsOverHi); 773 fprintf(fp,"Target No. MB's:%i\nThreshold adjusted to: %i\n",ui32MaxMBs, -(ctx->sAirInfo.i32SAD_Threshold)); 774#endif 775 } 776 777#ifdef ADAPTIVE_INTRA_REFRESH_DEBUG_OUTPUT 778 fprintf(fp,"\n MBs tagged:%i\n", ui32NumMBsOverThreshold); 779 fclose(fp); 780#endif 781 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: end\n", __FUNCTION__); 782 //release buffer 783 //if (pBestMBDecisionCtrlBuf) 784 //IMG_C_ReleaseBuffer(ctx->hContext, pBestMBDecisionCtrlBuf, IMG_TRUE); 785 //else 786 //IMG_C_ReleaseBuffer(ctx->hContext, pFirstPassOutBuf,IMG_TRUE); 787 return ; 788} 789 790// Adaptive Intra Refresh (AIR) - Calculate the new AIR values based upon Motion Search feedback 791// APP_UpdateAdaptiveIntraRefresh_Calc 792static void tng_update_air_calc(context_ENC_p ctx, IMG_UINT8 ui8SlotNum) 793{ 794 IMG_UINT8 *pFirstPassOutBuf = NULL; 795 IMG_UINT8 *pBestMBDecisionCtrlBuf = NULL; 796 797 // Get pointer to MB Control buffer for current source buffer (if input control is enabled, otherwise buffer is NULL) 798 tng__map_first_pass_out_buf(ctx, ui8SlotNum, &pFirstPassOutBuf); 799 tng__map_best_mb_decision_out_buf(ctx, ui8SlotNum, &pBestMBDecisionCtrlBuf); 800 801 if(pFirstPassOutBuf || pBestMBDecisionCtrlBuf) 802 tng__calc_air_inp_ctrl_buf (ctx, pFirstPassOutBuf, pBestMBDecisionCtrlBuf); 803 804 tng__unmap_first_pass_out_buf(ctx, ui8SlotNum, &pFirstPassOutBuf); 805 tng__unmap_best_mb_decision_out_buf(ctx, ui8SlotNum, &pBestMBDecisionCtrlBuf); 806 807} 808 809/*********************************************************************************** 810 * Function Name : 811 * Inputs : 812 * Description : 813 ************************************************************************************/ 814void tng_air_set_input_control(context_ENC_p ctx, IMG_UINT8 ui8StreamID) 815{ 816 IMG_UINT8 ui8SlotIndex = ctx->ui8SlotsCoded; 817drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: slot index = %d\n", __FUNCTION__, ctx->ui8SlotsCoded); 818// IMG_UINT32 ui32HalfWayBU; 819// ui32HalfWayBU = tng_fill_slice_map(ctx, ui8SlotIndex, ui8StreamID); 820 821 ////////////////////////////// INPUT CONTROL 822 // Add input control stuff here 823 tng__fill_input_control(ctx, ui8SlotIndex, ctx->ui32HalfWayBU[ui8SlotIndex]); 824 825 // Adaptive Intra Refresh (AIR) - send the AIR values to the next buffer 826 if (ctx->bEnableAIR) 827 tng__update_air_send(ctx, ui8SlotIndex); 828} 829 830 831/*********************************************************************************** 832 * Function Name : 833 * Inputs : 834 * Description : 835 ************************************************************************************/ 836void tng_air_set_output_control(context_ENC_p ctx, IMG_UINT8 ui8StreamID) 837{ 838 IMG_UINT8 ui8SlotIndex = ctx->ui8SlotsCoded; 839 840drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: slot index = %d\n", __FUNCTION__, ctx->ui8SlotsCoded); 841 842 if ((ctx->ePreFrameType == IMG_INTRA_IDR) || 843 (ctx->ePreFrameType == IMG_INTRA_FRAME)) 844 tng_air_buf_clear(ctx); 845 else 846 tng_update_air_calc(ctx, ui8SlotIndex); 847 848 return ; 849} 850