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 "y4minput.h"
21
22 // Reads 'size' bytes from 'file' into 'buf' with some fault tolerance.
23 // Returns true on success.
file_read(void * buf,size_t size,FILE * file)24 static int file_read(void *buf, size_t size, FILE *file) {
25 const int kMaxTries = 5;
26 int try_count = 0;
27 int file_error = 0;
28 size_t len = 0;
29 while (!feof(file) && len < size && try_count < kMaxTries) {
30 const size_t n = fread((uint8_t *)buf + len, 1, size - len, file);
31 ++try_count;
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;
42 }
43 }
44 }
45
46 if (!feof(file) && len != size) {
47 fprintf(stderr,
48 "Error reading file: %u of %u bytes read,"
49 " error: %d, tries: %d, %d: %s\n",
50 (uint32_t)len, (uint32_t)size, file_error, try_count, errno,
51 strerror(errno));
52 }
53 return len == size;
54 }
55
56 // Stores the color range in 'y4m_ctx', returning 1 if successfully parsed,
57 // 0 otherwise.
parse_color_range(y4m_input * y4m_ctx,const char * buf)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;
62 }
63 if (strcmp(buf, "FULL") == 0) {
64 y4m_ctx->color_range = AOM_CR_FULL_RANGE;
65 return 1;
66 }
67 fprintf(stderr, "Unknown color range value: %s\n", buf);
68 return 0;
69 }
70
parse_metadata(y4m_input * y4m_ctx,const char * buf)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);
74 }
75 return 1; // No support for other metadata, just ignore them.
76 }
77
y4m_parse_tags(y4m_input * _y4m,char * _tags)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++) {
88 }
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;
100 }
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;
108 }
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.*/
119 }
120 }
121 return 0;
122 }
123
124 // Copy a single tag into the buffer, along with a null character.
125 // Returns 0 if any file IO errors occur.
copy_tag(char * buf,size_t buf_len,char * end_tag,FILE * file)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;
133 }
134 } while (buf[0] == ' ');
135
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;
141 }
142
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;
147 }
148 if (buf[i] == ' ' || buf[i] == '\n') {
149 break;
150 }
151 }
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;
156 }
157 *end_tag = buf[i];
158 buf[i] = '\0';
159 return 1;
160 }
161
162 // Returns 1 if tags were parsed successfully, 0 otherwise.
parse_tags(y4m_input * y4m_ctx,FILE * file)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");
176
177 // Find one tag at a time.
178 do {
179 if (!copy_tag(tag, sizeof(tag), &end, file)) {
180 return 0;
181 }
182 // y4m_parse_tags returns 0 on success.
183 if (y4m_parse_tags(y4m_ctx, tag)) {
184 return 0;
185 }
186 } while (end != '\n');
187
188 // Check the mandatory fields.
189 if (y4m_ctx->pic_w == -1) {
190 fprintf(stderr, "Width field missing\n");
191 return 0;
192 }
193 if (y4m_ctx->pic_h == -1) {
194 fprintf(stderr, "Height field missing\n");
195 return 0;
196 }
197 if (y4m_ctx->fps_n == -1) {
198 fprintf(stderr, "FPS field missing\n");
199 return 0;
200 }
201 return 1;
202 }
203
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.
215
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.
221
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)))
228
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 | | | |
246
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 | | | |
264
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).*/
y4m_42xmpeg2_42xjpeg_helper(unsigned char * _dst,const unsigned char * _src,int _c_w,int _c_h)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(
280 0,
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) >>
285 7,
286 255);
287 }
288 for (; x < _c_w - 3; x++) {
289 _dst[x] = (unsigned char)OC_CLAMPI(
290 0,
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) >>
293 7,
294 255);
295 }
296 for (; x < _c_w; x++) {
297 _dst[x] = (unsigned char)OC_CLAMPI(
298 0,
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) >>
302 7,
303 255);
304 }
305 _dst += _c_w;
306 _src += _c_w;
307 }
308 }
309
310 /*This format is only used for interlaced content, but is included for
311 completeness.
312
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 | | | |
330
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 | | | |
348
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.*/
y4m_convert_42xpaldv_42xjpeg(y4m_input * _y4m,unsigned char * _dst,unsigned char * _aux)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(
382 0,
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) >>
387 7,
388 255);
389 }
390 for (; y < c_h - 2; y++) {
391 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
392 0,
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) >>
396 7,
397 255);
398 }
399 for (; y < c_h; y++) {
400 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
401 0,
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) >>
406 7,
407 255);
408 }
409 _dst++;
410 tmp++;
411 }
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(
421 0,
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) >>
426 7,
427 255);
428 }
429 for (; y < c_h - 3; y++) {
430 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
431 0,
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) >>
435 7,
436 255);
437 }
438 for (; y < c_h; y++) {
439 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
440 0,
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) >>
445 7,
446 255);
447 }
448 _dst++;
449 tmp++;
450 }
451 } break;
452 }
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*/
460 }
461 }
462
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.*/
y4m_422jpeg_420jpeg_helper(unsigned char * _dst,const unsigned char * _src,int _c_w,int _c_h)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) >>
478 7,
479 255);
480 }
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) >>
487 7,
488 255);
489 }
490 for (; y < _c_h; y += 2) {
491 _dst[(y >> 1) * _c_w] = OC_CLAMPI(
492 0,
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) >>
497 7,
498 255);
499 }
500 _src++;
501 _dst++;
502 }
503 }
504
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 | | | |
522
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 | | | |
540
541 We use a resampling filter to decimate the chroma planes by two in the
542 vertical direction.*/
y4m_convert_422jpeg_420jpeg(y4m_input * _y4m,unsigned char * _dst,unsigned char * _aux)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;
565 }
566 }
567
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 | | | |
585
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 | | | |
603
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.*/
y4m_convert_422_420jpeg(y4m_input * _y4m,unsigned char * _dst,unsigned char * _aux)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;
636 }
637 }
638
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 | | | |
656
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 | | | |
674
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.*/
y4m_convert_411_420jpeg(y4m_input * _y4m,unsigned char * _dst,unsigned char * _aux)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(
714 0,
715 (111 * _aux[0] + 18 * _aux[OC_MINI(1, c_w - 1)] -
716 _aux[OC_MINI(2, c_w - 1)] + 64) >>
717 7,
718 255);
719 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
720 0,
721 (47 * _aux[0] + 86 * _aux[OC_MINI(1, c_w - 1)] -
722 5 * _aux[OC_MINI(2, c_w - 1)] + 64) >>
723 7,
724 255);
725 }
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) >>
731 7,
732 255);
733 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
734 0,
735 (-3 * _aux[x - 1] + 50 * _aux[x] + 86 * _aux[x + 1] -
736 5 * _aux[x + 2] + 64) >>
737 7,
738 255);
739 }
740 for (; x < c_w; x++) {
741 tmp[x << 1] = (unsigned char)OC_CLAMPI(
742 0,
743 (_aux[x - 1] + 110 * _aux[x] + 18 * _aux[OC_MINI(x + 1, c_w - 1)] -
744 _aux[c_w - 1] + 64) >>
745 7,
746 255);
747 if ((x << 1 | 1) < dst_c_w) {
748 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
749 0,
750 (-3 * _aux[x - 1] + 50 * _aux[x] +
751 86 * _aux[OC_MINI(x + 1, c_w - 1)] - 5 * _aux[c_w - 1] + 64) >>
752 7,
753 255);
754 }
755 }
756 tmp += dst_c_w;
757 _aux += c_w;
758 }
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;
763 }
764 }
765
766 /*Convert 444 to 420jpeg.*/
y4m_convert_444_420jpeg(y4m_input * _y4m,unsigned char * _dst,unsigned char * _aux)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) >>
799 7,
800 255);
801 }
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) >>
807 7,
808 255);
809 }
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) >>
816 7,
817 255);
818 }
819 tmp += dst_c_w;
820 _aux += c_w;
821 }
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;
826 }
827 }
828
829 /*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)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);
838 }
839
840 /*No conversion function needed.*/
y4m_convert_null(y4m_input * _y4m,unsigned char * _dst,unsigned char * _aux)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;
846 }
847
848 static const char TAG[] = "YUV4MPEG2";
849
y4m_input_open(y4m_input * y4m_ctx,FILE * file,char * skip_buffer,int num_skip,aom_chroma_sample_position_t csp,int only_420)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);
860 }
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;
864 }
865 if (memcmp(TAG, tag_buffer, 9) != 0) {
866 fprintf(stderr, "Error parsing header: must start with %s\n", TAG);
867 return -1;
868 }
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;
873 }
874 if (!parse_tags(y4m_ctx, file)) {
875 fprintf(stderr, "Error parsing %s header.\n", TAG);
876 return -1;
877 }
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;
887 }
888 /* Only support vertical chroma sample position if the input format is
889 * already 420mpeg2. Colocated is not supported in Y4M.
890 */
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;
897 }
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");
902 }
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;
936 }
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;
954 }
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;
1002 }
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;
1019 }
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;
1036 }
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;
1073 }
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;
1088 }
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;
1103 }
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;
1122 }
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;
1133 }
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);
1144 if (!y4m_ctx->dst_buf) return -1;
1145
1146 if (y4m_ctx->aux_buf_sz > 0) {
1147 y4m_ctx->aux_buf = (unsigned char *)malloc(y4m_ctx->aux_buf_sz);
1148 if (!y4m_ctx->aux_buf) {
1149 free(y4m_ctx->dst_buf);
1150 return -1;
1151 }
1152 }
1153 return 0;
1154 }
1155
y4m_input_close(y4m_input * _y4m)1156 void y4m_input_close(y4m_input *_y4m) {
1157 free(_y4m->dst_buf);
1158 free(_y4m->aux_buf);
1159 }
1160
y4m_input_fetch_frame(y4m_input * _y4m,FILE * _fin,aom_image_t * _img)1161 int y4m_input_fetch_frame(y4m_input *_y4m, FILE *_fin, aom_image_t *_img) {
1162 char frame[6];
1163 int pic_sz;
1164 int c_w;
1165 int c_h;
1166 int c_sz;
1167 int bytes_per_sample = _y4m->bit_depth > 8 ? 2 : 1;
1168 /*Read and skip the frame header.*/
1169 if (!file_read(frame, 6, _fin)) return 0;
1170 if (memcmp(frame, "FRAME", 5)) {
1171 fprintf(stderr, "Loss of framing in Y4M input data\n");
1172 return -1;
1173 }
1174 if (frame[5] != '\n') {
1175 char c;
1176 int j;
1177 for (j = 0; j < 79 && file_read(&c, 1, _fin) && c != '\n'; j++) {
1178 }
1179 if (j == 79) {
1180 fprintf(stderr, "Error parsing Y4M frame header\n");
1181 return -1;
1182 }
1183 }
1184 /*Read the frame data that needs no conversion.*/
1185 if (!file_read(_y4m->dst_buf, _y4m->dst_buf_read_sz, _fin)) {
1186 fprintf(stderr, "Error reading Y4M frame data.\n");
1187 return -1;
1188 }
1189 /*Read the frame data that does need conversion.*/
1190 if (!file_read(_y4m->aux_buf, _y4m->aux_buf_read_sz, _fin)) {
1191 fprintf(stderr, "Error reading Y4M frame data.\n");
1192 return -1;
1193 }
1194 /*Now convert the just read frame.*/
1195 (*_y4m->convert)(_y4m, _y4m->dst_buf, _y4m->aux_buf);
1196 /*Fill in the frame buffer pointers.
1197 We don't use aom_img_wrap() because it forces padding for odd picture
1198 sizes, which would require a separate fread call for every row.*/
1199 memset(_img, 0, sizeof(*_img));
1200 /*Y4M has the planes in Y'CbCr order, which libaom calls Y, U, and V.*/
1201 _img->fmt = _y4m->aom_fmt;
1202 _img->w = _img->d_w = _y4m->pic_w;
1203 _img->h = _img->d_h = _y4m->pic_h;
1204 _img->bit_depth = _y4m->bit_depth;
1205 _img->x_chroma_shift = _y4m->dst_c_dec_h >> 1;
1206 _img->y_chroma_shift = _y4m->dst_c_dec_v >> 1;
1207 _img->bps = _y4m->bps;
1208
1209 /*Set up the buffer pointers.*/
1210 pic_sz = _y4m->pic_w * _y4m->pic_h * bytes_per_sample;
1211 c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
1212 c_w *= bytes_per_sample;
1213 c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
1214 c_sz = c_w * c_h;
1215 _img->stride[AOM_PLANE_Y] = _y4m->pic_w * bytes_per_sample;
1216 _img->stride[AOM_PLANE_U] = _img->stride[AOM_PLANE_V] = c_w;
1217 _img->planes[AOM_PLANE_Y] = _y4m->dst_buf;
1218 _img->planes[AOM_PLANE_U] = _y4m->dst_buf + pic_sz;
1219 _img->planes[AOM_PLANE_V] = _y4m->dst_buf + pic_sz + c_sz;
1220 return 1;
1221 }
1222