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