OSDN Git Service

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