summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/Makefile.am7
-rw-r--r--tests/simple-encoder.c514
-rw-r--r--tests/y4mreader.c261
-rw-r--r--tests/y4mreader.h40
4 files changed, 822 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9b016813..fa1ee3a4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -6,6 +6,7 @@ noinst_PROGRAMS = \
test-surfaces \
test-windows \
test-subpicture \
+ simple-encoder \
$(NULL)
if USE_GLX
@@ -122,6 +123,12 @@ simple_decoder_SOURCES = $(simple_decoder_source_c)
simple_decoder_CFLAGS = $(TEST_CFLAGS) $(GST_VIDEO_CFLAGS)
simple_decoder_LDADD = libutils.la $(TEST_LIBS) $(GST_VIDEO_LIBS)
+simple_encoder_source_c = simple-encoder.c y4mreader.c
+simple_encoder_source_h = y4mreader.h
+simple_encoder_SOURCES = $(simple_encoder_source_c)
+simple_encoder_CFLAGS = $(TEST_CFLAGS) $(GST_VIDEO_CFLAGS)
+simple_encoder_LDADD = libutils.la $(TEST_LIBS) $(GST_VIDEO_LIBS)
+
EXTRA_DIST = \
test-subpicture-data.h \
$(simple_decoder_source_h) \
diff --git a/tests/simple-encoder.c b/tests/simple-encoder.c
new file mode 100644
index 00000000..1a6f32c5
--- /dev/null
+++ b/tests/simple-encoder.c
@@ -0,0 +1,514 @@
+/*
+ * simple-encoder.c - Test GstVaapiencoder
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/vaapi/gstvaapiencoder_mpeg2.h>
+#include <gst/vaapi/gstvaapiencoder_h264.h>
+#include <gst/vaapi/gstvaapisurfacepool.h>
+#include <gst/vaapi/gstvaapisurfaceproxy.h>
+
+#include "output.h"
+#include "y4mreader.h"
+
+static guint g_bitrate = 0;
+static gchar *g_codec_str;
+static gchar *g_output_file_name;
+static char **g_input_files = NULL;
+
+#define SURFACE_NUM 16
+
+static GOptionEntry g_options[] = {
+ {"codec", 'c', 0, G_OPTION_ARG_STRING, &g_codec_str,
+ "codec to use for video encoding (h264/mpeg2)", NULL},
+ {"bitrate", 'b', 0, G_OPTION_ARG_INT, &g_bitrate,
+ "desired bitrate expressed in kbps", NULL},
+ {"output", 'o', 0, G_OPTION_ARG_FILENAME, &g_output_file_name,
+ "output file name", NULL},
+ {G_OPTION_REMAINING, ' ', 0, G_OPTION_ARG_FILENAME_ARRAY, &g_input_files,
+ "input file name", NULL},
+ {NULL}
+};
+
+typedef struct
+{
+ GstVaapiDisplay *display;
+ GstVaapiEncoder *encoder;
+ guint read_frames;
+ guint encoded_frames;
+ guint saved_frames;
+ Y4MReader *parser;
+ FILE *output_file;
+ guint input_stopped:1;
+ guint encode_failed:1;
+} App;
+
+static inline gchar *
+generate_output_filename (const gchar * ext)
+{
+ gchar *fn;
+ int i = 0;
+
+ while (1) {
+ fn = g_strdup_printf ("temp%02d.%s", i, ext);
+ if (g_file_test (fn, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+ i++;
+ g_free (fn);
+ } else {
+ break;
+ }
+ }
+
+ return fn;
+}
+
+static gboolean
+parse_options (int *argc, char *argv[])
+{
+ GOptionContext *ctx;
+ gboolean success;
+ GError *error = NULL;
+
+ ctx = g_option_context_new (" - encoder test options");
+ if (!ctx)
+ return FALSE;
+
+ g_option_context_add_group (ctx, gst_init_get_option_group ());
+ g_option_context_add_main_entries (ctx, g_options, NULL);
+ g_option_context_set_help_enabled (ctx, TRUE);
+ success = g_option_context_parse (ctx, argc, &argv, &error);
+ if (!success) {
+ g_printerr ("Option parsing failed: %s\n", error->message);
+ g_error_free (error);
+ goto bail;
+ }
+
+ if (!g_codec_str)
+ g_codec_str = g_strdup ("h264");
+ if (!g_output_file_name)
+ g_output_file_name = generate_output_filename (g_codec_str);
+
+bail:
+ g_option_context_free (ctx);
+ return success;
+}
+
+static void
+print_yuv_info (App * app)
+{
+ g_print ("\n");
+ g_print ("Encode : %s\n", g_codec_str);
+ g_print ("Resolution : %dx%d\n", app->parser->width, app->parser->height);
+ g_print ("Source YUV : %s\n", g_input_files ? g_input_files[0] : "stdin");
+ g_print ("Frame Rate : %0.1f fps\n",
+ 1.0 * app->parser->fps_n / app->parser->fps_d);
+ g_print ("Coded file : %s\n", g_output_file_name);
+ g_print ("\n");
+}
+
+static void
+print_num_frame (App * app)
+{
+ g_print ("\n");
+ g_print ("read frames : %d\n", app->read_frames);
+ g_print ("encoded frames : %d\n", app->encoded_frames);
+ g_print ("saved frames : %d\n", app->saved_frames);
+ g_print ("\n");
+}
+
+static GstVaapiEncoder *
+encoder_new (GstVaapiDisplay * display)
+{
+ GstVaapiEncoder *encoder = NULL;
+
+ if (!g_strcmp0 (g_codec_str, "mpeg2"))
+ encoder = gst_vaapi_encoder_mpeg2_new (display);
+ else if (!g_strcmp0 (g_codec_str, "h264"))
+ encoder = gst_vaapi_encoder_h264_new (display);
+ else
+ return NULL;
+
+ gst_vaapi_encoder_set_bitrate (encoder, g_bitrate);
+
+ return encoder;
+}
+
+static GstVideoCodecState *
+new_codec_state (gint width, gint height, gint fps_n, gint fps_d)
+{
+ GstVideoCodecState *state;
+
+ state = g_slice_new0 (GstVideoCodecState);
+ state->ref_count = 1;
+ gst_video_info_init (&state->info);
+ gst_video_info_set_format (&state->info, GST_VIDEO_FORMAT_ENCODED, width,
+ height);
+
+ state->info.fps_n = fps_n;
+ state->info.fps_d = fps_d;
+
+ return state;
+}
+
+static gboolean
+set_format (GstVaapiEncoder * encoder, gint width, gint height, gint fps_n,
+ gint fps_d)
+{
+ GstVideoCodecState *in_state;
+ GstVaapiEncoderStatus status;
+ GstCaps *caps;
+
+ if (!g_strcmp0 (g_codec_str, "mpeg2")) {
+ caps = gst_caps_from_string ("video/mpeg");
+ gst_caps_set_simple (caps,
+ "mpegversion", G_TYPE_INT, 2,
+ "systemstream", G_TYPE_BOOLEAN, FALSE,
+ "width", G_TYPE_INT, width,
+ "height", G_TYPE_INT, height,
+ "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
+ } else if (!g_strcmp0 (g_codec_str, "h264")) {
+ caps = gst_caps_new_empty_simple ("video/x-h264");
+ gst_caps_set_simple (caps, "width", G_TYPE_INT, width,
+ "height", G_TYPE_INT, height,
+ "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
+ } else {
+ return FALSE;
+ }
+
+ in_state = new_codec_state (width, height, fps_n, fps_d);
+ status = gst_vaapi_encoder_set_codec_state (encoder, in_state);
+ gst_caps_unref (caps);
+ g_slice_free (GstVideoCodecState, in_state);
+
+ return (status == GST_VAAPI_ENCODER_STATUS_SUCCESS);
+}
+
+static GstBuffer *
+allocate_buffer (GstVaapiCodedBuffer * vbuf)
+{
+ GstBuffer *buf;
+ gssize size;
+
+ size = gst_vaapi_coded_buffer_get_size (vbuf);
+ if (size <= 0) {
+ g_warning ("Invalid VAAPI buffer size (%d)", size);
+ return NULL;
+ }
+
+ buf = gst_buffer_new_and_alloc (size);
+ if (!buf) {
+ g_warning ("Failed to create output buffer of size %d", size);
+ return NULL;
+ }
+
+ if (!gst_vaapi_coded_buffer_copy_into (buf, vbuf)) {
+ g_warning ("Failed to copy VAAPI buffer data");
+ gst_buffer_unref (buf);
+ return NULL;
+ }
+
+ return buf;
+}
+
+static GstVaapiEncoderStatus
+get_encoder_buffer (GstVaapiEncoder * encoder, GstBuffer ** buffer)
+{
+ GstVaapiCodedBufferProxy *proxy = NULL;
+ GstVaapiEncoderStatus status;
+
+ status = gst_vaapi_encoder_get_buffer_with_timeout (encoder, &proxy, 50000);
+ if (status < GST_VAAPI_ENCODER_STATUS_SUCCESS) {
+ g_warning ("Failed to get a buffer from encoder: %d", status);
+ return status;
+ } else if (status > GST_VAAPI_ENCODER_STATUS_SUCCESS) {
+ return status;
+ }
+
+ *buffer = allocate_buffer (GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (proxy));
+ gst_vaapi_coded_buffer_proxy_unref (proxy);
+
+ return status;
+}
+
+static gboolean
+outputs_to_file (GstBuffer * buffer, FILE * file)
+{
+ GstMapInfo info;
+ size_t written;
+ gboolean ret = FALSE;
+
+ gst_buffer_map (buffer, &info, GST_MAP_READ);
+
+ if (info.size <= 0 || !info.data)
+ return FALSE;
+
+ written = fwrite (info.data, 1, info.size, file);
+ if (written < info.size) {
+ g_warning ("write file error.");
+ goto bail;
+ }
+
+ ret = TRUE;
+
+bail:
+ gst_buffer_unmap (buffer, &info);
+ return ret;
+}
+
+static gpointer
+get_buffer_thread (gpointer data)
+{
+ App *app = data;
+
+ GstVaapiEncoderStatus ret;
+ GstBuffer *obuf;
+
+ while (1) {
+ obuf = NULL;
+ ret = get_encoder_buffer (app->encoder, &obuf);
+ if (app->input_stopped && ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) {
+ break; /* finished */
+ } else if (ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) { /* another chance */
+ continue;
+ }
+ if (ret < GST_VAAPI_ENCODER_STATUS_SUCCESS) { /* fatal error */
+ app->encode_failed = TRUE;
+ break;
+ }
+
+ app->encoded_frames++;
+ g_debug ("encoded frame %d, buffer = %p", app->encoded_frames, obuf);
+
+ if (app->output_file && outputs_to_file (obuf, app->output_file))
+ app->saved_frames++;
+
+ gst_buffer_unref (obuf);
+ }
+
+ if (obuf)
+ gst_buffer_replace (&obuf, NULL);
+
+ return NULL;
+}
+
+static void
+app_free (App * app)
+{
+ g_return_if_fail (app);
+
+ if (app->parser)
+ y4m_reader_close (app->parser);
+
+ if (app->encoder) {
+ gst_vaapi_encoder_flush (app->encoder);
+ gst_vaapi_encoder_unref (app->encoder);
+ }
+
+ if (app->display)
+ gst_vaapi_display_unref (app->display);
+
+ if (app->output_file)
+ fclose (app->output_file);
+
+ g_slice_free (App, app);
+}
+
+static App *
+app_new (const gchar * input_fn, const gchar * output_fn)
+{
+ App *app = g_slice_new0 (App);
+ if (!app)
+ return NULL;
+
+ app->parser = y4m_reader_open (input_fn);
+ if (!app->parser) {
+ g_warning ("Could not parse input stream.");
+ goto error;
+ }
+
+ app->output_file = fopen (output_fn, "w");
+ if (app->output_file == NULL) {
+ g_warning ("Could not open file \"%s\" for writing: %s.", output_fn,
+ g_strerror (errno));
+ goto error;
+ }
+
+ app->display = video_output_create_display (NULL);
+ if (!app->display) {
+ g_warning ("Could not create VA display.");
+ goto error;
+ }
+
+ app->encoder = encoder_new (app->display);
+ if (!app->encoder) {
+ g_warning ("Could not create encoder.");
+ goto error;
+ }
+
+ if (!set_format (app->encoder, app->parser->width, app->parser->height,
+ app->parser->fps_n, app->parser->fps_d)) {
+ g_warning ("Could not set format.");
+ goto error;
+ }
+
+ return app;
+
+error:
+ app_free (app);
+ return NULL;
+}
+
+static gboolean
+upload_frame (GstVaapiEncoder * encoder, GstVaapiSurfaceProxy * proxy)
+{
+ GstVideoCodecFrame *frame;
+ GstVaapiEncoderStatus ret;
+
+ frame = g_slice_new0 (GstVideoCodecFrame);
+ gst_video_codec_frame_set_user_data (frame,
+ gst_vaapi_surface_proxy_ref (proxy),
+ (GDestroyNotify) gst_vaapi_surface_proxy_unref);
+
+ ret = gst_vaapi_encoder_put_frame (encoder, frame);
+ return (ret == GST_VAAPI_ENCODER_STATUS_SUCCESS);
+}
+
+static gboolean
+load_frame (App * app, GstVaapiImage * image)
+{
+ gboolean ret = FALSE;
+
+ if (!gst_vaapi_image_map (image))
+ return FALSE;
+
+ ret = y4m_reader_load_image (app->parser, image);
+
+ if (!gst_vaapi_image_unmap (image))
+ return FALSE;
+
+ return ret;
+}
+
+static int
+app_run (App * app)
+{
+ GstVaapiImage *image;
+ GstVaapiVideoPool *pool;
+ GThread *buffer_thread;
+ gsize id;
+ int ret = EXIT_FAILURE;
+
+ image = gst_vaapi_image_new (app->display, GST_VIDEO_FORMAT_I420,
+ app->parser->width, app->parser->height);
+
+ {
+ GstVideoInfo vi;
+ gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_ENCODED,
+ app->parser->width, app->parser->height);
+ pool = gst_vaapi_surface_pool_new_full (app->display, &vi, 0);
+ }
+
+ buffer_thread = g_thread_new ("get buffer thread", get_buffer_thread, app);
+
+ while (1) {
+ if (!load_frame (app, image))
+ break;
+
+ if (!gst_vaapi_image_unmap (image))
+ break;
+
+ GstVaapiSurfaceProxy *proxy =
+ gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL (pool));
+ if (!proxy) {
+ g_warning ("Could not get surface proxy from pool.");
+ break;
+ }
+ GstVaapiSurface *surface = gst_vaapi_surface_proxy_get_surface (proxy);
+ if (!surface) {
+ g_warning ("Could not get surface from proxy.");
+ break;
+ }
+
+ if (!gst_vaapi_surface_put_image (surface, image)) {
+ g_warning ("Could not update surface");
+ break;
+ }
+
+ if (!upload_frame (app->encoder, proxy)) {
+ g_warning ("put frame failed");
+ break;
+ }
+
+ app->read_frames++;
+ id = gst_vaapi_surface_get_id (surface);
+ g_debug ("input frame %d, surface id = %lu", app->read_frames, id);
+
+ gst_vaapi_surface_proxy_unref (proxy);
+ }
+
+ app->input_stopped = TRUE;
+
+ g_thread_join (buffer_thread);
+
+ if (!app->encode_failed && feof (app->parser->fp))
+ ret = EXIT_SUCCESS;
+
+ gst_vaapi_video_pool_replace (&pool, NULL);
+ gst_vaapi_object_unref (image);
+ return ret;
+}
+
+int
+main (int argc, char *argv[])
+{
+ App *app;
+ int ret = EXIT_FAILURE;
+ gchar *input_fn;
+
+ if (!parse_options (&argc, argv))
+ return EXIT_FAILURE;
+
+ /* @TODO: iterate all the input files */
+ input_fn = g_input_files ? g_input_files[0] : NULL;
+ if (input_fn && !g_file_test (input_fn,
+ G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+ g_warning ("input file \"%s\" doesn't exist", input_fn);
+ goto bail;
+ }
+
+ app = app_new (input_fn, g_output_file_name);
+ if (!app)
+ goto bail;
+
+ print_yuv_info (app);
+ ret = app_run (app);
+ print_num_frame (app);
+
+ app_free (app);
+
+bail:
+ g_free (g_codec_str);
+ g_free (g_output_file_name);
+ g_strfreev (g_input_files);
+
+ gst_deinit ();
+
+ return ret;
+}
diff --git a/tests/y4mreader.c b/tests/y4mreader.c
new file mode 100644
index 00000000..aeb1d808
--- /dev/null
+++ b/tests/y4mreader.c
@@ -0,0 +1,261 @@
+/*
+ * y4mreader.c - Y4M parser
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "y4mreader.h"
+
+#include <stdio.h>
+
+/* format documentation:
+ * http://wiki.multimedia.cx/index.php?title=YUV4MPEG2 */
+
+static inline gboolean
+parse_int (const gchar * str, glong * out_value_ptr)
+{
+ gint saved_errno;
+ glong value;
+ gboolean ret;
+
+ if (!str)
+ return FALSE;
+ str += 1;
+ if (!str)
+ return FALSE;
+
+ saved_errno = errno;
+ errno = 0;
+ value = strtol (str, NULL, 0);
+ ret = (errno == 0);
+ errno = saved_errno;
+ *out_value_ptr = value;
+
+ return ret;
+}
+
+static gboolean
+parse_header (Y4MReader * file)
+{
+ gint i, j;
+ guint8 header[BUFSIZ];
+ gint8 b;
+ size_t s;
+ gchar *str;
+
+ memset (header, 0, BUFSIZ);
+ s = fread (header, 1, 9, file->fp);
+ if (s < 9)
+ return FALSE;
+
+ if (memcmp (header, "YUV4MPEG2", 9) != 0)
+ return FALSE;
+
+ for (i = 9; i < BUFSIZ - 1; i++) {
+ b = fgetc (file->fp);
+ if (b == EOF)
+ return FALSE;
+ if (b == 0xa)
+ break;
+ header[i] = b;
+ }
+
+ if (i == BUFSIZ - 1)
+ return FALSE;
+
+ j = 9;
+ while (j < i) {
+ if ((header[j] != 0x20) && (header[j - 1] == 0x20)) {
+ switch (header[j]) {
+ case 'W':
+ if (!parse_int ((gchar *) & header[j], (glong *) & file->width))
+ return FALSE;
+ break;
+ case 'H':
+ if (!parse_int ((gchar *) & header[j], (glong *) & file->height))
+ return FALSE;
+ break;
+ case 'C':
+ str = (char *) &header[j + 1];
+ if (strncmp (str, "420", 3) != 0) {
+ g_warning ("Unsupported chroma subsampling.");
+ return FALSE; /* unsupported chroma subsampling */
+ }
+ break;
+ case 'I':
+ str = (char *) &header[j + 1];
+ if (*str != 'p' && *str != '?') {
+ g_warning ("Interlaced content are not supported.");
+ return FALSE; /* interlaced is unsupported */
+ }
+ break;
+ case 'F': /* frame rate ratio */
+ {
+ guint num, den;
+
+ if (!parse_int ((gchar *) & header[j], (glong *) & num))
+ return FALSE;
+ while ((header[j] != ':') && (j < i))
+ j++;
+ if (!parse_int ((gchar *) & header[j], (glong *) & den))
+ return FALSE;
+
+ if (num <= 0 || den <= 0) {
+ file->fps_n = 30; /* default to 30 fps */
+ file->fps_d = 1;
+ } else {
+ file->fps_n = num;
+ file->fps_d = den;
+ }
+ break;
+ }
+ case 'A': /* sample aspect ration */
+ break;
+ case 'X': /* metadata */
+ break;
+ default:
+ break;
+ }
+ }
+ j++;
+ }
+
+ return TRUE;
+}
+
+Y4MReader *
+y4m_reader_open (const gchar * filename)
+{
+ Y4MReader *imagefile;
+
+ imagefile = g_slice_new0 (Y4MReader);
+
+ if (filename) {
+ imagefile->fp = fopen (filename, "r");
+ if (!imagefile->fp) {
+ g_warning ("open file %s error", filename);
+ goto bail;
+ }
+ } else {
+ imagefile->fp = stdin;
+ }
+
+ if (!parse_header (imagefile))
+ goto bail;
+
+ return imagefile;
+
+bail:
+ if (imagefile->fp && imagefile->fp != stdin)
+ fclose (imagefile->fp);
+
+ g_slice_free (Y4MReader, imagefile);
+ return NULL;
+}
+
+void
+y4m_reader_close (Y4MReader * file)
+{
+ g_return_if_fail (file);
+
+ if (file->fp && file->fp != stdin)
+ fclose (file->fp);
+
+ g_slice_free (Y4MReader, file);
+}
+
+static gboolean
+skip_frame_header (Y4MReader * file)
+{
+ gint i;
+ guint8 header[BUFSIZ];
+ gint8 b;
+ size_t s;
+
+ memset (header, 0, BUFSIZ);
+ s = fread (header, 1, 5, file->fp);
+ if (s < 5)
+ return FALSE;
+
+ if (memcmp (header, "FRAME", 5) != 0)
+ return FALSE;
+
+ for (i = 5; i < BUFSIZ - 1; i++) {
+ b = fgetc (file->fp);
+ if (b == EOF)
+ return FALSE;
+ if (b == 0xa)
+ break;
+ header[i] = b;
+ }
+
+ return (i < BUFSIZ - 1);
+}
+
+gboolean
+y4m_reader_load_image (Y4MReader * file, GstVaapiImage * image)
+{
+ guint8 *plane;
+ size_t s;
+ guint frame_size, stride, i;
+
+ g_return_val_if_fail (gst_vaapi_image_is_mapped (image), FALSE);
+ g_return_val_if_fail (file && file->fp, FALSE);
+
+ /* only valid for I420 */
+ frame_size = file->height * file->width * 3 / 2;
+ if (gst_vaapi_image_get_data_size (image) < frame_size)
+ return FALSE;
+ if (gst_vaapi_image_get_plane_count (image) != 3)
+ return FALSE;
+
+ if (!skip_frame_header (file))
+ return FALSE;
+
+ /* Y plane */
+ plane = gst_vaapi_image_get_plane (image, 0);
+ stride = gst_vaapi_image_get_pitch (image, 0);
+ for (i = 0; i < file->height; i++) {
+ s = fread (plane, 1, file->width, file->fp);
+ if (s != file->width)
+ return FALSE;
+ plane += stride;
+ }
+
+ /* U plane */
+ plane = gst_vaapi_image_get_plane (image, 1);
+ stride = gst_vaapi_image_get_pitch (image, 1);
+ for (i = 0; i < file->height / 2; i++) {
+ s = fread (plane, 1, file->width / 2, file->fp);
+ if (s != file->width / 2)
+ return FALSE;
+ plane += stride;
+ }
+
+ /* V plane */
+ plane = gst_vaapi_image_get_plane (image, 2);
+ stride = gst_vaapi_image_get_pitch (image, 2);
+ for (i = 0; i < file->height / 2; i++) {
+ s = fread (plane, 1, file->width / 2, file->fp);
+ if (s != file->width / 2)
+ return FALSE;
+ plane += stride;
+ }
+
+ return TRUE;
+}
diff --git a/tests/y4mreader.h b/tests/y4mreader.h
new file mode 100644
index 00000000..30d754bc
--- /dev/null
+++ b/tests/y4mreader.h
@@ -0,0 +1,40 @@
+/*
+ * y4mreader.h - Y4M parser
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/vaapi/gstvaapiimage.h>
+
+typedef struct _Y4MReader Y4MReader;
+
+struct _Y4MReader
+{
+ FILE *fp;
+ guint width;
+ guint height;
+ gint fps_n;
+ gint fps_d;
+};
+
+Y4MReader *y4m_reader_open (const gchar * filename);
+
+void y4m_reader_close (Y4MReader * file);
+
+gboolean y4m_reader_load_image (Y4MReader * file, GstVaapiImage * image);