summaryrefslogtreecommitdiff
path: root/tests/y4mreader.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/y4mreader.c')
-rw-r--r--tests/y4mreader.c261
1 files changed, 261 insertions, 0 deletions
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;
+}