param->analyse.intra = X264_ANALYSE_I4x4;
param->analyse.inter = X264_ANALYSE_I4x4 | X264_ANALYSE_PSUB16x16 | X264_ANALYSE_BSUB16x16;
param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_TEMPORAL;
+ param->analyse.i_me_method = X264_ME_HEX;
+ param->analyse.i_me_range = 16;
param->analyse.i_subpel_refine = 5;
param->analyse.b_chroma_me = 1;
param->analyse.i_mv_range = 512;
h->param.i_cabac_init_idc = x264_clip3( h->param.i_cabac_init_idc, -1, 2 );
+ if( h->param.analyse.i_me_method != X264_ME_DIA &&
+ h->param.analyse.i_me_method != X264_ME_HEX &&
+ h->param.analyse.i_me_method != X264_ME_ESA )
+ h->param.analyse.i_me_method = X264_ME_HEX;
+ if( h->param.analyse.i_me_range < 2 )
+ h->param.analyse.i_me_range = 2;
+ if( h->param.analyse.i_me_range > 16 && h->param.analyse.i_me_method != X264_ME_ESA )
+ h->param.analyse.i_me_range = 16;
h->param.analyse.i_subpel_refine = x264_clip3( h->param.analyse.i_subpel_refine, 1, 5 );
if( h->param.analyse.inter & X264_ANALYSE_PSUB8x8 )
h->param.analyse.inter |= X264_ANALYSE_PSUB16x16;
void x264_me_search_ref( x264_t *h, x264_me_t *m, int (*mvc)[2], int i_mvc, int *p_fullpel_thresh )
{
const int i_pixel = m->i_pixel;
+ const unsigned int i_me_range = h->param.analyse.i_me_range;
const int b_chroma_me = h->mb.b_chroma_me && i_pixel <= PIXEL_8x8;
int bmx, bmy, bcost;
int omx, omy;
COST_MV( 0, 0 );
- if( h->mb.i_subpel_refine >= 2 )
- {
+ switch( h->param.analyse.i_me_method ) {
+ case X264_ME_DIA:
+ /* diamond search */
+ for( i_iter = 0; i_iter < i_me_range; i_iter++ )
+ {
+ omx = bmx;
+ omy = bmy;
+ COST_MV( omx , omy-1 );
+ COST_MV( omx , omy+1 );
+ COST_MV( omx-1, omy );
+ COST_MV( omx+1, omy );
+ if( bmx == omx && bmy == omy )
+ break;
+ }
+ break;
+ case X264_ME_HEX:
/* hexagon search */
/* Don't need to test mv_range each time, we won't go outside picture+padding */
omx = bmx;
omy = bmy;
- for( i_iter = 0; i_iter < 8; i_iter++ )
+ for( i_iter = 0; i_iter < i_me_range/2; i_iter++ )
{
COST_MV( omx-2, omy );
COST_MV( omx-1, omy+2 );
COST_MV( omx+1, omy-1 );
COST_MV( omx+1, omy );
COST_MV( omx+1, omy+1 );
- }
- else
- {
- /* diamond search */
- for( i_iter = 0; i_iter < 16; i_iter++ )
+ break;
+ case X264_ME_ESA:
{
- omx = bmx;
- omy = bmy;
- COST_MV( omx , omy-1 );
- COST_MV( omx , omy+1 );
- COST_MV( omx-1, omy );
- COST_MV( omx+1, omy );
- if( bmx == omx && bmy == omy )
- break;
+ const int min_x = X264_MAX( bmx - i_me_range, mv_x_min-8);
+ const int min_y = X264_MAX( bmy - i_me_range, mv_y_min-8);
+ const int max_x = X264_MIN( bmx + i_me_range, mv_x_max+8);
+ const int max_y = X264_MIN( bmy + i_me_range, mv_y_max+8);
+ for( omy = min_y; omy <= max_y; omy++ )
+ for( omx = min_x; omx <= max_x; omx++ )
+ {
+ COST_MV( omx, omy );
+ }
}
+ break;
}
/* -> qpel mv */
" --direct <string> Direct MV prediction mode [\"temporal\"]\n"
" - none, spatial, temporal\n"
" -w, --weightb Weighted prediction for B-frames\n"
+ " --me <string> Integer pixel motion estimation method [\"%s\"]\n"
+ " - dia: diamond search, radius 1 (fast)\n"
+ " - hex: hexagonal search, radius 2\n"
+ " - esa: exhaustive search algorithm (slow)\n"
+ " --merange <integer> Maximum motion vector search range [%d]\n"
" -m, --subme <integer> Subpixel motion estimation quality: 1=fast, 5=best. [%d]\n"
" --no-chroma-me Ignore chroma in motion estimation\n"
"\n"
defaults->rc.f_qcompress,
defaults->rc.f_complexity_blur,
defaults->rc.f_qblur,
+ defaults->analyse.i_me_method==X264_ME_DIA ? "dia"
+ : defaults->analyse.i_me_method==X264_ME_HEX ? "hex"
+ : defaults->analyse.i_me_method==X264_ME_ESA ? "esa" : NULL,
+ defaults->analyse.i_me_range,
defaults->analyse.i_subpel_refine
);
}
#define OPT_NO_CABAC 282
#define OPT_AUD 283
#define OPT_PROGRESS 284
+#define OPT_ME 285
+#define OPT_MERANGE 286
static struct option long_options[] =
{
{ "analyse", required_argument, NULL, 'A' },
{ "direct", required_argument, NULL, OPT_DIRECT },
{ "weightb", no_argument, NULL, 'w' },
+ { "me", required_argument, NULL, OPT_ME },
+ { "merange", required_argument, NULL, OPT_MERANGE },
{ "subme", required_argument, NULL, 'm' },
{ "no-chroma-me", no_argument, NULL, OPT_NO_CHROMA_ME },
{ "level", required_argument, NULL, OPT_LEVEL },
case 'w':
param->analyse.b_weighted_bipred = 1;
break;
+ case OPT_ME:
+ if( strstr( optarg, "dia" ) )
+ param->analyse.i_me_method = X264_ME_DIA;
+ else if( strstr( optarg, "hex" ) )
+ param->analyse.i_me_method = X264_ME_HEX;
+ else if( strstr( optarg, "esa" ) )
+ param->analyse.i_me_method = X264_ME_ESA;
+ else
+ {
+ fprintf( stderr, "bad ME method `%s'\n", optarg );
+ return -1;
+ }
+ break;
+ case OPT_MERANGE:
+ param->analyse.i_me_range = atoi(optarg);
+ break;
case 'm':
param->analyse.i_subpel_refine = atoi(optarg);
break;
#include <stdarg.h>
-#define X264_BUILD 22
+#define X264_BUILD 23
/* x264_t:
* opaque handler for decoder and encoder */
#define X264_DIRECT_PRED_NONE 0
#define X264_DIRECT_PRED_SPATIAL 1
#define X264_DIRECT_PRED_TEMPORAL 2
+#define X264_ME_DIA 0
+#define X264_ME_HEX 1
+#define X264_ME_ESA 2
/* Colorspace type
*/
unsigned int inter; /* inter flags */
int i_direct_mv_pred; /* spatial vs temporal mv prediction */
+ int i_me_method; /* motion estimation algorithm to use (X264_ME_*) */
+ int i_me_range; /* integer pixel motion estimation search range (from predicted mv) */
int i_subpel_refine; /* subpixel motion estimation quality */
int b_chroma_me; /* chroma ME for subpel and mode decision in P-frames */
int i_mv_range; /* maximum length of a mv (in pixels) */