1316 lines
40 KiB
C
1316 lines
40 KiB
C
/*------------------------------------------------------------------------------
|
|
-- --
|
|
-- This software is confidential and proprietary and may be used --
|
|
-- only as expressly authorized by a licensing agreement from --
|
|
-- --
|
|
-- Hantro Products Oy. --
|
|
-- --
|
|
-- (C) COPYRIGHT 2006 HANTRO PRODUCTS OY --
|
|
-- ALL RIGHTS RESERVED --
|
|
-- --
|
|
-- The entire notice above must be reproduced --
|
|
-- on all copies and should not be removed. --
|
|
-- --
|
|
--------------------------------------------------------------------------------
|
|
--
|
|
-- Description : Reference buffer control functions.
|
|
--
|
|
------------------------------------------------------------------------------
|
|
--
|
|
-- Version control information, please leave untouched.
|
|
--
|
|
-- $RCSfile: refbuffer.c,v $
|
|
-- $Revision: 1.49 $
|
|
-- $Date: 2010/11/10 08:01:28 $
|
|
--
|
|
------------------------------------------------------------------------------*/
|
|
|
|
#include "basetype.h"
|
|
#include "regdrv.h"
|
|
#include "deccfg.h"
|
|
#include "refbuffer.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#define DEC_X170_MODE_H264 (0)
|
|
#define DEC_X170_MODE_MPEG4 (1)
|
|
#define DEC_X170_MODE_H263 (2)
|
|
#define DEC_X170_MODE_VC1 (4)
|
|
#define DEC_X170_MODE_MPEG2 (5)
|
|
#define DEC_X170_MODE_MPEG1 (6)
|
|
#define DEC_X170_MODE_VP6 (7)
|
|
#define DEC_X170_MODE_RV (8)
|
|
#define DEC_X170_MODE_VP7 (9)
|
|
#define DEC_X170_MODE_VP8 (10)
|
|
#define DEC_X170_MODE_AVS (11)
|
|
|
|
#define THR_ADJ_MAX (8)
|
|
#define THR_ADJ_MIN (1)
|
|
|
|
#define MAX_DIRECT_MVS (3000)
|
|
|
|
#ifndef DEC_X170_REFBU_ADJUST_VALUE
|
|
#define DEC_X170_REFBU_ADJUST_VALUE 130
|
|
#endif
|
|
|
|
/* Read direct MV from output memory; indexes i0..i2 used to
|
|
* handle both big- and little-endian modes. */
|
|
#define DIR_MV_VER(p,i0,i1,i2) \
|
|
((((u32)(p[(i0)])) << 3) | (((u32)(p[(i1)])) >> 5) | (((u32)(p[(i2)] & 0x3) ) << 11 ))
|
|
#define DIR_MV_BE_VER(p) \
|
|
((((u32)(p[1])) << 3) | (((u32)(p[0])) >> 5) | (((u32)(p[2] & 0x3) ) << 11 ))
|
|
#define DIR_MV_LE_VER(p) \
|
|
((((u32)(p[2])) << 3) | (((u32)(p[3])) >> 5) | (((u32)(p[1] & 0x3) ) << 11 ))
|
|
#define SIGN_EXTEND(value, bits) (value) = (((value)<<(32-bits))>>(32-bits))
|
|
|
|
/* Distribution ranges and zero point */
|
|
#define VER_DISTR_MIN (-256)
|
|
#define VER_DISTR_MAX (255)
|
|
#define VER_DISTR_RANGE (512)
|
|
#define VER_DISTR_ZERO_POINT (256)
|
|
#define VER_MV_RANGE (16)
|
|
#define HOR_CALC_WIDTH (32)
|
|
|
|
/* macro to get absolute value */
|
|
#define ABS(a) (((a) < 0) ? -(a) : (a))
|
|
|
|
static const memAccess_t memStatsPerFormat[] = {
|
|
{ 307, 36, 150 }, /* H.264 (upped 20%) */
|
|
{ 236, 29, 112 }, /* MPEG-4 */
|
|
{ 228, 25, 92 }, /* H.263 (based on MPEG-2) */
|
|
{ 0, 0, 0 }, /* JPEG */
|
|
{ 240, 29, 112 }, /* VC-1 */
|
|
{ 302, 25, 92 }, /* MPEG-2 */
|
|
{ 228, 25, 92 }, /* MPEG-1 */
|
|
{ 240, 29, 112 }, /* AVS (based on VC-1) */
|
|
{ 240, 29, 112 }, /* VP6 (based on VC-1) */
|
|
{ 240, 29, 112 }, /* RVx (based on VC-1) */
|
|
{ 240, 29, 112 }, /* VP7 (based on VC-1) */
|
|
{ 240, 29, 112 }, /* VP8 (based on VC-1) */
|
|
{ 240, 29, 112 } /* AVS (based on VC-1) */
|
|
};
|
|
|
|
static const i32 mbDataPerFormat[][2] = {
|
|
{ 734, 880 }, /* H.264 (upped 20%) */
|
|
{ 464, 535 }, /* MPEG-4 */
|
|
{ 435, 486 }, /* H.263 (same as MPEG-2 used) */
|
|
{ 0, 0 }, /* JPEG */
|
|
{ 533, 644 }, /* VC-1 */
|
|
{ 435, 486 }, /* MPEG-2 */
|
|
{ 435, 486 }, /* MPEG-1 */
|
|
{ 533, 486 }, /* AVS (based now on VC-1) */
|
|
{ 533, 486 }, /* VP6 (based now on VC-1) */
|
|
{ 533, 486 }, /* RVx (based on VC-1) */
|
|
{ 533, 486 }, /* VP7 (based now on VC-1) */
|
|
{ 533, 486 }, /* VP8 (based now on VC-1) */
|
|
{ 533, 486 } /* AVS (based now on VC-1) */
|
|
};
|
|
|
|
|
|
static u32 GetSettings( refBuffer_t *pRefbu, i32 *pX, i32 *pY, u32 isBpic,
|
|
u32 isFieldPic );
|
|
static void IntraFrame( refBuffer_t *pRefbu );
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : UpdateMemModel
|
|
Description : Update memory model for reference buffer
|
|
|
|
Return type :
|
|
Argument :
|
|
------------------------------------------------------------------------------*/
|
|
void UpdateMemModel( refBuffer_t *pRefbu )
|
|
{
|
|
|
|
/* Variables */
|
|
|
|
i32 widthInMbs;
|
|
i32 heightInMbs;
|
|
i32 latency;
|
|
i32 nonseq;
|
|
i32 seq;
|
|
|
|
i32 busWidth;
|
|
i32 tmp, tmp2;
|
|
|
|
/* Code */
|
|
|
|
#define DIV_CEIL(a,b) (((a)+(b)-1)/(b))
|
|
|
|
widthInMbs = pRefbu->picWidthInMbs;
|
|
heightInMbs = pRefbu->picHeightInMbs;
|
|
busWidth = pRefbu->busWidthInBits;
|
|
|
|
tmp = busWidth >> 2; /* initially buffered mbs per row */
|
|
tmp2 = busWidth >> 3; /* n:o of mbs buffered at refresh */
|
|
tmp = ( 1 + DIV_CEIL(widthInMbs - tmp, tmp2 ) ); /* latencies per mb row */
|
|
tmp2 = 24 * heightInMbs; /* Number of rows to buffer in total */
|
|
/* Latencies per frame */
|
|
latency = 2 * tmp * heightInMbs;
|
|
nonseq = tmp2 * tmp;
|
|
seq = ( DIV_CEIL( 16*widthInMbs, busWidth>>3 ) ) * tmp2 -
|
|
nonseq;
|
|
|
|
pRefbu->numCyclesForBuffering =
|
|
latency * pRefbu->currMemModel.latency +
|
|
nonseq * ( 1 + pRefbu->currMemModel.nonseq ) +
|
|
seq * ( 1 + pRefbu->currMemModel.seq );
|
|
|
|
pRefbu->bufferPenalty =
|
|
pRefbu->memAccessStats.nonseq +
|
|
pRefbu->memAccessStats.seq;
|
|
if( busWidth == 32 )
|
|
pRefbu->bufferPenalty >>= 1;
|
|
|
|
pRefbu->avgCyclesPerMb =
|
|
( ( pRefbu->memAccessStats.latency * pRefbu->currMemModel.latency ) / 100 ) +
|
|
pRefbu->memAccessStats.nonseq * ( 1 + pRefbu->currMemModel.nonseq ) +
|
|
pRefbu->memAccessStats.seq * ( 1 + pRefbu->currMemModel.seq );
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
printf("***** ref buffer mem model trace *****\n");
|
|
printf("latency = %7d clk\n", pRefbu->currMemModel.latency );
|
|
printf("sequential = %7d clk\n", pRefbu->currMemModel.nonseq );
|
|
printf("non-sequential = %7d clk\n", pRefbu->currMemModel.seq );
|
|
|
|
printf("latency (mb) = %7d\n", pRefbu->memAccessStats.latency );
|
|
printf("sequential (mb) = %7d\n", pRefbu->memAccessStats.nonseq );
|
|
printf("non-sequential (mb) = %7d\n", pRefbu->memAccessStats.seq );
|
|
|
|
printf("bus-width = %7d\n", busWidth );
|
|
|
|
printf("buffering cycles = %7d\n", pRefbu->numCyclesForBuffering );
|
|
printf("buffer penalty = %7d\n", pRefbu->bufferPenalty );
|
|
printf("avg cycles per mb = %7d\n", pRefbu->avgCyclesPerMb );
|
|
|
|
printf("***** ref buffer mem model trace *****\n");
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
#undef DIV_CEIL
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : IntraFrame
|
|
Description : Clear history buffers on intra frames
|
|
|
|
Return type :
|
|
Argument :
|
|
------------------------------------------------------------------------------*/
|
|
void IntraFrame( refBuffer_t *pRefbu )
|
|
{
|
|
pRefbu->oy[0] = pRefbu->oy[1] = pRefbu->oy[2] = 0;
|
|
pRefbu->numIntraBlk[0] =
|
|
pRefbu->numIntraBlk[1] = pRefbu->numIntraBlk[2] = (-1);
|
|
pRefbu->coverage[0] = /*4 * tmp;*/
|
|
pRefbu->coverage[1] =
|
|
pRefbu->coverage[2] = (-1); /* initial value */
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : RefbuGetHitThreshold
|
|
Description :
|
|
|
|
Return type :
|
|
Argument :
|
|
------------------------------------------------------------------------------*/
|
|
i32 RefbuGetHitThreshold( refBuffer_t *pRefbu )
|
|
{
|
|
|
|
i32 requiredHitsClk = 0;
|
|
i32 requiredHitsData = 0;
|
|
i32 divisor;
|
|
i32 tmp;
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
i32 predMiss;
|
|
printf("***** ref buffer threshold trace *****\n");
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
divisor = pRefbu->avgCyclesPerMb - pRefbu->bufferPenalty;
|
|
|
|
if( divisor > 0 )
|
|
requiredHitsClk = ( 4 * pRefbu->numCyclesForBuffering ) / divisor;
|
|
|
|
divisor = pRefbu->mbWeight;
|
|
#ifdef REFBUFFER_TRACE
|
|
printf("mb weight = %7d\n", divisor );
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
if( divisor > 0)
|
|
{
|
|
|
|
divisor = ( divisor * pRefbu->dataExcessMaxPct ) / 100;
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
predMiss = 4 * pRefbu->frmSizeInMbs - pRefbu->predIntraBlk -
|
|
pRefbu->predCoverage;
|
|
printf("predicted misses = %7d\n", predMiss );
|
|
printf("data excess %% = %7d\n", pRefbu->dataExcessMaxPct );
|
|
printf("divisor = %7d\n", divisor );
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
/*tmp = (( DATA_EXCESS_MAX_PCT - 100 ) * pRefbu->mbWeight * predMiss ) / 400;*/
|
|
tmp = 0;
|
|
requiredHitsData = ( 4 * pRefbu->totalDataForBuffering - tmp);
|
|
requiredHitsData /= divisor;
|
|
}
|
|
|
|
if(pRefbu->picHeightInMbs)
|
|
{
|
|
requiredHitsClk /= pRefbu->picHeightInMbs;
|
|
requiredHitsData /= pRefbu->picHeightInMbs;
|
|
}
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
printf("target (clk) = %7d\n", requiredHitsClk );
|
|
printf("target (data) = %7d\n", requiredHitsData );
|
|
printf("***** ref buffer threshold trace *****\n");
|
|
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
return requiredHitsClk > requiredHitsData ?
|
|
requiredHitsClk : requiredHitsData;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : InitMemAccess
|
|
Description :
|
|
|
|
Return type :
|
|
Argument :
|
|
------------------------------------------------------------------------------*/
|
|
void InitMemAccess( refBuffer_t *pRefbu, u32 decMode, u32 busWidth )
|
|
{
|
|
/* Initialize stream format memory model */
|
|
pRefbu->memAccessStats = memStatsPerFormat[decMode];
|
|
pRefbu->memAccessStatsFlag = 0;
|
|
if( busWidth == 64 )
|
|
{
|
|
pRefbu->memAccessStats.seq >>= 1;
|
|
pRefbu->mbWeight = mbDataPerFormat[decMode][1];
|
|
}
|
|
else
|
|
{
|
|
pRefbu->mbWeight = mbDataPerFormat[decMode][0];
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : RefbuInit
|
|
Description :
|
|
|
|
Return type :
|
|
Argument :
|
|
------------------------------------------------------------------------------*/
|
|
void RefbuInit( refBuffer_t *pRefbu, u32 decMode, u32 picWidthInMbs,
|
|
u32 picHeightInMbs, u32 supportFlags )
|
|
{
|
|
|
|
/* Variables */
|
|
|
|
u32 tmp;
|
|
u32 i;
|
|
|
|
/* Code */
|
|
|
|
/* Ignore init's if image size doesn't change. For example H264 SW may
|
|
* call here when moving to RLC mode. */
|
|
if( pRefbu->picWidthInMbs == picWidthInMbs &&
|
|
pRefbu->picHeightInMbs == picHeightInMbs )
|
|
{
|
|
return;
|
|
}
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
printf("***** ref buffer initialized to %dx%d *****\n",
|
|
picWidthInMbs, picHeightInMbs);
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
pRefbu->decMode = decMode;
|
|
pRefbu->picWidthInMbs = picWidthInMbs;
|
|
pRefbu->picHeightInMbs = picHeightInMbs;
|
|
tmp = picWidthInMbs * picHeightInMbs;
|
|
pRefbu->frmSizeInMbs = tmp;
|
|
|
|
pRefbu->totalDataForBuffering
|
|
= pRefbu->frmSizeInMbs*384;
|
|
tmp = picWidthInMbs * ((picHeightInMbs + 1) / 2);
|
|
pRefbu->fldSizeInMbs = tmp;
|
|
|
|
pRefbu->offsetSupport = (supportFlags & REFBU_SUPPORT_OFFSET) ? 1 : 0;
|
|
pRefbu->interlacedSupport = (supportFlags & REFBU_SUPPORT_INTERLACED) ? 1 : 0;
|
|
pRefbu->doubleSupport = (supportFlags & REFBU_SUPPORT_DOUBLE) ? 1 : 0;
|
|
pRefbu->thrAdj = THR_ADJ_MAX;
|
|
pRefbu->dataExcessMaxPct = DEC_X170_REFBU_ADJUST_VALUE;
|
|
|
|
pRefbu->predCoverage = pRefbu->predIntraBlk = 0;
|
|
IntraFrame( pRefbu );
|
|
if( decMode == DEC_X170_MODE_H264 )
|
|
{
|
|
pRefbu->mvsPerMb = 16;
|
|
pRefbu->filterSize = 3;
|
|
}
|
|
else if ( decMode == DEC_X170_MODE_VC1 )
|
|
{
|
|
pRefbu->mvsPerMb = 2;
|
|
pRefbu->filterSize = 2;
|
|
}
|
|
else
|
|
{
|
|
pRefbu->mvsPerMb = 1;
|
|
pRefbu->filterSize = 1;
|
|
}
|
|
|
|
/* Initialize buffer memory model */
|
|
pRefbu->busWidthInBits = DEC_X170_REFBU_WIDTH;
|
|
pRefbu->currMemModel.latency = DEC_X170_REFBU_LATENCY;
|
|
pRefbu->currMemModel.nonseq = DEC_X170_REFBU_NONSEQ;
|
|
pRefbu->currMemModel.seq = DEC_X170_REFBU_SEQ;
|
|
pRefbu->prevLatency = -1;
|
|
pRefbu->numCyclesForBuffering = 0;
|
|
|
|
for ( i = 0 ; i < 3 ; ++i )
|
|
{
|
|
pRefbu->fldHitsP[i][0] =
|
|
pRefbu->fldHitsP[i][1] =
|
|
pRefbu->fldHitsB[i][0] =
|
|
pRefbu->fldHitsB[i][1] = -1;
|
|
}
|
|
pRefbu->fldCnt = 0;
|
|
|
|
/* Initialize stream format memory model */
|
|
InitMemAccess( pRefbu, decMode, DEC_X170_REFBU_WIDTH );
|
|
|
|
pRefbu->decModeMbWeights[0] = mbDataPerFormat[decMode][0];
|
|
pRefbu->decModeMbWeights[1] = mbDataPerFormat[decMode][1];
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : GetSettings
|
|
Description : Determine whether or not to enable buffer, and calculate
|
|
buffer offset.
|
|
|
|
Return type : u32
|
|
Argument :
|
|
------------------------------------------------------------------------------*/
|
|
u32 GetSettings( refBuffer_t *pRefbu, i32 *pX, i32 *pY, u32 isBpic,
|
|
u32 isFieldPic)
|
|
{
|
|
|
|
/* Variables */
|
|
|
|
i32 tmp;
|
|
u32 enable = HANTRO_TRUE;
|
|
u32 frmSizeInMbs;
|
|
i32 cov;
|
|
i32 sign;
|
|
i32 numCyclesForBuffering;
|
|
|
|
/* Code */
|
|
|
|
frmSizeInMbs = pRefbu->frmSizeInMbs;
|
|
*pX = 0;
|
|
*pY = 0;
|
|
|
|
/* Disable automatically for pictures less than 16MB wide */
|
|
if( pRefbu->picWidthInMbs <= 16 )
|
|
{
|
|
return HANTRO_FALSE;
|
|
}
|
|
|
|
numCyclesForBuffering = pRefbu->numCyclesForBuffering;
|
|
if(isFieldPic)
|
|
numCyclesForBuffering /= 2;
|
|
|
|
if( pRefbu->prevUsedDouble )
|
|
{
|
|
cov = pRefbu->coverage[0];
|
|
tmp = pRefbu->avgCyclesPerMb * cov / 4;
|
|
|
|
/* Check whether it is viable to enable buffering */
|
|
tmp = (2*numCyclesForBuffering < tmp);
|
|
if( !tmp )
|
|
{
|
|
pRefbu->thrAdj -= 2;
|
|
if ( pRefbu->thrAdj < THR_ADJ_MIN )
|
|
pRefbu->thrAdj = THR_ADJ_MIN;
|
|
}
|
|
else
|
|
{
|
|
pRefbu->thrAdj++;
|
|
if ( pRefbu->thrAdj > THR_ADJ_MAX )
|
|
pRefbu->thrAdj = THR_ADJ_MAX;
|
|
}
|
|
}
|
|
|
|
if( !isBpic )
|
|
{
|
|
if( pRefbu->coverage[1] != -1 )
|
|
{
|
|
cov = (5*pRefbu->coverage[0] - 1*pRefbu->coverage[1])/4;
|
|
if( pRefbu->coverage[2] != -1 )
|
|
{
|
|
cov = cov + ( pRefbu->coverage[0] + pRefbu->coverage[1] + pRefbu->coverage[2] ) / 3;
|
|
cov /= 2;
|
|
}
|
|
|
|
}
|
|
else if ( pRefbu->coverage[0] != -1 )
|
|
{
|
|
cov = pRefbu->coverage[0];
|
|
}
|
|
else
|
|
{
|
|
cov = 4*frmSizeInMbs;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cov = pRefbu->coverage[0];
|
|
if( cov == -1 )
|
|
{
|
|
cov = 4*frmSizeInMbs;
|
|
}
|
|
/* MPEG-4 B-frames have no intra coding possibility, so extrapolate
|
|
* hit rate to match it */
|
|
else if( pRefbu->predIntraBlk < 4*frmSizeInMbs &&
|
|
pRefbu->decMode == DEC_X170_MODE_MPEG4 )
|
|
{
|
|
cov *= (128*4*frmSizeInMbs) / (4*frmSizeInMbs-pRefbu->predIntraBlk) ;
|
|
cov /= 128;
|
|
}
|
|
/* Assume that other formats have less intra MBs in B pictures */
|
|
else
|
|
{
|
|
cov *= (128*4*frmSizeInMbs) / (4*frmSizeInMbs-pRefbu->predIntraBlk/2) ;
|
|
cov /= 128;
|
|
}
|
|
}
|
|
if( cov < 0 ) cov = 0;
|
|
pRefbu->predCoverage = cov;
|
|
|
|
/* Check whether it is viable to enable buffering */
|
|
/* 1.criteria = cycles */
|
|
tmp = pRefbu->avgCyclesPerMb * cov / 4;
|
|
numCyclesForBuffering += pRefbu->bufferPenalty * cov / 4;
|
|
enable = (numCyclesForBuffering < tmp);
|
|
/* 2.criteria = data */
|
|
/*
|
|
tmp = ( DATA_EXCESS_MAX_PCT * cov ) / 400;
|
|
tmp = tmp * pRefbu->mbWeight;
|
|
enable = enable && (pRefbu->totalDataForBuffering < tmp);
|
|
*/
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
printf("***** ref buffer algorithm trace *****\n");
|
|
printf("predicted coverage = %7d\n", cov );
|
|
printf("bus width in calc = %7d\n", pRefbu->busWidthInBits );
|
|
printf("coverage history = %7d%7d%7d\n",
|
|
pRefbu->coverage[0],
|
|
pRefbu->coverage[1],
|
|
pRefbu->coverage[2] );
|
|
printf("enable = %d (%8d<%8d)\n", enable, numCyclesForBuffering, tmp );
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
/* If still enabled, calculate offsets */
|
|
if( enable )
|
|
{
|
|
/* Round to nearest 16 multiple */
|
|
tmp = (pRefbu->oy[0] + pRefbu->oy[1] + 1)/2;
|
|
sign = ( tmp < 0 );
|
|
if( pRefbu->prevWasField )
|
|
tmp /= 2;
|
|
tmp = ABS(tmp);
|
|
tmp = tmp & ~15;
|
|
if( sign ) tmp = -tmp;
|
|
*pY = tmp;
|
|
}
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
printf("offset_x = %7d\n", *pX );
|
|
printf("offset_y = %7d (%d %d)\n", *pY, pRefbu->oy[0], pRefbu->oy[1] );
|
|
printf("***** ref buffer algorithm trace *****\n");
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
|
|
return enable;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : BuildDistribution
|
|
Description :
|
|
|
|
Return type :
|
|
Argument :
|
|
------------------------------------------------------------------------------*/
|
|
void BuildDistribution( u32 *pDistrVer,
|
|
u32 *pMv, i32 frmSizeInMbs,
|
|
u32 mvsPerMb,
|
|
u32 bigEndian,
|
|
i32 *minY, i32 *maxY )
|
|
{
|
|
|
|
/* Variables */
|
|
|
|
i32 mb;
|
|
i32 ver;
|
|
u8 * pMvTmp;
|
|
u32 mvs;
|
|
u32 skipMv = mvsPerMb*4;
|
|
u32 multiplier = 4;
|
|
u32 div = 2;
|
|
|
|
/* Code */
|
|
|
|
mvs = frmSizeInMbs;
|
|
/* Try to keep total n:o of mvs checked under MAX_DIRECT_MVS */
|
|
if( mvs > MAX_DIRECT_MVS )
|
|
{
|
|
while( mvs/div > MAX_DIRECT_MVS )
|
|
div++;
|
|
|
|
mvs /= div;
|
|
skipMv *= div;
|
|
multiplier *= div;
|
|
}
|
|
|
|
pMvTmp = (u8*)pMv;
|
|
if( bigEndian )
|
|
{
|
|
for( mb = 0 ; mb < mvs ; ++mb )
|
|
{
|
|
{
|
|
ver = DIR_MV_BE_VER(pMvTmp);
|
|
SIGN_EXTEND(ver, 13);
|
|
/* Cut fraction and saturate */
|
|
/*lint -save -e702 */
|
|
ver >>= 2;
|
|
/*lint -restore */
|
|
if( ver >= VER_DISTR_MIN && ver <= VER_DISTR_MAX )
|
|
{
|
|
pDistrVer[ver] += multiplier;
|
|
if( ver < *minY ) *minY = ver;
|
|
if( ver > *maxY ) *maxY = ver;
|
|
}
|
|
}
|
|
pMvTmp += skipMv; /* Skip all other blocks for macroblock */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( mb = 0 ; mb < mvs ; ++mb )
|
|
{
|
|
{
|
|
ver = DIR_MV_LE_VER(pMvTmp);
|
|
SIGN_EXTEND(ver, 13);
|
|
/* Cut fraction and saturate */
|
|
/*lint -save -e702 */
|
|
ver >>= 2;
|
|
/*lint -restore */
|
|
if( ver >= VER_DISTR_MIN && ver <= VER_DISTR_MAX )
|
|
{
|
|
pDistrVer[ver] += multiplier;
|
|
if( ver < *minY ) *minY = ver;
|
|
if( ver > *maxY ) *maxY = ver;
|
|
}
|
|
}
|
|
pMvTmp += skipMv; /* Skip all other blocks for macroblock */
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : DirectMvStatistics
|
|
Description :
|
|
|
|
Return type :
|
|
Argument :
|
|
------------------------------------------------------------------------------*/
|
|
void DirectMvStatistics( refBuffer_t *pRefbu, u32 *pMv, i32 numIntraBlk,
|
|
u32 bigEndian )
|
|
{
|
|
|
|
/* Variables */
|
|
|
|
i32 * pTmp;
|
|
i32 frmSizeInMbs;
|
|
i32 i;
|
|
i32 oy = 0;
|
|
i32 best = 0;
|
|
i32 sum;
|
|
i32 mvsPerMb;
|
|
i32 minY = VER_DISTR_MAX, maxY = VER_DISTR_MIN;
|
|
|
|
/* Mv distributions per component*/
|
|
u32 distrVer[VER_DISTR_RANGE] = { 0 };
|
|
u32 *pDistrVer = distrVer + VER_DISTR_ZERO_POINT;
|
|
|
|
/* Code */
|
|
|
|
mvsPerMb = pRefbu->mvsPerMb;
|
|
|
|
if( pRefbu->prevWasField )
|
|
frmSizeInMbs = pRefbu->fldSizeInMbs;
|
|
else
|
|
frmSizeInMbs = pRefbu->frmSizeInMbs;
|
|
|
|
if( numIntraBlk < 4*frmSizeInMbs )
|
|
{
|
|
BuildDistribution( pDistrVer,
|
|
pMv,
|
|
frmSizeInMbs,
|
|
mvsPerMb,
|
|
bigEndian,
|
|
&minY, &maxY );
|
|
|
|
/* Fix Intra occurences */
|
|
pDistrVer[0] -= numIntraBlk;
|
|
|
|
#if 0 /* Use median for MV calculation */
|
|
/* Find median */
|
|
{
|
|
tmp = (frmSizeInMbs - numIntraMbs) / 2;
|
|
sum = 0;
|
|
i = VER_DISTR_MIN;
|
|
for( i = VER_DISTR_MIN ; sum < tmp ; i++ )
|
|
sum += pDistrVer[i];
|
|
oy = i-1;
|
|
|
|
/* Calculate coverage percent */
|
|
best = 0;
|
|
i = MAX( VER_DISTR_MIN, oy-VER_MV_RANGE );
|
|
limit = MIN( VER_DISTR_MAX, oy+VER_MV_RANGE );
|
|
for( ; i < limit ; ++i )
|
|
best += pDistrVer[i];
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
i32 y;
|
|
i32 penalty;
|
|
|
|
/* Initial sum */
|
|
sum = 0;
|
|
minY += VER_DISTR_ZERO_POINT;
|
|
maxY += VER_DISTR_ZERO_POINT;
|
|
|
|
for( i = 0 ; i < 2*VER_MV_RANGE ; ++i )
|
|
{
|
|
sum += distrVer[i];
|
|
}
|
|
best = 0;
|
|
/* Other sums */
|
|
maxY -= 2*VER_MV_RANGE;
|
|
for( i = 0 ; i < VER_DISTR_RANGE-2*VER_MV_RANGE-1 ; ++i )
|
|
{
|
|
sum -= distrVer[i];
|
|
sum += distrVer[2*VER_MV_RANGE+i];
|
|
y = VER_DISTR_MIN+VER_MV_RANGE+i+1;
|
|
if ( ABS(y) > 8 )
|
|
{
|
|
penalty = ABS(y)-8;
|
|
penalty = (frmSizeInMbs*penalty)/16;
|
|
}
|
|
else
|
|
{
|
|
penalty = 0;
|
|
}
|
|
/*if( (ABS(y) & 15) == 0 )*/
|
|
{
|
|
if( sum - penalty > best )
|
|
{
|
|
best = sum - penalty;
|
|
oy = y;
|
|
}
|
|
else if ( sum - penalty == best )
|
|
{
|
|
if( ABS(y) < ABS(oy) ) oy = y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pRefbu->prevWasField)
|
|
best *= 2;
|
|
pRefbu->coverage[0] = best;
|
|
|
|
/* Store updated offsets */
|
|
pTmp = pRefbu->oy;
|
|
pTmp[2] = pTmp[1];
|
|
pTmp[1] = pTmp[0];
|
|
pTmp[0] = oy;
|
|
|
|
}
|
|
else
|
|
{
|
|
pTmp = pRefbu->oy;
|
|
pTmp[2] = pTmp[1];
|
|
pTmp[1] = pTmp[0];
|
|
pTmp[0] = 0;
|
|
}
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : RefbuMvStatisticsB
|
|
Description :
|
|
|
|
Return type :
|
|
Argument :
|
|
------------------------------------------------------------------------------*/
|
|
void RefbuMvStatisticsB( refBuffer_t *pRefbu, u32 *regBase )
|
|
{
|
|
|
|
/* Variables */
|
|
|
|
i32 topFldCnt;
|
|
i32 botFldCnt;
|
|
|
|
/* Code */
|
|
|
|
topFldCnt = GetDecRegister( regBase, HWIF_REFBU_TOP_SUM );
|
|
botFldCnt = GetDecRegister( regBase, HWIF_REFBU_BOT_SUM );
|
|
|
|
if( pRefbu->fldCnt >= 2 &&
|
|
GetDecRegister( regBase, HWIF_FIELDPIC_FLAG_E ) &&
|
|
(topFldCnt || botFldCnt))
|
|
{
|
|
pRefbu->fldHitsB[2][0] = pRefbu->fldHitsB[1][0]; pRefbu->fldHitsB[2][1] = pRefbu->fldHitsB[1][1];
|
|
pRefbu->fldHitsB[1][0] = pRefbu->fldHitsB[0][0]; pRefbu->fldHitsB[1][1] = pRefbu->fldHitsB[0][1];
|
|
if( GetDecRegister( regBase, HWIF_PIC_TOPFIELD_E ) ) {
|
|
pRefbu->fldHitsB[0][0] = topFldCnt; pRefbu->fldHitsB[0][1] = botFldCnt;
|
|
} else {
|
|
pRefbu->fldHitsB[0][0] = botFldCnt; pRefbu->fldHitsB[0][1] = topFldCnt;
|
|
}
|
|
}
|
|
if( GetDecRegister( regBase, HWIF_FIELDPIC_FLAG_E ) )
|
|
pRefbu->fldCnt++;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : RefbuMvStatistics
|
|
Description :
|
|
|
|
Return type :
|
|
Argument :
|
|
------------------------------------------------------------------------------*/
|
|
void RefbuMvStatistics( refBuffer_t *pRefbu, u32 *regBase,
|
|
u32 *pMv, u32 directMvsAvailable, u32 isIntraPicture )
|
|
{
|
|
|
|
/* Variables */
|
|
|
|
i32 * pTmp;
|
|
i32 tmp;
|
|
i32 numIntraBlk;
|
|
i32 topFldCnt;
|
|
i32 botFldCnt;
|
|
u32 bigEndian;
|
|
|
|
/* Code */
|
|
|
|
if( isIntraPicture )
|
|
{
|
|
/*IntraFrame( pRefbu );*/
|
|
return; /* Clear buffers etc. ? */
|
|
}
|
|
|
|
if(pRefbu->prevWasField && !pRefbu->interlacedSupport)
|
|
return;
|
|
|
|
#ifdef ASIC_TRACE_SUPPORT
|
|
/* big endian */
|
|
bigEndian = 1;
|
|
#else
|
|
/* Determine HW endianness; this affects how we read motion vector
|
|
* map from HW. Map endianness is same as decoder output endianness */
|
|
if( GetDecRegister( regBase, HWIF_DEC_OUT_ENDIAN ) == 0 )
|
|
{
|
|
/* big endian */
|
|
bigEndian = 1;
|
|
}
|
|
else
|
|
{
|
|
/* little endian */
|
|
bigEndian = 0;
|
|
}
|
|
#endif
|
|
|
|
if(!pRefbu->offsetSupport || 1) /* Note: offset always disabled for now,
|
|
* so always disallow direct mv data */
|
|
{
|
|
directMvsAvailable = 0;
|
|
}
|
|
|
|
numIntraBlk = GetDecRegister( regBase, HWIF_REFBU_INTRA_SUM );
|
|
topFldCnt = GetDecRegister( regBase, HWIF_REFBU_TOP_SUM );
|
|
botFldCnt = GetDecRegister( regBase, HWIF_REFBU_BOT_SUM );
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
printf("***** ref buffer mv statistics trace *****\n");
|
|
printf("intra blocks = %7d\n", numIntraBlk );
|
|
printf("top fields = %7d\n", topFldCnt );
|
|
printf("bottom fields = %7d\n", botFldCnt );
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
if( pRefbu->fldCnt > 0 &&
|
|
GetDecRegister( regBase, HWIF_FIELDPIC_FLAG_E ) &&
|
|
(topFldCnt || botFldCnt))
|
|
{
|
|
pRefbu->fldHitsP[2][0] = pRefbu->fldHitsP[1][0]; pRefbu->fldHitsP[2][1] = pRefbu->fldHitsP[1][1];
|
|
pRefbu->fldHitsP[1][0] = pRefbu->fldHitsP[0][0]; pRefbu->fldHitsP[1][1] = pRefbu->fldHitsP[0][1];
|
|
if( GetDecRegister( regBase, HWIF_PIC_TOPFIELD_E ) ) {
|
|
pRefbu->fldHitsP[0][0] = topFldCnt; pRefbu->fldHitsP[0][1] = botFldCnt;
|
|
} else {
|
|
pRefbu->fldHitsP[0][0] = botFldCnt; pRefbu->fldHitsP[0][1] = topFldCnt;
|
|
}
|
|
}
|
|
if( GetDecRegister( regBase, HWIF_FIELDPIC_FLAG_E ) )
|
|
pRefbu->fldCnt++;
|
|
|
|
pRefbu->coverage[2] = pRefbu->coverage[1];
|
|
pRefbu->coverage[1] = pRefbu->coverage[0];
|
|
if(directMvsAvailable)
|
|
{
|
|
DirectMvStatistics( pRefbu, pMv, numIntraBlk, bigEndian );
|
|
}
|
|
else if(pRefbu->offsetSupport)
|
|
{
|
|
i32 interMvs;
|
|
i32 sum;
|
|
sum = GetDecRegister( regBase, HWIF_REFBU_Y_MV_SUM );
|
|
SIGN_EXTEND( sum, 22 );
|
|
interMvs = (4*pRefbu->frmSizeInMbs - numIntraBlk)/4;
|
|
if( pRefbu->prevWasField )
|
|
interMvs *= 2;
|
|
if( interMvs == 0 )
|
|
interMvs = 1;
|
|
/* Require at least 50% mvs present to calculate reliable avg offset */
|
|
if( interMvs * 50 >= pRefbu->frmSizeInMbs )
|
|
{
|
|
/* Store updated offsets */
|
|
pTmp = pRefbu->oy;
|
|
pTmp[2] = pTmp[1];
|
|
pTmp[1] = pTmp[0];
|
|
pTmp[0] = sum/interMvs;
|
|
}
|
|
}
|
|
|
|
/* Read buffer hits from previous frame. If number of hits < threshold
|
|
* for the frame, then we know that HW switched buffering off. */
|
|
tmp = GetDecRegister( regBase, HWIF_REFBU_HIT_SUM );
|
|
pRefbu->prevFrameHitSum = tmp;
|
|
if ( tmp >= pRefbu->checkpoint && pRefbu->checkpoint )
|
|
{
|
|
if(pRefbu->prevWasField)
|
|
tmp *= 2;
|
|
pRefbu->coverage[0] = tmp;
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
printf("actual coverage = %7d\n", tmp );
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
}
|
|
else if(!directMvsAvailable)
|
|
{
|
|
/* Buffering was disabled for previous frame, no direct mv
|
|
* data available either, so assume we got a bit more hits than
|
|
* the frame before that */
|
|
if( pRefbu->coverage[1] != -1 )
|
|
{
|
|
pRefbu->coverage[0] = ( 4 *
|
|
pRefbu->picWidthInMbs *
|
|
pRefbu->picHeightInMbs + 5 * pRefbu->coverage[1] ) / 6;
|
|
}
|
|
else
|
|
pRefbu->coverage[0] = pRefbu->frmSizeInMbs * 4;
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
printf("calculated coverage = %7d\n", pRefbu->coverage[0] );
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
printf("estimated coverage = %7d\n", pRefbu->coverage[0] );
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
}
|
|
|
|
/* Store intra counts for rate prediction */
|
|
pTmp = pRefbu->numIntraBlk;
|
|
pTmp[2] = pTmp[1];
|
|
pTmp[1] = pTmp[0];
|
|
pTmp[0] = numIntraBlk;
|
|
|
|
/* Predict number of intra mbs for next frame */
|
|
if(pTmp[2] != -1) tmp = (pTmp[0] + pTmp[1] + pTmp[2])/3;
|
|
else if( pTmp[1] != -1 ) tmp = (pTmp[0] + pTmp[1])/2;
|
|
else tmp = pTmp[0];
|
|
pRefbu->predIntraBlk = MIN( pTmp[0], tmp );
|
|
|
|
#ifdef REFBUFFER_TRACE
|
|
printf("predicted intra blk = %7d\n", pRefbu->predIntraBlk );
|
|
printf("***** ref buffer mv statistics trace *****\n");
|
|
#endif /* REFBUFFER_TRACE */
|
|
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : DecideParityMode
|
|
Description : Setup reference buffer for next frame.
|
|
|
|
Return type :
|
|
Argument : pRefbu Reference buffer descriptor
|
|
isBframe Is frame B-coded
|
|
------------------------------------------------------------------------------*/
|
|
u32 DecideParityMode( refBuffer_t *pRefbu, u32 isBframe )
|
|
{
|
|
|
|
/* Variables */
|
|
|
|
i32 same, opp;
|
|
|
|
/* Code */
|
|
|
|
if( pRefbu->decMode != DEC_X170_MODE_H264 )
|
|
{
|
|
/* Don't use parity mode for other formats than H264
|
|
* for now */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Read history */
|
|
if( isBframe )
|
|
{
|
|
same = pRefbu->fldHitsB[0][0];
|
|
/*
|
|
if( pRefbu->fldHitsB[1][0] >= 0 )
|
|
same += pRefbu->fldHitsB[1][0];
|
|
if( pRefbu->fldHitsB[2][0] >= 0 )
|
|
same += pRefbu->fldHitsB[2][0];
|
|
*/
|
|
opp = pRefbu->fldHitsB[0][1];
|
|
/*
|
|
if( pRefbu->fldHitsB[1][1] >= 0 )
|
|
opp += pRefbu->fldHitsB[1][1];
|
|
if( pRefbu->fldHitsB[2][0] >= 0 )
|
|
opp += pRefbu->fldHitsB[2][1];*/
|
|
}
|
|
else
|
|
{
|
|
same = pRefbu->fldHitsP[0][0];
|
|
/*
|
|
if( pRefbu->fldHitsP[1][0] >= 0 )
|
|
same += pRefbu->fldHitsP[1][0];
|
|
if( pRefbu->fldHitsP[2][0] >= 0 )
|
|
same += pRefbu->fldHitsP[2][0];
|
|
*/
|
|
opp = pRefbu->fldHitsP[0][1];
|
|
/*
|
|
if( pRefbu->fldHitsP[1][1] >= 0 )
|
|
opp += pRefbu->fldHitsP[1][1];
|
|
if( pRefbu->fldHitsP[2][0] >= 0 )
|
|
opp += pRefbu->fldHitsP[2][1];
|
|
*/
|
|
}
|
|
|
|
/* If not enough data yet, bail out */
|
|
if( same == -1 || opp == -1 )
|
|
return 0;
|
|
|
|
if( opp*2 <= same )
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : RefbuSetup
|
|
Description : Setup reference buffer for next frame.
|
|
|
|
Return type :
|
|
Argument : pRefbu Reference buffer descriptor
|
|
regBase Pointer to SW/HW control registers
|
|
isInterlacedField
|
|
isIntraFrame Is frame intra-coded (or IDR for H.264)
|
|
isBframe Is frame B-coded
|
|
refPicId pic_id for reference picture, if
|
|
applicable. For H.264 pic_id for
|
|
nearest reference picture of L0.
|
|
------------------------------------------------------------------------------*/
|
|
void RefbuSetup( refBuffer_t *pRefbu, u32 *regBase,
|
|
refbuMode_e mode,
|
|
u32 isIntraFrame,
|
|
u32 isBframe,
|
|
u32 refPicId0, u32 refPicId1, u32 flags )
|
|
{
|
|
|
|
/* Variables */
|
|
|
|
i32 ox, oy;
|
|
i32 enable;
|
|
i32 tmp;
|
|
i32 thr2 = 0;
|
|
u32 featureDisable = 0;
|
|
u32 useAdaptiveMode = 0;
|
|
u32 useDoubleMode = 0;
|
|
u32 disableCheckpoint = 0;
|
|
u32 multipleRefFrames = 1;
|
|
u32 multipleRefFields = 1;
|
|
u32 forceAdaptiveSingle = 1;
|
|
u32 singleRefField = 0;
|
|
u32 pic0 = 0, pic1 = 0;
|
|
|
|
/* Code */
|
|
|
|
SetDecRegister(regBase, HWIF_REFBU_THR, 0 );
|
|
SetDecRegister(regBase, HWIF_REFBU2_THR, 0 );
|
|
SetDecRegister(regBase, HWIF_REFBU_PICID, 0 );
|
|
SetDecRegister(regBase, HWIF_REFBU_Y_OFFSET, 0 );
|
|
|
|
multipleRefFrames = ( flags & REFBU_MULTIPLE_REF_FRAMES ) ? 1 : 0;
|
|
disableCheckpoint = ( flags & REFBU_DISABLE_CHECKPOINT ) ? 1 : 0;
|
|
forceAdaptiveSingle = ( flags & REFBU_FORCE_ADAPTIVE_SINGLE ) ? 1 : 0;
|
|
|
|
pRefbu->prevWasField = (mode == REFBU_FIELD && !isBframe);
|
|
|
|
/* Check supported features */
|
|
if(mode != REFBU_FRAME && !pRefbu->interlacedSupport)
|
|
featureDisable = 1;
|
|
|
|
if(!isIntraFrame && !featureDisable)
|
|
{
|
|
if(pRefbu->prevLatency != pRefbu->currMemModel.latency)
|
|
{
|
|
UpdateMemModel( pRefbu );
|
|
pRefbu->prevLatency = pRefbu->currMemModel.latency;
|
|
}
|
|
|
|
enable = GetSettings( pRefbu, &ox, &oy,
|
|
isBframe, mode == REFBU_FIELD);
|
|
|
|
tmp = RefbuGetHitThreshold( pRefbu );
|
|
pRefbu->checkpoint = tmp;
|
|
|
|
if( mode == REFBU_FIELD )
|
|
{
|
|
tmp = DecideParityMode( pRefbu, isBframe );
|
|
SetDecRegister( regBase, HWIF_REFBU_FPARMOD_E, tmp );
|
|
if( !tmp )
|
|
{
|
|
pRefbu->thrAdj = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pRefbu->thrAdj = 1;
|
|
}
|
|
|
|
SetDecRegister(regBase, HWIF_REFBU_E, enable );
|
|
if( enable )
|
|
{
|
|
/* Figure out which features to enable */
|
|
if( pRefbu->doubleSupport )
|
|
{
|
|
if( !isBframe ) /* P field/frame */
|
|
{
|
|
if( mode == REFBU_FIELD )
|
|
{
|
|
if( singleRefField )
|
|
{
|
|
/* Buffer only reference field given in refPicId0 */
|
|
}
|
|
else if (multipleRefFields )
|
|
{
|
|
/* Let's not try to guess */
|
|
useDoubleMode = 1;
|
|
useAdaptiveMode = 1;
|
|
pRefbu->checkpoint /= pRefbu->thrAdj;
|
|
thr2 = pRefbu->checkpoint ;
|
|
}
|
|
else
|
|
{
|
|
/* Buffer both reference fields explicitly */
|
|
useDoubleMode = 1;
|
|
pRefbu->checkpoint /= pRefbu->thrAdj;
|
|
thr2 = pRefbu->checkpoint;
|
|
}
|
|
}
|
|
else if (forceAdaptiveSingle)
|
|
{
|
|
useAdaptiveMode = 1;
|
|
useDoubleMode = 0;
|
|
}
|
|
else if( multipleRefFrames )
|
|
{
|
|
useAdaptiveMode = 1;
|
|
useDoubleMode = 1;
|
|
pRefbu->checkpoint /= pRefbu->thrAdj;
|
|
thr2 = pRefbu->checkpoint;
|
|
}
|
|
else
|
|
{
|
|
/* Content to buffer just one ref pic */
|
|
}
|
|
}
|
|
else /* B field/frame */
|
|
{
|
|
if( mode == REFBU_FIELD )
|
|
{
|
|
/* Let's not try to guess */
|
|
useAdaptiveMode = 1;
|
|
useDoubleMode = 1;
|
|
pRefbu->checkpoint /= pRefbu->thrAdj;
|
|
/*pRefbu->checkpoint /= 2;*/
|
|
thr2 = pRefbu->checkpoint;
|
|
}
|
|
else if (!multipleRefFrames )
|
|
{
|
|
/* Buffer forward and backward pictures as given in
|
|
* refPicId0 and refPicId1 */
|
|
useDoubleMode = 1;
|
|
pRefbu->checkpoint /= pRefbu->thrAdj;
|
|
thr2 = pRefbu->checkpoint;
|
|
}
|
|
else
|
|
{
|
|
/* Let's not try to guess */
|
|
useDoubleMode = 1;
|
|
useAdaptiveMode = 1;
|
|
pRefbu->checkpoint /= pRefbu->thrAdj;
|
|
thr2 = pRefbu->checkpoint;
|
|
}
|
|
}
|
|
}
|
|
else /* Just single buffering supported */
|
|
{
|
|
if( !isBframe ) /* P field/frame */
|
|
{
|
|
if( mode == REFBU_FIELD )
|
|
{
|
|
useAdaptiveMode = 1;
|
|
}
|
|
else if (forceAdaptiveSingle)
|
|
{
|
|
useAdaptiveMode = 1;
|
|
}
|
|
else if (multipleRefFrames)
|
|
{
|
|
/*useAdaptiveMode = 1;*/
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
else /* B field/frame */
|
|
{
|
|
useAdaptiveMode = 1;
|
|
}
|
|
}
|
|
|
|
if(!useAdaptiveMode)
|
|
{
|
|
pic0 = refPicId0;
|
|
if( useDoubleMode )
|
|
{
|
|
pic1 = refPicId1;
|
|
}
|
|
}
|
|
|
|
SetDecRegister(regBase, HWIF_REFBU_EVAL_E, useAdaptiveMode );
|
|
|
|
/* Calculate amount of hits required for first mb row */
|
|
|
|
if ( mode == REFBU_MBAFF )
|
|
{
|
|
pRefbu->checkpoint *= 2;
|
|
thr2 *= 2;
|
|
}
|
|
|
|
if( useDoubleMode )
|
|
{
|
|
oy = 0; /* Disable offset */
|
|
}
|
|
|
|
/* Limit offset */
|
|
{
|
|
i32 limit, height;
|
|
height = pRefbu->picHeightInMbs;
|
|
if( mode == REFBU_FIELD )
|
|
height /= 2; /* adjust to field height */
|
|
|
|
if( mode == REFBU_MBAFF )
|
|
limit = 64; /* 4 macroblock rows */
|
|
else
|
|
limit = 48; /* 3 macroblock rows */
|
|
|
|
if( (i32)(oy+limit) > (i32)(height*16) )
|
|
oy = height*16-limit;
|
|
if( (i32)((-oy)+limit) > (i32)(height*16) )
|
|
oy = -(height*16-limit);
|
|
}
|
|
|
|
/* Disable offset just to make sure */
|
|
if(!pRefbu->offsetSupport || 1) /* NOTE: always disabled for now */
|
|
oy = 0;
|
|
|
|
if(!disableCheckpoint)
|
|
SetDecRegister(regBase, HWIF_REFBU_THR, pRefbu->checkpoint );
|
|
else
|
|
SetDecRegister(regBase, HWIF_REFBU_THR, 0 );
|
|
SetDecRegister(regBase, HWIF_REFBU_PICID, pic0 );
|
|
SetDecRegister(regBase, HWIF_REFBU_Y_OFFSET, oy );
|
|
|
|
if(pRefbu->doubleSupport)
|
|
{
|
|
/* Very much TODO */
|
|
SetDecRegister(regBase, HWIF_REFBU2_BUF_E, useDoubleMode );
|
|
SetDecRegister(regBase, HWIF_REFBU2_THR, thr2 );
|
|
SetDecRegister(regBase, HWIF_REFBU2_PICID, pic1 );
|
|
pRefbu->prevUsedDouble = useDoubleMode;
|
|
}
|
|
}
|
|
pRefbu->prevWasField = (mode == REFBU_FIELD && !isBframe);
|
|
}
|
|
else
|
|
{
|
|
pRefbu->checkpoint = 0;
|
|
SetDecRegister(regBase, HWIF_REFBU_E, HANTRO_FALSE );
|
|
}
|
|
|
|
if(pRefbu->testFunction)
|
|
{
|
|
pRefbu->testFunction(pRefbu, regBase, isIntraFrame, mode );
|
|
}
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : RefbuGetVpxCoveragePrediction
|
|
Description : Return coverage and intra block prediction for VPx
|
|
"intelligent" ref buffer control. Prediction algorithm
|
|
to be finalized
|
|
|
|
Return type :
|
|
Argument :
|
|
------------------------------------------------------------------------------*/
|
|
u32 RefbuVpxGetPrevFrameStats( refBuffer_t *pRefbu)
|
|
{
|
|
i32 cov, tmp;
|
|
|
|
tmp = pRefbu->prevFrameHitSum;
|
|
if ( tmp >= pRefbu->checkpoint && pRefbu->checkpoint )
|
|
cov = tmp/4;
|
|
else
|
|
cov = 0;
|
|
return cov;
|
|
}
|