1 /*****************************************************************************
2 * x264_gtk_cqm.c: h264 gtk encoder frontend
3 *****************************************************************************
4 * Copyright (C) 2006 Vincent Torri
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.
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.
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 *****************************************************************************/
21 #if defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ || defined __DragonFly__
22 # include <inttypes.h>
30 #include "x264_gtk_private.h"
31 #include "x264_gtk_i18n.h"
32 #include "x264_gtk_enum.h"
36 static void x264_cqm_flat_matrix_cb (GtkToggleButton *togglebutton,
38 static void x264_cqm_jvt_matrix_cb (GtkToggleButton *togglebutton,
40 static void x264_cqm_custom_matrix_cb (GtkToggleButton *togglebutton,
42 static void x264_cqm_matrix_file_cb (GtkFileChooser *filechooser,
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);
52 x264_cqm_page (X264_Gui_Config *gconfig)
60 GtkTooltips *tooltips;
62 tooltips = gtk_tooltips_new ();
64 vbox = gtk_vbox_new (FALSE, 0);
65 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
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);
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"),
78 gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.radio_flat,
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);
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"),
88 gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.radio_jvt,
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);
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"),
98 gtk_table_attach_defaults (GTK_TABLE (table), gconfig->cqm.radio_custom,
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);
104 chooser = gtk_file_chooser_dialog_new(_("Select a file"),
106 GTK_FILE_CHOOSER_ACTION_OPEN,
107 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
108 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
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),
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,
117 gtk_widget_show (gconfig->cqm.cqm_file);
119 notebook = gtk_notebook_new ();
120 gtk_table_attach_defaults (GTK_TABLE (table), notebook,
122 gtk_widget_show (notebook);
124 label = gtk_label_new (_("4x4 quant. matrices"));
125 gtk_widget_show (label);
127 page = x264_cqm_4x4_page (gconfig);
128 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
129 gtk_widget_show (page);
131 label = gtk_label_new (_("8x8 I luma quant. matrices"));
132 gtk_widget_show (label);
134 page = x264_cqm_8x8_iy_page (gconfig);
135 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
136 gtk_widget_show (page);
138 label = gtk_label_new (_("8x8 P luma quant. matrices"));
139 gtk_widget_show (label);
141 page = x264_cqm_8x8_py_page (gconfig);
142 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
143 gtk_widget_show (page);
149 x264_cqm_4x4_page (X264_Gui_Config *gconfig)
158 misc = gtk_entry_new_with_max_length (3);
159 gtk_widget_size_request (misc, &size);
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);
166 frame = gtk_frame_new (_("4x4 I luma quant. matrices"));
167 gtk_table_attach_defaults (GTK_TABLE (table), frame,
169 gtk_widget_show (frame);
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);
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]);
186 frame = gtk_frame_new (_("4x4 I chroma quant. matrices"));
187 gtk_table_attach_defaults (GTK_TABLE (table), frame,
189 gtk_widget_show (frame);
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);
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]);
206 frame = gtk_frame_new (_("4x4 P luma quant. matrix"));
207 gtk_table_attach_defaults (GTK_TABLE (table), frame,
209 gtk_widget_show (frame);
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);
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]);
226 frame = gtk_frame_new (_("4x4 P chroma quant. matrix"));
227 gtk_table_attach_defaults (GTK_TABLE (table), frame,
229 gtk_widget_show (frame);
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);
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]);
250 x264_cqm_8x8_iy_page (X264_Gui_Config *gconfig)
257 misc = gtk_entry_new_with_max_length (3);
258 gtk_widget_size_request (misc, &size);
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);
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]);
277 x264_cqm_8x8_py_page (X264_Gui_Config *gconfig)
284 misc = gtk_entry_new_with_max_length (3);
285 gtk_widget_size_request (misc, &size);
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);
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]);
305 x264_cqm_flat_matrix_cb (GtkToggleButton *togglebutton,
308 X264_Gui_Config *gconfig;
310 gconfig = (X264_Gui_Config *)user_data;
311 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gconfig->cqm.radio_flat))) {
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);
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);
329 x264_cqm_jvt_matrix_cb (GtkToggleButton *togglebutton,
332 X264_Gui_Config *gconfig;
334 gconfig = (X264_Gui_Config *)user_data;
335 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gconfig->cqm.radio_jvt))) {
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);
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);
353 x264_cqm_custom_matrix_cb (GtkToggleButton *togglebutton,
356 X264_Gui_Config *gconfig;
358 gconfig = (X264_Gui_Config *)user_data;
359 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gconfig->cqm.radio_custom))) {
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);
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);
377 x264_set_coefs (int size, GtkWidget **entries, GIOChannel *file)
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");
392 if ((line[0] == '\0') || (line[0] == '\n') || (line[0] == '\r') || (line[0] == '#')) {
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]);
409 x264_cqm_matrix_file_cb (GtkFileChooser *filechooser,
413 X264_Gui_Config *gconfig;
415 GError *error = NULL;
423 gconfig = (X264_Gui_Config *)user_data;
425 filename = gtk_file_chooser_get_filename (filechooser);
426 file = g_io_channel_new_file (filename, "r", &error);
428 g_print ("Can not open file %s\n", filename);
434 while ((g_io_channel_read_line (file, &line, &length, NULL, NULL) == G_IO_STATUS_NORMAL)) {
436 if ((line[0] == '\0') || (line[0] == '\n') || (line[0] == '\r') || (line[0] == '#')) {
440 if (g_str_has_prefix (line, "INTRA4X4_LUMA")) {
442 if (!x264_set_coefs (4, gconfig->cqm.cqm_4iy, file)) {
448 if (g_str_has_prefix (line, "INTRA4X4_CHROMAU")) {
450 if (!x264_set_coefs (4, gconfig->cqm.cqm_4ic, file)) {
456 if (g_str_has_prefix (line, "INTER4X4_LUMA")) {
458 if (!x264_set_coefs (4, gconfig->cqm.cqm_4py, file)) {
465 if (g_str_has_prefix (line, "INTER4X4_CHROMAU")) {
467 if (!x264_set_coefs (4, gconfig->cqm.cqm_4pc, file)) {
473 if (g_str_has_prefix (line, "INTRA8X8_LUMA")) {
475 if (!x264_set_coefs (8, gconfig->cqm.cqm_8iy, file)) {
481 if (g_str_has_prefix (line, "INTER8X8_LUMA")) {
483 if (!x264_set_coefs (8, gconfig->cqm.cqm_8py, file)) {