OSDN Git Service

4167a160f08315201a3b300c54072d9f96e999ca
[handbrake-jp/handbrake-jp-git.git] / gtk / src / settings.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * settings.c
4  * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
5  * 
6  * settings.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 <fcntl.h>
15 #include <unistd.h>
16 #include <glib.h>
17 #include <glib/gstdio.h>
18 #include <string.h>
19 #include <gtk/gtk.h>
20 #include "settings.h"
21 #include "hb-backend.h"
22 #include "values.h"
23
24 void dump_settings(GValue *settings);
25 void ghb_pref_audio_init(signal_user_data_t *ud);
26
27 GObject*
28 debug_get_object(GtkBuilder* b, const gchar *n)
29 {
30         g_message("name %s\n", n);
31         return gtk_builder_get_object(b, n);
32 }
33
34 GValue*
35 ghb_settings_new()
36 {
37         return ghb_dict_value_new();
38 }
39
40 void
41 ghb_settings_set_value(
42         GValue *settings, 
43         const gchar *key, 
44         const GValue *value)
45 {
46         if (key == NULL || value == NULL)
47                 return;
48         ghb_dict_insert(settings, g_strdup(key), ghb_value_dup(value));
49 }
50
51 void
52 ghb_settings_take_value(GValue *settings, const gchar *key, GValue *value)
53 {
54         ghb_dict_insert(settings, g_strdup(key), value);
55 }
56
57 void
58 ghb_settings_set_string(
59         GValue *settings, 
60         const gchar *key, 
61         const gchar *sval)
62 {
63         GValue *value;
64         value = ghb_string_value_new(sval);
65         ghb_dict_insert(settings, g_strdup(key), value);
66 }
67
68 void
69 ghb_settings_set_double(GValue *settings, const gchar *key, gdouble dval)
70 {
71         GValue *value;
72         value = ghb_double_value_new(dval);
73         ghb_dict_insert(settings, g_strdup(key), value);
74 }
75
76 void
77 ghb_settings_set_int64(GValue *settings, const gchar *key, gint64 ival)
78 {
79         GValue *value;
80         value = ghb_int64_value_new(ival);
81         ghb_dict_insert(settings, g_strdup(key), value);
82 }
83
84 void
85 ghb_settings_set_int(GValue *settings, const gchar *key, gint ival)
86 {
87         GValue *value;
88         value = ghb_int64_value_new((gint64)ival);
89         ghb_dict_insert(settings, g_strdup(key), value);
90 }
91
92 void
93 ghb_settings_set_boolean(GValue *settings, const gchar *key, gboolean bval)
94 {
95         GValue *value;
96         value = ghb_boolean_value_new(bval);
97         ghb_dict_insert(settings, g_strdup(key), value);
98 }
99
100 void
101 ghb_settings_set_combo(
102         GValue *settings, 
103         const gchar *key, 
104         gint index,
105         const gchar *option,
106         const gchar *shortOpt,
107         const gchar *svalue,
108         gint ivalue)
109 {
110         GValue *value;
111         value = ghb_combo_value_new(index, option, shortOpt, svalue, ivalue);
112         ghb_dict_insert(settings, g_strdup(key), value);
113 }
114
115 GValue*
116 ghb_settings_get_value(GValue *settings, const gchar *key)
117 {
118         GValue *value;
119         value = ghb_dict_lookup(settings, key);
120         if (value == NULL)
121                 g_warning("returning null (%s)", key);
122         return value;
123 }
124
125 gboolean
126 ghb_settings_get_boolean(GValue *settings, const gchar *key)
127 {
128         const GValue* value;
129         value = ghb_settings_get_value(settings, key);
130         if (value == NULL) return FALSE;
131         return ghb_value_boolean(value);
132 }
133
134 gint64
135 ghb_settings_get_int64(GValue *settings, const gchar *key)
136 {
137         const GValue* value;
138         value = ghb_settings_get_value(settings, key);
139         if (value == NULL) return 0;
140         return ghb_value_int64(value);
141 }
142
143 gint
144 ghb_settings_get_int(GValue *settings, const gchar *key)
145 {
146         const GValue* value;
147         value = ghb_settings_get_value(settings, key);
148         if (value == NULL) return 0;
149         return ghb_value_int(value);
150 }
151
152 gdouble
153 ghb_settings_get_double(GValue *settings, const gchar *key)
154 {
155         const GValue* value;
156         value = ghb_settings_get_value(settings, key);
157         if (value == NULL) return 0;
158         return ghb_value_double(value);
159 }
160
161 gchar*
162 ghb_settings_get_string(GValue *settings, const gchar *key)
163 {
164         const GValue* value;
165         value = ghb_settings_get_value(settings, key);
166         if (value == NULL) return g_strdup("");
167         return ghb_value_string(value);
168 }
169
170 gint
171 ghb_settings_get_combo_index(GValue *settings, const gchar *key)
172 {
173         const GValue* value;
174         value = ghb_settings_get_value(settings, key);
175         if (value == NULL) return 0;
176         ghb_combodata_t *cd;
177         if (G_VALUE_TYPE(value) != ghb_combodata_get_type())
178                 return 0;
179         cd = g_value_get_boxed(value);
180         return cd->index;
181 }
182
183 gchar*
184 ghb_settings_get_combo_option(GValue *settings, const gchar *key)
185 {
186         const GValue* value;
187         value = ghb_settings_get_value(settings, key);
188         if (value == NULL) return g_strdup("");
189         ghb_combodata_t *cd;
190         if (G_VALUE_TYPE(value) != ghb_combodata_get_type())
191                 return g_strdup("");
192         cd = g_value_get_boxed(value);
193         return g_strdup(cd->option);
194 }
195
196 // Map widget names to setting keys
197 // Widgets that map to settings have names
198 // of this format: s_<setting key>
199 static const gchar*
200 get_setting_key(GtkWidget *widget)
201 {
202         const gchar *name;
203         
204         g_debug("get_setting_key ()\n");
205         if (widget == NULL) return NULL;
206         if (GTK_IS_ACTION(widget))
207                 name = gtk_action_get_name(GTK_ACTION(widget));
208         else
209                 name = gtk_widget_get_name(widget);
210                 
211         if (name == NULL)
212         {
213                 // Bad widget pointer?  Should never happen.
214                 g_debug("Bad widget\n");
215                 return NULL;
216         }
217         return name;
218 }
219
220 GValue*
221 ghb_widget_value(GtkWidget *widget)
222 {
223         GValue *value = NULL;
224         const gchar *name;
225         GType type;
226         
227         if (widget == NULL)
228         {
229                 g_debug("NULL widget\n");
230                 return NULL;
231         }
232
233         type = GTK_WIDGET_TYPE(widget);
234         if (GTK_IS_ACTION(widget))
235                 name = gtk_action_get_name(GTK_ACTION(widget));
236         else
237                 name = gtk_widget_get_name(widget);
238         g_debug("ghb_widget_value widget (%s)\n", name);
239         if (type == GTK_TYPE_ENTRY)
240         {
241                 const gchar *str = gtk_entry_get_text(GTK_ENTRY(widget));
242                 value = ghb_string_value_new(str);
243         }
244         else if (type == GTK_TYPE_RADIO_BUTTON)
245         {
246                 g_debug("\tradio_button");
247                 gboolean bval;
248                 bval = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
249                 value = ghb_boolean_value_new(bval);
250         }
251         else if (type == GTK_TYPE_CHECK_BUTTON)
252         {
253                 g_debug("\tcheck_button");
254                 gboolean bval;
255                 bval = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
256                 value = ghb_boolean_value_new(bval);
257         }
258         else if (type == GTK_TYPE_TOGGLE_ACTION)
259         {
260                 g_debug("\ttoggle action");
261                 gboolean bval;
262                 bval = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(widget));
263                 value = ghb_boolean_value_new(bval);
264         }
265         else if (type == GTK_TYPE_CHECK_MENU_ITEM)
266         {
267                 g_debug("\tcheck_menu_item");
268                 gboolean bval;
269                 bval = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
270                 value = ghb_boolean_value_new(bval);
271         }
272         else if (type == GTK_TYPE_COMBO_BOX)
273         {
274                 g_debug("\tcombo_box");
275                 GtkTreeModel *store;
276                 GtkTreeIter iter;
277                 gchar *shortOpt, *option, *svalue;
278                 gint index, ivalue;
279
280                 index = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
281                 store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
282                 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
283                 {
284                         gtk_tree_model_get(store, &iter, 0, &option, 2, &shortOpt, 
285                                                            3, &ivalue, 4, &svalue, -1);
286                         value = ghb_combo_value_new(index, option, shortOpt, 
287                                                                                 svalue, ivalue);
288                         g_free(option);
289                         g_free(shortOpt);
290                         g_free(svalue);
291                 }
292                 else
293                 {
294                         value = ghb_combo_value_new(-1, "", "", "", 0);
295                 }
296                 g_debug("\tdone");
297         }
298         else if (type == GTK_TYPE_COMBO_BOX_ENTRY)
299         {
300                 GtkTreeModel *store;
301                 GtkTreeIter iter;
302                 gchar *shortOpt, *option, *svalue;
303                 gint index, ivalue;
304
305                 index = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
306                 store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
307                 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
308                 {
309                         gtk_tree_model_get(store, &iter, 0, &option, 2, &shortOpt, 
310                                                            3, &ivalue, 4, &svalue, -1);
311                         value = ghb_combo_value_new(index, option, shortOpt, 
312                                                                                 svalue, ivalue);
313                 }
314                 else
315                 {
316                         const gchar *str;
317                         str = gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget));
318                         if (str == NULL) str = "";
319                         value = ghb_combo_value_new(-1, str, str, str, -1);
320                 }
321         }
322         else if (type == GTK_TYPE_SPIN_BUTTON)
323         {
324                 gint ival;
325                 ival = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
326                 value = ghb_int64_value_new(ival);
327         }
328         else if (type == GTK_TYPE_HSCALE)
329         {
330                 gdouble dval;
331                 dval = gtk_range_get_value(GTK_RANGE(widget));
332                 value = ghb_double_value_new(dval);
333         }
334         else if (type == GTK_TYPE_TEXT_VIEW)
335         {
336                 GtkTextBuffer *buffer;
337                 GtkTextIter start, end;
338                 gchar *str;
339
340                 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
341                 gtk_text_buffer_get_bounds(buffer, &start, &end);
342                 str = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
343                 value = ghb_string_value_new(str);
344                 g_free(str);
345         }
346         else if (type == GTK_TYPE_LABEL)
347         {
348                 const gchar *str;
349                 str = gtk_label_get_text (GTK_LABEL(widget));
350                 value = ghb_string_value_new(str);
351         }
352         else
353         {
354                 g_debug("Attempt to set unknown widget type: %s\n", name);
355                 g_free(value);
356                 value = NULL;
357         }
358         return value;
359 }
360
361 gchar*
362 ghb_widget_string(GtkWidget *widget)
363 {
364         GValue *value;
365         gchar *sval;
366         
367         value = ghb_widget_value(widget);
368         sval = ghb_value_string(value);
369         ghb_value_free(value);
370         return sval;
371 }
372
373 gdouble
374 ghb_widget_double(GtkWidget *widget)
375 {
376         GValue *value;
377         gdouble dval;
378         
379         value = ghb_widget_value(widget);
380         dval = ghb_value_double(value);
381         ghb_value_free(value);
382         return dval;
383 }
384
385 gint64
386 ghb_widget_int64(GtkWidget *widget)
387 {
388         GValue *value;
389         gint64 ival;
390         
391         value = ghb_widget_value(widget);
392         ival = ghb_value_int64(value);
393         ghb_value_free(value);
394         return ival;
395 }
396
397 gint
398 ghb_widget_int(GtkWidget *widget)
399 {
400         GValue *value;
401         gint ival;
402         
403         value = ghb_widget_value(widget);
404         ival = (gint)ghb_value_int64(value);
405         ghb_value_free(value);
406         return ival;
407 }
408
409 gint
410 ghb_widget_index(GtkWidget *widget)
411 {
412         GValue *value;
413         gint index = 0;
414         
415         value = ghb_widget_value(widget);
416         if (value == NULL) return 0;
417         ghb_combodata_t *cd;
418         if (G_VALUE_TYPE(value) != ghb_combodata_get_type())
419         {
420                 ghb_value_free(value);
421                 return 0;
422         }
423         cd = g_value_get_boxed(value);
424         index = cd->index;
425         ghb_value_free(value);
426         return index;
427 }
428
429 void
430 ghb_widget_to_setting(GValue *settings, GtkWidget *widget)
431 {
432         const gchar *key = NULL;
433         GValue *value;
434         
435         if (widget == NULL) return;
436         g_debug("ghb_widget_to_setting");
437         // Find corresponding setting
438         key = get_setting_key(widget);
439         if (key == NULL) return;
440         value = ghb_widget_value(widget);
441         if (value != NULL)
442         {
443                 ghb_settings_take_value(settings, key, value);
444         }
445         else
446         {
447                 g_debug("No value found for %s\n", key);
448         }
449 }
450
451 static void
452 update_widget(GtkWidget *widget, const GValue *value)
453 {
454         GType type;
455         gchar *str;
456         gint ival;
457         gdouble dval;
458
459         type = G_VALUE_TYPE(value);
460         if (type == ghb_array_get_type() || type == ghb_dict_get_type())
461                 return;
462         if (value == NULL) return;
463         str = ghb_value_string(value);
464         ival = ghb_value_int(value);
465         dval = ghb_value_double(value);
466         type = GTK_OBJECT_TYPE(widget);
467         if (type == GTK_TYPE_ENTRY)
468         {
469                 g_debug("entry");
470                 gtk_entry_set_text((GtkEntry*)widget, str);
471         }
472         else if (type == GTK_TYPE_RADIO_BUTTON)
473         {
474                 g_debug("radio button");
475                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), ival);
476         }
477         else if (type == GTK_TYPE_CHECK_BUTTON)
478         {
479                 g_debug("check button");
480                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), ival);
481         }
482         else if (type == GTK_TYPE_TOGGLE_ACTION)
483         {
484                 g_debug("toggle action");
485                 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(widget), ival);
486         }
487         else if (type == GTK_TYPE_CHECK_MENU_ITEM)
488         {
489                 g_debug("check menu item");
490                 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), ival);
491         }
492         else if (type == GTK_TYPE_COMBO_BOX)
493         {
494                 GtkTreeModel *store;
495                 GtkTreeIter iter;
496                 gchar *shortOpt;
497                 gint ivalue;
498                 gboolean foundit = FALSE;
499
500                 g_debug("combo (%s)", str);
501                 store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
502                 if (gtk_tree_model_get_iter_first (store, &iter))
503                 {
504                         do
505                         {
506                                 gtk_tree_model_get(store, &iter, 2, &shortOpt, -1);
507                                 if (strcmp(shortOpt, str) == 0)
508                                 {
509                                         gtk_combo_box_set_active_iter (
510                                                 GTK_COMBO_BOX(widget), &iter);
511                                         g_free(shortOpt);
512                                         foundit = TRUE;
513                                         break;
514                                 }
515                                 g_free(shortOpt);
516                         } while (gtk_tree_model_iter_next (store, &iter));
517                 }
518                 if (!foundit && gtk_tree_model_get_iter_first (store, &iter))
519                 {
520                         do
521                         {
522                                 gtk_tree_model_get(store, &iter, 3, &ivalue, -1);
523                                 if (ivalue == ival)
524                                 {
525                                         gtk_combo_box_set_active_iter (
526                                                 GTK_COMBO_BOX(widget), &iter);
527                                         foundit = TRUE;
528                                         break;
529                                 }
530                         } while (gtk_tree_model_iter_next (store, &iter));
531                 }
532                 if (!foundit)
533                 {
534                         gtk_combo_box_set_active (GTK_COMBO_BOX(widget), 0);
535                 }
536         }
537         else if (type == GTK_TYPE_COMBO_BOX_ENTRY)
538         {
539                 GtkTreeModel *store;
540                 GtkTreeIter iter;
541                 gchar *shortOpt;
542                 gint ivalue;
543                 gboolean foundit = FALSE;
544
545                 g_debug("GTK_COMBO_BOX_ENTRY");
546                 store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
547                 if (gtk_tree_model_get_iter_first (store, &iter))
548                 {
549                         do
550                         {
551                                 gtk_tree_model_get(store, &iter, 2, &shortOpt, -1);
552                                 if (strcmp(shortOpt, str) == 0)
553                                 {
554                                         gtk_combo_box_set_active_iter (
555                                                 GTK_COMBO_BOX(widget), &iter);
556                                         g_free(shortOpt);
557                                         foundit = TRUE;
558                                         break;
559                                 }
560                                 g_free(shortOpt);
561                         } while (gtk_tree_model_iter_next (store, &iter));
562                 }
563                 if (!foundit && gtk_tree_model_get_iter_first (store, &iter))
564                 {
565                         do
566                         {
567                                 gtk_tree_model_get(store, &iter, 3, &ivalue, -1);
568                                 if (ivalue == ival)
569                                 {
570                                         gtk_combo_box_set_active_iter (
571                                                 GTK_COMBO_BOX(widget), &iter);
572                                         foundit = TRUE;
573                                         break;
574                                 }
575                         } while (gtk_tree_model_iter_next (store, &iter));
576                 }
577                 if (!foundit)
578                 {
579                         GtkEntry *entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(widget)));
580                         if (entry)
581                         {
582                                 gtk_entry_set_text (entry, str);
583                         }
584                 }
585         }
586         else if (type == GTK_TYPE_SPIN_BUTTON)
587         {
588                 g_debug("spin (%s)", str);
589                 gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), dval);
590         }
591         else if (type == GTK_TYPE_HSCALE)
592         {
593                 g_debug("hscale");
594                 gtk_range_set_value(GTK_RANGE(widget), dval);
595         }
596         else if (type == GTK_TYPE_TEXT_VIEW)
597         {
598                 g_debug("textview (%s)", str);
599                 GtkTextBuffer *buffer = gtk_text_view_get_buffer(
600                                                                                                 GTK_TEXT_VIEW(widget));
601                 gtk_text_buffer_set_text (buffer, str, -1);
602         }
603         else
604         {
605                 g_debug("Attempt to set unknown widget type");
606         }
607         g_free(str);
608 }
609
610 int
611 ghb_ui_update(signal_user_data_t *ud, const gchar *name, const GValue *value)
612 {
613         GObject *object;
614
615         if (name == NULL || value == NULL)
616                 return 0;
617         object = GHB_OBJECT(ud->builder, name);
618         if (object == NULL)
619         {
620                 g_debug("Failed to find widget for key: %s\n", name);
621                 return -1;
622         }
623         update_widget((GtkWidget*)object, value);
624         // Its possible the value hasn't changed. Since settings are only
625         // updated when the value changes, I'm initializing settings here as well.
626         ghb_widget_to_setting(ud->settings, (GtkWidget*)object);
627         return 0;
628 }
629
630 enum
631 {
632         X264_OPT_DEBLOCK,
633         X264_OPT_INT,
634         X264_OPT_COMBO,
635         X264_OPT_BOOL,
636 };
637
638 struct x264_opt_map_s
639 {
640         gchar **opt_syns;
641         gchar *name;
642         gchar *def_val;
643         gint type;
644         gboolean found;
645 };
646
647 static gchar *x264_ref_syns[] = {"ref", "frameref", NULL};
648 static gchar *x264_mixed_syns[] = {"mixed-refs", "mixed_refs", NULL};
649 static gchar *x264_bframes_syns[] = {"bframes", NULL};
650 static gchar *x264_direct_syns[] = 
651         {"direct", "direct-pred", "direct_pred", NULL};
652 static gchar *x264_weightb_syns[] = {"weightb", "weight-b", "weight_b", NULL};
653 static gchar *x264_brdo_syns[] = {"brdo", "b-rdo", "b_rdo", NULL};
654 static gchar *x264_bime_syns[] = {"bime", NULL};
655 static gchar *x264_bpyramid_syns[] = {"b-pyramid", "b_pyramid", NULL};
656 static gchar *x264_me_syns[] = {"me", NULL};
657 static gchar *x264_merange_syns[] = {"merange", "me-range", "me_range", NULL};
658 static gchar *x264_subme_syns[] = {"subme", "subq", NULL};
659 static gchar *x264_analyse_syns[] = {"analyse", "partitions", NULL};
660 static gchar *x264_8x8dct_syns[] = {"8x8dct", NULL};
661 static gchar *x264_deblock_syns[] = {"deblock", "filter", NULL};
662 static gchar *x264_trellis_syns[] = {"trellis", NULL};
663 static gchar *x264_pskip_syns[] = {"no-fast-pskip", "no_fast_pskip", NULL};
664 static gchar *x264_decimate_syns[] = 
665         {"no-dct-decimate", "no_dct_decimate", NULL};
666 static gchar *x264_cabac_syns[] = {"cabac", NULL};
667
668 static gint
669 find_syn_match(const gchar *opt, gchar **syns)
670 {
671         gint ii;
672         for (ii = 0; syns[ii] != NULL; ii++)
673         {
674                 if (strcmp(opt, syns[ii]) == 0)
675                         return ii;
676         }
677         return -1;
678 }
679
680 struct x264_opt_map_s x264_opt_map[] =
681 {
682         {x264_ref_syns, "x264_refs", "1", X264_OPT_INT},
683         {x264_mixed_syns, "x264_mixed_refs", "0", X264_OPT_BOOL},
684         {x264_bframes_syns, "x264_bframes", "0", X264_OPT_INT},
685         {x264_direct_syns, "x264_direct", "spatial", X264_OPT_COMBO},
686         {x264_weightb_syns, "x264_weighted_bframes", "0", X264_OPT_BOOL},
687         {x264_brdo_syns, "x264_brdo", "0", X264_OPT_BOOL},
688         {x264_bime_syns, "x264_bime", "0", X264_OPT_BOOL},
689         {x264_bpyramid_syns, "x264_bpyramid", "0", X264_OPT_BOOL},
690         {x264_me_syns, "x264_me", "hex", X264_OPT_COMBO},
691         {x264_merange_syns, "x264_merange", "16", X264_OPT_INT},
692         {x264_subme_syns, "x264_subme", "4", X264_OPT_COMBO},
693         {x264_analyse_syns, "x264_analyse", "some", X264_OPT_COMBO},
694         {x264_8x8dct_syns, "x264_8x8dct", "0", X264_OPT_BOOL},
695         {x264_deblock_syns, "x264_deblock_alpha", "0,0", X264_OPT_DEBLOCK},
696         {x264_deblock_syns, "x264_deblock_beta", "0,0", X264_OPT_DEBLOCK},
697         {x264_trellis_syns, "x264_trellis", "0", X264_OPT_COMBO},
698         {x264_pskip_syns, "x264_no_fast_pskip", "0", X264_OPT_BOOL},
699         {x264_decimate_syns, "x264_no_dct_decimate", "0", X264_OPT_BOOL},
700         {x264_cabac_syns, "x264_cabac", "1", X264_OPT_BOOL},
701 };
702 #define X264_OPT_MAP_SIZE (sizeof(x264_opt_map)/sizeof(struct x264_opt_map_s))
703
704 static const gchar*
705 x264_opt_get_default(const gchar *opt)
706 {
707         gint jj;
708         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
709         {
710                 if (find_syn_match(opt, x264_opt_map[jj].opt_syns) >= 0)
711                 {
712                         return x264_opt_map[jj].def_val;
713                 }
714         }
715         return "";
716 }
717
718 static void
719 x264_update_int(signal_user_data_t *ud, const gchar *name, const gchar *val)
720 {
721         gint ival;
722
723         if (val == NULL) return;
724         ival = g_strtod (val, NULL);
725         ghb_ui_update(ud, name, ghb_int64_value(ival));
726 }
727
728 static gchar *true_str[] =
729 {
730         "true",
731         "yes",
732         "1",
733         NULL
734 };
735
736 static gboolean 
737 str_is_true(const gchar *str)
738 {
739         gint ii;
740         for (ii = 0; true_str[ii]; ii++)
741         {
742                 if (g_ascii_strcasecmp(str, true_str[ii]) == 0)
743                         return TRUE;
744         }
745         return FALSE;
746 }
747
748 static void
749 x264_update_bool(signal_user_data_t *ud, const gchar *name, const gchar *val)
750 {
751         if (val == NULL)
752                 ghb_ui_update(ud, name, ghb_boolean_value(1));
753         else
754                 ghb_ui_update(ud, name, ghb_boolean_value(str_is_true(val)));
755 }
756
757 static void
758 x264_update_combo(signal_user_data_t *ud, const gchar *name, const gchar *val)
759 {
760         GtkTreeModel *store;
761         GtkTreeIter iter;
762         gchar *shortOpt;
763         gint ivalue;
764         gboolean foundit = FALSE;
765         GtkWidget *widget;
766
767         if (val == NULL) return;
768         widget = GHB_WIDGET(ud->builder, name);
769         if (widget == NULL)
770         {
771                 g_debug("Failed to find widget for key: %s\n", name);
772                 return;
773         }
774         store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
775         if (gtk_tree_model_get_iter_first (store, &iter))
776         {
777                 do
778                 {
779                         gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1);
780                         if (strcmp(shortOpt, val) == 0)
781                         {
782                                 gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
783                                 g_free(shortOpt);
784                                 foundit = TRUE;
785                                 break;
786                         }
787                         g_free(shortOpt);
788                 } while (gtk_tree_model_iter_next (store, &iter));
789         }
790         if (!foundit)
791         {
792                 if (gtk_tree_model_get_iter_first (store, &iter))
793                 {
794                         do
795                         {
796                                 gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1);
797                                 if (strcmp(shortOpt, "custom") == 0)
798                                 {
799                                         gtk_list_store_set(GTK_LIST_STORE(store), &iter, 4, val, -1);
800                                         gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
801                                         g_free(shortOpt);
802                                         foundit = TRUE;
803                                         break;
804                                 }
805                                 g_free(shortOpt);
806                         } while (gtk_tree_model_iter_next (store, &iter));
807                 }
808         }
809         // Its possible the value hasn't changed. Since settings are only
810         // updated when the value changes, I'm initializing settings here as well.
811         ghb_widget_to_setting(ud->settings, widget);
812 }
813
814 static void
815 x264_update_deblock(signal_user_data_t *ud, const gchar *xval)
816 {
817         gdouble avalue, bvalue;
818         gchar *end;
819         gchar *val;
820         gchar *bval = NULL;
821
822         if (xval == NULL) return;
823         val = g_strdup(xval);
824         bvalue = avalue = 0;
825         if (val != NULL) 
826         {
827                 gchar *pos = strchr(val, ',');
828                 if (pos != NULL)
829                 {
830                         bval = pos + 1;
831                         *pos = 0;
832                 }
833                 avalue = g_strtod (val, &end);
834                 if (bval != NULL)
835                 {
836                         bvalue = g_strtod (bval, &end);
837                 }
838         }
839         g_free(val);
840         ghb_ui_update(ud, "x264_deblock_alpha", ghb_int64_value(avalue));
841         ghb_ui_update(ud, "x264_deblock_beta", ghb_int64_value(bvalue));
842 }
843
844 void
845 ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options)
846 {
847         gchar **split = g_strsplit(options, ":", -1);
848         if (split == NULL) return;
849
850         gint ii;
851         gint jj;
852
853         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
854                 x264_opt_map[jj].found = FALSE;
855
856         for (ii = 0; split[ii] != NULL; ii++)
857         {
858                 gchar *val = NULL;
859                 gchar *pos = strchr(split[ii], '=');
860                 if (pos != NULL)
861                 {
862                         val = pos + 1;
863                         *pos = 0;
864                 }
865                 for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
866                 {
867                         if (find_syn_match(split[ii], x264_opt_map[jj].opt_syns) >= 0)
868                         {
869                                 x264_opt_map[jj].found = TRUE;
870                                 switch(x264_opt_map[jj].type)
871                                 {
872                                 case X264_OPT_INT:
873                                         x264_update_int(ud, x264_opt_map[jj].name, val);
874                                         break;
875                                 case X264_OPT_BOOL:
876                                         x264_update_bool(ud, x264_opt_map[jj].name, val);
877                                         break;
878                                 case X264_OPT_COMBO:
879                                         x264_update_combo(ud, x264_opt_map[jj].name, val);
880                                         break;
881                                 case X264_OPT_DEBLOCK:
882                                         // dirty little hack.  mark deblock_beta found as well
883                                         x264_opt_map[jj+1].found = TRUE;
884                                         x264_update_deblock(ud, val);
885                                         break;
886                                 }
887                                 break;
888                         }
889                 }
890         }
891         // For any options not found in the option string, set ui to
892         // default values
893         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
894         {
895                 if (!x264_opt_map[jj].found)
896                 {
897                         gchar *val = strdup(x264_opt_map[jj].def_val);
898                         switch(x264_opt_map[jj].type)
899                         {
900                         case X264_OPT_INT:
901                                 x264_update_int(ud, x264_opt_map[jj].name, val);
902                                 break;
903                         case X264_OPT_BOOL:
904                                 x264_update_bool(ud, x264_opt_map[jj].name, val);
905                                 break;
906                         case X264_OPT_COMBO:
907                                 x264_update_combo(ud, x264_opt_map[jj].name, val);
908                                 break;
909                         case X264_OPT_DEBLOCK:
910                                 x264_update_deblock(ud, val);
911                                 break;
912                         }
913                         x264_opt_map[jj].found = TRUE;
914                         g_free(val);
915                 }
916         }
917         g_strfreev(split);
918 }
919
920 gchar*
921 get_deblock_val(signal_user_data_t *ud)
922 {
923         gchar *alpha, *beta;
924         gchar *result;
925         alpha = ghb_settings_get_string(ud->settings, "x264_deblock_alpha");
926         beta = ghb_settings_get_string(ud->settings, "x264_deblock_beta");
927         result = g_strdup_printf("%s,%s", alpha, beta);
928         g_free(alpha);
929         g_free(beta);
930         return result;
931 }
932
933 void
934 ghb_x264_opt_update(signal_user_data_t *ud, GtkWidget *widget)
935 {
936         gint jj;
937         const gchar *name = gtk_widget_get_name(widget);
938         gchar **opt_syns = NULL;
939         const gchar *def_val = NULL;
940         gint type;
941
942         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
943         {
944                 if (strcmp(name, x264_opt_map[jj].name) == 0)
945                 {
946                         // found the options that needs updating
947                         opt_syns = x264_opt_map[jj].opt_syns;
948                         def_val = x264_opt_map[jj].def_val;
949                         type = x264_opt_map[jj].type;
950                         break;
951                 }
952         }
953         if (opt_syns != NULL)
954         {
955                 GString *x264opts = g_string_new("");
956                 gchar *options;
957                 gchar **split = NULL;
958                 gint ii;
959                 gboolean foundit = FALSE;
960
961                 options = ghb_settings_get_string(ud->settings, "x264_options");
962                 if (options)
963                 {
964                         split = g_strsplit(options, ":", -1);
965                         g_free(options);
966                 }
967                 for (ii = 0; split && split[ii] != NULL; ii++)
968                 {
969                         gint syn;
970                         gchar *val = NULL;
971                         gchar *pos = strchr(split[ii], '=');
972                         if (pos != NULL)
973                         {
974                                 val = pos + 1;
975                                 *pos = 0;
976                         }
977                         syn = find_syn_match(split[ii], opt_syns);
978                         if (syn >= 0)
979                         { // Updating this option
980                                 gchar *val;
981                                 foundit = TRUE;
982                                 if (type == X264_OPT_DEBLOCK)
983                                         val = get_deblock_val(ud);
984                                 else
985                                 {
986                                         GValue *gval;
987                                         gval = ghb_widget_value(widget);
988                                         if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN)
989                                         {
990                                                 if (ghb_value_boolean(gval))
991                                                         val = g_strdup("1");
992                                                 else
993                                                         val = g_strdup("0");
994                                         }
995                                         else
996                                         {
997                                                 val = ghb_widget_string(widget);
998                                         }
999                                         ghb_value_free(gval);
1000                                 }
1001                                 if (strcmp(def_val, val) != 0)
1002                                 {
1003                                         g_string_append_printf(x264opts, "%s=%s:", opt_syns[syn], val);
1004                                 }
1005                                 g_free(val);
1006                         }
1007                         else if (val != NULL)
1008                                 g_string_append_printf(x264opts, "%s=%s:", split[ii], val);
1009                         else
1010                                 g_string_append_printf(x264opts, "%s:", split[ii]);
1011
1012                 }
1013                 if (split) g_strfreev(split);
1014                 if (!foundit)
1015                 {
1016                         gchar *val;
1017                         if (type == X264_OPT_DEBLOCK)
1018                                 val = get_deblock_val(ud);
1019                         else
1020                         {
1021                                 GValue *gval;
1022                                 gval = ghb_widget_value(widget);
1023                                 if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN)
1024                                 {
1025                                         if (ghb_value_boolean(gval))
1026                                                 val = g_strdup("1");
1027                                         else
1028                                                 val = g_strdup("0");
1029                                 }
1030                                 else
1031                                 {
1032                                         val = ghb_widget_string(widget);
1033                                 }
1034                                 ghb_value_free(gval);
1035                         }
1036                         if (strcmp(def_val, val) != 0)
1037                         {
1038                                 g_string_append_printf(x264opts, "%s=%s:", opt_syns[0], val);
1039                         }
1040                         g_free(val);
1041                 }
1042                 // Update the options value
1043                 // strip the trailing ":"
1044                 gchar *result;
1045                 gint len;
1046                 result = g_string_free(x264opts, FALSE);
1047                 len = strlen(result);
1048                 if (len > 0) result[len - 1] = 0;
1049                 gchar *sopts;
1050                 sopts = ghb_sanitize_x264opts(ud, result);
1051                 ghb_ui_update(ud, "x264_options", ghb_string_value(sopts));
1052                 ghb_x264_parse_options(ud, sopts);
1053                 g_free(sopts);
1054                 g_free(result);
1055         }
1056 }
1057
1058 static void
1059 x264_remove_opt(gchar **opts, gchar **opt_syns)
1060 {
1061         gint ii;
1062         for (ii = 0; opts[ii] != NULL; ii++)
1063         {
1064                 gchar *opt;
1065                 opt = g_strdup(opts[ii]);
1066                 gchar *pos = strchr(opt, '=');
1067                 if (pos != NULL)
1068                 {
1069                         *pos = 0;
1070                 }
1071                 if (find_syn_match(opt, opt_syns) >= 0)
1072                 {
1073                         // Mark as deleted
1074                         opts[ii][0] = 0;
1075                 }
1076                 g_free(opt);
1077         }
1078 }
1079
1080 // Construct the x264 options string
1081 // The result is allocated, so someone must free it at some point.
1082 gchar*
1083 ghb_sanitize_x264opts(signal_user_data_t *ud, const gchar *options)
1084 {
1085         GString *x264opts = g_string_new("");
1086         gchar **split = g_strsplit(options, ":", -1);
1087
1088         // Remove entries that match the defaults
1089         gint ii;
1090         for (ii = 0; split[ii] != NULL; ii++)
1091         {
1092                 gchar *val = NULL;
1093                 gchar *opt = g_strdup(split[ii]);
1094                 gchar *pos = strchr(opt, '=');
1095                 if (pos != NULL)
1096                 {
1097                         val = pos + 1;
1098                         *pos = 0;
1099                 }
1100                 else
1101                 {
1102                         val = "1";
1103                 }
1104                 const gchar *def_val = x264_opt_get_default(opt);
1105                 if (strcmp(val, def_val) == 0)
1106                 {
1107                         // Matches the default, so remove it
1108                         split[ii][0] = 0;
1109                 }
1110                 g_free(opt);
1111         }
1112         gint refs = ghb_settings_get_int(ud->settings, "x264_refs");
1113         if (refs <= 1)
1114         {
1115                 x264_remove_opt(split, x264_mixed_syns);
1116         }
1117         gint subme = ghb_settings_get_int(ud->settings, "x264_subme");
1118         if (subme < 6)
1119         {
1120                 x264_remove_opt(split, x264_brdo_syns);
1121         }
1122         gint bframes = ghb_settings_get_int(ud->settings, "x264_bframes");
1123         if (bframes == 0)
1124         {
1125                 x264_remove_opt(split, x264_weightb_syns);
1126                 x264_remove_opt(split, x264_brdo_syns);
1127                 x264_remove_opt(split, x264_bime_syns);
1128         }
1129         if (bframes <= 1)
1130         {
1131                 x264_remove_opt(split, x264_bpyramid_syns);
1132         }
1133         gchar *me = ghb_settings_get_string(ud->settings, "x264_me");
1134         if (!(strcmp(me, "umh") == 0 || strcmp(me, "esa") == 0))
1135         {
1136                 x264_remove_opt(split, x264_merange_syns);
1137         }
1138         g_free(me);
1139         if (!ghb_settings_get_boolean(ud->settings, "x264_cabac"))
1140         {
1141                 x264_remove_opt(split, x264_trellis_syns);
1142         }
1143         gint analyse = ghb_settings_get_int(ud->settings, "x264_analyse");
1144         if (analyse == 1)
1145         {
1146                 x264_remove_opt(split, x264_direct_syns);
1147         }
1148         for (ii = 0; split[ii] != NULL; ii++)
1149         {
1150                 if (split[ii][0] != 0)
1151                         g_string_append_printf(x264opts, "%s:", split[ii]);
1152         }
1153         g_strfreev(split);
1154         // strip the trailing ":"
1155         gchar *result;
1156         gint len;
1157         result = g_string_free(x264opts, FALSE);
1158         len = strlen(result);
1159         if (len > 0) result[len - 1] = 0;
1160         return result;
1161 }
1162
1163 gint
1164 ghb_pref_acount(GValue *settings)
1165 {
1166         GValue *acodec;
1167         acodec = ghb_settings_get_value(settings, "pref_audio_codec");
1168         return ghb_array_len(acodec);
1169 }
1170
1171 gint
1172 ghb_pref_acodec(GValue *settings, gint index)
1173 {
1174         GValue *acodec;
1175         gint count;
1176
1177         acodec = ghb_settings_get_value(settings, "pref_audio_codec");
1178         count = ghb_array_len(acodec);
1179         if (index >= count)
1180                 return 0;
1181         return ghb_value_int(ghb_array_get_nth(acodec, index));
1182 }
1183
1184 gint
1185 ghb_pref_bitrate(GValue *settings, gint index)
1186 {
1187         GValue *bitrate;
1188         gint count;
1189
1190         bitrate = ghb_settings_get_value(settings, "pref_audio_bitrate");
1191         count = ghb_array_len(bitrate);
1192         if (index >= count)
1193                 return 0;
1194         return ghb_value_int(ghb_array_get_nth(bitrate, index));
1195 }
1196
1197 gint
1198 ghb_pref_rate(GValue *settings, gint index)
1199 {
1200         GValue *rate;
1201         gint count;
1202
1203         rate = ghb_settings_get_value(settings, "pref_audio_rate");
1204         count = ghb_array_len(rate);
1205         if (index >= count)
1206                 return 0;
1207         return ghb_value_int(ghb_array_get_nth(rate, index));
1208 }
1209
1210 gint
1211 ghb_pref_mix(GValue *settings, gint index)
1212 {
1213         GValue *mix;
1214         gint count;
1215
1216         mix = ghb_settings_get_value(settings, "pref_audio_mix");
1217         count = ghb_array_len(mix);
1218         if (index >= count)
1219                 return 0;
1220         return ghb_value_int(ghb_array_get_nth(mix, index));
1221 }
1222
1223 gdouble
1224 ghb_pref_drc(GValue *settings, gint index)
1225 {
1226         GValue *drc;
1227         gint count;
1228
1229         drc = ghb_settings_get_value(settings, "pref_audio_drc");
1230         count = ghb_array_len(drc);
1231         if (index >= count)
1232                 return 0;
1233         return ghb_value_double(ghb_array_get_nth(drc, index));
1234 }
1235