blob: 319c76f0cd6bca46edacaaf0364f896406945e13 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "mp4def.h"
#include "mp4enc_lib.h"
#include "mp4lib_int.h"
#include "m4venc_oscl.h"
/* 3/29/01 fast half-pel search based on neighboring guess */
/* value ranging from 0 to 4, high complexity (more accurate) to
low complexity (less accurate) */
#define HP_DISTANCE_TH 2 /* half-pel distance threshold */
#define PREF_16_VEC 129 /* 1MV bias versus 4MVs*/
#ifdef __cplusplus
extern "C"
{
#endif
void GenerateSearchRegion(UChar *searchPadding, UChar *ref, Int width, Int height,
Int ilow, Int ihigh, Int jlow, Int jhigh);
void InterpDiag(UChar *prev, Int lx, UChar *pred_block);
void InterpHorz(UChar *prev, Int lx, UChar *pred_block);
void InterpVert(UChar *prev, Int lx, UChar *pred_block);
#ifdef __cplusplus
}
#endif
const static Int distance_tab[9][9] = /* [hp_guess][k] */
{
{0, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 2, 3, 4, 3, 2, 1},
{1, 0, 0, 0, 1, 2, 3, 2, 1},
{1, 2, 1, 0, 1, 2, 3, 4, 3},
{1, 2, 1, 0, 0, 0, 1, 2, 3},
{1, 4, 3, 2, 1, 0, 1, 2, 3},
{1, 2, 3, 2, 1, 0, 0, 0, 1},
{1, 2, 3, 4, 3, 2, 1, 0, 1},
{1, 0, 1, 2, 3, 2, 1, 0, 0}
};
/*=====================================================================
Function: FindHalfPelMB
Date: 10/7/2000
Purpose: Find half pel resolution MV surrounding the full-pel MV
=====================================================================*/
void FindHalfPelMB(VideoEncData *video, UChar *cur, MOT *mot, UChar *ncand,
Int xpos, Int ypos, Int *xhmin, Int *yhmin, Int hp_guess)
{
// hp_mem = ULong *vertArray; /* 20x17 */
// ULong *horzArray; /* 20x16 */
// ULong *diagArray; /* 20x17 */
Int dmin, d;
Int xh, yh;
Int k, kmin = 0;
Int imin, jmin, ilow, jlow;
Int h263_mode = video->encParams->H263_Enabled; /* 3/29/01 */
Int in_range[9] = {0, 1, 1, 1, 1, 1, 1, 1, 1}; /* 3/29/01 */
Int range = video->encParams->SearchRange;
Int lx = video->currVop->pitch;
Int width = video->currVop->width; /* padding */
Int height = video->vol[video->currLayer]->height;
Int(**SAD_MB_HalfPel)(UChar*, UChar*, Int, void*) =
video->functionPointer->SAD_MB_HalfPel;
void *extra_info = video->sad_extra_info;
Int next_hp_pos[9][2] = {{0, 0}, {2, 0}, {1, 1}, {0, 2}, { -1, 1}, { -2, 0}, { -1, -1}, {0, -2}, {0, -1}};
Int next_ncand[9] = {0, 1 , lx, lx, 0, -1, -1, -lx, -lx};
cur = video->currYMB;
/**************** check range ***************************/
/* 3/29/01 */
imin = xpos + (mot[0].x >> 1);
jmin = ypos + (mot[0].y >> 1);
ilow = xpos - range;
jlow = ypos - range;
if (!h263_mode)
{
if (imin <= -15 || imin == ilow)
in_range[1] = in_range[7] = in_range[8] = 0;
else if (imin >= width - 1)
in_range[3] = in_range[4] = in_range[5] = 0;
if (jmin <= -15 || jmin == jlow)
in_range[1] = in_range[2] = in_range[3] = 0;
else if (jmin >= height - 1)
in_range[5] = in_range[6] = in_range[7] = 0;
}
else
{
if (imin <= 0 || imin == ilow)
in_range[1] = in_range[7] = in_range[8] = 0;
else if (imin >= width - 16)
in_range[3] = in_range[4] = in_range[5] = 0;
if (jmin <= 0 || jmin == jlow)
in_range[1] = in_range[2] = in_range[3] = 0;
else if (jmin >= height - 16)
in_range[5] = in_range[6] = in_range[7] = 0;
}
xhmin[0] = 0;
yhmin[0] = 0;
dmin = mot[0].sad;
xh = 0;
yh = -1;
ncand -= lx; /* initial position */
for (k = 2; k <= 8; k += 2)
{
if (distance_tab[hp_guess][k] < HP_DISTANCE_TH)
{
if (in_range[k])
{
d = (*(SAD_MB_HalfPel[((yh&1)<<1)+(xh&1)]))(ncand, cur, (dmin << 16) | lx, extra_info);
if (d < dmin)
{
dmin = d;
xhmin[0] = xh;
yhmin[0] = yh;
kmin = k;
}
else if (d == dmin &&
PV_ABS(mot[0].x + xh) + PV_ABS(mot[0].y + yh) < PV_ABS(mot[0].x + xhmin[0]) + PV_ABS(mot[0].y + yhmin[0]))
{
xhmin[0] = xh;
yhmin[0] = yh;
kmin = k;
}
}
}
xh += next_hp_pos[k][0];
yh += next_hp_pos[k][1];
ncand += next_ncand[k];
if (k == 8)
{
if (xhmin[0] != 0 || yhmin[0] != 0)
{
k = -1;
hp_guess = kmin;
}
}
}
mot[0].sad = dmin;
mot[0].x += xhmin[0];
mot[0].y += yhmin[0];
return ;
}
#ifndef NO_INTER4V
/*=====================================================================
Function: FindHalfPelBlk
Date: 10/7/2000
Purpose: Find half pel resolution MV surrounding the full-pel MV
And decide between 1MV or 4MV mode
=====================================================================*/
///// THIS FUNCTION IS NOT WORKING!!! NEED TO BE RIVISITED
Int FindHalfPelBlk(VideoEncData *video, UChar *cur, MOT *mot, Int sad16, UChar *ncand8[],
UChar *mode, Int xpos, Int ypos, Int *xhmin, Int *yhmin, UChar *hp_mem)
{
Int k, comp;
Int xh, yh;//, xhmin, yhmin;
Int imin, jmin, ilow, jlow;
Int height;
UChar *cand, *cur8;
UChar *hmem;//[17*17]; /* half-pel memory */
Int d, dmin, sad8;
Int lx = video->currVop->pitch;
Int width = video->currVop->width; /* , padding */
Int(*SAD_Blk_HalfPel)(UChar*, UChar*, Int, Int, Int, Int, Int, void*) = video->functionPointer->SAD_Blk_HalfPel;
void *extra_info = video->sad_extra_info;
Int in_range[8]; /* 3/29/01 */
Int range = video->encParams->SearchRange;
Int swidth;
Int next_hp_pos[8][2] = {{1, 0}, {1, 0}, {0, 1}, {0, 1}, { -1, 0}, { -1, 0}, {0, -1}, {0, -1}};
height = video->vol[video->currLayer]->height;
hmem = hp_mem;
sad8 = 0;
for (comp = 0; comp < 4; comp++)
{
#ifdef _SAD_STAT
num_HP_Blk++;
#endif
/**************** check range ***************************/
/* 3/29/01 */
M4VENC_MEMSET(in_range, 1, sizeof(Int) << 3);
imin = xpos + ((comp & 1) << 3) + (mot[comp+1].x >> 1);
jmin = ypos + ((comp & 2) << 2) + (mot[comp+1].y >> 1);
ilow = xpos + ((comp & 1) << 3) - range;
jlow = ypos + ((comp & 2) << 2) - range;
if (imin <= -15 || imin == ilow)
in_range[0] = in_range[6] = in_range[7] = 0;
else if (imin >= width - 1)
in_range[2] = in_range[3] = in_range[4] = 0;
if (jmin <= -15 || jmin == jlow)
in_range[0] = in_range[1] = in_range[2] = 0;
else if (jmin >= height - 1)
in_range[4] = in_range[5] = in_range[6] = 0;
/**************** half-pel search ***********************/
cur8 = cur + ((comp & 1) << 3) + ((comp & 2) << 2) * width ;
/* generate half-pel search region */
{
cand = ncand8[comp+1];
swidth = lx;
}
xhmin[comp+1] = 0;
yhmin[comp+1] = 0;
dmin = mot[comp+1].sad;
xh = -1;
yh = -1;
for (k = 0; k < 8; k++)
{
if (in_range[k])
{
d = (*SAD_Blk_HalfPel)(cand, cur8, dmin, lx, swidth, xh, yh, extra_info);
if (d < dmin)
{
dmin = d;
xhmin[comp+1] = xh;
yhmin[comp+1] = yh;
}
}
xh += next_hp_pos[k][0];
yh += next_hp_pos[k][1];
}
/********************************************/
mot[comp+1].x += xhmin[comp+1];
mot[comp+1].y += yhmin[comp+1];
mot[comp+1].sad = dmin;
sad8 += dmin;
if (sad8 >= sad16 - PREF_16_VEC)
{
*mode = MODE_INTER;
for (k = 1; k <= 4; k++)
{
mot[k].sad = (mot[0].sad + 2) >> 2;
mot[k].x = mot[0].x;
mot[k].y = mot[0].y;
}
return sad8;
}
hmem += (10 * 10);
}
*mode = MODE_INTER4V;
return sad8;
}
#endif /* NO_INTER4V */