blob: f12f366a2a38f1abec4dc9f9af948100aefed316 [file] [log] [blame]
/*!
*************************************************************************************
* \file me_epzs.c
*
* \brief
* Motion Estimation using EPZS
*
* \author
* Main contributors (see contributors.h for copyright, address and affiliation details)
* - Alexis Michael Tourapis <alexismt@ieee.org>
* - Athanasios Leontaris <aleon@dolby.com>
*
*************************************************************************************
*/
#include "contributors.h"
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include "global.h"
#include "image.h"
#include "memalloc.h"
#include "mb_access.h"
#include "refbuf.h"
#include "me_distortion.h"
#include "me_epzs.h"
#define EPZSREF 1
extern int *mvbits;
extern int *byte_abs;
// Define Global Parameters
static const short blk_parent[8] = {1, 1, 1, 1, 2, 4, 4, 5}; //!< {skip, 16x16, 16x8, 8x16, 8x8, 8x4, 4x8, 4x4}
//static const short blk_child[8] = {1, 2, 4, 4, 5, 7, 7, 7}; //!< {skip, 16x16, 16x8, 8x16, 8x8, 8x4, 4x8, 4x4}
static const int minthres_base[8] = {0, 64, 32, 32, 16, 8, 8, 4};
static const int medthres_base[8] = {0, 256, 128, 128, 64, 32, 32, 16};
static const int maxthres_base[8] = {0, 768, 384, 384, 192, 96, 96, 48};
static const short search_point_hp[10][2] = {{0,0},{-2,0}, {0,2}, {2,0}, {0,-2}, {-2,2}, {2,2}, {2,-2}, {-2,-2}, {-2,2}};
static const short search_point_qp[10][2] = {{0,0},{-1,0}, {0,1}, {1,0}, {0,-1}, {-1,1}, {1,1}, {1,-1}, {-1,-1}, {-1,1}};
//static const int next_subpel_pos_start[5][5] = {};
//static const int next_subpel_pos_end [5][5] = {};
static short EPZSBlkCount;
static int searcharray;
static int mv_rescale;
//! Define EPZS Refinement patterns
static int pattern_data[5][12][4] =
{
{ // Small Diamond pattern
{ 0, 4, 3, 3 }, { 4, 0, 0, 3 }, { 0, -4, 1, 3 }, { -4, 0, 2, 3 }
},
{ // Square pattern
{ 0, 4, 7, 3 }, { 4, 4, 7, 5 }, { 4, 0, 1, 3 }, { 4, -4, 1, 5 },
{ 0, -4, 3, 3 }, { -4, -4, 3, 5 }, { -4, 0, 5, 3 }, { -4, 4, 5, 5 }
},
{ // Enhanced Diamond pattern
{ -4, 4, 10, 5 }, { 0, 8, 10, 8 }, { 0, 4, 10, 7 }, { 4, 4, 1, 5 },
{ 8, 0, 1, 8 }, { 4, 0, 1, 7 }, { 4, -4, 4, 5 }, { 0, -8, 4, 8 },
{ 0, -4, 4, 7 }, { -4, -4, 7, 5 }, { -8, 0, 7, 8 }, { -4, 0, 7, 7 }
},
{ // Large Diamond pattern
{ 0, 8, 6, 5 }, { 4, 4, 0, 3 }, { 8, 0, 0, 5 }, { 4, -4, 2, 3 },
{ 0, -8, 2, 5 }, { -4, -4, 4, 3 }, { -8, 0, 4, 5 }, { -4, 4, 6, 3 }
},
{ // Extended Subpixel pattern
{ 0, 8, 6, 12 }, { 4, 4, 0, 12 }, { 8, 0, 0, 12 }, { 4, -4, 2, 12 },
{ 0, -8, 2, 12 }, { -4, -4, 4, 12 }, { -8, 0, 4, 12 }, { -4, 4, 6, 12 },
{ 0, 2, 6, 12 }, { 2, 0, 0, 12 }, { 0, -2, 2, 12 }, { -2, 0, 4, 12 }
}
};
// Other definitions
const char c_EPZSPattern[6][20] = { "Diamond", "Square", "Extended Diamond", "Large Diamond", "SBP Large Diamond", "PMVFAST"};
const char c_EPZSDualPattern[7][20] = { "Disabled","Diamond", "Square", "Extended Diamond", "Large Diamond", "SBP Large Diamond", "PMVFAST"};
const char c_EPZSFixed[3][20] = { "Disabled","All P", "All P + B"};
const char c_EPZSOther[2][20] = { "Disabled","Enabled"};
static int medthres[8];
static int maxthres[8];
static int minthres[8];
static int subthres[8];
static int mv_scale[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES];
static short **EPZSMap; //!< Memory Map definition
int ***EPZSDistortion; //!< Array for storing SAD Values
#if EPZSREF
short ******EPZSMotion; //!< Array for storing Motion Vectors
#else
short *****EPZSMotion; //!< Array for storing Motion Vectors
#endif
//
EPZSStructure *searchPattern,*searchPatternD, *predictor;
EPZSStructure *window_predictor, *window_predictor_extended;
EPZSStructure *sdiamond,*square,*ediamond,*ldiamond, *sbdiamond, *pmvfast;
EPZSColocParams *EPZSCo_located;
/*!
************************************************************************
* \brief
* Allocate co-located memory
*
* \param size_x
* horizontal luma size
* \param size_y
* vertical luma size
* \param mb_adaptive_frame_field_flag
* flag that indicates macroblock adaptive frame/field coding
*
* \return
* the allocated EPZSColocParams structure
************************************************************************
*/
EPZSColocParams* allocEPZScolocated(int size_x, int size_y, int mb_adaptive_frame_field_flag)
{
EPZSColocParams *s;
s = calloc(1, sizeof(EPZSColocParams));
if (NULL == s)
no_mem_exit("alloc_EPZScolocated: s");
s->size_x = size_x;
s->size_y = size_y;
get_mem4Dshort (&(s->mv), 2, size_y / BLOCK_SIZE, size_x / BLOCK_SIZE, 2);
if (mb_adaptive_frame_field_flag)
{
get_mem4Dshort (&(s->top_mv), 2, size_y / BLOCK_SIZE/2, size_x / BLOCK_SIZE, 2);
get_mem4Dshort (&(s->bottom_mv),2, size_y / BLOCK_SIZE/2, size_x / BLOCK_SIZE, 2);
}
s->mb_adaptive_frame_field_flag = mb_adaptive_frame_field_flag;
return s;
}
/*!
************************************************************************
* \brief
* Free co-located memory.
*
* \param p
* structure to be freed
*
************************************************************************
*/
void freeEPZScolocated(EPZSColocParams* p)
{
if (p)
{
free_mem4Dshort (p->mv, 2, p->size_y / BLOCK_SIZE);
if (p->mb_adaptive_frame_field_flag)
{
free_mem4Dshort (p->top_mv, 2, p->size_y / BLOCK_SIZE / 2);
free_mem4Dshort (p->bottom_mv, 2, p->size_y / BLOCK_SIZE / 2);
}
free(p);
p=NULL;
}
}
/*!
************************************************************************
* \brief
* Allocate EPZS pattern memory
*
* \param searchpoints
* number of searchpoints to allocate
*
* \return
* the allocated EPZSStructure structure
************************************************************************
*/
EPZSStructure* allocEPZSpattern(int searchpoints)
{
EPZSStructure *s;
s = calloc(1, sizeof(EPZSStructure));
if (NULL == s)
no_mem_exit("alloc_EPZSpattern: s");
s->searchPoints = searchpoints;
s->point = (SPoint*) calloc(searchpoints, sizeof(SPoint));
return s;
}
/*!
************************************************************************
* \brief
* Free EPZS pattern memory.
*
* \param p
* structure to be freed
*
************************************************************************
*/
void freeEPZSpattern(EPZSStructure* p)
{
if (p)
{
free ( (SPoint*) p->point);
free(p);
p=NULL;
}
}
void assignEPZSpattern(EPZSStructure *pattern,int type, int stopSearch, int nextLast, EPZSStructure *nextpattern)
{
int i;
for (i = 0; i < pattern->searchPoints; i++)
{
pattern->point[i].mv[0] = pattern_data[type][i][0] >> mv_rescale;
pattern->point[i].mv[1] = pattern_data[type][i][1] >> mv_rescale;
pattern->point[i].start_nmbr = pattern_data[type][i][2];
pattern->point[i].next_points = pattern_data[type][i][3];
}
pattern->stopSearch = stopSearch;
pattern->nextLast = nextLast;
pattern->nextpattern = nextpattern;
}
/*!
************************************************************************
* \brief
* calculate RoundLog2(uiVal)
************************************************************************
*/
static int RoundLog2 (int iValue)
{
int iRet = 0;
int iValue_square = iValue * iValue;
while ((1 << (iRet + 1)) <= iValue_square)
iRet++;
iRet = (iRet + 1) >> 1;
return iRet;
}
/*!
************************************************************************
* \brief
* EPZS Search Window Predictor Initialization
************************************************************************
*/
void EPZSWindowPredictorInit (short search_range, EPZSStructure * predictor, short mode)
{
int pos;
int searchpos, fieldsearchpos;
int prednum = 0;
int i;
int search_range_qpel = input->EPZSSubPelGrid ? 2 : 0;
if (mode == 0)
{
for (pos = RoundLog2 (search_range) - 2; pos > -1; pos--)
{
searchpos = ((search_range << search_range_qpel)>> pos);
for (i=1; i>=-1; i-=2)
{
predictor->point[prednum ].mv[0] = i * searchpos;
predictor->point[prednum++].mv[1] = 0;
predictor->point[prednum ].mv[0] = i * searchpos;
predictor->point[prednum++].mv[1] = i * searchpos;
predictor->point[prednum ].mv[0] = 0;
predictor->point[prednum++].mv[1] = i * searchpos;
predictor->point[prednum ].mv[0] = -i * searchpos;
predictor->point[prednum++].mv[1] = i * searchpos;
}
}
}
else // if (mode == 0)
{
for (pos = RoundLog2 (search_range) - 2; pos > -1; pos--)
{
searchpos = ((search_range << search_range_qpel) >> pos);
fieldsearchpos = ((3 * searchpos + 1) << search_range_qpel) >> 1;
for (i=1; i>=-1; i-=2)
{
predictor->point[prednum ].mv[0] = i * searchpos;
predictor->point[prednum++].mv[1] = 0;
predictor->point[prednum ].mv[0] = i * searchpos;
predictor->point[prednum++].mv[1] = i * searchpos;
predictor->point[prednum ].mv[0] = 0;
predictor->point[prednum++].mv[1] = i * searchpos;
predictor->point[prednum ].mv[0] = -i * searchpos;
predictor->point[prednum++].mv[1] = i * searchpos;
}
for (i=1; i>=-1; i-=2)
{
predictor->point[prednum ].mv[0] = i * fieldsearchpos;
predictor->point[prednum++].mv[1] = -i * searchpos;
predictor->point[prednum ].mv[0] = i * fieldsearchpos;
predictor->point[prednum++].mv[1] = 0;
predictor->point[prednum ].mv[0] = i * fieldsearchpos;
predictor->point[prednum++].mv[1] = i * searchpos;
predictor->point[prednum ].mv[0] = i * searchpos;
predictor->point[prednum++].mv[1] = i * fieldsearchpos;
predictor->point[prednum ].mv[0] = 0;
predictor->point[prednum++].mv[1] = i * fieldsearchpos;
predictor->point[prednum ].mv[0] = -i * searchpos;
predictor->point[prednum++].mv[1] = i * fieldsearchpos;
}
}
}
predictor->searchPoints = prednum;
}
/*!
************************************************************************
* \brief
* EPZS Global Initialization
************************************************************************
*/
int
EPZSInit (void)
{
int pel_error_me = 1 << (img->bitdepth_luma - 8);
int i, memory_size = 0;
int searchlevels = RoundLog2 (input->search_range) - 1;
searcharray = input->BiPredMotionEstimation? (2 * imax (input->search_range, input->BiPredMESearchRange) + 1) << (2 * input->EPZSSubPelGrid) : (2 * input->search_range + 1)<< (2 * input->EPZSSubPelGrid);
mv_rescale = input->EPZSSubPelGrid ? 0 : 2;
//! In this implementation we keep threshold limits fixed.
//! However one could adapt these limits based on lagrangian
//! optimization considerations (i.e. qp), while also allow
//! adaptation of the limits themselves based on content or complexity.
for (i=0;i<8;i++)
{
medthres[i] = input->EPZSMedThresScale * medthres_base[i] * pel_error_me;
maxthres[i] = input->EPZSMaxThresScale * maxthres_base[i] * pel_error_me;
minthres[i] = input->EPZSMinThresScale * minthres_base[i] * pel_error_me;
subthres[i] = input->EPZSSubPelThresScale * medthres_base[i] * pel_error_me;
}
//! Definition of pottential EPZS patterns.
//! It is possible to also define other patterns, or even use
//! resizing patterns (such as the PMVFAST scheme. These patterns
//! are only shown here as reference, while the same also holds
//! for this implementation (i.e. new conditions could be added
//! on adapting predictors, or thresholds etc. Note that search
//! could also be performed on subpel positions directly while
//! pattern needs not be restricted on integer positions only.
//! Allocate memory and assign search patterns
sdiamond = allocEPZSpattern(4);
assignEPZSpattern(sdiamond, SDIAMOND, TRUE, TRUE, sdiamond);
square = allocEPZSpattern(8);
assignEPZSpattern(square, SQUARE, TRUE, TRUE, square);
ediamond = allocEPZSpattern(12);
assignEPZSpattern(ediamond, EDIAMOND, TRUE, TRUE, ediamond);
ldiamond = allocEPZSpattern(8);
assignEPZSpattern(ldiamond, LDIAMOND, TRUE, TRUE, ldiamond);
sbdiamond = allocEPZSpattern(12);
assignEPZSpattern(sbdiamond, SBDIAMOND, FALSE, TRUE, sdiamond);
pmvfast = allocEPZSpattern(8);
assignEPZSpattern(pmvfast, LDIAMOND, FALSE, TRUE, sdiamond);
//! Allocate and assign window based predictors.
//! Other window types could also be used, while method could be
//! made a bit more adaptive (i.e. patterns could be assigned
//! based on neighborhood
window_predictor = allocEPZSpattern(searchlevels * 8);
window_predictor_extended = allocEPZSpattern(searchlevels * 20);
EPZSWindowPredictorInit ((short) input->search_range, window_predictor, 0);
EPZSWindowPredictorInit ((short) input->search_range, window_predictor_extended, 1);
//! Also assing search predictor memory
// maxwindow + spatial + blocktype + temporal + memspatial
predictor = allocEPZSpattern(searchlevels * 20 + 5 + 5 + 9 * (input->EPZSTemporal) + 3 * (input->EPZSSpatialMem));
//! Finally assign memory for all other elements
//! (distortion, EPZSMap, and temporal predictors)
memory_size += get_mem3Dint (&EPZSDistortion, 6, 7, img->width/BLOCK_SIZE);
memory_size += get_mem2Dshort (&EPZSMap, searcharray, searcharray );
if (input->EPZSSpatialMem)
{
#if EPZSREF
memory_size += get_mem6Dshort (&EPZSMotion, 6, img->max_num_references, 7, 4, img->width/BLOCK_SIZE, 2);
#else
memory_size += get_mem5Dshort (&EPZSMotion, 6, 7, 4, img->width/BLOCK_SIZE, 2);
#endif
}
if (input->EPZSTemporal)
EPZSCo_located = allocEPZScolocated (img->width, img->height,
active_sps->mb_adaptive_frame_field_flag);
switch (input->EPZSPattern)
{
case 5:
searchPattern = pmvfast;
break;
case 4:
searchPattern = sbdiamond;
break;
case 3:
searchPattern = ldiamond;
break;
case 2:
searchPattern = ediamond;
break;
case 1:
searchPattern = square;
break;
case 0:
default:
searchPattern = sdiamond;
break;
}
switch (input->EPZSDual)
{
case 6:
searchPatternD = pmvfast;
break;
case 5:
searchPatternD = sbdiamond;
break;
case 4:
searchPatternD = ldiamond;
break;
case 3:
searchPatternD = ediamond;
break;
case 2:
searchPatternD = square;
break;
case 1:
default:
searchPatternD = sdiamond;
break;
}
return memory_size;
}
/*!
************************************************************************
* \brief
* Delete EPZS Alocated memory
************************************************************************
*/
void EPZSDelete (void)
{
if (input->EPZSTemporal)
freeEPZScolocated (EPZSCo_located);
free_mem2Dshort(EPZSMap);
free_mem3Dint (EPZSDistortion, 6);
freeEPZSpattern(window_predictor_extended);
freeEPZSpattern(window_predictor);
freeEPZSpattern(predictor);
// Free search patterns
freeEPZSpattern(pmvfast);
freeEPZSpattern(sbdiamond);
freeEPZSpattern(ldiamond);
freeEPZSpattern(ediamond);
freeEPZSpattern(sdiamond);
freeEPZSpattern(square);
if (input->EPZSSpatialMem)
{
#if EPZSREF
free_mem6Dshort (EPZSMotion, 6, img->max_num_references, 7, 4);
#else
free_mem5Dshort (EPZSMotion, 6, 7, 4);
#endif
}
}
//! For ME purposes restricting the co-located partition is not necessary.
/*!
************************************************************************
* \brief
* EPZS Slice Level Initialization
************************************************************************
*/
void
EPZSSliceInit (EPZSColocParams * p,
StorablePicture ** listX[6])
{
StorablePicture *fs, *fs_top, *fs_bottom;
StorablePicture *fs1, *fs_top1, *fs_bottom1, *fsx;
int i, j, k, jj, jdiv, loffset;
int prescale, iTRb, iTRp;
int list = img->type == B_SLICE ? LIST_1 : LIST_0;
int tempmv_scale[2];
int epzs_scale[2][6][MAX_LIST_SIZE];
int iref;
int invmv_precision = 8;
// Lets compute scaling factoes between all references in lists.
// Needed to scale spatial predictors.
for (j = LIST_0; j < 2 + (img->MbaffFrameFlag * 4); j ++)
{
for (k = 0; k < listXsize[j]; k++)
{
for (i = 0; i < listXsize[j]; i++)
{
if (j/2 == 0)
{
iTRb = iClip3 (-128, 127, enc_picture->poc - listX[j][i]->poc);
iTRp = iClip3 (-128, 127, enc_picture->poc - listX[j][k]->poc);
}
else if (j/2 == 1)
{
iTRb = iClip3 (-128, 127, enc_picture->top_poc - listX[j][i]->poc);
iTRp = iClip3 (-128, 127, enc_picture->top_poc - listX[j][k]->poc);
}
else
{
iTRb = iClip3 (-128, 127, enc_picture->bottom_poc - listX[j][i]->poc);
iTRp = iClip3 (-128, 127, enc_picture->bottom_poc - listX[j][k]->poc);
}
if (iTRp != 0)
{
prescale = (16384 + iabs (iTRp / 2)) / iTRp;
mv_scale[j][i][k] = iClip3 (-2048, 2047, rshift_rnd_sf((iTRb * prescale), 6));
}
else
mv_scale[j][i][k] = 256;
}
}
}
if (input->EPZSTemporal)
{
fs_top = fs_bottom = fs = listX[list][0];
if (listXsize[list]> 1)
fs_top1 = fs_bottom1 = fs1 = listX[list][1];
else
fs_top1 = fs_bottom1 = fs1 = listX[list][0];
for (j = 0; j < 6; j++)
{
for (i = 0; i < 6; i++)
{
epzs_scale[0][j][i] = 256;
epzs_scale[1][j][i] = 256;
}
}
for (j = 0; j < 2 + (img->MbaffFrameFlag * 4); j += 2)
{
for (i = 0; i < listXsize[j]; i++)
{
if (j == 0)
iTRb = iClip3 (-128, 127, enc_picture->poc - listX[LIST_0 + j][i]->poc);
else if (j == 2)
iTRb = iClip3 (-128, 127, enc_picture->top_poc - listX[LIST_0 + j][i]->poc);
else
iTRb = iClip3 (-128, 127, enc_picture->bottom_poc - listX[LIST_0 + j][i]->poc);
iTRp = iClip3 (-128, 127, listX[list + j][0]->poc - listX[LIST_0 + j][i]->poc);
if (iTRp != 0)
{
prescale = (16384 + iabs (iTRp / 2)) / iTRp;
prescale = iClip3 (-2048, 2047, rshift_rnd_sf((iTRb * prescale), 6));
//prescale = (iTRb * prescale + 32) >> 6;
}
else // This could not happen but lets use it in case that reference is removed.
prescale = 256;
epzs_scale[0][j][i] = rshift_rnd_sf((mv_scale[j][0][i] * prescale), 8);
epzs_scale[0][j + 1][i] = prescale - 256;
if (listXsize[list + j]>1)
{
iTRp = iClip3 (-128, 127, listX[list + j][1]->poc - listX[LIST_0 + j][i]->poc);
if (iTRp != 0)
{
prescale = (16384 + iabs (iTRp / 2)) / iTRp;
prescale = iClip3 (-2048, 2047, rshift_rnd_sf((iTRb * prescale), 6));
//prescale = (iTRb * prescale + 32) >> 6;
}
else // This could not happen but lets use it for case that reference is removed.
prescale = 256;
epzs_scale[1][j][i] = rshift_rnd_sf((mv_scale[j][1][i] * prescale), 8);
epzs_scale[1][j + 1][i] = prescale - 256;
}
else
{
epzs_scale[1][j][i] = epzs_scale[0][j][i];
epzs_scale[1][j + 1][i] = epzs_scale[0][j + 1][i];
}
}
}
if (img->MbaffFrameFlag)
{
fs_top = listX[list + 2][0];
fs_bottom = listX[list + 4][0];
if (listXsize[0]> 1)
{
fs_top1 = listX[list + 2][1];
fs_bottom = listX[list + 4][1];
}
}
else
{
if (img->structure != FRAME)
{
if ((img->structure != fs->structure) && (fs->coded_frame))
{
if (img->structure == TOP_FIELD)
{
fs_top = fs_bottom = fs = listX[list][0]->top_field;
fs_top1 = fs_bottom1 = fs1 = listX[list][0]->bottom_field;
}
else
{
fs_top = fs_bottom = fs = listX[list][0]->bottom_field;
fs_top1 = fs_bottom1 = fs1 = listX[list][0]->top_field;
}
}
}
}
//if (!active_sps->frame_mbs_only_flag || active_sps->direct_8x8_inference_flag)
if (!active_sps->frame_mbs_only_flag)
{
for (j = 0; j < fs->size_y >> 2; j++)
{
jj = j / 2;
jdiv = j / 2 + 4 * (j / 8);
for (i = 0; i < fs->size_x >> 2; i++)
{
if (img->MbaffFrameFlag && fs->field_frame[j][i])
{
//! Assign frame buffers for field MBs
//! Check whether we should use top or bottom field mvs.
//! Depending on the assigned poc values.
if (iabs (enc_picture->poc - fs_bottom->poc) > iabs (enc_picture->poc - fs_top->poc))
{
tempmv_scale[LIST_0] = 256;
tempmv_scale[LIST_1] = 0;
if (fs->ref_id [LIST_0][jdiv][i] < 0 && listXsize[LIST_0] > 1)
{
fsx = fs_top1;
loffset = 1;
}
else
{
fsx = fs_top;
loffset = 0;
}
if (fs->ref_id [LIST_0][jdiv][i] != -1)
{
for (iref = 0; iref < imin(img->num_ref_idx_l0_active,listXsize[LIST_0]); iref++)
{
if (enc_picture->ref_pic_num[LIST_0][iref]==fs->ref_id [LIST_0][jdiv][i])
{
tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref];
tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref];
break;
}
}
p->mv[LIST_0][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][jj][i][0]), invmv_precision));
p->mv[LIST_0][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][jj][i][1]), invmv_precision));
p->mv[LIST_1][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][jj][i][0]), invmv_precision));
p->mv[LIST_1][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][jj][i][1]), invmv_precision));
}
else
{
p->mv[LIST_0][j][i][0] = 0;
p->mv[LIST_0][j][i][1] = 0;
p->mv[LIST_1][j][i][0] = 0;
p->mv[LIST_1][j][i][1] = 0;
}
}
else
{
tempmv_scale[LIST_0] = 256;
tempmv_scale[LIST_1] = 0;
if (fs->ref_id [LIST_0][jdiv + 4][i] < 0 && listXsize[LIST_0] > 1)
{
fsx = fs_bottom1;
loffset = 1;
}
else
{
fsx = fs_bottom;
loffset = 0;
}
if (fs->ref_id [LIST_0][jdiv + 4][i] != -1)
{
for (iref = 0; iref < imin(img->num_ref_idx_l0_active,listXsize[LIST_0]); iref++)
{
if (enc_picture->ref_pic_num[LIST_0][iref]==fs->ref_id [LIST_0][jdiv + 4][i])
{
tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref];
tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref];
break;
}
}
p->mv[LIST_0][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][jj][i][0]), invmv_precision));
p->mv[LIST_0][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][jj][i][1]), invmv_precision));
p->mv[LIST_1][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][jj][i][0]), invmv_precision));
p->mv[LIST_1][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][jj][i][1]), invmv_precision));
}
else
{
p->mv[LIST_0][j][i][0] = 0;
p->mv[LIST_0][j][i][1] = 0;
p->mv[LIST_1][j][i][0] = 0;
p->mv[LIST_1][j][i][1] = 0;
}
}
}
else
{
tempmv_scale[LIST_0] = 256;
tempmv_scale[LIST_1] = 0;
if (fs->ref_id [LIST_0][j][i] < 0 && listXsize[LIST_0] > 1)
{
fsx = fs1;
loffset = 1;
}
else
{
fsx = fs;
loffset = 0;
}
if (fsx->ref_id [LIST_0][j][i] != -1)
{
for (iref = 0; iref < imin(img->num_ref_idx_l0_active,listXsize[LIST_0]); iref++)
{
if (enc_picture->ref_pic_num[LIST_0][iref]==fsx->ref_id [LIST_0][j][i])
{
tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref];
tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref];
break;
}
}
p->mv[LIST_0][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][j][i][0]), invmv_precision));
p->mv[LIST_0][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][j][i][1]), invmv_precision));
p->mv[LIST_1][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][j][i][0]), invmv_precision));
p->mv[LIST_1][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][j][i][1]), invmv_precision));
}
else
{
p->mv[LIST_0][j][i][0] = 0;
p->mv[LIST_0][j][i][1] = 0;
p->mv[LIST_1][j][i][0] = 0;
p->mv[LIST_1][j][i][1] = 0;
}
}
}
}
}
//! Generate field MVs from Frame MVs
if (img->structure || img->MbaffFrameFlag)
{
for (j = 0; j < fs->size_y / 8; j++)
{
for (i = 0; i < fs->size_x / 4; i++)
{
if (!img->MbaffFrameFlag)
{
tempmv_scale[LIST_0] = 256;
tempmv_scale[LIST_1] = 0;
if (fs->ref_id [LIST_0][j][i] < 0 && listXsize[LIST_0] > 1)
{
fsx = fs1;
loffset = 1;
}
else
{
fsx = fs;
loffset = 0;
}
if (fsx->ref_id [LIST_0][j][i] != -1)
{
for (iref = 0; iref < imin(img->num_ref_idx_l0_active,listXsize[LIST_0]); iref++)
{
if (enc_picture->ref_pic_num[LIST_0][iref]==fsx->ref_id [LIST_0][j][i])
{
tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref];
tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref];
break;
}
}
p->mv[LIST_0][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][j][i][0]), invmv_precision));
p->mv[LIST_0][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][j][i][1]), invmv_precision));
p->mv[LIST_1][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][j][i][0]), invmv_precision));
p->mv[LIST_1][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][j][i][1]), invmv_precision));
}
else
{
p->mv[LIST_0][j][i][0] = 0;
p->mv[LIST_0][j][i][1] = 0;
p->mv[LIST_1][j][i][0] = 0;
p->mv[LIST_1][j][i][1] = 0;
}
}
else
{
tempmv_scale[LIST_0] = 256;
tempmv_scale[LIST_1] = 0;
if (fs_bottom->ref_id [LIST_0][j][i] < 0 && listXsize[LIST_0] > 1)
{
fsx = fs_bottom1;
loffset = 1;
}
else
{
fsx = fs_bottom;
loffset = 0;
}
if (fsx->ref_id [LIST_0][j][i] != -1)
{
for (iref = 0; iref < imin(2*img->num_ref_idx_l0_active,listXsize[LIST_0 + 4]); iref++)
{
if (enc_picture->ref_pic_num[LIST_0 + 4][iref]==fsx->ref_id [LIST_0][j][i])
{
tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0 + 4][iref];
tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1 + 4][iref];
break;
}
}
p->bottom_mv[LIST_0][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][j][i][0]), invmv_precision));
p->bottom_mv[LIST_0][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][j][i][1]), invmv_precision));
p->bottom_mv[LIST_1][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][j][i][0]), invmv_precision));
p->bottom_mv[LIST_1][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][j][i][1]), invmv_precision));
}
else
{
p->bottom_mv[LIST_0][j][i][0] = 0;
p->bottom_mv[LIST_0][j][i][1] = 0;
p->bottom_mv[LIST_1][j][i][0] = 0;
p->bottom_mv[LIST_1][j][i][1] = 0;
}
if (!fs->field_frame[2 * j][i])
{
p->bottom_mv[LIST_0][j][i][1] = (p->bottom_mv[LIST_0][j][i][1] + 1) >> 1;
p->bottom_mv[LIST_1][j][i][1] = (p->bottom_mv[LIST_1][j][i][1] + 1) >> 1;
}
tempmv_scale[LIST_0] = 256;
tempmv_scale[LIST_1] = 0;
if (fs_top->ref_id [LIST_0][j][i] < 0 && listXsize[LIST_0] > 1)
{
fsx = fs_top1;
loffset = 1;
}
else
{
fsx = fs_top;
loffset = 0;
}
if (fsx->ref_id [LIST_0][j][i] != -1)
{
for (iref = 0; iref < imin(2*img->num_ref_idx_l0_active,listXsize[LIST_0 + 2]); iref++)
{
if (enc_picture->ref_pic_num[LIST_0 + 2][iref]==fsx->ref_id [LIST_0][j][i])
{
tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0 + 2][iref];
tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1 + 2][iref];
break;
}
}
p->top_mv[LIST_0][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][j][i][0]), invmv_precision));
p->top_mv[LIST_0][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][j][i][1]), invmv_precision));
p->top_mv[LIST_1][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][j][i][0]), invmv_precision));
p->top_mv[LIST_1][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][j][i][1]), invmv_precision));
}
else
{
p->top_mv[LIST_0][j][i][0] = 0;
p->top_mv[LIST_0][j][i][1] = 0;
p->top_mv[LIST_1][j][i][0] = 0;
p->top_mv[LIST_1][j][i][1] = 0;
}
if (!fs->field_frame[2 * j][i])
{
p->top_mv[LIST_0][j][i][1] = rshift_rnd_sf((p->top_mv[LIST_0][j][i][1]), 1);
p->top_mv[LIST_1][j][i][1] = rshift_rnd_sf((p->top_mv[LIST_1][j][i][1]), 1);
}
}
}
}
}
//if (!active_sps->frame_mbs_only_flag || active_sps->direct_8x8_inference_flag)
if (!active_sps->frame_mbs_only_flag )
{
//! Use inference flag to remap mvs/references
//! Frame with field co-located
if (!img->structure)
{
for (j = 0; j < fs->size_y >> 2; j++)
{
jj = j>>1;
jdiv = (j>>1) + ((j>>3) << 2);
for (i = 0; i < fs->size_x >> 2; i++)
{
if (fs->field_frame[j][i])
{
tempmv_scale[LIST_0] = 256;
tempmv_scale[LIST_1] = 0;
if (fs->ref_id [LIST_0][jdiv][i] < 0 && listXsize[LIST_0] > 1)
{
fsx = fs1;
loffset = 1;
}
else
{
fsx = fs;
loffset = 0;
}
if (fsx->ref_id [LIST_0][jdiv][i] != -1)
{
for (iref = 0; iref < imin(img->num_ref_idx_l0_active,listXsize[LIST_0]); iref++)
{
if (enc_picture->ref_pic_num[LIST_0][iref]==fsx->ref_id [LIST_0][jdiv][i])
{
tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref];
tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref];
break;
}
}
if (iabs (enc_picture->poc - fsx->bottom_field->poc) > iabs (enc_picture->poc - fsx->top_field->poc))
{
p->mv[LIST_0][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->top_field->mv[LIST_0][jj][i][0]), invmv_precision));
p->mv[LIST_0][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->top_field->mv[LIST_0][jj][i][1]), invmv_precision));
p->mv[LIST_1][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->top_field->mv[LIST_0][jj][i][0]), invmv_precision));
p->mv[LIST_1][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->top_field->mv[LIST_0][jj][i][1]), invmv_precision));
}
else
{
p->mv[LIST_0][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->bottom_field->mv[LIST_0][jj][i][0]), invmv_precision));
p->mv[LIST_0][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->bottom_field->mv[LIST_0][jj][i][1]), invmv_precision));
p->mv[LIST_1][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->bottom_field->mv[LIST_0][jj][i][0]), invmv_precision));
p->mv[LIST_1][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->bottom_field->mv[LIST_0][jj][i][1]), invmv_precision));
}
}
else
{
p->mv[LIST_0][j][i][0] = 0;
p->mv[LIST_0][j][i][1] = 0;
p->mv[LIST_1][j][i][0] = 0;
p->mv[LIST_1][j][i][1] = 0;
}
}
}
}
}
}
if (active_sps->frame_mbs_only_flag)
{
for (j = 0; j < fs->size_y >> 2; j++)
{
for (i = 0; i < fs->size_x >> 2; i++)
{
tempmv_scale[LIST_0] = 256;
tempmv_scale[LIST_1] = 0;
if (fs->ref_id [LIST_0][j][i] < 0 && listXsize[LIST_0] > 1)
{
fsx = fs1;
loffset = 1;
}
else
{
fsx = fs;
loffset = 0;
}
if (fsx->ref_id [LIST_0][j][i] != -1)
{
for (iref = 0; iref < imin(img->num_ref_idx_l0_active,listXsize[LIST_0]); iref++)
{
if (enc_picture->ref_pic_num[LIST_0][iref]==fsx->ref_id [LIST_0][j][i])
{
tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref];
tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref];
break;
}
}
p->mv[LIST_0][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][j][i][0]), invmv_precision));
p->mv[LIST_0][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * fsx->mv[LIST_0][j][i][1]), invmv_precision));
p->mv[LIST_1][j][i][0] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][j][i][0]), invmv_precision));
p->mv[LIST_1][j][i][1] = iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * fsx->mv[LIST_0][j][i][1]), invmv_precision));
}
else
{
p->mv[LIST_0][j][i][0] = 0;
p->mv[LIST_0][j][i][1] = 0;
p->mv[LIST_1][j][i][0] = 0;
p->mv[LIST_1][j][i][1] = 0;
}
}
}
}
if (!active_sps->frame_mbs_only_flag)
{
for (j = 0; j < fs->size_y >> 2; j++)
{
for (i = 0; i < fs->size_x >> 2; i++)
{
if ((!img->MbaffFrameFlag && !img->structure && fs->field_frame[j][i]) || (img->MbaffFrameFlag && fs->field_frame[j][i]))
{
p->mv[LIST_0][j][i][1] *= 2;
p->mv[LIST_1][j][i][1] *= 2;
}
else if (img->structure && !fs->field_frame[j][i])
{
p->mv[LIST_0][j][i][1] = rshift_rnd_sf((p->mv[LIST_0][j][i][1]), 1);
p->mv[LIST_1][j][i][1] = rshift_rnd_sf((p->mv[LIST_1][j][i][1]), 1);
}
}
}
}
}
}
/*!
***********************************************************************
* \brief
* Spatial Predictors
* AMT/HYC
***********************************************************************
*/
static short EPZSSpatialPredictors (PixelPos block_a,
PixelPos block_b,
PixelPos block_c,
PixelPos block_d,
int list,
int list_offset,
short ref,
signed char **refPic,
short ***tmp_mv,
EPZSStructure * predictor)
{
int refA, refB, refC, refD;
int *mot_scale = mv_scale[list + list_offset][ref];
short sp_shift_mv = 8 + mv_rescale;
// zero predictor
predictor->point[0].mv[0] = 0;
predictor->point[0].mv[1] = 0;
// Non MB-AFF mode
if (!img->MbaffFrameFlag)
{
refA = block_a.available ? (int) refPic[block_a.pos_y][block_a.pos_x] : -1;
refB = block_b.available ? (int) refPic[block_b.pos_y][block_b.pos_x] : -1;
refC = block_c.available ? (int) refPic[block_c.pos_y][block_c.pos_x] : -1;
refD = block_d.available ? (int) refPic[block_d.pos_y][block_d.pos_x] : -1;
// Left Predictor
if (block_a.available)
{
predictor->point[1].mv[0] = rshift_rnd_sf((mot_scale[refA] * tmp_mv[block_a.pos_y][block_a.pos_x][0]), sp_shift_mv);
predictor->point[1].mv[1] = rshift_rnd_sf((mot_scale[refA] * tmp_mv[block_a.pos_y][block_a.pos_x][1]), sp_shift_mv);
}
else
{
predictor->point[1].mv[0] = (12 >> mv_rescale);
predictor->point[1].mv[1] = 0;
}
// Up predictor
if (block_b.available)
{
predictor->point[2].mv[0] = rshift_rnd_sf((mot_scale[refB] * tmp_mv[block_b.pos_y][block_b.pos_x][0]), sp_shift_mv);
predictor->point[2].mv[1] = rshift_rnd_sf((mot_scale[refB] * tmp_mv[block_b.pos_y][block_b.pos_x][1]), sp_shift_mv);
}
else
{
predictor->point[2].mv[0] = 0;
predictor->point[2].mv[1] = (12 >> mv_rescale);
}
// Up-Right predictor
if (block_c.available)
{
predictor->point[3].mv[0] = rshift_rnd_sf((mot_scale[refC] * tmp_mv[block_c.pos_y][block_c.pos_x][0]), sp_shift_mv);
predictor->point[3].mv[1] = rshift_rnd_sf((mot_scale[refC] * tmp_mv[block_c.pos_y][block_c.pos_x][1]), sp_shift_mv);
}
else
{
predictor->point[3].mv[0] = -(12 >> mv_rescale);
predictor->point[3].mv[1] = 0;
}
//Up-Left predictor
if (block_d.available)
{
predictor->point[4].mv[0] = rshift_rnd_sf((mot_scale[refD] * tmp_mv[block_d.pos_y][block_d.pos_x][0]), sp_shift_mv);
predictor->point[4].mv[1] = rshift_rnd_sf((mot_scale[refD] * tmp_mv[block_d.pos_y][block_d.pos_x][1]), sp_shift_mv);
}
else
{
predictor->point[4].mv[0] = 0;
predictor->point[4].mv[1] = -(12 >> mv_rescale);
}
}
else // MB-AFF mode
{
// Field Macroblock
if (list_offset)
{
refA = block_a.available
? img->mb_data[block_a.mb_addr].mb_field
? (int) refPic[block_a.pos_y][block_a.pos_x]
: (int) refPic[block_a.pos_y][block_a.pos_x] * 2 : -1;
refB =block_b.available
? img->mb_data[block_b.mb_addr].mb_field
? (int) refPic[block_b.pos_y][block_b.pos_x]
: (int) refPic[block_b.pos_y][block_b.pos_x] * 2 : -1;
refC = block_c.available
? img->mb_data[block_c.mb_addr].mb_field
? (int) refPic[block_c.pos_y][block_c.pos_x]
: (int) refPic[block_c.pos_y][block_c.pos_x] * 2 : -1;
refD = block_d.available
? img->mb_data[block_d.mb_addr].mb_field
? (int) refPic[block_d.pos_y][block_d.pos_x]
: (int) refPic[block_d.pos_y][block_d.pos_x] * 2 : -1;
// Left Predictor
predictor->point[1].mv[0] = (block_a.available)
? rshift_rnd_sf((mot_scale[refA] * tmp_mv[block_a.pos_y][block_a.pos_x][0]), sp_shift_mv) : (12 >> mv_rescale);
predictor->point[1].mv[1] = (block_a.available)
? img->mb_data[block_a.mb_addr].mb_field
? rshift_rnd_sf((mot_scale[refA] * tmp_mv[block_a.pos_y][block_a.pos_x][1]), sp_shift_mv)
: rshift_rnd_sf((mot_scale[refA] * tmp_mv[block_a.pos_y][block_a.pos_x][1]), sp_shift_mv + 1) : 0;
// Up predictor
predictor->point[2].mv[0] = (block_b.available)
? rshift_rnd_sf((mot_scale[refB] * tmp_mv[block_b.pos_y][block_b.pos_x][0]), sp_shift_mv) : 0;
predictor->point[2].mv[1] = (block_b.available)
? img->mb_data[block_b.mb_addr].mb_field
? rshift_rnd_sf((mot_scale[refB] * tmp_mv[block_b.pos_y][block_b.pos_x][1]), sp_shift_mv)
: rshift_rnd_sf((mot_scale[refB] * tmp_mv[block_b.pos_y][block_b.pos_x][1]), sp_shift_mv + 1) : (12 >> mv_rescale);
// Up-Right predictor
predictor->point[3].mv[0] = (block_c.available)
? rshift_rnd_sf((mot_scale[refC] * tmp_mv[block_c.pos_y][block_c.pos_x][0]), sp_shift_mv) : -(12 >> mv_rescale);
predictor->point[3].mv[1] = (block_c.available)
? img->mb_data[block_c.mb_addr].mb_field
? rshift_rnd_sf((mot_scale[refC] * tmp_mv[block_c.pos_y][block_c.pos_x][1]), sp_shift_mv)
: rshift_rnd_sf((mot_scale[refC] * tmp_mv[block_c.pos_y][block_c.pos_x][1]), sp_shift_mv + 1) : 0;
//Up-Left predictor
predictor->point[4].mv[0] = (block_d.available)
? rshift_rnd_sf((mot_scale[refD] * tmp_mv[block_d.pos_y][block_d.pos_x][0]), sp_shift_mv) : 0;
predictor->point[4].mv[1] = (block_d.available)
? img->mb_data[block_d.mb_addr].mb_field
? rshift_rnd_sf((mot_scale[refD] * tmp_mv[block_d.pos_y][block_d.pos_x][1]), sp_shift_mv)
: rshift_rnd_sf((mot_scale[refD] * tmp_mv[block_d.pos_y][block_d.pos_x][1]), sp_shift_mv + 1) : -(12 >> mv_rescale);
}
else // Frame macroblock
{
refA = block_a.available
? img->mb_data[block_a.mb_addr].mb_field
? (int) refPic[block_a.pos_y][block_a.pos_x] >> 1
: (int) refPic[block_a.pos_y][block_a.pos_x] : -1;
refB = block_b.available
? img->mb_data[block_b.mb_addr].mb_field
? (int) refPic[block_b.pos_y][block_b.pos_x] >> 1
: (int) refPic[block_b.pos_y][block_b.pos_x] : -1;
refC = block_c.available
? img->mb_data[block_c.mb_addr].mb_field
? (int) refPic[block_c.pos_y][block_c.pos_x] >> 1
: (int) refPic[block_c.pos_y][block_c.pos_x] : -1;
refD = block_d.available
? img->mb_data[block_d.mb_addr].mb_field
? (int) refPic[block_d.pos_y][block_d.pos_x] >> 1
: (int) refPic[block_d.pos_y][block_d.pos_x] : -1;
// Left Predictor
predictor->point[1].mv[0] = (block_a.available)
? rshift_rnd_sf((mot_scale[refA] * tmp_mv[block_a.pos_y][block_a.pos_x][0]), sp_shift_mv) : (12 >> mv_rescale);
predictor->point[1].mv[1] = (block_a.available)
? img->mb_data[block_a.mb_addr].mb_field
? rshift_rnd_sf((mot_scale[refA] * tmp_mv[block_a.pos_y][block_a.pos_x][1]), sp_shift_mv - 1)
: rshift_rnd_sf((mot_scale[refA] * tmp_mv[block_a.pos_y][block_a.pos_x][1]), sp_shift_mv) : 0;
// Up predictor
predictor->point[2].mv[0] = (block_b.available)
? rshift_rnd_sf((mot_scale[refB] * tmp_mv[block_b.pos_y][block_b.pos_x][0]), sp_shift_mv) : 0;
predictor->point[2].mv[1] = (block_b.available)
? img->mb_data[block_b.mb_addr].mb_field
? rshift_rnd_sf((mot_scale[refB] * tmp_mv[block_b.pos_y][block_b.pos_x][1]), sp_shift_mv - 1)
: rshift_rnd_sf((mot_scale[refB] * tmp_mv[block_b.pos_y][block_b.pos_x][1]), sp_shift_mv) : (12 >> mv_rescale);
// Up-Right predictor
predictor->point[3].mv[0] = (block_c.available)
? rshift_rnd_sf((mot_scale[refC] * tmp_mv[block_c.pos_y][block_c.pos_x][0]), sp_shift_mv) : -(12 >> mv_rescale);
predictor->point[3].mv[1] = (block_c.available)
? img->mb_data[block_c.mb_addr].mb_field
? rshift_rnd_sf((mot_scale[refC] * tmp_mv[block_c.pos_y][block_c.pos_x][1]), sp_shift_mv - 1)
: rshift_rnd_sf((mot_scale[refC] * tmp_mv[block_c.pos_y][block_c.pos_x][1]), sp_shift_mv) : 0;
//Up-Left predictor
predictor->point[4].mv[0] = (block_d.available)
? rshift_rnd_sf((mot_scale[refD] * tmp_mv[block_d.pos_y][block_d.pos_x][0]), sp_shift_mv) : 0;
predictor->point[4].mv[1] = (block_d.available)
? img->mb_data[block_d.mb_addr].mb_field
? rshift_rnd_sf((mot_scale[refD] * tmp_mv[block_d.pos_y][block_d.pos_x][1]), sp_shift_mv - 1)
: rshift_rnd_sf((mot_scale[refD] * tmp_mv[block_d.pos_y][block_d.pos_x][1]), sp_shift_mv) : -(12 >> mv_rescale);
}
}
return ((refA == -1) + (refB == -1) + (refC == -1 && refD == -1));
}
/*!
***********************************************************************
* \brief
* Spatial Predictors
* AMT/HYC
***********************************************************************
*/
static void EPZSSpatialMemPredictors (int list,
short ref,
int blocktype,
int pic_x,
int bs_x,
int bs_y,
int by,
int *prednum,
int img_width,
EPZSStructure * predictor)
{
#if EPZSREF
short ***mv = EPZSMotion[list][ref][blocktype];
int *cur_mv = predictor->point[*prednum].mv;
// Left Predictor
cur_mv[0] = (pic_x > 0) ? mv[by][pic_x - bs_x][0] : 0;
cur_mv[1] = (pic_x > 0) ? mv[by][pic_x - bs_x][1] : 0;
*prednum += (cur_mv[0] | cur_mv[1])!=0;
// Up predictor
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = (by > 0) ? mv[by - bs_y][pic_x][0] : mv[4 - bs_y][pic_x][0];
cur_mv[1] = (by > 0) ? mv[by - bs_y][pic_x][1] : mv[4 - bs_y][pic_x][1];
*prednum += (cur_mv[0] | cur_mv[1])!=0;
// Up-Right predictor
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = (pic_x + bs_x < img_width) ? (by > 0)
? mv[by - bs_y][pic_x + bs_x][0] : mv[4 - bs_y][pic_x + bs_x][0] : 0;
cur_mv[1] = (pic_x + bs_x < img_width) ? (by > 0)
? mv[by - bs_y][pic_x + bs_x][1] : mv[4 - bs_y][pic_x + bs_x][1] : 0;
*prednum += (cur_mv[0] | cur_mv[1])!=0;
#else
int mot_scale = mv_scale[list][ref][0];
short **mv = EPZSMotion[list][blocktype];
// Left Predictor
predictor->point[*prednum].mv[0] = (pic_x > 0)
? rshift_rnd_sf((mot_scale * mv[by][pic_x - bs_x][0]), 8)
: 0;
predictor->point[*prednum].mv[1] = (pic_x > 0)
? rshift_rnd_sf((mot_scale * mv[by][pic_x - bs_x][1]), 8)
: 0;
*prednum += ((predictor->point[*prednum].mv[0] != 0) || (predictor->point[*prednum].mv[1] != 0));
// Up predictor
predictor->point[*prednum].mv[0] = (by > 0)
? rshift_rnd_sf((mot_scale * mv[by - bs_y][pic_x][0]), 8)
: rshift_rnd_sf((mot_scale * mv[4 - bs_y][pic_x][0]), 8);
predictor->point[*prednum].mv[1] = (by > 0)
? rshift_rnd_sf((mot_scale * mv[by - bs_y][pic_x][1]), 8)
: rshift_rnd_sf((mot_scale * mv[4 - bs_y][pic_x][1]), 8);
*prednum += ((predictor->point[*prednum].mv[0] != 0) || (predictor->point[*prednum].mv[1] != 0));
// Up-Right predictor
predictor->point[*prednum].mv[0] = (pic_x + bs_x < img_width)
? (by > 0)
? rshift_rnd_sf((mot_scale * mv[by - bs_y][pic_x + bs_x][0]), 8)
: rshift_rnd_sf((mot_scale * mv[4 - bs_y][pic_x + bs_x][0]), 8)
: 0;
predictor->point[*prednum].mv[1] = (pic_x + bs_x < img_width)
? (by > 0)
? rshift_rnd_sf((mot_scale * mv[by - bs_y][pic_x + bs_x][1]), 8)
: rshift_rnd_sf((mot_scale * mv[4 - bs_y][pic_x + bs_x][1]), 8)
: 0;
*prednum += ((predictor->point[*prednum].mv[0] != 0) || (predictor->point[*prednum].mv[1] != 0));
#endif
}
/*!
***********************************************************************
* \brief
* Temporal Predictors
* AMT/HYC
***********************************************************************
*/
static void
EPZSTemporalPredictors (int list, // <-- current list
int list_offset, // <-- list offset for MBAFF
short ref, // <-- current reference frame
int o_block_x, // <-- absolute x-coordinate of regarded AxB block
int o_block_y, // <-- absolute y-coordinate of regarded AxB block
EPZSStructure * predictor,
int *prednum,
int block_available_left,
int block_available_up,
int block_available_right,
int block_available_below,
int blockshape_x,
int blockshape_y,
int stopCriterion,
int min_mcost)
{
int mvScale = mv_scale[list + list_offset][ref][0];
short ***col_mv = (list_offset == 0) ? EPZSCo_located->mv[list]
: (list_offset == 2) ? EPZSCo_located->top_mv[list] : EPZSCo_located->bottom_mv[list];
short temp_shift_mv = 8 + mv_rescale; // 16 - invmv_precision + mv_rescale
int *cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd_sf((mvScale * col_mv[o_block_y][o_block_x][0]), temp_shift_mv);
cur_mv[1] = rshift_rnd_sf((mvScale * col_mv[o_block_y][o_block_x][1]), temp_shift_mv);
*prednum += (cur_mv[0] | cur_mv[1])!=0;
if (min_mcost > stopCriterion && ref < 2)
{
if (block_available_left)
{
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd_sf((mvScale * col_mv[o_block_y][o_block_x - 1][0]), temp_shift_mv);
cur_mv[1] = rshift_rnd_sf((mvScale * col_mv[o_block_y][o_block_x - 1][1]), temp_shift_mv);
*prednum += (cur_mv[0] | cur_mv[1])!=0;
//Up_Left
if (block_available_up)
{
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd_sf((mvScale * col_mv[o_block_y - 1][o_block_x - 1][0]), temp_shift_mv);
cur_mv[1] = rshift_rnd_sf((mvScale * col_mv[o_block_y - 1][o_block_x - 1][1]), temp_shift_mv);
*prednum += (cur_mv[0] | cur_mv[1])!=0;
}
//Down_Left
if (block_available_below)
{
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd_sf((mvScale * col_mv[o_block_y + blockshape_y][o_block_x - 1][0]), temp_shift_mv);
cur_mv[1] = rshift_rnd_sf((mvScale * col_mv[o_block_y + blockshape_y][o_block_x - 1][1]), temp_shift_mv);
*prednum += (cur_mv[0] | cur_mv[1])!=0;
}
}
// Up
if (block_available_up)
{
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd_sf((mvScale * col_mv[o_block_y - 1][o_block_x][0]), temp_shift_mv);
cur_mv[1] = rshift_rnd_sf((mvScale * col_mv[o_block_y - 1][o_block_x][1]), temp_shift_mv);
*prednum += (cur_mv[0] | cur_mv[1])!=0;
}
// Up - Right
if (block_available_right)
{
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd_sf((mvScale * col_mv[o_block_y][o_block_x + blockshape_x][0]), temp_shift_mv);
cur_mv[1] = rshift_rnd_sf((mvScale * col_mv[o_block_y][o_block_x + blockshape_x][1]), temp_shift_mv);
*prednum += (cur_mv[0] | cur_mv[1])!=0;
if (block_available_up)
{
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd_sf((mvScale * col_mv[o_block_y - 1][o_block_x + blockshape_x][0]), temp_shift_mv);
cur_mv[1] = rshift_rnd_sf((mvScale * col_mv[o_block_y - 1][o_block_x + blockshape_x][1]), temp_shift_mv);
*prednum += (cur_mv[0] | cur_mv[1])!=0;
}
if (block_available_below)
{
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd_sf((mvScale * col_mv[o_block_y + blockshape_y][o_block_x + blockshape_x][0]), temp_shift_mv);
cur_mv[1] = rshift_rnd_sf((mvScale * col_mv[o_block_y + blockshape_y][o_block_x + blockshape_x][1]), temp_shift_mv);
*prednum += (cur_mv[0] | cur_mv[1])!=0;
}
}
if (block_available_below)
{
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd_sf((mvScale * col_mv[o_block_y + blockshape_y][o_block_x][0]), temp_shift_mv);
cur_mv[1] = rshift_rnd_sf((mvScale * col_mv[o_block_y + blockshape_y][o_block_x][1]), temp_shift_mv);
*prednum += (cur_mv[0] | cur_mv[1])!=0;
}
}
}
/*!
************************************************************************
* \brief
* EPZS Block Type Predictors
************************************************************************
*/
static void EPZSBlockTypePredictors (int block_x, int block_y, int blocktype, int ref, int list,
EPZSStructure * predictor, int *prednum)
{
short ***all_mv = img->all_mv[block_y][block_x][list];
short block_shift_mv = 8 + mv_rescale;
int *cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd((all_mv[ref][(blk_parent[blocktype])][0]), mv_rescale);
cur_mv[1] = rshift_rnd((all_mv[ref][(blk_parent[blocktype])][1]), mv_rescale);
*prednum += ((cur_mv[0] | cur_mv[1])!=0);
if ((ref > 0) && (blocktype < 5 || img->structure != FRAME))
{
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd_sf((mv_scale[list][ref][ref-1] * all_mv[ref-1][blocktype][0]), block_shift_mv );
cur_mv[1] = rshift_rnd_sf((mv_scale[list][ref][ref-1] * all_mv[ref-1][blocktype][1]), block_shift_mv );
*prednum += (cur_mv[0] | cur_mv[1])!=0;
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd_sf((mv_scale[list][ref][0] * all_mv[0][blocktype][0]), block_shift_mv );
cur_mv[1] = rshift_rnd_sf((mv_scale[list][ref][0] * all_mv[0][blocktype][1]), block_shift_mv );
*prednum += (cur_mv[0] | cur_mv[1])!=0;
}
if (blocktype != 1)
{
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd((all_mv[ref][1][0]), mv_rescale);
cur_mv[1] = rshift_rnd((all_mv[ref][1][1]), mv_rescale);
*prednum += (cur_mv[0] | cur_mv[1])!=0;
}
if (blocktype != 4)
{
cur_mv = predictor->point[*prednum].mv;
cur_mv[0] = rshift_rnd((all_mv[ref][4][0]), mv_rescale);
cur_mv[1] = rshift_rnd((all_mv[ref][4][1]), mv_rescale);
*prednum += (cur_mv[0] | cur_mv[1])!=0;
}
}
/*!
************************************************************************
* \brief
* EPZS Window Based Predictors
************************************************************************
*/
static void EPZSWindowPredictors (short mv[2], EPZSStructure *predictor, int *prednum, int extended)
{
int pos;
EPZSStructure *windowPred = (extended) ? window_predictor_extended : window_predictor;
for (pos = 0; pos < windowPred->searchPoints; pos++)
{
predictor->point[(*prednum) ].mv[0] = mv[0] + windowPred->point[pos].mv[0];
predictor->point[(*prednum)++].mv[1] = mv[1] + windowPred->point[pos].mv[1];
}
}
/*!
***********************************************************************
* \brief
* FAST Motion Estimation using EPZS
* AMT/HYC
***********************************************************************
*/
int // ==> minimum motion cost after search
EPZSPelBlockMotionSearch (imgpel * cur_pic, // <-- original pixel values for the AxB block
short ref, // <-- reference picture
int list, // <-- reference list
int list_offset, // <-- offset for Mbaff
signed char ***refPic, // <-- reference array
short ****tmp_mv, // <-- mv array
int pic_pix_x, // <-- absolute x-coordinate of regarded AxB block
int pic_pix_y, // <-- absolute y-coordinate of regarded AxB block
int blocktype, // <-- block type (1-16x16 ... 7-4x4)
short pred_mv[2], // <-- motion vector predictor (x) in sub-pel units
short mv[2], // <--> in: search center (x) / out: motion vector (x) - in pel units
int search_range, // <-- 1-d search range in pel units
int min_mcost, // <-- minimum motion cost (cost for center or huge value)
int lambda_factor) // <-- lagrangian parameter for determining motion cost
{
StorablePicture *ref_picture = listX[list+list_offset][ref];
short blocksize_y = input->blc_size[blocktype][1]; // vertical block size
short blocksize_x = input->blc_size[blocktype][0]; // horizontal block size
short blockshape_x = (blocksize_x >> 2); // horizontal block size in 4-pel units
short blockshape_y = (blocksize_y >> 2); // vertical block size in 4-pel units
short mb_x = pic_pix_x - img->opix_x;
short mb_y = pic_pix_y - img->opix_y;
short pic_pix_x2 = pic_pix_x >> 2;
short pic_pix_y2 = pic_pix_y >> 2;
short block_x = (mb_x >> 2);
short block_y = (mb_y >> 2);
int pred_x = (pic_pix_x << 2) + pred_mv[0]; // predicted position x (in sub-pel units)
int pred_y = (pic_pix_y << 2) + pred_mv[1]; // predicted position y (in sub-pel units)
int center_x = (pic_pix_x << (2 - mv_rescale))+ mv[0]; // center position x (in pel units)
int center_y = (pic_pix_y << (2 - mv_rescale))+ mv[1]; // center position y (in pel units)
int cand_x = center_x << mv_rescale;
int cand_y = center_y << mv_rescale;
int tempmv[2] = {mv[0], mv[1]};
int tempmv2[2] = {0, 0};
int stopCriterion = medthres[blocktype];
int mapCenter_x = search_range - mv[0];
int mapCenter_y = search_range - mv[1];
int second_mcost = INT_MAX;
short apply_weights = (active_pps->weighted_pred_flag > 0 || (active_pps->weighted_bipred_idc && (img->type == B_SLICE))) && input->UseWeightedReferenceME;
int *prevSad = EPZSDistortion[list + list_offset][blocktype - 1];
short *motion=NULL;
int dist_method = F_PEL + 3 * apply_weights;
short invalid_refs = 0;
byte checkMedian = FALSE;
EPZSStructure *searchPatternF = searchPattern;
EPZSBlkCount ++;
ref_pic_sub.luma = ref_picture->imgY_sub;
img_width = ref_picture->size_x;
img_height = ref_picture->size_y;
width_pad = ref_picture->size_x_pad;
height_pad = ref_picture->size_y_pad;
if (apply_weights)
{
weight_luma = wp_weight[list + list_offset][ref][0];
offset_luma = wp_offset[list + list_offset][ref][0];
}
if ( ChromaMEEnable)
{
ref_pic_sub.crcb[0] = ref_picture->imgUV_sub[0];
ref_pic_sub.crcb[1] = ref_picture->imgUV_sub[1];
width_pad_cr = ref_picture->size_x_cr_pad;
height_pad_cr = ref_picture->size_y_cr_pad;
if (apply_weights)
{
weight_cr[0] = wp_weight[list + list_offset][ref][1];
weight_cr[1] = wp_weight[list + list_offset][ref][2];
offset_cr[0] = wp_offset[list + list_offset][ref][1];
offset_cr[1] = wp_offset[list + list_offset][ref][2];
}
}
pic_pix_x = (pic_pix_x << (2 - mv_rescale));
pic_pix_y = (pic_pix_y << (2 - mv_rescale));
if (input->EPZSSpatialMem)
{
#if EPZSREF
motion = EPZSMotion[list + list_offset][ref][blocktype - 1][block_y][pic_pix_x2];
#else
motion = EPZSMotion[list + list_offset][blocktype - 1][block_y][pic_pix_x2];
#endif
}
//===== set function for getting reference picture lines =====
ref_access_method = CHECK_RANGE ? FAST_ACCESS : UMV_ACCESS;
// Clear EPZSMap
// memset(EPZSMap[0],FALSE,searcharray*searcharray);
// Check median candidate;
EPZSMap[search_range][search_range] = EPZSBlkCount;
//--- initialize motion cost (cost for motion vector) and check ---
min_mcost = MV_COST_SMP (lambda_factor, cand_x, cand_y, pred_x, pred_y);
//--- add residual cost to motion cost ---
min_mcost += computeUniPred[dist_method](cur_pic, blocksize_y, blocksize_x,
INT_MAX, cand_x + IMG_PAD_SIZE_TIMES4, cand_y + IMG_PAD_SIZE_TIMES4);
// Additional threshold for ref>0
if ((ref>0 && img->structure == FRAME)
&& (prevSad[pic_pix_x2] < medthres[blocktype])
&& (prevSad[pic_pix_x2] < min_mcost))
{
#if EPZSREF
if (input->EPZSSpatialMem)
#else
if (input->EPZSSpatialMem && ref == 0)
#endif
{
motion[0] = tempmv[0];
motion[1] = tempmv[1];
}
return min_mcost;
}
// if ((center_x > search_range) && (center_x < img_width - search_range - blocksize_x) &&
//(center_y > search_range) && (center_y < img_height - search_range - blocksize_y) )
if ( (center_x > search_range) && (center_x < ((img_width - blocksize_x) << (input->EPZSSubPelGrid * 2)) - search_range)
&& (center_y > search_range) && (center_y < ((img_height - blocksize_y) << (input->EPZSSubPelGrid * 2)) - search_range))
{
ref_access_method = FAST_ACCESS;
}
else
{
ref_access_method = UMV_ACCESS;
}
//! If medthres satisfied, then terminate, otherwise generate Predictors
//! Condition could be strengthened by consideration distortion of adjacent partitions.
if (min_mcost > stopCriterion)
{
int mb_available_right = (img->mb_x < (img_width >> 4) - 1);
int mb_available_below = (img->mb_y < (img_height >> 4) - 1);
int sadA, sadB, sadC;
int block_available_right;
int block_available_below;
int prednum = 5;
int patternStop = 0, pointNumber = 0, checkPts, nextLast = 0;
int totalCheckPts = 0, motionDirection = 0;
int conditionEPZS;
int tmv[2];
int pos, mcost;
PixelPos block_a, block_b, block_c, block_d;
getLuma4x4Neighbour (img->current_mb_nr, mb_x - 1, mb_y, &block_a);
getLuma4x4Neighbour (img->current_mb_nr, mb_x, mb_y - 1, &block_b);
getLuma4x4Neighbour (img->current_mb_nr, mb_x + blocksize_x, mb_y -1, &block_c);
getLuma4x4Neighbour (img->current_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)
{
block_available_right = (blocksize_x != MB_BLOCK_SIZE) || mb_available_right;
if (blocksize_x == MB_BLOCK_SIZE)
block_c.available = 0;
}
else
{
block_available_right = (mb_x + blocksize_x != 8) || mb_available_right;
if (mb_x + blocksize_x == 8)
block_c.available = 0;
}
}
else
{
block_available_right = (mb_x + blocksize_x != MB_BLOCK_SIZE) || mb_available_right;
if (mb_x + blocksize_x == MB_BLOCK_SIZE)
block_c.available = 0;
}
}
else
{
block_available_right = (mb_x + blocksize_x != MB_BLOCK_SIZE) || mb_available_right;
}
block_available_below = (mb_y + blocksize_y != MB_BLOCK_SIZE) || (mb_available_below);
sadA = block_a.available ? prevSad[pic_pix_x2 - blockshape_x] : INT_MAX;
sadB = block_b.available ? prevSad[pic_pix_x2] : INT_MAX;
sadC = block_c.available ? prevSad[pic_pix_x2 + blockshape_x] : INT_MAX;
stopCriterion = imin(sadA,imin(sadB,sadC));
stopCriterion = imax(stopCriterion,minthres[blocktype]);
stopCriterion = imin(stopCriterion,maxthres[blocktype]);
stopCriterion = (9 * imax (medthres[blocktype], stopCriterion) + 2 * medthres[blocktype]) >> 3;
//! Add Spatial Predictors in predictor list.
//! Scheme adds zero, left, top-left, top, top-right. Note that top-left adds very little
//! in terms of performance and could be removed with little penalty if any.
invalid_refs = EPZSSpatialPredictors (block_a, block_b, block_c, block_d,
list, list_offset, ref, refPic[list], tmp_mv[list], predictor);
if (input->EPZSSpatialMem)
EPZSSpatialMemPredictors (list + list_offset, ref, blocktype - 1, pic_pix_x2,
blockshape_x, blockshape_y, block_y, &prednum, img_width>>2, predictor);
// Temporal predictors
if (input->EPZSTemporal)
EPZSTemporalPredictors (list, list_offset, ref, pic_pix_x2, pic_pix_y2, predictor, &prednum,
block_a.available, block_b.available, block_available_right,
block_available_below, blockshape_x, blockshape_y, stopCriterion, min_mcost);
//! Window Size Based Predictors
//! Basically replaces a Hierarchical ME concept and helps escaping local minima, or
//! determining large motion variations.
//! Following predictors can be adjusted further (i.e. removed, conditioned etc)
//! based on distortion, correlation of adjacent MVs, complexity etc. These predictors
//! and their conditioning could also be moved after all other predictors have been
//! tested. Adaptation could also be based on type of material and coding mode (i.e.
//! field/frame coding,MBAFF etc considering the higher dependency with opposite parity field
//conditionEPZS = ((min_mcost > stopCriterion)
// && (input->EPZSFixed > 1 || (input->EPZSFixed && img->type == P_SLICE)));
//conditionEPZS = ((ref == 0) && (blocktype < 5) && (min_mcost > stopCriterion)
//&& (input->EPZSFixed > 1 || (input->EPZSFixed && img->type == P_SLICE)));
conditionEPZS = ((min_mcost > stopCriterion) && ((ref < 2 && blocktype < 5)
|| ((img->structure!=FRAME || list_offset) && ref < 3))
&& (input->EPZSFixed > 1 || (input->EPZSFixed && img->type == P_SLICE)));
if (conditionEPZS)
EPZSWindowPredictors (mv, predictor, &prednum,
(blocktype < 5) && (invalid_refs > 2) && (ref < 1 + (img->structure!=FRAME || list_offset)));
//! Blocktype/Reference dependent predictors.
//! Since already mvs for other blocktypes/references have been computed, we can reuse
//! them in order to easier determine the optimal point. Use of predictors could depend
//! on cost,
//conditionEPZS = (ref == 0 || (ref > 0 && min_mcost > stopCriterion) || img->structure != FRAME || list_offset);
conditionEPZS = (ref == 0 || (ref > 0 && min_mcost > stopCriterion));
// above seems to result in memory leak issues which need to be resolved
if (conditionEPZS && img->current_mb_nr != 0)
EPZSBlockTypePredictors (block_x, block_y, blocktype, ref, list, predictor, &prednum);
//! Check all predictors
for (pos = 0; pos < prednum; pos++)
{
tmv[0] = predictor->point[pos].mv[0];
tmv[1] = predictor->point[pos].mv[1];
//if ((iabs (tmv[0] - mv[0]) > search_range || iabs (tmv[1] - mv[1]) > search_range) && (tmv[0] || tmv[1]))
if (iabs (tmv[0] - mv[0]) > search_range || iabs (tmv[1] - mv[1]) > search_range)
continue;
if ((iabs (tmv[0] - mv[0]) <= search_range) && (iabs (tmv[1] - mv[1]) <= search_range))
{
if (EPZSMap[mapCenter_y + tmv[1]][mapCenter_x + tmv[0]] == EPZSBlkCount)
continue;
else
EPZSMap[mapCenter_y + tmv[1]][mapCenter_x + tmv[0]] = EPZSBlkCount;
}
cand_x = (pic_pix_x + tmv[0])<<mv_rescale;
cand_y = (pic_pix_y + tmv[1])<<mv_rescale;
//--- set motion cost (cost for motion vector) and check ---
mcost = MV_COST_SMP (lambda_factor, cand_x, cand_y, pred_x, pred_y);
if (mcost >= second_mcost) continue;
ref_access_method = CHECK_RANGE ? FAST_ACCESS : UMV_ACCESS;
mcost += computeUniPred[dist_method](cur_pic, blocksize_y,blocksize_x,
second_mcost - mcost, cand_x + IMG_PAD_SIZE_TIMES4,cand_y + IMG_PAD_SIZE_TIMES4);
//--- check if motion cost is less than minimum cost ---
if (mcost < min_mcost)
{
tempmv2[0] = tempmv[0];
tempmv2[1] = tempmv[1];
tempmv[0] = tmv[0];
tempmv[1] = tmv[1];
second_mcost = min_mcost;
min_mcost = mcost;
checkMedian = TRUE;
}
//else if (mcost < second_mcost && (tempmv[0] != tmv[0] || tempmv[1] != tmv[1]))
else if (mcost < second_mcost)
{
tempmv2[0] = tmv[0];
tempmv2[1] = tmv[1];
second_mcost = mcost;
checkMedian = TRUE;
}
}
//! Refine using EPZS pattern if needed
//! Note that we are using a conservative threshold method. Threshold
//! could be tested after checking only a certain number of predictors
//! instead of the full set. Code could be easily modified for this task.
if (min_mcost > stopCriterion)
{
//! Adapt pattern based on different conditions.
if (input->EPZSPattern != 0)
{
if ((min_mcost < stopCriterion + ((3 * medthres[blocktype]) >> 1)))
{
if ((tempmv[0] == 0 && tempmv[1] == 0)
|| (iabs (tempmv[0] - mv[0]) < (2<<(2-mv_rescale)) && iabs (tempmv[1] - mv[1]) < (2<<(2-mv_rescale))))
searchPatternF = sdiamond;
else
searchPatternF = square;
}
else if (blocktype > 5 || (ref > 0 && blocktype != 1))
searchPatternF = square;
else
searchPatternF = searchPattern;
}
totalCheckPts = searchPatternF->searchPoints;
//! center on best predictor
center_x = tempmv[0];
center_y = tempmv[1];
while(1)
{
do
{
checkPts = totalCheckPts;
do
{
tmv[0] = center_x + searchPatternF->point[pointNumber].mv[0];
tmv[1] = center_y + searchPatternF->point[pointNumber].mv[1];
cand_x = (pic_pix_x + tmv[0])<<mv_rescale;
cand_y = (pic_pix_y + tmv[1])<<mv_rescale;
if ((iabs (tmv[0] - mv[0]) <= search_range)
&& (iabs (tmv[1] - mv[1]) <= search_range))
{
if (EPZSMap[mapCenter_y + tmv[1]][mapCenter_x + tmv[0]] != EPZSBlkCount)
EPZSMap[mapCenter_y + tmv[1]][mapCenter_x + tmv[0]] = EPZSBlkCount;
else
{
pointNumber += 1;
if (pointNumber >= searchPatternF->searchPoints)
pointNumber -= searchPatternF->searchPoints;
checkPts -= 1;
continue;
}
mcost = MV_COST_SMP (lambda_factor, cand_x, cand_y, pred_x, pred_y);
if (mcost < min_mcost)
{
ref_access_method = CHECK_RANGE ? FAST_ACCESS : UMV_ACCESS;
mcost += computeUniPred[dist_method](cur_pic, blocksize_y,blocksize_x,
min_mcost - mcost, cand_x + IMG_PAD_SIZE_TIMES4, cand_y + IMG_PAD_SIZE_TIMES4);
if (mcost < min_mcost)
{
min_mcost = mcost;
tempmv[0] = tmv[0];
tempmv[1] = tmv[1];
motionDirection = pointNumber;
}
}
}
pointNumber += 1;
if (pointNumber >= searchPatternF->searchPoints)
pointNumber -= searchPatternF->searchPoints;
checkPts -= 1;
}
while (checkPts > 0);
if (nextLast || ((tempmv[0] == center_x) && (tempmv[1] == center_y)))
{
patternStop = searchPatternF->stopSearch;
searchPatternF = searchPatternF->nextpattern;
totalCheckPts = searchPatternF->searchPoints;
nextLast = searchPatternF->nextLast;
motionDirection = 0;
pointNumber = 0;
}
else
{
totalCheckPts = searchPatternF->point[motionDirection].next_points;
pointNumber = searchPatternF->point[motionDirection].start_nmbr;
center_x = tempmv[0];
center_y = tempmv[1];
}
}
while (patternStop != 1);
if ((ref>0) && (img->structure == FRAME)
&& (( 4 * prevSad[pic_pix_x2] < min_mcost) ||
((3 * prevSad[pic_pix_x2] < min_mcost) && (prevSad[pic_pix_x2] <= stopCriterion))))
{
mv[0] = tempmv[0];
mv[1] = tempmv[1];
#if EPZSREF
if (input->EPZSSpatialMem)
#else
if (input->EPZSSpatialMem && ref == 0)
#endif
{
motion[0] = tempmv[0];
motion[1] = tempmv[1];
}
return min_mcost;
}
//! Check Second best predictor with EPZS pattern
conditionEPZS = (checkMedian == TRUE)
&& ((img->type == P_SLICE) || (blocktype < 5))
&& (min_mcost > stopCriterion) && (input->EPZSDual > 0);
if (!conditionEPZS) break;
pointNumber = 0;
patternStop = 0;
motionDirection = 0;
nextLast = 0;
if ((tempmv[0] == 0 && tempmv[1] == 0)
|| (tempmv[0] == mv[0] && tempmv[1] == mv[1]))
{
if (iabs (tempmv[0] - mv[0]) < (2<<(2-mv_rescale)) && iabs (tempmv[1] - mv[1]) < (2<<(2-mv_rescale)))
searchPatternF = sdiamond;
else
searchPatternF = square;
}
else
searchPatternF = searchPatternD;
totalCheckPts = searchPatternF->searchPoints;
//! Second best. Note that following code is identical as for best predictor.
center_x = tempmv2[0];
center_y = tempmv2[1];
checkMedian = FALSE;
}
}
}
if ((ref==0) || (prevSad[pic_pix_x2] > min_mcost))
prevSad[pic_pix_x2] = min_mcost;
#if EPZSREF
if (input->EPZSSpatialMem)
#else
if (input->EPZSSpatialMem && ref == 0)
#endif
{
motion[0] = tempmv[0];
motion[1] = tempmv[1];
}
mv[0] = tempmv[0];
mv[1] = tempmv[1];
return min_mcost;
}
/*!
***********************************************************************
* \brief
* FAST Motion Estimation using EPZS
* AMT/HYC
***********************************************************************
*/
int // ==> minimum motion cost after search
EPZSBiPredBlockMotionSearch (imgpel * cur_pic, // <-- original pixel values for the AxB block
short ref, // <-- reference picture
int list, // <-- reference list
int list_offset, // <-- offset for Mbaff
signed char ***refPic, // <-- reference array
short ****tmp_mv, // <-- mv array
int pic_pix_x, // <-- absolute x-coordinate of regarded AxB block
int pic_pix_y, // <-- absolute y-coordinate of regarded AxB block
int blocktype, //<-- block type (1-16x16 ... 7-4x4)
short *pred_mv1, // <-- motion vector predictor (x) in sub-pel units
short *pred_mv2, // <-- motion vector predictor (x) in sub-pel units
short mv[2], // <--> in: search center (x) / out: motion vector (x) - in pel units
short s_mv[2], // <--> in: search center (x) / out: motion vector (x) - in pel units
int search_range, // <-- 1-d search range in pel units
int min_mcost, // <-- minimum motion cost (cost for center or huge value)
int lambda_factor) // <-- lagrangian parameter for determining motion cost
{
short blocksize_y = input->blc_size[blocktype][1]; // vertical block size
short blocksize_x = input->blc_size[blocktype][0]; // horizontal block size
short mb_x = pic_pix_x - img->opix_x;
short mb_y = pic_pix_y - img->opix_y;
int pred_x1 = (pic_pix_x << 2) + pred_mv1[0]; // predicted position x (in sub-pel units)
int pred_y1 = (pic_pix_y << 2) + pred_mv1[1]; // predicted position y (in sub-pel units)
int pred_x2 = (pic_pix_x << 2) + pred_mv2[0]; // predicted position x (in sub-pel units)
int pred_y2 = (pic_pix_y << 2) + pred_mv2[1]; // predicted position y (in sub-pel units)
int center2_x = (pic_pix_x << (input->EPZSSubPelGrid * 2))+ mv[0]; // center position x (in pel units)
int center2_y = (pic_pix_y << (input->EPZSSubPelGrid * 2))+ mv[1]; // center position y (in pel units)
int center1_x = (pic_pix_x << (input->EPZSSubPelGrid * 2))+ s_mv[0]; // center position x (in pel units)
int center1_y = (pic_pix_y << (input->EPZSSubPelGrid * 2))+ s_mv[1]; // center position y (in pel units)
int tempmv[2] = {mv[0], mv[1]};
int tempmv2[2] = {0, 0};
int stopCriterion = medthres[blocktype];
int mapCenter_x = search_range - mv[0];
int mapCenter_y = search_range - mv[1];
int second_mcost = INT_MAX;
StorablePicture *ref_picture1 = listX[list + list_offset][ref];
StorablePicture *ref_picture2 = listX[(list ^ 1) + list_offset][0];
short apply_weights = (active_pps->weighted_bipred_idc != 0);
short offset1 = apply_weights ? list == 0
? wp_offset[list_offset ][ref][0]
: wp_offset[list_offset + LIST_1][0 ][0]
: 0;
short offset2 = apply_weights ? list == 0
? wp_offset[list_offset + LIST_1][ref][0]
: wp_offset[list_offset ][0 ][0]
: 0;
short invalid_refs = 0;
byte checkMedian = FALSE;
EPZSStructure *searchPatternF = searchPattern;
EPZSBlkCount ++;
pic_pix_x = (pic_pix_x << (2 - mv_rescale));
pic_pix_y = (pic_pix_y << (2 - mv_rescale));
ref_pic1_sub.luma = ref_picture1->imgY_sub;
ref_pic2_sub.luma = ref_picture2->imgY_sub;
img_width = ref_picture1->size_x;
img_height = ref_picture1->size_y;
width_pad = ref_picture1->size_x_pad;
height_pad = ref_picture1->size_y_pad;
if (apply_weights)
{
weight1 = list == 0 ? wbp_weight[list_offset ][ref][0][0] : wbp_weight[list_offset + LIST_1][0 ][ref][0];
weight2 = list == 0 ? wbp_weight[list_offset + LIST_1][ref][0][0] : wbp_weight[list_offset ][0 ][ref][0];
offsetBi=(offset1 + offset2 + 1)>>1;
computeBiPred = computeBiPred2[F_PEL];
}
else
{
weight1 = 1<<luma_log_weight_denom;
weight2 = 1<<luma_log_weight_denom;
offsetBi = 0;
computeBiPred = computeBiPred1[F_PEL];
}
if ( ChromaMEEnable ) {
ref_pic1_sub.crcb[0] = ref_picture1->imgUV_sub[0];
ref_pic1_sub.crcb[1] = ref_picture1->imgUV_sub[1];
ref_pic2_sub.crcb[0] = ref_picture2->imgUV_sub[0];
ref_pic2_sub.crcb[1] = ref_picture2->imgUV_sub[1];
width_pad_cr = ref_picture1->size_x_cr_pad;
height_pad_cr = ref_picture1->size_y_cr_pad;
if (apply_weights)
{
weight1_cr[0] = list == 0 ? wbp_weight[list_offset ][ref][0][1] : wbp_weight[list_offset + LIST_1][0 ][ref][1];
weight1_cr[1] = list == 0 ? wbp_weight[list_offset ][ref][0][2] : wbp_weight[list_offset + LIST_1][0 ][ref][2];
weight2_cr[0] = list == 0 ? wbp_weight[list_offset + LIST_1][ref][0][1] : wbp_weight[list_offset ][0 ][ref][1];
weight2_cr[1] = list == 0 ? wbp_weight[list_offset + LIST_1][ref][0][2] : wbp_weight[list_offset ][0 ][ref][2];
offsetBi_cr[0] = (list == 0)
? (wp_offset[list_offset ][ref][1] + wp_offset[list_offset + LIST_1][ref][1] + 1) >> 1
: (wp_offset[list_offset + LIST_1][0 ][1] + wp_offset[list_offset ][0 ][1] + 1) >> 1;
offsetBi_cr[1] = (list == 0)
? (wp_offset[list_offset ][ref][2] + wp_offset[list_offset + LIST_1][ref][2] + 1) >> 1
: (wp_offset[list_offset + LIST_1][0 ][2] + wp_offset[list_offset ][0 ][2] + 1) >> 1;
}
else
{
weight1_cr[0] = 1<<chroma_log_weight_denom;
weight1_cr[1] = 1<<chroma_log_weight_denom;
weight2_cr[0] = 1<<chroma_log_weight_denom;
weight2_cr[1] = 1<<chroma_log_weight_denom;
offsetBi_cr[0] = 0;
offsetBi_cr[1] = 0;
}
}
//===== set function for getting reference picture lines from reference 1=====
if ( (center2_x > search_range) && (center2_x < ((img_width - blocksize_x) << (input->EPZSSubPelGrid * 2)) - search_range)
&& (center2_y > search_range) && (center2_y < ((img_height - blocksize_y) << (input->EPZSSubPelGrid * 2)) - search_range))
{
bipred2_access_method = FAST_ACCESS;
}
else
{
bipred2_access_method = UMV_ACCESS;
}
//===== set function for getting reference picture lines from reference 2=====
if ( (center1_x > search_range) && (center1_x < ((img_width - blocksize_x) << (input->EPZSSubPelGrid * 2)) - search_range)
&& (center1_y > search_range) && (center1_y < ((img_height - blocksize_y) << (input->EPZSSubPelGrid * 2)) - search_range))
{
bipred1_access_method = FAST_ACCESS;
}
else
{
bipred1_access_method = UMV_ACCESS;
}
// Clear EPZSMap
//memset(EPZSMap[0],FALSE,searcharray*searcharray);
// Check median candidate;
EPZSMap[search_range][search_range] = EPZSBlkCount;
//--- initialize motion cost (cost for motion vector) and check ---
min_mcost = MV_COST_SMP (lambda_factor, (center1_x<<mv_rescale), (center1_y<<mv_rescale), pred_x1, pred_y1);
min_mcost += MV_COST_SMP (lambda_factor, (center2_x<<mv_rescale), (center2_y<<mv_rescale), pred_x2, pred_y2);
//--- add residual cost to motion cost ---
min_mcost += computeBiPred(cur_pic,
blocksize_y, blocksize_x, INT_MAX,
(center1_x << mv_rescale) + IMG_PAD_SIZE_TIMES4,
(center1_y << mv_rescale) + IMG_PAD_SIZE_TIMES4,
(center2_x << mv_rescale) + IMG_PAD_SIZE_TIMES4,
(center2_y << mv_rescale) + IMG_PAD_SIZE_TIMES4);
//! If medthres satisfied, then terminate, otherwise generate Predictors
if (min_mcost > stopCriterion)
{
int prednum = 5;
int patternStop = 0, pointNumber = 0, checkPts, nextLast = 0;
int totalCheckPts = 0, motionDirection = 0;
int conditionEPZS;
int tmv[2], cand_x, cand_y;
int pos, mcost;
PixelPos block_a, block_b, block_c, block_d;
getLuma4x4Neighbour (img->current_mb_nr, mb_x - 1, mb_y, &block_a);