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