blob: 733d59f76b31281597c7526757751e1a68a98993 [file] [log] [blame]
/*!
*************************************************************************************
* \file mv-search.c
*
* \brief
* Motion Vector Search, unified for B and P Pictures
*
* \author
* Main contributors (see contributors.h for copyright, address and affiliation details)
* - Stephan Wenger <stewe@cs.tu-berlin.de>
* - Inge Lille-Langoy <inge.lille-langoy@telenor.com>
* - Rickard Sjoberg <rickard.sjoberg@era.ericsson.se>
* - Stephan Wenger <stewe@cs.tu-berlin.de>
* - Jani Lainema <jani.lainema@nokia.com>
* - Detlev Marpe <marpe@hhi.de>
* - Thomas Wedi <wedi@tnt.uni-hannover.de>
* - Heiko Schwarz <hschwarz@hhi.de>
* - Alexis Michael Tourapis <alexismt@ieee.org>
*
*************************************************************************************
*/
#include "contributors.h"
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <string.h>
#include <time.h>
#include <sys/timeb.h>
#include "global.h"
#include "image.h"
#include "mv-search.h"
#include "refbuf.h"
#include "memalloc.h"
#include "mb_access.h"
#include "macroblock.h"
// Motion estimation distortion header file
#include "me_distortion.h"
// Motion estimation search algorithms
#include "me_epzs.h"
#include "me_fullfast.h"
#include "me_fullsearch.h"
#include "me_umhex.h"
#include "me_umhexsmp.h"
// Statistics, temporary
int max_mvd;
short* spiral_search_x;
short* spiral_search_y;
short* spiral_hpel_search_x;
short* spiral_hpel_search_y;
int* mvbits;
int* refbits;
int* byte_abs;
int**** motion_cost;
int byte_abs_range;
static int diff [16];
static int diff64[64];
static imgpel orig_pic [768];
void SetMotionVectorPredictor (short pmv[2],
signed char **refPic,
short ***tmp_mv,
short ref_frame,
int list,
int block_x,
int block_y,
int blockshape_x,
int blockshape_y);
extern ColocatedParams *Co_located;
extern const short block_type_shift_factor[8];
/*!
************************************************************************
* \brief
* Set motion vector predictor
************************************************************************
*/
void SetMotionVectorPredictor (short pmv[2],
signed char **refPic,
short ***tmp_mv,
short ref_frame,
int list,
int block_x,
int block_y,
int blockshape_x,
int blockshape_y)
{
int mb_x = 4*block_x;
int mb_y = 4*block_y;
int mb_nr = img->current_mb_nr;
int mv_a, mv_b, mv_c, pred_vec=0;
int mvPredType, rFrameL, rFrameU, rFrameUR;
int hv;
PixelPos block_a, block_b, block_c, block_d;
getLuma4x4Neighbour(mb_nr, mb_x - 1, mb_y, &block_a);
getLuma4x4Neighbour(mb_nr, mb_x, mb_y - 1, &block_b);
getLuma4x4Neighbour(mb_nr, mb_x + blockshape_x, mb_y - 1, &block_c);
getLuma4x4Neighbour(mb_nr, mb_x - 1, mb_y - 1, &block_d);
if (mb_y > 0)
{
if (mb_x < 8) // first column of 8x8 blocks
{
if (mb_y==8)
{
if (blockshape_x == 16) block_c.available = 0;
}
else
{
if (mb_x+blockshape_x == 8) block_c.available = 0;
}
}
else
{
if (mb_x+blockshape_x == 16) block_c.available = 0;
}
}
if (!block_c.available)
{
block_c=block_d;
}
mvPredType = MVPRED_MEDIAN;
if (!img->MbaffFrameFlag)
{
rFrameL = block_a.available ? refPic[block_a.pos_y][block_a.pos_x] : -1;
rFrameU = block_b.available ? refPic[block_b.pos_y][block_b.pos_x] : -1;
rFrameUR = block_c.available ? refPic[block_c.pos_y][block_c.pos_x] : -1;
}
else
{
if (img->mb_data[img->current_mb_nr].mb_field)
{
rFrameL = block_a.available
? (img->mb_data[block_a.mb_addr].mb_field
? refPic[block_a.pos_y][block_a.pos_x]
: refPic[block_a.pos_y][block_a.pos_x] * 2) : -1;
rFrameU = block_b.available
? (img->mb_data[block_b.mb_addr].mb_field
? refPic[block_b.pos_y][block_b.pos_x]
: refPic[block_b.pos_y][block_b.pos_x] * 2) : -1;
rFrameUR = block_c.available
? (img->mb_data[block_c.mb_addr].mb_field
? refPic[block_c.pos_y][block_c.pos_x]
: refPic[block_c.pos_y][block_c.pos_x] * 2) : -1;
}
else
{
rFrameL = block_a.available
? (img->mb_data[block_a.mb_addr].mb_field
? refPic[block_a.pos_y][block_a.pos_x] >>1
: refPic[block_a.pos_y][block_a.pos_x]) : -1;
rFrameU = block_b.available
? (img->mb_data[block_b.mb_addr].mb_field
? refPic[block_b.pos_y][block_b.pos_x] >>1
: refPic[block_b.pos_y][block_b.pos_x]) : -1;
rFrameUR = block_c.available
? (img->mb_data[block_c.mb_addr].mb_field
? refPic[block_c.pos_y][block_c.pos_x] >>1
: refPic[block_c.pos_y][block_c.pos_x]) : -1;
}
}
/* Prediction if only one of the neighbors uses the reference frame
* we are checking
*/
if(rFrameL == ref_frame && rFrameU != ref_frame && rFrameUR != ref_frame) mvPredType = MVPRED_L;
else if(rFrameL != ref_frame && rFrameU == ref_frame && rFrameUR != ref_frame) mvPredType = MVPRED_U;
else if(rFrameL != ref_frame && rFrameU != ref_frame && rFrameUR == ref_frame) mvPredType = MVPRED_UR;
// Directional predictions
if(blockshape_x == 8 && blockshape_y == 16)
{
if(mb_x == 0)
{
if(rFrameL == ref_frame)
mvPredType = MVPRED_L;
}
else
{
if( rFrameUR == ref_frame)
mvPredType = MVPRED_UR;
}
}
else if(blockshape_x == 16 && blockshape_y == 8)
{
if(mb_y == 0)
{
if(rFrameU == ref_frame)
mvPredType = MVPRED_U;
}
else
{
if(rFrameL == ref_frame)
mvPredType = MVPRED_L;
}
}
for (hv=0; hv < 2; hv++)
{
if (!img->MbaffFrameFlag || hv==0)
{
mv_a = block_a.available ? tmp_mv[block_a.pos_y][block_a.pos_x][hv] : 0;
mv_b = block_b.available ? tmp_mv[block_b.pos_y][block_b.pos_x][hv] : 0;
mv_c = block_c.available ? tmp_mv[block_c.pos_y][block_c.pos_x][hv] : 0;
}
else
{
if (img->mb_data[img->current_mb_nr].mb_field)
{
mv_a = block_a.available ? img->mb_data[block_a.mb_addr].mb_field
? tmp_mv[block_a.pos_y][block_a.pos_x][hv]
: tmp_mv[block_a.pos_y][block_a.pos_x][hv] / 2
: 0;
mv_b = block_b.available ? img->mb_data[block_b.mb_addr].mb_field
? tmp_mv[block_b.pos_y][block_b.pos_x][hv]
: tmp_mv[block_b.pos_y][block_b.pos_x][hv] / 2
: 0;
mv_c = block_c.available ? img->mb_data[block_c.mb_addr].mb_field
? tmp_mv[block_c.pos_y][block_c.pos_x][hv]
: tmp_mv[block_c.pos_y][block_c.pos_x][hv] / 2
: 0;
}
else
{
mv_a = block_a.available ? img->mb_data[block_a.mb_addr].mb_field
? tmp_mv[block_a.pos_y][block_a.pos_x][hv] * 2
: tmp_mv[block_a.pos_y][block_a.pos_x][hv]
: 0;
mv_b = block_b.available ? img->mb_data[block_b.mb_addr].mb_field
? tmp_mv[block_b.pos_y][block_b.pos_x][hv] * 2
: tmp_mv[block_b.pos_y][block_b.pos_x][hv]
: 0;
mv_c = block_c.available ? img->mb_data[block_c.mb_addr].mb_field
? tmp_mv[block_c.pos_y][block_c.pos_x][hv] * 2
: tmp_mv[block_c.pos_y][block_c.pos_x][hv]
: 0;
}
}
switch (mvPredType)
{
case MVPRED_MEDIAN:
if(!(block_b.available || block_c.available))
{
pred_vec = mv_a;
}
else
{
pred_vec = mv_a+mv_b+mv_c-imin(mv_a,imin(mv_b,mv_c))-imax(mv_a,imax(mv_b,mv_c));
}
break;
case MVPRED_L:
pred_vec = mv_a;
break;
case MVPRED_U:
pred_vec = mv_b;
break;
case MVPRED_UR:
pred_vec = mv_c;
break;
default:
break;
}
pmv[hv] = pred_vec;
}
}
/*!
************************************************************************
* \brief
* Initialize the motion search
************************************************************************
*/
void
Init_Motion_Search_Module ()
{
int bits, i_min, i_max, k;
int i, l;
int search_range = input->search_range;
int max_search_points = imax(9, (2*search_range+1)*(2*search_range+1));
int max_ref_bits = 1 + 2 * (int)floor(log(imax(16,img->max_num_references+1)) / log(2) + 1e-10);
int max_ref = (1<<((max_ref_bits>>1)+1))-1;
int number_of_subpel_positions = 4 * (2*search_range+3);
int max_mv_bits = 3 + 2 * (int)ceil (log(number_of_subpel_positions+1) / log(2) + 1e-10);
max_mvd = (1<<( max_mv_bits >>1) )-1;
byte_abs_range = (img->max_imgpel_value > img->max_imgpel_value_uv) ? (img->max_imgpel_value + 1) * 64 : (img->max_imgpel_value_uv + 1) * 64;
//===== CREATE ARRAYS =====
//-----------------------------
if ((spiral_search_x = (short*)calloc(max_search_points, sizeof(short))) == NULL)
no_mem_exit("Init_Motion_Search_Module: spiral_search_x");
if ((spiral_search_y = (short*)calloc(max_search_points, sizeof(short))) == NULL)
no_mem_exit("Init_Motion_Search_Module: spiral_search_y");
if ((spiral_hpel_search_x = (short*)calloc(max_search_points, sizeof(short))) == NULL)
no_mem_exit("Init_Motion_Search_Module: spiral_hpel_search_x");
if ((spiral_hpel_search_y = (short*)calloc(max_search_points, sizeof(short))) == NULL)
no_mem_exit("Init_Motion_Search_Module: spiral_hpel_search_y");
if ((mvbits = (int*)calloc(2*max_mvd+1, sizeof(int))) == NULL)
no_mem_exit("Init_Motion_Search_Module: mvbits");
if ((refbits = (int*)calloc(max_ref, sizeof(int))) == NULL)
no_mem_exit("Init_Motion_Search_Module: refbits");
if ((byte_abs = (int*)calloc(byte_abs_range, sizeof(int))) == NULL)
no_mem_exit("Init_Motion_Search_Module: byte_abs");
get_mem4Dint (&motion_cost, 8, 2, img->max_num_references, 4);
//--- set array offsets ---
mvbits += max_mvd;
byte_abs += byte_abs_range/2;
//===== INIT ARRAYS =====
//---------------------------
//--- init array: motion vector bits ---
mvbits[0] = 1;
for (bits=3; bits<=max_mv_bits; bits+=2)
{
i_max = 1 << (bits >> 1);
i_min = i_max >> 1;
for (i = i_min; i < i_max; i++)
mvbits[-i] = mvbits[i] = bits;
}
//--- init array: reference frame bits ---
refbits[0] = 1;
for (bits=3; bits<=max_ref_bits; bits+=2)
{
i_max = (1 << ((bits >> 1) + 1)) - 1;
i_min = i_max >> 1;
for (i = i_min; i < i_max; i++)
refbits[i] = bits;
}
//--- init array: absolute value ---
byte_abs[0] = 0;
// Set scaler for integer/subpel motion refinement.
// Currently only EPZS supports subpel positions
for (i=1; i<byte_abs_range/2; i++)
{
byte_abs[i] = byte_abs[-i] = i;
}
//--- init array: search pattern ---
spiral_search_x[0] = spiral_search_y[0] = 0;
spiral_hpel_search_x[0] = spiral_hpel_search_y[0] = 0;
for (k=1, l=1; l <= imax(1,search_range); l++)
{
for (i=-l+1; i< l; i++)
{
spiral_search_x[k] = i;
spiral_search_y[k] = -l;
spiral_hpel_search_x[k] = i<<1;
spiral_hpel_search_y[k++] = -l<<1;
spiral_search_x[k] = i;
spiral_search_y[k] = l;
spiral_hpel_search_x[k] = i<<1;
spiral_hpel_search_y[k++] = l<<1;
}
for (i=-l; i<=l; i++)
{
spiral_search_x[k] = -l;
spiral_search_y[k] = i;
spiral_hpel_search_x[k] = -l<<1;
spiral_hpel_search_y[k++] = i<<1;
spiral_search_x[k] = l;
spiral_search_y[k] = i;
spiral_hpel_search_x[k] = l<<1;
spiral_hpel_search_y[k++] = i<<1;
}
}
// set global variable prior to ME
start_me_refinement_hp = (input->ChromaMEEnable == 1 || input->MEErrorMetric[F_PEL] != input->MEErrorMetric[H_PEL] ) ? 0 : 1;
start_me_refinement_qp = (input->ChromaMEEnable == 1 || input->MEErrorMetric[H_PEL] != input->MEErrorMetric[Q_PEL] ) ? 0 : 1;
// Setup Distortion Metrics depending on refinement level
for (i=0; i<3; i++)
{
switch(input->MEErrorMetric[i])
{
case ERROR_SAD:
computeUniPred[i] = computeSAD;
computeUniPred[i + 3] = computeSADWP;
computeBiPred1[i] = computeBiPredSAD1;
computeBiPred2[i] = computeBiPredSAD2;
break;
case ERROR_SSE:
computeUniPred[i] = computeSSE;
computeUniPred[i + 3] = computeSSEWP;
computeBiPred1[i] = computeBiPredSSE1;
computeBiPred2[i] = computeBiPredSSE2;
break;
case ERROR_SATD :
default:
computeUniPred[i] = computeSATD;
computeUniPred[i + 3] = computeSATDWP;
computeBiPred1[i] = computeBiPredSATD1;
computeBiPred2[i] = computeBiPredSATD2;
break;
}
}
// Setup buffer access methods
get_line[0] = FastLine4X;
get_line[1] = UMVLine4X;
get_crline[0] = FastLine8X_chroma;
get_crline[1] = UMVLine8X_chroma;
if(input->SearchMode == FAST_FULL_SEARCH)
InitializeFastFullIntegerSearch ();
}
/*!
************************************************************************
* \brief
* Free memory used by motion search
************************************************************************
*/
void
Clear_Motion_Search_Module ()
{
//--- correct array offset ---
mvbits -= max_mvd;
byte_abs -= byte_abs_range/2;
//--- delete arrays ---
free (spiral_search_x);
free (spiral_search_y);
free (spiral_hpel_search_x);
free (spiral_hpel_search_y);
free (mvbits);
free (refbits);
free (byte_abs);
free_mem4Dint (motion_cost, 8, 2);
if(input->SearchMode == FAST_FULL_SEARCH)
ClearFastFullIntegerSearch ();
}
/*!
***********************************************************************
* \brief
* Motion Cost for Bidirectional modes
***********************************************************************
*/
int BPredPartitionCost (int blocktype,
int block8x8,
short ref_l0,
short ref_l1,
int lambda_factor,
int list)
{
static int bx0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,2,0,2}};
static int by0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,0,0,0}, {0,0,2,2}};
int curr_blk[MB_BLOCK_SIZE][MB_BLOCK_SIZE]; // ABT pred.error buffer
int bsx = imin(input->blc_size[blocktype][0],8);
int bsy = imin(input->blc_size[blocktype][1],8);
int pic_pix_x, pic_pix_y, block_x, block_y;
int v, h, mcost, i, j, k;
int mvd_bits = 0;
int parttype = (blocktype<4?blocktype:4);
int step_h0 = (input->part_size[ parttype][0]);
int step_v0 = (input->part_size[ parttype][1]);
int step_h = (input->part_size[blocktype][0]);
int step_v = (input->part_size[blocktype][1]);
int bxx, byy; // indexing curr_blk
short ******all_mv = list ? img->bipred_mv1 : img->bipred_mv2;
short ****** p_mv = img->pred_mv;
for (v=by0[parttype][block8x8]; v<by0[parttype][block8x8]+step_v0; v+=step_v)
{
for (h=bx0[parttype][block8x8]; h<bx0[parttype][block8x8]+step_h0; h+=step_h)
{
mvd_bits += mvbits[ all_mv [v][h][LIST_0][ref_l0][blocktype][0] - p_mv[v][h][LIST_0][ref_l0][blocktype][0] ];
mvd_bits += mvbits[ all_mv [v][h][LIST_0][ref_l0][blocktype][1] - p_mv[v][h][LIST_0][ref_l0][blocktype][1] ];
mvd_bits += mvbits[ all_mv [v][h][LIST_1][ref_l1][blocktype][0] - p_mv[v][h][LIST_1][ref_l1][blocktype][0] ];
mvd_bits += mvbits[ all_mv [v][h][LIST_1][ref_l1][blocktype][1] - p_mv[v][h][LIST_1][ref_l1][blocktype][1] ];
}
}
mcost = WEIGHTED_COST (lambda_factor, mvd_bits);
//----- cost of residual signal -----
for (byy=0, v=by0[parttype][block8x8]; v<by0[parttype][block8x8]+step_v0; byy+=4, v++)
{
pic_pix_y = img->opix_y + (block_y = (v<<2));
for (bxx=0, h=bx0[parttype][block8x8]; h<bx0[parttype][block8x8]+step_h0; bxx+=4, h++)
{
pic_pix_x = img->opix_x + (block_x = (h<<2));
LumaPrediction4x4Bi (block_x, block_y, blocktype, blocktype, ref_l0, ref_l1, list);
for (k=j=0; j<4; j++)
{
for ( i=0; i<4; i++)
diff64[k++] = curr_blk[byy+j][bxx+i] =
imgY_org[pic_pix_y+j][pic_pix_x+i] - img->mpr[j+block_y][i+block_x];
}
if ((!input->Transform8x8Mode) || (blocktype>4))
{
mcost += distortion4x4 (diff64);
}
}
}
if (input->Transform8x8Mode && (blocktype<=4)) // tchen 4-29-04
{
for (byy=0; byy < input->blc_size[parttype][1]; byy+=bsy)
for (bxx=0; bxx<input->blc_size[parttype][0]; bxx+=bsx)
{
for (k=0, j=byy;j<byy + 8;j++, k += 8)
memcpy(&diff64[k], &(curr_blk[j][bxx]), 8 * sizeof(int));
mcost += distortion8x8(diff64);
}
}
return mcost;
}
/*!
***********************************************************************
* \brief
* Block motion search
***********************************************************************
*/
int //!< minimum motion cost after search
BlockMotionSearch (short ref, //!< reference idx
int list, //!< reference pciture list
int mb_x, //!< x-coordinate inside macroblock
int mb_y, //!< y-coordinate inside macroblock
int blocktype, //!< block type (1-16x16 ... 7-4x4)
int search_range, //!< 1-d search range for integer-position search
int* lambda_factor) //!< lagrangian parameter for determining motion cost
{
// each 48-pel line stores the 16 luma pels (at 0) followed by 8 or 16 crcb[0] (at 16) and crcb[1] (at 32) pels
// depending on the type of chroma subsampling used: YUV 4:4:4, 4:2:2, and 4:2:0
imgpel *orig_pic_tmp = orig_pic;
short mv[2];
int i, j;
int max_value = INT_MAX;
int min_mcost = max_value;
int block_x = (mb_x>>2);
int block_y = (mb_y>>2);
int bsx = input->blc_size[blocktype][0];
int bsy = input->blc_size[blocktype][1];
int pic_pix_x = img->opix_x + mb_x;
int pic_pix_y = img->opix_y + mb_y;
int pic_pix_x_c = pic_pix_x >> (chroma_shift_x - 2);
int pic_pix_y_c = pic_pix_y >> (chroma_shift_y - 2);
int bsx_c = bsx >> (chroma_shift_x - 2);
int bsy_c = bsy >> (chroma_shift_y - 2);
short* pred_mv = img->pred_mv[block_y][block_x][list][ref][blocktype];
short****** all_mv = img->all_mv;
int list_offset = ((img->MbaffFrameFlag) && (img->mb_data[img->current_mb_nr].mb_field)) ? img->current_mb_nr % 2 ? 4 : 2 : 0;
int *prevSad = (input->SearchMode == EPZS)? EPZSDistortion[list + list_offset][blocktype - 1]: NULL;
#if GET_METIME
static struct TIMEB tstruct1;
static struct TIMEB tstruct2;
time_t me_tmp_time;
ftime( &tstruct1 ); // start time ms
#endif
//==================================
//===== GET ORIGINAL BLOCK =====
//==================================
for (j = 0; j < bsy; j++)
{
memcpy(orig_pic_tmp,&imgY_org[pic_pix_y+j][pic_pix_x], bsx *sizeof(imgpel));
orig_pic_tmp += bsx;
}
ChromaMEEnable = input->ChromaMEEnable;
if ( ChromaMEEnable )
{
// copy the original cmp1 and cmp2 data to the orig_pic matrix
orig_pic_tmp = orig_pic + 256;
for (j = 0; j < bsy_c; j++)
{
memcpy(orig_pic_tmp, &(imgUV_org[0][pic_pix_y_c+j][pic_pix_x_c]), bsx_c *sizeof(imgpel));
orig_pic_tmp += bsx_c;
}
orig_pic_tmp = orig_pic + 512;
for (j = 0; j < bsy_c; j++)
{
memcpy(orig_pic_tmp, &(imgUV_org[1][pic_pix_y_c+j][pic_pix_x_c]), bsx_c *sizeof(imgpel));
orig_pic_tmp += bsx_c;
}
}
if(input->SearchMode == UM_HEX)
{
UMHEX_blocktype = blocktype;
bipred_flag = 0;
}
else if (input->SearchMode == UM_HEX_SIMPLE)
{
smpUMHEX_setup(ref, list, block_y, block_x, blocktype, all_mv );
}
// Set if 8x8 transform will be used if SATD is used
test8x8transform = input->Transform8x8Mode && blocktype <= 4;
//===========================================
//===== GET MOTION VECTOR PREDICTOR =====
//===========================================
if (input->SearchMode == UM_HEX)
UMHEXSetMotionVectorPredictor(pred_mv, enc_picture->ref_idx[list], enc_picture->mv[list], ref, list, block_x, block_y, bsx, bsy, &search_range);
else
SetMotionVectorPredictor (pred_mv, enc_picture->ref_idx[list], enc_picture->mv[list], ref, list, block_x, block_y, bsx, bsy);
//==================================
//===== INTEGER-PEL SEARCH =====
//==================================
if (input->SearchMode == UM_HEX)
{
mv[0] = pred_mv[0] / 4;
mv[1] = pred_mv[1] / 4;
if (!input->rdopt)
{
//--- adjust search center so that the (0,0)-vector is inside ---
mv[0] = iClip3(-search_range, search_range, mv[0]);
mv[1] = iClip3(-search_range, search_range, mv[1]);
}
mv[0] = iClip3(-2047 + search_range, 2047 - search_range, mv[0]);
mv[1] = iClip3(LEVELMVLIMIT[img->LevelIndex][0] + search_range, LEVELMVLIMIT[img->LevelIndex][1] - search_range, mv[1]);
min_mcost = UMHEXIntegerPelBlockMotionSearch(orig_pic, ref, list, pic_pix_x, pic_pix_y, blocktype,
pred_mv[0], pred_mv[1], &mv[0], &mv[1], search_range,
min_mcost, lambda_factor[F_PEL]);
}
else if (input->SearchMode == UM_HEX_SIMPLE)
{
mv[0] = pred_mv[0] / 4;
mv[1] = pred_mv[1] / 4;
if (!input->rdopt)
{
//--- adjust search center so that the (0,0)-vector is inside ---
mv[0] = iClip3(-search_range, search_range, mv[0]);
mv[1] = iClip3(-search_range, search_range, mv[1]);
}
mv[0] = iClip3(-2047 + search_range, 2047 - search_range, mv[0]);
mv[1] = iClip3(LEVELMVLIMIT[img->LevelIndex][0] + search_range, LEVELMVLIMIT[img->LevelIndex][1] - search_range, mv[1]);
min_mcost = smpUMHEXIntegerPelBlockMotionSearch (orig_pic, ref, list, pic_pix_x, pic_pix_y, blocktype,
pred_mv[0], pred_mv[1], &mv[0], &mv[1], search_range,
min_mcost, lambda_factor[F_PEL]);
for (i=0; i < (bsx>>2); i++)
{
for (j=0; j < (bsy>>2); j++)
{
if(list == 0)
{
smpUMHEX_l0_cost[blocktype][(img->pix_y>>2)+block_y+j][(img->pix_x>>2)+block_x+i] = min_mcost;
}
else
{
smpUMHEX_l1_cost[blocktype][(img->pix_y>>2)+block_y+j][(img->pix_x>>2)+block_x+i] = min_mcost;
}
}
}
}
//--- perform motion search using EPZS schemes---
else if (input->SearchMode == EPZS)
{
//--- set search center ---
// This has to be modified in the future
if (input->EPZSSubPelGrid)
{
mv[0] = pred_mv[0];
mv[1] = pred_mv[1];
}
else
{
mv[0] = (pred_mv[0] + 2)>> 2;
mv[1] = (pred_mv[1] + 2)>> 2;
}
if (!input->rdopt)
{
//--- adjust search center so that the (0,0)-vector is inside ---
mv[0] = iClip3 (-search_range<<(input->EPZSSubPelGrid * 2), search_range<<(input->EPZSSubPelGrid * 2), mv[0]);
mv[1] = iClip3 (-search_range<<(input->EPZSSubPelGrid * 2), search_range<<(input->EPZSSubPelGrid * 2), mv[1]);
}
// valid search range limits could be precomputed once during the initialization process
mv[0] = iClip3((-2047 + search_range)<<(input->EPZSSubPelGrid * 2), (2047 - search_range)<<(input->EPZSSubPelGrid * 2), mv[0]);
mv[1] = iClip3((LEVELMVLIMIT[img->LevelIndex][0] + search_range)<<(input->EPZSSubPelGrid * 2),
(LEVELMVLIMIT[img->LevelIndex][1] - search_range)<<(input->EPZSSubPelGrid * 2), mv[1]);
min_mcost = EPZSPelBlockMotionSearch (orig_pic, ref, list, list_offset,
enc_picture->ref_idx, enc_picture->mv, pic_pix_x, pic_pix_y, blocktype,
pred_mv, mv, search_range<<(input->EPZSSubPelGrid * 2), min_mcost, lambda_factor[F_PEL]);
}
else if (input->SearchMode == FAST_FULL_SEARCH)
{
// comments: - orig_pic is not used -> be careful
// - search center is automatically determined
min_mcost = FastFullPelBlockMotionSearch (orig_pic, ref, list, pic_pix_x, pic_pix_y, blocktype,
pred_mv[0], pred_mv[1], &mv[0], &mv[1], search_range,
min_mcost, lambda_factor[F_PEL]);
}
else
{
//--- set search center ---
mv[0] = pred_mv[0] / 4;
mv[1] = pred_mv[1] / 4;
if (!input->rdopt)
{
//--- adjust search center so that the (0,0)-vector is inside ---
mv[0] = iClip3 (-search_range, search_range, mv[0]);
mv[1] = iClip3 (-search_range, search_range, mv[1]);
}
mv[0] = iClip3(-2047 + search_range, 2047 - search_range, mv[0]);
mv[1] = iClip3(LEVELMVLIMIT[img->LevelIndex][0] + search_range, LEVELMVLIMIT[img->LevelIndex][1] - search_range, mv[1]);
//--- perform motion search ---
min_mcost = FullPelBlockMotionSearch (orig_pic, ref, list, pic_pix_x, pic_pix_y, blocktype,
pred_mv[0], pred_mv[1], &mv[0], &mv[1], search_range,
min_mcost, lambda_factor[F_PEL]);
}
//===== convert search center to quarter-pel units =====
if (input->EPZSSubPelGrid == 0 || input->SearchMode != EPZS)
{
mv[0] <<= 2;
mv[1] <<= 2;
}
//==============================
//===== SUB-PEL SEARCH =====
//==============================
ChromaMEEnable = (input->ChromaMEEnable == ME_YUV_FP_SP ) ? 1 : 0; // set it externally
if (!input->DisableSubpelME)
{
if (input->SearchMode != EPZS || (ref == 0 || img->structure != FRAME || (ref > 0 && min_mcost < 3.5 * prevSad[pic_pix_x >> 2])))
{
if ( !start_me_refinement_hp )
{
min_mcost = max_value;
}
if (input->SearchMode == UM_HEX)
{
if(blocktype >3)
{
min_mcost = UMHEXSubPelBlockMotionSearch (orig_pic, ref, list, pic_pix_x, pic_pix_y, blocktype,
pred_mv[0], pred_mv[1], &mv[0], &mv[1], 9, 9, min_mcost, lambda_factor[Q_PEL]);
}
else
{
min_mcost = SubPelBlockMotionSearch (orig_pic, ref, list, pic_pix_x, pic_pix_y, blocktype,
pred_mv[0], pred_mv[1], &mv[0], &mv[1], 9, 9, min_mcost, lambda_factor);
}
}
else if (input->SearchMode == UM_HEX_SIMPLE)
{
if(blocktype > 1)
{
min_mcost = smpUMHEXSubPelBlockMotionSearch (orig_pic, ref, list, pic_pix_x, pic_pix_y,
blocktype, pred_mv[0], pred_mv[1], &mv[0], &mv[1], 9, 9, min_mcost, lambda_factor[Q_PEL]);
}
else
{
min_mcost = smpUMHEXFullSubPelBlockMotionSearch (orig_pic, ref, list, pic_pix_x, pic_pix_y,
blocktype, pred_mv[0], pred_mv[1], &mv[0], &mv[1], 9, 9, min_mcost, lambda_factor[Q_PEL]);
}
}
else if (input->SearchMode == EPZS && input->EPZSSubPelME)
{
min_mcost = EPZSSubPelBlockMotionSearch (orig_pic, ref, list, pic_pix_x, pic_pix_y, blocktype,
pred_mv, mv, 9, 9, min_mcost, lambda_factor);
}
else
{
min_mcost = SubPelBlockMotionSearch (orig_pic, ref, list, pic_pix_x, pic_pix_y, blocktype,
pred_mv[0], pred_mv[1], &mv[0], &mv[1], 9, 9, min_mcost, lambda_factor);
}
}
}
if (!input->rdopt)
{
// Get the skip mode cost
if (blocktype == 1 && (img->type == P_SLICE||img->type == SP_SLICE))
{
int cost;
FindSkipModeMotionVector ();
cost = GetSkipCostMB ();
cost -= ((lambda_factor[Q_PEL] + 4096) >> 13);
if (cost < min_mcost)
{
min_mcost = cost;
mv[0] = img->all_mv [0][0][0][0][0][0];
mv[1] = img->all_mv [0][0][0][0][0][1];
}
}
}
//===============================================
//===== SET MV'S AND RETURN MOTION COST =====
//===============================================
for (j=block_y; j < block_y + (bsy>>2); j++)
{
for (i=block_x; i < block_x + (bsx>>2); i++)
{
all_mv[j][i][list][ref][blocktype][0] = mv[0];
all_mv[j][i][list][ref][blocktype][1] = mv[1];
}
}
if (img->type==B_SLICE && input->BiPredMotionEstimation!=0 && (blocktype == 1) && (ref==0))
{
short ******bipred_mv = list ? img->bipred_mv1 : img->bipred_mv2;
int min_mcostbi = max_value;
short bimv[2] = {0, 0}, tempmv[2] = {0, 0};
short *pred_mv1 = NULL;
short *pred_mv2 = NULL;
short iterlist=list;
short pred_mv_bi[2];
if (input->SearchMode == UM_HEX)
{
bipred_flag = 1;
UMHEXSetMotionVectorPredictor(pred_mv_bi, enc_picture->ref_idx[list ^ 1], enc_picture->mv[(list == LIST_0? LIST_1: LIST_0)], 0, (list == LIST_0? LIST_1: LIST_0), block_x, block_y, bsx, bsy, &search_range);
}
else
SetMotionVectorPredictor (pred_mv_bi, enc_picture->ref_idx[list ^ 1], enc_picture->mv[(list == LIST_0? LIST_1: LIST_0)], 0, (list == LIST_0? LIST_1: LIST_0), block_x, block_y, bsx, bsy);
if ((input->SearchMode != EPZS) || (input->EPZSSubPelGrid == 0))
{
mv[0]=(mv[0] + 2)>>2;
mv[1]=(mv[1] + 2)>>2;
}
//Bi-predictive motion Refinements
for (i=0;i<=input->BiPredMERefinements;i++)
{
if (i%2)
{
pred_mv2=pred_mv;
pred_mv1=pred_mv_bi;
tempmv[0]=bimv[0];
tempmv[1]=bimv[1];
bimv[0]=mv[0];
bimv[1]=mv[1];
iterlist= list ^ 1;
}
else
{
pred_mv1=pred_mv;
pred_mv2=pred_mv_bi;
if (i!=0)
{
tempmv[0]=bimv[0];
tempmv[1]=bimv[1];
bimv[0]=mv[0];
bimv[1]=mv[1];
}
else
{
tempmv[0]=mv[0];
tempmv[1]=mv[1];
if ((input->SearchMode != EPZS) || (input->EPZSSubPelGrid == 0))
{
bimv[0] = (pred_mv2[0] + 2)>>2;
bimv[1] = (pred_mv2[1] + 2)>>2;
}
else
{
bimv[0] = pred_mv2[0];
bimv[1] = pred_mv2[1];
}
}
iterlist=list;
}
mv[0]=bimv[0];
mv[1]=bimv[1];
if (input->SearchMode == EPZS)
{
min_mcostbi = EPZSBiPredBlockMotionSearch (orig_pic, ref, iterlist,
list_offset, enc_picture->ref_idx, enc_picture->mv,
pic_pix_x, pic_pix_y, blocktype,
pred_mv1, pred_mv2, bimv, tempmv,
(input->BiPredMESearchRange<<(input->EPZSSubPelGrid * 2))>>i, min_mcostbi, lambda_factor[F_PEL]);
}
else if(input->SearchMode == UM_HEX)
{
min_mcostbi = UMHEXBipredIntegerPelBlockMotionSearch (orig_pic, ref, iterlist,
pic_pix_x, pic_pix_y, blocktype,
pred_mv1[0], pred_mv1[1], pred_mv2[0], pred_mv2[1],
&bimv[0], &bimv[1], &tempmv[0], &tempmv[1],
input->BiPredMESearchRange>>i, min_mcostbi, lambda_factor[F_PEL]);
}
else if(input->SearchMode == UM_HEX_SIMPLE)
{
min_mcostbi = smpUMHEXBipredIntegerPelBlockMotionSearch (orig_pic, ref, iterlist,
pic_pix_x, pic_pix_y, blocktype,
pred_mv[0], pred_mv[1], pred_mv[0], pred_mv[1],
&bimv[0], &bimv[1], &tempmv[0], &tempmv[1],
input->BiPredMESearchRange>>i, min_mcostbi, lambda_factor[F_PEL]);
}
else
{
min_mcostbi = FullPelBlockMotionBiPred (orig_pic, ref, iterlist,
pic_pix_x, pic_pix_y, blocktype,
pred_mv1[0], pred_mv1[1], pred_mv2[0], pred_mv2[1],
&bimv[0], &bimv[1], &tempmv[0], &tempmv[1],
input->BiPredMESearchRange>>i, min_mcostbi, lambda_factor[F_PEL]);
}
if ((mv[0] == bimv[0]) && (mv[1] == bimv[1]))
{
//mv[0]=tempmv[0];
//mv[1]=tempmv[1];
//break;
}
mv[0]=tempmv[0];
mv[1]=tempmv[1];
}
if ((input->SearchMode != EPZS) || (input->EPZSSubPelGrid == 0))
{
mv[0]=tempmv[0] << 2;
mv[1]=tempmv[1] << 2;
bimv[0] = bimv[0] << 2;
bimv[1] = bimv[1] << 2;
}
if (input->BiPredMESubPel && !input->DisableSubpelME)
{
if ( !start_me_refinement_hp )
{
min_mcostbi = max_value;
}
if (input->SearchMode == EPZS && input->EPZSSubPelMEBiPred)
{
min_mcostbi = EPZSSubPelBlockSearchBiPred (orig_pic, ref, iterlist, pic_pix_x, pic_pix_y, blocktype,
pred_mv2, pred_mv1, bimv, mv, 9, 9, min_mcostbi, lambda_factor);
}
else
{
min_mcostbi = SubPelBlockSearchBiPred (orig_pic, ref, iterlist, pic_pix_x, pic_pix_y, blocktype,
pred_mv2[0], pred_mv2[1], &bimv[0], &bimv[1], &mv[0], &mv[1], 9, 9,
min_mcostbi, lambda_factor);
}
}
if (input->BiPredMESubPel==2 && !input->DisableSubpelME)
{
if ( !start_me_refinement_hp || !start_me_refinement_qp)
{
min_mcostbi = max_value;
}
if (input->SearchMode == EPZS && input->EPZSSubPelMEBiPred)
{
min_mcostbi = EPZSSubPelBlockSearchBiPred (orig_pic, ref, iterlist ^ 1, pic_pix_x, pic_pix_y, blocktype,
pred_mv1, pred_mv2, mv, bimv, 9, 9, min_mcostbi, lambda_factor);
}
else
{
min_mcostbi = SubPelBlockSearchBiPred (orig_pic, ref, iterlist ^ 1, pic_pix_x, pic_pix_y, blocktype,
pred_mv1[0], pred_mv1[1], &mv[0], &mv[1], &bimv[0], &bimv[1], 9, 9,
min_mcostbi, lambda_factor);
}
}
for (j=block_y; j < block_y + (bsy>>2); j++)
{
for (i=block_x ; i < block_x + (bsx>>2); i++)
{
bipred_mv[j][i][iterlist ][0][blocktype][0] = mv[0];
bipred_mv[j][i][iterlist ][0][blocktype][1] = mv[1];
bipred_mv[j][i][iterlist ^ 1][0][blocktype][0] = bimv[0];
bipred_mv[j][i][iterlist ^ 1][0][blocktype][1] = bimv[1];
}
}
}
#if GET_METIME
ftime(&tstruct2); // end time ms
me_tmp_time=(tstruct2.time*1000+tstruct2.millitm) - (tstruct1.time*1000+tstruct1.millitm);
me_tot_time += me_tmp_time;
me_time += me_tmp_time;
#endif
return min_mcost;
}
/*!
***********************************************************************
* \brief
* Motion Cost for Bidirectional modes
***********************************************************************
*/
int BIDPartitionCost (int blocktype,
int block8x8,
short ref_l0,
short ref_l1,
int lambda_factor)
{
static int bx0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,2,0,2}};
static int by0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,0,0,0}, {0,0,2,2}};
int curr_blk[MB_BLOCK_SIZE][MB_BLOCK_SIZE]; // ABT pred.error buffer
int bsx = imin(input->blc_size[blocktype][0],8);
int bsy = imin(input->blc_size[blocktype][1],8);
int pic_pix_x, pic_pix_y, block_x, block_y;
int v, h, mcost, i, j, k;
int mvd_bits = 0;
int parttype = (blocktype<4?blocktype:4);
int step_h0 = (input->part_size[ parttype][0]);
int step_v0 = (input->part_size[ parttype][1]);
int step_h = (input->part_size[blocktype][0]);
int step_v = (input->part_size[blocktype][1]);
int bxx, byy; // indexing curr_blk
int bx = bx0[parttype][block8x8];
int by = by0[parttype][block8x8];
short ******all_mv = img->all_mv;
short ****** p_mv = img->pred_mv;
//----- cost for motion vector bits -----
for (v=by; v<by + step_v0; v+=step_v)
{
for (h=bx; h<bx + step_h0; h+=step_h)
{
mvd_bits += mvbits[ all_mv [v][h][LIST_0][ref_l0][blocktype][0] - p_mv[v][h][LIST_0][ref_l0][blocktype][0] ];
mvd_bits += mvbits[ all_mv [v][h][LIST_0][ref_l0][blocktype][1] - p_mv[v][h][LIST_0][ref_l0][blocktype][1] ];
mvd_bits += mvbits[ all_mv [v][h][LIST_1][ref_l1][blocktype][0] - p_mv[v][h][LIST_1][ref_l1][blocktype][0] ];
mvd_bits += mvbits[ all_mv [v][h][LIST_1][ref_l1][blocktype][1] - p_mv[v][h][LIST_1][ref_l1][blocktype][1] ];
}
}
mcost = WEIGHTED_COST (lambda_factor, mvd_bits);
//----- cost of residual signal -----
for (byy=0, v=by; v<by + step_v0; byy+=4, v++)
{
pic_pix_y = img->opix_y + (block_y = (v<<2));
for (bxx=0, h=bx; h<bx + step_h0; bxx+=4, h++)
{
pic_pix_x = img->opix_x + (block_x = (h<<2));
LumaPrediction4x4 (block_x, block_y, 2, blocktype, blocktype, ref_l0, ref_l1);
for (k=j=0; j<4; j++)
{
for ( i=0; i<4; i++)
diff64[k++] = curr_blk[byy+j][bxx+i] =
imgY_org[pic_pix_y+j][pic_pix_x+i] - img->mpr[j+block_y][i+block_x];
}
if ((!input->Transform8x8Mode) || (blocktype>4))
mcost += distortion4x4 (diff64);
}
}
if (input->Transform8x8Mode && (blocktype<=4)) // tchen 4-29-04
{
for (byy=0; byy < input->blc_size[parttype][1]; byy+=bsy)
for (bxx=0; bxx<input->blc_size[parttype][0]; bxx+=bsx)
{
for (k=0, j=byy;j<byy + 8;j++, k += 8)
memcpy(&diff64[k], &(curr_blk[j][bxx]), 8 * sizeof(int));
mcost += distortion8x8(diff64);
}
}
return mcost;
}
/*!
************************************************************************
* \brief
* Get cost for skip mode for an macroblock
************************************************************************
*/
int GetSkipCostMB (void)
{
int block_y, block_x, pic_pix_y, pic_pix_x, i, j, k;
int cost = 0;
int curr_diff[8][8];
int mb_x, mb_y;
int block;
for(block=0;block<4;block++)
{
mb_y = (block/2)<<3;
mb_x = (block%2)<<3;
for (block_y=mb_y; block_y<mb_y+8; block_y+=4)
{
pic_pix_y = img->opix_y + block_y;
for (block_x=mb_x; block_x<mb_x+8; block_x+=4)
{
pic_pix_x = img->opix_x + block_x;
//===== prediction of 4x4 block =====
LumaPrediction4x4 (block_x, block_y, 0, 0, 0, 0, 0);
//===== get displaced frame difference ======
for (k=j=0; j<4; j++)
for (i=0; i<4; i++, k++)
{
diff[k] = curr_diff[block_y-mb_y+j][block_x-mb_x+i] = imgY_org[pic_pix_y+j][pic_pix_x+i] - img->mpr[j+block_y][i+block_x];
}
if(!((input->rdopt==0)&&(input->Transform8x8Mode)))
cost += distortion4x4 (diff);
}
}
if((input->rdopt==0)&&(input->Transform8x8Mode))
{
for(k=j=0; j<8; j++, k+=8)
memcpy(&diff64[k], &(curr_diff[j]), 8 * sizeof(int));
cost += distortion8x8 (diff64);
}
}
return cost;
}
/*!
************************************************************************
* \brief
* Find motion vector for the Skip mode
************************************************************************
*/
void FindSkipModeMotionVector ()
{
int bx, by;
short ******all_mv = img->all_mv;
short pmv[2];
int zeroMotionAbove;
int zeroMotionLeft;
PixelPos mb_a, mb_b;
int a_mv_y = 0;
int a_ref_idx = 0;
int b_mv_y = 0;
int b_ref_idx = 0;
short ***mv = enc_picture->mv[LIST_0];
Macroblock *currMB = &img->mb_data[img->current_mb_nr];
getLuma4x4Neighbour(img->current_mb_nr,-1, 0, &mb_a);
getLuma4x4Neighbour(img->current_mb_nr, 0,-1, &mb_b);
if (mb_a.available)
{
a_mv_y = mv[mb_a.pos_y][mb_a.pos_x][1];
a_ref_idx = enc_picture->ref_idx[LIST_0][mb_a.pos_y][mb_a.pos_x];
if (currMB->mb_field && !img->mb_data[mb_a.mb_addr].mb_field)
{
a_mv_y /=2;
a_ref_idx *=2;
}
if (!currMB->mb_field && img->mb_data[mb_a.mb_addr].mb_field)
{
a_mv_y *=2;
a_ref_idx >>=1;
}
}
if (mb_b.available)
{
b_mv_y = mv[mb_b.pos_y][mb_b.pos_x][1];
b_ref_idx = enc_picture->ref_idx[LIST_0][mb_b.pos_y][mb_b.pos_x];
if (currMB->mb_field && !img->mb_data[mb_b.mb_addr].mb_field)
{
b_mv_y /=2;
b_ref_idx *=2;
}
if (!currMB->mb_field && img->mb_data[mb_b.mb_addr].mb_field)
{
b_mv_y *=2;
b_ref_idx >>=1;
}
}
zeroMotionLeft = !mb_a.available ? 1 : a_ref_idx==0 && mv[mb_a.pos_y][mb_a.pos_x][0]==0 && a_mv_y==0 ? 1 : 0;
zeroMotionAbove = !mb_b.available ? 1 : b_ref_idx==0 && mv[mb_b.pos_y][mb_b.pos_x][0]==0 && b_mv_y==0 ? 1 : 0;
if (zeroMotionAbove || zeroMotionLeft)
{
for (by = 0;by < 4;by++)
for (bx = 0;bx < 4;bx++)
{
memset(all_mv [by][bx][0][0][0], 0, 2* sizeof(short));
//all_mv [by][bx][0][0][0][0] = 0;
//all_mv [by][bx][0][0][0][1] = 0;
}
}
else
{
SetMotionVectorPredictor (pmv, enc_picture->ref_idx[LIST_0], mv, 0, LIST_0, 0, 0, 16, 16);
for (by = 0;by < 4;by++)
for (bx = 0;bx < 4;bx++)
{
memcpy(all_mv [by][bx][0][0][0], pmv, 2* sizeof(short));
}
}
}
/*!
************************************************************************
* \brief
* Get cost for direct mode for an 8x8 block
************************************************************************
*/
int GetDirectCost8x8 (int block, int *cost8x8)
{
int block_y, block_x, pic_pix_y, pic_pix_x, i, j, k;
int curr_diff[8][8];
int cost = 0;
int mb_y = (block/2)<<3;
int mb_x = (block%2)<<3;
for (block_y=mb_y; block_y<mb_y+8; block_y+=4)
{
pic_pix_y = img->opix_y + block_y;
for (block_x=mb_x; block_x<mb_x+8; block_x+=4)
{
pic_pix_x = img->opix_x + block_x;
if (direct_pdir[pic_pix_y>>2][pic_pix_x>>2]<0)
{
*cost8x8=INT_MAX;
return INT_MAX; //mode not allowed
}
//===== prediction of 4x4 block =====
LumaPrediction4x4 (block_x, block_y, direct_pdir[pic_pix_y>>2][pic_pix_x>>2], 0, 0,
direct_ref_idx[LIST_0][pic_pix_y>>2][pic_pix_x>>2],
direct_ref_idx[LIST_1][pic_pix_y>>2][pic_pix_x>>2]);
//===== get displaced frame difference ======
for (k=j=0; j<4; j++)
for (i=0; i<4; i++, k++)
{
diff[k] = curr_diff[block_y-mb_y+j][block_x-mb_x+i] =
imgY_org[pic_pix_y+j][pic_pix_x+i] - img->mpr[j+block_y][i+block_x];
}
cost += distortion4x4 (diff);
}
}
if((input->rdopt==0)&&(input->Transform8x8Mode))
{
k=0;
for(j=0; j<8; j++, k+=8)
memcpy(&diff64[k], &(curr_diff[j]), 8 * sizeof(int));
*cost8x8 += distortion8x8 (diff64);
}
return cost;
}
/*!
************************************************************************
* \brief
* Get cost for direct mode for an macroblock
************************************************************************
*/
int GetDirectCostMB (void)
{
int i;
int cost = 0;
int cost8x8 = 0;
for (i=0; i<4; i++)
{
cost += GetDirectCost8x8 (i, &cost8x8);
if (cost8x8 == INT_MAX) return INT_MAX;
}
switch(input->Transform8x8Mode)
{
case 1: // Mixture of 8x8 & 4x4 transform
if((cost8x8 < cost)||
!(input->InterSearch8x4 &&
input->InterSearch4x8 &&
input->InterSearch4x4)
)
{
cost = cost8x8; //return 8x8 cost
}
break;
case 2: // 8x8 Transform only
cost = cost8x8;
break;
default: // 4x4 Transform only
break;
}
return cost;
// T.Nishi(MEI ACC) 04-28-2004 end
}
/*!
************************************************************************
* \brief
* Motion search for a partition
************************************************************************
*/
void
PartitionMotionSearch (int blocktype,
int block8x8,
int *lambda_factor)
{
static int bx0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,2,0,2}};
static int by0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,0,0,0}, {0,0,2,2}};
signed char **ref_array;
short ***mv_array;
short *all_mv;
short ref;
int v, h, mcost, search_range, i, j;
int pic_block_x, pic_block_y;
int bslice = (img->type==B_SLICE);
int parttype = (blocktype<4?blocktype:4);
int step_h0 = (input->part_size[ parttype][0]);
int step_v0 = (input->part_size[ parttype][1]);
int step_h = (input->part_size[blocktype][0]);
int step_v = (input->part_size[blocktype][1]);
int list;
int numlists = bslice ? 2 : 1;
int list_offset = img->mb_data[img->current_mb_nr].list_offset;
int *m_cost;
int by = by0[parttype][block8x8];
int bx = bx0[parttype][block8x8];
//===== LOOP OVER REFERENCE FRAMES =====
for (list=0; list<numlists;list++)
{
for (ref=0; ref < listXsize[list+list_offset]; ref++)
{
m_cost = &motion_cost[blocktype][list][ref][block8x8];
//----- set search range ---
#ifdef _FULL_SEARCH_RANGE_
if (input->full_search == 2)
search_range = input->search_range;
else if (input->full_search == 1)
search_range = input->search_range / (imin(ref,1)+1);
else
search_range = input->search_range / ((imin(ref,1)+1) * imin(2,blocktype));
#else
search_range = input->search_range / ((imin(ref,1)+1) * imin(2,blocktype));
#endif
//----- set arrays -----
ref_array = enc_picture->ref_idx[list];
mv_array = enc_picture->mv[list];
//----- init motion cost -----
//motion_cost[blocktype][list][ref][block8x8] = 0;
*m_cost = 0;
//===== LOOP OVER SUB MACRO BLOCK partitions
for (v=by; v<by + step_v0; v += step_v)
{
pic_block_y = img->block_y + v;
for (h=bx; h<bx+step_h0; h+=step_h)
{
all_mv = img->all_mv[v][h][list][ref][blocktype];
pic_block_x = img->block_x + h;
//--- motion search for block ---
mcost = BlockMotionSearch (ref, list, h<<2, v<<2, blocktype, search_range, lambda_factor);
*m_cost += mcost;
//--- set motion vectors and reference frame (for motion vector prediction) ---
for (j=pic_block_y; j<pic_block_y + step_v; j++)
{
memset(&ref_array [j][pic_block_x], ref, step_h * sizeof(char));
for (i=pic_block_x; i<pic_block_x + step_h; i++)
{
memcpy(mv_array [j][i], all_mv, 2* sizeof(short));
}
}
}
}
}
}
}
/*!
************************************************************************
* \brief
* Calculate Direct Motion Vectors *****
************************************************************************
*/
void Get_Direct_Motion_Vectors ()
{
int block_x, block_y, pic_block_x, pic_block_y, opic_block_x, opic_block_y;
short ****all_mvs;
int mv_scale;
int refList;
int ref_idx;
byte ** moving_block;
short **** co_located_mv;
signed char *** co_located_ref_idx;
int64 *** co_located_ref_id;
signed char ** ref_pic_l0 = enc_picture->ref_idx[LIST_0];
signed char ** ref_pic_l1 = enc_picture->ref_idx[LIST_1];
Macroblock *currMB = &img->mb_data[img->current_mb_nr];
if (currMB->list_offset)
{
if(img->current_mb_nr%2)
{
moving_block = Co_located->bottom_moving_block;
co_located_mv = Co_located->bottom_mv;
co_located_ref_idx = Co_located->bottom_ref_idx;
co_located_ref_id = Co_located->bottom_ref_pic_id;
}
else
{
moving_block = Co_located->top_moving_block;
co_located_mv = Co_located->top_mv;
co_located_ref_idx = Co_located->top_ref_idx;
co_located_ref_id = Co_located->top_ref_pic_id;
}
}
else
{
moving_block = Co_located->moving_block;
co_located_mv = Co_located->mv;
co_located_ref_idx = Co_located->ref_idx;
co_located_ref_id = Co_located->ref_pic_id;
}
if (img->direct_spatial_mv_pred_flag) //spatial direct mode copy from decoder
{
short l0_refA, l0_refB, l0_refD, l0_refC;
short l1_refA, l1_refB, l1_refD, l1_refC;
short l0_refX,l1_refX;
short pmvfw[2]={0,0},pmvbw[2]={0,0};
PixelPos mb_a, mb_b, mb_d, mb_c;
getLuma4x4Neighbour(img->current_mb_nr, -1, 0,&mb_a);
getLuma4x4Neighbour(img->current_mb_nr, 0, -1,&mb_b);
getLuma4x4Neighbour(img->current_mb_nr, 16, -1,&mb_c);
getLuma4x4Neighbour(img->current_mb_nr, -1, -1,&mb_d);
if (!img->MbaffFrameFlag)
{
l0_refA = mb_a.available ? ref_pic_l0[mb_a.pos_y][mb_a.pos_x] : -1;
l0_refB = mb_b.available ? ref_pic_l0[mb_b.pos_y][mb_b.pos_x] : -1;
l0_refD = mb_d.available ? ref_pic_l0[mb_d.pos_y][mb_d.pos_x] : -1;
l0_refC = mb_c.available ? ref_pic_l0[mb_c.pos_y][mb_c.pos_x] : l0_refD;
l1_refA = mb_a.available ? ref_pic_l1[mb_a.pos_y][mb_a.pos_x] : -1;
l1_refB = mb_b.available ? ref_pic_l1[mb_b.pos_y][mb_b.pos_x] : -1;
l1_refD = mb_d.available ? ref_pic_l1[mb_d.pos_y][mb_d.pos_x] : -1;
l1_refC = mb_c.available ? ref_pic_l1[mb_c.pos_y][mb_c.pos_x] : l1_refD;
}
else
{
if (currMB->mb_field)
{
l0_refA = mb_a.available
? (img->mb_data[mb_a.mb_addr].mb_field || ref_pic_l0[mb_a.pos_y][mb_a.pos_x] < 0
? ref_pic_l0[mb_a.pos_y][mb_a.pos_x]
: ref_pic_l0[mb_a.pos_y][mb_a.pos_x] * 2) : -1;
l0_refB = mb_b.available
? (img->mb_data[mb_b.mb_addr].mb_field || ref_pic_l0[mb_b.pos_y][mb_b.pos_x] < 0
? ref_pic_l0[mb_b.pos_y][mb_b.pos_x]
: ref_pic_l0[mb_b.pos_y][mb_b.pos_x] * 2) : -1;
l0_refD = mb_d.available
? (img->mb_data[mb_d.mb_addr].mb_field || ref_pic_l0[mb_d.pos_y][mb_d.pos_x] < 0
? ref_pic_l0[mb_d.pos_y][mb_d.pos_x]
: ref_pic_l0[mb_d.pos_y][mb_d.pos_x] * 2) : -1;
l0_refC = mb_c.available
? (img->mb_data[mb_c.mb_addr].mb_field || ref_pic_l0[mb_c.pos_y][mb_c.pos_x] < 0
? ref_pic_l0[mb_c.pos_y][mb_c.pos_x]
: ref_pic_l0[mb_c.pos_y][mb_c.pos_x] * 2) : l0_refD;
l1_refA = mb_a.available
? (img->mb_data[mb_a.mb_addr].mb_field || ref_pic_l1[mb_a.pos_y][mb_a.pos_x] < 0
? ref_pic_l1[mb_a.pos_y][mb_a.pos_x]
: ref_pic_l1[mb_a.pos_y][mb_a.pos_x] * 2) : -1;
l1_refB = mb_b.available
? (img->mb_data[mb_b.mb_addr].mb_field || ref_pic_l1[mb_b.pos_y][mb_b.pos_x] < 0
? ref_pic_l1[mb_b.pos_y][mb_b.pos_x]
: ref_pic_l1[mb_b.pos_y][mb_b.pos_x] * 2) : -1;
l1_refD = mb_d.available
? (img->mb_data[mb_d.mb_addr].mb_field || ref_pic_l1[mb_d.pos_y][mb_d.pos_x] < 0
? ref_pic_l1[mb_d.pos_y][mb_d.pos_x]
: ref_pic_l1[mb_d.pos_y][mb_d.pos_x] * 2) : -1;
l1_refC = mb_c.available
? (img->mb_data[mb_c.mb_addr].mb_field || ref_pic_l1[mb_c.pos_y][mb_c.pos_x] < 0
? ref_pic_l1[mb_c.pos_y][mb_c.pos_x]
: ref_pic_l1[mb_c.pos_y][mb_c.pos_x] * 2) : l1_refD;
}
else
{
l0_refA = mb_a.available
? (img->mb_data[mb_a.mb_addr].mb_field || ref_pic_l0[mb_a.pos_y][mb_a.pos_x] < 0
? ref_pic_l0[mb_a.pos_y][mb_a.pos_x] >> 1
: ref_pic_l0[mb_a.pos_y][mb_a.pos_x]) : -1;
l0_refB = mb_b.available
? (img->mb_data[mb_b.mb_addr].mb_field || ref_pic_l0[mb_b.pos_y][mb_b.pos_x] < 0
? ref_pic_l0[mb_b.pos_y][mb_b.pos_x] >> 1
: ref_pic_l0[mb_b.pos_y][mb_b.pos_x]) : -1;
l0_refD = mb_d.available
? (img->mb_data[mb_d.mb_addr].mb_field || ref_pic_l0[mb_d.pos_y][mb_d.pos_x] < 0
? ref_pic_l0[mb_d.pos_y][mb_d.pos_x] >> 1
: ref_pic_l0[mb_d.pos_y][mb_d.pos_x]) : -1;
l0_refC = mb_c.available
? (img->mb_data[mb_c.mb_addr].mb_field || ref_pic_l0[mb_c.pos_y][mb_c.pos_x] < 0
? ref_pic_l0[mb_c.pos_y][mb_c.pos_x] >> 1
: ref_pic_l0[mb_c.pos_y][mb_c.pos_x]) : l0_refD;
l1_refA = mb_a.available
? (img->mb_data[mb_a.mb_addr].mb_field || ref_pic_l1[mb_a.pos_y][mb_a.pos_x] < 0
? ref_pic_l1[mb_a.pos_y][mb_a.pos_x] >> 1
: ref_pic_l1[mb_a.pos_y][mb_a.pos_x]) : -1;
l1_refB = mb_b.available
? (img->mb_data[mb_b.mb_addr].mb_field || ref_pic_l1[mb_b.pos_y][mb_b.pos_x] < 0
? ref_pic_l1[mb_b.pos_y][mb_b.pos_x] >> 1
: ref_pic_l1[mb_b.pos_y][mb_b.pos_x]) : -1;
l1_refD = mb_d.available
? (img->mb_data[mb_d.mb_addr].mb_field || ref_pic_l1[mb_d.pos_y][mb_d.pos_x] < 0
? ref_pic_l1[mb_d.pos_y][mb_d.pos_x] >> 1
: ref_pic_l1[mb_d.pos_y][mb_d.pos_x]) : -1;
l1_refC = mb_c.available
? (img->mb_data[mb_c.mb_addr].mb_field || ref_pic_l1[mb_c.pos_y][mb_c.pos_x] < 0
? ref_pic_l1[mb_c.pos_y][mb_c.pos_x] >> 1
: ref_pic_l1[mb_c.pos_y][mb_c.pos_x]) : l1_refD;
}
}
l0_refX = (l0_refA >= 0 && l0_refB >= 0) ? imin(l0_refA,l0_refB): imax(l0_refA,l0_refB);
l0_refX = (l0_refX >= 0 && l0_refC >= 0) ? imin(l0_refX,l0_refC): imax(l0_refX,l0_refC);
l1_refX = (l1_refA >= 0 && l1_refB >= 0) ? imin(l1_refA,l1_refB): imax(l1_refA,l1_refB);
l1_refX = (l1_refX >= 0 && l1_refC >= 0) ? imin(l1_refX,l1_refC): imax(l1_refX,l1_refC);
if (l0_refX >=0)
SetMotionVectorPredictor (pmvfw, enc_picture->ref_idx[LIST_0], enc_picture->mv[LIST_0], l0_refX, LIST_0, 0, 0, 16, 16);
if (l1_refX >=0)
SetMotionVectorPredictor (pmvbw, enc_picture->ref_idx[LIST_1], enc_picture->mv[LIST_1], l1_refX, LIST_1, 0, 0, 16, 16);
for (block_y=0; block_y<4; block_y++)
{
pic_block_y = (img->pix_y >> 2) + block_y;
opic_block_y = (img->opix_y >> 2) + block_y;
for (block_x=0; block_x<4; block_x++)
{
pic_block_x = (img->pix_x >> 2) + block_x;
opic_block_x = (img->opix_x >> 2) + block_x;
all_mvs = img->all_mv[block_y][block_x];
if (l0_refX >=0)
{
if (!l0_refX && !moving_block[opic_block_y][opic_block_x])
{
memset(all_mvs[LIST_0][0][0], 0, 2* sizeof(short));
direct_ref_idx[LIST_0][pic_block_y][pic_block_x]=0;
}
else
{
all_mvs[LIST_0][l0_refX][0][0] = pmvfw[0];
all_mvs[LIST_0][l0_refX][0][1] = pmvfw[1];
direct_ref_idx[LIST_0][pic_block_y][pic_block_x]= (signed char)l0_refX;
}
}
else
{
all_mvs[LIST_0][0][0][0] = 0;
all_mvs[LIST_0][0][0][1] = 0;
direct_ref_idx[LIST_0][pic_block_y][pic_block_x]=-1;
}
if (l1_refX >=0)
{
if(l1_refX==0 && !moving_block[opic_block_y][opic_block_x])
{
all_mvs[LIST_1][0][0][0] = 0;
all_mvs[LIST_1][0][0][1] = 0;
direct_ref_idx[LIST_1][pic_block_y][pic_block_x]= (signed char)l1_refX;
}
else
{
all_mvs[LIST_1][l1_refX][0][0] = pmvbw[0];
all_mvs[LIST_1][l1_refX][0][1] = pmvbw[1];
direct_ref_idx[LIST_1][pic_block_y][pic_block_x]= (signed char)l1_refX;
}
}
else
{
direct_ref_idx[LIST_1][pic_block_y][pic_block_x]=-1;
all_mvs[LIST_1][0][0][0] = 0;
all_mvs[LIST_1][0][0][1] = 0;
}
// Test Level Limits if satisfied.
if (img->MbaffFrameFlag
&& (all_mvs[LIST_0][l0_refX < 0? 0 : l0_refX][0][0] < -8192
|| all_mvs[LIST_0][l0_refX < 0? 0 : l0_refX][0][0] > 8191
|| all_mvs[LIST_0][l0_refX < 0? 0 : l0_refX][0][1] < LEVELMVLIMIT[img->LevelIndex][4]
|| all_mvs[LIST_0][l0_refX < 0? 0 : l0_refX][0][1] > LEVELMVLIMIT[img->LevelIndex][5]
|| all_mvs[LIST_1][l1_refX < 0? 0 : l1_refX][0][0] < -8192
|| all_mvs[LIST_1][l1_refX < 0? 0 : l1_refX][0][0] > 8191
|| all_mvs[LIST_1][l1_refX < 0? 0 : l1_refX][0][1] < LEVELMVLIMIT[img->LevelIndex][4]
|| all_mvs[LIST_1][l1_refX < 0? 0 : l1_refX][0][1] > LEVELMVLIMIT[img->LevelIndex][5]))
{
direct_ref_idx[LIST_0][pic_block_y][pic_block_x] = -1;
direct_ref_idx[LIST_1][pic_block_y][pic_block_x] = -1;
direct_pdir [pic_block_y][pic_block_x] = -1;
}
else
{
if (l0_refX < 0 && l1_refX < 0)
{
direct_ref_idx[LIST_0][pic_block_y][pic_block_x] =
direct_ref_idx[LIST_1][pic_block_y][pic_block_x] = 0;
l0_refX = 0;
l1_refX = 0;
}
if (direct_ref_idx[LIST_1][pic_block_y][pic_block_x] == -1)
direct_pdir[pic_block_y][pic_block_x] = 0;
else if (direct_ref_idx[LIST_0][pic_block_y][pic_block_x] == -1)
direct_pdir[pic_block_y][pic_block_x] = 1;
else if (active_pps->weighted_bipred_idc == 1)
{
int weight_sum, i;
Boolean invalid_wp = FALSE;
for (i=0;i< (active_sps->chroma_format_idc == YUV400 ? 1 : 3); i++)
{
weight_sum = wbp_weight[0][l0_refX][l1_refX][i] + wbp_weight[1][l0_refX][l1_refX][i];
if (weight_sum < -128 || weight_sum > 127)
{
invalid_wp = TRUE;
break;
}
}
if (invalid_wp == FALSE)
direct_pdir[pic_block_y][pic_block_x] = 2;
else
{
direct_ref_idx[LIST_0][pic_block_y][pic_block_x] = -1;
direct_ref_idx[LIST_1][pic_block_y][pic_block_x] = -1;
direct_pdir [pic_block_y][pic_block_x] = -1;
}
}
else
direct_pdir[pic_block_y][pic_block_x] = 2;
}
}
}
}
else
{
int64 *refpic = enc_picture->ref_pic_num[LIST_0 +currMB->list_offset];
//temporal direct mode copy from decoder
for (block_y = 0; block_y < 4; block_y++)
{
pic_block_y = (img->pix_y >> 2) + block_y;
opic_block_y = (img->opix_y >> 2) + block_y;
for (block_x = 0; block_x < 4; block_x++)
{
pic_block_x = (img->pix_x>>2) + block_x;
opic_block_x = (img->opix_x>>2) + block_x;
all_mvs = img->all_mv[block_y][block_x];
refList = (co_located_ref_idx[LIST_0][opic_block_y][opic_block_x]== -1 ? LIST_1 : LIST_0);
ref_idx = co_located_ref_idx[refList][opic_block_y][opic_block_x];
// next P is intra mode
if (ref_idx==-1)
{
all_mvs[LIST_0][0][0][0] = 0;
all_mvs[LIST_0][0][0][1] = 0;
all_mvs[LIST_1][0][0][0] = 0;
all_mvs[LIST_1][0][0][1] = 0;
direct_ref_idx[LIST_0][pic_block_y][pic_block_x] = 0;
direct_ref_idx[LIST_1][pic_block_y][pic_block_x] = 0;
direct_pdir[pic_block_y][pic_block_x] = 2;
}
// next P is skip or inter mode
else
{
int mapped_idx=INVALIDINDEX;
int iref;
for (iref=0;iref<imin(img->num_ref_idx_l0_active,listXsize[LIST_0+currMB->list_offset]);iref++)
{
if (refpic[iref]==co_located_ref_id[refList ][opic_block_y][opic_block_x])
{
mapped_idx=iref;
break;
}
else //! invalid index. Default to zero even though this case should not happen
{
mapped_idx=INVALIDINDEX;
}
}
if (mapped_idx !=INVALIDINDEX)
{
mv_scale = img->mvscale[LIST_0+currMB->list_offset][mapped_idx];
if (mv_scale==9999)
{
// forward
all_mvs[LIST_0][0][0][0] = co_located_mv[refList][opic_block_y][opic_block_x][0];
all_mvs[LIST_0][0][0][1] = co_located_mv[refList][opic_block_y][opic_block_x][1];
// backward
all_mvs[LIST_1][0][0][0] = 0;
all_mvs[LIST_1][0][0][1] = 0;
}
else
{
// forward
all_mvs[LIST_0][mapped_idx][0][0] = (mv_scale * co_located_mv[refList][opic_block_y][opic_block_x][0] + 128) >> 8;
all_mvs[LIST_0][mapped_idx][0][1] = (mv_scale * co_located_mv[refList][opic_block_y][opic_block_x][1] + 128) >> 8;
// backward
all_mvs[LIST_1][ 0][0][0] = ((mv_scale - 256)* co_located_mv[refList][opic_block_y][opic_block_x][0] + 128) >> 8;
all_mvs[LIST_1][ 0][0][1] = ((mv_scale - 256)* co_located_mv[refList][opic_block_y][opic_block_x][1] + 128) >> 8;
}
// Test Level Limits if satisfied.
if ( all_mvs[LIST_0][mapped_idx][0][0] < -8192
|| all_mvs[LIST_0][mapped_idx][0][0] > 8191
|| all_mvs[LIST_0][mapped_idx][0][1] < LEVELMVLIMIT[img->LevelIndex][4]
|| all_mvs[LIST_0][mapped_idx][0][1] > LEVELMVLIMIT[img->LevelIndex][5]
|| all_mvs[LIST_1][0][0][0] < -8192
|| all_mvs[LIST_1][0][0][0] > 8191
|| all_mvs[LIST_1][0][0][1] < LEVELMVLIMIT[img->LevelIndex][4]
|| all_mvs[LIST_1][0][0][1] > LEVELMVLIMIT[img->LevelIndex][5])
{
direct_ref_idx[LIST_0][pic_block_y][pic_block_x] = -1;
direct_ref_idx[LIST_1][pic_block_y][pic_block_x] = -1;
direct_pdir[pic_block_y][pic_block_x] = -1;
}
else
{
direct_ref_idx[LIST_0][pic_block_y][pic_block_x] = mapped_idx;
direct_ref_idx[LIST_1][pic_block_y][pic_block_x] = 0;
direct_pdir[pic_block_y][pic_block_x] = 2;
}
}
else
{
direct_ref_idx[LIST_0][pic_block_y][pic_block_x] = -1;
direct_ref_idx[LIST_1][pic_block_y][pic_block_x] = -1;
direct_pdir[pic_block_y][pic_block_x] = -1;
}
}
if (active_pps->weighted_bipred_idc == 1 && direct_pdir[pic_block_y][pic_block_x] == 2)
{
int weight_sum, i;
short l0_refX = direct_ref_idx[LIST_0][pic_block_y][pic_block_x];
short l1_refX = direct_ref_idx[LIST_1][pic_block_y][pic_block_x];
for (i=0;i< (active_sps->chroma_format_idc == YUV400 ? 1 : 3); i++)
{
weight_sum = wbp_weight[0][l0_refX][l1_refX][i] + wbp_weight[1][l0_refX][l1_refX][i];
if (weight_sum < -128 || weight_sum > 127)
{
direct_ref_idx[LIST_0][pic_block_y][pic_block_x] = -1;
direct_ref_idx[LIST_1][pic_block_y][pic_block_x] = -1;
direct_pdir [pic_block_y][pic_block_x] = -1;
break;
}
}
}
}
}
}
}