]> git.sesse.net Git - x264/blob - gtk/x264_gtk_encode_encode.c
GTK: support yuv4mpeg input.
[x264] / gtk / x264_gtk_encode_encode.c
1 #include <string.h>
2 #if defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ || defined __DragonFly__
3 #  include <inttypes.h>
4 #else
5 #  include <stdint.h>
6 #endif
7
8 #include <gtk/gtk.h>
9
10 #include "../x264.h"
11 #include "x264_gtk_demuxers.h"
12 #include "x264_gtk_encode_private.h"
13
14
15 #define DATA_MAX 3000000
16 uint8_t data[DATA_MAX];
17
18 int64_t x264_mdate (void);
19
20 /* input interface */
21 int           (*p_open_infile)( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
22 int           (*p_get_frame_total)( hnd_t handle );
23 int           (*p_read_frame)( x264_picture_t *p_pic, hnd_t handle, int i_frame );
24 int           (*p_close_infile)( hnd_t handle );
25
26 /* output interface */
27 static int (*p_open_outfile)      (char *filename, void **handle);
28 static int (*p_set_outfile_param) (void *handle, x264_param_t *p_param);
29 static int (*p_write_nalu)        (void *handle, uint8_t *p_nal, int i_size);
30 static int (*p_set_eop)           (void *handle, x264_picture_t *p_picture);
31 static int (*p_close_outfile)     (void *handle);
32
33 static int _set_drivers  (X264_Demuxer_Type in_container, gint out_container);
34 static int _encode_frame (x264_t *h, void *handle, x264_picture_t *pic);
35
36
37 gpointer
38 x264_gtk_encode_encode (X264_Thread_Data *thread_data)
39 {
40   GIOStatus       status;
41   gsize           size;
42   X264_Pipe_Data  pipe_data;
43   x264_param_t   *param;
44   x264_picture_t  pic;
45   x264_t         *h;
46   hnd_t           hin;
47   hnd_t           hout;
48   int             i_frame;
49   int             i_frame_total;
50   int64_t         i_start;
51   int64_t         i_end;
52   int64_t         i_file;
53   int             i_frame_size;
54   int             i_progress;
55   int             err;
56
57   g_print ("encoding...\n");
58   param = thread_data->param;
59   err = _set_drivers (thread_data->in_container, thread_data->out_container);
60   if (err < 0) {
61     GtkWidget *no_driver;
62     no_driver = gtk_message_dialog_new (GTK_WINDOW(thread_data->dialog),
63                                         GTK_DIALOG_DESTROY_WITH_PARENT,
64                                         GTK_MESSAGE_ERROR,
65                                         GTK_BUTTONS_CLOSE,
66                                         (err == -2) ? "Error: unknown output file type"
67                                                     : "Error: unknown input file type");
68     gtk_dialog_run (GTK_DIALOG (no_driver));
69     gtk_widget_destroy (no_driver);
70     return NULL;
71   }
72     
73   if (p_open_infile (thread_data->file_input, &hin, param)) {
74     fprintf( stderr, "could not open input file '%s'\n", thread_data->file_input );
75     return NULL;
76   }
77
78   p_open_outfile ((char *)thread_data->file_output, &hout);
79
80   i_frame_total = p_get_frame_total (hin );
81   if (((i_frame_total == 0) || (param->i_frame_total < i_frame_total)) &&
82       (param->i_frame_total > 0))
83     i_frame_total = param->i_frame_total;
84   param->i_frame_total = i_frame_total;
85
86   if ((h = x264_encoder_open (param)) == NULL)
87     {
88       fprintf (stderr, "x264_encoder_open failed\n");
89       p_close_infile (hin);
90       p_close_outfile (hout);
91       g_free (param);
92
93       return NULL;
94     }
95
96   if (p_set_outfile_param (hout, param))
97     {
98       fprintf (stderr, "can't set outfile param\n");
99       p_close_infile (hin);
100       p_close_outfile (hout);
101       g_free (param);
102
103       return NULL;
104     }
105
106   /* Create a new pic */
107   x264_picture_alloc (&pic, X264_CSP_I420, param->i_width, param->i_height );
108
109   i_start = x264_mdate();
110
111   /* Encode frames */
112   for (i_frame = 0, i_file = 0, i_progress = 0;
113        ((i_frame < i_frame_total) || (i_frame_total == 0)); )
114     {
115       if (p_read_frame (&pic, hin, i_frame))
116         break;
117
118       pic.i_pts = (int64_t)i_frame * param->i_fps_den;
119
120       i_file += _encode_frame (h, hout, &pic);
121
122       i_frame++;
123
124       /* update status line (up to 1000 times per input file) */
125       if (param->i_log_level < X264_LOG_DEBUG && 
126           (i_frame_total ? i_frame * 1000 / i_frame_total > i_progress
127            : i_frame % 10 == 0))
128         {
129           int64_t i_elapsed = x264_mdate () - i_start;
130           double fps = i_elapsed > 0 ? i_frame * 1000000. / i_elapsed : 0;
131
132           if (i_frame_total)
133             {
134               pipe_data.frame = i_frame;
135               pipe_data.frame_total = i_frame_total;
136               pipe_data.file = i_file;
137               pipe_data.elapsed = i_elapsed;
138               status = g_io_channel_write_chars (thread_data->io_write,
139                                                  (const gchar *)&pipe_data,
140                                                  sizeof (X264_Pipe_Data),
141                                                  &size, NULL);
142               if (status != G_IO_STATUS_NORMAL) {
143                 g_print ("Error ! %d %d %d\n", status, sizeof (X264_Pipe_Data), size);
144               }
145               else {
146                 /* we force the GIOChannel to write to the pipeline */
147                 status = g_io_channel_flush (thread_data->io_write,
148                                              NULL);
149                 if (status != G_IO_STATUS_NORMAL) {
150                   g_print ("Error ! %d\n", status);
151                 }
152               }
153             }
154           else
155             fprintf( stderr, "encoded frames: %d, %.2f fps   \r", i_frame, fps );
156           fflush( stderr ); /* needed in windows */
157         }
158     }
159   /* Flush delayed B-frames */
160   do {
161     i_file += i_frame_size = _encode_frame (h, hout, NULL);
162   } while (i_frame_size);
163
164   i_end = x264_mdate ();
165   x264_picture_clean (&pic);
166   x264_encoder_close (h);
167   fprintf (stderr, "\n");
168
169   p_close_infile (hin);
170   p_close_outfile (hout);
171
172   if (i_frame > 0) {
173     double fps = (double)i_frame * (double)1000000 /
174       (double)(i_end - i_start);
175
176     fprintf (stderr, "encoded %d frames, %.2f fps, %.2f kb/s\n",
177              i_frame, fps,
178              (double) i_file * 8 * param->i_fps_num /
179              ((double) param->i_fps_den * i_frame * 1000));
180   }
181
182   gtk_widget_set_sensitive (thread_data->end_button, TRUE);
183   gtk_widget_hide (thread_data->button);
184   return NULL;
185 }
186
187 static int
188 _set_drivers (X264_Demuxer_Type in_container, gint out_container)
189 {
190   switch (in_container) {
191   case X264_DEMUXER_YUV:
192   case X264_DEMUXER_CIF:
193   case X264_DEMUXER_QCIF:
194     /*   Default input file driver */
195     p_open_infile = open_file_yuv;
196     p_get_frame_total = get_frame_total_yuv;
197     p_read_frame = read_frame_yuv;
198     p_close_infile = close_file_yuv;
199     break;
200   case X264_DEMUXER_Y4M:
201     p_open_infile = open_file_y4m;
202     p_get_frame_total = get_frame_total_y4m;
203     p_read_frame = read_frame_y4m;
204     p_close_infile = close_file_y4m;
205     break;
206 #ifdef AVIS_INPUT
207   case X264_DEMUXER_AVI:
208   case X264_DEMUXER_AVS:
209     p_open_infile = open_file_avis;
210     p_get_frame_total = get_frame_total_avis;
211     p_read_frame = read_frame_avis;
212     p_close_infile = close_file_avis;
213     break;
214 #endif
215   default: /* Unknown */
216     return -1;
217   }
218
219   switch (out_container) {
220   case 0:
221 /*     Raw ES output file driver */
222     p_open_outfile = open_file_bsf;
223     p_set_outfile_param = set_param_bsf;
224     p_write_nalu = write_nalu_bsf;
225     p_set_eop = set_eop_bsf;
226     p_close_outfile = close_file_bsf;
227     break;
228   case 1:
229 /*     Matroska output file driver */
230     p_open_outfile = open_file_mkv;
231     p_set_outfile_param = set_param_mkv;
232     p_write_nalu = write_nalu_mkv;
233     p_set_eop = set_eop_mkv;
234     p_close_outfile = close_file_mkv;
235     break;
236 #ifdef MP4_OUTPUT
237   case 2:
238     p_open_outfile = open_file_mp4;
239     p_set_outfile_param = set_param_mp4;
240     p_write_nalu = write_nalu_mp4;
241     p_set_eop = set_eop_mp4;
242     p_close_outfile = close_file_mp4;
243     break;
244 #endif
245   default:
246     return -2;
247   }
248
249   return 1;
250 }
251
252 static int
253 _encode_frame (x264_t *h, void *handle, x264_picture_t *pic)
254 {
255   x264_picture_t pic_out;
256   x264_nal_t    *nal;
257   int            i_nal;
258   int            i;
259   int            i_file = 0;
260
261   /* Do not force any parameters */
262   if (pic)
263     {
264       pic->i_type = X264_TYPE_AUTO;
265       pic->i_qpplus1 = 0;
266     }
267   if (x264_encoder_encode (h, &nal, &i_nal, pic, &pic_out) < 0)
268     {
269       fprintf (stderr, "x264_encoder_encode failed\n");
270     }
271
272   for (i = 0; i < i_nal; i++)
273     {
274       int i_size;
275       int i_data;
276
277       i_data = DATA_MAX;
278       if ((i_size = x264_nal_encode (data, &i_data, 1, &nal[i])) > 0 )
279         {
280           i_file += p_write_nalu (handle, data, i_size);
281         }
282       else if (i_size < 0)
283         {
284           fprintf (stderr, "need to increase buffer size (size=%d)\n", -i_size);
285         }
286     }
287   if (i_nal)
288     p_set_eop (handle, &pic_out);
289
290   return i_file;
291 }