#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);
// 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);
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 ()");
}
}
-gboolean
+G_MODULE_EXPORT gboolean
x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event,
signal_user_data_t *ud)
{
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, "x264Option", ghb_string_value(sopts));
ghb_x264_parse_options(ud, sopts);
enum
{
+ X264_OPT_NONE,
X264_OPT_DEBLOCK,
+ X264_OPT_PSY,
X264_OPT_INT,
X264_OPT_COMBO,
X264_OPT_BOOL,
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};
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_decimate_syns[] =
{"no-dct-decimate", "no_dct_decimate", NULL};
static gchar *x264_cabac_syns[] = {"cabac", NULL};
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_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))
GtkTreeModel *store;
GtkTreeIter iter;
gchar *shortOpt;
- gint ivalue;
+ gdouble ivalue;
gboolean foundit = FALSE;
GtkWidget *widget;
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)
{
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;
}
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);
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)
{
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;
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;
}
}
+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)
{
}
}
+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*
{
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
+ gint subme = ghb_settings_combo_int(ud->settings, "x264_subme");
+ if (subme < 6)
{
- 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_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)
{
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)