]> git.sesse.net Git - x264/blob - gtk/x264_gtk_cqm.c
GTK update. patch by Vincent Torri.
[x264] / gtk / x264_gtk_cqm.c
1 #if defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ || defined __DragonFly__
2 #  include <inttypes.h>
3 #else
4 #  include <stdint.h>
5 #endif
6
7 #include <gtk/gtk.h>
8
9 #include "../x264.h"
10 #include "x264_gtk_private.h"
11 #include "x264_gtk_i18n.h"
12 #include "x264_gtk_enum.h"
13
14
15 /* Callbacks */
16 static void _cqm_flat_matrix_cb   (GtkToggleButton *togglebutton,
17                                    gpointer         user_data);
18 static void _cqm_jvt_matrix_cb    (GtkToggleButton *togglebutton,
19                                    gpointer         user_data);
20 static void _cqm_custom_matrix_cb (GtkToggleButton *togglebutton,
21                                    gpointer         user_data);
22 static void _cqm_matrix_file_cb   (GtkFileChooser  *filechooser,
23                                    gint             response,
24                                    gpointer         user_data);
25
26
27 static GtkWidget *_cqm_4x4_page    (X264_Gui_Config *gconfig);
28 static GtkWidget *_cqm_8x8_iy_page (X264_Gui_Config *gconfig);
29 static GtkWidget *_cqm_8x8_py_page (X264_Gui_Config *gconfig);
30
31 GtkWidget *
32 _cqm_page (X264_Gui_Config *gconfig)
33 {
34   GtkWidget   *vbox;
35   GtkWidget   *table;
36   GtkWidget   *notebook;
37   GtkWidget   *chooser;
38   GtkWidget   *label;
39   GtkWidget   *page;
40   GtkTooltips *tooltips;
41
42   tooltips = gtk_tooltips_new ();
43
44   vbox = gtk_vbox_new (FALSE, 0);
45   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
46
47   table = gtk_table_new (4, 2, FALSE);
48   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
49   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
50   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
51   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 6);
52   gtk_widget_show (table);
53
54   gconfig->cqm.radio_flat = gtk_radio_button_new_with_label (NULL, _("Flat matrix"));
55   gtk_tooltips_set_tip (tooltips, gconfig->cqm.radio_flat,
56                         _("Flat matrix - description"),
57                         "");
58   gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.radio_flat,
59                              0, 1, 0, 1);
60   g_signal_connect (G_OBJECT (gconfig->cqm.radio_flat), "toggled",
61                     G_CALLBACK (_cqm_flat_matrix_cb), gconfig);
62   gtk_widget_show (gconfig->cqm.radio_flat);
63
64   gconfig->cqm.radio_jvt = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (gconfig->cqm.radio_flat), _("JVT matrix"));
65   gtk_tooltips_set_tip (tooltips, gconfig->cqm.radio_jvt,
66                         _("JVT matrix - description"),
67                         "");
68   gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.radio_jvt,
69                              0, 1, 1, 2);
70   g_signal_connect (G_OBJECT (gconfig->cqm.radio_jvt), "toggled",
71                     G_CALLBACK (_cqm_jvt_matrix_cb), gconfig);
72   gtk_widget_show (gconfig->cqm.radio_jvt);
73
74   gconfig->cqm.radio_custom = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (gconfig->cqm.radio_flat), _("Custom matrix"));
75   gtk_tooltips_set_tip (tooltips, gconfig->cqm.radio_custom,
76                         _("Custom matrix - description"),
77                         "");
78   gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.radio_custom,
79                              0, 1, 2, 3);
80   g_signal_connect (G_OBJECT (gconfig->cqm.radio_custom), "toggled",
81                     G_CALLBACK (_cqm_custom_matrix_cb), gconfig);
82   gtk_widget_show (gconfig->cqm.radio_custom);
83
84   chooser = gtk_file_chooser_dialog_new(_("Select a file"),
85                                         NULL,
86                                         GTK_FILE_CHOOSER_ACTION_OPEN,
87                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
88                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
89                                         NULL);
90   g_signal_connect (G_OBJECT (chooser), "response",
91                     G_CALLBACK (_cqm_matrix_file_cb), gconfig);
92   gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
93                                        g_get_home_dir ());
94   gconfig->cqm.cqm_file = gtk_file_chooser_button_new_with_dialog (chooser);
95   gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.cqm_file,
96                              1, 2, 2, 3);
97   gtk_widget_show (gconfig->cqm.cqm_file);
98
99   notebook = gtk_notebook_new ();
100   gtk_table_attach_defaults (GTK_TABLE (table), notebook,
101                              0, 2, 3, 4);
102   gtk_widget_show (notebook);
103
104   label = gtk_label_new (_("4x4 quant. matrices"));
105   gtk_widget_show (label);
106
107   page = _cqm_4x4_page (gconfig);
108   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
109   gtk_widget_show (page);
110
111   label = gtk_label_new (_("8x8 I luma quant. matrices"));
112   gtk_widget_show (label);
113
114   page = _cqm_8x8_iy_page (gconfig);
115   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
116   gtk_widget_show (page);
117
118   label = gtk_label_new (_("8x8 P luma quant. matrices"));
119   gtk_widget_show (label);
120
121   page = _cqm_8x8_py_page (gconfig);
122   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
123   gtk_widget_show (page);
124
125   return vbox;
126 }
127
128 static GtkWidget *
129 _cqm_4x4_page   (X264_Gui_Config *gconfig)
130 {
131   GtkWidget     *table;
132   GtkWidget     *misc;
133   GtkWidget     *frame;
134   GtkWidget     *t;
135   GtkRequisition size;
136   gint           i;
137
138   misc = gtk_entry_new_with_max_length (3);
139   gtk_widget_size_request (misc, &size);
140
141   table = gtk_table_new (2, 2, FALSE);
142   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
143   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
144   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
145
146   frame = gtk_frame_new (_("4x4 I luma quant. matrices"));
147   gtk_table_attach_defaults (GTK_TABLE (table), frame,
148                              0, 1, 0, 1);
149   gtk_widget_show (frame);
150
151   t = gtk_table_new (4, 4, FALSE);
152   gtk_table_set_row_spacings (GTK_TABLE (t), 6);
153   gtk_table_set_col_spacings (GTK_TABLE (t), 6);
154   gtk_container_set_border_width (GTK_CONTAINER (t), 6);
155   gtk_container_add (GTK_CONTAINER (frame), t);
156   gtk_widget_show (t);
157
158   for (i = 0; i < 16; i++) {
159     gconfig->cqm.cqm_4iy[i] = gtk_entry_new_with_max_length (3);
160     gtk_widget_set_size_request (gconfig->cqm.cqm_4iy[i], 25, size.height);
161     gtk_table_attach_defaults (GTK_TABLE (t), gconfig->cqm.cqm_4iy[i],
162                                i >> 2, (i >> 2) + 1, i & 3, (i & 3) + 1);
163     gtk_widget_show (gconfig->cqm.cqm_4iy[i]);
164   }
165
166   frame = gtk_frame_new (_("4x4 I chroma quant. matrices"));
167   gtk_table_attach_defaults (GTK_TABLE (table), frame,
168                              0, 1, 1, 2);
169   gtk_widget_show (frame);
170
171   t = gtk_table_new (4, 4, FALSE);
172   gtk_table_set_row_spacings (GTK_TABLE (t), 6);
173   gtk_table_set_col_spacings (GTK_TABLE (t), 6);
174   gtk_container_set_border_width (GTK_CONTAINER (t), 6);
175   gtk_container_add (GTK_CONTAINER (frame), t);
176   gtk_widget_show (t);
177
178   for (i = 0; i < 16; i++) {
179     gconfig->cqm.cqm_4ic[i] = gtk_entry_new_with_max_length (3);
180     gtk_widget_set_size_request (gconfig->cqm.cqm_4ic[i], 25, size.height);
181     gtk_table_attach_defaults (GTK_TABLE (t), gconfig->cqm.cqm_4ic[i],
182                                i >> 2, (i >> 2) + 1, i & 3, (i & 3) + 1);
183     gtk_widget_show (gconfig->cqm.cqm_4ic[i]);
184   }
185
186   frame = gtk_frame_new (_("4x4 P luma quant. matrix"));
187   gtk_table_attach_defaults (GTK_TABLE (table), frame,
188                              1, 2, 0, 1);
189   gtk_widget_show (frame);
190
191   t = gtk_table_new (4, 4, FALSE);
192   gtk_table_set_row_spacings (GTK_TABLE (t), 6);
193   gtk_table_set_col_spacings (GTK_TABLE (t), 6);
194   gtk_container_set_border_width (GTK_CONTAINER (t), 6);
195   gtk_container_add (GTK_CONTAINER (frame), t);
196   gtk_widget_show (t);
197
198   for (i = 0; i < 16; i++) {
199     gconfig->cqm.cqm_4py[i] = gtk_entry_new_with_max_length (3);
200     gtk_widget_set_size_request (gconfig->cqm.cqm_4py[i], 25, size.height);
201     gtk_table_attach_defaults (GTK_TABLE (t), gconfig->cqm.cqm_4py[i],
202                                i >> 2, (i >> 2) + 1, i & 3, (i & 3) + 1);
203     gtk_widget_show (gconfig->cqm.cqm_4py[i]);
204   }
205
206   frame = gtk_frame_new (_("4x4 P chroma quant. matrix"));
207   gtk_table_attach_defaults (GTK_TABLE (table), frame,
208                              1, 2, 1, 2);
209   gtk_widget_show (frame);
210
211   t = gtk_table_new (4, 4, FALSE);
212   gtk_table_set_row_spacings (GTK_TABLE (t), 6);
213   gtk_table_set_col_spacings (GTK_TABLE (t), 6);
214   gtk_container_set_border_width (GTK_CONTAINER (t), 6);
215   gtk_container_add (GTK_CONTAINER (frame), t);
216   gtk_widget_show (t);
217
218   for (i = 0; i < 16; i++) {
219     gconfig->cqm.cqm_4pc[i] = gtk_entry_new_with_max_length (3);
220     gtk_widget_set_size_request (gconfig->cqm.cqm_4pc[i], 25, size.height);
221     gtk_table_attach_defaults (GTK_TABLE (t), gconfig->cqm.cqm_4pc[i],
222                                i >> 2, (i >> 2) + 1, i & 3, (i & 3) + 1);
223     gtk_widget_show (gconfig->cqm.cqm_4pc[i]);
224   }
225
226   return table;
227 }
228
229 static GtkWidget *
230 _cqm_8x8_iy_page (X264_Gui_Config *gconfig)
231 {
232   GtkWidget     *table;
233   GtkWidget     *misc;
234   GtkRequisition size;
235   gint           i;
236
237   misc = gtk_entry_new_with_max_length (3);
238   gtk_widget_size_request (misc, &size);
239
240   table = gtk_table_new (8, 8, FALSE);
241   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
242   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
243   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
244
245   for (i = 0; i < 64; i++) {
246     gconfig->cqm.cqm_8iy[i] = gtk_entry_new_with_max_length (3);
247     gtk_widget_set_size_request (gconfig->cqm.cqm_8iy[i], 25, size.height);
248     gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.cqm_8iy[i],
249                                i >> 3, (i >> 3) + 1, i & 7, (i & 7) + 1);
250     gtk_widget_show (gconfig->cqm.cqm_8iy[i]);
251   }
252
253   return table;
254 }
255
256 static GtkWidget *
257 _cqm_8x8_py_page (X264_Gui_Config *gconfig)
258 {
259   GtkWidget     *table;
260   GtkWidget     *misc;
261   GtkRequisition size;
262   gint           i;
263
264   misc = gtk_entry_new_with_max_length (3);
265   gtk_widget_size_request (misc, &size);
266
267   table = gtk_table_new (8, 8, FALSE);
268   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
269   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
270   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
271
272   for (i = 0; i < 64; i++) {
273     gconfig->cqm.cqm_8py[i] = gtk_entry_new_with_max_length (3);
274     gtk_widget_set_size_request (gconfig->cqm.cqm_8py[i], 25, size.height);
275     gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.cqm_8py[i],
276                                i >> 3, (i >> 3) + 1, i & 7, (i & 7) + 1);
277     gtk_widget_show (gconfig->cqm.cqm_8py[i]);
278   }
279
280   return table;
281 }
282
283 /* Callbacks */
284 static void
285 _cqm_flat_matrix_cb (GtkToggleButton *togglebutton,
286                      gpointer         user_data)
287 {
288   X264_Gui_Config *gconfig;
289
290   gconfig = (X264_Gui_Config *)user_data;
291   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gconfig->cqm.radio_flat))) {
292     gint i;
293
294     gtk_widget_set_sensitive (gconfig->cqm.cqm_file, FALSE);
295     for (i = 0; i < 16; i++) {
296       gtk_widget_set_sensitive (gconfig->cqm.cqm_4iy[i], FALSE);
297       gtk_widget_set_sensitive (gconfig->cqm.cqm_4ic[i], FALSE);
298       gtk_widget_set_sensitive (gconfig->cqm.cqm_4py[i], FALSE);
299       gtk_widget_set_sensitive (gconfig->cqm.cqm_4pc[i], FALSE);
300     }
301     for (i = 0; i < 64; i++) {
302       gtk_widget_set_sensitive (gconfig->cqm.cqm_8iy[i], FALSE);
303       gtk_widget_set_sensitive (gconfig->cqm.cqm_8py[i], FALSE);
304     }
305   }
306 }
307
308 static void
309 _cqm_jvt_matrix_cb (GtkToggleButton *togglebutton,
310                     gpointer         user_data)
311 {
312   X264_Gui_Config *gconfig;
313
314   gconfig = (X264_Gui_Config *)user_data;
315   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gconfig->cqm.radio_jvt))) {
316     gint i;
317
318     gtk_widget_set_sensitive (gconfig->cqm.cqm_file, FALSE);
319     for (i = 0; i < 16; i++) {
320       gtk_widget_set_sensitive (gconfig->cqm.cqm_4iy[i], FALSE);
321       gtk_widget_set_sensitive (gconfig->cqm.cqm_4ic[i], FALSE);
322       gtk_widget_set_sensitive (gconfig->cqm.cqm_4py[i], FALSE);
323       gtk_widget_set_sensitive (gconfig->cqm.cqm_4pc[i], FALSE);
324     }
325     for (i = 0; i < 64; i++) {
326       gtk_widget_set_sensitive (gconfig->cqm.cqm_8iy[i], FALSE);
327       gtk_widget_set_sensitive (gconfig->cqm.cqm_8py[i], FALSE);
328     }
329   }
330 }
331
332 static void
333 _cqm_custom_matrix_cb (GtkToggleButton *togglebutton,
334                        gpointer         user_data)
335 {
336   X264_Gui_Config *gconfig;
337
338   gconfig = (X264_Gui_Config *)user_data;
339   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gconfig->cqm.radio_custom))) {
340     gint i;
341
342     gtk_widget_set_sensitive (gconfig->cqm.cqm_file, TRUE);
343     for (i = 0; i < 16; i++) {
344       gtk_widget_set_sensitive (gconfig->cqm.cqm_4iy[i], TRUE);
345       gtk_widget_set_sensitive (gconfig->cqm.cqm_4ic[i], TRUE);
346       gtk_widget_set_sensitive (gconfig->cqm.cqm_4py[i], TRUE);
347       gtk_widget_set_sensitive (gconfig->cqm.cqm_4pc[i], TRUE);
348     }
349     for (i = 0; i < 64; i++) {
350       gtk_widget_set_sensitive (gconfig->cqm.cqm_8iy[i], TRUE);
351       gtk_widget_set_sensitive (gconfig->cqm.cqm_8py[i], TRUE);
352     }
353   }
354 }
355
356 static gboolean
357 _set_coefs (int size, GtkWidget **entries, GIOChannel *file)
358 {
359   gchar *line;
360   gsize  length;
361   int    i = 0;
362   int    offset = 0;
363
364   while (i < size) {
365     gchar **coefs;
366     int     j;
367
368     if (g_io_channel_read_line (file, &line, &length, NULL, NULL) != G_IO_STATUS_NORMAL) {
369       g_print ("Not a JM custom AVC matrix compliant file\n");
370       return FALSE;
371     }
372     if ((line[0] == '\0') || (line[0] == '\n') || (line[0] == '\r') || (line[0] == '#')) {
373       g_free (line);
374       continue;
375     }
376     coefs = g_strsplit (line, ",", size + 1);
377     for (j = 0; j < size; j++) {
378       gtk_entry_set_text (GTK_ENTRY (entries[offset]), coefs[j]);
379       offset++;
380     }
381     g_strfreev (coefs);
382     g_free (line);
383     i++;
384   }
385   return TRUE;
386 }
387
388 static void
389 _cqm_matrix_file_cb (GtkFileChooser  *filechooser,
390                      gint             response,
391                      gpointer         user_data)
392 {
393   X264_Gui_Config *gconfig;
394   GIOChannel      *file;
395   GError          *error = NULL;
396   gchar           *filename;
397   gchar           *line;
398   gsize            length;
399
400   if (!user_data)
401     return;
402
403   gconfig = (X264_Gui_Config *)user_data;
404
405   filename = gtk_file_chooser_get_filename (filechooser);
406   file = g_io_channel_new_file (filename, "r", &error);
407   if (error) {
408     g_print ("Can not open file %s\n", filename);
409     g_free (filename);
410
411     return;
412   }
413
414   while ((g_io_channel_read_line (file, &line, &length, NULL, NULL) == G_IO_STATUS_NORMAL)) {
415     if (!line) continue;
416     if ((line[0] == '\0') || (line[0] == '\n') || (line[0] == '\r') || (line[0] == '#')) {
417       g_free (line);
418       continue;
419     }
420     if (g_str_has_prefix (line, "INTRA4X4_LUMA")) {
421       g_free (line);
422       if (!_set_coefs (4, gconfig->cqm.cqm_4iy, file)) {
423         g_free (filename);
424         return;
425       }
426       continue;
427     }
428     if (g_str_has_prefix (line, "INTRA4X4_CHROMAU")) {
429       g_free (line);
430       if (!_set_coefs (4, gconfig->cqm.cqm_4ic, file)) {
431         g_free (filename);
432         return;
433       }
434       continue;
435     }
436     if (g_str_has_prefix (line, "INTER4X4_LUMA")) {
437       g_free (line);
438       if (!_set_coefs (4, gconfig->cqm.cqm_4py, file)) {
439         g_free (filename);
440         return;
441       }
442       continue;
443     }
444
445     if (g_str_has_prefix (line, "INTER4X4_CHROMAU")) {
446       g_free (line);
447       if (!_set_coefs (4, gconfig->cqm.cqm_4pc, file)) {
448         g_free (filename);
449         return;
450       }
451       continue;
452     }
453     if (g_str_has_prefix (line, "INTRA8X8_LUMA")) {
454       g_free (line);
455       if (!_set_coefs (8, gconfig->cqm.cqm_8iy, file)) {
456         g_free (filename);
457         return;
458       }
459       continue;
460     }
461     if (g_str_has_prefix (line, "INTER8X8_LUMA")) {
462       g_free (line);
463       if (!_set_coefs (8, gconfig->cqm.cqm_8py, file)) {
464         g_free (filename);
465         return;
466       }
467       continue;
468     }
469   }
470   g_free (filename);
471 }