From 7d35ba6bf080610d8f144f4270e961c69ba14f1c Mon Sep 17 00:00:00 2001
From: Loren Merritt <pengvado@videolan.org>
Date: Tue, 19 Apr 2005 08:45:36 +0000
Subject: [PATCH] Allow manual selection of fullpel ME method. New method:
 Exhaustive search. based on a patch by Tuukka Toivonen.

git-svn-id: svn://svn.videolan.org/x264/trunk@211 df754926-b1dd-0310-bc7b-ec298dee348c
---
 common/common.c   |  2 ++
 encoder/encoder.c |  8 ++++++++
 encoder/me.c      | 46 ++++++++++++++++++++++++++++++----------------
 x264.c            | 29 +++++++++++++++++++++++++++++
 x264.h            |  7 ++++++-
 5 files changed, 75 insertions(+), 17 deletions(-)

diff --git a/common/common.c b/common/common.c
index a586c39d..4bce6563 100644
--- a/common/common.c
+++ b/common/common.c
@@ -105,6 +105,8 @@ void    x264_param_default( x264_param_t *param )
     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;
diff --git a/encoder/encoder.c b/encoder/encoder.c
index cceb8e0a..39c5f1cf 100644
--- a/encoder/encoder.c
+++ b/encoder/encoder.c
@@ -390,6 +390,14 @@ x264_t *x264_encoder_open   ( x264_param_t *param )
 
     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;
diff --git a/encoder/me.c b/encoder/me.c
index d343b2ac..d5e6d2bf 100644
--- a/encoder/me.c
+++ b/encoder/me.c
@@ -60,6 +60,7 @@ static void refine_subpel( x264_t *h, x264_me_t *m, int hpel_iters, int qpel_ite
 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;
@@ -99,13 +100,27 @@ void x264_me_search_ref( x264_t *h, x264_me_t *m, int (*mvc)[2], int i_mvc, int
     
     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 );
@@ -129,21 +144,20 @@ void x264_me_search_ref( x264_t *h, x264_me_t *m, int (*mvc)[2], int i_mvc, int
         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 */
diff --git a/x264.c b/x264.c
index 3ffb9c11..dfe0b9e5 100644
--- a/x264.c
+++ b/x264.c
@@ -205,6 +205,11 @@ static void Help( x264_param_t *defaults )
              "      --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"
@@ -255,6 +260,10 @@ static void Help( x264_param_t *defaults )
             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
            );
 }
@@ -323,6 +332,8 @@ static int  Parse( int argc, char **argv,
 #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[] =
         {
@@ -351,6 +362,8 @@ static int  Parse( int argc, char **argv,
             { "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 },
@@ -529,6 +542,22 @@ static int  Parse( int argc, char **argv,
             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;
diff --git a/x264.h b/x264.h
index f7d9d181..8d61ad6c 100644
--- a/x264.h
+++ b/x264.h
@@ -26,7 +26,7 @@
 
 #include <stdarg.h>
 
-#define X264_BUILD 22
+#define X264_BUILD 23
 
 /* x264_t:
  *      opaque handler for decoder and encoder */
@@ -54,6 +54,9 @@ typedef struct x264_t x264_t;
 #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
  */
@@ -140,6 +143,8 @@ typedef struct
         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) */
-- 
2.40.0