diff options
Diffstat (limited to 'tests/y4mreader.c')
-rw-r--r-- | tests/y4mreader.c | 261 |
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; +} |