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 <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 ************************************************************************************/
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#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
70void 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 ************************************************************************************/
80static 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
89IMG_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
220out1:
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
228static 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
255static 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
277static 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 ************************************************************************************/
386static 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
408static 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
529static 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
551VAStatus 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
576VAStatus 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
594VAStatus 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
611VAStatus 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)
629static 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
827static 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 ************************************************************************************/
851void 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 ************************************************************************************/
873void 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