OSDN Git Service

patch to allow higher bitrates with faac
[handbrake-jp/handbrake-jp-git.git] / gtk / src / x264handler.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * x264handler.c
4  * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
5  * 
6  * x264handler.c is free software.
7  * 
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)
11  * any later version.
12  */
13
14 #include <gtk/gtk.h>
15 #include <string.h>
16 #include "settings.h"
17 #include "values.h"
18 #include "callbacks.h"
19 #include "presets.h"
20 #include "hb-backend.h"
21 #include "x264handler.h"
22
23 gint ghb_lookup_bframes(const gchar *options);
24 static void x264_opt_update(signal_user_data_t *ud, GtkWidget *widget);
25 static gchar* sanitize_x264opts(signal_user_data_t *ud, const gchar *options);
26
27 // Flag needed to prevent x264 options processing from chasing its tail
28 static gboolean ignore_options_update = FALSE;
29
30 G_MODULE_EXPORT void
31 x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
32 {
33         ghb_widget_to_setting(ud->settings, widget);
34         if (!ignore_options_update)
35         {
36                 ignore_options_update = TRUE;
37                 x264_opt_update(ud, widget);
38                 ignore_options_update = FALSE;
39         }
40         ghb_check_dependency(ud, widget, NULL);
41         ghb_clear_presets_selection(ud);
42 }
43
44 G_MODULE_EXPORT void
45 x264_me_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
46 {
47         gint me;
48
49         ghb_widget_to_setting(ud->settings, widget);
50         if (!ignore_options_update)
51         {
52                 ignore_options_update = TRUE;
53                 x264_opt_update(ud, widget);
54                 ignore_options_update = FALSE;
55         }
56         ghb_check_dependency(ud, widget, NULL);
57         ghb_clear_presets_selection(ud);
58         widget = GHB_WIDGET(ud->builder, "x264_merange");
59         me = ghb_settings_combo_int(ud->settings, "x264_me");
60         if (me < 2)
61         {       // me < umh
62                 // me_range 4 - 16
63                 gtk_spin_button_set_range(GTK_SPIN_BUTTON(widget), 4, 16);
64         }
65         else
66         {
67                 // me_range 4 - 64
68                 gtk_spin_button_set_range(GTK_SPIN_BUTTON(widget), 4, 64);
69         }
70 }
71
72 G_MODULE_EXPORT void
73 x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
74 {
75         g_debug("x264_entry_changed_cb ()");
76         if (!ignore_options_update)
77         {
78                 GtkWidget *textview;
79                 gchar *options;
80
81                 textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264Option"));
82                 ghb_widget_to_setting(ud->settings, textview);
83                 options = ghb_settings_get_string(ud->settings, "x264Option");
84                 ignore_options_update = TRUE;
85                 ghb_x264_parse_options(ud, options);
86                 if (!GTK_WIDGET_HAS_FOCUS(textview))
87                 {
88                         gchar *sopts;
89
90                         sopts = sanitize_x264opts(ud, options);
91                         ghb_ui_update(ud, "x264Option", ghb_string_value(sopts));
92                         ghb_x264_parse_options(ud, sopts);
93                         g_free(sopts);
94                 }
95                 g_free(options);
96                 ignore_options_update = FALSE;
97         }
98 }
99
100 G_MODULE_EXPORT gboolean
101 x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
102         signal_user_data_t *ud)
103 {
104         gchar *options, *sopts;
105
106         ghb_widget_to_setting(ud->settings, widget);
107         options = ghb_settings_get_string(ud->settings, "x264Option");
108         sopts = sanitize_x264opts(ud, options);
109         ignore_options_update = TRUE;
110         if (sopts != NULL && strcmp(sopts, options) != 0)
111         {
112                 ghb_ui_update(ud, "x264Option", ghb_string_value(sopts));
113                 ghb_x264_parse_options(ud, sopts);
114         }
115         g_free(options);
116         g_free(sopts);
117         ignore_options_update = FALSE;
118         return FALSE;
119 }
120
121 enum
122 {
123         X264_OPT_NONE,
124         X264_OPT_BOOL_NONE,
125         X264_OPT_INT_NONE,
126         X264_OPT_DEBLOCK,
127         X264_OPT_PSY,
128         X264_OPT_INT,
129         X264_OPT_COMBO,
130         X264_OPT_BOOL,
131 };
132
133 struct x264_opt_map_s
134 {
135         gchar **opt_syns;
136         gchar *name;
137         gchar *def_val;
138         gint type;
139         gboolean found;
140 };
141
142 static gchar *x264_ref_syns[] = {"ref", "frameref", NULL};
143 static gchar *x264_mixed_syns[] = {"mixed-refs", "mixed_refs", NULL};
144 static gchar *x264_bframes_syns[] = {"bframes", NULL};
145 static gchar *x264_badapt_syns[] = {"b-adapt", "b_adapt", NULL};
146 static gchar *x264_direct_syns[] = 
147         {"direct", "direct-pred", "direct_pred", NULL};
148 static gchar *x264_weightb_syns[] = {"weightb", "weight-b", "weight_b", NULL};
149 static gchar *x264_bpyramid_syns[] = {"b-pyramid", "b_pyramid", NULL};
150 static gchar *x264_me_syns[] = {"me", NULL};
151 static gchar *x264_merange_syns[] = {"merange", "me-range", "me_range", NULL};
152 static gchar *x264_subme_syns[] = {"subme", "subq", NULL};
153 static gchar *x264_aqmode_syns[] = {"aq-mode", NULL};
154 static gchar *x264_analyse_syns[] = {"analyse", "partitions", NULL};
155 static gchar *x264_8x8dct_syns[] = {"8x8dct", NULL};
156 static gchar *x264_deblock_syns[] = {"deblock", "filter", NULL};
157 static gchar *x264_trellis_syns[] = {"trellis", NULL};
158 static gchar *x264_pskip_syns[] = {"no-fast-pskip", "no_fast_pskip", NULL};
159 static gchar *x264_psy_syns[] = {"psy-rd", "psy_rd", NULL};
160 static gchar *x264_mbtree_syns[] = {"mbtree", NULL};
161 static gchar *x264_decimate_syns[] = 
162         {"no-dct-decimate", "no_dct_decimate", NULL};
163 static gchar *x264_cabac_syns[] = {"cabac", NULL};
164
165 static gint
166 find_syn_match(const gchar *opt, gchar **syns)
167 {
168         gint ii;
169         for (ii = 0; syns[ii] != NULL; ii++)
170         {
171                 if (strcmp(opt, syns[ii]) == 0)
172                         return ii;
173         }
174         return -1;
175 }
176
177 struct x264_opt_map_s x264_opt_map[] =
178 {
179         {x264_ref_syns, "x264_refs", "3", X264_OPT_INT},
180         {x264_mixed_syns, "x264_mixed_refs", "1", X264_OPT_BOOL},
181         {x264_bframes_syns, "x264_bframes", "3", X264_OPT_INT},
182         {x264_direct_syns, "x264_direct", "spatial", X264_OPT_COMBO},
183         {x264_badapt_syns, "x264_b_adapt", "1", X264_OPT_COMBO},
184         {x264_weightb_syns, "x264_weighted_bframes", "1", X264_OPT_BOOL},
185         {x264_bpyramid_syns, "x264_bpyramid", "0", X264_OPT_BOOL},
186         {x264_me_syns, "x264_me", "hex", X264_OPT_COMBO},
187         {x264_merange_syns, "x264_merange", "16", X264_OPT_INT},
188         {x264_subme_syns, "x264_subme", "7", X264_OPT_COMBO},
189         {x264_aqmode_syns, "x264_aqmode", "1", X264_OPT_INT_NONE},
190         {x264_analyse_syns, "x264_analyse", "some", X264_OPT_COMBO},
191         {x264_8x8dct_syns, "x264_8x8dct", "1", X264_OPT_BOOL},
192         {x264_deblock_syns, "x264_deblock_alpha", "0,0", X264_OPT_DEBLOCK},
193         {x264_deblock_syns, "x264_deblock_beta", "0,0", X264_OPT_DEBLOCK},
194         {x264_trellis_syns, "x264_trellis", "1", X264_OPT_COMBO},
195         {x264_pskip_syns, "x264_no_fast_pskip", "0", X264_OPT_BOOL},
196         {x264_decimate_syns, "x264_no_dct_decimate", "0", X264_OPT_BOOL},
197         {x264_cabac_syns, "x264_cabac", "1", X264_OPT_BOOL},
198         {x264_psy_syns, "x264_psy_rd", "1,0", X264_OPT_PSY},
199         {x264_psy_syns, "x264_psy_trell", "1,0", X264_OPT_PSY},
200         {x264_mbtree_syns, "x264_mbtree", "1", X264_OPT_BOOL_NONE},
201 };
202 #define X264_OPT_MAP_SIZE (sizeof(x264_opt_map)/sizeof(struct x264_opt_map_s))
203
204 static const gchar*
205 x264_opt_get_default(const gchar *opt)
206 {
207         gint jj;
208         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
209         {
210                 if (find_syn_match(opt, x264_opt_map[jj].opt_syns) >= 0)
211                 {
212                         return x264_opt_map[jj].def_val;
213                 }
214         }
215         return "";
216 }
217
218 static void
219 x264_update_int(signal_user_data_t *ud, const gchar *name, const gchar *val)
220 {
221         gint ival;
222
223         if (val == NULL) return;
224         ival = g_strtod (val, NULL);
225         ghb_ui_update(ud, name, ghb_int64_value(ival));
226 }
227
228 static void
229 x264_update_int_setting(signal_user_data_t *ud, const gchar *name, const gchar *val)
230 {
231         gint ival;
232
233         if (val == NULL) return;
234         ival = g_strtod (val, NULL);
235         ghb_settings_set_value(ud->settings, name, ghb_int64_value(ival));
236         ghb_check_dependency(ud, NULL, name);
237 }
238
239 static gchar *true_str[] =
240 {
241         "true",
242         "yes",
243         "1",
244         NULL
245 };
246
247 static gboolean 
248 str_is_true(const gchar *str)
249 {
250         gint ii;
251         for (ii = 0; true_str[ii]; ii++)
252         {
253                 if (g_ascii_strcasecmp(str, true_str[ii]) == 0)
254                         return TRUE;
255         }
256         return FALSE;
257 }
258
259 static void
260 x264_update_bool(signal_user_data_t *ud, const gchar *name, const gchar *val)
261 {
262         if (val == NULL)
263                 ghb_ui_update(ud, name, ghb_boolean_value(1));
264         else
265                 ghb_ui_update(ud, name, ghb_boolean_value(str_is_true(val)));
266 }
267
268 static void
269 x264_update_bool_setting(signal_user_data_t *ud, const gchar *name, const gchar *val)
270 {
271         if (val == NULL)
272                 ghb_settings_set_value(ud->settings, name, ghb_boolean_value(1));
273         else
274                 ghb_settings_set_value(ud->settings, name, ghb_boolean_value(str_is_true(val)));
275
276         ghb_check_dependency(ud, NULL, name);
277 }
278
279 static void
280 x264_update_combo(signal_user_data_t *ud, const gchar *name, const gchar *val)
281 {
282         GtkTreeModel *store;
283         GtkTreeIter iter;
284         gchar *shortOpt;
285         gdouble ivalue;
286         gboolean foundit = FALSE;
287         GtkWidget *widget;
288
289         if (val == NULL) return;
290         widget = GHB_WIDGET(ud->builder, name);
291         if (widget == NULL)
292         {
293                 g_debug("Failed to find widget for key: %s\n", name);
294                 return;
295         }
296         store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
297         if (gtk_tree_model_get_iter_first (store, &iter))
298         {
299                 do
300                 {
301                         gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1);
302                         if (strcmp(shortOpt, val) == 0)
303                         {
304                                 gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
305                                 g_free(shortOpt);
306                                 foundit = TRUE;
307                                 break;
308                         }
309                         g_free(shortOpt);
310                 } while (gtk_tree_model_iter_next (store, &iter));
311         }
312         if (!foundit)
313         {
314                 if (gtk_tree_model_get_iter_first (store, &iter))
315                 {
316                         do
317                         {
318                                 gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1);
319                                 if (strcmp(shortOpt, "custom") == 0)
320                                 {
321                                         gtk_list_store_set(GTK_LIST_STORE(store), &iter, 4, val, -1);
322                                         gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
323                                         g_free(shortOpt);
324                                         foundit = TRUE;
325                                         break;
326                                 }
327                                 g_free(shortOpt);
328                         } while (gtk_tree_model_iter_next (store, &iter));
329                 }
330         }
331         // Its possible the value hasn't changed. Since settings are only
332         // updated when the value changes, I'm initializing settings here as well.
333         ghb_widget_to_setting(ud->settings, widget);
334 }
335
336 static void
337 x264_update_deblock(signal_user_data_t *ud, const gchar *xval)
338 {
339         gdouble avalue, bvalue;
340         gchar *end;
341         gchar *val;
342         gchar *bval = NULL;
343
344         if (xval == NULL) return;
345         val = g_strdup(xval);
346         bvalue = avalue = 0;
347         if (val != NULL) 
348         {
349                 gchar *pos = strchr(val, ',');
350                 if (pos != NULL)
351                 {
352                         bval = pos + 1;
353                         *pos = 0;
354                 }
355                 avalue = g_strtod (val, &end);
356                 if (bval != NULL)
357                 {
358                         bvalue = g_strtod (bval, &end);
359                 }
360         }
361         g_free(val);
362         ghb_ui_update(ud, "x264_deblock_alpha", ghb_int64_value(avalue));
363         ghb_ui_update(ud, "x264_deblock_beta", ghb_int64_value(bvalue));
364 }
365
366 static void
367 x264_parse_psy(const gchar *psy, gdouble *psy_rd, gdouble *psy_trell)
368 {
369         gchar *val;
370         gchar *trell_val = NULL;
371         gchar *end;
372
373         *psy_rd = 0.;
374         *psy_trell = 0.;
375         if (psy == NULL) return;
376         val = g_strdup(psy);
377         gchar *pos = strchr(val, ',');
378         if (pos != NULL)
379         {
380                 trell_val = pos + 1;
381                 *pos = 0;
382         }
383         *psy_rd = g_strtod (val, &end);
384         if (trell_val != NULL)
385         {
386                 *psy_trell = g_strtod (trell_val, &end);
387         }
388         g_free(val);
389 }
390
391 static void
392 x264_update_psy(signal_user_data_t *ud, const gchar *xval)
393 {
394         gdouble rd_value, trell_value;
395
396         if (xval == NULL) return;
397         x264_parse_psy(xval, &rd_value, &trell_value);
398         ghb_ui_update(ud, "x264_psy_rd", ghb_double_value(rd_value));
399         ghb_ui_update(ud, "x264_psy_trell", ghb_double_value(trell_value));
400 }
401
402 void
403 ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options)
404 {
405         gchar **split = g_strsplit(options, ":", -1);
406         if (split == NULL) return;
407
408         gint ii;
409         gint jj;
410
411         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
412                 x264_opt_map[jj].found = FALSE;
413
414         for (ii = 0; split[ii] != NULL; ii++)
415         {
416                 gchar *val = NULL;
417                 gchar *pos = strchr(split[ii], '=');
418                 if (pos != NULL)
419                 {
420                         val = pos + 1;
421                         *pos = 0;
422                 }
423                 for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
424                 {
425                         if (find_syn_match(split[ii], x264_opt_map[jj].opt_syns) >= 0)
426                         {
427                                 x264_opt_map[jj].found = TRUE;
428                                 switch(x264_opt_map[jj].type)
429                                 {
430                                 case X264_OPT_INT:
431                                         x264_update_int(ud, x264_opt_map[jj].name, val);
432                                         break;
433                                 case X264_OPT_BOOL:
434                                         x264_update_bool(ud, x264_opt_map[jj].name, val);
435                                         break;
436                                 case X264_OPT_COMBO:
437                                         x264_update_combo(ud, x264_opt_map[jj].name, val);
438                                         break;
439                                 case X264_OPT_DEBLOCK:
440                                         // dirty little hack.  mark deblock_beta found as well
441                                         x264_opt_map[jj+1].found = TRUE;
442                                         x264_update_deblock(ud, val);
443                                         break;
444                                 case X264_OPT_PSY:
445                                         // dirty little hack.  mark psy_trell found as well
446                                         x264_opt_map[jj+1].found = TRUE;
447                                         x264_update_psy(ud, val);
448                                         break;
449                                 case X264_OPT_BOOL_NONE:
450                                         x264_update_bool_setting(ud, x264_opt_map[jj].name, val);
451                                         break;
452                                 case X264_OPT_INT_NONE:
453                                         x264_update_int_setting(ud, x264_opt_map[jj].name, val);
454                                         break;
455                                 }
456                                 break;
457                         }
458                 }
459         }
460         // For any options not found in the option string, set ui to
461         // default values
462         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
463         {
464                 if (!x264_opt_map[jj].found)
465                 {
466                         gchar *val = strdup(x264_opt_map[jj].def_val);
467                         switch(x264_opt_map[jj].type)
468                         {
469                         case X264_OPT_INT:
470                                 x264_update_int(ud, x264_opt_map[jj].name, val);
471                                 break;
472                         case X264_OPT_BOOL:
473                                 x264_update_bool(ud, x264_opt_map[jj].name, val);
474                                 break;
475                         case X264_OPT_COMBO:
476                                 x264_update_combo(ud, x264_opt_map[jj].name, val);
477                                 break;
478                         case X264_OPT_DEBLOCK:
479                                 x264_update_deblock(ud, val);
480                                 break;
481                         case X264_OPT_PSY:
482                                 x264_update_psy(ud, val);
483                                 break;
484                         case X264_OPT_BOOL_NONE:
485                                 x264_update_bool_setting(ud, x264_opt_map[jj].name, val);
486                                 break;
487                         case X264_OPT_INT_NONE:
488                                 x264_update_int_setting(ud, x264_opt_map[jj].name, val);
489                                 break;
490                         }
491                         x264_opt_map[jj].found = TRUE;
492                         g_free(val);
493                 }
494         }
495         g_strfreev(split);
496 }
497
498 gchar*
499 get_deblock_val(signal_user_data_t *ud)
500 {
501         gchar *alpha, *beta;
502         gchar *result;
503         alpha = ghb_settings_get_string(ud->settings, "x264_deblock_alpha");
504         beta = ghb_settings_get_string(ud->settings, "x264_deblock_beta");
505         result = g_strdup_printf("%s,%s", alpha, beta);
506         g_free(alpha);
507         g_free(beta);
508         return result;
509 }
510
511 gchar*
512 get_psy_val(signal_user_data_t *ud)
513 {
514         gdouble rd, trell;
515         gchar *result;
516         rd = ghb_settings_get_double(ud->settings, "x264_psy_rd");
517         trell = ghb_settings_get_double(ud->settings, "x264_psy_trell");
518         result = g_strdup_printf("%g,%g", rd, trell);
519         return result;
520 }
521
522 static void
523 x264_opt_update(signal_user_data_t *ud, GtkWidget *widget)
524 {
525         gint jj;
526         const gchar *name = ghb_get_setting_key(widget);
527         gchar **opt_syns = NULL;
528         const gchar *def_val = NULL;
529         gint type;
530
531         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
532         {
533                 if (strcmp(name, x264_opt_map[jj].name) == 0)
534                 {
535                         // found the options that needs updating
536                         opt_syns = x264_opt_map[jj].opt_syns;
537                         def_val = x264_opt_map[jj].def_val;
538                         type = x264_opt_map[jj].type;
539                         break;
540                 }
541         }
542         if (opt_syns != NULL)
543         {
544                 GString *x264opts = g_string_new("");
545                 gchar *options;
546                 gchar **split = NULL;
547                 gint ii;
548                 gboolean foundit = FALSE;
549
550                 options = ghb_settings_get_string(ud->settings, "x264Option");
551                 if (options)
552                 {
553                         split = g_strsplit(options, ":", -1);
554                         g_free(options);
555                 }
556                 for (ii = 0; split && split[ii] != NULL; ii++)
557                 {
558                         gint syn;
559                         gchar *val = NULL;
560                         gchar *pos = strchr(split[ii], '=');
561                         if (pos != NULL)
562                         {
563                                 val = pos + 1;
564                                 *pos = 0;
565                         }
566                         syn = find_syn_match(split[ii], opt_syns);
567                         if (syn >= 0)
568                         { // Updating this option
569                                 gchar *val;
570                                 foundit = TRUE;
571                                 if (type == X264_OPT_DEBLOCK)
572                                         val = get_deblock_val(ud);
573                                 else if (type == X264_OPT_PSY)
574                                         val = get_psy_val(ud);
575                                 else
576                                 {
577                                         GValue *gval;
578                                         gval = ghb_widget_value(widget);
579                                         if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN)
580                                         {
581                                                 if (ghb_value_boolean(gval))
582                                                         val = g_strdup("1");
583                                                 else
584                                                         val = g_strdup("0");
585                                         }
586                                         else
587                                         {
588                                                 val = ghb_widget_string(widget);
589                                         }
590                                         ghb_value_free(gval);
591                                 }
592                                 if (strcmp(def_val, val) != 0)
593                                 {
594                                         g_string_append_printf(x264opts, "%s=%s:", opt_syns[syn], val);
595                                 }
596                                 g_free(val);
597                         }
598                         else if (val != NULL)
599                                 g_string_append_printf(x264opts, "%s=%s:", split[ii], val);
600                         else
601                                 g_string_append_printf(x264opts, "%s:", split[ii]);
602
603                 }
604                 if (split) g_strfreev(split);
605                 if (!foundit)
606                 {
607                         gchar *val;
608                         if (type == X264_OPT_DEBLOCK)
609                                 val = get_deblock_val(ud);
610                         else if (type == X264_OPT_PSY)
611                                 val = get_psy_val(ud);
612                         else
613                         {
614                                 GValue *gval;
615                                 gval = ghb_widget_value(widget);
616                                 if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN)
617                                 {
618                                         if (ghb_value_boolean(gval))
619                                                 val = g_strdup("1");
620                                         else
621                                                 val = g_strdup("0");
622                                 }
623                                 else
624                                 {
625                                         val = ghb_widget_string(widget);
626                                 }
627                                 ghb_value_free(gval);
628                         }
629                         if (strcmp(def_val, val) != 0)
630                         {
631                                 g_string_append_printf(x264opts, "%s=%s:", opt_syns[0], val);
632                         }
633                         g_free(val);
634                 }
635                 // Update the options value
636                 // strip the trailing ":"
637                 gchar *result;
638                 gint len;
639                 result = g_string_free(x264opts, FALSE);
640                 len = strlen(result);
641                 if (len > 0) result[len - 1] = 0;
642                 gchar *sopts;
643                 sopts = sanitize_x264opts(ud, result);
644                 ghb_ui_update(ud, "x264Option", ghb_string_value(sopts));
645                 ghb_x264_parse_options(ud, sopts);
646                 g_free(sopts);
647                 g_free(result);
648         }
649 }
650
651 static gint
652 x264_find_opt(gchar **opts, gchar **opt_syns)
653 {
654         gint ii;
655         for (ii = 0; opts[ii] != NULL; ii++)
656         {
657                 gchar *opt;
658                 opt = g_strdup(opts[ii]);
659                 gchar *pos = strchr(opt, '=');
660                 if (pos != NULL)
661                 {
662                         *pos = 0;
663                 }
664                 if (find_syn_match(opt, opt_syns) >= 0)
665                 {
666                         g_free(opt);
667                         return ii;
668                 }
669                 g_free(opt);
670         }
671         return -1;
672 }
673
674 static void
675 x264_remove_opt(gchar **opts, gchar **opt_syns)
676 {
677         gint ii;
678         for (ii = 0; opts[ii] != NULL; ii++)
679         {
680                 gchar *opt;
681                 opt = g_strdup(opts[ii]);
682                 gchar *pos = strchr(opt, '=');
683                 if (pos != NULL)
684                 {
685                         *pos = 0;
686                 }
687                 if (find_syn_match(opt, opt_syns) >= 0)
688                 {
689                         // Mark as deleted
690                         opts[ii][0] = 0;
691                 }
692                 g_free(opt);
693         }
694 }
695
696 static gchar*
697 x264_lookup_value(gchar **opts, gchar **opt_syns)
698 {
699         gchar *ret = NULL;
700         gint pos;
701
702         const gchar *def_val = x264_opt_get_default(opt_syns[0]);
703
704         pos = x264_find_opt(opts, opt_syns);
705         if (pos >= 0)
706         {
707                 gchar *cpos = strchr(opts[pos], '=');
708                 if (cpos != NULL)
709                 {
710                         ret = g_strdup(cpos+1);
711                 }
712                 else
713                 {
714                         ret = g_strdup("");
715                 }
716         }
717         else if (def_val != NULL)
718         {
719                 ret = g_strdup(def_val);
720         }
721         return ret;
722 }
723
724 gint
725 ghb_lookup_badapt(const gchar *options)
726 {
727         gint ret = 0;
728         gchar *result;
729         gchar **split;
730         
731         if (options == NULL)
732                 options = "";
733
734         split = g_strsplit(options, ":", -1);
735
736         result = x264_lookup_value(split, x264_badapt_syns);
737         g_strfreev(split);
738         if (result != NULL)
739         {
740                 ret = g_strtod(result, NULL);
741                 g_free(result);
742         }
743         return ret;
744 }
745
746 gint
747 ghb_lookup_aqmode(const gchar *options)
748 {
749         gint ret = 0;
750         gchar *result;
751         gchar **split;
752         
753         if (options == NULL)
754                 options = "";
755
756         split = g_strsplit(options, ":", -1);
757
758         result = x264_lookup_value(split, x264_aqmode_syns);
759         g_strfreev(split);
760         if (result != NULL)
761         {
762                 ret = g_strtod(result, NULL);
763                 g_free(result);
764         }
765         return ret;
766 }
767
768 gint
769 ghb_lookup_bframes(const gchar *options)
770 {
771         gint ret = 0;
772         gchar *result;
773         gchar **split;
774         
775         if (options == NULL)
776                 options = "";
777
778         split = g_strsplit(options, ":", -1);
779
780         result = x264_lookup_value(split, x264_bframes_syns);
781         g_strfreev(split);
782         if (result != NULL)
783         {
784                 ret = g_strtod(result, NULL);
785                 g_free(result);
786         }
787         return ret;
788 }
789
790 gint
791 ghb_lookup_mbtree(const gchar *options)
792 {
793         gint ret = ghb_lookup_bframes(options) != 0;
794         gchar *result;
795         gchar **split;
796         
797         if (options == NULL)
798                 options = "";
799
800         split = g_strsplit(options, ":", -1);
801
802         result = x264_lookup_value(split, x264_mbtree_syns);
803         g_strfreev(split);
804         if (result != NULL)
805         {
806                 ret = g_strtod(result, NULL);
807                 g_free(result);
808         }
809         return ret;
810 }
811
812 // Construct the x264 options string
813 // The result is allocated, so someone must free it at some point.
814 static gchar*
815 sanitize_x264opts(signal_user_data_t *ud, const gchar *options)
816 {
817         GString *x264opts = g_string_new("");
818         gchar **split = g_strsplit(options, ":", -1);
819         gint ii;
820
821         // Fix up option dependencies
822         gint subme = ghb_settings_combo_int(ud->settings, "x264_subme");
823         if (subme < 6)
824         {
825                 x264_remove_opt(split, x264_psy_syns);
826         }
827         gint trell = ghb_settings_combo_int(ud->settings, "x264_trellis");
828         if (subme == 10)
829         {
830                 gint aqmode = ghb_lookup_aqmode(options);
831                 if (trell != 2 || aqmode == 0)
832                 {
833                         gint pos = x264_find_opt(split, x264_subme_syns);
834                         g_free(split[pos]);
835                         split[pos] = g_strdup_printf("subme=9");
836                 }
837         }
838         if (trell < 1)
839         {
840                 gint psy;
841                 gdouble psy_rd = 0., psy_trell;
842
843                 psy = x264_find_opt(split, x264_psy_syns);
844                 if (psy >= 0)
845                 {
846                         gchar *pos = strchr(split[psy], '=');
847                         if (pos != NULL)
848                         {
849                                 x264_parse_psy(pos+1, &psy_rd, &psy_trell);
850                         }
851                         g_free(split[psy]);
852                         split[psy] = g_strdup_printf("psy-rd=%g,0", psy_rd);
853                 }
854         }
855         gint refs = ghb_settings_get_int(ud->settings, "x264_refs");
856         if (refs <= 1)
857         {
858                 x264_remove_opt(split, x264_mixed_syns);
859         }
860         gint bframes = ghb_settings_get_int(ud->settings, "x264_bframes");
861         if (bframes == 0)
862         {
863                 x264_remove_opt(split, x264_weightb_syns);
864                 x264_remove_opt(split, x264_direct_syns);
865                 x264_remove_opt(split, x264_badapt_syns);
866         }
867         if (bframes <= 1)
868         {
869                 x264_remove_opt(split, x264_bpyramid_syns);
870         }
871         if (!ghb_settings_get_boolean(ud->settings, "x264_cabac"))
872         {
873                 x264_remove_opt(split, x264_trellis_syns);
874         }
875         // Remove entries that match the defaults
876         for (ii = 0; split[ii] != NULL; ii++)
877         {
878                 gchar *val = NULL;
879                 gchar *opt = g_strdup(split[ii]);
880                 gchar *pos = strchr(opt, '=');
881                 if (pos != NULL)
882                 {
883                         val = pos + 1;
884                         *pos = 0;
885                 }
886                 else
887                 {
888                         val = "1";
889                 }
890                 const gchar *def_val;
891                 def_val = x264_opt_get_default(opt);
892                 if (strcmp(val, def_val) == 0)
893                 {
894                         // Matches the default, so remove it
895                         split[ii][0] = 0;
896                 }
897                 g_free(opt);
898         }
899         for (ii = 0; split[ii] != NULL; ii++)
900         {
901                 if (split[ii][0] != 0)
902                         g_string_append_printf(x264opts, "%s:", split[ii]);
903         }
904         g_strfreev(split);
905         // strip the trailing ":"
906         gchar *result;
907         gint len;
908         result = g_string_free(x264opts, FALSE);
909         len = strlen(result);
910         if (len > 0) result[len - 1] = 0;
911         return result;
912 }
913