blob: 47f005a950be021325c1a3180033570e74c95f03 [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 */
13#include <stdlib.h>
14#include <string.h>
15#include "y4minput.h"
16
John Koleszarc6b90392012-07-13 15:21:29 -070017static int y4m_parse_tags(y4m_input *_y4m, char *_tags) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040018 int got_w;
19 int got_h;
20 int got_fps;
21 int got_interlace;
22 int got_par;
23 int got_chroma;
24 char *p;
25 char *q;
John Koleszarc6b90392012-07-13 15:21:29 -070026 got_w = got_h = got_fps = got_interlace = got_par = got_chroma = 0;
27 for (p = _tags;; p = q) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040028 /*Skip any leading spaces.*/
John Koleszarc6b90392012-07-13 15:21:29 -070029 while (*p == ' ')p++;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040030 /*If that's all we have, stop.*/
John Koleszarc6b90392012-07-13 15:21:29 -070031 if (p[0] == '\0')break;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040032 /*Find the end of this tag.*/
John Koleszarc6b90392012-07-13 15:21:29 -070033 for (q = p + 1; *q != '\0' && *q != ' '; q++);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040034 /*Process the tag.*/
John Koleszarc6b90392012-07-13 15:21:29 -070035 switch (p[0]) {
36 case 'W': {
37 if (sscanf(p + 1, "%d", &_y4m->pic_w) != 1)return -1;
38 got_w = 1;
39 }
40 break;
41 case 'H': {
42 if (sscanf(p + 1, "%d", &_y4m->pic_h) != 1)return -1;
43 got_h = 1;
44 }
45 break;
46 case 'F': {
47 if (sscanf(p + 1, "%d:%d", &_y4m->fps_n, &_y4m->fps_d) != 2) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040048 return -1;
49 }
John Koleszarc6b90392012-07-13 15:21:29 -070050 got_fps = 1;
51 }
52 break;
53 case 'I': {
54 _y4m->interlace = p[1];
55 got_interlace = 1;
56 }
57 break;
58 case 'A': {
59 if (sscanf(p + 1, "%d:%d", &_y4m->par_n, &_y4m->par_d) != 2) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040060 return -1;
61 }
John Koleszarc6b90392012-07-13 15:21:29 -070062 got_par = 1;
63 }
64 break;
65 case 'C': {
66 if (q - p > 16)return -1;
67 memcpy(_y4m->chroma_type, p + 1, q - p - 1);
68 _y4m->chroma_type[q - p - 1] = '\0';
69 got_chroma = 1;
70 }
71 break;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040072 /*Ignore unknown tags.*/
73 }
74 }
John Koleszarc6b90392012-07-13 15:21:29 -070075 if (!got_w || !got_h || !got_fps)return -1;
76 if (!got_interlace)_y4m->interlace = '?';
77 if (!got_par)_y4m->par_n = _y4m->par_d = 0;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040078 /*Chroma-type is not specified in older files, e.g., those generated by
79 mplayer.*/
John Koleszarc6b90392012-07-13 15:21:29 -070080 if (!got_chroma)strcpy(_y4m->chroma_type, "420");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -040081 return 0;
82}
83
84
85
86/*All anti-aliasing filters in the following conversion functions are based on
87 one of two window functions:
88 The 6-tap Lanczos window (for down-sampling and shifts):
89 sinc(\pi*t)*sinc(\pi*t/3), |t|<3 (sinc(t)==sin(t)/t)
90 0, |t|>=3
91 The 4-tap Mitchell window (for up-sampling):
92 7|t|^3-12|t|^2+16/3, |t|<1
93 -(7/3)|x|^3+12|x|^2-20|x|+32/3, |t|<2
94 0, |t|>=2
95 The number of taps is intentionally kept small to reduce computational
96 overhead and limit ringing.
97
98 The taps from these filters are scaled so that their sum is 1, and the result
99 is scaled by 128 and rounded to integers to create a filter whose
100 intermediate values fit inside 16 bits.
101 Coefficients are rounded in such a way as to ensure their sum is still 128,
102 which is usually equivalent to normal rounding.
103
104 Conversions which require both horizontal and vertical filtering could
105 have these steps pipelined, for less memory consumption and better cache
106 performance, but we do them separately for simplicity.*/
107
108#define OC_MINI(_a,_b) ((_a)>(_b)?(_b):(_a))
109#define OC_MAXI(_a,_b) ((_a)<(_b)?(_b):(_a))
110#define OC_CLAMPI(_a,_b,_c) (OC_MAXI(_a,OC_MINI(_b,_c)))
111
112/*420jpeg chroma samples are sited like:
113 Y-------Y-------Y-------Y-------
114 | | | |
115 | BR | | BR |
116 | | | |
117 Y-------Y-------Y-------Y-------
118 | | | |
119 | | | |
120 | | | |
121 Y-------Y-------Y-------Y-------
122 | | | |
123 | BR | | BR |
124 | | | |
125 Y-------Y-------Y-------Y-------
126 | | | |
127 | | | |
128 | | | |
129
130 420mpeg2 chroma samples are sited like:
131 Y-------Y-------Y-------Y-------
132 | | | |
133 BR | BR |
134 | | | |
135 Y-------Y-------Y-------Y-------
136 | | | |
137 | | | |
138 | | | |
139 Y-------Y-------Y-------Y-------
140 | | | |
141 BR | BR |
142 | | | |
143 Y-------Y-------Y-------Y-------
144 | | | |
145 | | | |
146 | | | |
147
148 We use a resampling filter to shift the site locations one quarter pixel (at
149 the chroma plane's resolution) to the right.
150 The 4:2:2 modes look exactly the same, except there are twice as many chroma
151 lines, and they are vertically co-sited with the luma samples in both the
152 mpeg2 and jpeg cases (thus requiring no vertical resampling).*/
153static void y4m_42xmpeg2_42xjpeg_helper(unsigned char *_dst,
John Koleszarc6b90392012-07-13 15:21:29 -0700154 const unsigned char *_src, int _c_w, int _c_h) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400155 int y;
156 int x;
John Koleszarc6b90392012-07-13 15:21:29 -0700157 for (y = 0; y < _c_h; y++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400158 /*Filter: [4 -17 114 35 -9 1]/128, derived from a 6-tap Lanczos
159 window.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700160 for (x = 0; x < OC_MINI(_c_w, 2); x++) {
161 _dst[x] = (unsigned char)OC_CLAMPI(0, (4 * _src[0] - 17 * _src[OC_MAXI(x - 1, 0)] +
162 114 * _src[x] + 35 * _src[OC_MINI(x + 1, _c_w - 1)] - 9 * _src[OC_MINI(x + 2, _c_w - 1)] +
163 _src[OC_MINI(x + 3, _c_w - 1)] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400164 }
John Koleszarc6b90392012-07-13 15:21:29 -0700165 for (; x < _c_w - 3; x++) {
166 _dst[x] = (unsigned char)OC_CLAMPI(0, (4 * _src[x - 2] - 17 * _src[x - 1] +
167 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 -0400168 }
John Koleszarc6b90392012-07-13 15:21:29 -0700169 for (; x < _c_w; x++) {
170 _dst[x] = (unsigned char)OC_CLAMPI(0, (4 * _src[x - 2] - 17 * _src[x - 1] +
171 114 * _src[x] + 35 * _src[OC_MINI(x + 1, _c_w - 1)] - 9 * _src[OC_MINI(x + 2, _c_w - 1)] +
172 _src[_c_w - 1] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400173 }
John Koleszarc6b90392012-07-13 15:21:29 -0700174 _dst += _c_w;
175 _src += _c_w;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400176 }
177}
178
179/*Handles both 422 and 420mpeg2 to 422jpeg and 420jpeg, respectively.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700180static void y4m_convert_42xmpeg2_42xjpeg(y4m_input *_y4m, unsigned char *_dst,
181 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400182 int c_w;
183 int c_h;
184 int c_sz;
185 int pli;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400186 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700187 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400188 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700189 c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
190 c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
191 c_sz = c_w * c_h;
192 for (pli = 1; pli < 3; pli++) {
193 y4m_42xmpeg2_42xjpeg_helper(_dst, _aux, c_w, c_h);
194 _dst += c_sz;
195 _aux += c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400196 }
197}
198
199/*This format is only used for interlaced content, but is included for
200 completeness.
201
202 420jpeg chroma samples are sited like:
203 Y-------Y-------Y-------Y-------
204 | | | |
205 | BR | | BR |
206 | | | |
207 Y-------Y-------Y-------Y-------
208 | | | |
209 | | | |
210 | | | |
211 Y-------Y-------Y-------Y-------
212 | | | |
213 | BR | | BR |
214 | | | |
215 Y-------Y-------Y-------Y-------
216 | | | |
217 | | | |
218 | | | |
219
220 420paldv chroma samples are sited like:
221 YR------Y-------YR------Y-------
222 | | | |
223 | | | |
224 | | | |
225 YB------Y-------YB------Y-------
226 | | | |
227 | | | |
228 | | | |
229 YR------Y-------YR------Y-------
230 | | | |
231 | | | |
232 | | | |
233 YB------Y-------YB------Y-------
234 | | | |
235 | | | |
236 | | | |
237
238 We use a resampling filter to shift the site locations one quarter pixel (at
239 the chroma plane's resolution) to the right.
240 Then we use another filter to move the C_r location down one quarter pixel,
241 and the C_b location up one quarter pixel.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700242static void y4m_convert_42xpaldv_42xjpeg(y4m_input *_y4m, unsigned char *_dst,
243 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400244 unsigned char *tmp;
245 int c_w;
246 int c_h;
247 int c_sz;
248 int pli;
249 int y;
250 int x;
251 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700252 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400253 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700254 c_w = (_y4m->pic_w + 1) / 2;
255 c_h = (_y4m->pic_h + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
256 c_sz = c_w * c_h;
257 tmp = _aux + 2 * c_sz;
258 for (pli = 1; pli < 3; pli++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400259 /*First do the horizontal re-sampling.
260 This is the same as the mpeg2 case, except that after the horizontal
261 case, we need to apply a second vertical filter.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700262 y4m_42xmpeg2_42xjpeg_helper(tmp, _aux, c_w, c_h);
263 _aux += c_sz;
264 switch (pli) {
265 case 1: {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400266 /*Slide C_b up a quarter-pel.
267 This is the same filter used above, but in the other order.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700268 for (x = 0; x < c_w; x++) {
269 for (y = 0; y < OC_MINI(c_h, 3); y++) {
270 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (tmp[0]
271 - 9 * tmp[OC_MAXI(y - 2, 0) * c_w] + 35 * tmp[OC_MAXI(y - 1, 0) * c_w]
272 + 114 * tmp[y * c_w] - 17 * tmp[OC_MINI(y + 1, c_h - 1) * c_w]
273 + 4 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400274 }
John Koleszarc6b90392012-07-13 15:21:29 -0700275 for (; y < c_h - 2; y++) {
276 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (tmp[(y - 3) * c_w]
277 - 9 * tmp[(y - 2) * c_w] + 35 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w]
278 - 17 * tmp[(y + 1) * c_w] + 4 * tmp[(y + 2) * c_w] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400279 }
John Koleszarc6b90392012-07-13 15:21:29 -0700280 for (; y < c_h; y++) {
281 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (tmp[(y - 3) * c_w]
282 - 9 * tmp[(y - 2) * c_w] + 35 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w]
283 - 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 -0400284 }
285 _dst++;
286 tmp++;
287 }
John Koleszarc6b90392012-07-13 15:21:29 -0700288 _dst += c_sz - c_w;
289 tmp -= c_w;
290 }
291 break;
292 case 2: {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400293 /*Slide C_r down a quarter-pel.
294 This is the same as the horizontal filter.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700295 for (x = 0; x < c_w; x++) {
296 for (y = 0; y < OC_MINI(c_h, 2); y++) {
297 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (4 * tmp[0]
298 - 17 * tmp[OC_MAXI(y - 1, 0) * c_w] + 114 * tmp[y * c_w]
299 + 35 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] - 9 * tmp[OC_MINI(y + 2, c_h - 1) * c_w]
300 + tmp[OC_MINI(y + 3, c_h - 1) * c_w] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400301 }
John Koleszarc6b90392012-07-13 15:21:29 -0700302 for (; y < c_h - 3; y++) {
303 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (4 * tmp[(y - 2) * c_w]
304 - 17 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w] + 35 * tmp[(y + 1) * c_w]
305 - 9 * tmp[(y + 2) * c_w] + tmp[(y + 3) * c_w] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400306 }
John Koleszarc6b90392012-07-13 15:21:29 -0700307 for (; y < c_h; y++) {
308 _dst[y * c_w] = (unsigned char)OC_CLAMPI(0, (4 * tmp[(y - 2) * c_w]
309 - 17 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w] + 35 * tmp[OC_MINI(y + 1, c_h - 1) * c_w]
310 - 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 -0400311 }
312 _dst++;
313 tmp++;
314 }
John Koleszarc6b90392012-07-13 15:21:29 -0700315 }
316 break;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400317 }
318 /*For actual interlaced material, this would have to be done separately on
319 each field, and the shift amounts would be different.
320 C_r moves down 1/8, C_b up 3/8 in the top field, and C_r moves down 3/8,
321 C_b up 1/8 in the bottom field.
322 The corresponding filters would be:
323 Down 1/8 (reverse order for up): [3 -11 125 15 -4 0]/128
324 Down 3/8 (reverse order for up): [4 -19 98 56 -13 2]/128*/
325 }
326}
327
328/*Perform vertical filtering to reduce a single plane from 4:2:2 to 4:2:0.
329 This is used as a helper by several converation routines.*/
330static void y4m_422jpeg_420jpeg_helper(unsigned char *_dst,
John Koleszarc6b90392012-07-13 15:21:29 -0700331 const unsigned char *_src, int _c_w, int _c_h) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400332 int y;
333 int x;
334 /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700335 for (x = 0; x < _c_w; x++) {
336 for (y = 0; y < OC_MINI(_c_h, 2); y += 2) {
337 _dst[(y >> 1)*_c_w] = OC_CLAMPI(0, (64 * _src[0]
338 + 78 * _src[OC_MINI(1, _c_h - 1) * _c_w]
339 - 17 * _src[OC_MINI(2, _c_h - 1) * _c_w]
340 + 3 * _src[OC_MINI(3, _c_h - 1) * _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 - 3; y += 2) {
343 _dst[(y >> 1)*_c_w] = OC_CLAMPI(0, (3 * (_src[(y - 2) * _c_w] + _src[(y + 3) * _c_w])
344 - 17 * (_src[(y - 1) * _c_w] + _src[(y + 2) * _c_w])
345 + 78 * (_src[y * _c_w] + _src[(y + 1) * _c_w]) + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400346 }
John Koleszarc6b90392012-07-13 15:21:29 -0700347 for (; y < _c_h; y += 2) {
348 _dst[(y >> 1)*_c_w] = OC_CLAMPI(0, (3 * (_src[(y - 2) * _c_w]
349 + _src[(_c_h - 1) * _c_w]) - 17 * (_src[(y - 1) * _c_w]
350 + _src[OC_MINI(y + 2, _c_h - 1) * _c_w])
351 + 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 -0400352 }
353 _src++;
354 _dst++;
355 }
356}
357
358/*420jpeg chroma samples are sited like:
359 Y-------Y-------Y-------Y-------
360 | | | |
361 | BR | | BR |
362 | | | |
363 Y-------Y-------Y-------Y-------
364 | | | |
365 | | | |
366 | | | |
367 Y-------Y-------Y-------Y-------
368 | | | |
369 | BR | | BR |
370 | | | |
371 Y-------Y-------Y-------Y-------
372 | | | |
373 | | | |
374 | | | |
375
376 422jpeg chroma samples are sited like:
377 Y---BR--Y-------Y---BR--Y-------
378 | | | |
379 | | | |
380 | | | |
381 Y---BR--Y-------Y---BR--Y-------
382 | | | |
383 | | | |
384 | | | |
385 Y---BR--Y-------Y---BR--Y-------
386 | | | |
387 | | | |
388 | | | |
389 Y---BR--Y-------Y---BR--Y-------
390 | | | |
391 | | | |
392 | | | |
393
394 We use a resampling filter to decimate the chroma planes by two in the
395 vertical direction.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700396static void y4m_convert_422jpeg_420jpeg(y4m_input *_y4m, unsigned char *_dst,
397 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400398 int c_w;
399 int c_h;
400 int c_sz;
401 int dst_c_w;
402 int dst_c_h;
403 int dst_c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400404 int pli;
405 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700406 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400407 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700408 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
409 c_h = _y4m->pic_h;
410 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
411 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
412 c_sz = c_w * c_h;
413 dst_c_sz = dst_c_w * dst_c_h;
414 for (pli = 1; pli < 3; pli++) {
415 y4m_422jpeg_420jpeg_helper(_dst, _aux, c_w, c_h);
416 _aux += c_sz;
417 _dst += dst_c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400418 }
419}
420
421/*420jpeg chroma samples are sited like:
422 Y-------Y-------Y-------Y-------
423 | | | |
424 | BR | | BR |
425 | | | |
426 Y-------Y-------Y-------Y-------
427 | | | |
428 | | | |
429 | | | |
430 Y-------Y-------Y-------Y-------
431 | | | |
432 | BR | | BR |
433 | | | |
434 Y-------Y-------Y-------Y-------
435 | | | |
436 | | | |
437 | | | |
438
439 422 chroma samples are sited like:
440 YBR-----Y-------YBR-----Y-------
441 | | | |
442 | | | |
443 | | | |
444 YBR-----Y-------YBR-----Y-------
445 | | | |
446 | | | |
447 | | | |
448 YBR-----Y-------YBR-----Y-------
449 | | | |
450 | | | |
451 | | | |
452 YBR-----Y-------YBR-----Y-------
453 | | | |
454 | | | |
455 | | | |
456
457 We use a resampling filter to shift the original site locations one quarter
458 pixel (at the original chroma resolution) to the right.
459 Then we use a second resampling filter to decimate the chroma planes by two
460 in the vertical direction.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700461static void y4m_convert_422_420jpeg(y4m_input *_y4m, unsigned char *_dst,
462 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400463 unsigned char *tmp;
464 int c_w;
465 int c_h;
466 int c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400467 int dst_c_h;
468 int dst_c_sz;
469 int pli;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400470 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700471 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400472 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700473 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
474 c_h = _y4m->pic_h;
475 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
476 c_sz = c_w * c_h;
477 dst_c_sz = c_w * dst_c_h;
478 tmp = _aux + 2 * c_sz;
479 for (pli = 1; pli < 3; pli++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400480 /*In reality, the horizontal and vertical steps could be pipelined, for
481 less memory consumption and better cache performance, but we do them
482 separately for simplicity.*/
483 /*First do horizontal filtering (convert to 422jpeg)*/
John Koleszarc6b90392012-07-13 15:21:29 -0700484 y4m_42xmpeg2_42xjpeg_helper(tmp, _aux, c_w, c_h);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400485 /*Now do the vertical filtering.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700486 y4m_422jpeg_420jpeg_helper(_dst, tmp, c_w, c_h);
487 _aux += c_sz;
488 _dst += dst_c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400489 }
490}
491
492/*420jpeg chroma samples are sited like:
493 Y-------Y-------Y-------Y-------
494 | | | |
495 | BR | | BR |
496 | | | |
497 Y-------Y-------Y-------Y-------
498 | | | |
499 | | | |
500 | | | |
501 Y-------Y-------Y-------Y-------
502 | | | |
503 | BR | | BR |
504 | | | |
505 Y-------Y-------Y-------Y-------
506 | | | |
507 | | | |
508 | | | |
509
510 411 chroma samples are sited like:
511 YBR-----Y-------Y-------Y-------
512 | | | |
513 | | | |
514 | | | |
515 YBR-----Y-------Y-------Y-------
516 | | | |
517 | | | |
518 | | | |
519 YBR-----Y-------Y-------Y-------
520 | | | |
521 | | | |
522 | | | |
523 YBR-----Y-------Y-------Y-------
524 | | | |
525 | | | |
526 | | | |
527
528 We use a filter to resample at site locations one eighth pixel (at the source
529 chroma plane's horizontal resolution) and five eighths of a pixel to the
530 right.
531 Then we use another filter to decimate the planes by 2 in the vertical
532 direction.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700533static void y4m_convert_411_420jpeg(y4m_input *_y4m, unsigned char *_dst,
534 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400535 unsigned char *tmp;
536 int c_w;
537 int c_h;
538 int c_sz;
539 int dst_c_w;
540 int dst_c_h;
541 int dst_c_sz;
542 int tmp_sz;
543 int pli;
544 int y;
545 int x;
546 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700547 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400548 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700549 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
550 c_h = _y4m->pic_h;
551 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
552 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
553 c_sz = c_w * c_h;
554 dst_c_sz = dst_c_w * dst_c_h;
555 tmp_sz = dst_c_w * c_h;
556 tmp = _aux + 2 * c_sz;
557 for (pli = 1; pli < 3; pli++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400558 /*In reality, the horizontal and vertical steps could be pipelined, for
559 less memory consumption and better cache performance, but we do them
560 separately for simplicity.*/
561 /*First do horizontal filtering (convert to 422jpeg)*/
John Koleszarc6b90392012-07-13 15:21:29 -0700562 for (y = 0; y < c_h; y++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400563 /*Filters: [1 110 18 -1]/128 and [-3 50 86 -5]/128, both derived from a
564 4-tap Mitchell window.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700565 for (x = 0; x < OC_MINI(c_w, 1); x++) {
566 tmp[x << 1] = (unsigned char)OC_CLAMPI(0, (111 * _aux[0]
567 + 18 * _aux[OC_MINI(1, c_w - 1)] - _aux[OC_MINI(2, c_w - 1)] + 64) >> 7, 255);
568 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(0, (47 * _aux[0]
569 + 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 -0400570 }
John Koleszarc6b90392012-07-13 15:21:29 -0700571 for (; x < c_w - 2; x++) {
572 tmp[x << 1] = (unsigned char)OC_CLAMPI(0, (_aux[x - 1] + 110 * _aux[x]
573 + 18 * _aux[x + 1] - _aux[x + 2] + 64) >> 7, 255);
574 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(0, (-3 * _aux[x - 1] + 50 * _aux[x]
575 + 86 * _aux[x + 1] - 5 * _aux[x + 2] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400576 }
John Koleszarc6b90392012-07-13 15:21:29 -0700577 for (; x < c_w; x++) {
578 tmp[x << 1] = (unsigned char)OC_CLAMPI(0, (_aux[x - 1] + 110 * _aux[x]
579 + 18 * _aux[OC_MINI(x + 1, c_w - 1)] - _aux[c_w - 1] + 64) >> 7, 255);
580 if ((x << 1 | 1) < dst_c_w) {
581 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(0, (-3 * _aux[x - 1] + 50 * _aux[x]
582 + 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 -0400583 }
584 }
John Koleszarc6b90392012-07-13 15:21:29 -0700585 tmp += dst_c_w;
586 _aux += c_w;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400587 }
John Koleszarc6b90392012-07-13 15:21:29 -0700588 tmp -= tmp_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400589 /*Now do the vertical filtering.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700590 y4m_422jpeg_420jpeg_helper(_dst, tmp, dst_c_w, c_h);
591 _dst += dst_c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400592 }
593}
594
595/*Convert 444 to 420jpeg.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700596static void y4m_convert_444_420jpeg(y4m_input *_y4m, unsigned char *_dst,
597 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400598 unsigned char *tmp;
599 int c_w;
600 int c_h;
601 int c_sz;
602 int dst_c_w;
603 int dst_c_h;
604 int dst_c_sz;
605 int tmp_sz;
606 int pli;
607 int y;
608 int x;
609 /*Skip past the luma data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700610 _dst += _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400611 /*Compute the size of each chroma plane.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700612 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
613 c_h = _y4m->pic_h;
614 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
615 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
616 c_sz = c_w * c_h;
617 dst_c_sz = dst_c_w * dst_c_h;
618 tmp_sz = dst_c_w * c_h;
619 tmp = _aux + 2 * c_sz;
620 for (pli = 1; pli < 3; pli++) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400621 /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700622 for (y = 0; y < c_h; y++) {
623 for (x = 0; x < OC_MINI(c_w, 2); x += 2) {
624 tmp[x >> 1] = OC_CLAMPI(0, (64 * _aux[0] + 78 * _aux[OC_MINI(1, c_w - 1)]
625 - 17 * _aux[OC_MINI(2, c_w - 1)]
626 + 3 * _aux[OC_MINI(3, c_w - 1)] + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400627 }
John Koleszarc6b90392012-07-13 15:21:29 -0700628 for (; x < c_w - 3; x += 2) {
629 tmp[x >> 1] = OC_CLAMPI(0, (3 * (_aux[x - 2] + _aux[x + 3])
630 - 17 * (_aux[x - 1] + _aux[x + 2]) + 78 * (_aux[x] + _aux[x + 1]) + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400631 }
John Koleszarc6b90392012-07-13 15:21:29 -0700632 for (; x < c_w; x += 2) {
633 tmp[x >> 1] = OC_CLAMPI(0, (3 * (_aux[x - 2] + _aux[c_w - 1]) -
634 17 * (_aux[x - 1] + _aux[OC_MINI(x + 2, c_w - 1)]) +
635 78 * (_aux[x] + _aux[OC_MINI(x + 1, c_w - 1)]) + 64) >> 7, 255);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400636 }
John Koleszarc6b90392012-07-13 15:21:29 -0700637 tmp += dst_c_w;
638 _aux += c_w;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400639 }
John Koleszarc6b90392012-07-13 15:21:29 -0700640 tmp -= tmp_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400641 /*Now do the vertical filtering.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700642 y4m_422jpeg_420jpeg_helper(_dst, tmp, dst_c_w, c_h);
643 _dst += dst_c_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400644 }
645}
646
647/*The image is padded with empty chroma components at 4:2:0.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700648static void y4m_convert_mono_420jpeg(y4m_input *_y4m, unsigned char *_dst,
649 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400650 int c_sz;
John Koleszarc6b90392012-07-13 15:21:29 -0700651 _dst += _y4m->pic_w * _y4m->pic_h;
652 c_sz = ((_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h) *
653 ((_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v);
654 memset(_dst, 128, c_sz * 2);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400655}
656
657/*No conversion function needed.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700658static void y4m_convert_null(y4m_input *_y4m, unsigned char *_dst,
659 unsigned char *_aux) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400660}
661
John Koleszar8dd82872013-05-06 11:01:35 -0700662int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip,
663 int only_420) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400664 char buffer[80];
665 int ret;
666 int i;
667 /*Read until newline, or 80 cols, whichever happens first.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700668 for (i = 0; i < 79; i++) {
669 if (_nskip > 0) {
670 buffer[i] = *_skip++;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400671 _nskip--;
John Koleszarc6b90392012-07-13 15:21:29 -0700672 } else {
John Koleszar82b1a342012-11-06 12:08:05 -0800673 ret = (int)fread(buffer + i, 1, 1, _fin);
John Koleszarc6b90392012-07-13 15:21:29 -0700674 if (ret < 1)return -1;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400675 }
John Koleszarc6b90392012-07-13 15:21:29 -0700676 if (buffer[i] == '\n')break;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400677 }
678 /*We skipped too much header data.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700679 if (_nskip > 0)return -1;
680 if (i == 79) {
681 fprintf(stderr, "Error parsing header; not a YUV2MPEG2 file?\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400682 return -1;
683 }
John Koleszarc6b90392012-07-13 15:21:29 -0700684 buffer[i] = '\0';
685 if (memcmp(buffer, "YUV4MPEG", 8)) {
686 fprintf(stderr, "Incomplete magic for YUV4MPEG file.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400687 return -1;
688 }
John Koleszarc6b90392012-07-13 15:21:29 -0700689 if (buffer[8] != '2') {
690 fprintf(stderr, "Incorrect YUV input file version; YUV4MPEG2 required.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400691 }
John Koleszarc6b90392012-07-13 15:21:29 -0700692 ret = y4m_parse_tags(_y4m, buffer + 5);
693 if (ret < 0) {
694 fprintf(stderr, "Error parsing YUV4MPEG2 header.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400695 return ret;
696 }
John Koleszarc6b90392012-07-13 15:21:29 -0700697 if (_y4m->interlace == '?') {
698 fprintf(stderr, "Warning: Input video interlacing format unknown; "
699 "assuming progressive scan.\n");
700 } else if (_y4m->interlace != 'p') {
701 fprintf(stderr, "Input video is interlaced; "
702 "Only progressive scan handled.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400703 return -1;
704 }
John Koleszar8dd82872013-05-06 11:01:35 -0700705 _y4m->vpx_fmt = VPX_IMG_FMT_I420;
706 _y4m->vpx_bps = 12;
John Koleszarc6b90392012-07-13 15:21:29 -0700707 if (strcmp(_y4m->chroma_type, "420") == 0 ||
708 strcmp(_y4m->chroma_type, "420jpeg") == 0) {
709 _y4m->src_c_dec_h = _y4m->dst_c_dec_h = _y4m->src_c_dec_v = _y4m->dst_c_dec_v = 2;
710 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h
711 + 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400712 /*Natively supported: no conversion required.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700713 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
714 _y4m->convert = y4m_convert_null;
715 } else if (strcmp(_y4m->chroma_type, "420mpeg2") == 0) {
716 _y4m->src_c_dec_h = _y4m->dst_c_dec_h = _y4m->src_c_dec_v = _y4m->dst_c_dec_v = 2;
717 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400718 /*Chroma filter required: read into the aux buf first.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700719 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz =
720 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
721 _y4m->convert = y4m_convert_42xmpeg2_42xjpeg;
722 } else if (strcmp(_y4m->chroma_type, "420paldv") == 0) {
723 _y4m->src_c_dec_h = _y4m->dst_c_dec_h = _y4m->src_c_dec_v = _y4m->dst_c_dec_v = 2;
724 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400725 /*Chroma filter required: read into the aux buf first.
726 We need to make two filter passes, so we need some extra space in the
727 aux buffer.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700728 _y4m->aux_buf_sz = 3 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
729 _y4m->aux_buf_read_sz = 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
730 _y4m->convert = y4m_convert_42xpaldv_42xjpeg;
731 } else if (strcmp(_y4m->chroma_type, "422jpeg") == 0) {
732 _y4m->src_c_dec_h = _y4m->dst_c_dec_h = 2;
733 _y4m->src_c_dec_v = 1;
734 _y4m->dst_c_dec_v = 2;
735 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400736 /*Chroma filter required: read into the aux buf first.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700737 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
738 _y4m->convert = y4m_convert_422jpeg_420jpeg;
739 } else if (strcmp(_y4m->chroma_type, "422") == 0) {
John Koleszar8dd82872013-05-06 11:01:35 -0700740 _y4m->src_c_dec_h = 2;
John Koleszarc6b90392012-07-13 15:21:29 -0700741 _y4m->src_c_dec_v = 1;
John Koleszar8dd82872013-05-06 11:01:35 -0700742 if (only_420) {
743 _y4m->dst_c_dec_h = 2;
744 _y4m->dst_c_dec_v = 2;
745 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
746 /*Chroma filter required: read into the aux buf first.
747 We need to make two filter passes, so we need some extra space in the
748 aux buffer.*/
749 _y4m->aux_buf_read_sz = 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
750 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz +
751 ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
752 _y4m->convert = y4m_convert_422_420jpeg;
753 } else {
754 _y4m->vpx_fmt = VPX_IMG_FMT_I422;
755 _y4m->vpx_bps = 16;
756 _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
757 _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
758 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h
759 + 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
760 /*Natively supported: no conversion required.*/
761 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
762 _y4m->convert = y4m_convert_null;
763 }
John Koleszarc6b90392012-07-13 15:21:29 -0700764 } else if (strcmp(_y4m->chroma_type, "411") == 0) {
765 _y4m->src_c_dec_h = 4;
766 _y4m->dst_c_dec_h = 2;
767 _y4m->src_c_dec_v = 1;
768 _y4m->dst_c_dec_v = 2;
769 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400770 /*Chroma filter required: read into the aux buf first.
771 We need to make two filter passes, so we need some extra space in the
772 aux buffer.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700773 _y4m->aux_buf_read_sz = 2 * ((_y4m->pic_w + 3) / 4) * _y4m->pic_h;
774 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz + ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
775 _y4m->convert = y4m_convert_411_420jpeg;
776 } else if (strcmp(_y4m->chroma_type, "444") == 0) {
777 _y4m->src_c_dec_h = 1;
John Koleszarc6b90392012-07-13 15:21:29 -0700778 _y4m->src_c_dec_v = 1;
John Koleszar8dd82872013-05-06 11:01:35 -0700779 if (only_420) {
780 _y4m->dst_c_dec_h = 2;
781 _y4m->dst_c_dec_v = 2;
782 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
783 /*Chroma filter required: read into the aux buf first.
784 We need to make two filter passes, so we need some extra space in the
785 aux buffer.*/
786 _y4m->aux_buf_read_sz = 2 * _y4m->pic_w * _y4m->pic_h;
787 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz +
788 ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
789 _y4m->convert = y4m_convert_444_420jpeg;
790 } else {
791 _y4m->vpx_fmt = VPX_IMG_FMT_I444;
792 _y4m->vpx_bps = 24;
793 _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
794 _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
795 _y4m->dst_buf_read_sz = 3 * _y4m->pic_w * _y4m->pic_h;
796 /*Natively supported: no conversion required.*/
797 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
798 _y4m->convert = y4m_convert_null;
799 }
John Koleszarc6b90392012-07-13 15:21:29 -0700800 } else if (strcmp(_y4m->chroma_type, "444alpha") == 0) {
801 _y4m->src_c_dec_h = 1;
John Koleszarc6b90392012-07-13 15:21:29 -0700802 _y4m->src_c_dec_v = 1;
John Koleszar8dd82872013-05-06 11:01:35 -0700803 if (only_420) {
804 _y4m->dst_c_dec_h = 2;
805 _y4m->dst_c_dec_v = 2;
806 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
807 /*Chroma filter required: read into the aux buf first.
808 We need to make two filter passes, so we need some extra space in the
809 aux buffer.
810 The extra plane also gets read into the aux buf.
811 It will be discarded.*/
812 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 3 * _y4m->pic_w * _y4m->pic_h;
813 _y4m->convert = y4m_convert_444_420jpeg;
814 } else {
815 _y4m->vpx_fmt = VPX_IMG_FMT_444A;
816 _y4m->vpx_bps = 32;
817 _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
818 _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
819 _y4m->dst_buf_read_sz = 4 * _y4m->pic_w * _y4m->pic_h;
820 /*Natively supported: no conversion required.*/
821 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
822 _y4m->convert = y4m_convert_null;
823 }
John Koleszarc6b90392012-07-13 15:21:29 -0700824 } else if (strcmp(_y4m->chroma_type, "mono") == 0) {
825 _y4m->src_c_dec_h = _y4m->src_c_dec_v = 0;
826 _y4m->dst_c_dec_h = _y4m->dst_c_dec_v = 2;
827 _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400828 /*No extra space required, but we need to clear the chroma planes.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700829 _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
830 _y4m->convert = y4m_convert_mono_420jpeg;
831 } else {
832 fprintf(stderr, "Unknown chroma sampling type: %s\n", _y4m->chroma_type);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400833 return -1;
834 }
835 /*The size of the final frame buffers is always computed from the
836 destination chroma decimation type.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700837 _y4m->dst_buf_sz = _y4m->pic_w * _y4m->pic_h
838 + 2 * ((_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h) *
839 ((_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v);
840 _y4m->dst_buf = (unsigned char *)malloc(_y4m->dst_buf_sz);
841 _y4m->aux_buf = (unsigned char *)malloc(_y4m->aux_buf_sz);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400842 return 0;
843}
844
John Koleszarc6b90392012-07-13 15:21:29 -0700845void y4m_input_close(y4m_input *_y4m) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400846 free(_y4m->dst_buf);
847 free(_y4m->aux_buf);
848}
849
John Koleszarc6b90392012-07-13 15:21:29 -0700850int y4m_input_fetch_frame(y4m_input *_y4m, FILE *_fin, vpx_image_t *_img) {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400851 char frame[6];
852 int pic_sz;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400853 int c_w;
854 int c_h;
855 int c_sz;
856 int ret;
857 /*Read and skip the frame header.*/
John Koleszar82b1a342012-11-06 12:08:05 -0800858 ret = (int)fread(frame, 1, 6, _fin);
John Koleszarc6b90392012-07-13 15:21:29 -0700859 if (ret < 6)return 0;
860 if (memcmp(frame, "FRAME", 5)) {
861 fprintf(stderr, "Loss of framing in Y4M input data\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400862 return -1;
863 }
John Koleszarc6b90392012-07-13 15:21:29 -0700864 if (frame[5] != '\n') {
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400865 char c;
866 int j;
John Koleszarc6b90392012-07-13 15:21:29 -0700867 for (j = 0; j < 79 && fread(&c, 1, 1, _fin) && c != '\n'; j++);
868 if (j == 79) {
869 fprintf(stderr, "Error parsing Y4M frame header\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400870 return -1;
871 }
872 }
873 /*Read the frame data that needs no conversion.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700874 if (fread(_y4m->dst_buf, 1, _y4m->dst_buf_read_sz, _fin) != _y4m->dst_buf_read_sz) {
875 fprintf(stderr, "Error reading Y4M frame data.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400876 return -1;
877 }
878 /*Read the frame data that does need conversion.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700879 if (fread(_y4m->aux_buf, 1, _y4m->aux_buf_read_sz, _fin) != _y4m->aux_buf_read_sz) {
880 fprintf(stderr, "Error reading Y4M frame data.\n");
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400881 return -1;
882 }
883 /*Now convert the just read frame.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700884 (*_y4m->convert)(_y4m, _y4m->dst_buf, _y4m->aux_buf);
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400885 /*Fill in the frame buffer pointers.
886 We don't use vpx_img_wrap() because it forces padding for odd picture
887 sizes, which would require a separate fread call for every row.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700888 memset(_img, 0, sizeof(*_img));
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400889 /*Y4M has the planes in Y'CbCr order, which libvpx calls Y, U, and V.*/
John Koleszar8dd82872013-05-06 11:01:35 -0700890 _img->fmt = _y4m->vpx_fmt;
John Koleszarc6b90392012-07-13 15:21:29 -0700891 _img->w = _img->d_w = _y4m->pic_w;
892 _img->h = _img->d_h = _y4m->pic_h;
John Koleszar8dd82872013-05-06 11:01:35 -0700893 _img->x_chroma_shift = _y4m->dst_c_dec_h >> 1;
894 _img->y_chroma_shift = _y4m->dst_c_dec_v >> 1;
895 _img->bps = _y4m->vpx_bps;
896
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400897 /*Set up the buffer pointers.*/
John Koleszarc6b90392012-07-13 15:21:29 -0700898 pic_sz = _y4m->pic_w * _y4m->pic_h;
899 c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
900 c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
901 c_sz = c_w * c_h;
John Koleszar8dd82872013-05-06 11:01:35 -0700902 _img->stride[PLANE_Y] = _img->stride[PLANE_ALPHA] = _y4m->pic_w;
John Koleszarc6b90392012-07-13 15:21:29 -0700903 _img->stride[PLANE_U] = _img->stride[PLANE_V] = c_w;
904 _img->planes[PLANE_Y] = _y4m->dst_buf;
905 _img->planes[PLANE_U] = _y4m->dst_buf + pic_sz;
906 _img->planes[PLANE_V] = _y4m->dst_buf + pic_sz + c_sz;
John Koleszar8dd82872013-05-06 11:01:35 -0700907 _img->planes[PLANE_ALPHA] = _y4m->dst_buf + pic_sz + 2 * c_sz;
Timothy B. Terriberryc4d7e5e2010-10-27 16:04:02 -0700908 return 1;
Timothy B. Terriberry44d89492010-05-26 18:27:51 -0400909}