2 * simple-encoder.c - Test GstVaapiencoder
4 * Copyright (C) 2015 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
22 #include "gst/vaapi/sysdeps.h"
23 #include <gst/vaapi/gstvaapiencoder_mpeg2.h>
24 #include <gst/vaapi/gstvaapiencoder_h264.h>
25 #include <gst/vaapi/gstvaapisurfacepool.h>
26 #include <gst/vaapi/gstvaapisurfaceproxy.h>
29 #include "y4mreader.h"
31 static guint g_bitrate = 0;
32 static gchar *g_codec_str;
33 static gchar *g_output_file_name;
34 static char **g_input_files = NULL;
36 #define SURFACE_NUM 16
38 static GOptionEntry g_options[] = {
39 {"codec", 'c', 0, G_OPTION_ARG_STRING, &g_codec_str,
40 "codec to use for video encoding (h264/mpeg2)", NULL},
41 {"bitrate", 'b', 0, G_OPTION_ARG_INT, &g_bitrate,
42 "desired bitrate expressed in kbps", NULL},
43 {"output", 'o', 0, G_OPTION_ARG_FILENAME, &g_output_file_name,
44 "output file name", NULL},
45 {G_OPTION_REMAINING, ' ', 0, G_OPTION_ARG_FILENAME_ARRAY, &g_input_files,
46 "input file name", NULL},
52 GstVaapiDisplay *display;
53 GstVaapiEncoder *encoder;
59 guint input_stopped:1;
60 guint encode_failed:1;
64 generate_output_filename (const gchar * ext)
70 fn = g_strdup_printf ("temp%02d.%s", i, ext);
71 if (g_file_test (fn, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
83 parse_options (int *argc, char *argv[])
89 ctx = g_option_context_new (" - encoder test options");
93 g_option_context_add_group (ctx, gst_init_get_option_group ());
94 g_option_context_add_main_entries (ctx, g_options, NULL);
95 g_option_context_set_help_enabled (ctx, TRUE);
96 success = g_option_context_parse (ctx, argc, &argv, &error);
98 g_printerr ("Option parsing failed: %s\n", error->message);
104 g_codec_str = g_strdup ("h264");
105 if (!g_output_file_name)
106 g_output_file_name = generate_output_filename (g_codec_str);
109 g_option_context_free (ctx);
114 print_yuv_info (App * app)
117 g_print ("Encode : %s\n", g_codec_str);
118 g_print ("Resolution : %dx%d\n", app->parser->width, app->parser->height);
119 g_print ("Source YUV : %s\n", g_input_files ? g_input_files[0] : "stdin");
120 g_print ("Frame Rate : %0.1f fps\n",
121 1.0 * app->parser->fps_n / app->parser->fps_d);
122 g_print ("Coded file : %s\n", g_output_file_name);
127 print_num_frame (App * app)
130 g_print ("read frames : %d\n", app->read_frames);
131 g_print ("encoded frames : %d\n", app->encoded_frames);
132 g_print ("saved frames : %d\n", app->saved_frames);
136 static GstVaapiEncoder *
137 encoder_new (GstVaapiDisplay * display)
139 GstVaapiEncoder *encoder = NULL;
141 if (!g_strcmp0 (g_codec_str, "mpeg2"))
142 encoder = gst_vaapi_encoder_mpeg2_new (display);
143 else if (!g_strcmp0 (g_codec_str, "h264"))
144 encoder = gst_vaapi_encoder_h264_new (display);
148 gst_vaapi_encoder_set_bitrate (encoder, g_bitrate);
153 static inline GstVideoCodecState *
154 new_codec_state (gint width, gint height, gint fps_n, gint fps_d)
156 GstVideoCodecState *state;
158 state = g_slice_new0 (GstVideoCodecState);
159 state->ref_count = 1;
160 gst_video_info_set_format (&state->info, GST_VIDEO_FORMAT_ENCODED, width,
163 state->info.fps_n = fps_n;
164 state->info.fps_d = fps_d;
170 set_format (GstVaapiEncoder * encoder, gint width, gint height, gint fps_n,
173 GstVideoCodecState *in_state;
174 GstVaapiEncoderStatus status;
176 in_state = new_codec_state (width, height, fps_n, fps_d);
177 status = gst_vaapi_encoder_set_codec_state (encoder, in_state);
178 g_slice_free (GstVideoCodecState, in_state);
180 return (status == GST_VAAPI_ENCODER_STATUS_SUCCESS);
184 allocate_buffer (GstVaapiCodedBuffer * vbuf)
189 size = gst_vaapi_coded_buffer_get_size (vbuf);
191 g_warning ("Invalid VA buffer size (%zd)", size);
195 buf = gst_buffer_new_and_alloc (size);
197 g_warning ("Failed to create output buffer of size %zd", size);
201 if (!gst_vaapi_coded_buffer_copy_into (buf, vbuf)) {
202 g_warning ("Failed to copy VA buffer data");
203 gst_buffer_unref (buf);
210 static GstVaapiEncoderStatus
211 get_encoder_buffer (GstVaapiEncoder * encoder, GstBuffer ** buffer)
213 GstVaapiCodedBufferProxy *proxy = NULL;
214 GstVaapiEncoderStatus status;
216 status = gst_vaapi_encoder_get_buffer_with_timeout (encoder, &proxy, 50000);
217 if (status < GST_VAAPI_ENCODER_STATUS_SUCCESS) {
218 g_warning ("Failed to get a buffer from encoder: %d", status);
220 } else if (status > GST_VAAPI_ENCODER_STATUS_SUCCESS) {
224 *buffer = allocate_buffer (GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (proxy));
225 gst_vaapi_coded_buffer_proxy_unref (proxy);
231 outputs_to_file (GstBuffer * buffer, FILE * file)
235 gboolean ret = FALSE;
237 if (!gst_buffer_map (buffer, &info, GST_MAP_READ))
240 if (info.size <= 0 || !info.data)
243 written = fwrite (info.data, 1, info.size, file);
244 if (written < info.size) {
245 g_warning ("write file error.");
252 gst_buffer_unmap (buffer, &info);
257 get_buffer_thread (gpointer data)
261 GstVaapiEncoderStatus ret;
266 ret = get_encoder_buffer (app->encoder, &obuf);
267 if (app->input_stopped && ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) {
268 break; /* finished */
269 } else if (ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) { /* another chance */
272 if (ret < GST_VAAPI_ENCODER_STATUS_SUCCESS) { /* fatal error */
273 app->encode_failed = TRUE;
277 app->encoded_frames++;
278 g_debug ("encoded frame %d, buffer = %p", app->encoded_frames, obuf);
280 if (app->output_file && outputs_to_file (obuf, app->output_file))
283 gst_buffer_unref (obuf);
287 gst_buffer_replace (&obuf, NULL);
295 g_return_if_fail (app);
298 y4m_reader_close (app->parser);
301 gst_vaapi_encoder_flush (app->encoder);
302 gst_object_unref (app->encoder);
306 gst_object_unref (app->display);
308 if (app->output_file)
309 fclose (app->output_file);
311 g_slice_free (App, app);
315 app_new (const gchar * input_fn, const gchar * output_fn)
317 App *app = g_slice_new0 (App);
321 app->parser = y4m_reader_open (input_fn);
323 g_warning ("Could not parse input stream.");
327 app->output_file = fopen (output_fn, "w");
328 if (app->output_file == NULL) {
329 g_warning ("Could not open file \"%s\" for writing: %s.", output_fn,
334 app->display = video_output_create_display (NULL);
336 g_warning ("Could not create VA display.");
340 app->encoder = encoder_new (app->display);
342 g_warning ("Could not create encoder.");
346 if (!set_format (app->encoder, app->parser->width, app->parser->height,
347 app->parser->fps_n, app->parser->fps_d)) {
348 g_warning ("Could not set format.");
360 upload_frame (GstVaapiEncoder * encoder, GstVaapiSurfaceProxy * proxy)
362 GstVideoCodecFrame *frame;
363 GstVaapiEncoderStatus ret;
365 frame = g_slice_new0 (GstVideoCodecFrame);
366 gst_video_codec_frame_set_user_data (frame,
367 gst_vaapi_surface_proxy_ref (proxy),
368 (GDestroyNotify) gst_vaapi_surface_proxy_unref);
370 ret = gst_vaapi_encoder_put_frame (encoder, frame);
371 return (ret == GST_VAAPI_ENCODER_STATUS_SUCCESS);
375 load_frame (App * app, GstVaapiImage * image)
377 gboolean ret = FALSE;
379 if (!gst_vaapi_image_map (image))
382 ret = y4m_reader_load_image (app->parser, image);
384 if (!gst_vaapi_image_unmap (image))
393 GstVaapiImage *image;
394 GstVaapiVideoPool *pool;
395 GThread *buffer_thread;
397 int ret = EXIT_FAILURE;
399 image = gst_vaapi_image_new (app->display, GST_VIDEO_FORMAT_I420,
400 app->parser->width, app->parser->height);
404 gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_ENCODED,
405 app->parser->width, app->parser->height);
406 pool = gst_vaapi_surface_pool_new_full (app->display, &vi, 0);
409 buffer_thread = g_thread_new ("get buffer thread", get_buffer_thread, app);
412 GstVaapiSurfaceProxy *proxy;
413 GstVaapiSurface *surface;
415 if (!load_frame (app, image))
418 if (!gst_vaapi_image_unmap (image))
422 gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL (pool));
424 g_warning ("Could not get surface proxy from pool.");
427 surface = gst_vaapi_surface_proxy_get_surface (proxy);
429 g_warning ("Could not get surface from proxy.");
433 if (!gst_vaapi_surface_put_image (surface, image)) {
434 g_warning ("Could not update surface");
438 if (!upload_frame (app->encoder, proxy)) {
439 g_warning ("put frame failed");
444 id = gst_vaapi_surface_get_id (surface);
445 g_debug ("input frame %d, surface id = %" G_GSIZE_FORMAT, app->read_frames,
448 gst_vaapi_surface_proxy_unref (proxy);
451 app->input_stopped = TRUE;
453 g_thread_join (buffer_thread);
455 if (!app->encode_failed && feof (app->parser->fp))
458 gst_vaapi_video_pool_replace (&pool, NULL);
459 gst_vaapi_object_unref (image);
464 main (int argc, char *argv[])
467 int ret = EXIT_FAILURE;
470 if (!parse_options (&argc, argv))
473 /* @TODO: iterate all the input files */
474 input_fn = g_input_files ? g_input_files[0] : NULL;
475 if (input_fn && !g_file_test (input_fn,
476 G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
477 g_warning ("input file \"%s\" doesn't exist", input_fn);
481 app = app_new (input_fn, g_output_file_name);
485 print_yuv_info (app);
487 print_num_frame (app);
492 g_free (g_codec_str);
493 g_free (g_output_file_name);
494 g_strfreev (g_input_files);