76847bb21757b0201e373233ec2ae018ce3d40b3
[platform/upstream/gstreamer.git] / subprojects / gstreamer-vaapi / tests / internal / y4mreader.c
1 /*
2  * y4mreader.c - Y4M parser
3  *
4  * Copyright (C) 2015 Intel Corporation
5  *
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.
10  *
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.
15  *
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
20  */
21
22 #include "gst/vaapi/sysdeps.h"
23 #include "y4mreader.h"
24
25 /* format documentation:
26  * http://wiki.multimedia.cx/index.php?title=YUV4MPEG2 */
27
28 static inline gboolean
29 parse_int (const gchar * str, guint * out_value_ptr)
30 {
31   gint saved_errno;
32   glong value;
33   gboolean ret;
34
35   if (!str)
36     return FALSE;
37   str += 1;
38   if (*str == '\0')
39     return FALSE;
40
41   saved_errno = errno;
42   errno = 0;
43   value = strtol (str, NULL, 0);
44   ret = (errno == 0);
45   errno = saved_errno;
46   if (value > 0 && value <= G_MAXUINT)
47     *out_value_ptr = value;
48   else
49     ret = FALSE;
50
51   return ret;
52 }
53
54 static gboolean
55 parse_header (Y4MReader * file)
56 {
57   gint i, j, b;
58   guint8 header[BUFSIZ];
59   size_t s;
60   gchar *str;
61
62   memset (header, 0, BUFSIZ);
63   s = fread (header, 1, 9, file->fp);
64   if (s < 9)
65     return FALSE;
66
67   if (memcmp (header, "YUV4MPEG2", 9) != 0)
68     return FALSE;
69
70   for (i = 9; i < BUFSIZ - 1; i++) {
71     b = fgetc (file->fp);
72     if (b == EOF)
73       return FALSE;
74     if (b == 0xa)
75       break;
76     header[i] = b;
77   }
78
79   if (i == BUFSIZ - 1)
80     return FALSE;
81
82   j = 9;
83   while (j < i) {
84     if ((header[j] != 0x20) && (header[j - 1] == 0x20)) {
85       switch (header[j]) {
86         case 'W':
87           if (!parse_int ((gchar *) & header[j], &file->width))
88             return FALSE;
89           break;
90         case 'H':
91           if (!parse_int ((gchar *) & header[j], &file->height))
92             return FALSE;
93           break;
94         case 'C':
95           str = (char *) &header[j + 1];
96           if (strncmp (str, "420", 3) != 0) {
97             g_warning ("Unsupported chroma subsampling.");
98             return FALSE;       /* unsupported chroma subsampling */
99           }
100           break;
101         case 'I':
102           str = (char *) &header[j + 1];
103           if (*str != 'p' && *str != '?') {
104             g_warning ("Interlaced content are not supported.");
105             return FALSE;       /* interlaced is unsupported */
106           }
107           break;
108         case 'F':              /* frame rate ratio */
109         {
110           guint num, den;
111
112           if (!parse_int ((gchar *) & header[j], &num))
113             return FALSE;
114           while ((header[j] != ':') && (j < i))
115             j++;
116           if (!parse_int ((gchar *) & header[j], &den))
117             return FALSE;
118
119           if (num <= 0 || den <= 0) {
120             file->fps_n = 30;   /* default to 30 fps */
121             file->fps_d = 1;
122           } else {
123             file->fps_n = num;
124             file->fps_d = den;
125           }
126           break;
127         }
128         case 'A':              /* sample aspect ration */
129           break;
130         case 'X':              /* metadata */
131           break;
132         default:
133           break;
134       }
135     }
136     j++;
137   }
138
139   return TRUE;
140 }
141
142 Y4MReader *
143 y4m_reader_open (const gchar * filename)
144 {
145   Y4MReader *imagefile;
146
147   imagefile = g_slice_new0 (Y4MReader);
148
149   if (filename) {
150     imagefile->fp = fopen (filename, "r");
151     if (!imagefile->fp) {
152       g_warning ("open file %s error", filename);
153       goto bail;
154     }
155   } else {
156     imagefile->fp = stdin;
157   }
158
159   if (!parse_header (imagefile))
160     goto bail;
161
162   return imagefile;
163
164 bail:
165   if (imagefile->fp && imagefile->fp != stdin)
166     fclose (imagefile->fp);
167
168   g_slice_free (Y4MReader, imagefile);
169   return NULL;
170 }
171
172 void
173 y4m_reader_close (Y4MReader * file)
174 {
175   g_return_if_fail (file);
176
177   if (file->fp && file->fp != stdin)
178     fclose (file->fp);
179
180   g_slice_free (Y4MReader, file);
181 }
182
183 static gboolean
184 skip_frame_header (Y4MReader * file)
185 {
186   gint i, b;
187   guint8 header[BUFSIZ];
188   size_t s;
189
190   memset (header, 0, BUFSIZ);
191   s = fread (header, 1, 5, file->fp);
192   if (s < 5)
193     return FALSE;
194
195   if (memcmp (header, "FRAME", 5) != 0)
196     return FALSE;
197
198   for (i = 5; i < BUFSIZ - 1; i++) {
199     b = fgetc (file->fp);
200     if (b == EOF)
201       return FALSE;
202     if (b == 0xa)
203       break;
204     header[i] = b;
205   }
206
207   return (i < BUFSIZ - 1);
208 }
209
210 gboolean
211 y4m_reader_load_image (Y4MReader * file, GstVaapiImage * image)
212 {
213   guint8 *plane;
214   size_t s;
215   guint frame_size, stride, i;
216
217   g_return_val_if_fail (gst_vaapi_image_is_mapped (image), FALSE);
218   g_return_val_if_fail (file && file->fp, FALSE);
219
220   /* only valid for I420 */
221   frame_size = file->height * file->width * 3 / 2;
222   if (gst_vaapi_image_get_data_size (image) < frame_size)
223     return FALSE;
224   if (gst_vaapi_image_get_plane_count (image) != 3)
225     return FALSE;
226
227   if (!skip_frame_header (file))
228     return FALSE;
229
230   /* Y plane */
231   plane = gst_vaapi_image_get_plane (image, 0);
232   stride = gst_vaapi_image_get_pitch (image, 0);
233   for (i = 0; i < file->height; i++) {
234     s = fread (plane, 1, file->width, file->fp);
235     if (s != file->width)
236       return FALSE;
237     plane += stride;
238   }
239
240   /* U plane */
241   plane = gst_vaapi_image_get_plane (image, 1);
242   stride = gst_vaapi_image_get_pitch (image, 1);
243   for (i = 0; i < file->height / 2; i++) {
244     s = fread (plane, 1, file->width / 2, file->fp);
245     if (s != file->width / 2)
246       return FALSE;
247     plane += stride;
248   }
249
250   /* V plane */
251   plane = gst_vaapi_image_get_plane (image, 2);
252   stride = gst_vaapi_image_get_pitch (image, 2);
253   for (i = 0; i < file->height / 2; i++) {
254     s = fread (plane, 1, file->width / 2, file->fp);
255     if (s != file->width / 2)
256       return FALSE;
257     plane += stride;
258   }
259
260   return TRUE;
261 }