2 |
* |
* |
3 |
* Modifications: |
* Modifications: |
4 |
* |
* |
5 |
|
* 22.04.2002 remove some compile warning by chenm001 <chenm001@163.com> |
6 |
|
* 14.04.2002 added MotionEstimationBVOP() |
7 |
* 02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between |
* 02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between |
8 |
* EPZS and EPZS^2 |
* EPZS and EPZS^2 |
9 |
* 08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop |
* 08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop |
42 |
#include "../prediction/mbprediction.h" |
#include "../prediction/mbprediction.h" |
43 |
#include "../global.h" |
#include "../global.h" |
44 |
#include "../utils/timer.h" |
#include "../utils/timer.h" |
45 |
|
#include "motion.h" |
46 |
#include "sad.h" |
#include "sad.h" |
47 |
|
|
48 |
// very large value |
// very large value |
71 |
#define EVEN(A) (((A)<0?(A)+1:(A)) & ~1) |
#define EVEN(A) (((A)<0?(A)+1:(A)) & ~1) |
72 |
|
|
73 |
|
|
|
#define MIN(X, Y) ((X)<(Y)?(X):(Y)) |
|
|
#define MAX(X, Y) ((X)>(Y)?(X):(Y)) |
|
|
#define ABS(X) (((X)>0)?(X):-(X)) |
|
|
#define SIGN(X) (((X)>0)?1:-1) |
|
|
|
|
74 |
int32_t PMVfastSearch16( |
int32_t PMVfastSearch16( |
75 |
const uint8_t * const pRef, |
const uint8_t * const pRef, |
76 |
const uint8_t * const pRefH, |
const uint8_t * const pRefH, |
219 |
|
|
220 |
|
|
221 |
|
|
|
/* calculate the min/max range (in halfpixels) |
|
|
relative to the _MACROBLOCK_ position |
|
|
*/ |
|
|
|
|
|
static void __inline get_range( |
|
|
int32_t * const min_dx, int32_t * const max_dx, |
|
|
int32_t * const min_dy, int32_t * const max_dy, |
|
|
const uint32_t x, const uint32_t y, |
|
|
const uint32_t block_sz, // block dimension, 8 or 16 |
|
|
const uint32_t width, const uint32_t height, |
|
|
const uint32_t fcode) |
|
|
{ |
|
|
|
|
|
const int search_range = 32 << (fcode - 1); |
|
|
const int high = search_range - 1; |
|
|
const int low = -search_range; |
|
|
|
|
|
// convert full-pixel measurements to half pixel |
|
|
const int hp_width = 2 * width; |
|
|
const int hp_height = 2 * height; |
|
|
const int hp_edge = 2 * block_sz; |
|
|
const int hp_x = 2 * (x) * block_sz; // we need _right end_ of block, not x-coordinate |
|
|
const int hp_y = 2 * (y) * block_sz; // same for _bottom end_ |
|
|
|
|
|
*max_dx = MIN(high, hp_width - hp_x); |
|
|
*max_dy = MIN(high, hp_height - hp_y); |
|
|
*min_dx = MAX(low, -(hp_edge + hp_x)); |
|
|
*min_dy = MAX(low, -(hp_edge + hp_y)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* getref: calculate reference image pointer |
|
|
* the decision to use interpolation h/v/hv or the normal image is |
|
|
* based on dx & dy. |
|
|
*/ |
|
|
|
|
|
static __inline const uint8_t * get_ref( |
|
|
const uint8_t * const refn, |
|
|
const uint8_t * const refh, |
|
|
const uint8_t * const refv, |
|
|
const uint8_t * const refhv, |
|
|
const uint32_t x, const uint32_t y, |
|
|
const uint32_t block, // block dimension, 8 or 16 |
|
|
const int32_t dx, const int32_t dy, |
|
|
const uint32_t stride) |
|
|
{ |
|
|
|
|
|
switch ( ((dx&1)<<1) + (dy&1) ) // ((dx%2)?2:0)+((dy%2)?1:0) |
|
|
{ |
|
|
case 0 : return refn + (x*block+dx/2) + (y*block+dy/2)*stride; |
|
|
case 1 : return refv + (x*block+dx/2) + (y*block+(dy-1)/2)*stride; |
|
|
case 2 : return refh + (x*block+(dx-1)/2) + (y*block+dy/2)*stride; |
|
|
default : |
|
|
case 3 : return refhv + (x*block+(dx-1)/2) + (y*block+(dy-1)/2)*stride; |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/* This is somehow a copy of get_ref, but with MV instead of X,Y */ |
|
|
|
|
|
static __inline const uint8_t * get_ref_mv( |
|
|
const uint8_t * const refn, |
|
|
const uint8_t * const refh, |
|
|
const uint8_t * const refv, |
|
|
const uint8_t * const refhv, |
|
|
const uint32_t x, const uint32_t y, |
|
|
const uint32_t block, // block dimension, 8 or 16 |
|
|
const VECTOR* mv, // measured in half-pel! |
|
|
const uint32_t stride) |
|
|
{ |
|
|
|
|
|
switch ( (((mv->x)&1)<<1) + ((mv->y)&1) ) |
|
|
{ |
|
|
case 0 : return refn + (x*block+(mv->x)/2) + (y*block+(mv->y)/2)*stride; |
|
|
case 1 : return refv + (x*block+(mv->x)/2) + (y*block+((mv->y)-1)/2)*stride; |
|
|
case 2 : return refh + (x*block+((mv->x)-1)/2) + (y*block+(mv->y)/2)*stride; |
|
|
default : |
|
|
case 3 : return refhv + (x*block+((mv->x)-1)/2) + (y*block+((mv->y)-1)/2)*stride; |
|
|
} |
|
|
|
|
|
} |
|
222 |
|
|
223 |
#ifndef SEARCH16 |
#ifndef SEARCH16 |
224 |
#define SEARCH16 PMVfastSearch16 |
#define SEARCH16 PMVfastSearch16 |
254 |
int32_t sad16; |
int32_t sad16; |
255 |
int32_t deviation; |
int32_t deviation; |
256 |
|
|
257 |
|
if (sadInit) |
258 |
|
(*sadInit)(); |
259 |
|
|
260 |
// note: i==horizontal, j==vertical |
// note: i==horizontal, j==vertical |
261 |
for (i = 0; i < iHcount; i++) |
for (i = 0; i < iHcount; i++) |
262 |
for (j = 0; j < iWcount; j++) |
for (j = 0; j < iWcount; j++) |
907 |
iEdgedWidth, MV_MAX_ERROR); |
iEdgedWidth, MV_MAX_ERROR); |
908 |
iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant; |
iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant; |
909 |
|
|
910 |
if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && (iMinSAD < pMB->sad16) ) ) |
if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && ((uint32_t)iMinSAD < pMB->sad16) ) ) |
911 |
{ |
{ |
912 |
|
|
913 |
if (MotionFlags & PMV_QUICKSTOP16) |
if (MotionFlags & PMV_QUICKSTOP16) |
950 |
CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y); |
CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y); |
951 |
|
|
952 |
// top right neighbour, if allowed |
// top right neighbour, if allowed |
953 |
if (x != (iWcount-1)) |
if ((uint32_t)x != (iWcount-1)) |
954 |
{ |
{ |
955 |
if (!(MotionFlags & PMV_HALFPEL16 )) |
if (!(MotionFlags & PMV_HALFPEL16 )) |
956 |
{ pmv[3].x = EVEN(pmv[3].x); |
{ pmv[3].x = EVEN(pmv[3].x); |
964 |
If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10. |
If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10. |
965 |
*/ |
*/ |
966 |
|
|
967 |
if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[0]) && (iMinSAD < pMB->sad16) ) ) |
if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[0]) && ((uint32_t)iMinSAD < pMB->sad16) ) ) |
968 |
{ |
{ |
969 |
if (MotionFlags & PMV_QUICKSTOP16) |
if (MotionFlags & PMV_QUICKSTOP16) |
970 |
goto PMVfast16_Terminate_without_Refine; |
goto PMVfast16_Terminate_without_Refine; |
1258 |
iEdgedWidth); |
iEdgedWidth); |
1259 |
iMinSAD += calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y, (uint8_t)iFcode) * iQuant; |
iMinSAD += calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y, (uint8_t)iFcode) * iQuant; |
1260 |
|
|
1261 |
if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && (iMinSAD < pMB->sad8[iSubBlock]) ) ) |
if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && ((uint32_t)iMinSAD < pMB->sad8[iSubBlock]) ) ) |
1262 |
{ |
{ |
1263 |
if (MotionFlags & PMV_QUICKSTOP16) |
if (MotionFlags & PMV_QUICKSTOP16) |
1264 |
goto PMVfast8_Terminate_without_Refine; |
goto PMVfast8_Terminate_without_Refine; |
1317 |
If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10. |
If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10. |
1318 |
*/ |
*/ |
1319 |
|
|
1320 |
if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && (iMinSAD < pMB->sad8[iSubBlock]) ) ) |
if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && ((uint32_t)iMinSAD < pMB->sad8[iSubBlock]) ) ) |
1321 |
{ |
{ |
1322 |
if (MotionFlags & PMV_QUICKSTOP16) |
if (MotionFlags & PMV_QUICKSTOP16) |
1323 |
goto PMVfast8_Terminate_without_Refine; |
goto PMVfast8_Terminate_without_Refine; |
1498 |
iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant; |
iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant; |
1499 |
|
|
1500 |
// thresh1 is fixed to 256 |
// thresh1 is fixed to 256 |
1501 |
if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && (iMinSAD < pMB->sad16) ) ) |
if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && ((uint32_t)iMinSAD < pMB->sad16) ) ) |
1502 |
{ |
{ |
1503 |
if (MotionFlags & PMV_QUICKSTOP16) |
if (MotionFlags & PMV_QUICKSTOP16) |
1504 |
goto EPZS16_Terminate_without_Refine; |
goto EPZS16_Terminate_without_Refine; |
1550 |
CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y); |
CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y); |
1551 |
|
|
1552 |
// top right neighbour, if allowed |
// top right neighbour, if allowed |
1553 |
if (x != (iWcount-1)) |
if ((uint32_t)x != (iWcount-1)) |
1554 |
{ |
{ |
1555 |
if (!(MotionFlags & PMV_HALFPEL16 )) |
if (!(MotionFlags & PMV_HALFPEL16 )) |
1556 |
{ pmv[3].x = EVEN(pmv[3].x); |
{ pmv[3].x = EVEN(pmv[3].x); |
1565 |
*/ |
*/ |
1566 |
|
|
1567 |
if ( (iMinSAD <= thresh2) |
if ( (iMinSAD <= thresh2) |
1568 |
|| ( MVequal(*currMV,pMB->mvs[0]) && (iMinSAD <= pMB->sad16) ) ) |
|| ( MVequal(*currMV,pMB->mvs[0]) && ((uint32_t)iMinSAD <= pMB->sad16) ) ) |
1569 |
{ |
{ |
1570 |
if (MotionFlags & PMV_QUICKSTOP16) |
if (MotionFlags & PMV_QUICKSTOP16) |
1571 |
goto EPZS16_Terminate_without_Refine; |
goto EPZS16_Terminate_without_Refine; |
1591 |
|
|
1592 |
// right neighbour, if allowed (this value is not written yet, so take it from pMB->mvs |
// right neighbour, if allowed (this value is not written yet, so take it from pMB->mvs |
1593 |
|
|
1594 |
if (x != iWcount-1) |
if ((uint32_t)x != iWcount-1) |
1595 |
CHECK_MV16_CANDIDATE((pMB+1)->mvs[0].x,oldMB->mvs[0].y); |
CHECK_MV16_CANDIDATE((pMB+1)->mvs[0].x,oldMB->mvs[0].y); |
1596 |
|
|
1597 |
// bottom neighbour, dito |
// bottom neighbour, dito |
1598 |
if (y != iHcount-1) |
if ((uint32_t)y != iHcount-1) |
1599 |
CHECK_MV16_CANDIDATE((pMB+iWcount)->mvs[0].x,oldMB->mvs[0].y); |
CHECK_MV16_CANDIDATE((pMB+iWcount)->mvs[0].x,oldMB->mvs[0].y); |
1600 |
|
|
1601 |
/* Terminate if MinSAD <= T_3 (here T_3 = T_2) */ |
/* Terminate if MinSAD <= T_3 (here T_3 = T_2) */ |
1884 |
return iMinSAD; |
return iMinSAD; |
1885 |
} |
} |
1886 |
|
|
1887 |
|
|
1888 |
|
|
1889 |
|
|
1890 |
|
|
1891 |
|
/* *********************************************************** |
1892 |
|
bvop motion estimation |
1893 |
|
// TODO: need to incorporate prediction here (eg. sad += calc_delta_16) |
1894 |
|
***************************************************************/ |
1895 |
|
|
1896 |
|
/* |
1897 |
|
void MotionEstimationBVOP( |
1898 |
|
MBParam * const pParam, |
1899 |
|
FRAMEINFO * const frame, |
1900 |
|
|
1901 |
|
// forward (past) reference |
1902 |
|
const MACROBLOCK * const f_mbs, |
1903 |
|
const IMAGE * const f_ref, |
1904 |
|
const IMAGE * const f_refH, |
1905 |
|
const IMAGE * const f_refV, |
1906 |
|
const IMAGE * const f_refHV, |
1907 |
|
// backward (future) reference |
1908 |
|
const MACROBLOCK * const b_mbs, |
1909 |
|
const IMAGE * const b_ref, |
1910 |
|
const IMAGE * const b_refH, |
1911 |
|
const IMAGE * const b_refV, |
1912 |
|
const IMAGE * const b_refHV) |
1913 |
|
{ |
1914 |
|
const uint32_t mb_width = pParam->mb_width; |
1915 |
|
const uint32_t mb_height = pParam->mb_height; |
1916 |
|
const int32_t edged_width = pParam->edged_width; |
1917 |
|
|
1918 |
|
int32_t i,j; |
1919 |
|
|
1920 |
|
int32_t f_sad16; |
1921 |
|
int32_t b_sad16; |
1922 |
|
int32_t i_sad16; |
1923 |
|
int32_t d_sad16; |
1924 |
|
int32_t best_sad; |
1925 |
|
|
1926 |
|
VECTOR pmv_dontcare; |
1927 |
|
|
1928 |
|
// note: i==horizontal, j==vertical |
1929 |
|
for (j = 0; j < mb_height; j++) |
1930 |
|
{ |
1931 |
|
for (i = 0; i < mb_width; i++) |
1932 |
|
{ |
1933 |
|
MACROBLOCK *mb = &frame->mbs[i + j*mb_width]; |
1934 |
|
const MACROBLOCK *f_mb = &f_mbs[i + j*mb_width]; |
1935 |
|
const MACROBLOCK *b_mb = &b_mbs[i + j*mb_width]; |
1936 |
|
|
1937 |
|
if (b_mb->mode == MODE_INTER |
1938 |
|
&& b_mb->cbp == 0 |
1939 |
|
&& b_mb->mvs[0].x == 0 |
1940 |
|
&& b_mb->mvs[0].y == 0) |
1941 |
|
{ |
1942 |
|
mb->mode = MB_IGNORE; |
1943 |
|
mb->mvs[0].x = 0; |
1944 |
|
mb->mvs[0].y = 0; |
1945 |
|
mb->b_mvs[0].x = 0; |
1946 |
|
mb->b_mvs[0].y = 0; |
1947 |
|
continue; |
1948 |
|
} |
1949 |
|
|
1950 |
|
|
1951 |
|
// forward search |
1952 |
|
f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y, |
1953 |
|
&frame->image, |
1954 |
|
i, j, |
1955 |
|
frame->motion_flags, frame->quant, frame->fcode, |
1956 |
|
pParam, |
1957 |
|
f_mbs, |
1958 |
|
&mb->mvs[0], &pmv_dontcare); // ignore pmv |
1959 |
|
|
1960 |
|
// backward search |
1961 |
|
b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y, |
1962 |
|
&frame->image, |
1963 |
|
i, j, |
1964 |
|
frame->motion_flags, frame->quant, frame->bcode, |
1965 |
|
pParam, |
1966 |
|
b_mbs, |
1967 |
|
&mb->b_mvs[0], &pmv_dontcare); // ignore pmv |
1968 |
|
|
1969 |
|
// interpolate search (simple, but effective) |
1970 |
|
i_sad16 = sad16bi_c( |
1971 |
|
frame->image.y + i*16 + j*16*edged_width, |
1972 |
|
get_ref(f_ref->y, f_refH->y, f_refV->y, f_refHV->y, |
1973 |
|
i, j, 16, mb->mvs[0].x, mb->mvs[0].y, edged_width), |
1974 |
|
get_ref(b_ref->y, b_refH->y, b_refV->y, b_refHV->y, |
1975 |
|
i, j, 16, mb->b_mvs[0].x, mb->b_mvs[0].x, edged_width), |
1976 |
|
edged_width); |
1977 |
|
|
1978 |
|
// TODO: direct search |
1979 |
|
// predictor + range of [-32,32] |
1980 |
|
d_sad16 = 65535; |
1981 |
|
|
1982 |
|
|
1983 |
|
if (f_sad16 < b_sad16) |
1984 |
|
{ |
1985 |
|
best_sad = f_sad16; |
1986 |
|
mb->mode = MB_FORWARD; |
1987 |
|
} |
1988 |
|
else |
1989 |
|
{ |
1990 |
|
best_sad = b_sad16; |
1991 |
|
mb->mode = MB_BACKWARD; |
1992 |
|
} |
1993 |
|
|
1994 |
|
if (i_sad16 < best_sad) |
1995 |
|
{ |
1996 |
|
best_sad = i_sad16; |
1997 |
|
mb->mode = MB_INTERPOLATE; |
1998 |
|
} |
1999 |
|
|
2000 |
|
if (d_sad16 < best_sad) |
2001 |
|
{ |
2002 |
|
best_sad = d_sad16; |
2003 |
|
mb->mode = MB_DIRECT; |
2004 |
|
} |
2005 |
|
|
2006 |
|
} |
2007 |
|
} |
2008 |
|
} |
2009 |
|
|
2010 |
|
*/ |