OSDN Git Service

LinGui: add mbtree checkbox to x264 settings tab
[handbrake-jp/handbrake-jp-git.git] / gtk / src / x264handler.c
index 1ff2c41..f1c4bfa 100644 (file)
@@ -17,6 +17,7 @@
 #include "values.h"
 #include "callbacks.h"
 #include "presets.h"
+#include "hb-backend.h"
 #include "x264handler.h"
 
 static void x264_opt_update(signal_user_data_t *ud, GtkWidget *widget);
@@ -25,7 +26,7 @@ static gchar* sanitize_x264opts(signal_user_data_t *ud, const gchar *options);
 // Flag needed to prevent x264 options processing from chasing its tail
 static gboolean ignore_options_update = FALSE;
 
-void
+G_MODULE_EXPORT void
 x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
        ghb_widget_to_setting(ud->settings, widget);
@@ -39,7 +40,35 @@ x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
        ghb_clear_presets_selection(ud);
 }
 
-void
+G_MODULE_EXPORT void
+x264_me_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+       gint me;
+
+       ghb_widget_to_setting(ud->settings, widget);
+       if (!ignore_options_update)
+       {
+               ignore_options_update = TRUE;
+               x264_opt_update(ud, widget);
+               ignore_options_update = FALSE;
+       }
+       ghb_check_dependency(ud, widget);
+       ghb_clear_presets_selection(ud);
+       widget = GHB_WIDGET(ud->builder, "x264_merange");
+       me = ghb_settings_combo_int(ud->settings, "x264_me");
+       if (me < 2)
+       {       // me < umh
+               // me_range 4 - 16
+               gtk_spin_button_set_range(GTK_SPIN_BUTTON(widget), 4, 16);
+       }
+       else
+       {
+               // me_range 4 - 64
+               gtk_spin_button_set_range(GTK_SPIN_BUTTON(widget), 4, 64);
+       }
+}
+
+G_MODULE_EXPORT void
 x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
        g_debug("x264_entry_changed_cb ()");
@@ -48,9 +77,9 @@ x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
                GtkWidget *textview;
                gchar *options;
 
-               textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264_options"));
+               textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264Option"));
                ghb_widget_to_setting(ud->settings, textview);
-               options = ghb_settings_get_string(ud->settings, "x264_options");
+               options = ghb_settings_get_string(ud->settings, "x264Option");
                ignore_options_update = TRUE;
                ghb_x264_parse_options(ud, options);
                if (!GTK_WIDGET_HAS_FOCUS(textview))
@@ -58,7 +87,7 @@ x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
                        gchar *sopts;
 
                        sopts = sanitize_x264opts(ud, options);
-                       ghb_ui_update(ud, "x264_options", ghb_string_value(sopts));
+                       ghb_ui_update(ud, "x264Option", ghb_string_value(sopts));
                        ghb_x264_parse_options(ud, sopts);
                        g_free(sopts);
                }
@@ -67,19 +96,19 @@ x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
        }
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
        signal_user_data_t *ud)
 {
        gchar *options, *sopts;
 
        ghb_widget_to_setting(ud->settings, widget);
-       options = ghb_settings_get_string(ud->settings, "x264_options");
+       options = ghb_settings_get_string(ud->settings, "x264Option");
        sopts = sanitize_x264opts(ud, options);
        ignore_options_update = TRUE;
-       if (sopts != NULL)
+       if (sopts != NULL && strcmp(sopts, options) != 0)
        {
-               ghb_ui_update(ud, "x264_options", ghb_string_value(sopts));
+               ghb_ui_update(ud, "x264Option", ghb_string_value(sopts));
                ghb_x264_parse_options(ud, sopts);
        }
        g_free(options);
@@ -90,7 +119,9 @@ x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event,
 
 enum
 {
+       X264_OPT_NONE,
        X264_OPT_DEBLOCK,
+       X264_OPT_PSY,
        X264_OPT_INT,
        X264_OPT_COMBO,
        X264_OPT_BOOL,
@@ -108,6 +139,7 @@ struct x264_opt_map_s
 static gchar *x264_ref_syns[] = {"ref", "frameref", NULL};
 static gchar *x264_mixed_syns[] = {"mixed-refs", "mixed_refs", NULL};
 static gchar *x264_bframes_syns[] = {"bframes", NULL};
+static gchar *x264_badapt_syns[] = {"b-adapt", "b_adapt", NULL};
 static gchar *x264_direct_syns[] = 
        {"direct", "direct-pred", "direct_pred", NULL};
 static gchar *x264_weightb_syns[] = {"weightb", "weight-b", "weight_b", NULL};
@@ -115,11 +147,14 @@ static gchar *x264_bpyramid_syns[] = {"b-pyramid", "b_pyramid", NULL};
 static gchar *x264_me_syns[] = {"me", NULL};
 static gchar *x264_merange_syns[] = {"merange", "me-range", "me_range", NULL};
 static gchar *x264_subme_syns[] = {"subme", "subq", NULL};
+static gchar *x264_aqmode_syns[] = {"aq-mode", NULL};
 static gchar *x264_analyse_syns[] = {"analyse", "partitions", NULL};
 static gchar *x264_8x8dct_syns[] = {"8x8dct", NULL};
 static gchar *x264_deblock_syns[] = {"deblock", "filter", NULL};
 static gchar *x264_trellis_syns[] = {"trellis", NULL};
 static gchar *x264_pskip_syns[] = {"no-fast-pskip", "no_fast_pskip", NULL};
+static gchar *x264_psy_syns[] = {"psy-rd", "psy_rd", NULL};
+static gchar *x264_mbtree_syns[] = {"mbtree", NULL};
 static gchar *x264_decimate_syns[] = 
        {"no-dct-decimate", "no_dct_decimate", NULL};
 static gchar *x264_cabac_syns[] = {"cabac", NULL};
@@ -138,23 +173,28 @@ find_syn_match(const gchar *opt, gchar **syns)
 
 struct x264_opt_map_s x264_opt_map[] =
 {
-       {x264_ref_syns, "x264_refs", "1", X264_OPT_INT},
-       {x264_mixed_syns, "x264_mixed_refs", "0", X264_OPT_BOOL},
-       {x264_bframes_syns, "x264_bframes", "0", X264_OPT_INT},
+       {x264_ref_syns, "x264_refs", "3", X264_OPT_INT},
+       {x264_mixed_syns, "x264_mixed_refs", "1", X264_OPT_BOOL},
+       {x264_bframes_syns, "x264_bframes", "3", X264_OPT_INT},
        {x264_direct_syns, "x264_direct", "spatial", X264_OPT_COMBO},
-       {x264_weightb_syns, "x264_weighted_bframes", "0", X264_OPT_BOOL},
+       {x264_badapt_syns, "x264_b_adapt", "1", X264_OPT_COMBO},
+       {x264_weightb_syns, "x264_weighted_bframes", "1", X264_OPT_BOOL},
        {x264_bpyramid_syns, "x264_bpyramid", "0", X264_OPT_BOOL},
        {x264_me_syns, "x264_me", "hex", X264_OPT_COMBO},
        {x264_merange_syns, "x264_merange", "16", X264_OPT_INT},
-       {x264_subme_syns, "x264_subme", "6", X264_OPT_COMBO},
+       {x264_subme_syns, "x264_subme", "7", X264_OPT_COMBO},
+       {x264_aqmode_syns, "x264_aqmode", "1", X264_OPT_NONE},
        {x264_analyse_syns, "x264_analyse", "some", X264_OPT_COMBO},
-       {x264_8x8dct_syns, "x264_8x8dct", "0", X264_OPT_BOOL},
+       {x264_8x8dct_syns, "x264_8x8dct", "1", X264_OPT_BOOL},
        {x264_deblock_syns, "x264_deblock_alpha", "0,0", X264_OPT_DEBLOCK},
        {x264_deblock_syns, "x264_deblock_beta", "0,0", X264_OPT_DEBLOCK},
-       {x264_trellis_syns, "x264_trellis", "0", X264_OPT_COMBO},
+       {x264_trellis_syns, "x264_trellis", "1", X264_OPT_COMBO},
        {x264_pskip_syns, "x264_no_fast_pskip", "0", X264_OPT_BOOL},
        {x264_decimate_syns, "x264_no_dct_decimate", "0", X264_OPT_BOOL},
        {x264_cabac_syns, "x264_cabac", "1", X264_OPT_BOOL},
+       {x264_psy_syns, "x264_psy_rd", "1,0", X264_OPT_PSY},
+       {x264_mbtree_syns, "x264_mbtree", "1", X264_OPT_BOOL},
+       {x264_psy_syns, "x264_psy_trell", "1,0", X264_OPT_PSY},
 };
 #define X264_OPT_MAP_SIZE (sizeof(x264_opt_map)/sizeof(struct x264_opt_map_s))
 
@@ -217,7 +257,7 @@ x264_update_combo(signal_user_data_t *ud, const gchar *name, const gchar *val)
        GtkTreeModel *store;
        GtkTreeIter iter;
        gchar *shortOpt;
-       gint ivalue;
+       gdouble ivalue;
        gboolean foundit = FALSE;
        GtkWidget *widget;
 
@@ -298,6 +338,42 @@ x264_update_deblock(signal_user_data_t *ud, const gchar *xval)
        ghb_ui_update(ud, "x264_deblock_beta", ghb_int64_value(bvalue));
 }
 
+static void
+x264_parse_psy(const gchar *psy, gdouble *psy_rd, gdouble *psy_trell)
+{
+       gchar *val;
+       gchar *trell_val = NULL;
+       gchar *end;
+
+       *psy_rd = 0.;
+       *psy_trell = 0.;
+       if (psy == NULL) return;
+       val = g_strdup(psy);
+       gchar *pos = strchr(val, ',');
+       if (pos != NULL)
+       {
+               trell_val = pos + 1;
+               *pos = 0;
+       }
+       *psy_rd = g_strtod (val, &end);
+       if (trell_val != NULL)
+       {
+               *psy_trell = g_strtod (trell_val, &end);
+       }
+       g_free(val);
+}
+
+static void
+x264_update_psy(signal_user_data_t *ud, const gchar *xval)
+{
+       gdouble rd_value, trell_value;
+
+       if (xval == NULL) return;
+       x264_parse_psy(xval, &rd_value, &trell_value);
+       ghb_ui_update(ud, "x264_psy_rd", ghb_double_value(rd_value));
+       ghb_ui_update(ud, "x264_psy_trell", ghb_double_value(trell_value));
+}
+
 void
 ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options)
 {
@@ -340,6 +416,11 @@ ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options)
                                        x264_opt_map[jj+1].found = TRUE;
                                        x264_update_deblock(ud, val);
                                        break;
+                               case X264_OPT_PSY:
+                                       // dirty little hack.  mark psy_trell found as well
+                                       x264_opt_map[jj+1].found = TRUE;
+                                       x264_update_psy(ud, val);
+                                       break;
                                }
                                break;
                        }
@@ -366,6 +447,9 @@ ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options)
                        case X264_OPT_DEBLOCK:
                                x264_update_deblock(ud, val);
                                break;
+                       case X264_OPT_PSY:
+                               x264_update_psy(ud, val);
+                               break;
                        }
                        x264_opt_map[jj].found = TRUE;
                        g_free(val);
@@ -387,6 +471,17 @@ get_deblock_val(signal_user_data_t *ud)
        return result;
 }
 
+gchar*
+get_psy_val(signal_user_data_t *ud)
+{
+       gdouble rd, trell;
+       gchar *result;
+       rd = ghb_settings_get_double(ud->settings, "x264_psy_rd");
+       trell = ghb_settings_get_double(ud->settings, "x264_psy_trell");
+       result = g_strdup_printf("%g,%g", rd, trell);
+       return result;
+}
+
 static void
 x264_opt_update(signal_user_data_t *ud, GtkWidget *widget)
 {
@@ -415,7 +510,7 @@ x264_opt_update(signal_user_data_t *ud, GtkWidget *widget)
                gint ii;
                gboolean foundit = FALSE;
 
-               options = ghb_settings_get_string(ud->settings, "x264_options");
+               options = ghb_settings_get_string(ud->settings, "x264Option");
                if (options)
                {
                        split = g_strsplit(options, ":", -1);
@@ -438,6 +533,8 @@ x264_opt_update(signal_user_data_t *ud, GtkWidget *widget)
                                foundit = TRUE;
                                if (type == X264_OPT_DEBLOCK)
                                        val = get_deblock_val(ud);
+                               else if (type == X264_OPT_PSY)
+                                       val = get_psy_val(ud);
                                else
                                {
                                        GValue *gval;
@@ -473,6 +570,8 @@ x264_opt_update(signal_user_data_t *ud, GtkWidget *widget)
                        gchar *val;
                        if (type == X264_OPT_DEBLOCK)
                                val = get_deblock_val(ud);
+                       else if (type == X264_OPT_PSY)
+                               val = get_psy_val(ud);
                        else
                        {
                                GValue *gval;
@@ -505,13 +604,36 @@ x264_opt_update(signal_user_data_t *ud, GtkWidget *widget)
                if (len > 0) result[len - 1] = 0;
                gchar *sopts;
                sopts = sanitize_x264opts(ud, result);
-               ghb_ui_update(ud, "x264_options", ghb_string_value(sopts));
+               ghb_ui_update(ud, "x264Option", ghb_string_value(sopts));
                ghb_x264_parse_options(ud, sopts);
                g_free(sopts);
                g_free(result);
        }
 }
 
+static gint
+x264_find_opt(gchar **opts, gchar **opt_syns)
+{
+       gint ii;
+       for (ii = 0; opts[ii] != NULL; ii++)
+       {
+               gchar *opt;
+               opt = g_strdup(opts[ii]);
+               gchar *pos = strchr(opt, '=');
+               if (pos != NULL)
+               {
+                       *pos = 0;
+               }
+               if (find_syn_match(opt, opt_syns) >= 0)
+               {
+                       g_free(opt);
+                       return ii;
+               }
+               g_free(opt);
+       }
+       return -1;
+}
+
 static void
 x264_remove_opt(gchar **opts, gchar **opt_syns)
 {
@@ -534,6 +656,78 @@ x264_remove_opt(gchar **opts, gchar **opt_syns)
        }
 }
 
+static gchar*
+x264_lookup_value(gchar **opts, gchar **opt_syns)
+{
+       gchar *ret = NULL;
+       gint pos;
+
+       const gchar *def_val = x264_opt_get_default(opt_syns[0]);
+
+       pos = x264_find_opt(opts, opt_syns);
+       if (pos >= 0)
+       {
+               gchar *cpos = strchr(opts[pos], '=');
+               if (cpos != NULL)
+               {
+                       ret = g_strdup(cpos+1);
+               }
+               else
+               {
+                       ret = g_strdup("");
+               }
+       }
+       else if (def_val != NULL)
+       {
+               ret = g_strdup(def_val);
+       }
+       return ret;
+}
+
+gint
+ghb_lookup_badapt(const gchar *options)
+{
+       gint ret = 0;
+       gchar *result;
+       gchar **split;
+       
+       if (options == NULL)
+               options = "";
+
+       split = g_strsplit(options, ":", -1);
+
+       result = x264_lookup_value(split, x264_badapt_syns);
+       g_strfreev(split);
+       if (result != NULL)
+       {
+               ret = g_strtod(result, NULL);
+               g_free(result);
+       }
+       return ret;
+}
+
+gint
+ghb_lookup_aqmode(const gchar *options)
+{
+       gint ret = 0;
+       gchar *result;
+       gchar **split;
+       
+       if (options == NULL)
+               options = "";
+
+       split = g_strsplit(options, ":", -1);
+
+       result = x264_lookup_value(split, x264_aqmode_syns);
+       g_strfreev(split);
+       if (result != NULL)
+       {
+               ret = g_strtod(result, NULL);
+               g_free(result);
+       }
+       return ret;
+}
+
 // Construct the x264 options string
 // The result is allocated, so someone must free it at some point.
 static gchar*
@@ -541,30 +735,46 @@ sanitize_x264opts(signal_user_data_t *ud, const gchar *options)
 {
        GString *x264opts = g_string_new("");
        gchar **split = g_strsplit(options, ":", -1);
-
-       // Remove entries that match the defaults
        gint ii;
-       for (ii = 0; split[ii] != NULL; ii++)
+
+       // Fix up option dependencies
+       gboolean mbtree = ghb_settings_get_boolean(ud->settings, "x264_mbtree");
+       if (mbtree)
        {
-               gchar *val = NULL;
-               gchar *opt = g_strdup(split[ii]);
-               gchar *pos = strchr(opt, '=');
-               if (pos != NULL)
-               {
-                       val = pos + 1;
-                       *pos = 0;
-               }
-               else
+               x264_remove_opt(split, x264_bpyramid_syns);
+       }
+       gint subme = ghb_settings_combo_int(ud->settings, "x264_subme");
+       if (subme < 6)
+       {
+               x264_remove_opt(split, x264_psy_syns);
+       }
+       gint trell = ghb_settings_combo_int(ud->settings, "x264_trellis");
+       if (subme == 10)
+       {
+               gint aqmode = ghb_lookup_aqmode(options);
+               if (trell != 2 || aqmode == 0)
                {
-                       val = "1";
+                       gint pos = x264_find_opt(split, x264_subme_syns);
+                       g_free(split[pos]);
+                       split[pos] = g_strdup_printf("subme=9");
                }
-               const gchar *def_val = x264_opt_get_default(opt);
-               if (strcmp(val, def_val) == 0)
+       }
+       if (trell < 1)
+       {
+               gint psy;
+               gdouble psy_rd = 0., psy_trell;
+
+               psy = x264_find_opt(split, x264_psy_syns);
+               if (psy >= 0)
                {
-                       // Matches the default, so remove it
-                       split[ii][0] = 0;
+                       gchar *pos = strchr(split[psy], '=');
+                       if (pos != NULL)
+                       {
+                               x264_parse_psy(pos+1, &psy_rd, &psy_trell);
+                       }
+                       g_free(split[psy]);
+                       split[psy] = g_strdup_printf("psy-rd=%g,0", psy_rd);
                }
-               g_free(opt);
        }
        gint refs = ghb_settings_get_int(ud->settings, "x264_refs");
        if (refs <= 1)
@@ -576,21 +786,39 @@ sanitize_x264opts(signal_user_data_t *ud, const gchar *options)
        {
                x264_remove_opt(split, x264_weightb_syns);
                x264_remove_opt(split, x264_direct_syns);
+               x264_remove_opt(split, x264_badapt_syns);
        }
        if (bframes <= 1)
        {
                x264_remove_opt(split, x264_bpyramid_syns);
        }
-       gchar *me = ghb_settings_get_string(ud->settings, "x264_me");
-       if (!(strcmp(me, "umh") == 0 || strcmp(me, "esa") == 0))
-       {
-               x264_remove_opt(split, x264_merange_syns);
-       }
-       g_free(me);
        if (!ghb_settings_get_boolean(ud->settings, "x264_cabac"))
        {
                x264_remove_opt(split, x264_trellis_syns);
        }
+       // Remove entries that match the defaults
+       for (ii = 0; split[ii] != NULL; ii++)
+       {
+               gchar *val = NULL;
+               gchar *opt = g_strdup(split[ii]);
+               gchar *pos = strchr(opt, '=');
+               if (pos != NULL)
+               {
+                       val = pos + 1;
+                       *pos = 0;
+               }
+               else
+               {
+                       val = "1";
+               }
+               const gchar *def_val = x264_opt_get_default(opt);
+               if (strcmp(val, def_val) == 0)
+               {
+                       // Matches the default, so remove it
+                       split[ii][0] = 0;
+               }
+               g_free(opt);
+       }
        for (ii = 0; split[ii] != NULL; ii++)
        {
                if (split[ii][0] != 0)