]> git.sesse.net Git - x264/blob - gtk/x264_gtk_encode_main_window.c
Update file headers throughout x264
[x264] / gtk / x264_gtk_encode_main_window.c
1 /*****************************************************************************
2  * x264_gtk_encode_main_window.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 #include <unistd.h>
27 #ifdef _WIN32 /* Needed to define _O_BINARY */
28 #  include <fcntl.h>
29 #  define strncasecmp _strnicmp
30 #endif
31 #include <errno.h>
32 #include <string.h>
33 #include <sys/stat.h>  /* For stat */
34
35 #include <gtk/gtk.h>
36
37 #include "../x264.h"
38 #include "../config.h"
39 #include "x264_icon.h"
40 #include "x264_gtk.h"
41 #include "x264_gtk_i18n.h"
42 #include "x264_gtk_demuxers.h"
43 #include "x264_gtk_encode_private.h"
44 #include "x264_gtk_encode_encode.h"
45 #include "x264_gtk_encode_status_window.h"
46
47
48 typedef struct X264_Gtk_Encode_ X264_Gtk_Encode;
49
50 struct X264_Gtk_Encode_
51 {
52   GtkWidget         *main_dialog;
53
54   /* input */
55   X264_Demuxer_Type  container;
56   guint64            size; /* For YUV formats */
57   GtkWidget         *file_input;
58   GtkWidget         *width;
59   GtkWidget         *height;
60   GtkWidget         *fps_num;
61   GtkWidget         *fps_den;
62   GtkWidget         *frame_count;
63
64   /* output */
65   GtkWidget         *path_output;
66   GtkWidget         *file_output;
67   GtkWidget         *combo;
68 };
69
70
71 /* Callbacks */
72 static gboolean x264_delete_window_cb    (GtkWidget   *widget,
73                                       GdkEvent    *event,
74                                       gpointer     user_data);
75 static void     x264_configure_window_cb (GtkButton   *button,
76                                       gpointer     user_data);
77 static void     x264_chooser_window_cb   (GtkDialog   *dialog,
78                                       gint         res,
79                                       gpointer     user_data);
80 static void     x264_response_window_cb  (GtkDialog   *dialog,
81                                       gint         res,
82                                       gpointer     user_data);
83 static void     x264_dimension_entry_cb  (GtkEditable *editable,
84                                       gpointer     user_data);
85
86 static gboolean x264_fill_status_window (GIOChannel  *io,
87                                      GIOCondition condition,
88                                      gpointer     user_data);
89 /* Code */
90 guint64
91 x264_file_size(const char* name)
92 {
93   struct stat buf;
94   memset(&buf, 0, sizeof(struct stat));
95
96   if (stat(name, &buf) < 0)
97   {
98     fprintf(stderr, _("Can't stat file\n"));
99     return 0;
100   }
101   return buf.st_size;
102 }
103
104 void
105 x264_gtk_encode_main_window ()
106 {
107   GtkWidget       *dialog;
108   GtkWidget       *frame;
109   GtkWidget       *button;
110   GtkWidget       *table;
111   GtkWidget       *label;
112   GtkFileChooser  *chooser;
113   GtkFileFilter   *filter;
114   GdkPixbuf       *icon;
115   X264_Gtk_Encode *encode;
116
117   encode = (X264_Gtk_Encode *)g_malloc0 (sizeof (X264_Gtk_Encode));
118
119   dialog = gtk_dialog_new_with_buttons (_("X264 Gtk Encoder"),
120                                         NULL, 0,
121                                         NULL);
122   icon = gdk_pixbuf_new_from_inline (-1, x264_icon,
123                                         FALSE, NULL);
124   gtk_window_set_icon (GTK_WINDOW (dialog), icon);
125   g_signal_connect (G_OBJECT (dialog),
126                     "delete-event",
127                     G_CALLBACK (x264_delete_window_cb),
128                     encode);
129   g_signal_connect (G_OBJECT (dialog),
130                     "response",
131                     G_CALLBACK (x264_response_window_cb),
132                     encode);
133   encode->main_dialog = dialog;
134
135   button = gtk_button_new_with_label (_("Configure"));
136   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, FALSE, TRUE, 6);
137   g_signal_connect (G_OBJECT (button),
138                     "clicked",
139                     G_CALLBACK (x264_configure_window_cb),
140                     dialog);
141   gtk_widget_show (button);
142
143   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
144                           GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
145                           GTK_STOCK_EXECUTE, GTK_RESPONSE_APPLY,
146                           NULL);
147
148   /* input */
149   frame = gtk_frame_new (_("Input file"));
150   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame, FALSE, TRUE, 6);
151   gtk_widget_show (frame);
152
153   table = gtk_table_new (6, 2, TRUE);
154   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
155   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
156   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
157   gtk_container_add (GTK_CONTAINER (frame), table);
158   gtk_widget_show (table);
159
160   label = gtk_label_new (_("Input file:"));
161   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
162   gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
163   gtk_widget_show (label);
164
165   chooser = (GtkFileChooser*)
166       gtk_file_chooser_dialog_new(_("Select a file"),
167                                   GTK_WINDOW(dialog),
168                                   GTK_FILE_CHOOSER_ACTION_OPEN,
169                                   GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
170                                   GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
171                                   NULL);
172   gtk_file_chooser_set_current_folder (chooser, g_get_home_dir ());
173    /* All supported */
174   filter = gtk_file_filter_new ();
175   gtk_file_filter_set_name (filter, _("All supported"));
176   gtk_file_filter_add_pattern (filter, "*.yuv");
177   gtk_file_filter_add_pattern (filter, "*.cif");
178   gtk_file_filter_add_pattern (filter, "*.qcif");
179   gtk_file_filter_add_pattern (filter, "*.y4m");
180 #ifdef AVIS_INPUT
181   gtk_file_filter_add_pattern (filter, "*.avs");
182   gtk_file_filter_add_pattern (filter, "*.avi");
183 #endif
184   gtk_file_chooser_add_filter (chooser, filter);
185   /* YUV filter */
186   filter = gtk_file_filter_new ();
187   gtk_file_filter_set_name (filter, _("YUV sequence"));
188   gtk_file_filter_add_pattern (filter, "*.yuv");
189   gtk_file_chooser_add_filter (chooser, filter);
190
191   /* CIF filter */
192   filter = gtk_file_filter_new ();
193   gtk_file_filter_set_name (filter, _("YUV CIF sequence"));
194   gtk_file_filter_add_pattern (filter, "*.cif");
195   gtk_file_chooser_add_filter (chooser, filter);
196
197   /* QCIF filter */
198   filter = gtk_file_filter_new ();
199   gtk_file_filter_set_name (filter, _("YUV QCIF sequence"));
200   gtk_file_filter_add_pattern (filter, "*.qcif");
201   gtk_file_chooser_add_filter (chooser, filter);
202
203   /* YUV4MPEG2 filter */
204   filter = gtk_file_filter_new ();
205   gtk_file_filter_set_name (filter, _("YUV4MPEG2 sequence"));
206   gtk_file_filter_add_pattern (filter, "*.y4m");
207   gtk_file_chooser_add_filter (chooser, filter);
208
209 #ifdef AVIS_INPUT
210   /* AVI filter */
211   filter = gtk_file_filter_new ();
212   gtk_file_filter_set_name (filter, "AVI");
213   gtk_file_filter_add_pattern (filter, "*.avi");
214   gtk_file_chooser_add_filter (chooser, filter);
215   /* AVS filter */
216   filter = gtk_file_filter_new ();
217   gtk_file_filter_set_name (filter, _("Avisynth Script"));
218   gtk_file_filter_add_pattern (filter, "*.avs");
219   gtk_file_chooser_add_filter (chooser, filter);
220 #endif
221   g_signal_connect_after(G_OBJECT (chooser), "response",
222                          G_CALLBACK (x264_chooser_window_cb),
223                          encode);
224   encode->file_input = gtk_file_chooser_button_new_with_dialog (GTK_WIDGET(chooser));
225   gtk_table_attach_defaults (GTK_TABLE (table), encode->file_input, 1, 2, 0, 1);
226   gtk_widget_show (encode->file_input);
227
228   label = gtk_label_new (_("Width:"));
229   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
230   gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2);
231   gtk_widget_show (label);
232
233   encode->width = gtk_entry_new_with_max_length (255);
234   gtk_entry_set_text (GTK_ENTRY (encode->width), "352");
235   g_signal_connect_after(G_OBJECT (encode->width), "changed",
236                    G_CALLBACK (x264_dimension_entry_cb),
237                    encode);
238   gtk_table_attach_defaults (GTK_TABLE (table), encode->width, 1, 2, 1, 2);
239   gtk_widget_show (encode->width);
240
241   label = gtk_label_new (_("Height:"));
242   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
243   gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 2, 3);
244   gtk_widget_show (label);
245
246   encode->height = gtk_entry_new_with_max_length (255);
247   gtk_entry_set_text (GTK_ENTRY (encode->height), "288");
248   gtk_table_attach_defaults (GTK_TABLE (table), encode->height, 1, 2, 2, 3);
249   g_signal_connect_after(G_OBJECT (encode->height), "changed",
250                    G_CALLBACK (x264_dimension_entry_cb),
251                    encode);
252   gtk_widget_show (encode->height);
253
254   label = gtk_label_new (_("Frame rate num:"));
255   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
256   gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 3, 4);
257   gtk_widget_show (label);
258
259   encode->fps_num = gtk_entry_new_with_max_length (255);
260   gtk_entry_set_text (GTK_ENTRY (encode->fps_num), "25");
261   gtk_table_attach_defaults (GTK_TABLE (table), encode->fps_num, 1, 2, 3, 4);
262   gtk_widget_show (encode->fps_num);
263
264   label = gtk_label_new (_("Frame rate den:"));
265   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
266   gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 4, 5);
267   gtk_widget_show (label);
268
269   encode->fps_den = gtk_entry_new_with_max_length (255);
270   gtk_entry_set_text (GTK_ENTRY (encode->fps_den), "1");
271   gtk_table_attach_defaults (GTK_TABLE (table), encode->fps_den, 1, 2, 4, 5);
272   gtk_widget_show (encode->fps_den);
273
274   label = gtk_label_new (_("Frame count:"));
275   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
276   gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 5, 6);
277   gtk_widget_show (label);
278
279   encode->frame_count = gtk_entry_new_with_max_length (255);
280   gtk_entry_set_text (GTK_ENTRY (encode->frame_count), "0");
281   gtk_table_attach_defaults (GTK_TABLE (table), encode->frame_count, 1, 2, 5, 6);
282   gtk_widget_show (encode->frame_count);
283
284   /* output */
285   frame = gtk_frame_new (_("Output file"));
286   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame, FALSE, TRUE, 6);
287   gtk_widget_show (frame);
288
289   table = gtk_table_new (3, 2, TRUE);
290   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
291   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
292   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
293   gtk_container_add (GTK_CONTAINER (frame), table);
294   gtk_widget_show (table);
295
296   label = gtk_label_new (_("Output path:"));
297   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
298   gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
299   gtk_widget_show (label);
300
301   encode->path_output = gtk_file_chooser_button_new (_("Select a path"),
302                                                      GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
303   gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (encode->path_output),
304                                        g_get_home_dir ());
305   gtk_table_attach_defaults (GTK_TABLE (table), encode->path_output, 1, 2, 0, 1);
306   gtk_widget_show (encode->path_output);
307
308   label = gtk_label_new (_("Output file (without ext.):"));
309   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
310   gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2);
311   gtk_widget_show (label);
312
313   encode->file_output = gtk_entry_new_with_max_length (4095);
314   gtk_table_attach_defaults (GTK_TABLE (table), encode->file_output, 1, 2, 1, 2);
315   gtk_widget_show (encode->file_output);
316
317   label = gtk_label_new (_("Container:"));
318   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
319   gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 2, 3);
320   gtk_widget_show (label);
321
322   encode->combo = gtk_combo_box_new_text ();
323   gtk_combo_box_append_text (GTK_COMBO_BOX (encode->combo),
324                              "Raw ES");
325   gtk_combo_box_append_text (GTK_COMBO_BOX (encode->combo),
326                              "Matroska");
327 #ifdef MP4_OUTPUT
328   gtk_combo_box_append_text (GTK_COMBO_BOX (encode->combo),
329                              "Mp4");
330 #endif
331   gtk_table_attach_defaults (GTK_TABLE (table), encode->combo, 1, 2, 2, 3);
332   gtk_widget_show (encode->combo);
333
334   gtk_combo_box_set_active (GTK_COMBO_BOX (encode->combo), 0);
335
336   gtk_widget_show (dialog);
337 }
338
339 /* Callbacks */
340
341 static void
342 x264_encode_shutdown (X264_Gtk_Encode *encode)
343 {
344   if (!encode) return;
345
346   g_free (encode);
347   encode = NULL;
348 }
349
350 static gboolean
351 x264_delete_window_cb (GtkWidget *widget UNUSED,
352                    GdkEvent  *event UNUSED,
353                    gpointer   user_data)
354 {
355   gtk_main_quit ();
356   x264_encode_shutdown ((X264_Gtk_Encode *)user_data);
357
358   return TRUE;
359 }
360
361 static void
362 x264_chooser_window_cb (GtkDialog *dialog,
363                     gint       res,
364                     gpointer   user_data)
365 {
366   X264_Gtk_Encode *encode;
367   gboolean         sensitivity = TRUE;
368   x264_param_t     param;
369   hnd_t            hin;
370   char            *in;
371 #define       BUFFER_LENGTH  64
372   gchar            buffer[BUFFER_LENGTH];
373
374   /* input interface */
375   int              (*p_open_infile)( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
376   int              (*p_get_frame_total)( hnd_t handle );
377   int              (*p_close_infile)( hnd_t handle );
378
379   encode = (X264_Gtk_Encode *)user_data;
380   in = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (encode->file_input));
381   if (!in) return;
382
383   /* Set defaults */
384   p_open_infile = open_file_yuv;
385   p_get_frame_total = get_frame_total_yuv;
386   p_close_infile = close_file_yuv;
387   param.i_width = (gint)(g_ascii_strtod (gtk_entry_get_text (GTK_ENTRY (encode->width)), NULL));
388   param.i_height = (gint)(g_ascii_strtod (gtk_entry_get_text (GTK_ENTRY (encode->height)), NULL));
389   param.i_fps_num = 25;
390   param.i_fps_den = 1;
391   param.i_frame_total = 0;
392
393   switch (res) {
394   case GTK_RESPONSE_OK:
395   case GTK_RESPONSE_ACCEPT:
396   case GTK_RESPONSE_APPLY: {
397     X264_Gtk_Encode  *encode = (X264_Gtk_Encode *)user_data;
398     GSList           *filters;
399     GtkFileFilter    *selected;
400     int               container;
401
402     filters = gtk_file_chooser_list_filters(GTK_FILE_CHOOSER (encode->file_input));
403     selected = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER (encode->file_input));
404     container = g_slist_index(filters, selected);
405     g_slist_free (filters);
406
407     if (container == 0)
408     {
409       /* All format needed, search for extension */
410       const char *ext = strrchr(in, '.');
411       if (!strncasecmp(ext, ".y4m", 4))
412         encode->container = X264_DEMUXER_Y4M;
413       else if (!strncasecmp(ext, ".avs", 4))
414         encode->container = X264_DEMUXER_AVS;
415       else if (!strncasecmp(ext, ".avi", 4))
416         encode->container = X264_DEMUXER_AVI;
417       else if (!strncasecmp(ext, ".cif", 4))
418         encode->container = X264_DEMUXER_CIF;
419       else if (!strncasecmp(ext, ".qcif", 4))
420         encode->container = X264_DEMUXER_QCIF;
421       else
422         encode->container = X264_DEMUXER_YUV;
423     }
424     else
425     {
426       /* The all supproted type is 0 => shift of 1 */
427       encode->container = (X264_Demuxer_Type)container-1;
428     }
429
430     switch (encode->container) {
431     case X264_DEMUXER_YUV: /* YUV */
432       break;
433     case X264_DEMUXER_CIF: /* YUV CIF */
434       param.i_width = 352;
435       param.i_height = 288;
436       break;
437     case X264_DEMUXER_QCIF: /* YUV QCIF */
438       /*   Default input file driver */
439       param.i_width = 176;
440       param.i_height = 144;
441       break;
442     case X264_DEMUXER_Y4M: /* YUV4MPEG */
443       /*   Default input file driver */
444       sensitivity = FALSE;
445       p_open_infile = open_file_y4m;
446       p_get_frame_total = get_frame_total_y4m;
447       p_close_infile = close_file_y4m;
448       break;
449 #ifdef AVIS_INPUT
450     case X264_DEMUXER_AVI: /* AVI */
451     case X264_DEMUXER_AVS: /* AVS */
452       sensitivity = FALSE;
453       p_open_infile = open_file_avis;
454       p_get_frame_total = get_frame_total_avis;
455       p_close_infile = close_file_avis;
456     break;
457 #endif
458     default: /* Unknown */
459       break;
460     }
461     break;
462   }
463   default:
464     break;
465   }
466
467   /* Modify dialog */
468   gtk_widget_set_sensitive(encode->width, sensitivity);
469   gtk_widget_set_sensitive(encode->height, sensitivity);
470   gtk_widget_set_sensitive(encode->fps_num, sensitivity);
471   gtk_widget_set_sensitive(encode->fps_den, sensitivity);
472   gtk_widget_set_sensitive(encode->frame_count, sensitivity);
473
474   /* Inquire input format */
475   if (param.i_width < 2) param.i_width = 352;
476   if (param.i_height < 2) param.i_height = 288;
477   if (p_open_infile (in, &hin, &param) >= 0) {
478     param.i_frame_total = p_get_frame_total(hin);
479     p_close_infile (hin);
480   } else {
481     GtkWidget *dialog_message;
482
483     dialog_message = gtk_message_dialog_new (GTK_WINDOW (dialog),
484                                              GTK_DIALOG_DESTROY_WITH_PARENT,
485                                              GTK_MESSAGE_ERROR,
486                                              GTK_BUTTONS_CLOSE,
487                                              strerror(errno));
488     gtk_dialog_run (GTK_DIALOG (dialog_message));
489     gtk_widget_destroy (dialog_message);
490   }
491   encode->size = x264_file_size(in);
492
493   if (g_snprintf(buffer, BUFFER_LENGTH, "%i", param.i_width) > 0)
494     gtk_entry_set_text (GTK_ENTRY (encode->width), buffer);
495   if (g_snprintf(buffer, BUFFER_LENGTH, "%i", param.i_height) > 0)
496     gtk_entry_set_text (GTK_ENTRY (encode->height), buffer);
497   if (g_snprintf(buffer, BUFFER_LENGTH, "%i", param.i_fps_num) > 0)
498     gtk_entry_set_text (GTK_ENTRY (encode->fps_num), buffer);
499   if (g_snprintf(buffer, BUFFER_LENGTH, "%i", param.i_fps_den) > 0)
500     gtk_entry_set_text (GTK_ENTRY (encode->fps_den), buffer);
501
502   if (g_snprintf(buffer, BUFFER_LENGTH, "%i", param.i_frame_total) > 0)
503     gtk_entry_set_text (GTK_ENTRY (encode->frame_count), buffer);
504 }
505 static void
506 x264_dimension_entry_cb (GtkEditable *editable,
507                      gpointer     user_data)
508 {
509   X264_Gtk_Encode *encode = (X264_Gtk_Encode *)user_data;
510   char             buffer[32];
511   gint             width;
512   gint             height;
513   gint             frame_size;
514
515   width = (gint)(g_ascii_strtod (gtk_entry_get_text (GTK_ENTRY (encode->width)), NULL));
516   height = (gint)(g_ascii_strtod (gtk_entry_get_text (GTK_ENTRY (encode->height)), NULL));
517   frame_size = (3*width*height)/2;
518
519   if (frame_size > 0 && encode->container <= X264_DEMUXER_QCIF)
520   {
521     snprintf(buffer, 32, "%lu", (long unsigned int)((encode->size+frame_size/2)/frame_size));
522     gtk_entry_set_text (GTK_ENTRY (encode->frame_count), buffer);
523   }
524 }
525
526 static void
527 x264_configure_window_cb (GtkButton *button UNUSED,
528                       gpointer   user_data)
529 {
530   GtkWidget *window;
531
532   window = x264_gtk_window_create (GTK_WIDGET (user_data));
533   x264_gtk_shutdown (window);
534 }
535
536 static void
537 x264_response_window_cb (GtkDialog *dialog,
538                      gint       res,
539                      gpointer   user_data)
540 {
541   switch (res) {
542   case GTK_RESPONSE_APPLY: {
543     x264_param_t     *param;
544     X264_Gtk         *x264_gtk;
545     X264_Gtk_Encode  *encode;
546     X264_Thread_Data *thread_data;
547     GtkWidget        *win_status;
548     GThread          *thread;
549     const gchar      *file_input = NULL;
550     const gchar      *path_output = NULL;
551     const gchar      *filename_output = NULL;
552     gchar            *file_output = NULL;
553     gchar            *ext;
554     gint              fds[2];
555     gint              out_container;
556
557     encode = (X264_Gtk_Encode *)user_data;
558     file_input = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (encode->file_input));
559     path_output = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (encode->path_output));
560     filename_output = gtk_entry_get_text (GTK_ENTRY (encode->file_output));
561
562     if (!file_input ||
563         (file_input[0] == '\0')) {
564       GtkWidget *dialog_message;
565
566       dialog_message = gtk_message_dialog_new (GTK_WINDOW (dialog),
567                                                GTK_DIALOG_DESTROY_WITH_PARENT,
568                                                GTK_MESSAGE_ERROR,
569                                                GTK_BUTTONS_CLOSE,
570                                                _("Error: input file name is not set"));
571       gtk_dialog_run (GTK_DIALOG (dialog_message));
572       gtk_widget_destroy (dialog_message);
573       break;
574     }
575
576     if (!filename_output ||
577         (filename_output[0] == '\0')) {
578       GtkWidget *dialog_message;
579
580       dialog_message = gtk_message_dialog_new (GTK_WINDOW (dialog),
581                                                GTK_DIALOG_DESTROY_WITH_PARENT,
582                                                GTK_MESSAGE_ERROR,
583                                                GTK_BUTTONS_CLOSE,
584                                                _("Error: output file name is not set"));
585       gtk_dialog_run (GTK_DIALOG (dialog_message));
586       gtk_widget_destroy (dialog_message);
587       break;
588     }
589
590     out_container = gtk_combo_box_get_active (GTK_COMBO_BOX (encode->combo));
591
592     switch (out_container) {
593     case 1:
594       ext = ".mkv";
595       break;
596 #ifdef MP4_OUTPUT
597     case 2:
598       ext = ".mp4";
599       break;
600 #endif
601     case 0:
602     default:
603       ext = ".264";
604     }
605
606     file_output = g_strconcat (path_output, "/", filename_output, ext, NULL);
607     g_print (_("file output : %s\n"), file_output);
608
609     {
610       GIOChannel *file;
611
612       file = g_io_channel_new_file (file_output, "r", NULL);
613       if (file) {
614         GtkWidget   *dialog_overwrite;
615         GtkWidget   *eb;
616         GtkWidget   *label;
617         const gchar *label_text = NULL;
618         gint         res;
619
620         dialog_overwrite = gtk_dialog_new_with_buttons (_("Existing file"),
621                                                         GTK_WINDOW (dialog),
622                                                         GTK_DIALOG_DESTROY_WITH_PARENT,
623                                                         GTK_STOCK_YES,
624                                                         GTK_RESPONSE_ACCEPT,
625                                                         GTK_STOCK_NO,
626                                                         GTK_RESPONSE_REJECT,
627                                                         NULL);
628
629         eb = gtk_event_box_new ();
630         gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog_overwrite)->vbox), eb);
631         gtk_container_set_border_width (GTK_CONTAINER (eb), 6);
632         gtk_widget_show (eb);
633
634         label_text = g_strconcat (_("Do you want to overwrite file\n"),
635                                   file_output, " ?", NULL);
636         label = gtk_label_new (label_text);
637         gtk_container_add (GTK_CONTAINER (eb), label);
638         gtk_widget_show (label);
639
640         res = gtk_dialog_run (GTK_DIALOG (dialog_overwrite));
641         gtk_widget_destroy (dialog_overwrite);
642         g_io_channel_unref (file);
643         if ((res == GTK_RESPONSE_REJECT) || (res == GTK_RESPONSE_DELETE_EVENT))
644           break;
645       }
646     }
647
648     x264_gtk = x264_gtk_load ();
649     param = x264_gtk_param_get (x264_gtk);
650     x264_gtk_free (x264_gtk);
651
652     {
653       gint width;
654       gint height;
655       gint fps_num;
656       gint fps_den;
657       gint frame_count;
658
659       width = (gint)(g_ascii_strtod (gtk_entry_get_text (GTK_ENTRY (encode->width)), NULL));
660       height = (gint)(g_ascii_strtod (gtk_entry_get_text (GTK_ENTRY (encode->height)), NULL));
661       fps_num = (gint)(g_ascii_strtod (gtk_entry_get_text (GTK_ENTRY (encode->fps_num)), NULL));
662       fps_den = (gint)(g_ascii_strtod (gtk_entry_get_text (GTK_ENTRY (encode->fps_den)), NULL));
663       frame_count = (gint)(g_ascii_strtod (gtk_entry_get_text (GTK_ENTRY (encode->frame_count)), NULL));
664
665       if ((width <= 0) ||
666           (height <= 0) ||
667           (fps_num <= 0) ||
668           (fps_den <= 0) ||
669           (frame_count < 0))
670         break;
671
672       param->i_width = width;
673       param->i_height = height;
674       param->i_fps_num = fps_num;
675       param->i_fps_den = fps_den;
676       param->i_frame_total = frame_count;
677     }
678
679     if (pipe (fds) == -1)
680       break;
681
682     thread_data = (X264_Thread_Data *)g_malloc0 (sizeof (X264_Thread_Data));
683     thread_data->param = param;
684     thread_data->file_input = g_strdup (file_input);
685     thread_data->file_output = g_strdup (file_output);
686     thread_data->in_container = encode->container;
687     thread_data->out_container = out_container;
688     g_free (file_output);
689
690     thread_data->io_read = g_io_channel_unix_new (fds[0]);
691     g_io_channel_set_encoding (thread_data->io_read, NULL, NULL);
692     thread_data->io_write = g_io_channel_unix_new (fds[1]);
693     g_io_channel_set_encoding (thread_data->io_write, NULL, NULL);
694
695     g_io_add_watch (thread_data->io_read, G_IO_IN,
696                     (GIOFunc)x264_fill_status_window, thread_data);
697
698     win_status = x264_gtk_encode_status_window (thread_data);
699     gtk_window_set_transient_for (GTK_WINDOW (win_status), GTK_WINDOW (dialog));
700     gtk_window_set_modal (GTK_WINDOW (win_status), TRUE);
701     gtk_widget_show (win_status);
702     //gtk_widget_hide(thread_data->end_button);
703
704     thread = g_thread_create ((GThreadFunc)x264_gtk_encode_encode, thread_data, FALSE, NULL);
705
706     break;
707   }
708   case GTK_RESPONSE_CLOSE:
709   default:
710     gtk_main_quit ();
711     x264_encode_shutdown ((X264_Gtk_Encode *)user_data);
712   }
713 }
714
715 static gboolean
716 x264_fill_status_window (GIOChannel  *io UNUSED,
717                      GIOCondition condition UNUSED,
718                      gpointer     user_data)
719 {
720   gchar             str[128];
721   X264_Thread_Data *thread_data;
722   X264_Pipe_Data    pipe_data;
723   GIOStatus         status;
724   gsize             size;
725   gint              eta;
726   gdouble           progress;
727   gdouble           fps;
728
729   thread_data = (X264_Thread_Data *)user_data;
730   status = g_io_channel_read_chars (thread_data->io_read,
731                                     (gchar *)&pipe_data,
732                                     sizeof (X264_Pipe_Data),
733                                     &size, NULL);
734   if (status != G_IO_STATUS_NORMAL) {
735     g_print (_("Error ! %d %d %d\n"), status, (int)sizeof (X264_Pipe_Data), (int)size);
736     return FALSE;
737   }
738
739   snprintf (str, 128, "%d/%d", pipe_data.frame, pipe_data.frame_total);
740   gtk_entry_set_text (GTK_ENTRY (thread_data->current_video_frame),
741                       str);
742
743   snprintf (str, 128, _("%dKB"),
744             pipe_data.file >> 10);
745   gtk_entry_set_text (GTK_ENTRY (thread_data->video_data),
746                       str);
747
748   fps = pipe_data.elapsed > 0 ? 1000000.0 * (gdouble)pipe_data.frame / (gdouble)pipe_data.elapsed : 0.0;
749   snprintf (str, 128, _("%.2fKB/s (%.2f fps)"),
750             (double) pipe_data.file * 8 * thread_data->param->i_fps_num /
751             ((double) thread_data->param->i_fps_den * pipe_data.frame * 1000),
752             fps);
753   gtk_entry_set_text (GTK_ENTRY (thread_data->video_rendering_rate),
754                       str);
755
756   snprintf (str, 128, "%lld:%02lld:%02lld",
757             (pipe_data.elapsed / 1000000) / 3600,
758             ((pipe_data.elapsed / 1000000) / 60) % 60,
759             (pipe_data.elapsed / 1000000) % 60);
760   gtk_entry_set_text (GTK_ENTRY (thread_data->time_elapsed),
761                       str);
762
763   eta = pipe_data.elapsed * (pipe_data.frame_total - pipe_data.frame) / ((int64_t)pipe_data.frame * 1000000);
764   snprintf (str, 128, "%d:%02d:%02d", eta / 3600, (eta / 60) % 60, eta % 60);
765   gtk_entry_set_text (GTK_ENTRY (thread_data->time_remaining),
766                       str);
767
768   progress = (gdouble)pipe_data.frame / (gdouble)pipe_data.frame_total;
769   gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (thread_data->progress),
770                                  progress);
771
772   snprintf (str, 128, "%0.1f%%", 100.0 * progress);
773   gtk_progress_bar_set_text (GTK_PROGRESS_BAR (thread_data->progress), str);
774
775   return TRUE;
776 }