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