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