1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
6 * x264handler.c is free software.
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
18 #include "callbacks.h"
20 #include "x264handler.h"
22 static void x264_opt_update(signal_user_data_t *ud, GtkWidget *widget);
23 static gchar* sanitize_x264opts(signal_user_data_t *ud, const gchar *options);
25 // Flag needed to prevent x264 options processing from chasing its tail
26 static gboolean ignore_options_update = FALSE;
29 x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
31 ghb_widget_to_setting(ud->settings, widget);
32 if (!ignore_options_update)
34 ignore_options_update = TRUE;
35 x264_opt_update(ud, widget);
36 ignore_options_update = FALSE;
38 ghb_check_dependency(ud, widget);
39 ghb_clear_presets_selection(ud);
43 x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
45 g_debug("x264_entry_changed_cb ()");
46 if (!ignore_options_update)
51 textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264_options"));
52 ghb_widget_to_setting(ud->settings, textview);
53 options = ghb_settings_get_string(ud->settings, "x264_options");
54 ignore_options_update = TRUE;
55 ghb_x264_parse_options(ud, options);
56 if (!GTK_WIDGET_HAS_FOCUS(textview))
60 sopts = sanitize_x264opts(ud, options);
61 ghb_ui_update(ud, "x264_options", ghb_string_value(sopts));
62 ghb_x264_parse_options(ud, sopts);
66 ignore_options_update = FALSE;
71 x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event,
72 signal_user_data_t *ud)
74 gchar *options, *sopts;
76 ghb_widget_to_setting(ud->settings, widget);
77 options = ghb_settings_get_string(ud->settings, "x264_options");
78 sopts = sanitize_x264opts(ud, options);
79 ignore_options_update = TRUE;
82 ghb_ui_update(ud, "x264_options", ghb_string_value(sopts));
83 ghb_x264_parse_options(ud, sopts);
87 ignore_options_update = FALSE;
108 static gchar *x264_ref_syns[] = {"ref", "frameref", NULL};
109 static gchar *x264_mixed_syns[] = {"mixed-refs", "mixed_refs", NULL};
110 static gchar *x264_bframes_syns[] = {"bframes", NULL};
111 static gchar *x264_direct_syns[] =
112 {"direct", "direct-pred", "direct_pred", NULL};
113 static gchar *x264_weightb_syns[] = {"weightb", "weight-b", "weight_b", NULL};
114 static gchar *x264_brdo_syns[] = {"brdo", "b-rdo", "b_rdo", NULL};
115 static gchar *x264_bime_syns[] = {"bime", NULL};
116 static gchar *x264_bpyramid_syns[] = {"b-pyramid", "b_pyramid", NULL};
117 static gchar *x264_me_syns[] = {"me", NULL};
118 static gchar *x264_merange_syns[] = {"merange", "me-range", "me_range", NULL};
119 static gchar *x264_subme_syns[] = {"subme", "subq", NULL};
120 static gchar *x264_analyse_syns[] = {"analyse", "partitions", NULL};
121 static gchar *x264_8x8dct_syns[] = {"8x8dct", NULL};
122 static gchar *x264_deblock_syns[] = {"deblock", "filter", NULL};
123 static gchar *x264_trellis_syns[] = {"trellis", NULL};
124 static gchar *x264_pskip_syns[] = {"no-fast-pskip", "no_fast_pskip", NULL};
125 static gchar *x264_decimate_syns[] =
126 {"no-dct-decimate", "no_dct_decimate", NULL};
127 static gchar *x264_cabac_syns[] = {"cabac", NULL};
130 find_syn_match(const gchar *opt, gchar **syns)
133 for (ii = 0; syns[ii] != NULL; ii++)
135 if (strcmp(opt, syns[ii]) == 0)
141 struct x264_opt_map_s x264_opt_map[] =
143 {x264_ref_syns, "x264_refs", "1", X264_OPT_INT},
144 {x264_mixed_syns, "x264_mixed_refs", "0", X264_OPT_BOOL},
145 {x264_bframes_syns, "x264_bframes", "0", X264_OPT_INT},
146 {x264_direct_syns, "x264_direct", "spatial", X264_OPT_COMBO},
147 {x264_weightb_syns, "x264_weighted_bframes", "0", X264_OPT_BOOL},
148 {x264_brdo_syns, "x264_brdo", "0", X264_OPT_BOOL},
149 {x264_bime_syns, "x264_bime", "0", X264_OPT_BOOL},
150 {x264_bpyramid_syns, "x264_bpyramid", "0", X264_OPT_BOOL},
151 {x264_me_syns, "x264_me", "hex", X264_OPT_COMBO},
152 {x264_merange_syns, "x264_merange", "16", X264_OPT_INT},
153 {x264_subme_syns, "x264_subme", "6", X264_OPT_COMBO},
154 {x264_analyse_syns, "x264_analyse", "some", X264_OPT_COMBO},
155 {x264_8x8dct_syns, "x264_8x8dct", "0", X264_OPT_BOOL},
156 {x264_deblock_syns, "x264_deblock_alpha", "0,0", X264_OPT_DEBLOCK},
157 {x264_deblock_syns, "x264_deblock_beta", "0,0", X264_OPT_DEBLOCK},
158 {x264_trellis_syns, "x264_trellis", "0", X264_OPT_COMBO},
159 {x264_pskip_syns, "x264_no_fast_pskip", "0", X264_OPT_BOOL},
160 {x264_decimate_syns, "x264_no_dct_decimate", "0", X264_OPT_BOOL},
161 {x264_cabac_syns, "x264_cabac", "1", X264_OPT_BOOL},
163 #define X264_OPT_MAP_SIZE (sizeof(x264_opt_map)/sizeof(struct x264_opt_map_s))
166 x264_opt_get_default(const gchar *opt)
169 for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
171 if (find_syn_match(opt, x264_opt_map[jj].opt_syns) >= 0)
173 return x264_opt_map[jj].def_val;
180 x264_update_int(signal_user_data_t *ud, const gchar *name, const gchar *val)
184 if (val == NULL) return;
185 ival = g_strtod (val, NULL);
186 ghb_ui_update(ud, name, ghb_int64_value(ival));
189 static gchar *true_str[] =
198 str_is_true(const gchar *str)
201 for (ii = 0; true_str[ii]; ii++)
203 if (g_ascii_strcasecmp(str, true_str[ii]) == 0)
210 x264_update_bool(signal_user_data_t *ud, const gchar *name, const gchar *val)
213 ghb_ui_update(ud, name, ghb_boolean_value(1));
215 ghb_ui_update(ud, name, ghb_boolean_value(str_is_true(val)));
219 x264_update_combo(signal_user_data_t *ud, const gchar *name, const gchar *val)
225 gboolean foundit = FALSE;
228 if (val == NULL) return;
229 widget = GHB_WIDGET(ud->builder, name);
232 g_debug("Failed to find widget for key: %s\n", name);
235 store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
236 if (gtk_tree_model_get_iter_first (store, &iter))
240 gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1);
241 if (strcmp(shortOpt, val) == 0)
243 gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
249 } while (gtk_tree_model_iter_next (store, &iter));
253 if (gtk_tree_model_get_iter_first (store, &iter))
257 gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1);
258 if (strcmp(shortOpt, "custom") == 0)
260 gtk_list_store_set(GTK_LIST_STORE(store), &iter, 4, val, -1);
261 gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
267 } while (gtk_tree_model_iter_next (store, &iter));
270 // Its possible the value hasn't changed. Since settings are only
271 // updated when the value changes, I'm initializing settings here as well.
272 ghb_widget_to_setting(ud->settings, widget);
276 x264_update_deblock(signal_user_data_t *ud, const gchar *xval)
278 gdouble avalue, bvalue;
283 if (xval == NULL) return;
284 val = g_strdup(xval);
288 gchar *pos = strchr(val, ',');
294 avalue = g_strtod (val, &end);
297 bvalue = g_strtod (bval, &end);
301 ghb_ui_update(ud, "x264_deblock_alpha", ghb_int64_value(avalue));
302 ghb_ui_update(ud, "x264_deblock_beta", ghb_int64_value(bvalue));
306 ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options)
308 gchar **split = g_strsplit(options, ":", -1);
309 if (split == NULL) return;
314 for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
315 x264_opt_map[jj].found = FALSE;
317 for (ii = 0; split[ii] != NULL; ii++)
320 gchar *pos = strchr(split[ii], '=');
326 for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
328 if (find_syn_match(split[ii], x264_opt_map[jj].opt_syns) >= 0)
330 x264_opt_map[jj].found = TRUE;
331 switch(x264_opt_map[jj].type)
334 x264_update_int(ud, x264_opt_map[jj].name, val);
337 x264_update_bool(ud, x264_opt_map[jj].name, val);
340 x264_update_combo(ud, x264_opt_map[jj].name, val);
342 case X264_OPT_DEBLOCK:
343 // dirty little hack. mark deblock_beta found as well
344 x264_opt_map[jj+1].found = TRUE;
345 x264_update_deblock(ud, val);
352 // For any options not found in the option string, set ui to
354 for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
356 if (!x264_opt_map[jj].found)
358 gchar *val = strdup(x264_opt_map[jj].def_val);
359 switch(x264_opt_map[jj].type)
362 x264_update_int(ud, x264_opt_map[jj].name, val);
365 x264_update_bool(ud, x264_opt_map[jj].name, val);
368 x264_update_combo(ud, x264_opt_map[jj].name, val);
370 case X264_OPT_DEBLOCK:
371 x264_update_deblock(ud, val);
374 x264_opt_map[jj].found = TRUE;
382 get_deblock_val(signal_user_data_t *ud)
386 alpha = ghb_settings_get_string(ud->settings, "x264_deblock_alpha");
387 beta = ghb_settings_get_string(ud->settings, "x264_deblock_beta");
388 result = g_strdup_printf("%s,%s", alpha, beta);
395 x264_opt_update(signal_user_data_t *ud, GtkWidget *widget)
398 const gchar *name = gtk_widget_get_name(widget);
399 gchar **opt_syns = NULL;
400 const gchar *def_val = NULL;
403 for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
405 if (strcmp(name, x264_opt_map[jj].name) == 0)
407 // found the options that needs updating
408 opt_syns = x264_opt_map[jj].opt_syns;
409 def_val = x264_opt_map[jj].def_val;
410 type = x264_opt_map[jj].type;
414 if (opt_syns != NULL)
416 GString *x264opts = g_string_new("");
418 gchar **split = NULL;
420 gboolean foundit = FALSE;
422 options = ghb_settings_get_string(ud->settings, "x264_options");
425 split = g_strsplit(options, ":", -1);
428 for (ii = 0; split && split[ii] != NULL; ii++)
432 gchar *pos = strchr(split[ii], '=');
438 syn = find_syn_match(split[ii], opt_syns);
440 { // Updating this option
443 if (type == X264_OPT_DEBLOCK)
444 val = get_deblock_val(ud);
448 gval = ghb_widget_value(widget);
449 if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN)
451 if (ghb_value_boolean(gval))
458 val = ghb_widget_string(widget);
460 ghb_value_free(gval);
462 if (strcmp(def_val, val) != 0)
464 g_string_append_printf(x264opts, "%s=%s:", opt_syns[syn], val);
468 else if (val != NULL)
469 g_string_append_printf(x264opts, "%s=%s:", split[ii], val);
471 g_string_append_printf(x264opts, "%s:", split[ii]);
474 if (split) g_strfreev(split);
478 if (type == X264_OPT_DEBLOCK)
479 val = get_deblock_val(ud);
483 gval = ghb_widget_value(widget);
484 if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN)
486 if (ghb_value_boolean(gval))
493 val = ghb_widget_string(widget);
495 ghb_value_free(gval);
497 if (strcmp(def_val, val) != 0)
499 g_string_append_printf(x264opts, "%s=%s:", opt_syns[0], val);
503 // Update the options value
504 // strip the trailing ":"
507 result = g_string_free(x264opts, FALSE);
508 len = strlen(result);
509 if (len > 0) result[len - 1] = 0;
511 sopts = sanitize_x264opts(ud, result);
512 ghb_ui_update(ud, "x264_options", ghb_string_value(sopts));
513 ghb_x264_parse_options(ud, sopts);
520 x264_remove_opt(gchar **opts, gchar **opt_syns)
523 for (ii = 0; opts[ii] != NULL; ii++)
526 opt = g_strdup(opts[ii]);
527 gchar *pos = strchr(opt, '=');
532 if (find_syn_match(opt, opt_syns) >= 0)
541 // Construct the x264 options string
542 // The result is allocated, so someone must free it at some point.
544 sanitize_x264opts(signal_user_data_t *ud, const gchar *options)
546 GString *x264opts = g_string_new("");
547 gchar **split = g_strsplit(options, ":", -1);
549 // Remove entries that match the defaults
551 for (ii = 0; split[ii] != NULL; ii++)
554 gchar *opt = g_strdup(split[ii]);
555 gchar *pos = strchr(opt, '=');
565 const gchar *def_val = x264_opt_get_default(opt);
566 if (strcmp(val, def_val) == 0)
568 // Matches the default, so remove it
573 gint refs = ghb_settings_get_int(ud->settings, "x264_refs");
576 x264_remove_opt(split, x264_mixed_syns);
580 subme = ghb_settings_combo_int(ud->settings, "x264_subme");
583 x264_remove_opt(split, x264_brdo_syns);
585 gint bframes = ghb_settings_get_int(ud->settings, "x264_bframes");
588 x264_remove_opt(split, x264_weightb_syns);
589 x264_remove_opt(split, x264_brdo_syns);
590 x264_remove_opt(split, x264_bime_syns);
591 x264_remove_opt(split, x264_direct_syns);
595 x264_remove_opt(split, x264_bpyramid_syns);
597 gchar *me = ghb_settings_get_string(ud->settings, "x264_me");
598 if (!(strcmp(me, "umh") == 0 || strcmp(me, "esa") == 0))
600 x264_remove_opt(split, x264_merange_syns);
603 if (!ghb_settings_get_boolean(ud->settings, "x264_cabac"))
605 x264_remove_opt(split, x264_trellis_syns);
607 for (ii = 0; split[ii] != NULL; ii++)
609 if (split[ii][0] != 0)
610 g_string_append_printf(x264opts, "%s:", split[ii]);
613 // strip the trailing ":"
616 result = g_string_free(x264opts, FALSE);
617 len = strlen(result);
618 if (len > 0) result[len - 1] = 0;