OSDN Git Service

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