297 lines
6.1 KiB
C++
297 lines
6.1 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
#include "M4Prediction.h"
|
|
#include "M4Global.h"
|
|
|
|
namespace vdecmpeg4
|
|
{
|
|
|
|
static const int16 defaultACDCValues[15] =
|
|
{
|
|
1024, // default DC predictor
|
|
0, 0, 0, 0, 0, 0, 0, // default AC row predictors
|
|
0, 0, 0, 0, 0, 0, 0 // default AC column predictors
|
|
};
|
|
|
|
|
|
static int32 XDIV_DIV(int32 a, int32 b)
|
|
{
|
|
float A = float(a);
|
|
float B = float(b);
|
|
float B2 = float(b >> 1);
|
|
float R;
|
|
if (a > 0)
|
|
{
|
|
R = (A + B2) / B;
|
|
}
|
|
else
|
|
{
|
|
R = (A - B2) / B;
|
|
}
|
|
int32 r = int32(R);
|
|
/*
|
|
int32 r;
|
|
if (a > 0)
|
|
r = (a + (b >> 1)) / b;
|
|
else
|
|
r = (a - (b >> 1)) / b;
|
|
*/
|
|
return r;
|
|
}
|
|
|
|
static int32 rescaleF32(int32 predictQuant, int32 currentQuant, int32 coeff)
|
|
{
|
|
if (coeff)
|
|
{
|
|
return XDIV_DIV(coeff * predictQuant, currentQuant);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/**
|
|
* Perform ACDC prediction
|
|
*
|
|
* @param macroblocks
|
|
* macroblock array
|
|
* @param mbx macroblock x
|
|
* @param mby macroblock y
|
|
* @param pMBWidth stride for macroblocks
|
|
* @param block current yuv subblock (0..5)
|
|
* @param currentQuant
|
|
* @param iDcScaler
|
|
* @param pPredictionOut
|
|
*/
|
|
void M4PredictionInit(M4_MB* macroblocks, int32 mbx, int32 mby, int32 pMBWidth, uint32 block, uint8 currentQuant, uint16 iDcScaler, int16* pPredictionOut)
|
|
{
|
|
int32 index = mbx + mby * pMBWidth; // current macroblock
|
|
|
|
int32 leftQuant = currentQuant;
|
|
int32 topQuant = currentQuant;
|
|
|
|
const int16* pLeft = defaultACDCValues;
|
|
const int16* pTop = defaultACDCValues;
|
|
const int16* pDiag = defaultACDCValues;
|
|
|
|
int16* left = nullptr;
|
|
int16* top = nullptr;
|
|
int16* diag = nullptr;
|
|
int16* current = nullptr;
|
|
|
|
// left macroblock
|
|
if (mbx && (macroblocks[index-1].mMode == M4_MBMODE_INTRA || macroblocks[index-1].mMode == M4_MBMODE_INTRA_Q))
|
|
{
|
|
left = macroblocks[index-1].mPredictedValues[0];
|
|
leftQuant = macroblocks[index-1].mQuant;
|
|
}
|
|
|
|
// top macroblock
|
|
if (mby && (macroblocks[index-pMBWidth].mMode == M4_MBMODE_INTRA || macroblocks[index-pMBWidth].mMode == M4_MBMODE_INTRA_Q))
|
|
{
|
|
top = macroblocks[index - pMBWidth].mPredictedValues[0];
|
|
topQuant = macroblocks[index - pMBWidth].mQuant;
|
|
}
|
|
|
|
// diag macroblock
|
|
if (mbx && mby && (macroblocks[index-1-pMBWidth].mMode == M4_MBMODE_INTRA || macroblocks[index-1-pMBWidth].mMode == M4_MBMODE_INTRA_Q))
|
|
{
|
|
diag = macroblocks[index - 1 - pMBWidth].mPredictedValues[0];
|
|
}
|
|
|
|
current = macroblocks[index].mPredictedValues[0];
|
|
|
|
// now grab pLeft, pTop, pDiag _blocks_
|
|
// this are the different patterns based on the the dct block 0..5
|
|
switch (block)
|
|
{
|
|
case 0:
|
|
{
|
|
if (left)
|
|
{
|
|
pLeft = left + M4_MBPRED_SIZE; // pointer to left mb
|
|
}
|
|
|
|
if (top)
|
|
{
|
|
pTop = top + (M4_MBPRED_SIZE << 1);
|
|
}
|
|
|
|
if (diag)
|
|
{
|
|
pDiag = diag + 3 * M4_MBPRED_SIZE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 1:
|
|
{
|
|
pLeft = current; // we use our current MB
|
|
leftQuant = currentQuant;
|
|
|
|
if (top)
|
|
{
|
|
pTop = top + 3 * M4_MBPRED_SIZE;
|
|
pDiag = top + (M4_MBPRED_SIZE << 1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 2:
|
|
{
|
|
if (left)
|
|
{
|
|
pLeft = left + 3 * M4_MBPRED_SIZE;
|
|
pDiag = left + M4_MBPRED_SIZE;
|
|
}
|
|
pTop = current;
|
|
topQuant = currentQuant;
|
|
break;
|
|
}
|
|
|
|
case 3:
|
|
{
|
|
pLeft = current + (M4_MBPRED_SIZE << 1);
|
|
leftQuant = currentQuant;
|
|
pTop = current + M4_MBPRED_SIZE;
|
|
topQuant = currentQuant;
|
|
pDiag = current;
|
|
break;
|
|
}
|
|
|
|
case 4:
|
|
{
|
|
if (left)
|
|
{
|
|
pLeft = left + (M4_MBPRED_SIZE << 2);
|
|
}
|
|
if (top)
|
|
{
|
|
pTop = top + (M4_MBPRED_SIZE << 2);
|
|
}
|
|
if (diag)
|
|
{
|
|
pDiag = diag + (M4_MBPRED_SIZE << 2);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 5:
|
|
{
|
|
if (left)
|
|
{
|
|
pLeft = left + 5 * M4_MBPRED_SIZE;
|
|
}
|
|
if (top)
|
|
{
|
|
pTop = top + 5 * M4_MBPRED_SIZE;
|
|
}
|
|
if (diag)
|
|
{
|
|
pDiag = diag + 5 * M4_MBPRED_SIZE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// determine ac prediction direction & ac/dc predictor
|
|
// place rescaled ac/dc predictions into predictors[] for later use
|
|
uint8* acPredDirection = ¯oblocks[index].mACPredDirections[block];
|
|
|
|
if (M4ABS(pLeft[0] - pDiag[0]) < M4ABS(pDiag[0] - pTop[0]))
|
|
{
|
|
// use vertical prediction, predict from block ABOVE
|
|
|
|
// set prediction direction of this block to vertical
|
|
*acPredDirection = 1;
|
|
|
|
// set DC value
|
|
pPredictionOut[0] = M4DIVDIV(pTop[0], iDcScaler);
|
|
|
|
// set AC vlues
|
|
for(uint32 i=1; i<8; ++i)
|
|
{
|
|
pPredictionOut[i] = (int16)rescaleF32(topQuant, currentQuant, pTop[i]);
|
|
//???? pPredictionOut[i] = (int16)rescale(topQuant, currentQuant, pTop[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// use horizontal prediction, predict from block to LEFT
|
|
|
|
// set prediction direction of this block to horizontal
|
|
*acPredDirection = 2;
|
|
|
|
// set DC value
|
|
pPredictionOut[0] = M4DIVDIV(pLeft[0], iDcScaler);
|
|
|
|
// set AC values
|
|
for(uint32 i=1; i<8; ++i)
|
|
{
|
|
pPredictionOut[i] = (int16)rescaleF32(leftQuant, currentQuant, pLeft[i + 7]);
|
|
//???? pPredictionOut[i] = (int16)rescale(leftQuant, currentQuant, pLeft[i + 7]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/**
|
|
* Add prediction to residual
|
|
*
|
|
* @param mb
|
|
* @param dctBlock
|
|
* @param block
|
|
* @param iDcScaler
|
|
* @param pPrediction
|
|
*/
|
|
void M4PredictionAdd(M4_MB* mb, int16* dctBlock, uint32 block, uint16 iDcScaler, const int16* pPrediction)
|
|
{
|
|
int16* pCurrent = mb->mPredictedValues[block];
|
|
|
|
// ALWAYS predict DC value from DC predictor
|
|
dctBlock[0] += pPrediction[0];
|
|
pCurrent[0] = dctBlock[0] * iDcScaler;
|
|
|
|
uint8 acPredDirection = mb->mACPredDirections[block];
|
|
if (acPredDirection == 1)
|
|
{
|
|
// vertical prediction
|
|
for(uint32 i=1; i<8; ++i)
|
|
{
|
|
int16 level = dctBlock[i] + pPrediction[i];
|
|
dctBlock[i] = level;
|
|
pCurrent[i] = level;
|
|
pCurrent[i+7] = dctBlock[i*8];
|
|
}
|
|
}
|
|
else if (acPredDirection == 2)
|
|
{
|
|
// horizontal prediction
|
|
for(uint32 i=1; i<8; ++i)
|
|
{
|
|
int16 level = dctBlock[i*8] + pPrediction[i];
|
|
dctBlock[i*8] = level;
|
|
pCurrent[i+7] = level;
|
|
pCurrent[i] = dctBlock[i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no prediction, but save data in macroblock
|
|
// save first ROW and COLUMN in mPredictedValues[block]
|
|
for(uint32 i=1; i<8; ++i)
|
|
{
|
|
pCurrent[i] = dctBlock[i];
|
|
pCurrent[i+7] = dctBlock[i*8];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|