OSDN Git Service

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