diff options
-rw-r--r-- | gtk/src/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/src/callbacks.c | 125 | ||||
-rw-r--r-- | gtk/src/callbacks.h | 1 | ||||
-rw-r--r-- | gtk/src/main.c | 1 | ||||
-rw-r--r-- | gtk/src/settings.c | 532 | ||||
-rw-r--r-- | gtk/src/settings.h | 3 | ||||
-rw-r--r-- | gtk/src/x264handler.c | 620 | ||||
-rw-r--r-- | gtk/src/x264handler.h | 32 |
8 files changed, 678 insertions, 638 deletions
diff --git a/gtk/src/Makefile.am b/gtk/src/Makefile.am index 24d386682..7d4d1d3ba 100644 --- a/gtk/src/Makefile.am +++ b/gtk/src/Makefile.am @@ -90,6 +90,8 @@ ghb_SOURCES = \ queuehandler.h \ audiohandler.c \ audiohandler.h \ + x264handler.c \ + x264handler.h \ main.c \ settings.c \ settings.h \ diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c index a26343268..2fc7e3979 100644 --- a/gtk/src/callbacks.c +++ b/gtk/src/callbacks.c @@ -210,14 +210,14 @@ ghb_check_all_depencencies(signal_user_data_t *ud) } } -static void -clear_presets_selection(signal_user_data_t *ud) +void +ghb_clear_presets_selection(signal_user_data_t *ud) { GtkTreeView *treeview; GtkTreeSelection *selection; if (ud->dont_clear_presets) return; - g_debug("clear_presets_selection()"); + g_debug("ghb_clear_presets_selection()"); treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list")); selection = gtk_tree_view_get_selection (treeview); gtk_tree_selection_unselect_all (selection); @@ -839,7 +839,7 @@ container_changed_cb(GtkWidget *widget, signal_user_data_t *ud) update_destination_extension(ud); ghb_check_dependency(ud, widget); update_acodec_combo(ud); - clear_presets_selection(ud); + ghb_clear_presets_selection(ud); audio_list = ghb_settings_get_value(ud->settings, "audio_list"); if (ghb_ac3_in_audio_list (audio_list)) @@ -1045,18 +1045,11 @@ title_changed_cb(GtkWidget *widget, signal_user_data_t *ud) } void -generic_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) -{ - g_debug("generic_widget_changed_cb ()"); - ghb_check_dependency(ud, widget); -} - -void setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) { ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget); - clear_presets_selection(ud); + ghb_clear_presets_selection(ud); } static void @@ -1117,7 +1110,8 @@ http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud) { ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget); - clear_presets_selection(ud); + ghb_clear_presets_selection(ud); + // AC3 is not allowed when Web optimized ghb_grey_combo_options (ud->builder); } @@ -1128,7 +1122,7 @@ vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget); - clear_presets_selection(ud); + ghb_clear_presets_selection(ud); ghb_vquality_range(ud, &vqmin, &vqmax); GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality"); gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax); @@ -1141,7 +1135,7 @@ target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud) g_debug("setting_widget_changed_cb () %s", name); ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget); - clear_presets_selection(ud); + ghb_clear_presets_selection(ud); if (ghb_settings_get_boolean(ud->settings, "vquality_type_target")) { gint titleindex; @@ -1265,7 +1259,7 @@ scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud) g_debug("scale_changed_cb ()"); ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget); - clear_presets_selection(ud); + ghb_clear_presets_selection(ud); ghb_set_scale (ud, GHB_SCALE_KEEP_NONE); update_preview = TRUE; @@ -1299,81 +1293,6 @@ generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud) } } -gboolean -generic_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, - signal_user_data_t *ud) -{ - g_debug("generic_focus_out_cb ()"); - ghb_widget_to_setting(ud->settings, widget); - return FALSE; -} - -// Flag needed to prevent x264 options processing from chasing its tail -static gboolean ignore_options_update = FALSE; - -void -x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) -{ - ghb_widget_to_setting(ud->settings, widget); - if (!ignore_options_update) - { - ignore_options_update = TRUE; - ghb_x264_opt_update(ud, widget); - ignore_options_update = FALSE; - } - ghb_check_dependency(ud, widget); - clear_presets_selection(ud); -} - -void -x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud) -{ - g_debug("x264_entry_changed_cb ()"); - if (!ignore_options_update) - { - GtkWidget *textview; - gchar *options; - - textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264_options")); - ghb_widget_to_setting(ud->settings, textview); - options = ghb_settings_get_string(ud->settings, "x264_options"); - ignore_options_update = TRUE; - ghb_x264_parse_options(ud, options); - if (!GTK_WIDGET_HAS_FOCUS(textview)) - { - gchar *sopts; - - sopts = ghb_sanitize_x264opts(ud, options); - ghb_ui_update(ud, "x264_options", ghb_string_value(sopts)); - ghb_x264_parse_options(ud, sopts); - g_free(sopts); - } - g_free(options); - ignore_options_update = FALSE; - } -} - -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"); - sopts = ghb_sanitize_x264opts(ud, options); - ignore_options_update = TRUE; - if (sopts != NULL) - { - ghb_ui_update(ud, "x264_options", ghb_string_value(sopts)); - ghb_x264_parse_options(ud, sopts); - } - g_free(options); - g_free(sopts); - ignore_options_update = FALSE; - return FALSE; -} - void ghb_presets_list_update(signal_user_data_t *ud) { @@ -1550,18 +1469,6 @@ presets_restore_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud) } void -prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud) -{ - GtkWidget *dialog; - GtkResponseType response; - - g_debug("prefs_dialog_cb ()"); - dialog = GHB_WIDGET(ud->builder, "prefs_dialog"); - response = gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_hide(dialog); -} - -void presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud) { GtkTreeView *treeview; @@ -1696,6 +1603,18 @@ presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_ } } +void +prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud) +{ + GtkWidget *dialog; + GtkResponseType response; + + g_debug("prefs_dialog_cb ()"); + dialog = GHB_WIDGET(ud->builder, "prefs_dialog"); + response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_hide(dialog); +} + gboolean ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes) { diff --git a/gtk/src/callbacks.h b/gtk/src/callbacks.h index d49144d1b..7bc793642 100644 --- a/gtk/src/callbacks.h +++ b/gtk/src/callbacks.h @@ -46,6 +46,7 @@ gboolean ghb_reload_queue(signal_user_data_t *ud); gboolean ghb_cancel_encode(const gchar *extra_msg); GValue* ghb_start_next_job(signal_user_data_t *ud, gboolean find_first); void ghb_check_dependency(signal_user_data_t *ud, GtkWidget *widget); +void ghb_clear_presets_selection(signal_user_data_t *ud); #endif // _CALLBACKS_H_ diff --git a/gtk/src/main.c b/gtk/src/main.c index 94e538672..52c581ca9 100644 --- a/gtk/src/main.c +++ b/gtk/src/main.c @@ -42,6 +42,7 @@ #include "values.h" #include "icons.h" #include "callbacks.h" +#include "x264handler.h" #include "settings.h" #include "resources.h" #include "presets.h" diff --git a/gtk/src/settings.c b/gtk/src/settings.c index d108814d5..e3bec95ea 100644 --- a/gtk/src/settings.c +++ b/gtk/src/settings.c @@ -587,538 +587,6 @@ ghb_ui_update(signal_user_data_t *ud, const gchar *name, const GValue *value) return 0; } -enum -{ - X264_OPT_DEBLOCK, - X264_OPT_INT, - X264_OPT_COMBO, - X264_OPT_BOOL, -}; - -struct x264_opt_map_s -{ - gchar **opt_syns; - gchar *name; - gchar *def_val; - gint type; - gboolean found; -}; - -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_direct_syns[] = - {"direct", "direct-pred", "direct_pred", NULL}; -static gchar *x264_weightb_syns[] = {"weightb", "weight-b", "weight_b", NULL}; -static gchar *x264_brdo_syns[] = {"brdo", "b-rdo", "b_rdo", NULL}; -static gchar *x264_bime_syns[] = {"bime", NULL}; -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_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_decimate_syns[] = - {"no-dct-decimate", "no_dct_decimate", NULL}; -static gchar *x264_cabac_syns[] = {"cabac", NULL}; - -static gint -find_syn_match(const gchar *opt, gchar **syns) -{ - gint ii; - for (ii = 0; syns[ii] != NULL; ii++) - { - if (strcmp(opt, syns[ii]) == 0) - return ii; - } - return -1; -} - -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_direct_syns, "x264_direct", "spatial", X264_OPT_COMBO}, - {x264_weightb_syns, "x264_weighted_bframes", "0", X264_OPT_BOOL}, - {x264_brdo_syns, "x264_brdo", "0", X264_OPT_BOOL}, - {x264_bime_syns, "x264_bime", "0", 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_analyse_syns, "x264_analyse", "some", X264_OPT_COMBO}, - {x264_8x8dct_syns, "x264_8x8dct", "0", 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_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}, -}; -#define X264_OPT_MAP_SIZE (sizeof(x264_opt_map)/sizeof(struct x264_opt_map_s)) - -static const gchar* -x264_opt_get_default(const gchar *opt) -{ - gint jj; - for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++) - { - if (find_syn_match(opt, x264_opt_map[jj].opt_syns) >= 0) - { - return x264_opt_map[jj].def_val; - } - } - return ""; -} - -static void -x264_update_int(signal_user_data_t *ud, const gchar *name, const gchar *val) -{ - gint ival; - - if (val == NULL) return; - ival = g_strtod (val, NULL); - ghb_ui_update(ud, name, ghb_int64_value(ival)); -} - -static gchar *true_str[] = -{ - "true", - "yes", - "1", - NULL -}; - -static gboolean -str_is_true(const gchar *str) -{ - gint ii; - for (ii = 0; true_str[ii]; ii++) - { - if (g_ascii_strcasecmp(str, true_str[ii]) == 0) - return TRUE; - } - return FALSE; -} - -static void -x264_update_bool(signal_user_data_t *ud, const gchar *name, const gchar *val) -{ - if (val == NULL) - ghb_ui_update(ud, name, ghb_boolean_value(1)); - else - ghb_ui_update(ud, name, ghb_boolean_value(str_is_true(val))); -} - -static void -x264_update_combo(signal_user_data_t *ud, const gchar *name, const gchar *val) -{ - GtkTreeModel *store; - GtkTreeIter iter; - gchar *shortOpt; - gint ivalue; - gboolean foundit = FALSE; - GtkWidget *widget; - - if (val == NULL) return; - widget = GHB_WIDGET(ud->builder, name); - if (widget == NULL) - { - g_debug("Failed to find widget for key: %s\n", name); - return; - } - store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget)); - if (gtk_tree_model_get_iter_first (store, &iter)) - { - do - { - gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1); - if (strcmp(shortOpt, val) == 0) - { - gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter); - g_free(shortOpt); - foundit = TRUE; - break; - } - g_free(shortOpt); - } while (gtk_tree_model_iter_next (store, &iter)); - } - if (!foundit) - { - if (gtk_tree_model_get_iter_first (store, &iter)) - { - do - { - gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1); - if (strcmp(shortOpt, "custom") == 0) - { - gtk_list_store_set(GTK_LIST_STORE(store), &iter, 4, val, -1); - gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter); - g_free(shortOpt); - foundit = TRUE; - break; - } - g_free(shortOpt); - } while (gtk_tree_model_iter_next (store, &iter)); - } - } - // Its possible the value hasn't changed. Since settings are only - // updated when the value changes, I'm initializing settings here as well. - ghb_widget_to_setting(ud->settings, widget); -} - -static void -x264_update_deblock(signal_user_data_t *ud, const gchar *xval) -{ - gdouble avalue, bvalue; - gchar *end; - gchar *val; - gchar *bval = NULL; - - if (xval == NULL) return; - val = g_strdup(xval); - bvalue = avalue = 0; - if (val != NULL) - { - gchar *pos = strchr(val, ','); - if (pos != NULL) - { - bval = pos + 1; - *pos = 0; - } - avalue = g_strtod (val, &end); - if (bval != NULL) - { - bvalue = g_strtod (bval, &end); - } - } - g_free(val); - ghb_ui_update(ud, "x264_deblock_alpha", ghb_int64_value(avalue)); - ghb_ui_update(ud, "x264_deblock_beta", ghb_int64_value(bvalue)); -} - -void -ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options) -{ - gchar **split = g_strsplit(options, ":", -1); - if (split == NULL) return; - - gint ii; - gint jj; - - for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++) - x264_opt_map[jj].found = FALSE; - - for (ii = 0; split[ii] != NULL; ii++) - { - gchar *val = NULL; - gchar *pos = strchr(split[ii], '='); - if (pos != NULL) - { - val = pos + 1; - *pos = 0; - } - for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++) - { - if (find_syn_match(split[ii], x264_opt_map[jj].opt_syns) >= 0) - { - x264_opt_map[jj].found = TRUE; - switch(x264_opt_map[jj].type) - { - case X264_OPT_INT: - x264_update_int(ud, x264_opt_map[jj].name, val); - break; - case X264_OPT_BOOL: - x264_update_bool(ud, x264_opt_map[jj].name, val); - break; - case X264_OPT_COMBO: - x264_update_combo(ud, x264_opt_map[jj].name, val); - break; - case X264_OPT_DEBLOCK: - // dirty little hack. mark deblock_beta found as well - x264_opt_map[jj+1].found = TRUE; - x264_update_deblock(ud, val); - break; - } - break; - } - } - } - // For any options not found in the option string, set ui to - // default values - for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++) - { - if (!x264_opt_map[jj].found) - { - gchar *val = strdup(x264_opt_map[jj].def_val); - switch(x264_opt_map[jj].type) - { - case X264_OPT_INT: - x264_update_int(ud, x264_opt_map[jj].name, val); - break; - case X264_OPT_BOOL: - x264_update_bool(ud, x264_opt_map[jj].name, val); - break; - case X264_OPT_COMBO: - x264_update_combo(ud, x264_opt_map[jj].name, val); - break; - case X264_OPT_DEBLOCK: - x264_update_deblock(ud, val); - break; - } - x264_opt_map[jj].found = TRUE; - g_free(val); - } - } - g_strfreev(split); -} - -gchar* -get_deblock_val(signal_user_data_t *ud) -{ - gchar *alpha, *beta; - gchar *result; - alpha = ghb_settings_get_string(ud->settings, "x264_deblock_alpha"); - beta = ghb_settings_get_string(ud->settings, "x264_deblock_beta"); - result = g_strdup_printf("%s,%s", alpha, beta); - g_free(alpha); - g_free(beta); - return result; -} - -void -ghb_x264_opt_update(signal_user_data_t *ud, GtkWidget *widget) -{ - gint jj; - const gchar *name = gtk_widget_get_name(widget); - gchar **opt_syns = NULL; - const gchar *def_val = NULL; - gint type; - - for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++) - { - if (strcmp(name, x264_opt_map[jj].name) == 0) - { - // found the options that needs updating - opt_syns = x264_opt_map[jj].opt_syns; - def_val = x264_opt_map[jj].def_val; - type = x264_opt_map[jj].type; - break; - } - } - if (opt_syns != NULL) - { - GString *x264opts = g_string_new(""); - gchar *options; - gchar **split = NULL; - gint ii; - gboolean foundit = FALSE; - - options = ghb_settings_get_string(ud->settings, "x264_options"); - if (options) - { - split = g_strsplit(options, ":", -1); - g_free(options); - } - for (ii = 0; split && split[ii] != NULL; ii++) - { - gint syn; - gchar *val = NULL; - gchar *pos = strchr(split[ii], '='); - if (pos != NULL) - { - val = pos + 1; - *pos = 0; - } - syn = find_syn_match(split[ii], opt_syns); - if (syn >= 0) - { // Updating this option - gchar *val; - foundit = TRUE; - if (type == X264_OPT_DEBLOCK) - val = get_deblock_val(ud); - else - { - GValue *gval; - gval = ghb_widget_value(widget); - if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN) - { - if (ghb_value_boolean(gval)) - val = g_strdup("1"); - else - val = g_strdup("0"); - } - else - { - val = ghb_widget_string(widget); - } - ghb_value_free(gval); - } - if (strcmp(def_val, val) != 0) - { - g_string_append_printf(x264opts, "%s=%s:", opt_syns[syn], val); - } - g_free(val); - } - else if (val != NULL) - g_string_append_printf(x264opts, "%s=%s:", split[ii], val); - else - g_string_append_printf(x264opts, "%s:", split[ii]); - - } - if (split) g_strfreev(split); - if (!foundit) - { - gchar *val; - if (type == X264_OPT_DEBLOCK) - val = get_deblock_val(ud); - else - { - GValue *gval; - gval = ghb_widget_value(widget); - if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN) - { - if (ghb_value_boolean(gval)) - val = g_strdup("1"); - else - val = g_strdup("0"); - } - else - { - val = ghb_widget_string(widget); - } - ghb_value_free(gval); - } - if (strcmp(def_val, val) != 0) - { - g_string_append_printf(x264opts, "%s=%s:", opt_syns[0], val); - } - g_free(val); - } - // Update the options value - // strip the trailing ":" - gchar *result; - gint len; - result = g_string_free(x264opts, FALSE); - len = strlen(result); - if (len > 0) result[len - 1] = 0; - gchar *sopts; - sopts = ghb_sanitize_x264opts(ud, result); - ghb_ui_update(ud, "x264_options", ghb_string_value(sopts)); - ghb_x264_parse_options(ud, sopts); - g_free(sopts); - g_free(result); - } -} - -static void -x264_remove_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) - { - // Mark as deleted - opts[ii][0] = 0; - } - g_free(opt); - } -} - -// Construct the x264 options string -// The result is allocated, so someone must free it at some point. -gchar* -ghb_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++) - { - 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); - } - gint refs = ghb_settings_get_int(ud->settings, "x264_refs"); - if (refs <= 1) - { - x264_remove_opt(split, x264_mixed_syns); - } - gint subme; - - subme = ghb_lookup_combo_int("x264_subme", - ghb_settings_get_value(ud->settings, "x264_subme")); - if (subme < 6) - { - x264_remove_opt(split, x264_brdo_syns); - } - gint bframes = ghb_settings_get_int(ud->settings, "x264_bframes"); - if (bframes == 0) - { - x264_remove_opt(split, x264_weightb_syns); - x264_remove_opt(split, x264_brdo_syns); - x264_remove_opt(split, x264_bime_syns); - x264_remove_opt(split, x264_direct_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); - } - for (ii = 0; split[ii] != NULL; ii++) - { - if (split[ii][0] != 0) - g_string_append_printf(x264opts, "%s:", split[ii]); - } - g_strfreev(split); - // strip the trailing ":" - gchar *result; - gint len; - result = g_string_free(x264opts, FALSE); - len = strlen(result); - if (len > 0) result[len - 1] = 0; - return result; -} - gint ghb_pref_acount(GValue *settings) { diff --git a/gtk/src/settings.h b/gtk/src/settings.h index ca3ffa1e2..69a79c2a3 100644 --- a/gtk/src/settings.h +++ b/gtk/src/settings.h @@ -94,9 +94,6 @@ void ghb_widget_to_setting(GValue *settings, GtkWidget *widget); int ghb_ui_update( signal_user_data_t *ud, const gchar *name, const GValue *value); -void ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options); -void ghb_x264_opt_update(signal_user_data_t *ud, GtkWidget *widget); -gchar* ghb_sanitize_x264opts(signal_user_data_t *ud, const gchar *options); gint ghb_pref_acount(GValue *settings); gint ghb_pref_acodec(GValue *settings, gint index); diff --git a/gtk/src/x264handler.c b/gtk/src/x264handler.c new file mode 100644 index 000000000..4a75520f0 --- /dev/null +++ b/gtk/src/x264handler.c @@ -0,0 +1,620 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * x264handler.c + * Copyright (C) John Stebbins 2008 <stebbins@stebbins> + * + * x264handler.c is free software. + * + * You may redistribute it and/or modify it under the terms of the + * GNU General Public License, as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include <gtk/gtk.h> +#include <string.h> +#include "settings.h" +#include "values.h" +#include "callbacks.h" +#include "x264handler.h" + +static void x264_opt_update(signal_user_data_t *ud, GtkWidget *widget); +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 +x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) +{ + 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); +} + +void +x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud) +{ + g_debug("x264_entry_changed_cb ()"); + if (!ignore_options_update) + { + GtkWidget *textview; + gchar *options; + + textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264_options")); + ghb_widget_to_setting(ud->settings, textview); + options = ghb_settings_get_string(ud->settings, "x264_options"); + ignore_options_update = TRUE; + ghb_x264_parse_options(ud, options); + if (!GTK_WIDGET_HAS_FOCUS(textview)) + { + gchar *sopts; + + sopts = sanitize_x264opts(ud, options); + ghb_ui_update(ud, "x264_options", ghb_string_value(sopts)); + ghb_x264_parse_options(ud, sopts); + g_free(sopts); + } + g_free(options); + ignore_options_update = FALSE; + } +} + +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"); + sopts = sanitize_x264opts(ud, options); + ignore_options_update = TRUE; + if (sopts != NULL) + { + ghb_ui_update(ud, "x264_options", ghb_string_value(sopts)); + ghb_x264_parse_options(ud, sopts); + } + g_free(options); + g_free(sopts); + ignore_options_update = FALSE; + return FALSE; +} + +enum +{ + X264_OPT_DEBLOCK, + X264_OPT_INT, + X264_OPT_COMBO, + X264_OPT_BOOL, +}; + +struct x264_opt_map_s +{ + gchar **opt_syns; + gchar *name; + gchar *def_val; + gint type; + gboolean found; +}; + +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_direct_syns[] = + {"direct", "direct-pred", "direct_pred", NULL}; +static gchar *x264_weightb_syns[] = {"weightb", "weight-b", "weight_b", NULL}; +static gchar *x264_brdo_syns[] = {"brdo", "b-rdo", "b_rdo", NULL}; +static gchar *x264_bime_syns[] = {"bime", NULL}; +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_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_decimate_syns[] = + {"no-dct-decimate", "no_dct_decimate", NULL}; +static gchar *x264_cabac_syns[] = {"cabac", NULL}; + +static gint +find_syn_match(const gchar *opt, gchar **syns) +{ + gint ii; + for (ii = 0; syns[ii] != NULL; ii++) + { + if (strcmp(opt, syns[ii]) == 0) + return ii; + } + return -1; +} + +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_direct_syns, "x264_direct", "spatial", X264_OPT_COMBO}, + {x264_weightb_syns, "x264_weighted_bframes", "0", X264_OPT_BOOL}, + {x264_brdo_syns, "x264_brdo", "0", X264_OPT_BOOL}, + {x264_bime_syns, "x264_bime", "0", 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_analyse_syns, "x264_analyse", "some", X264_OPT_COMBO}, + {x264_8x8dct_syns, "x264_8x8dct", "0", 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_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}, +}; +#define X264_OPT_MAP_SIZE (sizeof(x264_opt_map)/sizeof(struct x264_opt_map_s)) + +static const gchar* +x264_opt_get_default(const gchar *opt) +{ + gint jj; + for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++) + { + if (find_syn_match(opt, x264_opt_map[jj].opt_syns) >= 0) + { + return x264_opt_map[jj].def_val; + } + } + return ""; +} + +static void +x264_update_int(signal_user_data_t *ud, const gchar *name, const gchar *val) +{ + gint ival; + + if (val == NULL) return; + ival = g_strtod (val, NULL); + ghb_ui_update(ud, name, ghb_int64_value(ival)); +} + +static gchar *true_str[] = +{ + "true", + "yes", + "1", + NULL +}; + +static gboolean +str_is_true(const gchar *str) +{ + gint ii; + for (ii = 0; true_str[ii]; ii++) + { + if (g_ascii_strcasecmp(str, true_str[ii]) == 0) + return TRUE; + } + return FALSE; +} + +static void +x264_update_bool(signal_user_data_t *ud, const gchar *name, const gchar *val) +{ + if (val == NULL) + ghb_ui_update(ud, name, ghb_boolean_value(1)); + else + ghb_ui_update(ud, name, ghb_boolean_value(str_is_true(val))); +} + +static void +x264_update_combo(signal_user_data_t *ud, const gchar *name, const gchar *val) +{ + GtkTreeModel *store; + GtkTreeIter iter; + gchar *shortOpt; + gint ivalue; + gboolean foundit = FALSE; + GtkWidget *widget; + + if (val == NULL) return; + widget = GHB_WIDGET(ud->builder, name); + if (widget == NULL) + { + g_debug("Failed to find widget for key: %s\n", name); + return; + } + store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget)); + if (gtk_tree_model_get_iter_first (store, &iter)) + { + do + { + gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1); + if (strcmp(shortOpt, val) == 0) + { + gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter); + g_free(shortOpt); + foundit = TRUE; + break; + } + g_free(shortOpt); + } while (gtk_tree_model_iter_next (store, &iter)); + } + if (!foundit) + { + if (gtk_tree_model_get_iter_first (store, &iter)) + { + do + { + gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1); + if (strcmp(shortOpt, "custom") == 0) + { + gtk_list_store_set(GTK_LIST_STORE(store), &iter, 4, val, -1); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter); + g_free(shortOpt); + foundit = TRUE; + break; + } + g_free(shortOpt); + } while (gtk_tree_model_iter_next (store, &iter)); + } + } + // Its possible the value hasn't changed. Since settings are only + // updated when the value changes, I'm initializing settings here as well. + ghb_widget_to_setting(ud->settings, widget); +} + +static void +x264_update_deblock(signal_user_data_t *ud, const gchar *xval) +{ + gdouble avalue, bvalue; + gchar *end; + gchar *val; + gchar *bval = NULL; + + if (xval == NULL) return; + val = g_strdup(xval); + bvalue = avalue = 0; + if (val != NULL) + { + gchar *pos = strchr(val, ','); + if (pos != NULL) + { + bval = pos + 1; + *pos = 0; + } + avalue = g_strtod (val, &end); + if (bval != NULL) + { + bvalue = g_strtod (bval, &end); + } + } + g_free(val); + ghb_ui_update(ud, "x264_deblock_alpha", ghb_int64_value(avalue)); + ghb_ui_update(ud, "x264_deblock_beta", ghb_int64_value(bvalue)); +} + +void +ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options) +{ + gchar **split = g_strsplit(options, ":", -1); + if (split == NULL) return; + + gint ii; + gint jj; + + for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++) + x264_opt_map[jj].found = FALSE; + + for (ii = 0; split[ii] != NULL; ii++) + { + gchar *val = NULL; + gchar *pos = strchr(split[ii], '='); + if (pos != NULL) + { + val = pos + 1; + *pos = 0; + } + for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++) + { + if (find_syn_match(split[ii], x264_opt_map[jj].opt_syns) >= 0) + { + x264_opt_map[jj].found = TRUE; + switch(x264_opt_map[jj].type) + { + case X264_OPT_INT: + x264_update_int(ud, x264_opt_map[jj].name, val); + break; + case X264_OPT_BOOL: + x264_update_bool(ud, x264_opt_map[jj].name, val); + break; + case X264_OPT_COMBO: + x264_update_combo(ud, x264_opt_map[jj].name, val); + break; + case X264_OPT_DEBLOCK: + // dirty little hack. mark deblock_beta found as well + x264_opt_map[jj+1].found = TRUE; + x264_update_deblock(ud, val); + break; + } + break; + } + } + } + // For any options not found in the option string, set ui to + // default values + for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++) + { + if (!x264_opt_map[jj].found) + { + gchar *val = strdup(x264_opt_map[jj].def_val); + switch(x264_opt_map[jj].type) + { + case X264_OPT_INT: + x264_update_int(ud, x264_opt_map[jj].name, val); + break; + case X264_OPT_BOOL: + x264_update_bool(ud, x264_opt_map[jj].name, val); + break; + case X264_OPT_COMBO: + x264_update_combo(ud, x264_opt_map[jj].name, val); + break; + case X264_OPT_DEBLOCK: + x264_update_deblock(ud, val); + break; + } + x264_opt_map[jj].found = TRUE; + g_free(val); + } + } + g_strfreev(split); +} + +gchar* +get_deblock_val(signal_user_data_t *ud) +{ + gchar *alpha, *beta; + gchar *result; + alpha = ghb_settings_get_string(ud->settings, "x264_deblock_alpha"); + beta = ghb_settings_get_string(ud->settings, "x264_deblock_beta"); + result = g_strdup_printf("%s,%s", alpha, beta); + g_free(alpha); + g_free(beta); + return result; +} + +static void +x264_opt_update(signal_user_data_t *ud, GtkWidget *widget) +{ + gint jj; + const gchar *name = gtk_widget_get_name(widget); + gchar **opt_syns = NULL; + const gchar *def_val = NULL; + gint type; + + for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++) + { + if (strcmp(name, x264_opt_map[jj].name) == 0) + { + // found the options that needs updating + opt_syns = x264_opt_map[jj].opt_syns; + def_val = x264_opt_map[jj].def_val; + type = x264_opt_map[jj].type; + break; + } + } + if (opt_syns != NULL) + { + GString *x264opts = g_string_new(""); + gchar *options; + gchar **split = NULL; + gint ii; + gboolean foundit = FALSE; + + options = ghb_settings_get_string(ud->settings, "x264_options"); + if (options) + { + split = g_strsplit(options, ":", -1); + g_free(options); + } + for (ii = 0; split && split[ii] != NULL; ii++) + { + gint syn; + gchar *val = NULL; + gchar *pos = strchr(split[ii], '='); + if (pos != NULL) + { + val = pos + 1; + *pos = 0; + } + syn = find_syn_match(split[ii], opt_syns); + if (syn >= 0) + { // Updating this option + gchar *val; + foundit = TRUE; + if (type == X264_OPT_DEBLOCK) + val = get_deblock_val(ud); + else + { + GValue *gval; + gval = ghb_widget_value(widget); + if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN) + { + if (ghb_value_boolean(gval)) + val = g_strdup("1"); + else + val = g_strdup("0"); + } + else + { + val = ghb_widget_string(widget); + } + ghb_value_free(gval); + } + if (strcmp(def_val, val) != 0) + { + g_string_append_printf(x264opts, "%s=%s:", opt_syns[syn], val); + } + g_free(val); + } + else if (val != NULL) + g_string_append_printf(x264opts, "%s=%s:", split[ii], val); + else + g_string_append_printf(x264opts, "%s:", split[ii]); + + } + if (split) g_strfreev(split); + if (!foundit) + { + gchar *val; + if (type == X264_OPT_DEBLOCK) + val = get_deblock_val(ud); + else + { + GValue *gval; + gval = ghb_widget_value(widget); + if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN) + { + if (ghb_value_boolean(gval)) + val = g_strdup("1"); + else + val = g_strdup("0"); + } + else + { + val = ghb_widget_string(widget); + } + ghb_value_free(gval); + } + if (strcmp(def_val, val) != 0) + { + g_string_append_printf(x264opts, "%s=%s:", opt_syns[0], val); + } + g_free(val); + } + // Update the options value + // strip the trailing ":" + gchar *result; + gint len; + result = g_string_free(x264opts, FALSE); + len = strlen(result); + 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_x264_parse_options(ud, sopts); + g_free(sopts); + g_free(result); + } +} + +static void +x264_remove_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) + { + // Mark as deleted + opts[ii][0] = 0; + } + g_free(opt); + } +} + +// Construct the x264 options string +// The result is allocated, so someone must free it at some point. +static gchar* +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++) + { + 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); + } + gint refs = ghb_settings_get_int(ud->settings, "x264_refs"); + if (refs <= 1) + { + x264_remove_opt(split, x264_mixed_syns); + } + gint subme; + + subme = ghb_settings_combo_int(ud->settings, "x264_subme"); + if (subme < 6) + { + x264_remove_opt(split, x264_brdo_syns); + } + gint bframes = ghb_settings_get_int(ud->settings, "x264_bframes"); + if (bframes == 0) + { + x264_remove_opt(split, x264_weightb_syns); + x264_remove_opt(split, x264_brdo_syns); + x264_remove_opt(split, x264_bime_syns); + x264_remove_opt(split, x264_direct_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); + } + for (ii = 0; split[ii] != NULL; ii++) + { + if (split[ii][0] != 0) + g_string_append_printf(x264opts, "%s:", split[ii]); + } + g_strfreev(split); + // strip the trailing ":" + gchar *result; + gint len; + result = g_string_free(x264opts, FALSE); + len = strlen(result); + if (len > 0) result[len - 1] = 0; + return result; +} + diff --git a/gtk/src/x264handler.h b/gtk/src/x264handler.h new file mode 100644 index 000000000..89e906ab3 --- /dev/null +++ b/gtk/src/x264handler.h @@ -0,0 +1,32 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * x264handler.h + * Copyright (C) John Stebbins 2008 <stebbins@stebbins> + * + * x264handler.h is free software. + * + * You may redistribute it and/or modify it under the terms of the + * GNU General Public License, as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * callbacks.h is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with callbacks.h. If not, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + */ + +#if !defined(_X264HANDLER_H_) +#define _X264HANDLER_H_ + +#include "settings.h" + +void ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options); + +#endif // _X264HANDLER_H_ |