OSDN Git Service

LinGui: fix me_method/me_range dependency
[handbrake-jp/handbrake-jp-git.git] / gtk / src / x264handler.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * x264handler.c
4  * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
5  * 
6  * x264handler.c is free software.
7  * 
8  * You may redistribute it and/or modify it under the terms of the
9  * GNU General Public License, as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  */
13
14 #include <gtk/gtk.h>
15 #include <string.h>
16 #include "settings.h"
17 #include "values.h"
18 #include "callbacks.h"
19 #include "presets.h"
20 #include "hb-backend.h"
21 #include "x264handler.h"
22
23 static void x264_opt_update(signal_user_data_t *ud, GtkWidget *widget);
24 static gchar* sanitize_x264opts(signal_user_data_t *ud, const gchar *options);
25
26 // Flag needed to prevent x264 options processing from chasing its tail
27 static gboolean ignore_options_update = FALSE;
28
29 void
30 x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
31 {
32         ghb_widget_to_setting(ud->settings, widget);
33         if (!ignore_options_update)
34         {
35                 ignore_options_update = TRUE;
36                 x264_opt_update(ud, widget);
37                 ignore_options_update = FALSE;
38         }
39         ghb_check_dependency(ud, widget);
40         ghb_clear_presets_selection(ud);
41 }
42
43 void
44 x264_me_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
45 {
46         const GValue *gval;
47         gint me;
48
49         ghb_widget_to_setting(ud->settings, widget);
50         if (!ignore_options_update)
51         {
52                 ignore_options_update = TRUE;
53                 x264_opt_update(ud, widget);
54                 ignore_options_update = FALSE;
55         }
56         ghb_check_dependency(ud, widget);
57         ghb_clear_presets_selection(ud);
58         widget = GHB_WIDGET(ud->builder, "x264_merange");
59         gval = ghb_settings_get_value(ud->settings, "x264_me");
60         me = ghb_lookup_combo_int("x264_me", gval);
61         if (me < 2)
62         {       // me < umh
63                 // me_range 4 - 16
64                 gtk_spin_button_set_range(GTK_SPIN_BUTTON(widget), 4, 16);
65         }
66         else
67         {
68                 // me_range 4 - 64
69                 gtk_spin_button_set_range(GTK_SPIN_BUTTON(widget), 4, 64);
70         }
71 }
72
73 void
74 x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
75 {
76         g_debug("x264_entry_changed_cb ()");
77         if (!ignore_options_update)
78         {
79                 GtkWidget *textview;
80                 gchar *options;
81
82                 textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264Option"));
83                 ghb_widget_to_setting(ud->settings, textview);
84                 options = ghb_settings_get_string(ud->settings, "x264Option");
85                 ignore_options_update = TRUE;
86                 ghb_x264_parse_options(ud, options);
87                 if (!GTK_WIDGET_HAS_FOCUS(textview))
88                 {
89                         gchar *sopts;
90
91                         sopts = sanitize_x264opts(ud, options);
92                         ghb_ui_update(ud, "x264Option", ghb_string_value(sopts));
93                         ghb_x264_parse_options(ud, sopts);
94                         g_free(sopts);
95                 }
96                 g_free(options);
97                 ignore_options_update = FALSE;
98         }
99 }
100
101 gboolean
102 x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
103         signal_user_data_t *ud)
104 {
105         gchar *options, *sopts;
106
107         ghb_widget_to_setting(ud->settings, widget);
108         options = ghb_settings_get_string(ud->settings, "x264Option");
109         sopts = sanitize_x264opts(ud, options);
110         ignore_options_update = TRUE;
111         if (sopts != NULL && strcmp(sopts, options) != 0)
112         {
113                 ghb_ui_update(ud, "x264Option", ghb_string_value(sopts));
114                 ghb_x264_parse_options(ud, sopts);
115         }
116         g_free(options);
117         g_free(sopts);
118         ignore_options_update = FALSE;
119         return FALSE;
120 }
121
122 enum
123 {
124         X264_OPT_DEBLOCK,
125         X264_OPT_INT,
126         X264_OPT_COMBO,
127         X264_OPT_BOOL,
128 };
129
130 struct x264_opt_map_s
131 {
132         gchar **opt_syns;
133         gchar *name;
134         gchar *def_val;
135         gint type;
136         gboolean found;
137 };
138
139 static gchar *x264_ref_syns[] = {"ref", "frameref", NULL};
140 static gchar *x264_mixed_syns[] = {"mixed-refs", "mixed_refs", NULL};
141 static gchar *x264_bframes_syns[] = {"bframes", NULL};
142 static gchar *x264_direct_syns[] = 
143         {"direct", "direct-pred", "direct_pred", NULL};
144 static gchar *x264_weightb_syns[] = {"weightb", "weight-b", "weight_b", NULL};
145 static gchar *x264_bpyramid_syns[] = {"b-pyramid", "b_pyramid", NULL};
146 static gchar *x264_me_syns[] = {"me", NULL};
147 static gchar *x264_merange_syns[] = {"merange", "me-range", "me_range", NULL};
148 static gchar *x264_subme_syns[] = {"subme", "subq", NULL};
149 static gchar *x264_analyse_syns[] = {"analyse", "partitions", NULL};
150 static gchar *x264_8x8dct_syns[] = {"8x8dct", NULL};
151 static gchar *x264_deblock_syns[] = {"deblock", "filter", NULL};
152 static gchar *x264_trellis_syns[] = {"trellis", NULL};
153 static gchar *x264_pskip_syns[] = {"no-fast-pskip", "no_fast_pskip", NULL};
154 static gchar *x264_decimate_syns[] = 
155         {"no-dct-decimate", "no_dct_decimate", NULL};
156 static gchar *x264_cabac_syns[] = {"cabac", NULL};
157
158 static gint
159 find_syn_match(const gchar *opt, gchar **syns)
160 {
161         gint ii;
162         for (ii = 0; syns[ii] != NULL; ii++)
163         {
164                 if (strcmp(opt, syns[ii]) == 0)
165                         return ii;
166         }
167         return -1;
168 }
169
170 struct x264_opt_map_s x264_opt_map[] =
171 {
172         {x264_ref_syns, "x264_refs", "1", X264_OPT_INT},
173         {x264_mixed_syns, "x264_mixed_refs", "0", X264_OPT_BOOL},
174         {x264_bframes_syns, "x264_bframes", "0", X264_OPT_INT},
175         {x264_direct_syns, "x264_direct", "spatial", X264_OPT_COMBO},
176         {x264_weightb_syns, "x264_weighted_bframes", "0", X264_OPT_BOOL},
177         {x264_bpyramid_syns, "x264_bpyramid", "0", X264_OPT_BOOL},
178         {x264_me_syns, "x264_me", "hex", X264_OPT_COMBO},
179         {x264_merange_syns, "x264_merange", "16", X264_OPT_INT},
180         {x264_subme_syns, "x264_subme", "6", X264_OPT_COMBO},
181         {x264_analyse_syns, "x264_analyse", "some", X264_OPT_COMBO},
182         {x264_8x8dct_syns, "x264_8x8dct", "0", X264_OPT_BOOL},
183         {x264_deblock_syns, "x264_deblock_alpha", "0,0", X264_OPT_DEBLOCK},
184         {x264_deblock_syns, "x264_deblock_beta", "0,0", X264_OPT_DEBLOCK},
185         {x264_trellis_syns, "x264_trellis", "0", X264_OPT_COMBO},
186         {x264_pskip_syns, "x264_no_fast_pskip", "0", X264_OPT_BOOL},
187         {x264_decimate_syns, "x264_no_dct_decimate", "0", X264_OPT_BOOL},
188         {x264_cabac_syns, "x264_cabac", "1", X264_OPT_BOOL},
189 };
190 #define X264_OPT_MAP_SIZE (sizeof(x264_opt_map)/sizeof(struct x264_opt_map_s))
191
192 static const gchar*
193 x264_opt_get_default(const gchar *opt)
194 {
195         gint jj;
196         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
197         {
198                 if (find_syn_match(opt, x264_opt_map[jj].opt_syns) >= 0)
199                 {
200                         return x264_opt_map[jj].def_val;
201                 }
202         }
203         return "";
204 }
205
206 static void
207 x264_update_int(signal_user_data_t *ud, const gchar *name, const gchar *val)
208 {
209         gint ival;
210
211         if (val == NULL) return;
212         ival = g_strtod (val, NULL);
213         ghb_ui_update(ud, name, ghb_int64_value(ival));
214 }
215
216 static gchar *true_str[] =
217 {
218         "true",
219         "yes",
220         "1",
221         NULL
222 };
223
224 static gboolean 
225 str_is_true(const gchar *str)
226 {
227         gint ii;
228         for (ii = 0; true_str[ii]; ii++)
229         {
230                 if (g_ascii_strcasecmp(str, true_str[ii]) == 0)
231                         return TRUE;
232         }
233         return FALSE;
234 }
235
236 static void
237 x264_update_bool(signal_user_data_t *ud, const gchar *name, const gchar *val)
238 {
239         if (val == NULL)
240                 ghb_ui_update(ud, name, ghb_boolean_value(1));
241         else
242                 ghb_ui_update(ud, name, ghb_boolean_value(str_is_true(val)));
243 }
244
245 static void
246 x264_update_combo(signal_user_data_t *ud, const gchar *name, const gchar *val)
247 {
248         GtkTreeModel *store;
249         GtkTreeIter iter;
250         gchar *shortOpt;
251         gint ivalue;
252         gboolean foundit = FALSE;
253         GtkWidget *widget;
254
255         if (val == NULL) return;
256         widget = GHB_WIDGET(ud->builder, name);
257         if (widget == NULL)
258         {
259                 g_debug("Failed to find widget for key: %s\n", name);
260                 return;
261         }
262         store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
263         if (gtk_tree_model_get_iter_first (store, &iter))
264         {
265                 do
266                 {
267                         gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1);
268                         if (strcmp(shortOpt, val) == 0)
269                         {
270                                 gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
271                                 g_free(shortOpt);
272                                 foundit = TRUE;
273                                 break;
274                         }
275                         g_free(shortOpt);
276                 } while (gtk_tree_model_iter_next (store, &iter));
277         }
278         if (!foundit)
279         {
280                 if (gtk_tree_model_get_iter_first (store, &iter))
281                 {
282                         do
283                         {
284                                 gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1);
285                                 if (strcmp(shortOpt, "custom") == 0)
286                                 {
287                                         gtk_list_store_set(GTK_LIST_STORE(store), &iter, 4, val, -1);
288                                         gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
289                                         g_free(shortOpt);
290                                         foundit = TRUE;
291                                         break;
292                                 }
293                                 g_free(shortOpt);
294                         } while (gtk_tree_model_iter_next (store, &iter));
295                 }
296         }
297         // Its possible the value hasn't changed. Since settings are only
298         // updated when the value changes, I'm initializing settings here as well.
299         ghb_widget_to_setting(ud->settings, widget);
300 }
301
302 static void
303 x264_update_deblock(signal_user_data_t *ud, const gchar *xval)
304 {
305         gdouble avalue, bvalue;
306         gchar *end;
307         gchar *val;
308         gchar *bval = NULL;
309
310         if (xval == NULL) return;
311         val = g_strdup(xval);
312         bvalue = avalue = 0;
313         if (val != NULL) 
314         {
315                 gchar *pos = strchr(val, ',');
316                 if (pos != NULL)
317                 {
318                         bval = pos + 1;
319                         *pos = 0;
320                 }
321                 avalue = g_strtod (val, &end);
322                 if (bval != NULL)
323                 {
324                         bvalue = g_strtod (bval, &end);
325                 }
326         }
327         g_free(val);
328         ghb_ui_update(ud, "x264_deblock_alpha", ghb_int64_value(avalue));
329         ghb_ui_update(ud, "x264_deblock_beta", ghb_int64_value(bvalue));
330 }
331
332 void
333 ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options)
334 {
335         gchar **split = g_strsplit(options, ":", -1);
336         if (split == NULL) return;
337
338         gint ii;
339         gint jj;
340
341         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
342                 x264_opt_map[jj].found = FALSE;
343
344         for (ii = 0; split[ii] != NULL; ii++)
345         {
346                 gchar *val = NULL;
347                 gchar *pos = strchr(split[ii], '=');
348                 if (pos != NULL)
349                 {
350                         val = pos + 1;
351                         *pos = 0;
352                 }
353                 for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
354                 {
355                         if (find_syn_match(split[ii], x264_opt_map[jj].opt_syns) >= 0)
356                         {
357                                 x264_opt_map[jj].found = TRUE;
358                                 switch(x264_opt_map[jj].type)
359                                 {
360                                 case X264_OPT_INT:
361                                         x264_update_int(ud, x264_opt_map[jj].name, val);
362                                         break;
363                                 case X264_OPT_BOOL:
364                                         x264_update_bool(ud, x264_opt_map[jj].name, val);
365                                         break;
366                                 case X264_OPT_COMBO:
367                                         x264_update_combo(ud, x264_opt_map[jj].name, val);
368                                         break;
369                                 case X264_OPT_DEBLOCK:
370                                         // dirty little hack.  mark deblock_beta found as well
371                                         x264_opt_map[jj+1].found = TRUE;
372                                         x264_update_deblock(ud, val);
373                                         break;
374                                 }
375                                 break;
376                         }
377                 }
378         }
379         // For any options not found in the option string, set ui to
380         // default values
381         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
382         {
383                 if (!x264_opt_map[jj].found)
384                 {
385                         gchar *val = strdup(x264_opt_map[jj].def_val);
386                         switch(x264_opt_map[jj].type)
387                         {
388                         case X264_OPT_INT:
389                                 x264_update_int(ud, x264_opt_map[jj].name, val);
390                                 break;
391                         case X264_OPT_BOOL:
392                                 x264_update_bool(ud, x264_opt_map[jj].name, val);
393                                 break;
394                         case X264_OPT_COMBO:
395                                 x264_update_combo(ud, x264_opt_map[jj].name, val);
396                                 break;
397                         case X264_OPT_DEBLOCK:
398                                 x264_update_deblock(ud, val);
399                                 break;
400                         }
401                         x264_opt_map[jj].found = TRUE;
402                         g_free(val);
403                 }
404         }
405         g_strfreev(split);
406 }
407
408 gchar*
409 get_deblock_val(signal_user_data_t *ud)
410 {
411         gchar *alpha, *beta;
412         gchar *result;
413         alpha = ghb_settings_get_string(ud->settings, "x264_deblock_alpha");
414         beta = ghb_settings_get_string(ud->settings, "x264_deblock_beta");
415         result = g_strdup_printf("%s,%s", alpha, beta);
416         g_free(alpha);
417         g_free(beta);
418         return result;
419 }
420
421 static void
422 x264_opt_update(signal_user_data_t *ud, GtkWidget *widget)
423 {
424         gint jj;
425         const gchar *name = gtk_widget_get_name(widget);
426         gchar **opt_syns = NULL;
427         const gchar *def_val = NULL;
428         gint type;
429
430         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
431         {
432                 if (strcmp(name, x264_opt_map[jj].name) == 0)
433                 {
434                         // found the options that needs updating
435                         opt_syns = x264_opt_map[jj].opt_syns;
436                         def_val = x264_opt_map[jj].def_val;
437                         type = x264_opt_map[jj].type;
438                         break;
439                 }
440         }
441         if (opt_syns != NULL)
442         {
443                 GString *x264opts = g_string_new("");
444                 gchar *options;
445                 gchar **split = NULL;
446                 gint ii;
447                 gboolean foundit = FALSE;
448
449                 options = ghb_settings_get_string(ud->settings, "x264Option");
450                 if (options)
451                 {
452                         split = g_strsplit(options, ":", -1);
453                         g_free(options);
454                 }
455                 for (ii = 0; split && split[ii] != NULL; ii++)
456                 {
457                         gint syn;
458                         gchar *val = NULL;
459                         gchar *pos = strchr(split[ii], '=');
460                         if (pos != NULL)
461                         {
462                                 val = pos + 1;
463                                 *pos = 0;
464                         }
465                         syn = find_syn_match(split[ii], opt_syns);
466                         if (syn >= 0)
467                         { // Updating this option
468                                 gchar *val;
469                                 foundit = TRUE;
470                                 if (type == X264_OPT_DEBLOCK)
471                                         val = get_deblock_val(ud);
472                                 else
473                                 {
474                                         GValue *gval;
475                                         gval = ghb_widget_value(widget);
476                                         if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN)
477                                         {
478                                                 if (ghb_value_boolean(gval))
479                                                         val = g_strdup("1");
480                                                 else
481                                                         val = g_strdup("0");
482                                         }
483                                         else
484                                         {
485                                                 val = ghb_widget_string(widget);
486                                         }
487                                         ghb_value_free(gval);
488                                 }
489                                 if (strcmp(def_val, val) != 0)
490                                 {
491                                         g_string_append_printf(x264opts, "%s=%s:", opt_syns[syn], val);
492                                 }
493                                 g_free(val);
494                         }
495                         else if (val != NULL)
496                                 g_string_append_printf(x264opts, "%s=%s:", split[ii], val);
497                         else
498                                 g_string_append_printf(x264opts, "%s:", split[ii]);
499
500                 }
501                 if (split) g_strfreev(split);
502                 if (!foundit)
503                 {
504                         gchar *val;
505                         if (type == X264_OPT_DEBLOCK)
506                                 val = get_deblock_val(ud);
507                         else
508                         {
509                                 GValue *gval;
510                                 gval = ghb_widget_value(widget);
511                                 if (G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN)
512                                 {
513                                         if (ghb_value_boolean(gval))
514                                                 val = g_strdup("1");
515                                         else
516                                                 val = g_strdup("0");
517                                 }
518                                 else
519                                 {
520                                         val = ghb_widget_string(widget);
521                                 }
522                                 ghb_value_free(gval);
523                         }
524                         if (strcmp(def_val, val) != 0)
525                         {
526                                 g_string_append_printf(x264opts, "%s=%s:", opt_syns[0], val);
527                         }
528                         g_free(val);
529                 }
530                 // Update the options value
531                 // strip the trailing ":"
532                 gchar *result;
533                 gint len;
534                 result = g_string_free(x264opts, FALSE);
535                 len = strlen(result);
536                 if (len > 0) result[len - 1] = 0;
537                 gchar *sopts;
538                 sopts = sanitize_x264opts(ud, result);
539                 ghb_ui_update(ud, "x264Option", ghb_string_value(sopts));
540                 ghb_x264_parse_options(ud, sopts);
541                 g_free(sopts);
542                 g_free(result);
543         }
544 }
545
546 static void
547 x264_remove_opt(gchar **opts, gchar **opt_syns)
548 {
549         gint ii;
550         for (ii = 0; opts[ii] != NULL; ii++)
551         {
552                 gchar *opt;
553                 opt = g_strdup(opts[ii]);
554                 gchar *pos = strchr(opt, '=');
555                 if (pos != NULL)
556                 {
557                         *pos = 0;
558                 }
559                 if (find_syn_match(opt, opt_syns) >= 0)
560                 {
561                         // Mark as deleted
562                         opts[ii][0] = 0;
563                 }
564                 g_free(opt);
565         }
566 }
567
568 // Construct the x264 options string
569 // The result is allocated, so someone must free it at some point.
570 static gchar*
571 sanitize_x264opts(signal_user_data_t *ud, const gchar *options)
572 {
573         GString *x264opts = g_string_new("");
574         gchar **split = g_strsplit(options, ":", -1);
575
576         // Remove entries that match the defaults
577         gint ii;
578         for (ii = 0; split[ii] != NULL; ii++)
579         {
580                 gchar *val = NULL;
581                 gchar *opt = g_strdup(split[ii]);
582                 gchar *pos = strchr(opt, '=');
583                 if (pos != NULL)
584                 {
585                         val = pos + 1;
586                         *pos = 0;
587                 }
588                 else
589                 {
590                         val = "1";
591                 }
592                 const gchar *def_val = x264_opt_get_default(opt);
593                 if (strcmp(val, def_val) == 0)
594                 {
595                         // Matches the default, so remove it
596                         split[ii][0] = 0;
597                 }
598                 g_free(opt);
599         }
600         gint refs = ghb_settings_get_int(ud->settings, "x264_refs");
601         if (refs <= 1)
602         {
603                 x264_remove_opt(split, x264_mixed_syns);
604         }
605         gint bframes = ghb_settings_get_int(ud->settings, "x264_bframes");
606         if (bframes == 0)
607         {
608                 x264_remove_opt(split, x264_weightb_syns);
609                 x264_remove_opt(split, x264_direct_syns);
610         }
611         if (bframes <= 1)
612         {
613                 x264_remove_opt(split, x264_bpyramid_syns);
614         }
615         if (!ghb_settings_get_boolean(ud->settings, "x264_cabac"))
616         {
617                 x264_remove_opt(split, x264_trellis_syns);
618         }
619         for (ii = 0; split[ii] != NULL; ii++)
620         {
621                 if (split[ii][0] != 0)
622                         g_string_append_printf(x264opts, "%s:", split[ii]);
623         }
624         g_strfreev(split);
625         // strip the trailing ":"
626         gchar *result;
627         gint len;
628         result = g_string_free(x264opts, FALSE);
629         len = strlen(result);
630         if (len > 0) result[len - 1] = 0;
631         return result;
632 }
633