hadamard: Add 4x4 test.
[aom.git] / common / y4minput.c
blob8e20b49610ff51182728fab7a908c279a0b0e46a
1 /*
2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
11 * Based on code from the OggTheora software codec source code,
12 * Copyright (C) 2002-2010 The Xiph.Org Foundation and contributors.
14 #include <assert.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
19 #include "aom/aom_integer.h"
20 #include "aom_ports/msvc.h"
21 #include "y4minput.h"
23 // Reads 'size' bytes from 'file' into 'buf' with some fault tolerance.
24 // Returns true on success.
25 static int file_read(void *buf, size_t size, FILE *file) {
26 const int kMaxRetries = 5;
27 int retry_count = 0;
28 int file_error;
29 size_t len = 0;
30 do {
31 const size_t n = fread((uint8_t *)buf + len, 1, size - len, file);
32 len += n;
33 file_error = ferror(file);
34 if (file_error) {
35 if (errno == EINTR || errno == EAGAIN) {
36 clearerr(file);
37 continue;
38 } else {
39 fprintf(stderr, "Error reading file: %u of %u bytes read, %d: %s\n",
40 (uint32_t)len, (uint32_t)size, errno, strerror(errno));
41 return 0;
44 } while (!feof(file) && len < size && ++retry_count < kMaxRetries);
46 if (!feof(file) && len != size) {
47 fprintf(stderr,
48 "Error reading file: %u of %u bytes read,"
49 " error: %d, retries: %d, %d: %s\n",
50 (uint32_t)len, (uint32_t)size, file_error, retry_count, errno,
51 strerror(errno));
53 return len == size;
56 // Stores the color range in 'y4m_ctx', returning 1 if successfully parsed,
57 // 0 otherwise.
58 static int parse_color_range(y4m_input *y4m_ctx, const char *buf) {
59 // Note that default is studio range.
60 if (strcmp(buf, "LIMITED") == 0) {
61 return 1;
63 if (strcmp(buf, "FULL") == 0) {
64 y4m_ctx->color_range = AOM_CR_FULL_RANGE;
65 return 1;
67 fprintf(stderr, "Unknown color range value: %s\n", buf);
68 return 0;
71 static int parse_metadata(y4m_input *y4m_ctx, const char *buf) {
72 if (strncmp(buf, "COLORRANGE=", 11) == 0) {
73 return parse_color_range(y4m_ctx, buf + 11);
75 return 1; // No support for other metadata, just ignore them.
78 static int y4m_parse_tags(y4m_input *_y4m, char *_tags) {
79 char *p;
80 char *q;
81 for (p = _tags;; p = q) {
82 /*Skip any leading spaces.*/
83 while (*p == ' ') p++;
84 /*If that's all we have, stop.*/
85 if (p[0] == '\0') break;
86 /*Find the end of this tag.*/
87 for (q = p + 1; *q != '\0' && *q != ' '; q++) {
89 /*Process the tag.*/
90 switch (p[0]) {
91 case 'W': {
92 if (sscanf(p + 1, "%d", &_y4m->pic_w) != 1) return -1;
93 } break;
94 case 'H': {
95 if (sscanf(p + 1, "%d", &_y4m->pic_h) != 1) return -1;
96 } break;
97 case 'F': {
98 if (sscanf(p + 1, "%d:%d", &_y4m->fps_n, &_y4m->fps_d) != 2) {
99 return -1;
101 } break;
102 case 'I': {
103 _y4m->interlace = p[1];
104 } break;
105 case 'A': {
106 if (sscanf(p + 1, "%d:%d", &_y4m->par_n, &_y4m->par_d) != 2) {
107 return -1;
109 } break;
110 case 'C': {
111 if (q - p > 16) return -1;
112 memcpy(_y4m->chroma_type, p + 1, q - p - 1);
113 _y4m->chroma_type[q - p - 1] = '\0';
114 } break;
115 case 'X': {
116 if (!parse_metadata(_y4m, p + 1)) return -1;
117 } break;
118 default: break; /*Ignore unknown tags.*/
121 return 0;
124 // Copy a single tag into the buffer, along with a null character.
125 // Returns 0 if any file IO errors occur.
126 static int copy_tag(char *buf, size_t buf_len, char *end_tag, FILE *file) {
127 size_t i;
128 assert(buf_len >= 1);
129 // Skip leading space characters.
130 do {
131 if (!file_read(buf, 1, file)) {
132 return 0;
134 } while (buf[0] == ' ');
136 // If we hit the newline, treat this as the "empty" tag.
137 if (buf[0] == '\n') {
138 buf[0] = '\0';
139 *end_tag = '\n';
140 return 1;
143 // Copy over characters until a space is hit, or the buffer is exhausted.
144 for (i = 1; i < buf_len; ++i) {
145 if (!file_read(buf + i, 1, file)) {
146 return 0;
148 if (buf[i] == ' ' || buf[i] == '\n') {
149 break;
152 if (i == buf_len) {
153 fprintf(stderr, "Error: Y4M header tags must be less than %lu characters\n",
154 (unsigned long)i);
155 return 0;
157 *end_tag = buf[i];
158 buf[i] = '\0';
159 return 1;
162 // Returns 1 if tags were parsed successfully, 0 otherwise.
163 static int parse_tags(y4m_input *y4m_ctx, FILE *file) {
164 char tag[256];
165 char end; // Character denoting the end of the tag, ' ' or '\n'.
166 // Set Y4M tags to defaults, updating them as processing occurs. Mandatory
167 // fields are marked with -1 and will be checked after the tags are parsed.
168 y4m_ctx->pic_w = -1;
169 y4m_ctx->pic_h = -1;
170 y4m_ctx->fps_n = -1; // Also serves as marker for fps_d
171 y4m_ctx->par_n = 0;
172 y4m_ctx->par_d = 0;
173 y4m_ctx->interlace = '?';
174 y4m_ctx->color_range = AOM_CR_STUDIO_RANGE;
175 snprintf(y4m_ctx->chroma_type, sizeof(y4m_ctx->chroma_type), "420");
177 // Find one tag at a time.
178 do {
179 if (!copy_tag(tag, sizeof(tag), &end, file)) {
180 return 0;
182 // y4m_parse_tags returns 0 on success.
183 if (y4m_parse_tags(y4m_ctx, tag)) {
184 return 0;
186 } while (end != '\n');
188 // Check the mandatory fields.
189 if (y4m_ctx->pic_w == -1) {
190 fprintf(stderr, "Width field missing\n");
191 return 0;
193 if (y4m_ctx->pic_h == -1) {
194 fprintf(stderr, "Height field missing\n");
195 return 0;
197 if (y4m_ctx->fps_n == -1) {
198 fprintf(stderr, "FPS field missing\n");
199 return 0;
201 return 1;
204 /*All anti-aliasing filters in the following conversion functions are based on
205 one of two window functions:
206 The 6-tap Lanczos window (for down-sampling and shifts):
207 sinc(\pi*t)*sinc(\pi*t/3), |t|<3 (sinc(t)==sin(t)/t)
208 0, |t|>=3
209 The 4-tap Mitchell window (for up-sampling):
210 7|t|^3-12|t|^2+16/3, |t|<1
211 -(7/3)|x|^3+12|x|^2-20|x|+32/3, |t|<2
212 0, |t|>=2
213 The number of taps is intentionally kept small to reduce computational
214 overhead and limit ringing.
216 The taps from these filters are scaled so that their sum is 1, and the
217 result is scaled by 128 and rounded to integers to create a filter whose
218 intermediate values fit inside 16 bits.
219 Coefficients are rounded in such a way as to ensure their sum is still 128,
220 which is usually equivalent to normal rounding.
222 Conversions which require both horizontal and vertical filtering could
223 have these steps pipelined, for less memory consumption and better cache
224 performance, but we do them separately for simplicity.*/
225 #define OC_MINI(_a, _b) ((_a) > (_b) ? (_b) : (_a))
226 #define OC_MAXI(_a, _b) ((_a) < (_b) ? (_b) : (_a))
227 #define OC_CLAMPI(_a, _b, _c) (OC_MAXI(_a, OC_MINI(_b, _c)))
229 /*420jpeg chroma samples are sited like:
230 Y-------Y-------Y-------Y-------
231 | | | |
232 | BR | | BR |
233 | | | |
234 Y-------Y-------Y-------Y-------
235 | | | |
236 | | | |
237 | | | |
238 Y-------Y-------Y-------Y-------
239 | | | |
240 | BR | | BR |
241 | | | |
242 Y-------Y-------Y-------Y-------
243 | | | |
244 | | | |
245 | | | |
247 420mpeg2 chroma samples are sited like:
248 Y-------Y-------Y-------Y-------
249 | | | |
250 BR | BR |
251 | | | |
252 Y-------Y-------Y-------Y-------
253 | | | |
254 | | | |
255 | | | |
256 Y-------Y-------Y-------Y-------
257 | | | |
258 BR | BR |
259 | | | |
260 Y-------Y-------Y-------Y-------
261 | | | |
262 | | | |
263 | | | |
265 We use a resampling filter to shift the site locations one quarter pixel (at
266 the chroma plane's resolution) to the right.
267 The 4:2:2 modes look exactly the same, except there are twice as many chroma
268 lines, and they are vertically co-sited with the luma samples in both the
269 mpeg2 and jpeg cases (thus requiring no vertical resampling).*/
270 static void y4m_42xmpeg2_42xjpeg_helper(unsigned char *_dst,
271 const unsigned char *_src, int _c_w,
272 int _c_h) {
273 int y;
274 int x;
275 for (y = 0; y < _c_h; y++) {
276 /*Filter: [4 -17 114 35 -9 1]/128, derived from a 6-tap Lanczos
277 window.*/
278 for (x = 0; x < OC_MINI(_c_w, 2); x++) {
279 _dst[x] = (unsigned char)OC_CLAMPI(
281 (4 * _src[0] - 17 * _src[OC_MAXI(x - 1, 0)] + 114 * _src[x] +
282 35 * _src[OC_MINI(x + 1, _c_w - 1)] -
283 9 * _src[OC_MINI(x + 2, _c_w - 1)] + _src[OC_MINI(x + 3, _c_w - 1)] +
284 64) >>
286 255);
288 for (; x < _c_w - 3; x++) {
289 _dst[x] = (unsigned char)OC_CLAMPI(
291 (4 * _src[x - 2] - 17 * _src[x - 1] + 114 * _src[x] +
292 35 * _src[x + 1] - 9 * _src[x + 2] + _src[x + 3] + 64) >>
294 255);
296 for (; x < _c_w; x++) {
297 _dst[x] = (unsigned char)OC_CLAMPI(
299 (4 * _src[x - 2] - 17 * _src[x - 1] + 114 * _src[x] +
300 35 * _src[OC_MINI(x + 1, _c_w - 1)] -
301 9 * _src[OC_MINI(x + 2, _c_w - 1)] + _src[_c_w - 1] + 64) >>
303 255);
305 _dst += _c_w;
306 _src += _c_w;
310 /*This format is only used for interlaced content, but is included for
311 completeness.
313 420jpeg chroma samples are sited like:
314 Y-------Y-------Y-------Y-------
315 | | | |
316 | BR | | BR |
317 | | | |
318 Y-------Y-------Y-------Y-------
319 | | | |
320 | | | |
321 | | | |
322 Y-------Y-------Y-------Y-------
323 | | | |
324 | BR | | BR |
325 | | | |
326 Y-------Y-------Y-------Y-------
327 | | | |
328 | | | |
329 | | | |
331 420paldv chroma samples are sited like:
332 YR------Y-------YR------Y-------
333 | | | |
334 | | | |
335 | | | |
336 YB------Y-------YB------Y-------
337 | | | |
338 | | | |
339 | | | |
340 YR------Y-------YR------Y-------
341 | | | |
342 | | | |
343 | | | |
344 YB------Y-------YB------Y-------
345 | | | |
346 | | | |
347 | | | |
349 We use a resampling filter to shift the site locations one quarter pixel (at
350 the chroma plane's resolution) to the right.
351 Then we use another filter to move the C_r location down one quarter pixel,
352 and the C_b location up one quarter pixel.*/
353 static void y4m_convert_42xpaldv_42xjpeg(y4m_input *_y4m, unsigned char *_dst,
354 unsigned char *_aux) {
355 unsigned char *tmp;
356 int c_w;
357 int c_h;
358 int c_sz;
359 int pli;
360 int y;
361 int x;
362 /*Skip past the luma data.*/
363 _dst += _y4m->pic_w * _y4m->pic_h;
364 /*Compute the size of each chroma plane.*/
365 c_w = (_y4m->pic_w + 1) / 2;
366 c_h = (_y4m->pic_h + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
367 c_sz = c_w * c_h;
368 tmp = _aux + 2 * c_sz;
369 for (pli = 1; pli < 3; pli++) {
370 /*First do the horizontal re-sampling.
371 This is the same as the mpeg2 case, except that after the horizontal
372 case, we need to apply a second vertical filter.*/
373 y4m_42xmpeg2_42xjpeg_helper(tmp, _aux, c_w, c_h);
374 _aux += c_sz;
375 switch (pli) {
376 case 1: {
377 /*Slide C_b up a quarter-pel.
378 This is the same filter used above, but in the other order.*/
379 for (x = 0; x < c_w; x++) {
380 for (y = 0; y < OC_MINI(c_h, 3); y++) {
381 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
383 (tmp[0] - 9 * tmp[OC_MAXI(y - 2, 0) * c_w] +
384 35 * tmp[OC_MAXI(y - 1, 0) * c_w] + 114 * tmp[y * c_w] -
385 17 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] +
386 4 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] + 64) >>
388 255);
390 for (; y < c_h - 2; y++) {
391 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
393 (tmp[(y - 3) * c_w] - 9 * tmp[(y - 2) * c_w] +
394 35 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w] -
395 17 * tmp[(y + 1) * c_w] + 4 * tmp[(y + 2) * c_w] + 64) >>
397 255);
399 for (; y < c_h; y++) {
400 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
402 (tmp[(y - 3) * c_w] - 9 * tmp[(y - 2) * c_w] +
403 35 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w] -
404 17 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] +
405 4 * tmp[(c_h - 1) * c_w] + 64) >>
407 255);
409 _dst++;
410 tmp++;
412 _dst += c_sz - c_w;
413 tmp -= c_w;
414 } break;
415 case 2: {
416 /*Slide C_r down a quarter-pel.
417 This is the same as the horizontal filter.*/
418 for (x = 0; x < c_w; x++) {
419 for (y = 0; y < OC_MINI(c_h, 2); y++) {
420 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
422 (4 * tmp[0] - 17 * tmp[OC_MAXI(y - 1, 0) * c_w] +
423 114 * tmp[y * c_w] + 35 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] -
424 9 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] +
425 tmp[OC_MINI(y + 3, c_h - 1) * c_w] + 64) >>
427 255);
429 for (; y < c_h - 3; y++) {
430 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
432 (4 * tmp[(y - 2) * c_w] - 17 * tmp[(y - 1) * c_w] +
433 114 * tmp[y * c_w] + 35 * tmp[(y + 1) * c_w] -
434 9 * tmp[(y + 2) * c_w] + tmp[(y + 3) * c_w] + 64) >>
436 255);
438 for (; y < c_h; y++) {
439 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
441 (4 * tmp[(y - 2) * c_w] - 17 * tmp[(y - 1) * c_w] +
442 114 * tmp[y * c_w] + 35 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] -
443 9 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] + tmp[(c_h - 1) * c_w] +
444 64) >>
446 255);
448 _dst++;
449 tmp++;
451 } break;
453 /*For actual interlaced material, this would have to be done separately on
454 each field, and the shift amounts would be different.
455 C_r moves down 1/8, C_b up 3/8 in the top field, and C_r moves down 3/8,
456 C_b up 1/8 in the bottom field.
457 The corresponding filters would be:
458 Down 1/8 (reverse order for up): [3 -11 125 15 -4 0]/128
459 Down 3/8 (reverse order for up): [4 -19 98 56 -13 2]/128*/
463 /*Perform vertical filtering to reduce a single plane from 4:2:2 to 4:2:0.
464 This is used as a helper by several conversion routines.*/
465 static void y4m_422jpeg_420jpeg_helper(unsigned char *_dst,
466 const unsigned char *_src, int _c_w,
467 int _c_h) {
468 int y;
469 int x;
470 /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/
471 for (x = 0; x < _c_w; x++) {
472 for (y = 0; y < OC_MINI(_c_h, 2); y += 2) {
473 _dst[(y >> 1) * _c_w] =
474 OC_CLAMPI(0,
475 (64 * _src[0] + 78 * _src[OC_MINI(1, _c_h - 1) * _c_w] -
476 17 * _src[OC_MINI(2, _c_h - 1) * _c_w] +
477 3 * _src[OC_MINI(3, _c_h - 1) * _c_w] + 64) >>
479 255);
481 for (; y < _c_h - 3; y += 2) {
482 _dst[(y >> 1) * _c_w] =
483 OC_CLAMPI(0,
484 (3 * (_src[(y - 2) * _c_w] + _src[(y + 3) * _c_w]) -
485 17 * (_src[(y - 1) * _c_w] + _src[(y + 2) * _c_w]) +
486 78 * (_src[y * _c_w] + _src[(y + 1) * _c_w]) + 64) >>
488 255);
490 for (; y < _c_h; y += 2) {
491 _dst[(y >> 1) * _c_w] = OC_CLAMPI(
493 (3 * (_src[(y - 2) * _c_w] + _src[(_c_h - 1) * _c_w]) -
494 17 * (_src[(y - 1) * _c_w] + _src[OC_MINI(y + 2, _c_h - 1) * _c_w]) +
495 78 * (_src[y * _c_w] + _src[OC_MINI(y + 1, _c_h - 1) * _c_w]) +
496 64) >>
498 255);
500 _src++;
501 _dst++;
505 /*420jpeg chroma samples are sited like:
506 Y-------Y-------Y-------Y-------
507 | | | |
508 | BR | | BR |
509 | | | |
510 Y-------Y-------Y-------Y-------
511 | | | |
512 | | | |
513 | | | |
514 Y-------Y-------Y-------Y-------
515 | | | |
516 | BR | | BR |
517 | | | |
518 Y-------Y-------Y-------Y-------
519 | | | |
520 | | | |
521 | | | |
523 422jpeg chroma samples are sited like:
524 Y---BR--Y-------Y---BR--Y-------
525 | | | |
526 | | | |
527 | | | |
528 Y---BR--Y-------Y---BR--Y-------
529 | | | |
530 | | | |
531 | | | |
532 Y---BR--Y-------Y---BR--Y-------
533 | | | |
534 | | | |
535 | | | |
536 Y---BR--Y-------Y---BR--Y-------
537 | | | |
538 | | | |
539 | | | |
541 We use a resampling filter to decimate the chroma planes by two in the
542 vertical direction.*/
543 static void y4m_convert_422jpeg_420jpeg(y4m_input *_y4m, unsigned char *_dst,
544 unsigned char *_aux) {
545 int c_w;
546 int c_h;
547 int c_sz;
548 int dst_c_w;
549 int dst_c_h;
550 int dst_c_sz;
551 int pli;
552 /*Skip past the luma data.*/
553 _dst += _y4m->pic_w * _y4m->pic_h;
554 /*Compute the size of each chroma plane.*/
555 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
556 c_h = _y4m->pic_h;
557 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
558 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
559 c_sz = c_w * c_h;
560 dst_c_sz = dst_c_w * dst_c_h;
561 for (pli = 1; pli < 3; pli++) {
562 y4m_422jpeg_420jpeg_helper(_dst, _aux, c_w, c_h);
563 _aux += c_sz;
564 _dst += dst_c_sz;
568 /*420jpeg chroma samples are sited like:
569 Y-------Y-------Y-------Y-------
570 | | | |
571 | BR | | BR |
572 | | | |
573 Y-------Y-------Y-------Y-------
574 | | | |
575 | | | |
576 | | | |
577 Y-------Y-------Y-------Y-------
578 | | | |
579 | BR | | BR |
580 | | | |
581 Y-------Y-------Y-------Y-------
582 | | | |
583 | | | |
584 | | | |
586 422 chroma samples are sited like:
587 YBR-----Y-------YBR-----Y-------
588 | | | |
589 | | | |
590 | | | |
591 YBR-----Y-------YBR-----Y-------
592 | | | |
593 | | | |
594 | | | |
595 YBR-----Y-------YBR-----Y-------
596 | | | |
597 | | | |
598 | | | |
599 YBR-----Y-------YBR-----Y-------
600 | | | |
601 | | | |
602 | | | |
604 We use a resampling filter to shift the original site locations one quarter
605 pixel (at the original chroma resolution) to the right.
606 Then we use a second resampling filter to decimate the chroma planes by two
607 in the vertical direction.*/
608 static void y4m_convert_422_420jpeg(y4m_input *_y4m, unsigned char *_dst,
609 unsigned char *_aux) {
610 unsigned char *tmp;
611 int c_w;
612 int c_h;
613 int c_sz;
614 int dst_c_h;
615 int dst_c_sz;
616 int pli;
617 /*Skip past the luma data.*/
618 _dst += _y4m->pic_w * _y4m->pic_h;
619 /*Compute the size of each chroma plane.*/
620 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
621 c_h = _y4m->pic_h;
622 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
623 c_sz = c_w * c_h;
624 dst_c_sz = c_w * dst_c_h;
625 tmp = _aux + 2 * c_sz;
626 for (pli = 1; pli < 3; pli++) {
627 /*In reality, the horizontal and vertical steps could be pipelined, for
628 less memory consumption and better cache performance, but we do them
629 separately for simplicity.*/
630 /*First do horizontal filtering (convert to 422jpeg)*/
631 y4m_42xmpeg2_42xjpeg_helper(tmp, _aux, c_w, c_h);
632 /*Now do the vertical filtering.*/
633 y4m_422jpeg_420jpeg_helper(_dst, tmp, c_w, c_h);
634 _aux += c_sz;
635 _dst += dst_c_sz;
639 /*420jpeg chroma samples are sited like:
640 Y-------Y-------Y-------Y-------
641 | | | |
642 | BR | | BR |
643 | | | |
644 Y-------Y-------Y-------Y-------
645 | | | |
646 | | | |
647 | | | |
648 Y-------Y-------Y-------Y-------
649 | | | |
650 | BR | | BR |
651 | | | |
652 Y-------Y-------Y-------Y-------
653 | | | |
654 | | | |
655 | | | |
657 411 chroma samples are sited like:
658 YBR-----Y-------Y-------Y-------
659 | | | |
660 | | | |
661 | | | |
662 YBR-----Y-------Y-------Y-------
663 | | | |
664 | | | |
665 | | | |
666 YBR-----Y-------Y-------Y-------
667 | | | |
668 | | | |
669 | | | |
670 YBR-----Y-------Y-------Y-------
671 | | | |
672 | | | |
673 | | | |
675 We use a filter to resample at site locations one eighth pixel (at the source
676 chroma plane's horizontal resolution) and five eighths of a pixel to the
677 right.
678 Then we use another filter to decimate the planes by 2 in the vertical
679 direction.*/
680 static void y4m_convert_411_420jpeg(y4m_input *_y4m, unsigned char *_dst,
681 unsigned char *_aux) {
682 unsigned char *tmp;
683 int c_w;
684 int c_h;
685 int c_sz;
686 int dst_c_w;
687 int dst_c_h;
688 int dst_c_sz;
689 int tmp_sz;
690 int pli;
691 int y;
692 int x;
693 /*Skip past the luma data.*/
694 _dst += _y4m->pic_w * _y4m->pic_h;
695 /*Compute the size of each chroma plane.*/
696 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
697 c_h = _y4m->pic_h;
698 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
699 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
700 c_sz = c_w * c_h;
701 dst_c_sz = dst_c_w * dst_c_h;
702 tmp_sz = dst_c_w * c_h;
703 tmp = _aux + 2 * c_sz;
704 for (pli = 1; pli < 3; pli++) {
705 /*In reality, the horizontal and vertical steps could be pipelined, for
706 less memory consumption and better cache performance, but we do them
707 separately for simplicity.*/
708 /*First do horizontal filtering (convert to 422jpeg)*/
709 for (y = 0; y < c_h; y++) {
710 /*Filters: [1 110 18 -1]/128 and [-3 50 86 -5]/128, both derived from a
711 4-tap Mitchell window.*/
712 for (x = 0; x < OC_MINI(c_w, 1); x++) {
713 tmp[x << 1] = (unsigned char)OC_CLAMPI(
715 (111 * _aux[0] + 18 * _aux[OC_MINI(1, c_w - 1)] -
716 _aux[OC_MINI(2, c_w - 1)] + 64) >>
718 255);
719 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
721 (47 * _aux[0] + 86 * _aux[OC_MINI(1, c_w - 1)] -
722 5 * _aux[OC_MINI(2, c_w - 1)] + 64) >>
724 255);
726 for (; x < c_w - 2; x++) {
727 tmp[x << 1] =
728 (unsigned char)OC_CLAMPI(0,
729 (_aux[x - 1] + 110 * _aux[x] +
730 18 * _aux[x + 1] - _aux[x + 2] + 64) >>
732 255);
733 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
735 (-3 * _aux[x - 1] + 50 * _aux[x] + 86 * _aux[x + 1] -
736 5 * _aux[x + 2] + 64) >>
738 255);
740 for (; x < c_w; x++) {
741 tmp[x << 1] = (unsigned char)OC_CLAMPI(
743 (_aux[x - 1] + 110 * _aux[x] + 18 * _aux[OC_MINI(x + 1, c_w - 1)] -
744 _aux[c_w - 1] + 64) >>
746 255);
747 if ((x << 1 | 1) < dst_c_w) {
748 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
750 (-3 * _aux[x - 1] + 50 * _aux[x] +
751 86 * _aux[OC_MINI(x + 1, c_w - 1)] - 5 * _aux[c_w - 1] + 64) >>
753 255);
756 tmp += dst_c_w;
757 _aux += c_w;
759 tmp -= tmp_sz;
760 /*Now do the vertical filtering.*/
761 y4m_422jpeg_420jpeg_helper(_dst, tmp, dst_c_w, c_h);
762 _dst += dst_c_sz;
766 /*Convert 444 to 420jpeg.*/
767 static void y4m_convert_444_420jpeg(y4m_input *_y4m, unsigned char *_dst,
768 unsigned char *_aux) {
769 unsigned char *tmp;
770 int c_w;
771 int c_h;
772 int c_sz;
773 int dst_c_w;
774 int dst_c_h;
775 int dst_c_sz;
776 int tmp_sz;
777 int pli;
778 int y;
779 int x;
780 /*Skip past the luma data.*/
781 _dst += _y4m->pic_w * _y4m->pic_h;
782 /*Compute the size of each chroma plane.*/
783 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
784 c_h = _y4m->pic_h;
785 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
786 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
787 c_sz = c_w * c_h;
788 dst_c_sz = dst_c_w * dst_c_h;
789 tmp_sz = dst_c_w * c_h;
790 tmp = _aux + 2 * c_sz;
791 for (pli = 1; pli < 3; pli++) {
792 /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/
793 for (y = 0; y < c_h; y++) {
794 for (x = 0; x < OC_MINI(c_w, 2); x += 2) {
795 tmp[x >> 1] = OC_CLAMPI(0,
796 (64 * _aux[0] + 78 * _aux[OC_MINI(1, c_w - 1)] -
797 17 * _aux[OC_MINI(2, c_w - 1)] +
798 3 * _aux[OC_MINI(3, c_w - 1)] + 64) >>
800 255);
802 for (; x < c_w - 3; x += 2) {
803 tmp[x >> 1] = OC_CLAMPI(0,
804 (3 * (_aux[x - 2] + _aux[x + 3]) -
805 17 * (_aux[x - 1] + _aux[x + 2]) +
806 78 * (_aux[x] + _aux[x + 1]) + 64) >>
808 255);
810 for (; x < c_w; x += 2) {
811 tmp[x >> 1] =
812 OC_CLAMPI(0,
813 (3 * (_aux[x - 2] + _aux[c_w - 1]) -
814 17 * (_aux[x - 1] + _aux[OC_MINI(x + 2, c_w - 1)]) +
815 78 * (_aux[x] + _aux[OC_MINI(x + 1, c_w - 1)]) + 64) >>
817 255);
819 tmp += dst_c_w;
820 _aux += c_w;
822 tmp -= tmp_sz;
823 /*Now do the vertical filtering.*/
824 y4m_422jpeg_420jpeg_helper(_dst, tmp, dst_c_w, c_h);
825 _dst += dst_c_sz;
829 /*The image is padded with empty chroma components at 4:2:0.*/
830 static void y4m_convert_mono_420jpeg(y4m_input *_y4m, unsigned char *_dst,
831 unsigned char *_aux) {
832 int c_sz;
833 (void)_aux;
834 _dst += _y4m->pic_w * _y4m->pic_h;
835 c_sz = ((_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h) *
836 ((_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v);
837 memset(_dst, 128, c_sz * 2);
840 /*No conversion function needed.*/
841 static void y4m_convert_null(y4m_input *_y4m, unsigned char *_dst,
842 unsigned char *_aux) {
843 (void)_y4m;
844 (void)_dst;
845 (void)_aux;
848 static const char TAG[] = "YUV4MPEG2";
850 int y4m_input_open(y4m_input *y4m_ctx, FILE *file, char *skip_buffer,
851 int num_skip, aom_chroma_sample_position_t csp,
852 int only_420) {
853 // File must start with |TAG|.
854 char tag_buffer[9]; // 9 == strlen(TAG)
855 // Read as much as possible from |skip_buffer|, which were characters
856 // that were previously read from the file to do input-type detection.
857 assert(num_skip >= 0 && num_skip <= 8);
858 if (num_skip > 0) {
859 memcpy(tag_buffer, skip_buffer, num_skip);
861 // Start reading from the file now that the |skip_buffer| is depleted.
862 if (!file_read(tag_buffer + num_skip, 9 - num_skip, file)) {
863 return -1;
865 if (memcmp(TAG, tag_buffer, 9) != 0) {
866 fprintf(stderr, "Error parsing header: must start with %s\n", TAG);
867 return -1;
869 // Next character must be a space.
870 if (!file_read(tag_buffer, 1, file) || tag_buffer[0] != ' ') {
871 fprintf(stderr, "Error parsing header: space must follow %s\n", TAG);
872 return -1;
874 if (!parse_tags(y4m_ctx, file)) {
875 fprintf(stderr, "Error parsing %s header.\n", TAG);
876 return -1;
878 if (y4m_ctx->interlace == '?') {
879 fprintf(stderr,
880 "Warning: Input video interlacing format unknown; "
881 "assuming progressive scan.\n");
882 } else if (y4m_ctx->interlace != 'p') {
883 fprintf(stderr,
884 "Input video is interlaced; "
885 "Only progressive scan handled.\n");
886 return -1;
888 /* Only support vertical chroma sample position if the input format is
889 * already 420mpeg2. Colocated is not supported in Y4M.
891 if (csp == AOM_CSP_VERTICAL &&
892 strcmp(y4m_ctx->chroma_type, "420mpeg2") != 0) {
893 fprintf(stderr,
894 "Vertical chroma sample position only supported "
895 "for 420mpeg2 input\n");
896 return -1;
898 if (csp == AOM_CSP_COLOCATED) {
899 // TODO(any): check the right way to handle this in y4m
900 fprintf(stderr,
901 "Ignoring colocated chroma sample position for reading in Y4M\n");
903 y4m_ctx->aom_fmt = AOM_IMG_FMT_I420;
904 y4m_ctx->bps = 12;
905 y4m_ctx->bit_depth = 8;
906 y4m_ctx->aux_buf = NULL;
907 y4m_ctx->dst_buf = NULL;
908 if (strcmp(y4m_ctx->chroma_type, "420") == 0 ||
909 strcmp(y4m_ctx->chroma_type, "420jpeg") == 0 ||
910 strcmp(y4m_ctx->chroma_type, "420mpeg2") == 0) {
911 y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_v =
912 y4m_ctx->dst_c_dec_v = 2;
913 y4m_ctx->dst_buf_read_sz =
914 y4m_ctx->pic_w * y4m_ctx->pic_h +
915 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
916 /* Natively supported: no conversion required. */
917 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
918 y4m_ctx->convert = y4m_convert_null;
919 } else if (strcmp(y4m_ctx->chroma_type, "420p10") == 0) {
920 y4m_ctx->src_c_dec_h = 2;
921 y4m_ctx->dst_c_dec_h = 2;
922 y4m_ctx->src_c_dec_v = 2;
923 y4m_ctx->dst_c_dec_v = 2;
924 y4m_ctx->dst_buf_read_sz =
925 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
926 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2));
927 /* Natively supported: no conversion required. */
928 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
929 y4m_ctx->convert = y4m_convert_null;
930 y4m_ctx->bit_depth = 10;
931 y4m_ctx->bps = 15;
932 y4m_ctx->aom_fmt = AOM_IMG_FMT_I42016;
933 if (only_420) {
934 fprintf(stderr, "Unsupported conversion from 420p10 to 420jpeg\n");
935 return -1;
937 } else if (strcmp(y4m_ctx->chroma_type, "420p12") == 0) {
938 y4m_ctx->src_c_dec_h = 2;
939 y4m_ctx->dst_c_dec_h = 2;
940 y4m_ctx->src_c_dec_v = 2;
941 y4m_ctx->dst_c_dec_v = 2;
942 y4m_ctx->dst_buf_read_sz =
943 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
944 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2));
945 /* Natively supported: no conversion required. */
946 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
947 y4m_ctx->convert = y4m_convert_null;
948 y4m_ctx->bit_depth = 12;
949 y4m_ctx->bps = 18;
950 y4m_ctx->aom_fmt = AOM_IMG_FMT_I42016;
951 if (only_420) {
952 fprintf(stderr, "Unsupported conversion from 420p12 to 420jpeg\n");
953 return -1;
955 } else if (strcmp(y4m_ctx->chroma_type, "420paldv") == 0) {
956 y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_v =
957 y4m_ctx->dst_c_dec_v = 2;
958 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
959 /*Chroma filter required: read into the aux buf first.
960 We need to make two filter passes, so we need some extra space in the
961 aux buffer.*/
962 y4m_ctx->aux_buf_sz =
963 3 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
964 y4m_ctx->aux_buf_read_sz =
965 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
966 y4m_ctx->convert = y4m_convert_42xpaldv_42xjpeg;
967 } else if (strcmp(y4m_ctx->chroma_type, "422jpeg") == 0) {
968 y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = 2;
969 y4m_ctx->src_c_dec_v = 1;
970 y4m_ctx->dst_c_dec_v = 2;
971 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
972 /*Chroma filter required: read into the aux buf first.*/
973 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz =
974 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
975 y4m_ctx->convert = y4m_convert_422jpeg_420jpeg;
976 } else if (strcmp(y4m_ctx->chroma_type, "422") == 0) {
977 y4m_ctx->src_c_dec_h = 2;
978 y4m_ctx->src_c_dec_v = 1;
979 if (only_420) {
980 y4m_ctx->dst_c_dec_h = 2;
981 y4m_ctx->dst_c_dec_v = 2;
982 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
983 /*Chroma filter required: read into the aux buf first.
984 We need to make two filter passes, so we need some extra space in the
985 aux buffer.*/
986 y4m_ctx->aux_buf_read_sz =
987 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
988 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz +
989 ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
990 y4m_ctx->convert = y4m_convert_422_420jpeg;
991 } else {
992 y4m_ctx->aom_fmt = AOM_IMG_FMT_I422;
993 y4m_ctx->bps = 16;
994 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
995 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
996 y4m_ctx->dst_buf_read_sz =
997 y4m_ctx->pic_w * y4m_ctx->pic_h +
998 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
999 /*Natively supported: no conversion required.*/
1000 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1001 y4m_ctx->convert = y4m_convert_null;
1003 } else if (strcmp(y4m_ctx->chroma_type, "422p10") == 0) {
1004 y4m_ctx->src_c_dec_h = 2;
1005 y4m_ctx->src_c_dec_v = 1;
1006 y4m_ctx->aom_fmt = AOM_IMG_FMT_I42216;
1007 y4m_ctx->bps = 20;
1008 y4m_ctx->bit_depth = 10;
1009 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
1010 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
1011 y4m_ctx->dst_buf_read_sz =
1012 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
1013 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h);
1014 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1015 y4m_ctx->convert = y4m_convert_null;
1016 if (only_420) {
1017 fprintf(stderr, "Unsupported conversion from 422p10 to 420jpeg\n");
1018 return -1;
1020 } else if (strcmp(y4m_ctx->chroma_type, "422p12") == 0) {
1021 y4m_ctx->src_c_dec_h = 2;
1022 y4m_ctx->src_c_dec_v = 1;
1023 y4m_ctx->aom_fmt = AOM_IMG_FMT_I42216;
1024 y4m_ctx->bps = 24;
1025 y4m_ctx->bit_depth = 12;
1026 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
1027 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
1028 y4m_ctx->dst_buf_read_sz =
1029 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
1030 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h);
1031 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1032 y4m_ctx->convert = y4m_convert_null;
1033 if (only_420) {
1034 fprintf(stderr, "Unsupported conversion from 422p12 to 420jpeg\n");
1035 return -1;
1037 } else if (strcmp(y4m_ctx->chroma_type, "411") == 0) {
1038 y4m_ctx->src_c_dec_h = 4;
1039 y4m_ctx->dst_c_dec_h = 2;
1040 y4m_ctx->src_c_dec_v = 1;
1041 y4m_ctx->dst_c_dec_v = 2;
1042 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
1043 /*Chroma filter required: read into the aux buf first.
1044 We need to make two filter passes, so we need some extra space in the
1045 aux buffer.*/
1046 y4m_ctx->aux_buf_read_sz = 2 * ((y4m_ctx->pic_w + 3) / 4) * y4m_ctx->pic_h;
1047 y4m_ctx->aux_buf_sz =
1048 y4m_ctx->aux_buf_read_sz + ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
1049 y4m_ctx->convert = y4m_convert_411_420jpeg;
1050 } else if (strcmp(y4m_ctx->chroma_type, "444") == 0) {
1051 y4m_ctx->src_c_dec_h = 1;
1052 y4m_ctx->src_c_dec_v = 1;
1053 if (only_420) {
1054 y4m_ctx->dst_c_dec_h = 2;
1055 y4m_ctx->dst_c_dec_v = 2;
1056 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
1057 /*Chroma filter required: read into the aux buf first.
1058 We need to make two filter passes, so we need some extra space in the
1059 aux buffer.*/
1060 y4m_ctx->aux_buf_read_sz = 2 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1061 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz +
1062 ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
1063 y4m_ctx->convert = y4m_convert_444_420jpeg;
1064 } else {
1065 y4m_ctx->aom_fmt = AOM_IMG_FMT_I444;
1066 y4m_ctx->bps = 24;
1067 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
1068 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
1069 y4m_ctx->dst_buf_read_sz = 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1070 /*Natively supported: no conversion required.*/
1071 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1072 y4m_ctx->convert = y4m_convert_null;
1074 } else if (strcmp(y4m_ctx->chroma_type, "444p10") == 0) {
1075 y4m_ctx->src_c_dec_h = 1;
1076 y4m_ctx->src_c_dec_v = 1;
1077 y4m_ctx->aom_fmt = AOM_IMG_FMT_I44416;
1078 y4m_ctx->bps = 30;
1079 y4m_ctx->bit_depth = 10;
1080 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
1081 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
1082 y4m_ctx->dst_buf_read_sz = 2 * 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1083 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1084 y4m_ctx->convert = y4m_convert_null;
1085 if (only_420) {
1086 fprintf(stderr, "Unsupported conversion from 444p10 to 420jpeg\n");
1087 return -1;
1089 } else if (strcmp(y4m_ctx->chroma_type, "444p12") == 0) {
1090 y4m_ctx->src_c_dec_h = 1;
1091 y4m_ctx->src_c_dec_v = 1;
1092 y4m_ctx->aom_fmt = AOM_IMG_FMT_I44416;
1093 y4m_ctx->bps = 36;
1094 y4m_ctx->bit_depth = 12;
1095 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
1096 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
1097 y4m_ctx->dst_buf_read_sz = 2 * 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1098 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1099 y4m_ctx->convert = y4m_convert_null;
1100 if (only_420) {
1101 fprintf(stderr, "Unsupported conversion from 444p12 to 420jpeg\n");
1102 return -1;
1104 } else if (strcmp(y4m_ctx->chroma_type, "444alpha") == 0) {
1105 y4m_ctx->src_c_dec_h = 1;
1106 y4m_ctx->src_c_dec_v = 1;
1107 if (only_420) {
1108 y4m_ctx->dst_c_dec_h = 2;
1109 y4m_ctx->dst_c_dec_v = 2;
1110 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
1111 /*Chroma filter required: read into the aux buf first.
1112 We need to make two filter passes, so we need some extra space in the
1113 aux buffer.
1114 The extra plane also gets read into the aux buf.
1115 It will be discarded.*/
1116 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz =
1117 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1118 y4m_ctx->convert = y4m_convert_444_420jpeg;
1119 } else {
1120 fprintf(stderr, "Unsupported format: 444A\n");
1121 return -1;
1123 } else if (strcmp(y4m_ctx->chroma_type, "mono") == 0) {
1124 y4m_ctx->src_c_dec_h = y4m_ctx->src_c_dec_v = 0;
1125 y4m_ctx->dst_c_dec_h = y4m_ctx->dst_c_dec_v = 2;
1126 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
1127 /*No extra space required, but we need to clear the chroma planes.*/
1128 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1129 y4m_ctx->convert = y4m_convert_mono_420jpeg;
1130 } else {
1131 fprintf(stderr, "Unknown chroma sampling type: %s\n", y4m_ctx->chroma_type);
1132 return -1;
1134 /*The size of the final frame buffers is always computed from the
1135 destination chroma decimation type.*/
1136 y4m_ctx->dst_buf_sz =
1137 y4m_ctx->pic_w * y4m_ctx->pic_h +
1138 2 * ((y4m_ctx->pic_w + y4m_ctx->dst_c_dec_h - 1) / y4m_ctx->dst_c_dec_h) *
1139 ((y4m_ctx->pic_h + y4m_ctx->dst_c_dec_v - 1) / y4m_ctx->dst_c_dec_v);
1140 if (y4m_ctx->bit_depth == 8)
1141 y4m_ctx->dst_buf = (unsigned char *)malloc(y4m_ctx->dst_buf_sz);
1142 else
1143 y4m_ctx->dst_buf = (unsigned char *)malloc(2 * y4m_ctx->dst_buf_sz);
1145 if (y4m_ctx->aux_buf_sz > 0)
1146 y4m_ctx->aux_buf = (unsigned char *)malloc(y4m_ctx->aux_buf_sz);
1147 return 0;
1150 void y4m_input_close(y4m_input *_y4m) {
1151 free(_y4m->dst_buf);
1152 free(_y4m->aux_buf);
1155 int y4m_input_fetch_frame(y4m_input *_y4m, FILE *_fin, aom_image_t *_img) {
1156 char frame[6];
1157 int pic_sz;
1158 int c_w;
1159 int c_h;
1160 int c_sz;
1161 int bytes_per_sample = _y4m->bit_depth > 8 ? 2 : 1;
1162 /*Read and skip the frame header.*/
1163 if (!file_read(frame, 6, _fin)) return 0;
1164 if (memcmp(frame, "FRAME", 5)) {
1165 fprintf(stderr, "Loss of framing in Y4M input data\n");
1166 return -1;
1168 if (frame[5] != '\n') {
1169 char c;
1170 int j;
1171 for (j = 0; j < 79 && file_read(&c, 1, _fin) && c != '\n'; j++) {
1173 if (j == 79) {
1174 fprintf(stderr, "Error parsing Y4M frame header\n");
1175 return -1;
1178 /*Read the frame data that needs no conversion.*/
1179 if (!file_read(_y4m->dst_buf, _y4m->dst_buf_read_sz, _fin)) {
1180 fprintf(stderr, "Error reading Y4M frame data.\n");
1181 return -1;
1183 /*Read the frame data that does need conversion.*/
1184 if (!file_read(_y4m->aux_buf, _y4m->aux_buf_read_sz, _fin)) {
1185 fprintf(stderr, "Error reading Y4M frame data.\n");
1186 return -1;
1188 /*Now convert the just read frame.*/
1189 (*_y4m->convert)(_y4m, _y4m->dst_buf, _y4m->aux_buf);
1190 /*Fill in the frame buffer pointers.
1191 We don't use aom_img_wrap() because it forces padding for odd picture
1192 sizes, which would require a separate fread call for every row.*/
1193 memset(_img, 0, sizeof(*_img));
1194 /*Y4M has the planes in Y'CbCr order, which libaom calls Y, U, and V.*/
1195 _img->fmt = _y4m->aom_fmt;
1196 _img->w = _img->d_w = _y4m->pic_w;
1197 _img->h = _img->d_h = _y4m->pic_h;
1198 _img->x_chroma_shift = _y4m->dst_c_dec_h >> 1;
1199 _img->y_chroma_shift = _y4m->dst_c_dec_v >> 1;
1200 _img->bps = _y4m->bps;
1202 /*Set up the buffer pointers.*/
1203 pic_sz = _y4m->pic_w * _y4m->pic_h * bytes_per_sample;
1204 c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
1205 c_w *= bytes_per_sample;
1206 c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
1207 c_sz = c_w * c_h;
1208 _img->stride[AOM_PLANE_Y] = _y4m->pic_w * bytes_per_sample;
1209 _img->stride[AOM_PLANE_U] = _img->stride[AOM_PLANE_V] = c_w;
1210 _img->planes[AOM_PLANE_Y] = _y4m->dst_buf;
1211 _img->planes[AOM_PLANE_U] = _y4m->dst_buf + pic_sz;
1212 _img->planes[AOM_PLANE_V] = _y4m->dst_buf + pic_sz + c_sz;
1213 return 1;