blob: 34ea96d9d57d7f629582bbfa45f2c0afc80a4c19 [file] [log] [blame]
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04001/*
John Koleszarc2140b82010-09-09 08:16:39 -04002 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04003 *
John Koleszar94c52e42010-06-18 12:39:21 -04004 * Use of this source code is governed by a BSD-style license
John Koleszar09202d82010-06-04 16:19:40 -04005 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
John Koleszar94c52e42010-06-18 12:39:21 -04007 * in the file PATENTS. All contributing project authors may
John Koleszar09202d82010-06-04 16:19:40 -04008 * be found in the AUTHORS file in the root of the source tree.
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04009 *
10 * Based on code from the OggTheora software codec source code,
11 * Copyright (C) 2002-2010 The Xiph.Org Foundation and contributors.
12 */
James Zerndf0829f2014-02-12 16:30:43 -080013#include <errno.h>
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040014#include <stdlib.h>
15#include <string.h>
James Zerndf0829f2014-02-12 16:30:43 -080016
17#include "vpx/vpx_integer.h"
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040018#include "y4minput.h"
19
James Zerndf0829f2014-02-12 16:30:43 -080020// Reads 'size' bytes from 'file' into 'buf' with some fault tolerance.
21// Returns true on success.
22static int file_read(void *buf, size_t size, FILE *file) {
23 const int kMaxRetries = 5;
24 int retry_count = 0;
James Zernd5866982014-03-15 12:35:44 -070025 int file_error;
James Zerndf0829f2014-02-12 16:30:43 -080026 size_t len = 0;
27 do {
28 const size_t n = fread((uint8_t*)buf + len, 1, size - len, file);
29 len += n;
James Zernd5866982014-03-15 12:35:44 -070030 file_error = ferror(file);
31 if (file_error) {
James Zerndf0829f2014-02-12 16:30:43 -080032 if (errno == EINTR || errno == EAGAIN) {
James Zerndf0829f2014-02-12 16:30:43 -080033 clearerr(file);
34 continue;
35 } else {
36 fprintf(stderr, "Error reading file: %u of %u bytes read, %d: %s\n",
37 (uint32_t)len, (uint32_t)size, errno, strerror(errno));
38 return 0;
39 }
40 }
James Zernd5866982014-03-15 12:35:44 -070041 } while (!feof(file) && len < size && ++retry_count < kMaxRetries);
42
43 if (!feof(file) && len != size) {
44 fprintf(stderr, "Error reading file: %u of %u bytes read,"
45 " error: %d, retries: %d, %d: %s\n",
46 (uint32_t)len, (uint32_t)size, file_error, retry_count,
47 errno, strerror(errno));
48 }
James Zerndf0829f2014-02-12 16:30:43 -080049 return len == size;
50}
51
John Koleszarc6b90392012-07-13 15:21:29 -070052static int y4m_parse_tags(y4m_input *_y4m, char *_tags) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040053 int got_w;
54 int got_h;
55 int got_fps;
56 int got_interlace;
57 int got_par;
58 int got_chroma;
59 char *p;
60 char *q;
John Koleszarc6b90392012-07-13 15:21:29 -070061 got_w = got_h = got_fps = got_interlace = got_par = got_chroma = 0;
62 for (p = _tags;; p = q) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040063 /*Skip any leading spaces.*/
John Koleszarc6b90392012-07-13 15:21:29 -070064 while (*p == ' ')p++;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040065 /*If that's all we have, stop.*/
John Koleszarc6b90392012-07-13 15:21:29 -070066 if (p[0] == '\0')break;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040067 /*Find the end of this tag.*/
John Koleszarc6b90392012-07-13 15:21:29 -070068 for (q = p + 1; *q != '\0' && *q != ' '; q++);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040069 /*Process the tag.*/
John Koleszarc6b90392012-07-13 15:21:29 -070070 switch (p[0]) {
71 case 'W': {
72 if (sscanf(p + 1, "%d", &_y4m->pic_w) != 1)return -1;
73 got_w = 1;
74 }
75 break;
76 case 'H': {
77 if (sscanf(p + 1, "%d", &_y4m->pic_h) != 1)return -1;
78 got_h = 1;
79 }
80 break;
81 case 'F': {
82 if (sscanf(p + 1, "%d:%d", &_y4m->fps_n, &_y4m->fps_d) != 2) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040083 return -1;
84 }
John Koleszarc6b90392012-07-13 15:21:29 -070085 got_fps = 1;
86 }
87 break;
88 case 'I': {
89 _y4m->interlace = p[1];
90 got_interlace = 1;
91 }
92 break;
93 case 'A': {
94 if (sscanf(p + 1, "%d:%d", &_y4m->par_n, &_y4m->par_d) != 2) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040095 return -1;
96 }
John Koleszarc6b90392012-07-13 15:21:29 -070097 got_par = 1;
98 }
99 break;
100 case 'C': {
101 if (q - p > 16)return -1;
102 memcpy(_y4m->chroma_type, p + 1, q - p - 1);
103 _y4m->chroma_type[q - p - 1] = '\0';
104 got_chroma = 1;
105 }
106 break;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400107 /*Ignore unknown tags.*/
108 }
109 }
John Koleszarc6b90392012-07-13 15:21:29 -0700110 if (!got_w || !got_h || !got_fps)return -1;
111 if (!got_interlace)_y4m->interlace = '?';
112 if (!got_par)_y4m->par_n = _y4m->par_d = 0;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400113 /*Chroma-type is not specified in older files, e.g., those generated by
114 mplayer.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700115 if (!got_chroma)strcpy(_y4m->chroma_type, "420");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400116 return 0;
117}
118
119
120
121/*All anti-aliasing filters in the following conversion functions are based on
122 one of two window functions:
123 The 6-tap Lanczos window (for down-sampling and shifts):
124 sinc(\pi*t)*sinc(\pi*t/3), |t|<3 (sinc(t)==sin(t)/t)
125 0, |t|>=3
126 The 4-tap Mitchell window (for up-sampling):
127 7|t|^3-12|t|^2+16/3, |t|<1
128 -(7/3)|x|^3+12|x|^2-20|x|+32/3, |t|<2
129 0, |t|>=2
130 The number of taps is intentionally kept small to reduce computational
131 overhead and limit ringing.
132
133 The taps from these filters are scaled so that their sum is 1, and the result
134 is scaled by 128 and rounded to integers to create a filter whose
135 intermediate values fit inside 16 bits.
136 Coefficients are rounded in such a way as to ensure their sum is still 128,
137 which is usually equivalent to normal rounding.
138
139 Conversions which require both horizontal and vertical filtering could
140 have these steps pipelined, for less memory consumption and better cache
141 performance, but we do them separately for simplicity.*/
142
143#define OC_MINI(_a,_b) ((_a)>(_b)?(_b):(_a))
144#define OC_MAXI(_a,_b) ((_a)<(_b)?(_b):(_a))
145#define OC_CLAMPI(_a,_b,_c) (OC_MAXI(_a,OC_MINI(_b,_c)))
146
147/*420jpeg chroma samples are sited like:
148 Y-------Y-------Y-------Y-------
149 | | | |
150 | BR | | BR |
151 | | | |
152 Y-------Y-------Y-------Y-------
153 | | | |
154 | | | |
155 | | | |
156 Y-------Y-------Y-------Y-------
157 | | | |
158 | BR | | BR |
159 | | | |
160 Y-------Y-------Y-------Y-------
161 | | | |
162 | | | |
163 | | | |
164
165 420mpeg2 chroma samples are sited like:
166 Y-------Y-------Y-------Y-------
167 | | | |
168 BR | BR |
169 | | | |
170 Y-------Y-------Y-------Y-------
171 | | | |
172 | | | |
173 | | | |
174 Y-------Y-------Y-------Y-------
175 | | | |
176 BR | BR |
177 | | | |
178 Y-------Y-------Y-------Y-------
179 | | | |
180 | | | |
181 | | | |
182
183 We use a resampling filter to shift the site locations one quarter pixel (at
184 the chroma plane's resolution) to the right.
185 The 4:2:2 modes look exactly the same, except there are twice as many chroma
186 lines, and they are vertically co-sited with the luma samples in both the
187 mpeg2 and jpeg cases (thus requiring no vertical resampling).*/
188static void y4m_42xmpeg2_42xjpeg_helper(unsigned char *_dst,
John Koleszarc6b90392012-07-13 15:21:29 -0700189 const unsigned char *_src, int _c_w, int _c_h) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400190 int y;
191 int x;
John Koleszarc6b90392012-07-13 15:21:29 -0700192 for (y = 0; y < _c_h; y++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400193 /*Filter: [4 -17 114 35 -9 1]/128, derived from a 6-tap Lanczos
194 window.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700195 for (x = 0; x < OC_MINI(_c_w, 2); x++) {
196 _dst[x] = (unsigned char)OC_CLAMPI(0, (4 * _src[0] - 17 * _src[OC_MAXI(x - 1, 0)] +
197 114 * _src[x] + 35 * _src[OC_MINI(x + 1, _c_w - 1)] - 9 * _src[OC_MINI(x + 2, _c_w - 1)] +
198 _src[OC_MINI(x + 3, _c_w - 1)] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400199 }
John Koleszarc6b90392012-07-13 15:21:29 -0700200 for (; x < _c_w - 3; x++) {
201 _dst[x] = (unsigned char)OC_CLAMPI(0, (4 * _src[x - 2] - 17 * _src[x - 1] +
202 114 * _src[x] + 35 * _src[x + 1] - 9 * _src[x + 2] + _src[x + 3] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400203 }
John Koleszarc6b90392012-07-13 15:21:29 -0700204 for (; x < _c_w; x++) {
205 _dst[x] = (unsigned char)OC_CLAMPI(0, (4 * _src[x - 2] - 17 * _src[x - 1] +
206 114 * _src[x] + 35 * _src[OC_MINI(x + 1, _c_w - 1)] - 9 * _src[OC_MINI(x + 2, _c_w - 1)] +
207 _src[_c_w - 1] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400208 }
John Koleszarc6b90392012-07-13 15:21:29 -0700209 _dst += _c_w;
210 _src += _c_w;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400211 }
212}
213
214/*Handles both 422 and 420mpeg2 to 422jpeg and 420jpeg, respectively.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700215static void y4m_convert_42xmpeg2_42xjpeg(y4m_input *_y4m, unsigned char *_dst,
216 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400217 int c_w;
218 int c_h;
219 int c_sz;
220 int pli;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400221 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700222 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400223 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700224 c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
225 c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
226 c_sz = c_w * c_h;
227 for (pli = 1; pli < 3; pli++) {
228 y4m_42xmpeg2_42xjpeg_helper(_dst, _aux, c_w, c_h);
229 _dst += c_sz;
230 _aux += c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400231 }
232}
233
234/*This format is only used for interlaced content, but is included for
235 completeness.
236
237 420jpeg chroma samples are sited like:
238 Y-------Y-------Y-------Y-------
239 | | | |
240 | BR | | BR |
241 | | | |
242 Y-------Y-------Y-------Y-------
243 | | | |
244 | | | |
245 | | | |
246 Y-------Y-------Y-------Y-------
247 | | | |
248 | BR | | BR |
249 | | | |
250 Y-------Y-------Y-------Y-------
251 | | | |
252 | | | |
253 | | | |
254
255 420paldv chroma samples are sited like:
256 YR------Y-------YR------Y-------
257 | | | |
258 | | | |
259 | | | |
260 YB------Y-------YB------Y-------
261 | | | |
262 | | | |
263 | | | |
264 YR------Y-------YR------Y-------
265 | | | |
266 | | | |
267 | | | |
268 YB------Y-------YB------Y-------
269 | | | |
270 | | | |
271 | | | |
272
273 We use a resampling filter to shift the site locations one quarter pixel (at
274 the chroma plane's resolution) to the right.
275 Then we use another filter to move the C_r location down one quarter pixel,
276 and the C_b location up one quarter pixel.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700277static void y4m_convert_42xpaldv_42xjpeg(y4m_input *_y4m, unsigned char *_dst,
278 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400279 unsigned char *tmp;
280 int c_w;
281 int c_h;
282 int c_sz;
283 int pli;
284 int y;
285 int x;
286 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700287 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400288 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700289 c_w = (_y4m->pic_w + 1) / 2;
290 c_h = (_y4m->pic_h + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
291 c_sz = c_w * c_h;
292 tmp = _aux + 2 * c_sz;
293 for (pli = 1; pli < 3; pli++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400294 /*First do the horizontal re-sampling.
295 This is the same as the mpeg2 case, except that after the horizontal
296 case, we need to apply a second vertical filter.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700297 y4m_42xmpeg2_42xjpeg_helper(tmp, _aux, c_w, c_h);
298 _aux += c_sz;
299 switch (pli) {
300 case 1: {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400301 /*Slide C_b up a quarter-pel.
302 This is the same filter used above, but in the other order.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700303 for (x = 0; x < c_w; x++) {
304 for (y = 0; y < OC_MINI(c_h, 3); y++) {
305 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (tmp[0]
306 - 9 * tmp[OC_MAXI(y - 2, 0) * c_w] + 35 * tmp[OC_MAXI(y - 1, 0) * c_w]
307 + 114 * tmp[y * c_w] - 17 * tmp[OC_MINI(y + 1, c_h - 1) * c_w]
308 + 4 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400309 }
John Koleszarc6b90392012-07-13 15:21:29 -0700310 for (; y < c_h - 2; y++) {
311 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (tmp[(y - 3) * c_w]
312 - 9 * tmp[(y - 2) * c_w] + 35 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w]
313 - 17 * tmp[(y + 1) * c_w] + 4 * tmp[(y + 2) * c_w] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400314 }
John Koleszarc6b90392012-07-13 15:21:29 -0700315 for (; y < c_h; y++) {
316 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (tmp[(y - 3) * c_w]
317 - 9 * tmp[(y - 2) * c_w] + 35 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w]
318 - 17 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] + 4 * tmp[(c_h - 1) * c_w] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400319 }
320 _dst++;
321 tmp++;
322 }
John Koleszarc6b90392012-07-13 15:21:29 -0700323 _dst += c_sz - c_w;
324 tmp -= c_w;
325 }
326 break;
327 case 2: {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400328 /*Slide C_r down a quarter-pel.
329 This is the same as the horizontal filter.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700330 for (x = 0; x < c_w; x++) {
331 for (y = 0; y < OC_MINI(c_h, 2); y++) {
332 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (4 * tmp[0]
333 - 17 * tmp[OC_MAXI(y - 1, 0) * c_w] + 114 * tmp[y * c_w]
334 + 35 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] - 9 * tmp[OC_MINI(y + 2, c_h - 1) * c_w]
335 + tmp[OC_MINI(y + 3, c_h - 1) * c_w] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400336 }
John Koleszarc6b90392012-07-13 15:21:29 -0700337 for (; y < c_h - 3; y++) {
338 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (4 * tmp[(y - 2) * c_w]
339 - 17 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w] + 35 * tmp[(y + 1) * c_w]
340 - 9 * tmp[(y + 2) * c_w] + tmp[(y + 3) * c_w] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400341 }
John Koleszarc6b90392012-07-13 15:21:29 -0700342 for (; y < c_h; y++) {
343 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (4 * tmp[(y - 2) * c_w]
344 - 17 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w] + 35 * tmp[OC_MINI(y + 1, c_h - 1) * c_w]
345 - 9 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] + tmp[(c_h - 1) * c_w] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400346 }
347 _dst++;
348 tmp++;
349 }
John Koleszarc6b90392012-07-13 15:21:29 -0700350 }
351 break;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400352 }
353 /*For actual interlaced material, this would have to be done separately on
354 each field, and the shift amounts would be different.
355 C_r moves down 1/8, C_b up 3/8 in the top field, and C_r moves down 3/8,
356 C_b up 1/8 in the bottom field.
357 The corresponding filters would be:
358 Down 1/8 (reverse order for up): [3 -11 125 15 -4 0]/128
359 Down 3/8 (reverse order for up): [4 -19 98 56 -13 2]/128*/
360 }
361}
362
363/*Perform vertical filtering to reduce a single plane from 4:2:2 to 4:2:0.
364 This is used as a helper by several converation routines.*/
365static void y4m_422jpeg_420jpeg_helper(unsigned char *_dst,
John Koleszarc6b90392012-07-13 15:21:29 -0700366 const unsigned char *_src, int _c_w, int _c_h) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400367 int y;
368 int x;
369 /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700370 for (x = 0; x < _c_w; x++) {
371 for (y = 0; y < OC_MINI(_c_h, 2); y += 2) {
372 _dst[(y >> 1)*_c_w] = OC_CLAMPI(0, (64 * _src[0]
373 + 78 * _src[OC_MINI(1, _c_h - 1) * _c_w]
374 - 17 * _src[OC_MINI(2, _c_h - 1) * _c_w]
375 + 3 * _src[OC_MINI(3, _c_h - 1) * _c_w] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400376 }
John Koleszarc6b90392012-07-13 15:21:29 -0700377 for (; y < _c_h - 3; y += 2) {
378 _dst[(y >> 1)*_c_w] = OC_CLAMPI(0, (3 * (_src[(y - 2) * _c_w] + _src[(y + 3) * _c_w])
379 - 17 * (_src[(y - 1) * _c_w] + _src[(y + 2) * _c_w])
380 + 78 * (_src[y * _c_w] + _src[(y + 1) * _c_w]) + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400381 }
John Koleszarc6b90392012-07-13 15:21:29 -0700382 for (; y < _c_h; y += 2) {
383 _dst[(y >> 1)*_c_w] = OC_CLAMPI(0, (3 * (_src[(y - 2) * _c_w]
384 + _src[(_c_h - 1) * _c_w]) - 17 * (_src[(y - 1) * _c_w]
385 + _src[OC_MINI(y + 2, _c_h - 1) * _c_w])
386 + 78 * (_src[y * _c_w] + _src[OC_MINI(y + 1, _c_h - 1) * _c_w]) + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400387 }
388 _src++;
389 _dst++;
390 }
391}
392
393/*420jpeg chroma samples are sited like:
394 Y-------Y-------Y-------Y-------
395 | | | |
396 | BR | | BR |
397 | | | |
398 Y-------Y-------Y-------Y-------
399 | | | |
400 | | | |
401 | | | |
402 Y-------Y-------Y-------Y-------
403 | | | |
404 | BR | | BR |
405 | | | |
406 Y-------Y-------Y-------Y-------
407 | | | |
408 | | | |
409 | | | |
410
411 422jpeg chroma samples are sited like:
412 Y---BR--Y-------Y---BR--Y-------
413 | | | |
414 | | | |
415 | | | |
416 Y---BR--Y-------Y---BR--Y-------
417 | | | |
418 | | | |
419 | | | |
420 Y---BR--Y-------Y---BR--Y-------
421 | | | |
422 | | | |
423 | | | |
424 Y---BR--Y-------Y---BR--Y-------
425 | | | |
426 | | | |
427 | | | |
428
429 We use a resampling filter to decimate the chroma planes by two in the
430 vertical direction.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700431static void y4m_convert_422jpeg_420jpeg(y4m_input *_y4m, unsigned char *_dst,
432 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400433 int c_w;
434 int c_h;
435 int c_sz;
436 int dst_c_w;
437 int dst_c_h;
438 int dst_c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400439 int pli;
440 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700441 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400442 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700443 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
444 c_h = _y4m->pic_h;
445 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
446 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
447 c_sz = c_w * c_h;
448 dst_c_sz = dst_c_w * dst_c_h;
449 for (pli = 1; pli < 3; pli++) {
450 y4m_422jpeg_420jpeg_helper(_dst, _aux, c_w, c_h);
451 _aux += c_sz;
452 _dst += dst_c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400453 }
454}
455
456/*420jpeg chroma samples are sited like:
457 Y-------Y-------Y-------Y-------
458 | | | |
459 | BR | | BR |
460 | | | |
461 Y-------Y-------Y-------Y-------
462 | | | |
463 | | | |
464 | | | |
465 Y-------Y-------Y-------Y-------
466 | | | |
467 | BR | | BR |
468 | | | |
469 Y-------Y-------Y-------Y-------
470 | | | |
471 | | | |
472 | | | |
473
474 422 chroma samples are sited like:
475 YBR-----Y-------YBR-----Y-------
476 | | | |
477 | | | |
478 | | | |
479 YBR-----Y-------YBR-----Y-------
480 | | | |
481 | | | |
482 | | | |
483 YBR-----Y-------YBR-----Y-------
484 | | | |
485 | | | |
486 | | | |
487 YBR-----Y-------YBR-----Y-------
488 | | | |
489 | | | |
490 | | | |
491
492 We use a resampling filter to shift the original site locations one quarter
493 pixel (at the original chroma resolution) to the right.
494 Then we use a second resampling filter to decimate the chroma planes by two
495 in the vertical direction.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700496static void y4m_convert_422_420jpeg(y4m_input *_y4m, unsigned char *_dst,
497 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400498 unsigned char *tmp;
499 int c_w;
500 int c_h;
501 int c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400502 int dst_c_h;
503 int dst_c_sz;
504 int pli;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400505 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700506 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400507 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700508 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
509 c_h = _y4m->pic_h;
510 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
511 c_sz = c_w * c_h;
512 dst_c_sz = c_w * dst_c_h;
513 tmp = _aux + 2 * c_sz;
514 for (pli = 1; pli < 3; pli++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400515 /*In reality, the horizontal and vertical steps could be pipelined, for
516 less memory consumption and better cache performance, but we do them
517 separately for simplicity.*/
518 /*First do horizontal filtering (convert to 422jpeg)*/
John Koleszarc6b90392012-07-13 15:21:29 -0700519 y4m_42xmpeg2_42xjpeg_helper(tmp, _aux, c_w, c_h);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400520 /*Now do the vertical filtering.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700521 y4m_422jpeg_420jpeg_helper(_dst, tmp, c_w, c_h);
522 _aux += c_sz;
523 _dst += dst_c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400524 }
525}
526
527/*420jpeg chroma samples are sited like:
528 Y-------Y-------Y-------Y-------
529 | | | |
530 | BR | | BR |
531 | | | |
532 Y-------Y-------Y-------Y-------
533 | | | |
534 | | | |
535 | | | |
536 Y-------Y-------Y-------Y-------
537 | | | |
538 | BR | | BR |
539 | | | |
540 Y-------Y-------Y-------Y-------
541 | | | |
542 | | | |
543 | | | |
544
545 411 chroma samples are sited like:
546 YBR-----Y-------Y-------Y-------
547 | | | |
548 | | | |
549 | | | |
550 YBR-----Y-------Y-------Y-------
551 | | | |
552 | | | |
553 | | | |
554 YBR-----Y-------Y-------Y-------
555 | | | |
556 | | | |
557 | | | |
558 YBR-----Y-------Y-------Y-------
559 | | | |
560 | | | |
561 | | | |
562
563 We use a filter to resample at site locations one eighth pixel (at the source
564 chroma plane's horizontal resolution) and five eighths of a pixel to the
565 right.
566 Then we use another filter to decimate the planes by 2 in the vertical
567 direction.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700568static void y4m_convert_411_420jpeg(y4m_input *_y4m, unsigned char *_dst,
569 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400570 unsigned char *tmp;
571 int c_w;
572 int c_h;
573 int c_sz;
574 int dst_c_w;
575 int dst_c_h;
576 int dst_c_sz;
577 int tmp_sz;
578 int pli;
579 int y;
580 int x;
581 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700582 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400583 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700584 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
585 c_h = _y4m->pic_h;
586 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
587 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
588 c_sz = c_w * c_h;
589 dst_c_sz = dst_c_w * dst_c_h;
590 tmp_sz = dst_c_w * c_h;
591 tmp = _aux + 2 * c_sz;
592 for (pli = 1; pli < 3; pli++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400593 /*In reality, the horizontal and vertical steps could be pipelined, for
594 less memory consumption and better cache performance, but we do them
595 separately for simplicity.*/
596 /*First do horizontal filtering (convert to 422jpeg)*/
John Koleszarc6b90392012-07-13 15:21:29 -0700597 for (y = 0; y < c_h; y++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400598 /*Filters: [1 110 18 -1]/128 and [-3 50 86 -5]/128, both derived from a
599 4-tap Mitchell window.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700600 for (x = 0; x < OC_MINI(c_w, 1); x++) {
601 tmp[x << 1] = (unsigned char)OC_CLAMPI(0, (111 * _aux[0]
602 + 18 * _aux[OC_MINI(1, c_w - 1)] - _aux[OC_MINI(2, c_w - 1)] + 64) >> 7, 255);
603 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(0, (47 * _aux[0]
604 + 86 * _aux[OC_MINI(1, c_w - 1)] - 5 * _aux[OC_MINI(2, c_w - 1)] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400605 }
John Koleszarc6b90392012-07-13 15:21:29 -0700606 for (; x < c_w - 2; x++) {
607 tmp[x << 1] = (unsigned char)OC_CLAMPI(0, (_aux[x - 1] + 110 * _aux[x]
608 + 18 * _aux[x + 1] - _aux[x + 2] + 64) >> 7, 255);
609 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(0, (-3 * _aux[x - 1] + 50 * _aux[x]
610 + 86 * _aux[x + 1] - 5 * _aux[x + 2] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400611 }
John Koleszarc6b90392012-07-13 15:21:29 -0700612 for (; x < c_w; x++) {
613 tmp[x << 1] = (unsigned char)OC_CLAMPI(0, (_aux[x - 1] + 110 * _aux[x]
614 + 18 * _aux[OC_MINI(x + 1, c_w - 1)] - _aux[c_w - 1] + 64) >> 7, 255);
615 if ((x << 1 | 1) < dst_c_w) {
616 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(0, (-3 * _aux[x - 1] + 50 * _aux[x]
617 + 86 * _aux[OC_MINI(x + 1, c_w - 1)] - 5 * _aux[c_w - 1] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400618 }
619 }
John Koleszarc6b90392012-07-13 15:21:29 -0700620 tmp += dst_c_w;
621 _aux += c_w;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400622 }
John Koleszarc6b90392012-07-13 15:21:29 -0700623 tmp -= tmp_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400624 /*Now do the vertical filtering.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700625 y4m_422jpeg_420jpeg_helper(_dst, tmp, dst_c_w, c_h);
626 _dst += dst_c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400627 }
628}
629
630/*Convert 444 to 420jpeg.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700631static void y4m_convert_444_420jpeg(y4m_input *_y4m, unsigned char *_dst,
632 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400633 unsigned char *tmp;
634 int c_w;
635 int c_h;
636 int c_sz;
637 int dst_c_w;
638 int dst_c_h;
639 int dst_c_sz;
640 int tmp_sz;
641 int pli;
642 int y;
643 int x;
644 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700645 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400646 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700647 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
648 c_h = _y4m->pic_h;
649 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
650 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
651 c_sz = c_w * c_h;
652 dst_c_sz = dst_c_w * dst_c_h;
653 tmp_sz = dst_c_w * c_h;
654 tmp = _aux + 2 * c_sz;
655 for (pli = 1; pli < 3; pli++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400656 /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700657 for (y = 0; y < c_h; y++) {
658 for (x = 0; x < OC_MINI(c_w, 2); x += 2) {
659 tmp[x >> 1] = OC_CLAMPI(0, (64 * _aux[0] + 78 * _aux[OC_MINI(1, c_w - 1)]
660 - 17 * _aux[OC_MINI(2, c_w - 1)]
661 + 3 * _aux[OC_MINI(3, c_w - 1)] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400662 }
John Koleszarc6b90392012-07-13 15:21:29 -0700663 for (; x < c_w - 3; x += 2) {
664 tmp[x >> 1] = OC_CLAMPI(0, (3 * (_aux[x - 2] + _aux[x + 3])
665 - 17 * (_aux[x - 1] + _aux[x + 2]) + 78 * (_aux[x] + _aux[x + 1]) + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400666 }
John Koleszarc6b90392012-07-13 15:21:29 -0700667 for (; x < c_w; x += 2) {
668 tmp[x >> 1] = OC_CLAMPI(0, (3 * (_aux[x - 2] + _aux[c_w - 1]) -
669 17 * (_aux[x - 1] + _aux[OC_MINI(x + 2, c_w - 1)]) +
670 78 * (_aux[x] + _aux[OC_MINI(x + 1, c_w - 1)]) + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400671 }
John Koleszarc6b90392012-07-13 15:21:29 -0700672 tmp += dst_c_w;
673 _aux += c_w;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400674 }
John Koleszarc6b90392012-07-13 15:21:29 -0700675 tmp -= tmp_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400676 /*Now do the vertical filtering.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700677 y4m_422jpeg_420jpeg_helper(_dst, tmp, dst_c_w, c_h);
678 _dst += dst_c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400679 }
680}
681
682/*The image is padded with empty chroma components at 4:2:0.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700683static void y4m_convert_mono_420jpeg(y4m_input *_y4m, unsigned char *_dst,
684 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400685 int c_sz;
Yaowu Xu618e7ef2014-07-11 16:27:21 -0700686 (void)_aux;
John Koleszarc6b90392012-07-13 15:21:29 -0700687 _dst += _y4m->pic_w * _y4m->pic_h;
688 c_sz = ((_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h) *
689 ((_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v);
690 memset(_dst, 128, c_sz * 2);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400691}
692
693/*No conversion function needed.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700694static void y4m_convert_null(y4m_input *_y4m, unsigned char *_dst,
695 unsigned char *_aux) {
Yaowu Xu618e7ef2014-07-11 16:27:21 -0700696 (void)_y4m;
697 (void)_dst;
698 (void)_aux;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400699}
700
John Koleszar8dd82872013-05-06 11:01:35 -0700701int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip,
702 int only_420) {
Jim Bankoski75eb3af2014-08-19 11:47:26 -0700703 char buffer[80] = {0};
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400704 int ret;
705 int i;
706 /*Read until newline, or 80 cols, whichever happens first.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700707 for (i = 0; i < 79; i++) {
708 if (_nskip > 0) {
709 buffer[i] = *_skip++;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400710 _nskip--;
John Koleszarc6b90392012-07-13 15:21:29 -0700711 } else {
James Zerndf0829f2014-02-12 16:30:43 -0800712 if (!file_read(buffer + i, 1, _fin)) return -1;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400713 }
John Koleszarc6b90392012-07-13 15:21:29 -0700714 if (buffer[i] == '\n')break;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400715 }
716 /*We skipped too much header data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700717 if (_nskip > 0)return -1;
718 if (i == 79) {
719 fprintf(stderr, "Error parsing header; not a YUV2MPEG2 file?\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400720 return -1;
721 }
John Koleszarc6b90392012-07-13 15:21:29 -0700722 buffer[i] = '\0';
723 if (memcmp(buffer, "YUV4MPEG", 8)) {
724 fprintf(stderr, "Incomplete magic for YUV4MPEG file.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400725 return -1;
726 }
John Koleszarc6b90392012-07-13 15:21:29 -0700727 if (buffer[8] != '2') {
728 fprintf(stderr, "Incorrect YUV input file version; YUV4MPEG2 required.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400729 }
John Koleszarc6b90392012-07-13 15:21:29 -0700730 ret = y4m_parse_tags(_y4m, buffer + 5);
731 if (ret < 0) {
732 fprintf(stderr, "Error parsing YUV4MPEG2 header.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400733 return ret;
734 }
John Koleszarc6b90392012-07-13 15:21:29 -0700735 if (_y4m->interlace == '?') {
736 fprintf(stderr, "Warning: Input video interlacing format unknown; "
737 "assuming progressive scan.\n");
738 } else if (_y4m->interlace != 'p') {
739 fprintf(stderr, "Input video is interlaced; "
740 "Only progressive scan handled.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400741 return -1;
742 }
John Koleszar8dd82872013-05-06 11:01:35 -0700743 _y4m->vpx_fmt = VPX_IMG_FMT_I420;
Deb Mukherjee5820c5d2014-06-12 16:53:13 -0700744 _y4m->bps = 12;
745 _y4m->bit_depth = 8;
John Koleszarc6b90392012-07-13 15:21:29 -0700746 if (strcmp(_y4m->chroma_type, "420") == 0 ||
747 strcmp(_y4m->chroma_type, "420jpeg") == 0) {
748 _y4m->src_c_dec_h = _y4m->dst_c_dec_h = _y4m->src_c_dec_v = _y4m->dst_c_dec_v = 2;
749 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h
750 + 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
Deb Mukherjee5820c5d2014-06-12 16:53:13 -0700751 /* Natively supported: no conversion required. */
John Koleszarc6b90392012-07-13 15:21:29 -0700752 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
753 _y4m->convert = y4m_convert_null;
Deb Mukherjee5820c5d2014-06-12 16:53:13 -0700754 } else if (strcmp(_y4m->chroma_type, "420p10") == 0) {
755 _y4m->src_c_dec_h = 2;
756 _y4m->dst_c_dec_h = 2;
757 _y4m->src_c_dec_v = 2;
758 _y4m->dst_c_dec_v = 2;
759 _y4m->dst_buf_read_sz = 2 * (_y4m->pic_w * _y4m->pic_h +
760 2 * ((_y4m->pic_w + 1) / 2) *
761 ((_y4m->pic_h + 1) / 2));
762 /* Natively supported: no conversion required. */
763 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
764 _y4m->convert = y4m_convert_null;
765 _y4m->bit_depth = 10;
766 _y4m->bps = 15;
767 _y4m->vpx_fmt = VPX_IMG_FMT_I42016;
768 if (only_420) {
769 fprintf(stderr, "Unsupported conversion from 420p10 to 420jpeg\n");
770 return -1;
771 }
772 } else if (strcmp(_y4m->chroma_type, "420p12") == 0) {
773 _y4m->src_c_dec_h = 2;
774 _y4m->dst_c_dec_h = 2;
775 _y4m->src_c_dec_v = 2;
776 _y4m->dst_c_dec_v = 2;
777 _y4m->dst_buf_read_sz = 2 * (_y4m->pic_w * _y4m->pic_h +
778 2 * ((_y4m->pic_w + 1) / 2) *
779 ((_y4m->pic_h + 1) / 2));
780 /* Natively supported: no conversion required. */
781 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
782 _y4m->convert = y4m_convert_null;
783 _y4m->bit_depth = 12;
784 _y4m->bps = 18;
785 _y4m->vpx_fmt = VPX_IMG_FMT_I42016;
786 if (only_420) {
787 fprintf(stderr, "Unsupported conversion from 420p12 to 420jpeg\n");
788 return -1;
789 }
John Koleszarc6b90392012-07-13 15:21:29 -0700790 } else if (strcmp(_y4m->chroma_type, "420mpeg2") == 0) {
791 _y4m->src_c_dec_h = _y4m->dst_c_dec_h = _y4m->src_c_dec_v = _y4m->dst_c_dec_v = 2;
792 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400793 /*Chroma filter required: read into the aux buf first.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700794 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz =
795 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
796 _y4m->convert = y4m_convert_42xmpeg2_42xjpeg;
797 } else if (strcmp(_y4m->chroma_type, "420paldv") == 0) {
798 _y4m->src_c_dec_h = _y4m->dst_c_dec_h = _y4m->src_c_dec_v = _y4m->dst_c_dec_v = 2;
799 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400800 /*Chroma filter required: read into the aux buf first.
801 We need to make two filter passes, so we need some extra space in the
802 aux buffer.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700803 _y4m->aux_buf_sz = 3 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
804 _y4m->aux_buf_read_sz = 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
805 _y4m->convert = y4m_convert_42xpaldv_42xjpeg;
806 } else if (strcmp(_y4m->chroma_type, "422jpeg") == 0) {
807 _y4m->src_c_dec_h = _y4m->dst_c_dec_h = 2;
808 _y4m->src_c_dec_v = 1;
809 _y4m->dst_c_dec_v = 2;
810 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400811 /*Chroma filter required: read into the aux buf first.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700812 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
813 _y4m->convert = y4m_convert_422jpeg_420jpeg;
814 } else if (strcmp(_y4m->chroma_type, "422") == 0) {
John Koleszar8dd82872013-05-06 11:01:35 -0700815 _y4m->src_c_dec_h = 2;
John Koleszarc6b90392012-07-13 15:21:29 -0700816 _y4m->src_c_dec_v = 1;
John Koleszar8dd82872013-05-06 11:01:35 -0700817 if (only_420) {
818 _y4m->dst_c_dec_h = 2;
819 _y4m->dst_c_dec_v = 2;
820 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
821 /*Chroma filter required: read into the aux buf first.
822 We need to make two filter passes, so we need some extra space in the
823 aux buffer.*/
824 _y4m->aux_buf_read_sz = 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
825 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz +
826 ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
827 _y4m->convert = y4m_convert_422_420jpeg;
828 } else {
829 _y4m->vpx_fmt = VPX_IMG_FMT_I422;
Deb Mukherjee5820c5d2014-06-12 16:53:13 -0700830 _y4m->bps = 16;
John Koleszar8dd82872013-05-06 11:01:35 -0700831 _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
832 _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
833 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h
834 + 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
835 /*Natively supported: no conversion required.*/
836 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
837 _y4m->convert = y4m_convert_null;
Deb Mukherjee5820c5d2014-06-12 16:53:13 -0700838 }
839 } else if (strcmp(_y4m->chroma_type, "422p10") == 0) {
840 _y4m->src_c_dec_h = 2;
841 _y4m->src_c_dec_v = 1;
842 _y4m->vpx_fmt = VPX_IMG_FMT_I42216;
843 _y4m->bps = 20;
844 _y4m->bit_depth = 10;
845 _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
846 _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
847 _y4m->dst_buf_read_sz = 2 * (_y4m->pic_w * _y4m->pic_h +
848 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h);
849 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
850 _y4m->convert = y4m_convert_null;
851 if (only_420) {
852 fprintf(stderr, "Unsupported conversion from 422p10 to 420jpeg\n");
853 return -1;
854 }
855 } else if (strcmp(_y4m->chroma_type, "422p12") == 0) {
856 _y4m->src_c_dec_h = 2;
857 _y4m->src_c_dec_v = 1;
858 _y4m->vpx_fmt = VPX_IMG_FMT_I42216;
859 _y4m->bps = 24;
860 _y4m->bit_depth = 12;
861 _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
862 _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
863 _y4m->dst_buf_read_sz = 2 * (_y4m->pic_w * _y4m->pic_h +
864 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h);
865 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
866 _y4m->convert = y4m_convert_null;
867 if (only_420) {
868 fprintf(stderr, "Unsupported conversion from 422p12 to 420jpeg\n");
869 return -1;
870 }
John Koleszarc6b90392012-07-13 15:21:29 -0700871 } else if (strcmp(_y4m->chroma_type, "411") == 0) {
872 _y4m->src_c_dec_h = 4;
873 _y4m->dst_c_dec_h = 2;
874 _y4m->src_c_dec_v = 1;
875 _y4m->dst_c_dec_v = 2;
876 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400877 /*Chroma filter required: read into the aux buf first.
878 We need to make two filter passes, so we need some extra space in the
879 aux buffer.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700880 _y4m->aux_buf_read_sz = 2 * ((_y4m->pic_w + 3) / 4) * _y4m->pic_h;
881 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz + ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
882 _y4m->convert = y4m_convert_411_420jpeg;
883 } else if (strcmp(_y4m->chroma_type, "444") == 0) {
884 _y4m->src_c_dec_h = 1;
John Koleszarc6b90392012-07-13 15:21:29 -0700885 _y4m->src_c_dec_v = 1;
John Koleszar8dd82872013-05-06 11:01:35 -0700886 if (only_420) {
887 _y4m->dst_c_dec_h = 2;
888 _y4m->dst_c_dec_v = 2;
889 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
890 /*Chroma filter required: read into the aux buf first.
891 We need to make two filter passes, so we need some extra space in the
892 aux buffer.*/
893 _y4m->aux_buf_read_sz = 2 * _y4m->pic_w * _y4m->pic_h;
894 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz +
895 ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
896 _y4m->convert = y4m_convert_444_420jpeg;
897 } else {
898 _y4m->vpx_fmt = VPX_IMG_FMT_I444;
Deb Mukherjee5820c5d2014-06-12 16:53:13 -0700899 _y4m->bps = 24;
John Koleszar8dd82872013-05-06 11:01:35 -0700900 _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
901 _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
902 _y4m->dst_buf_read_sz = 3 * _y4m->pic_w * _y4m->pic_h;
903 /*Natively supported: no conversion required.*/
904 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
905 _y4m->convert = y4m_convert_null;
906 }
Deb Mukherjee5820c5d2014-06-12 16:53:13 -0700907 } else if (strcmp(_y4m->chroma_type, "444p10") == 0) {
908 _y4m->src_c_dec_h = 1;
909 _y4m->src_c_dec_v = 1;
910 _y4m->vpx_fmt = VPX_IMG_FMT_I44416;
911 _y4m->bps = 30;
912 _y4m->bit_depth = 10;
913 _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
914 _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
915 _y4m->dst_buf_read_sz = 2 * 3 * _y4m->pic_w * _y4m->pic_h;
916 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
917 _y4m->convert = y4m_convert_null;
918 if (only_420) {
919 fprintf(stderr, "Unsupported conversion from 444p10 to 420jpeg\n");
920 return -1;
921 }
922 } else if (strcmp(_y4m->chroma_type, "444p12") == 0) {
923 _y4m->src_c_dec_h = 1;
924 _y4m->src_c_dec_v = 1;
925 _y4m->vpx_fmt = VPX_IMG_FMT_I44416;
926 _y4m->bps = 36;
927 _y4m->bit_depth = 12;
928 _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
929 _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
930 _y4m->dst_buf_read_sz = 2 * 3 * _y4m->pic_w * _y4m->pic_h;
931 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
932 _y4m->convert = y4m_convert_null;
933 if (only_420) {
934 fprintf(stderr, "Unsupported conversion from 444p12 to 420jpeg\n");
935 return -1;
936 }
John Koleszarc6b90392012-07-13 15:21:29 -0700937 } else if (strcmp(_y4m->chroma_type, "444alpha") == 0) {
938 _y4m->src_c_dec_h = 1;
John Koleszarc6b90392012-07-13 15:21:29 -0700939 _y4m->src_c_dec_v = 1;
John Koleszar8dd82872013-05-06 11:01:35 -0700940 if (only_420) {
941 _y4m->dst_c_dec_h = 2;
942 _y4m->dst_c_dec_v = 2;
943 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
944 /*Chroma filter required: read into the aux buf first.
945 We need to make two filter passes, so we need some extra space in the
946 aux buffer.
947 The extra plane also gets read into the aux buf.
948 It will be discarded.*/
949 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 3 * _y4m->pic_w * _y4m->pic_h;
950 _y4m->convert = y4m_convert_444_420jpeg;
951 } else {
952 _y4m->vpx_fmt = VPX_IMG_FMT_444A;
Deb Mukherjee5820c5d2014-06-12 16:53:13 -0700953 _y4m->bps = 32;
John Koleszar8dd82872013-05-06 11:01:35 -0700954 _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
955 _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
956 _y4m->dst_buf_read_sz = 4 * _y4m->pic_w * _y4m->pic_h;
957 /*Natively supported: no conversion required.*/
958 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
959 _y4m->convert = y4m_convert_null;
960 }
John Koleszarc6b90392012-07-13 15:21:29 -0700961 } else if (strcmp(_y4m->chroma_type, "mono") == 0) {
962 _y4m->src_c_dec_h = _y4m->src_c_dec_v = 0;
963 _y4m->dst_c_dec_h = _y4m->dst_c_dec_v = 2;
964 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400965 /*No extra space required, but we need to clear the chroma planes.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700966 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
967 _y4m->convert = y4m_convert_mono_420jpeg;
968 } else {
969 fprintf(stderr, "Unknown chroma sampling type: %s\n", _y4m->chroma_type);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400970 return -1;
971 }
972 /*The size of the final frame buffers is always computed from the
973 destination chroma decimation type.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700974 _y4m->dst_buf_sz = _y4m->pic_w * _y4m->pic_h
975 + 2 * ((_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h) *
976 ((_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v);
Deb Mukherjee5820c5d2014-06-12 16:53:13 -0700977 if (_y4m->bit_depth == 8)
Yaowu Xua0af4162014-10-08 08:38:15 -0700978 _y4m->dst_buf = (unsigned char *)malloc(_y4m->dst_buf_sz);
Deb Mukherjee5820c5d2014-06-12 16:53:13 -0700979 else
Yaowu Xua0af4162014-10-08 08:38:15 -0700980 _y4m->dst_buf = (unsigned char *)malloc(2 * _y4m->dst_buf_sz);
Jim Bankoskie35c54e2014-08-19 09:00:44 -0700981
982 if (_y4m->aux_buf_sz > 0)
983 _y4m->aux_buf = (unsigned char *)malloc(_y4m->aux_buf_sz);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400984 return 0;
985}
986
John Koleszarc6b90392012-07-13 15:21:29 -0700987void y4m_input_close(y4m_input *_y4m) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400988 free(_y4m->dst_buf);
989 free(_y4m->aux_buf);
990}
991
John Koleszarc6b90392012-07-13 15:21:29 -0700992int y4m_input_fetch_frame(y4m_input *_y4m, FILE *_fin, vpx_image_t *_img) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400993 char frame[6];
994 int pic_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400995 int c_w;
996 int c_h;
997 int c_sz;
Deb Mukherjee5820c5d2014-06-12 16:53:13 -0700998 int bytes_per_sample = _y4m->bit_depth > 8 ? 2 : 1;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400999 /*Read and skip the frame header.*/
James Zerndf0829f2014-02-12 16:30:43 -08001000 if (!file_read(frame, 6, _fin)) return 0;
John Koleszarc6b90392012-07-13 15:21:29 -07001001 if (memcmp(frame, "FRAME", 5)) {
1002 fprintf(stderr, "Loss of framing in Y4M input data\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04001003 return -1;
1004 }
John Koleszarc6b90392012-07-13 15:21:29 -07001005 if (frame[5] != '\n') {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04001006 char c;
1007 int j;
James Zerndf0829f2014-02-12 16:30:43 -08001008 for (j = 0; j < 79 && file_read(&c, 1, _fin) && c != '\n'; j++) {}
John Koleszarc6b90392012-07-13 15:21:29 -07001009 if (j == 79) {
1010 fprintf(stderr, "Error parsing Y4M frame header\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04001011 return -1;
1012 }
1013 }
1014 /*Read the frame data that needs no conversion.*/
James Zerndf0829f2014-02-12 16:30:43 -08001015 if (!file_read(_y4m->dst_buf, _y4m->dst_buf_read_sz, _fin)) {
John Koleszarc6b90392012-07-13 15:21:29 -07001016 fprintf(stderr, "Error reading Y4M frame data.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04001017 return -1;
1018 }
1019 /*Read the frame data that does need conversion.*/
James Zerndf0829f2014-02-12 16:30:43 -08001020 if (!file_read(_y4m->aux_buf, _y4m->aux_buf_read_sz, _fin)) {
John Koleszarc6b90392012-07-13 15:21:29 -07001021 fprintf(stderr, "Error reading Y4M frame data.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04001022 return -1;
1023 }
1024 /*Now convert the just read frame.*/
John Koleszarc6b90392012-07-13 15:21:29 -07001025 (*_y4m->convert)(_y4m, _y4m->dst_buf, _y4m->aux_buf);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04001026 /*Fill in the frame buffer pointers.
1027 We don't use vpx_img_wrap() because it forces padding for odd picture
1028 sizes, which would require a separate fread call for every row.*/
John Koleszarc6b90392012-07-13 15:21:29 -07001029 memset(_img, 0, sizeof(*_img));
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04001030 /*Y4M has the planes in Y'CbCr order, which libvpx calls Y, U, and V.*/
John Koleszar8dd82872013-05-06 11:01:35 -07001031 _img->fmt = _y4m->vpx_fmt;
John Koleszarc6b90392012-07-13 15:21:29 -07001032 _img->w = _img->d_w = _y4m->pic_w;
1033 _img->h = _img->d_h = _y4m->pic_h;
John Koleszar8dd82872013-05-06 11:01:35 -07001034 _img->x_chroma_shift = _y4m->dst_c_dec_h >> 1;
1035 _img->y_chroma_shift = _y4m->dst_c_dec_v >> 1;
Deb Mukherjee5820c5d2014-06-12 16:53:13 -07001036 _img->bps = _y4m->bps;
John Koleszar8dd82872013-05-06 11:01:35 -07001037
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04001038 /*Set up the buffer pointers.*/
Deb Mukherjee5820c5d2014-06-12 16:53:13 -07001039 pic_sz = _y4m->pic_w * _y4m->pic_h * bytes_per_sample;
John Koleszarc6b90392012-07-13 15:21:29 -07001040 c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
Deb Mukherjee5820c5d2014-06-12 16:53:13 -07001041 c_w *= bytes_per_sample;
John Koleszarc6b90392012-07-13 15:21:29 -07001042 c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
1043 c_sz = c_w * c_h;
Dmitry Kovalev9cdaa3d2014-08-15 14:32:41 -07001044 _img->stride[VPX_PLANE_Y] = _img->stride[VPX_PLANE_ALPHA] =
Deb Mukherjee5820c5d2014-06-12 16:53:13 -07001045 _y4m->pic_w * bytes_per_sample;
Dmitry Kovalev9cdaa3d2014-08-15 14:32:41 -07001046 _img->stride[VPX_PLANE_U] = _img->stride[VPX_PLANE_V] = c_w;
1047 _img->planes[VPX_PLANE_Y] = _y4m->dst_buf;
1048 _img->planes[VPX_PLANE_U] = _y4m->dst_buf + pic_sz;
1049 _img->planes[VPX_PLANE_V] = _y4m->dst_buf + pic_sz + c_sz;
1050 _img->planes[VPX_PLANE_ALPHA] = _y4m->dst_buf + pic_sz + 2 * c_sz;
Timothy B. Terriberryc4d7e5e2010-10-27 16:04:02 -07001051 return 1;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -04001052}