OSDN Git Service

72883d85a7cb002daa23958649a149ffe373eb1b
[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         gchar *val;
463         gchar *trell_val = NULL;
464         gchar *end;
465
466         *psy_rd = 0.;
467         *psy_trell = 0.;
468         if (psy == NULL) return;
469         val = g_strdup(psy);
470         gchar *pos = strchr(val, ',');
471         if (pos != NULL)
472         {
473                 trell_val = pos + 1;
474                 *pos = 0;
475         }
476         *psy_rd = g_strtod (val, &end);
477         if (trell_val != NULL)
478         {
479                 *psy_trell = g_strtod (trell_val, &end);
480         }
481         g_free(val);
482 }
483
484 static void
485 x264_update_psy(signal_user_data_t *ud, const gchar *xval)
486 {
487         gdouble rd_value, trell_value;
488
489         if (xval == NULL) return;
490         x264_parse_psy(xval, &rd_value, &trell_value);
491         ghb_ui_update(ud, "x264_psy_rd", ghb_double_value(rd_value));
492         ghb_ui_update(ud, "x264_psy_trell", ghb_double_value(trell_value));
493 }
494
495 static void do_update(signal_user_data_t *ud, char *name, gint type, char *val)
496 {
497         switch(type)
498         {
499         case X264_OPT_INT:
500                 x264_update_int(ud, name, val);
501                 break;
502         case X264_OPT_DOUBLE:
503                 x264_update_double(ud, name, val);
504                 break;
505         case X264_OPT_BOOL:
506                 x264_update_bool(ud, name, val);
507                 break;
508         case X264_OPT_COMBO:
509                 x264_update_combo(ud, name, val);
510                 break;
511         case X264_OPT_BOOL_NONE:
512                 x264_update_bool_setting(ud, name, val);
513                 break;
514         case X264_OPT_INT_NONE:
515                 x264_update_int_setting(ud, name, val);
516                 break;
517         }
518 }
519
520 void
521 ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options)
522 {
523         gchar **split = g_strsplit(options, ":", -1);
524         if (split == NULL) return;
525
526         gint ii;
527         gint jj;
528
529         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
530                 x264_opt_map[jj].found = FALSE;
531
532         for (ii = 0; split[ii] != NULL; ii++)
533         {
534                 gchar *val = NULL;
535                 gchar *pos = strchr(split[ii], '=');
536                 if (pos != NULL)
537                 {
538                         val = pos + 1;
539                         *pos = 0;
540                 }
541                 for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
542                 {
543                         if (find_syn_match(split[ii], x264_opt_map[jj].opt_syns) >= 0)
544                         {
545                                 x264_opt_map[jj].found = TRUE;
546                                 switch(x264_opt_map[jj].type)
547                                 {
548                                 case X264_OPT_INT:
549                                         x264_update_int(ud, x264_opt_map[jj].name, val);
550                                         break;
551                                 case X264_OPT_DOUBLE:
552                                         x264_update_double(ud, x264_opt_map[jj].name, val);
553                                         break;
554                                 case X264_OPT_BOOL:
555                                         x264_update_bool(ud, x264_opt_map[jj].name, val);
556                                         break;
557                                 case X264_OPT_COMBO:
558                                         x264_update_combo(ud, x264_opt_map[jj].name, val);
559                                         break;
560                                 case X264_OPT_DEBLOCK:
561                                         // dirty little hack.  mark deblock_beta found as well
562                                         x264_opt_map[jj+1].found = TRUE;
563                                         x264_update_deblock(ud, val);
564                                         break;
565                                 case X264_OPT_PSY:
566                                         // dirty little hack.  mark psy_trell found as well
567                                         x264_opt_map[jj+1].found = TRUE;
568                                         x264_update_psy(ud, val);
569                                         break;
570                                 case X264_OPT_BOOL_NONE:
571                                         x264_update_bool_setting(ud, x264_opt_map[jj].name, val);
572                                         break;
573                                 case X264_OPT_INT_NONE:
574                                         x264_update_int_setting(ud, x264_opt_map[jj].name, val);
575                                         break;
576                                 case X264_OPT_TRANS:
577                                         if (x264_opt_map[jj].translation == NULL)
578                                                 break;
579                                         val = trans_x264_val(x264_opt_map[jj].translation, val);
580                                         if (val != NULL)
581                                         {
582                                                 do_update(ud, x264_opt_map[jj].name, 
583                                                         x264_opt_map[jj].translation->ui_type, val);
584                                                 // TODO un-grey the ui control
585                                         }
586                                         else
587                                         {
588                                                 // TODO grey out the ui control
589                                         }
590                                         break;
591                                 }
592                                 break;
593                         }
594                 }
595         }
596         // For any options not found in the option string, set ui to
597         // default values
598         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
599         {
600                 if (!x264_opt_map[jj].found)
601                 {
602                         gchar *val = strdup(x264_opt_map[jj].def_val);
603                         switch(x264_opt_map[jj].type)
604                         {
605                         case X264_OPT_INT:
606                                 x264_update_int(ud, x264_opt_map[jj].name, val);
607                                 break;
608                         case X264_OPT_DOUBLE:
609                                 x264_update_double(ud, x264_opt_map[jj].name, val);
610                                 break;
611                         case X264_OPT_BOOL:
612                                 x264_update_bool(ud, x264_opt_map[jj].name, val);
613                                 break;
614                         case X264_OPT_COMBO:
615                                 x264_update_combo(ud, x264_opt_map[jj].name, val);
616                                 break;
617                         case X264_OPT_DEBLOCK:
618                                 x264_update_deblock(ud, val);
619                                 break;
620                         case X264_OPT_PSY:
621                                 x264_update_psy(ud, val);
622                                 break;
623                         case X264_OPT_BOOL_NONE:
624                                 x264_update_bool_setting(ud, x264_opt_map[jj].name, val);
625                                 break;
626                         case X264_OPT_INT_NONE:
627                                 x264_update_int_setting(ud, x264_opt_map[jj].name, val);
628                                 break;
629                         case X264_OPT_TRANS:
630                                 if (x264_opt_map[jj].translation == NULL)
631                                         break;
632                                 val = g_strdup(trans_x264_val(x264_opt_map[jj].translation, val));
633                                 if (val != NULL)
634                                 {
635                                         do_update(ud, x264_opt_map[jj].name, 
636                                                 x264_opt_map[jj].translation->ui_type, val);
637                                         // TODO un-grey the ui control
638                                 }
639                                 else
640                                 {
641                                         // TODO grey out the ui control
642                                 }
643                                 break;
644                         }
645                         x264_opt_map[jj].found = TRUE;
646                         g_free(val);
647                 }
648         }
649         g_strfreev(split);
650 }
651
652 gchar*
653 get_deblock_val(signal_user_data_t *ud)
654 {
655         gchar *alpha, *beta;
656         gchar *result;
657         alpha = ghb_settings_get_string(ud->settings, "x264_deblock_alpha");
658         beta = ghb_settings_get_string(ud->settings, "x264_deblock_beta");
659         result = g_strdup_printf("%s,%s", alpha, beta);
660         g_free(alpha);
661         g_free(beta);
662         return result;
663 }
664
665 gchar*
666 get_psy_val(signal_user_data_t *ud)
667 {
668         gdouble rd, trell;
669         gchar *result;
670         rd = ghb_settings_get_double(ud->settings, "x264_psy_rd");
671         trell = ghb_settings_get_double(ud->settings, "x264_psy_trell");
672         result = g_strdup_printf("%g,%g", rd, trell);
673         return result;
674 }
675
676 static void
677 x264_opt_update(signal_user_data_t *ud, GtkWidget *widget)
678 {
679         gint jj;
680         const gchar *name = ghb_get_setting_key(widget);
681         gchar **opt_syns = NULL;
682         const gchar *def_val = NULL;
683         gint type;
684         trans_table_t *trans;
685
686         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
687         {
688                 if (strcmp(name, x264_opt_map[jj].name) == 0)
689                 {
690                         // found the options that needs updating
691                         opt_syns = x264_opt_map[jj].opt_syns;
692                         def_val = x264_opt_map[jj].def_val;
693                         type = x264_opt_map[jj].type;
694                         trans = x264_opt_map[jj].translation;
695                         break;
696                 }
697         }
698         if (opt_syns != NULL)
699         {
700                 GString *x264opts = g_string_new("");
701                 gchar *options;
702                 gchar **split = NULL;
703                 gint ii;
704                 gboolean foundit = FALSE;
705
706                 options = ghb_settings_get_string(ud->settings, "x264Option");
707                 if (options)
708                 {
709                         split = g_strsplit(options, ":", -1);
710                         g_free(options);
711                 }
712                 for (ii = 0; split && split[ii] != NULL; ii++)
713                 {
714                         gint syn;
715                         gchar *val = NULL;
716                         gchar *pos = strchr(split[ii], '=');
717                         if (pos != NULL)
718                         {
719                                 val = pos + 1;
720                                 *pos = 0;
721                         }
722                         syn = find_syn_match(split[ii], opt_syns);
723                         if (syn >= 0)
724                         { // Updating this option
725                                 gchar *val;
726                                 foundit = TRUE;
727                                 if (type == X264_OPT_DEBLOCK)
728                                         val = get_deblock_val(ud);
729                                 else if (type == X264_OPT_PSY)
730                                         val = get_psy_val(ud);
731                                 else
732                                 {
733                                         GValue *gval;
734                                         gval = ghb_widget_value(widget);
735                                         if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN)
736                                         {
737                                                 if (ghb_value_boolean(gval))
738                                                         val = g_strdup("1");
739                                                 else
740                                                         val = g_strdup("0");
741                                         }
742                                         else
743                                         {
744                                                 val = ghb_widget_string(widget);
745                                         }
746                                         ghb_value_free(gval);
747                                 }
748                                 if (type == X264_OPT_TRANS)
749                                 {
750                                         gchar *tmp;
751                                         tmp = g_strdup(trans_ui_val(trans, val));
752                                         if (tmp)
753                                         {
754                                                 g_free(val);
755                                                 val = tmp;
756                                         }
757                                 }
758                                 if (strcmp(def_val, val) != 0)
759                                 {
760                                         g_string_append_printf(x264opts, "%s=%s:", opt_syns[syn], val);
761                                 }
762                                 g_free(val);
763                         }
764                         else if (val != NULL)
765                                 g_string_append_printf(x264opts, "%s=%s:", split[ii], val);
766                         else
767                                 g_string_append_printf(x264opts, "%s:", split[ii]);
768
769                 }
770                 if (split) g_strfreev(split);
771                 if (!foundit)
772                 {
773                         gchar *val;
774                         if (type == X264_OPT_DEBLOCK)
775                                 val = get_deblock_val(ud);
776                         else if (type == X264_OPT_PSY)
777                                 val = get_psy_val(ud);
778                         else
779                         {
780                                 GValue *gval;
781                                 gval = ghb_widget_value(widget);
782                                 if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN)
783                                 {
784                                         if (ghb_value_boolean(gval))
785                                                 val = g_strdup("1");
786                                         else
787                                                 val = g_strdup("0");
788                                 }
789                                 else
790                                 {
791                                         val = ghb_widget_string(widget);
792                                 }
793                                 ghb_value_free(gval);
794                         }
795                         if (type == X264_OPT_TRANS)
796                         {
797                                 gchar *tmp;
798                                 tmp = g_strdup(trans_ui_val(trans, val));
799                                 if (tmp)
800                                 {
801                                         g_free(val);
802                                         val = tmp;
803                                 }
804                         }
805                         if (strcmp(def_val, val) != 0)
806                         {
807                                 g_string_append_printf(x264opts, "%s=%s:", opt_syns[0], val);
808                         }
809                         g_free(val);
810                 }
811                 // Update the options value
812                 // strip the trailing ":"
813                 gchar *result;
814                 gint len;
815                 result = g_string_free(x264opts, FALSE);
816                 len = strlen(result);
817                 if (len > 0) result[len - 1] = 0;
818                 gchar *sopts;
819                 sopts = sanitize_x264opts(ud, result);
820                 ghb_ui_update(ud, "x264Option", ghb_string_value(sopts));
821                 ghb_x264_parse_options(ud, sopts);
822                 g_free(sopts);
823                 g_free(result);
824         }
825 }
826
827 static gint
828 x264_find_opt(gchar **opts, gchar **opt_syns)
829 {
830         gint ii;
831         for (ii = 0; opts[ii] != NULL; ii++)
832         {
833                 gchar *opt;
834                 opt = g_strdup(opts[ii]);
835                 gchar *pos = strchr(opt, '=');
836                 if (pos != NULL)
837                 {
838                         *pos = 0;
839                 }
840                 if (find_syn_match(opt, opt_syns) >= 0)
841                 {
842                         g_free(opt);
843                         return ii;
844                 }
845                 g_free(opt);
846         }
847         return -1;
848 }
849
850 static void
851 x264_remove_opt(gchar **opts, gchar **opt_syns)
852 {
853         gint ii;
854         for (ii = 0; opts[ii] != NULL; ii++)
855         {
856                 gchar *opt;
857                 opt = g_strdup(opts[ii]);
858                 gchar *pos = strchr(opt, '=');
859                 if (pos != NULL)
860                 {
861                         *pos = 0;
862                 }
863                 if (find_syn_match(opt, opt_syns) >= 0)
864                 {
865                         // Mark as deleted
866                         opts[ii][0] = 0;
867                 }
868                 g_free(opt);
869         }
870 }
871
872 static gchar*
873 x264_lookup_value(gchar **opts, gchar **opt_syns)
874 {
875         gchar *ret = NULL;
876         gint pos;
877
878         const gchar *def_val = x264_opt_get_default(opt_syns[0]);
879
880         pos = x264_find_opt(opts, opt_syns);
881         if (pos >= 0)
882         {
883                 gchar *cpos = strchr(opts[pos], '=');
884                 if (cpos != NULL)
885                 {
886                         ret = g_strdup(cpos+1);
887                 }
888                 else
889                 {
890                         ret = g_strdup("");
891                 }
892         }
893         else if (def_val != NULL)
894         {
895                 ret = g_strdup(def_val);
896         }
897         return ret;
898 }
899
900 gint
901 ghb_lookup_badapt(const gchar *options)
902 {
903         gint ret = 0;
904         gchar *result;
905         gchar **split;
906         
907         if (options == NULL)
908                 options = "";
909
910         split = g_strsplit(options, ":", -1);
911
912         result = x264_lookup_value(split, x264_badapt_syns);
913         g_strfreev(split);
914         if (result != NULL)
915         {
916                 ret = g_strtod(result, NULL);
917                 g_free(result);
918         }
919         return ret;
920 }
921
922 gint
923 ghb_lookup_aqmode(const gchar *options)
924 {
925         gint ret = 0;
926         gchar *result;
927         gchar **split;
928         
929         if (options == NULL)
930                 options = "";
931
932         split = g_strsplit(options, ":", -1);
933
934         result = x264_lookup_value(split, x264_aqmode_syns);
935         g_strfreev(split);
936         if (result != NULL)
937         {
938                 ret = g_strtod(result, NULL);
939                 g_free(result);
940         }
941         return ret;
942 }
943
944 gint
945 ghb_lookup_bframes(const gchar *options)
946 {
947         gint ret = 0;
948         gchar *result;
949         gchar **split;
950         
951         if (options == NULL)
952                 options = "";
953
954         split = g_strsplit(options, ":", -1);
955
956         result = x264_lookup_value(split, x264_bframes_syns);
957         g_strfreev(split);
958         if (result != NULL)
959         {
960                 ret = g_strtod(result, NULL);
961                 g_free(result);
962         }
963         return ret;
964 }
965
966 gint
967 ghb_lookup_mbtree(const gchar *options)
968 {
969         gint ret = ghb_lookup_bframes(options) != 0;
970         gchar *result;
971         gchar **split;
972         
973         if (options == NULL)
974                 options = "";
975
976         split = g_strsplit(options, ":", -1);
977
978         result = x264_lookup_value(split, x264_mbtree_syns);
979         g_strfreev(split);
980         if (result != NULL)
981         {
982                 ret = g_strtod(result, NULL);
983                 g_free(result);
984         }
985         return ret;
986 }
987
988 // Construct the x264 options string
989 // The result is allocated, so someone must free it at some point.
990 static gchar*
991 sanitize_x264opts(signal_user_data_t *ud, const gchar *options)
992 {
993         GString *x264opts = g_string_new("");
994         gchar **split = g_strsplit(options, ":", -1);
995         gint ii;
996
997         // Fix up option dependencies
998         gint subme = ghb_settings_combo_int(ud->settings, "x264_subme");
999         if (subme < 6)
1000         {
1001                 x264_remove_opt(split, x264_psy_syns);
1002         }
1003         gint trell = ghb_settings_combo_int(ud->settings, "x264_trellis");
1004         if (subme == 10)
1005         {
1006                 gint aqmode = ghb_lookup_aqmode(options);
1007                 if (trell != 2 || aqmode == 0)
1008                 {
1009                         gint pos = x264_find_opt(split, x264_subme_syns);
1010                         g_free(split[pos]);
1011                         split[pos] = g_strdup_printf("subme=9");
1012                 }
1013         }
1014         if (trell < 1)
1015         {
1016                 gint psy;
1017                 gdouble psy_rd = 0., psy_trell;
1018
1019                 psy = x264_find_opt(split, x264_psy_syns);
1020                 if (psy >= 0)
1021                 {
1022                         gchar *pos = strchr(split[psy], '=');
1023                         if (pos != NULL)
1024                         {
1025                                 x264_parse_psy(pos+1, &psy_rd, &psy_trell);
1026                         }
1027                         g_free(split[psy]);
1028                         split[psy] = g_strdup_printf("psy-rd=%g,0", psy_rd);
1029                 }
1030         }
1031         gint bframes = ghb_settings_get_int(ud->settings, "x264_bframes");
1032         if (bframes == 0)
1033         {
1034                 x264_remove_opt(split, x264_direct_syns);
1035                 x264_remove_opt(split, x264_badapt_syns);
1036         }
1037         if (bframes <= 1)
1038         {
1039                 x264_remove_opt(split, x264_bpyramid_syns);
1040         }
1041         // Remove entries that match the defaults
1042         for (ii = 0; split[ii] != NULL; ii++)
1043         {
1044                 gchar *val = NULL;
1045                 gchar *opt = g_strdup(split[ii]);
1046                 gchar *pos = strchr(opt, '=');
1047                 if (pos != NULL)
1048                 {
1049                         val = pos + 1;
1050                         *pos = 0;
1051                 }
1052                 else
1053                 {
1054                         val = "1";
1055                 }
1056                 const gchar *def_val;
1057                 def_val = x264_opt_get_default(opt);
1058                 if (strcmp(val, def_val) == 0)
1059                 {
1060                         // Matches the default, so remove it
1061                         split[ii][0] = 0;
1062                 }
1063                 g_free(opt);
1064         }
1065         for (ii = 0; split[ii] != NULL; ii++)
1066         {
1067                 if (split[ii][0] != 0)
1068                         g_string_append_printf(x264opts, "%s:", split[ii]);
1069         }
1070         g_strfreev(split);
1071         // strip the trailing ":"
1072         gchar *result;
1073         gint len;
1074         result = g_string_free(x264opts, FALSE);
1075         len = strlen(result);
1076         if (len > 0) result[len - 1] = 0;
1077         return result;
1078 }
1079