OSDN Git Service

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