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