OSDN Git Service

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