]> git.sesse.net Git - x264/blob - gtk/x264_gtk_cqm.c
Update file headers throughout x264
[x264] / gtk / x264_gtk_cqm.c
1 /*****************************************************************************
2  * x264_gtk_cqm.c: h264 gtk encoder frontend
3  *****************************************************************************
4  * Copyright (C) 2006 Vincent Torri
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
19  *****************************************************************************/
20
21 #if defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ || defined __DragonFly__
22 #  include <inttypes.h>
23 #else
24 #  include <stdint.h>
25 #endif
26
27 #include <gtk/gtk.h>
28
29 #include "../x264.h"
30 #include "x264_gtk_private.h"
31 #include "x264_gtk_i18n.h"
32 #include "x264_gtk_enum.h"
33
34
35 /* Callbacks */
36 static void x264_cqm_flat_matrix_cb   (GtkToggleButton *togglebutton,
37                                    gpointer         user_data);
38 static void x264_cqm_jvt_matrix_cb    (GtkToggleButton *togglebutton,
39                                    gpointer         user_data);
40 static void x264_cqm_custom_matrix_cb (GtkToggleButton *togglebutton,
41                                    gpointer         user_data);
42 static void x264_cqm_matrix_file_cb   (GtkFileChooser  *filechooser,
43                                    gint             response,
44                                    gpointer         user_data);
45
46
47 static GtkWidget *x264_cqm_4x4_page    (X264_Gui_Config *gconfig);
48 static GtkWidget *x264_cqm_8x8_iy_page (X264_Gui_Config *gconfig);
49 static GtkWidget *x264_cqm_8x8_py_page (X264_Gui_Config *gconfig);
50
51 GtkWidget *
52 x264_cqm_page (X264_Gui_Config *gconfig)
53 {
54   GtkWidget   *vbox;
55   GtkWidget   *table;
56   GtkWidget   *notebook;
57   GtkWidget   *chooser;
58   GtkWidget   *label;
59   GtkWidget   *page;
60   GtkTooltips *tooltips;
61
62   tooltips = gtk_tooltips_new ();
63
64   vbox = gtk_vbox_new (FALSE, 0);
65   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
66
67   table = gtk_table_new (4, 2, FALSE);
68   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
69   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
70   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
71   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 6);
72   gtk_widget_show (table);
73
74   gconfig->cqm.radio_flat = gtk_radio_button_new_with_label (NULL, _("Flat matrix"));
75   gtk_tooltips_set_tip (tooltips, gconfig->cqm.radio_flat,
76                         _("Flat matrix - description"),
77                         "");
78   gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.radio_flat,
79                              0, 1, 0, 1);
80   g_signal_connect (G_OBJECT (gconfig->cqm.radio_flat), "toggled",
81                     G_CALLBACK (x264_cqm_flat_matrix_cb), gconfig);
82   gtk_widget_show (gconfig->cqm.radio_flat);
83
84   gconfig->cqm.radio_jvt = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (gconfig->cqm.radio_flat), _("JVT matrix"));
85   gtk_tooltips_set_tip (tooltips, gconfig->cqm.radio_jvt,
86                         _("JVT matrix - description"),
87                         "");
88   gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.radio_jvt,
89                              0, 1, 1, 2);
90   g_signal_connect (G_OBJECT (gconfig->cqm.radio_jvt), "toggled",
91                     G_CALLBACK (x264_cqm_jvt_matrix_cb), gconfig);
92   gtk_widget_show (gconfig->cqm.radio_jvt);
93
94   gconfig->cqm.radio_custom = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (gconfig->cqm.radio_flat), _("Custom matrix"));
95   gtk_tooltips_set_tip (tooltips, gconfig->cqm.radio_custom,
96                         _("Custom matrix - description"),
97                         "");
98   gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.radio_custom,
99                              0, 1, 2, 3);
100   g_signal_connect (G_OBJECT (gconfig->cqm.radio_custom), "toggled",
101                     G_CALLBACK (x264_cqm_custom_matrix_cb), gconfig);
102   gtk_widget_show (gconfig->cqm.radio_custom);
103
104   chooser = gtk_file_chooser_dialog_new(_("Select a file"),
105                                         NULL,
106                                         GTK_FILE_CHOOSER_ACTION_OPEN,
107                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
108                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
109                                         NULL);
110   g_signal_connect (G_OBJECT (chooser), "response",
111                     G_CALLBACK (x264_cqm_matrix_file_cb), gconfig);
112   gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
113                                        g_get_home_dir ());
114   gconfig->cqm.cqm_file = gtk_file_chooser_button_new_with_dialog (chooser);
115   gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.cqm_file,
116                              1, 2, 2, 3);
117   gtk_widget_show (gconfig->cqm.cqm_file);
118
119   notebook = gtk_notebook_new ();
120   gtk_table_attach_defaults (GTK_TABLE (table), notebook,
121                              0, 2, 3, 4);
122   gtk_widget_show (notebook);
123
124   label = gtk_label_new (_("4x4 quant. matrices"));
125   gtk_widget_show (label);
126
127   page = x264_cqm_4x4_page (gconfig);
128   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
129   gtk_widget_show (page);
130
131   label = gtk_label_new (_("8x8 I luma quant. matrices"));
132   gtk_widget_show (label);
133
134   page = x264_cqm_8x8_iy_page (gconfig);
135   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
136   gtk_widget_show (page);
137
138   label = gtk_label_new (_("8x8 P luma quant. matrices"));
139   gtk_widget_show (label);
140
141   page = x264_cqm_8x8_py_page (gconfig);
142   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
143   gtk_widget_show (page);
144
145   return vbox;
146 }
147
148 static GtkWidget *
149 x264_cqm_4x4_page   (X264_Gui_Config *gconfig)
150 {
151   GtkWidget     *table;
152   GtkWidget     *misc;
153   GtkWidget     *frame;
154   GtkWidget     *t;
155   GtkRequisition size;
156   gint           i;
157
158   misc = gtk_entry_new_with_max_length (3);
159   gtk_widget_size_request (misc, &size);
160
161   table = gtk_table_new (2, 2, FALSE);
162   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
163   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
164   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
165
166   frame = gtk_frame_new (_("4x4 I luma quant. matrices"));
167   gtk_table_attach_defaults (GTK_TABLE (table), frame,
168                              0, 1, 0, 1);
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_4iy[i] = gtk_entry_new_with_max_length (3);
180     gtk_widget_set_size_request (gconfig->cqm.cqm_4iy[i], 25, size.height);
181     gtk_table_attach_defaults (GTK_TABLE (t), gconfig->cqm.cqm_4iy[i],
182                                i >> 2, (i >> 2) + 1, i & 3, (i & 3) + 1);
183     gtk_widget_show (gconfig->cqm.cqm_4iy[i]);
184   }
185
186   frame = gtk_frame_new (_("4x4 I chroma quant. matrices"));
187   gtk_table_attach_defaults (GTK_TABLE (table), frame,
188                              0, 1, 1, 2);
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_4ic[i] = gtk_entry_new_with_max_length (3);
200     gtk_widget_set_size_request (gconfig->cqm.cqm_4ic[i], 25, size.height);
201     gtk_table_attach_defaults (GTK_TABLE (t), gconfig->cqm.cqm_4ic[i],
202                                i >> 2, (i >> 2) + 1, i & 3, (i & 3) + 1);
203     gtk_widget_show (gconfig->cqm.cqm_4ic[i]);
204   }
205
206   frame = gtk_frame_new (_("4x4 P luma quant. matrix"));
207   gtk_table_attach_defaults (GTK_TABLE (table), frame,
208                              1, 2, 0, 1);
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_4py[i] = gtk_entry_new_with_max_length (3);
220     gtk_widget_set_size_request (gconfig->cqm.cqm_4py[i], 25, size.height);
221     gtk_table_attach_defaults (GTK_TABLE (t), gconfig->cqm.cqm_4py[i],
222                                i >> 2, (i >> 2) + 1, i & 3, (i & 3) + 1);
223     gtk_widget_show (gconfig->cqm.cqm_4py[i]);
224   }
225
226   frame = gtk_frame_new (_("4x4 P chroma quant. matrix"));
227   gtk_table_attach_defaults (GTK_TABLE (table), frame,
228                              1, 2, 1, 2);
229   gtk_widget_show (frame);
230
231   t = gtk_table_new (4, 4, FALSE);
232   gtk_table_set_row_spacings (GTK_TABLE (t), 6);
233   gtk_table_set_col_spacings (GTK_TABLE (t), 6);
234   gtk_container_set_border_width (GTK_CONTAINER (t), 6);
235   gtk_container_add (GTK_CONTAINER (frame), t);
236   gtk_widget_show (t);
237
238   for (i = 0; i < 16; i++) {
239     gconfig->cqm.cqm_4pc[i] = gtk_entry_new_with_max_length (3);
240     gtk_widget_set_size_request (gconfig->cqm.cqm_4pc[i], 25, size.height);
241     gtk_table_attach_defaults (GTK_TABLE (t), gconfig->cqm.cqm_4pc[i],
242                                i >> 2, (i >> 2) + 1, i & 3, (i & 3) + 1);
243     gtk_widget_show (gconfig->cqm.cqm_4pc[i]);
244   }
245
246   return table;
247 }
248
249 static GtkWidget *
250 x264_cqm_8x8_iy_page (X264_Gui_Config *gconfig)
251 {
252   GtkWidget     *table;
253   GtkWidget     *misc;
254   GtkRequisition size;
255   gint           i;
256
257   misc = gtk_entry_new_with_max_length (3);
258   gtk_widget_size_request (misc, &size);
259
260   table = gtk_table_new (8, 8, FALSE);
261   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
262   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
263   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
264
265   for (i = 0; i < 64; i++) {
266     gconfig->cqm.cqm_8iy[i] = gtk_entry_new_with_max_length (3);
267     gtk_widget_set_size_request (gconfig->cqm.cqm_8iy[i], 25, size.height);
268     gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.cqm_8iy[i],
269                                i >> 3, (i >> 3) + 1, i & 7, (i & 7) + 1);
270     gtk_widget_show (gconfig->cqm.cqm_8iy[i]);
271   }
272
273   return table;
274 }
275
276 static GtkWidget *
277 x264_cqm_8x8_py_page (X264_Gui_Config *gconfig)
278 {
279   GtkWidget     *table;
280   GtkWidget     *misc;
281   GtkRequisition size;
282   gint           i;
283
284   misc = gtk_entry_new_with_max_length (3);
285   gtk_widget_size_request (misc, &size);
286
287   table = gtk_table_new (8, 8, FALSE);
288   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
289   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
290   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
291
292   for (i = 0; i < 64; i++) {
293     gconfig->cqm.cqm_8py[i] = gtk_entry_new_with_max_length (3);
294     gtk_widget_set_size_request (gconfig->cqm.cqm_8py[i], 25, size.height);
295     gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.cqm_8py[i],
296                                i >> 3, (i >> 3) + 1, i & 7, (i & 7) + 1);
297     gtk_widget_show (gconfig->cqm.cqm_8py[i]);
298   }
299
300   return table;
301 }
302
303 /* Callbacks */
304 static void
305 x264_cqm_flat_matrix_cb (GtkToggleButton *togglebutton,
306                      gpointer         user_data)
307 {
308   X264_Gui_Config *gconfig;
309
310   gconfig = (X264_Gui_Config *)user_data;
311   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gconfig->cqm.radio_flat))) {
312     gint i;
313
314     gtk_widget_set_sensitive (gconfig->cqm.cqm_file, FALSE);
315     for (i = 0; i < 16; i++) {
316       gtk_widget_set_sensitive (gconfig->cqm.cqm_4iy[i], FALSE);
317       gtk_widget_set_sensitive (gconfig->cqm.cqm_4ic[i], FALSE);
318       gtk_widget_set_sensitive (gconfig->cqm.cqm_4py[i], FALSE);
319       gtk_widget_set_sensitive (gconfig->cqm.cqm_4pc[i], FALSE);
320     }
321     for (i = 0; i < 64; i++) {
322       gtk_widget_set_sensitive (gconfig->cqm.cqm_8iy[i], FALSE);
323       gtk_widget_set_sensitive (gconfig->cqm.cqm_8py[i], FALSE);
324     }
325   }
326 }
327
328 static void
329 x264_cqm_jvt_matrix_cb (GtkToggleButton *togglebutton,
330                     gpointer         user_data)
331 {
332   X264_Gui_Config *gconfig;
333
334   gconfig = (X264_Gui_Config *)user_data;
335   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gconfig->cqm.radio_jvt))) {
336     gint i;
337
338     gtk_widget_set_sensitive (gconfig->cqm.cqm_file, FALSE);
339     for (i = 0; i < 16; i++) {
340       gtk_widget_set_sensitive (gconfig->cqm.cqm_4iy[i], FALSE);
341       gtk_widget_set_sensitive (gconfig->cqm.cqm_4ic[i], FALSE);
342       gtk_widget_set_sensitive (gconfig->cqm.cqm_4py[i], FALSE);
343       gtk_widget_set_sensitive (gconfig->cqm.cqm_4pc[i], FALSE);
344     }
345     for (i = 0; i < 64; i++) {
346       gtk_widget_set_sensitive (gconfig->cqm.cqm_8iy[i], FALSE);
347       gtk_widget_set_sensitive (gconfig->cqm.cqm_8py[i], FALSE);
348     }
349   }
350 }
351
352 static void
353 x264_cqm_custom_matrix_cb (GtkToggleButton *togglebutton,
354                        gpointer         user_data)
355 {
356   X264_Gui_Config *gconfig;
357
358   gconfig = (X264_Gui_Config *)user_data;
359   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gconfig->cqm.radio_custom))) {
360     gint i;
361
362     gtk_widget_set_sensitive (gconfig->cqm.cqm_file, TRUE);
363     for (i = 0; i < 16; i++) {
364       gtk_widget_set_sensitive (gconfig->cqm.cqm_4iy[i], TRUE);
365       gtk_widget_set_sensitive (gconfig->cqm.cqm_4ic[i], TRUE);
366       gtk_widget_set_sensitive (gconfig->cqm.cqm_4py[i], TRUE);
367       gtk_widget_set_sensitive (gconfig->cqm.cqm_4pc[i], TRUE);
368     }
369     for (i = 0; i < 64; i++) {
370       gtk_widget_set_sensitive (gconfig->cqm.cqm_8iy[i], TRUE);
371       gtk_widget_set_sensitive (gconfig->cqm.cqm_8py[i], TRUE);
372     }
373   }
374 }
375
376 static gboolean
377 x264_set_coefs (int size, GtkWidget **entries, GIOChannel *file)
378 {
379   gchar *line;
380   gsize  length;
381   int    i = 0;
382   int    offset = 0;
383
384   while (i < size) {
385     gchar **coefs;
386     int     j;
387
388     if (g_io_channel_read_line (file, &line, &length, NULL, NULL) != G_IO_STATUS_NORMAL) {
389       g_print ("Not a JM custom AVC matrix compliant file\n");
390       return FALSE;
391     }
392     if ((line[0] == '\0') || (line[0] == '\n') || (line[0] == '\r') || (line[0] == '#')) {
393       g_free (line);
394       continue;
395     }
396     coefs = g_strsplit (line, ",", size + 1);
397     for (j = 0; j < size; j++) {
398       gtk_entry_set_text (GTK_ENTRY (entries[offset]), coefs[j]);
399       offset++;
400     }
401     g_strfreev (coefs);
402     g_free (line);
403     i++;
404   }
405   return TRUE;
406 }
407
408 static void
409 x264_cqm_matrix_file_cb (GtkFileChooser  *filechooser,
410                      gint             response,
411                      gpointer         user_data)
412 {
413   X264_Gui_Config *gconfig;
414   GIOChannel      *file;
415   GError          *error = NULL;
416   gchar           *filename;
417   gchar           *line;
418   gsize            length;
419
420   if (!user_data)
421     return;
422
423   gconfig = (X264_Gui_Config *)user_data;
424
425   filename = gtk_file_chooser_get_filename (filechooser);
426   file = g_io_channel_new_file (filename, "r", &error);
427   if (error) {
428     g_print ("Can not open file %s\n", filename);
429     g_free (filename);
430
431     return;
432   }
433
434   while ((g_io_channel_read_line (file, &line, &length, NULL, NULL) == G_IO_STATUS_NORMAL)) {
435     if (!line) continue;
436     if ((line[0] == '\0') || (line[0] == '\n') || (line[0] == '\r') || (line[0] == '#')) {
437       g_free (line);
438       continue;
439     }
440     if (g_str_has_prefix (line, "INTRA4X4_LUMA")) {
441       g_free (line);
442       if (!x264_set_coefs (4, gconfig->cqm.cqm_4iy, file)) {
443         g_free (filename);
444         return;
445       }
446       continue;
447     }
448     if (g_str_has_prefix (line, "INTRA4X4_CHROMAU")) {
449       g_free (line);
450       if (!x264_set_coefs (4, gconfig->cqm.cqm_4ic, file)) {
451         g_free (filename);
452         return;
453       }
454       continue;
455     }
456     if (g_str_has_prefix (line, "INTER4X4_LUMA")) {
457       g_free (line);
458       if (!x264_set_coefs (4, gconfig->cqm.cqm_4py, file)) {
459         g_free (filename);
460         return;
461       }
462       continue;
463     }
464
465     if (g_str_has_prefix (line, "INTER4X4_CHROMAU")) {
466       g_free (line);
467       if (!x264_set_coefs (4, gconfig->cqm.cqm_4pc, file)) {
468         g_free (filename);
469         return;
470       }
471       continue;
472     }
473     if (g_str_has_prefix (line, "INTRA8X8_LUMA")) {
474       g_free (line);
475       if (!x264_set_coefs (8, gconfig->cqm.cqm_8iy, file)) {
476         g_free (filename);
477         return;
478       }
479       continue;
480     }
481     if (g_str_has_prefix (line, "INTER8X8_LUMA")) {
482       g_free (line);
483       if (!x264_set_coefs (8, gconfig->cqm.cqm_8py, file)) {
484         g_free (filename);
485         return;
486       }
487       continue;
488     }
489   }
490   g_free (filename);
491 }