winamp/Src/h264dec/ldecod/src/block.c

930 lines
31 KiB
C
Raw Normal View History

2024-09-24 12:54:57 +00:00
/*!
***********************************************************************
* \file
* block.c
*
* \brief
* Block functions
*
* \author
* Main contributors (see contributors.h for copyright, address and affiliation details)
* - Inge Lille-Langoy <inge.lille-langoy@telenor.com>
* - Rickard Sjoberg <rickard.sjoberg@era.ericsson.se>
***********************************************************************
*/
#include "contributors.h"
#include "global.h"
#include "block.h"
#include "image.h"
#include "mb_access.h"
#include "transform.h"
#include "quant.h"
#include "memalloc.h"
#include "optim.h"
/*!
****************************************************************************
* \brief
* Inverse 4x4 lossless_qpprime transformation, transforms cof to mb_rres
****************************************************************************
*/
void itrans4x4_ls(const h264_short_block_row_t *tblock,
const h264_imgpel_macroblock_row_t *mb_pred,
h264_imgpel_macroblock_row_t *mb_rec,
int ioff, //!< index to 4x4 block
int joff) //!< index to 4x4 block
{
int i,j;
for (j = 0; j < BLOCK_SIZE; ++j)
{
for (i = 0; i < BLOCK_SIZE; ++i)
{
mb_rec[j+joff][i+ioff] = (imgpel) iClip1(255/*max_imgpel_value*/, mb_pred[j+joff][i+ioff] + tblock[j][i]);
}
}
}
/*!
************************************************************************
* \brief
* Inverse residual DPCM for Intra lossless coding
*
************************************************************************
*/
void Inv_Residual_trans_4x4(Macroblock *currMB, //!< current macroblock
ColorPlane pl, //!< used color plane
int ioff, //!< index to 4x4 block
int joff) //!< index to 4x4 block
{
int i,j;
h264_short_block_t temp;
Slice *currSlice = currMB->p_Slice;
int subblock = cof4_pos_to_subblock[joff>>2][ioff>>2];
h264_short_block_row_t *tblock = currSlice->cof4[pl][subblock];
if(currMB->ipmode_DPCM == VERT_PRED)
{
for(i=0; i<4; ++i)
{
temp[0][i] = tblock[0][i];
temp[1][i] = tblock[1][i] + temp[0][i];
temp[2][i] = tblock[2][i] + temp[1][i];
temp[3][i] = tblock[3][i] + temp[2][i];
}
}
else if(currMB->ipmode_DPCM == HOR_PRED)
{
for(j=0; j<4; ++j)
{
temp[j][0] = tblock[j][0];
temp[j][1] = tblock[j][1] + temp[j][0];
temp[j][2] = tblock[j][2] + temp[j][1];
temp[j][3] = tblock[j][3] + temp[j][2];
}
}
else
{
for (j = 0; j < BLOCK_SIZE; ++j)
for (i = 0; i < BLOCK_SIZE; ++i)
temp[j][i] = tblock[j][i];
}
for (j = 0; j < BLOCK_SIZE; ++j)
{
for (i = 0; i < BLOCK_SIZE; ++i)
{
currSlice->mb_rec[pl][j+joff][i+ioff] = (imgpel) (temp[j][i] + currSlice->mb_pred[pl][j+joff][i+ioff]);
}
}
}
/*!
************************************************************************
* \brief
* Inverse residual DPCM for Intra lossless coding
*
* \par Input:
* ioff_x,joff_y: Block position inside a macro block (0,8).
************************************************************************
*/
//For residual DPCM
void Inv_Residual_trans_8x8(Macroblock *currMB, ColorPlane pl, int ioff,int joff)
{
Slice *currSlice = currMB->p_Slice;
int i, j;
h264_short_8x8block_t temp;
int block = (joff>>2) + (ioff>>3);
if(currMB->ipmode_DPCM == VERT_PRED)
{
for(i=0; i<8; ++i)
{
temp[0][i] = currSlice->mb_rres8[pl][block][0][i];
temp[1][i] = currSlice->mb_rres8[pl][block][1][i] + temp[0][i];
temp[2][i] = currSlice->mb_rres8[pl][block][2][i] + temp[1][i];
temp[3][i] = currSlice->mb_rres8[pl][block][3][i] + temp[2][i];
temp[4][i] = currSlice->mb_rres8[pl][block][4][i] + temp[3][i];
temp[5][i] = currSlice->mb_rres8[pl][block][5][i] + temp[4][i];
temp[6][i] = currSlice->mb_rres8[pl][block][6][i] + temp[5][i];
temp[7][i] = currSlice->mb_rres8[pl][block][7][i] + temp[6][i];
}
for(i=0; i<8; ++i)
{
currSlice->mb_rres8[pl][block][0][i]=temp[0][i];
currSlice->mb_rres8[pl][block][1][i]=temp[1][i];
currSlice->mb_rres8[pl][block][2][i]=temp[2][i];
currSlice->mb_rres8[pl][block][3][i]=temp[3][i];
currSlice->mb_rres8[pl][block][4][i]=temp[4][i];
currSlice->mb_rres8[pl][block][5][i]=temp[5][i];
currSlice->mb_rres8[pl][block][6][i]=temp[6][i];
currSlice->mb_rres8[pl][block][7][i]=temp[7][i];
}
}
else if(currMB->ipmode_DPCM == HOR_PRED)//HOR_PRED
{
for(i=0; i<8; ++i)
{
temp[i][0] = currSlice->mb_rres8[pl][block][i][0];
temp[i][1] = currSlice->mb_rres8[pl][block][i][1] + temp[i][0];
temp[i][2] = currSlice->mb_rres8[pl][block][i][2] + temp[i][1];
temp[i][3] = currSlice->mb_rres8[pl][block][i][3] + temp[i][2];
temp[i][4] = currSlice->mb_rres8[pl][block][i][4] + temp[i][3];
temp[i][5] = currSlice->mb_rres8[pl][block][i][5] + temp[i][4];
temp[i][6] = currSlice->mb_rres8[pl][block][i][6] + temp[i][5];
temp[i][7] = currSlice->mb_rres8[pl][block][i][7] + temp[i][6];
}
for(i=0; i<8; ++i)
{
currSlice->mb_rres8[pl][block][i][0]=temp[i][0];
currSlice->mb_rres8[pl][block][i][1]=temp[i][1];
currSlice->mb_rres8[pl][block][i][2]=temp[i][2];
currSlice->mb_rres8[pl][block][i][3]=temp[i][3];
currSlice->mb_rres8[pl][block][i][4]=temp[i][4];
currSlice->mb_rres8[pl][block][i][5]=temp[i][5];
currSlice->mb_rres8[pl][block][i][6]=temp[i][6];
currSlice->mb_rres8[pl][block][i][7]=temp[i][7];
}
}
for (j = 0; j < BLOCK_SIZE_8x8; ++j)
{
for (i = 0; i < BLOCK_SIZE_8x8; ++i)
{
currSlice->mb_rec[pl][joff+j][ioff+i] = (imgpel) (currSlice->mb_rres8[pl][block][j][i] + currSlice->mb_pred[pl][joff+j][ioff+i]);
}
}
}
/*!
***********************************************************************
* \brief
* Luma DC inverse transform
***********************************************************************
*/
void itrans_2(Macroblock *currMB, ColorPlane pl)
{
Slice *currSlice = currMB->p_Slice;
VideoParameters *p_Vid = currMB->p_Vid;
int transform_pl = IS_INDEPENDENT(p_Vid) ? PLANE_Y /*p_Vid->colour_plane_id*/ : pl;
h264_short_block_t *blocks = currSlice->cof4[transform_pl];
int qp_scaled = currMB->qp_scaled[pl];
int qp_per = p_Vid->qp_per_matrix[ qp_scaled ];
int qp_rem = p_Vid->qp_rem_matrix[ qp_scaled ];
int invLevelScale = currSlice->InvLevelScale4x4_Intra[pl][qp_rem][0][0];
h264_int_block_t M4;
// horizontal
M4[0][0]=blocks[0][0][0];
M4[0][1]=blocks[1][0][0];
M4[0][2]=blocks[4][0][0];
M4[0][3]=blocks[5][0][0];
M4[1][0]=blocks[2][0][0];
M4[1][1]=blocks[3][0][0];
M4[1][2]=blocks[6][0][0];
M4[1][3]=blocks[7][0][0];
M4[2][0]=blocks[8][0][0];
M4[2][1]=blocks[9][0][0];
M4[2][2]=blocks[12][0][0];
M4[2][3]=blocks[13][0][0];
M4[3][0]=blocks[10][0][0];
M4[3][1]=blocks[11][0][0];
M4[3][2]=blocks[14][0][0];
M4[3][3]=blocks[15][0][0];
ihadamard4x4(M4);
// vertical
blocks[0][0][0] = rshift_rnd((( M4[0][0] * invLevelScale) << qp_per), 6);
blocks[1][0][0] = rshift_rnd((( M4[0][1] * invLevelScale) << qp_per), 6);
blocks[4][0][0] = rshift_rnd((( M4[0][2] * invLevelScale) << qp_per), 6);
blocks[5][0][0] = rshift_rnd((( M4[0][3] * invLevelScale) << qp_per), 6);
blocks[2][0][0] = rshift_rnd((( M4[1][0] * invLevelScale) << qp_per), 6);
blocks[3][0][0] = rshift_rnd((( M4[1][1] * invLevelScale) << qp_per), 6);
blocks[6][0][0] = rshift_rnd((( M4[1][2] * invLevelScale) << qp_per), 6);
blocks[7][0][0] = rshift_rnd((( M4[1][3] * invLevelScale) << qp_per), 6);
blocks[8][0][0] = rshift_rnd((( M4[2][0] * invLevelScale) << qp_per), 6);
blocks[9][0][0] = rshift_rnd((( M4[2][1] * invLevelScale) << qp_per), 6);
blocks[12][0][0] = rshift_rnd((( M4[2][2] * invLevelScale) << qp_per), 6);
blocks[13][0][0] = rshift_rnd((( M4[2][3] * invLevelScale) << qp_per), 6);
blocks[10][0][0] = rshift_rnd((( M4[3][0] * invLevelScale) << qp_per), 6);
blocks[11][0][0] = rshift_rnd((( M4[3][1] * invLevelScale) << qp_per), 6);
blocks[14][0][0] = rshift_rnd((( M4[3][2] * invLevelScale) << qp_per), 6);
blocks[15][0][0] = rshift_rnd((( M4[3][3] * invLevelScale) << qp_per), 6);
}
void itrans_sp(h264_short_block_row_t *tblock, const h264_imgpel_macroblock_row_t *mb_pred, Macroblock *currMB, ColorPlane pl, int ioff, int joff)
{
VideoParameters *p_Vid = currMB->p_Vid;
Slice *currSlice = currMB->p_Slice;
int i,j;
int ilev, icof;
int qp = (currSlice->slice_type == SI_SLICE) ? currSlice->qs : p_Vid->qp;
int qp_per = p_Vid->qp_per_matrix[ qp ];
int qp_rem = p_Vid->qp_rem_matrix[ qp ];
int qp_per_sp = p_Vid->qp_per_matrix[ currSlice->qs ];
int qp_rem_sp = p_Vid->qp_rem_matrix[ currSlice->qs ];
int q_bits_sp = Q_BITS + qp_per_sp;
int max_imgpel_value = p_Vid->max_pel_value_comp[pl];
const int (*InvLevelScale4x4) [4] = dequant_coef[qp_rem];
const int (*InvLevelScale4x4SP)[4] = dequant_coef[qp_rem_sp];
int **PBlock;
get_mem2Dint(&PBlock, MB_BLOCK_SIZE, MB_BLOCK_SIZE);
for (j=0; j< BLOCK_SIZE; ++j)
for (i=0; i< BLOCK_SIZE; ++i)
PBlock[j][i] = mb_pred[j+joff][i+ioff];
forward4x4(PBlock, PBlock, 0, 0);
if(p_Vid->sp_switch || currSlice->slice_type==SI_SLICE)
{
for (j=0;j<BLOCK_SIZE;++j)
{
for (i=0;i<BLOCK_SIZE;++i)
{
// recovering coefficient since they are already dequantized earlier
icof = (tblock[j][i] >> qp_per) / InvLevelScale4x4[j][i];
ilev = rshift_rnd_sf(iabs(PBlock[j][i]) * quant_coef[qp_rem_sp][j][i], q_bits_sp);
ilev = isignab(ilev, PBlock[j][i]) + icof;
tblock[j][i] = ilev * InvLevelScale4x4SP[j][i] << qp_per_sp;
}
}
}
else
{
for (j=0;j<BLOCK_SIZE;++j)
{
for (i=0;i<BLOCK_SIZE;++i)
{
// recovering coefficient since they are already dequantized earlier
icof = (tblock[j][i] >> qp_per) / InvLevelScale4x4[j][i];
ilev = PBlock[j][i] + ((icof * InvLevelScale4x4[j][i] * A[j][i] << qp_per) >> 6);
ilev = isign(ilev) * rshift_rnd_sf(iabs(ilev) * quant_coef[qp_rem_sp][j][i], q_bits_sp);
tblock[j][i] = ilev * InvLevelScale4x4SP[j][i] << qp_per_sp;
}
}
}
{
h264_imgpel_macroblock_row_t *mb_rec = currSlice->mb_rec[pl];
opt_itrans4x4(tblock, mb_pred, mb_rec, ioff, joff);
}
free_mem2Dint(PBlock);
}
void itrans_sp_cr(Macroblock *currMB, int uv)
{
Slice *currSlice = currMB->p_Slice;
VideoParameters *p_Vid = currMB->p_Vid;
int i,j,ilev, icof, n2,n1;
int mp1[BLOCK_SIZE];
int qp_per,qp_rem;
int qp_per_sp,qp_rem_sp,q_bits_sp;
int **PBlock;
get_mem2Dint(&PBlock, MB_BLOCK_SIZE, MB_BLOCK_SIZE);
qp_per = p_Vid->qp_per_matrix[ ((p_Vid->qp < 0 ? p_Vid->qp : QP_SCALE_CR[p_Vid->qp]))];
qp_rem = p_Vid->qp_rem_matrix[ ((p_Vid->qp < 0 ? p_Vid->qp : QP_SCALE_CR[p_Vid->qp]))];
qp_per_sp = p_Vid->qp_per_matrix[ ((currSlice->qs < 0 ? currSlice->qs : QP_SCALE_CR[currSlice->qs]))];
qp_rem_sp = p_Vid->qp_rem_matrix[ ((currSlice->qs < 0 ? currSlice->qs : QP_SCALE_CR[currSlice->qs]))];
q_bits_sp = Q_BITS + qp_per_sp;
if (currSlice->slice_type == SI_SLICE)
{
qp_per = qp_per_sp;
qp_rem = qp_rem_sp;
}
for (j=0; j < p_Vid->mb_cr_size_y; ++j)
{
for (i=0; i < p_Vid->mb_cr_size_x; ++i)
{
PBlock[j][i] = currSlice->mb_pred[uv + 1][j][i];
currSlice->mb_pred[uv + 1][j][i] = 0;
}
}
for (n2=0; n2 < p_Vid->mb_cr_size_y; n2 += BLOCK_SIZE)
{
for (n1=0; n1 < p_Vid->mb_cr_size_x; n1 += BLOCK_SIZE)
{
forward4x4(PBlock, PBlock, n2, n1);
}
}
// 2X2 transform of DC coeffs.
mp1[0] = (PBlock[0][0] + PBlock[4][0] + PBlock[0][4] + PBlock[4][4]);
mp1[1] = (PBlock[0][0] - PBlock[4][0] + PBlock[0][4] - PBlock[4][4]);
mp1[2] = (PBlock[0][0] + PBlock[4][0] - PBlock[0][4] - PBlock[4][4]);
mp1[3] = (PBlock[0][0] - PBlock[4][0] - PBlock[0][4] + PBlock[4][4]);
if (p_Vid->sp_switch || currSlice->slice_type == SI_SLICE)
{
for (n2=0; n2 < 2; ++n2 )
{
for (n1=0; n1 < 2; ++n1 )
{
//quantization fo predicted block
ilev = rshift_rnd_sf(iabs (mp1[n1+n2*2]) * quant_coef[qp_rem_sp][0][0], q_bits_sp + 1);
//addition
ilev = isignab(ilev, mp1[n1+n2*2]) + currSlice->cof4[uv + 1][cof4_pos_to_subblock[n2][n1]][0][0];
//dequantization
mp1[n1+n2*2] =ilev * dequant_coef[qp_rem_sp][0][0] << qp_per_sp;
}
}
for (n2 = 0; n2 < p_Vid->mb_cr_size_y; n2 += BLOCK_SIZE)
{
for (n1 = 0; n1 < p_Vid->mb_cr_size_x; n1 += BLOCK_SIZE)
{
for (j = 0; j < BLOCK_SIZE; ++j)
{
for (i = 0; i < BLOCK_SIZE; ++i)
{
// recovering coefficient since they are already dequantized earlier
currSlice->cof4[uv + 1][cof4_pos_to_subblock[n2>>2][n1>>2]][j][i] = (currSlice->cof4[uv + 1][cof4_pos_to_subblock[n2>>2][n1>>2]][j][i] >> qp_per) / dequant_coef[qp_rem][j][i];
//quantization of the predicted block
ilev = rshift_rnd_sf(iabs(PBlock[n2 + j][n1 + i]) * quant_coef[qp_rem_sp][j][i], q_bits_sp);
//addition of the residual
ilev = isignab(ilev,PBlock[n2 + j][n1 + i]) + currSlice->cof4[uv + 1][cof4_pos_to_subblock[n2>>2][n1>>2]][j][i] ;
// Inverse quantization
currSlice->cof4[uv + 1][cof4_pos_to_subblock[n2>>2][n1>>2]][j][i] = ilev * dequant_coef[qp_rem_sp][j][i] << qp_per_sp;
}
}
}
}
}
else
{
for (n2=0; n2 < 2; ++n2 )
{
for (n1=0; n1 < 2; ++n1 )
{
ilev = mp1[n1+n2*2] + (((currSlice->cof4[uv + 1][cof4_pos_to_subblock[n2][n1]][0][0] * dequant_coef[qp_rem][0][0] * A[0][0]) << qp_per) >> 5);
ilev = isign(ilev) * rshift_rnd_sf(iabs(ilev) * quant_coef[qp_rem_sp][0][0], q_bits_sp + 1);
//ilev = isignab(rshift_rnd_sf(iabs(ilev)* quant_coef[qp_rem_sp][0][0], q_bits_sp + 1), ilev);
mp1[n1+n2*2] = ilev * dequant_coef[qp_rem_sp][0][0] << qp_per_sp;
}
}
for (n2 = 0; n2 < p_Vid->mb_cr_size_y; n2 += BLOCK_SIZE)
{
for (n1 = 0; n1 < p_Vid->mb_cr_size_x; n1 += BLOCK_SIZE)
{
for (j = 0; j< BLOCK_SIZE; ++j)
{
for (i = 0; i< BLOCK_SIZE; ++i)
{
// recovering coefficient since they are already dequantized earlier
icof = (currSlice->cof4[uv + 1][cof4_pos_to_subblock[n2>>2][n1>>2]][j][i] >> qp_per) / dequant_coef[qp_rem][j][i];
//dequantization and addition of the predicted block
ilev = PBlock[n2 + j][n1 + i] + ((icof * dequant_coef[qp_rem][j][i] * A[j][i] << qp_per) >> 6);
//quantization and dequantization
ilev = isign(ilev) * rshift_rnd_sf(iabs(ilev) * quant_coef[qp_rem_sp][j][i], q_bits_sp);
currSlice->cof4[uv + 1][cof4_pos_to_subblock[n2>>2][n1>>2]][j][i] = ilev * dequant_coef[qp_rem_sp][j][i] << qp_per_sp;
}
}
}
}
}
currSlice->cof4[uv + 1][0][0][0] = (mp1[0] + mp1[1] + mp1[2] + mp1[3]) >> 1;
currSlice->cof4[uv + 1][1][0][0] = (mp1[0] + mp1[1] - mp1[2] - mp1[3]) >> 1;
currSlice->cof4[uv + 1][2][0][0] = (mp1[0] - mp1[1] + mp1[2] - mp1[3]) >> 1;
currSlice->cof4[uv + 1][3][0][0] = (mp1[0] - mp1[1] - mp1[2] + mp1[3]) >> 1;
free_mem2Dint(PBlock);
}
#if defined(_DEBUG) || !defined(_M_IX86)
void iMBtrans4x4(Macroblock *currMB, ColorPlane pl, int smb)
{
Slice *currSlice = currMB->p_Slice;
VideoParameters *p_Vid = currMB->p_Vid;
StorablePicture *dec_picture = p_Vid->dec_picture;
VideoImage *curr_img = pl ? dec_picture->imgUV[pl - 1]: dec_picture->imgY;
// =============== 4x4 itrans ================
// -------------------------------------------
if (smb)
{
h264_short_block_t *blocks = currSlice->cof4[pl];
const h264_imgpel_macroblock_row_t *mb_pred=currSlice->mb_pred[pl];
itrans_sp(blocks[0], mb_pred, currMB, pl, 0, 0);
itrans_sp(blocks[1], mb_pred, currMB, pl, 4, 0);
itrans_sp(blocks[2], mb_pred, currMB, pl, 0, 4);
itrans_sp(blocks[3], mb_pred, currMB, pl, 4, 4);
itrans_sp(blocks[4], mb_pred, currMB, pl, 8, 0);
itrans_sp(blocks[5], mb_pred, currMB, pl, 12, 0);
itrans_sp(blocks[6], mb_pred, currMB, pl, 8, 4);
itrans_sp(blocks[7], mb_pred, currMB, pl, 12, 4);
itrans_sp(blocks[8], mb_pred, currMB, pl, 0, 8);
itrans_sp(blocks[9], mb_pred, currMB, pl, 4, 8);
itrans_sp(blocks[10], mb_pred, currMB, pl, 0, 12);
itrans_sp(blocks[11], mb_pred, currMB, pl, 4, 12);
itrans_sp(blocks[12], mb_pred, currMB, pl, 8, 8);
itrans_sp(blocks[13], mb_pred, currMB, pl, 12, 8);
itrans_sp(blocks[14], mb_pred, currMB, pl, 8, 12);
itrans_sp(blocks[15], mb_pred, currMB, pl, 12, 12);
}
else if (currMB->is_lossless)
{
Inv_Residual_trans_4x4(currMB, pl, 0, 0);
Inv_Residual_trans_4x4(currMB, pl, 4, 0);
Inv_Residual_trans_4x4(currMB, pl, 0, 4);
Inv_Residual_trans_4x4(currMB, pl, 4, 4);
Inv_Residual_trans_4x4(currMB, pl, 8, 0);
Inv_Residual_trans_4x4(currMB, pl, 12, 0);
Inv_Residual_trans_4x4(currMB, pl, 8, 4);
Inv_Residual_trans_4x4(currMB, pl, 12, 4);
Inv_Residual_trans_4x4(currMB, pl, 0, 8);
Inv_Residual_trans_4x4(currMB, pl, 4, 8);
Inv_Residual_trans_4x4(currMB, pl, 0, 12);
Inv_Residual_trans_4x4(currMB, pl, 4, 12);
Inv_Residual_trans_4x4(currMB, pl, 8, 8);
Inv_Residual_trans_4x4(currMB, pl, 12, 8);
Inv_Residual_trans_4x4(currMB, pl, 8, 12);
Inv_Residual_trans_4x4(currMB, pl, 12, 12);
}
else
{
const h264_short_block_t *blocks = currSlice->cof4[pl];
const h264_imgpel_macroblock_row_t *mb_pred=currSlice->mb_pred[pl];
h264_imgpel_macroblock_row_t *mb_rec = currSlice->mb_rec[pl];
opt_itrans4x4(blocks[0], mb_pred, mb_rec, 0, 0);
opt_itrans4x4(blocks[1], mb_pred, mb_rec, 4, 0);
opt_itrans4x4(blocks[2], mb_pred, mb_rec, 0, 4);
opt_itrans4x4(blocks[3], mb_pred, mb_rec, 4, 4);
opt_itrans4x4(blocks[4], mb_pred, mb_rec, 8, 0);
opt_itrans4x4(blocks[5], mb_pred, mb_rec, 12, 0);
opt_itrans4x4(blocks[6], mb_pred, mb_rec, 8, 4);
opt_itrans4x4(blocks[7], mb_pred, mb_rec, 12, 4);
opt_itrans4x4(blocks[8], mb_pred, mb_rec, 0, 8);
opt_itrans4x4(blocks[9], mb_pred, mb_rec, 4, 8);
opt_itrans4x4(blocks[10], mb_pred, mb_rec, 0, 12);
opt_itrans4x4(blocks[11], mb_pred, mb_rec, 4, 12);
opt_itrans4x4(blocks[12], mb_pred, mb_rec, 8, 8);
opt_itrans4x4(blocks[13], mb_pred, mb_rec, 12, 8);
opt_itrans4x4(blocks[14], mb_pred, mb_rec, 8, 12);
opt_itrans4x4(blocks[15], mb_pred, mb_rec, 12, 12);
}
// construct picture from 4x4 blocks
opt_copy_image_data_16x16_stride(curr_img, currMB->pix_x, currMB->pix_y, currSlice->mb_rec[pl]);
}
#endif
void iMBtrans8x8(Macroblock *currMB, ColorPlane pl)
{
Slice *currSlice = currMB->p_Slice;
VideoParameters *p_Vid = currMB->p_Vid;
StorablePicture *dec_picture = p_Vid->dec_picture;
VideoImage *curr_img = pl ? dec_picture->imgUV[pl - 1] : dec_picture->imgY;
h264_imgpel_macroblock_row_t *mb_rec = currSlice->mb_rec[pl];
h264_imgpel_macroblock_row_t *mb_pred = currSlice->mb_pred[pl];
h264_short_8x8block_t *mb_rres8 = currSlice->mb_rres8[pl];
if (currMB->is_lossless == FALSE)
{
opt_itrans8x8(mb_rec, mb_pred, mb_rres8[0], 0);
opt_itrans8x8(mb_rec, mb_pred, mb_rres8[1], 8);
opt_itrans8x8(mb_rec+8, mb_pred+8, mb_rres8[2], 0);
opt_itrans8x8(mb_rec+8, mb_pred+8, mb_rres8[3], 8);
}
else
{
itrans8x8_lossless(mb_rec, mb_pred, mb_rres8[0], 0);
itrans8x8_lossless(mb_rec, mb_pred, mb_rres8[1], 8);
itrans8x8_lossless(mb_rec+8, mb_pred+8, mb_rres8[2], 0);
itrans8x8_lossless(mb_rec+8, mb_pred+8, mb_rres8[3], 8);
}
opt_copy_image_data_16x16_stride(curr_img, currMB->pix_x, currMB->pix_y, mb_rec);
}
void iTransform(Macroblock *currMB, ColorPlane pl, int smb)
{
Slice *currSlice = currMB->p_Slice;
VideoParameters *p_Vid = currMB->p_Vid;
StorablePicture *dec_picture = p_Vid->dec_picture;
int uv = pl-1;
if ((currMB->cbp & 15) != 0 || smb)
{
if(currMB->luma_transform_size_8x8_flag == 0) // 4x4 inverse transform
{
iMBtrans4x4(currMB, pl, smb);
}
else // 8x8 inverse transform
{
iMBtrans8x8(currMB, pl);
}
}
else
{
VideoImage *curr_img = pl ? dec_picture->imgUV[uv] : dec_picture->imgY;
opt_copy_image_data_16x16_stride(curr_img, currMB->pix_x, currMB->pix_y, currSlice->mb_pred[pl]);
}
// TODO: fix 4x4 lossless
if (dec_picture->chroma_format_idc == YUV420)
{
VideoImage *curUV;
for(uv=0;uv<2;++uv)
{
int pl = uv + 1;
const h264_imgpel_macroblock_row_t *mb_pred=currSlice->mb_pred[pl];
// =============== 4x4 itrans ================
// -------------------------------------------
curUV = dec_picture->imgUV[uv];
if (!smb && (currMB->cbp>>4))
{
if (currMB->is_lossless == FALSE)
{
const h264_short_block_t *blocks = currSlice->cof4[pl];
h264_imgpel_macroblock_row_t *mb_rec = currSlice->mb_rec[pl];
opt_itrans4x4(blocks[0], mb_pred, mb_rec, 0, 0);
opt_itrans4x4(blocks[1], mb_pred, mb_rec, 4, 0);
opt_itrans4x4(blocks[2], mb_pred, mb_rec, 0, 4);
opt_itrans4x4(blocks[3], mb_pred, mb_rec, 4, 4);
copy_image_data_8x8_stride(curUV,currMB->pix_c_x, currMB->pix_c_y, mb_rec);
}
else
{ // lossless
const h264_short_block_t *blocks = currSlice->cof4[pl];
h264_imgpel_macroblock_row_t *mb_rec = currSlice->mb_rec[pl];
itrans4x4_ls(blocks[0], mb_pred, mb_rec, 0, 0);
itrans4x4_ls(blocks[1], mb_pred, mb_rec, 4, 0);
itrans4x4_ls(blocks[2], mb_pred, mb_rec, 0, 4);
itrans4x4_ls(blocks[3], mb_pred, mb_rec, 4, 4);
copy_image_data_8x8_stride(curUV,currMB->pix_c_x, currMB->pix_c_y, mb_rec);
}
}
else if (smb)
{
const h264_short_block_t *blocks = currSlice->cof4[pl];
h264_imgpel_macroblock_row_t *mb_rec = currSlice->mb_rec[pl];
itrans_sp_cr(currMB, uv);
opt_itrans4x4(blocks[0], mb_pred, mb_rec, 0, 0);
opt_itrans4x4(blocks[1], mb_pred, mb_rec, 4, 0);
opt_itrans4x4(blocks[2], mb_pred, mb_rec, 0, 4);
opt_itrans4x4(blocks[3], mb_pred, mb_rec, 4, 4);
copy_image_data_8x8_stride(curUV,currMB->pix_c_x, currMB->pix_c_y, mb_rec);
}
else
{
copy_image_data_8x8_stride(curUV,currMB->pix_c_x, currMB->pix_c_y, mb_pred);
}
}
}
else if (dec_picture->chroma_format_idc == YUV422)
{
VideoImage *curUV;
for(uv=0;uv<2;++uv)
{
// =============== 4x4 itrans ================
// -------------------------------------------
int pl = uv + 1;
const h264_imgpel_macroblock_row_t *mb_pred=currSlice->mb_pred[pl];
curUV = dec_picture->imgUV[uv];
if (!smb && (currMB->cbp>>4))
{
h264_imgpel_macroblock_row_t *mb_rec = currSlice->mb_rec[pl];
const h264_short_block_t *blocks = currSlice->cof4[pl];
opt_itrans4x4(blocks[0], mb_pred, mb_rec, 0, 0);
opt_itrans4x4(blocks[1], mb_pred, mb_rec, 4, 0);
opt_itrans4x4(blocks[2], mb_pred, mb_rec, 0, 4);
opt_itrans4x4(blocks[3], mb_pred, mb_rec, 4, 4);
opt_itrans4x4(blocks[8], mb_pred, mb_rec, 0, 8);
opt_itrans4x4(blocks[9], mb_pred, mb_rec, 4, 8);
opt_itrans4x4(blocks[10], mb_pred, mb_rec, 0, 12);
opt_itrans4x4(blocks[11], mb_pred, mb_rec, 4, 12);
copy_image_data_stride(curUV,currMB->pix_c_x, currMB->pix_c_y, mb_rec, 8, 16);
}
else if (smb)
{
const h264_short_block_t *blocks = currSlice->cof4[pl];
h264_imgpel_macroblock_row_t *mb_rec = currSlice->mb_rec[pl];
itrans_sp_cr(currMB, uv);
opt_itrans4x4(blocks[0], mb_pred, mb_rec, 0, 0);
opt_itrans4x4(blocks[1], mb_pred, mb_rec, 4, 0);
opt_itrans4x4(blocks[2], mb_pred, mb_rec, 0, 4);
opt_itrans4x4(blocks[3], mb_pred, mb_rec, 4, 4);
opt_itrans4x4(blocks[8], mb_pred, mb_rec, 0, 8);
opt_itrans4x4(blocks[9], mb_pred, mb_rec, 4, 8);
opt_itrans4x4(blocks[10], mb_pred, mb_rec, 0, 12);
opt_itrans4x4(blocks[11], mb_pred, mb_rec, 4, 12);
copy_image_data_stride(curUV,currMB->pix_c_x, currMB->pix_c_y, mb_rec, 8, 16);
}
else
{
copy_image_data_stride(curUV,currMB->pix_c_x, currMB->pix_c_y, mb_pred, 8, 16);
}
}
}
}
/*!
*************************************************************************************
* \brief
* Copy ImgPel Data from one structure to another (16x16)
*************************************************************************************
*/
void copy_image_data_16x16(imgpel **imgBuf1, imgpel **imgBuf2, int dest_x, int src_x)
{
int j;
for(j=0; j<MB_BLOCK_SIZE; ++j)
{
memcpy(&imgBuf1[j][dest_x], &imgBuf2[j][src_x], MB_BLOCK_SIZE * sizeof (imgpel));
}
}
/*!
*************************************************************************************
* \brief
* Copy ImgPel Data from one structure to another (16x16)
*************************************************************************************
*/
#ifdef _M_IX86
void copy_image_data_16x16_stride_sse(VideoImage *destination, int dest_x, int dest_y, const h264_imgpel_macroblock_t source)
{
ptrdiff_t destination_stride = destination->stride; // in case the compiler doesn't optimize this
imgpel *dest = destination->base_address + destination_stride * dest_y + dest_x;
_asm
{
mov eax, dest
mov ecx, destination_stride
mov edx, source;
movaps xmm0, 0[edx]
movaps xmm1, 16[edx]
movaps xmm2, 32[edx]
movaps xmm3, 64[edx]
movups [eax], xmm0 // dest[0]
movups [eax+ecx], xmm1 // dest[1]
movups [eax+2*ecx], xmm2 // dest[2]
movups [eax+4*ecx], xmm3 // dest[4]
movaps xmm0, 48[edx]
movaps xmm1, 96[edx]
lea eax, [eax+2*ecx] // dest = &dest[2]
movups [eax+ecx], xmm0 // dest[3]
movups [eax+4*ecx], xmm1 // dest[6]
movaps xmm0, 80[edx]
movaps xmm1, 128[edx]
lea eax, [eax+2*ecx] // dest = &dest[2] (dest[4] from start)
movups [eax+ecx], xmm0 // dest[5]
movups [eax+4*ecx], xmm1 // dest[8]
movaps xmm0, 112[edx]
movaps xmm1, 160[edx]
lea eax, [eax+2*ecx] // dest = &dest[2] (dest[6] from start)
movups [eax+ecx], xmm0 // dest[7]
movups [eax+4*ecx], xmm1 // dest[10]
movaps xmm0, 144[edx]
movaps xmm1, 192[edx]
lea eax, [eax+2*ecx] // dest = &dest[2] (dest[8] from start)
movups [eax+ecx], xmm0 // dest[9]
movups [eax+4*ecx], xmm1 // dest[12]
movaps xmm0, 176[edx]
movaps xmm1, 224[edx]
lea eax, [eax+2*ecx] // dest = &dest[2] (dest[10] from start)
movups [eax+ecx], xmm0 // dest[11]
movups [eax+4*ecx], xmm1 // dest[14]
movaps xmm0, 208[edx]
movaps xmm1, 240[edx]
lea eax, [eax+ecx] // dest = &dest[1] (dest[11] from start)
movups [eax+2*ecx], xmm0 // dest[13]
movups [eax+4*ecx], xmm1 // dest[15]
}
}
#endif
void copy_image_data_16x16_stride_c(VideoImage *destination, int dest_x, int dest_y, const h264_imgpel_macroblock_t source)
{
ptrdiff_t destination_stride = destination->stride; // in case the compiler doesn't optimize this
imgpel *dest = destination->base_address + destination_stride * dest_y + dest_x;
int j;
for(j=0; j<MB_BLOCK_SIZE; j++)
{
memcpy(dest, source[j], MB_BLOCK_SIZE * sizeof (imgpel));
dest+=destination_stride;
}
}
/*!
*************************************************************************************
* \brief
* Copy ImgPel Data from one structure to another (8x8)
*************************************************************************************
*/
void copy_image_data_8x8_stride2(VideoImage *destination, int dest_x, int dest_y, const h264_imgpel_macroblock_t imgBuf2, int src_x, int src_y)
{
#ifdef _M_IX86
ptrdiff_t destination_stride = destination->stride;
imgpel *dest = destination->base_address + destination_stride * dest_y + dest_x;
_asm
{
mov eax, src_y
shl eax, 4
add eax, src_x
add eax, imgBuf2
mov edx, dest
mov ecx, destination_stride
movq mm0, MMWORD PTR 0[eax]
movq mm1, MMWORD PTR 16[eax]
movq mm2, MMWORD PTR 32[eax]
movq mm3, MMWORD PTR 48[eax]
movq mm4, MMWORD PTR 64[eax]
movq mm5, MMWORD PTR 80[eax]
movq mm6, MMWORD PTR 96[eax]
movq mm7, MMWORD PTR 112[eax]
movntq [edx], mm0
movntq [edx+ecx], mm1
movntq [edx+2*ecx], mm2
movntq [edx+4*ecx], mm4
add edx, ecx
movntq 0[edx+2*ecx], mm3
movntq 0[edx+4*ecx], mm5
add edx, ecx
movntq 0[edx+4*ecx], mm6
add edx, ecx
movntq 0[edx+4*ecx], mm7
}
#else
ptrdiff_t destination_stride = destination->stride; // in case the compiler doesn't optimize this
imgpel *dest = destination->base_address + destination_stride * dest_y + dest_x;
int j;
for(j = 0; j < BLOCK_SIZE_8x8; ++j)
{
memcpy(dest, &imgBuf2[src_y+j][src_x], BLOCK_SIZE_8x8 * sizeof (imgpel));
dest+=destination_stride;
}
#endif
}
void copy_image_data_8x8_stride(VideoImage *destination, int dest_x, int dest_y, const h264_imgpel_macroblock_t imgBuf2)
{
#ifdef _M_IX86
ptrdiff_t destination_stride = destination->stride;
imgpel *dest = destination->base_address + destination_stride * dest_y + dest_x;
_asm
{
mov eax, imgBuf2
mov edx, dest
mov ecx, destination_stride
movq mm0, MMWORD PTR 0[eax]
movq mm1, MMWORD PTR 16[eax]
movq mm2, MMWORD PTR 32[eax]
movq mm3, MMWORD PTR 48[eax]
movq mm4, MMWORD PTR 64[eax]
movq mm5, MMWORD PTR 80[eax]
movq mm6, MMWORD PTR 96[eax]
movq mm7, MMWORD PTR 112[eax]
movntq [edx], mm0
movntq [edx+ecx], mm1
movntq [edx+2*ecx], mm2
movntq [edx+4*ecx], mm4
add edx, ecx
movntq 0[edx+2*ecx], mm3
movntq 0[edx+4*ecx], mm5
add edx, ecx
movntq 0[edx+4*ecx], mm6
add edx, ecx
movntq 0[edx+4*ecx], mm7
}
#else
ptrdiff_t destination_stride = destination->stride; // in case the compiler doesn't optimize this
imgpel *dest = destination->base_address + destination_stride * dest_y + dest_x;
int j;
for(j = 0; j < BLOCK_SIZE_8x8; ++j)
{
memcpy(dest, &imgBuf2[j][0], BLOCK_SIZE_8x8 * sizeof (imgpel));
dest+=destination_stride;
}
#endif
}
/*!
*************************************************************************************
* \brief
* Copy ImgPel Data from one structure to another (4x4)
*************************************************************************************
*/
void copy_image_data_4x4_stride(VideoImage *destination, int dest_x, int dest_y, const h264_imgpel_macroblock_t source, int src_x, int src_y)
{
ptrdiff_t destination_stride = destination->stride; // in case the compiler doesn't optimize this
imgpel *dest = destination->base_address + destination_stride * dest_y + dest_x;
h264_imgpel_macroblock_row_t *src = (h264_imgpel_macroblock_row_t *)source[src_y]; /* cast is for const */
int j;
for(j = 0; j < BLOCK_SIZE; ++j)
{
memcpy(dest, &src[j][src_x], BLOCK_SIZE * sizeof (imgpel));
dest+=destination_stride;
}
}
/*!
*************************************************************************************
* \brief
* Copy ImgPel Data from one structure to another (8x8)
*************************************************************************************
*/
void copy_image_data(imgpel **imgBuf1, imgpel **imgBuf2, int dest_x, int src_x, int width, int height)
{
int j;
for(j = 0; j < height; ++j)
{
memcpy(&imgBuf1[j][dest_x], &imgBuf2[j][src_x], width * sizeof (imgpel));
}
}
void copy_image_data_stride(VideoImage *destination, int dest_x, int dest_y, const h264_imgpel_macroblock_t imgBuf2, int width, int height)
{
ptrdiff_t destination_stride = destination->stride; // in case the compiler doesn't optimize this
imgpel *dest = destination->base_address + destination_stride * dest_y + dest_x;
#ifdef H264_IPP
IppiSize roi = {width,height};
ippiCopy_8u_C1R(imgBuf2[0], sizeof(imgBuf2[0]), dest, destination_stride, roi);
#else
int j;
for(j = 0; j < height; ++j)
{
memcpy(dest, imgBuf2[j], width * sizeof (imgpel));
dest+=destination_stride;
}
#endif
}