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