2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
10 * Based on code from the OggTheora software codec source code,
11 * Copyright (C) 2002-2010 The Xiph.Org Foundation and contributors.
18 #include "vpx/vpx_integer.h"
21 // Reads 'size' bytes from 'file' into 'buf' with some fault tolerance.
22 // Returns true on success.
23 static int file_read(void *buf, size_t size, FILE *file) {
24 const int kMaxRetries = 5;
29 const size_t n = fread((uint8_t *)buf + len, 1, size - len, file);
31 file_error = ferror(file);
33 if (errno == EINTR || errno == EAGAIN) {
37 fprintf(stderr, "Error reading file: %u of %u bytes read, %d: %s\n",
38 (uint32_t)len, (uint32_t)size, errno, strerror(errno));
42 } while (!feof(file) && len < size && ++retry_count < kMaxRetries);
44 if (!feof(file) && len != size) {
46 "Error reading file: %u of %u bytes read,"
47 " error: %d, retries: %d, %d: %s\n",
48 (uint32_t)len, (uint32_t)size, file_error, retry_count, errno,
54 static int y4m_parse_tags(y4m_input *_y4m, char *_tags) {
63 got_w = got_h = got_fps = got_interlace = got_par = got_chroma = 0;
64 for (p = _tags;; p = q) {
65 /*Skip any leading spaces.*/
66 while (*p == ' ') p++;
67 /*If that's all we have, stop.*/
68 if (p[0] == '\0') break;
69 /*Find the end of this tag.*/
70 for (q = p + 1; *q != '\0' && *q != ' '; q++) {
75 if (sscanf(p + 1, "%d", &_y4m->pic_w) != 1) return -1;
80 if (sscanf(p + 1, "%d", &_y4m->pic_h) != 1) return -1;
85 if (sscanf(p + 1, "%d:%d", &_y4m->fps_n, &_y4m->fps_d) != 2) {
92 _y4m->interlace = p[1];
97 if (sscanf(p + 1, "%d:%d", &_y4m->par_n, &_y4m->par_d) != 2) {
104 if (q - p > 16) return -1;
105 memcpy(_y4m->chroma_type, p + 1, q - p - 1);
106 _y4m->chroma_type[q - p - 1] = '\0';
110 /*Ignore unknown tags.*/
113 if (!got_w || !got_h || !got_fps) return -1;
114 if (!got_interlace) _y4m->interlace = '?';
115 if (!got_par) _y4m->par_n = _y4m->par_d = 0;
116 /*Chroma-type is not specified in older files, e.g., those generated by
118 if (!got_chroma) strcpy(_y4m->chroma_type, "420");
122 /*All anti-aliasing filters in the following conversion functions are based on
123 one of two window functions:
124 The 6-tap Lanczos window (for down-sampling and shifts):
125 sinc(\pi*t)*sinc(\pi*t/3), |t|<3 (sinc(t)==sin(t)/t)
127 The 4-tap Mitchell window (for up-sampling):
128 7|t|^3-12|t|^2+16/3, |t|<1
129 -(7/3)|x|^3+12|x|^2-20|x|+32/3, |t|<2
131 The number of taps is intentionally kept small to reduce computational
132 overhead and limit ringing.
134 The taps from these filters are scaled so that their sum is 1, and the
135 result is scaled by 128 and rounded to integers to create a filter whose
136 intermediate values fit inside 16 bits.
137 Coefficients are rounded in such a way as to ensure their sum is still 128,
138 which is usually equivalent to normal rounding.
140 Conversions which require both horizontal and vertical filtering could
141 have these steps pipelined, for less memory consumption and better cache
142 performance, but we do them separately for simplicity.*/
143 #define OC_MINI(_a, _b) ((_a) > (_b) ? (_b) : (_a))
144 #define OC_MAXI(_a, _b) ((_a) < (_b) ? (_b) : (_a))
145 #define OC_CLAMPI(_a, _b, _c) (OC_MAXI(_a, OC_MINI(_b, _c)))
147 /*420jpeg chroma samples are sited like:
148 Y-------Y-------Y-------Y-------
152 Y-------Y-------Y-------Y-------
156 Y-------Y-------Y-------Y-------
160 Y-------Y-------Y-------Y-------
165 420mpeg2 chroma samples are sited like:
166 Y-------Y-------Y-------Y-------
170 Y-------Y-------Y-------Y-------
174 Y-------Y-------Y-------Y-------
178 Y-------Y-------Y-------Y-------
183 We use a resampling filter to shift the site locations one quarter pixel (at
184 the chroma plane's resolution) to the right.
185 The 4:2:2 modes look exactly the same, except there are twice as many chroma
186 lines, and they are vertically co-sited with the luma samples in both the
187 mpeg2 and jpeg cases (thus requiring no vertical resampling).*/
188 static void y4m_42xmpeg2_42xjpeg_helper(unsigned char *_dst,
189 const unsigned char *_src, int _c_w,
193 for (y = 0; y < _c_h; y++) {
194 /*Filter: [4 -17 114 35 -9 1]/128, derived from a 6-tap Lanczos
196 for (x = 0; x < OC_MINI(_c_w, 2); x++) {
197 _dst[x] = (unsigned char)OC_CLAMPI(
199 (4 * _src[0] - 17 * _src[OC_MAXI(x - 1, 0)] + 114 * _src[x] +
200 35 * _src[OC_MINI(x + 1, _c_w - 1)] -
201 9 * _src[OC_MINI(x + 2, _c_w - 1)] + _src[OC_MINI(x + 3, _c_w - 1)] +
206 for (; x < _c_w - 3; x++) {
207 _dst[x] = (unsigned char)OC_CLAMPI(
209 (4 * _src[x - 2] - 17 * _src[x - 1] + 114 * _src[x] +
210 35 * _src[x + 1] - 9 * _src[x + 2] + _src[x + 3] + 64) >>
214 for (; x < _c_w; x++) {
215 _dst[x] = (unsigned char)OC_CLAMPI(
217 (4 * _src[x - 2] - 17 * _src[x - 1] + 114 * _src[x] +
218 35 * _src[OC_MINI(x + 1, _c_w - 1)] -
219 9 * _src[OC_MINI(x + 2, _c_w - 1)] + _src[_c_w - 1] + 64) >>
228 /*Handles both 422 and 420mpeg2 to 422jpeg and 420jpeg, respectively.*/
229 static void y4m_convert_42xmpeg2_42xjpeg(y4m_input *_y4m, unsigned char *_dst,
230 unsigned char *_aux) {
235 /*Skip past the luma data.*/
236 _dst += _y4m->pic_w * _y4m->pic_h;
237 /*Compute the size of each chroma plane.*/
238 c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
239 c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
241 for (pli = 1; pli < 3; pli++) {
242 y4m_42xmpeg2_42xjpeg_helper(_dst, _aux, c_w, c_h);
248 /*This format is only used for interlaced content, but is included for
251 420jpeg chroma samples are sited like:
252 Y-------Y-------Y-------Y-------
256 Y-------Y-------Y-------Y-------
260 Y-------Y-------Y-------Y-------
264 Y-------Y-------Y-------Y-------
269 420paldv chroma samples are sited like:
270 YR------Y-------YR------Y-------
274 YB------Y-------YB------Y-------
278 YR------Y-------YR------Y-------
282 YB------Y-------YB------Y-------
287 We use a resampling filter to shift the site locations one quarter pixel (at
288 the chroma plane's resolution) to the right.
289 Then we use another filter to move the C_r location down one quarter pixel,
290 and the C_b location up one quarter pixel.*/
291 static void y4m_convert_42xpaldv_42xjpeg(y4m_input *_y4m, unsigned char *_dst,
292 unsigned char *_aux) {
300 /*Skip past the luma data.*/
301 _dst += _y4m->pic_w * _y4m->pic_h;
302 /*Compute the size of each chroma plane.*/
303 c_w = (_y4m->pic_w + 1) / 2;
304 c_h = (_y4m->pic_h + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
306 tmp = _aux + 2 * c_sz;
307 for (pli = 1; pli < 3; pli++) {
308 /*First do the horizontal re-sampling.
309 This is the same as the mpeg2 case, except that after the horizontal
310 case, we need to apply a second vertical filter.*/
311 y4m_42xmpeg2_42xjpeg_helper(tmp, _aux, c_w, c_h);
315 /*Slide C_b up a quarter-pel.
316 This is the same filter used above, but in the other order.*/
317 for (x = 0; x < c_w; x++) {
318 for (y = 0; y < OC_MINI(c_h, 3); y++) {
319 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
321 (tmp[0] - 9 * tmp[OC_MAXI(y - 2, 0) * c_w] +
322 35 * tmp[OC_MAXI(y - 1, 0) * c_w] + 114 * tmp[y * c_w] -
323 17 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] +
324 4 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] + 64) >>
328 for (; y < c_h - 2; y++) {
329 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
331 (tmp[(y - 3) * c_w] - 9 * tmp[(y - 2) * c_w] +
332 35 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w] -
333 17 * tmp[(y + 1) * c_w] + 4 * tmp[(y + 2) * c_w] + 64) >>
337 for (; y < c_h; y++) {
338 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
340 (tmp[(y - 3) * c_w] - 9 * tmp[(y - 2) * c_w] +
341 35 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w] -
342 17 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] +
343 4 * tmp[(c_h - 1) * c_w] + 64) >>
355 /*Slide C_r down a quarter-pel.
356 This is the same as the horizontal filter.*/
357 for (x = 0; x < c_w; x++) {
358 for (y = 0; y < OC_MINI(c_h, 2); y++) {
359 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
361 (4 * tmp[0] - 17 * tmp[OC_MAXI(y - 1, 0) * c_w] +
362 114 * tmp[y * c_w] + 35 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] -
363 9 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] +
364 tmp[OC_MINI(y + 3, c_h - 1) * c_w] + 64) >>
368 for (; y < c_h - 3; y++) {
369 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
371 (4 * tmp[(y - 2) * c_w] - 17 * tmp[(y - 1) * c_w] +
372 114 * tmp[y * c_w] + 35 * tmp[(y + 1) * c_w] -
373 9 * tmp[(y + 2) * c_w] + tmp[(y + 3) * c_w] + 64) >>
377 for (; y < c_h; y++) {
378 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
380 (4 * tmp[(y - 2) * c_w] - 17 * tmp[(y - 1) * c_w] +
381 114 * tmp[y * c_w] + 35 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] -
382 9 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] + tmp[(c_h - 1) * c_w] +
393 /*For actual interlaced material, this would have to be done separately on
394 each field, and the shift amounts would be different.
395 C_r moves down 1/8, C_b up 3/8 in the top field, and C_r moves down 3/8,
396 C_b up 1/8 in the bottom field.
397 The corresponding filters would be:
398 Down 1/8 (reverse order for up): [3 -11 125 15 -4 0]/128
399 Down 3/8 (reverse order for up): [4 -19 98 56 -13 2]/128*/
403 /*Perform vertical filtering to reduce a single plane from 4:2:2 to 4:2:0.
404 This is used as a helper by several converation routines.*/
405 static void y4m_422jpeg_420jpeg_helper(unsigned char *_dst,
406 const unsigned char *_src, int _c_w,
410 /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/
411 for (x = 0; x < _c_w; x++) {
412 for (y = 0; y < OC_MINI(_c_h, 2); y += 2) {
413 _dst[(y >> 1) * _c_w] =
415 (64 * _src[0] + 78 * _src[OC_MINI(1, _c_h - 1) * _c_w] -
416 17 * _src[OC_MINI(2, _c_h - 1) * _c_w] +
417 3 * _src[OC_MINI(3, _c_h - 1) * _c_w] + 64) >>
421 for (; y < _c_h - 3; y += 2) {
422 _dst[(y >> 1) * _c_w] =
424 (3 * (_src[(y - 2) * _c_w] + _src[(y + 3) * _c_w]) -
425 17 * (_src[(y - 1) * _c_w] + _src[(y + 2) * _c_w]) +
426 78 * (_src[y * _c_w] + _src[(y + 1) * _c_w]) + 64) >>
430 for (; y < _c_h; y += 2) {
431 _dst[(y >> 1) * _c_w] = OC_CLAMPI(
433 (3 * (_src[(y - 2) * _c_w] + _src[(_c_h - 1) * _c_w]) -
434 17 * (_src[(y - 1) * _c_w] + _src[OC_MINI(y + 2, _c_h - 1) * _c_w]) +
435 78 * (_src[y * _c_w] + _src[OC_MINI(y + 1, _c_h - 1) * _c_w]) +
445 /*420jpeg chroma samples are sited like:
446 Y-------Y-------Y-------Y-------
450 Y-------Y-------Y-------Y-------
454 Y-------Y-------Y-------Y-------
458 Y-------Y-------Y-------Y-------
463 422jpeg chroma samples are sited like:
464 Y---BR--Y-------Y---BR--Y-------
468 Y---BR--Y-------Y---BR--Y-------
472 Y---BR--Y-------Y---BR--Y-------
476 Y---BR--Y-------Y---BR--Y-------
481 We use a resampling filter to decimate the chroma planes by two in the
482 vertical direction.*/
483 static void y4m_convert_422jpeg_420jpeg(y4m_input *_y4m, unsigned char *_dst,
484 unsigned char *_aux) {
492 /*Skip past the luma data.*/
493 _dst += _y4m->pic_w * _y4m->pic_h;
494 /*Compute the size of each chroma plane.*/
495 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
497 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
498 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
500 dst_c_sz = dst_c_w * dst_c_h;
501 for (pli = 1; pli < 3; pli++) {
502 y4m_422jpeg_420jpeg_helper(_dst, _aux, c_w, c_h);
508 /*420jpeg chroma samples are sited like:
509 Y-------Y-------Y-------Y-------
513 Y-------Y-------Y-------Y-------
517 Y-------Y-------Y-------Y-------
521 Y-------Y-------Y-------Y-------
526 422 chroma samples are sited like:
527 YBR-----Y-------YBR-----Y-------
531 YBR-----Y-------YBR-----Y-------
535 YBR-----Y-------YBR-----Y-------
539 YBR-----Y-------YBR-----Y-------
544 We use a resampling filter to shift the original site locations one quarter
545 pixel (at the original chroma resolution) to the right.
546 Then we use a second resampling filter to decimate the chroma planes by two
547 in the vertical direction.*/
548 static void y4m_convert_422_420jpeg(y4m_input *_y4m, unsigned char *_dst,
549 unsigned char *_aux) {
557 /*Skip past the luma data.*/
558 _dst += _y4m->pic_w * _y4m->pic_h;
559 /*Compute the size of each chroma plane.*/
560 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
562 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
564 dst_c_sz = c_w * dst_c_h;
565 tmp = _aux + 2 * c_sz;
566 for (pli = 1; pli < 3; pli++) {
567 /*In reality, the horizontal and vertical steps could be pipelined, for
568 less memory consumption and better cache performance, but we do them
569 separately for simplicity.*/
570 /*First do horizontal filtering (convert to 422jpeg)*/
571 y4m_42xmpeg2_42xjpeg_helper(tmp, _aux, c_w, c_h);
572 /*Now do the vertical filtering.*/
573 y4m_422jpeg_420jpeg_helper(_dst, tmp, c_w, c_h);
579 /*420jpeg chroma samples are sited like:
580 Y-------Y-------Y-------Y-------
584 Y-------Y-------Y-------Y-------
588 Y-------Y-------Y-------Y-------
592 Y-------Y-------Y-------Y-------
597 411 chroma samples are sited like:
598 YBR-----Y-------Y-------Y-------
602 YBR-----Y-------Y-------Y-------
606 YBR-----Y-------Y-------Y-------
610 YBR-----Y-------Y-------Y-------
615 We use a filter to resample at site locations one eighth pixel (at the source
616 chroma plane's horizontal resolution) and five eighths of a pixel to the
618 Then we use another filter to decimate the planes by 2 in the vertical
620 static void y4m_convert_411_420jpeg(y4m_input *_y4m, unsigned char *_dst,
621 unsigned char *_aux) {
633 /*Skip past the luma data.*/
634 _dst += _y4m->pic_w * _y4m->pic_h;
635 /*Compute the size of each chroma plane.*/
636 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
638 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
639 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
641 dst_c_sz = dst_c_w * dst_c_h;
642 tmp_sz = dst_c_w * c_h;
643 tmp = _aux + 2 * c_sz;
644 for (pli = 1; pli < 3; pli++) {
645 /*In reality, the horizontal and vertical steps could be pipelined, for
646 less memory consumption and better cache performance, but we do them
647 separately for simplicity.*/
648 /*First do horizontal filtering (convert to 422jpeg)*/
649 for (y = 0; y < c_h; y++) {
650 /*Filters: [1 110 18 -1]/128 and [-3 50 86 -5]/128, both derived from a
651 4-tap Mitchell window.*/
652 for (x = 0; x < OC_MINI(c_w, 1); x++) {
653 tmp[x << 1] = (unsigned char)OC_CLAMPI(
655 (111 * _aux[0] + 18 * _aux[OC_MINI(1, c_w - 1)] -
656 _aux[OC_MINI(2, c_w - 1)] + 64) >>
659 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
661 (47 * _aux[0] + 86 * _aux[OC_MINI(1, c_w - 1)] -
662 5 * _aux[OC_MINI(2, c_w - 1)] + 64) >>
666 for (; x < c_w - 2; x++) {
668 (unsigned char)OC_CLAMPI(0,
669 (_aux[x - 1] + 110 * _aux[x] +
670 18 * _aux[x + 1] - _aux[x + 2] + 64) >>
673 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
675 (-3 * _aux[x - 1] + 50 * _aux[x] + 86 * _aux[x + 1] -
676 5 * _aux[x + 2] + 64) >>
680 for (; x < c_w; x++) {
681 tmp[x << 1] = (unsigned char)OC_CLAMPI(
683 (_aux[x - 1] + 110 * _aux[x] + 18 * _aux[OC_MINI(x + 1, c_w - 1)] -
684 _aux[c_w - 1] + 64) >>
687 if ((x << 1 | 1) < dst_c_w) {
688 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
690 (-3 * _aux[x - 1] + 50 * _aux[x] +
691 86 * _aux[OC_MINI(x + 1, c_w - 1)] - 5 * _aux[c_w - 1] + 64) >>
700 /*Now do the vertical filtering.*/
701 y4m_422jpeg_420jpeg_helper(_dst, tmp, dst_c_w, c_h);
706 /*Convert 444 to 420jpeg.*/
707 static void y4m_convert_444_420jpeg(y4m_input *_y4m, unsigned char *_dst,
708 unsigned char *_aux) {
720 /*Skip past the luma data.*/
721 _dst += _y4m->pic_w * _y4m->pic_h;
722 /*Compute the size of each chroma plane.*/
723 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
725 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
726 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
728 dst_c_sz = dst_c_w * dst_c_h;
729 tmp_sz = dst_c_w * c_h;
730 tmp = _aux + 2 * c_sz;
731 for (pli = 1; pli < 3; pli++) {
732 /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/
733 for (y = 0; y < c_h; y++) {
734 for (x = 0; x < OC_MINI(c_w, 2); x += 2) {
735 tmp[x >> 1] = OC_CLAMPI(0,
736 (64 * _aux[0] + 78 * _aux[OC_MINI(1, c_w - 1)] -
737 17 * _aux[OC_MINI(2, c_w - 1)] +
738 3 * _aux[OC_MINI(3, c_w - 1)] + 64) >>
742 for (; x < c_w - 3; x += 2) {
743 tmp[x >> 1] = OC_CLAMPI(0,
744 (3 * (_aux[x - 2] + _aux[x + 3]) -
745 17 * (_aux[x - 1] + _aux[x + 2]) +
746 78 * (_aux[x] + _aux[x + 1]) + 64) >>
750 for (; x < c_w; x += 2) {
753 (3 * (_aux[x - 2] + _aux[c_w - 1]) -
754 17 * (_aux[x - 1] + _aux[OC_MINI(x + 2, c_w - 1)]) +
755 78 * (_aux[x] + _aux[OC_MINI(x + 1, c_w - 1)]) + 64) >>
763 /*Now do the vertical filtering.*/
764 y4m_422jpeg_420jpeg_helper(_dst, tmp, dst_c_w, c_h);
769 /*The image is padded with empty chroma components at 4:2:0.*/
770 static void y4m_convert_mono_420jpeg(y4m_input *_y4m, unsigned char *_dst,
771 unsigned char *_aux) {
774 _dst += _y4m->pic_w * _y4m->pic_h;
775 c_sz = ((_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h) *
776 ((_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v);
777 memset(_dst, 128, c_sz * 2);
780 /*No conversion function needed.*/
781 static void y4m_convert_null(y4m_input *_y4m, unsigned char *_dst,
782 unsigned char *_aux) {
788 static const char TAG[] = "YUV4MPEG2";
790 int y4m_input_open(y4m_input *y4m_ctx, FILE *file, char *skip_buffer,
791 int num_skip, int only_420) {
792 // File must start with |TAG|.
793 char tag_buffer[9]; // 9 == strlen(TAG)
794 char buffer[80] = { 0 };
797 // Read as much as possible from |skip_buffer|, which were characters
798 // that were previously read from the file to do input-type detection.
799 assert(num_skip >= 0 && num_skip <= 8);
801 memcpy(tag_buffer, skip_buffer, num_skip);
803 // Start reading from the file now that the |skip_buffer| is depleted.
804 if (!file_read(tag_buffer + num_skip, 9 - num_skip, file)) {
807 if (memcmp(TAG, tag_buffer, 9) != 0) {
808 fprintf(stderr, "Error parsing header: must start with %s\n", TAG);
811 // Next character must be a space.
812 if (!file_read(buffer, 1, file) || buffer[0] != ' ') {
813 fprintf(stderr, "Error parsing header: space must follow %s\n", TAG);
816 /*Read until newline, or 80 cols, whichever happens first.*/
817 for (i = 0; i < 79; i++) {
818 if (!file_read(buffer + i, 1, file)) return -1;
819 if (buffer[i] == '\n') break;
821 /*We skipped too much header data.*/
823 fprintf(stderr, "Error parsing header; not a YUV4MPEG2 file?\n");
827 ret = y4m_parse_tags(y4m_ctx, buffer);
829 fprintf(stderr, "Error parsing YUV4MPEG2 header.\n");
832 if (y4m_ctx->interlace == '?') {
834 "Warning: Input video interlacing format unknown; "
835 "assuming progressive scan.\n");
836 } else if (y4m_ctx->interlace != 'p') {
838 "Input video is interlaced; "
839 "Only progressive scan handled.\n");
842 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I420;
844 y4m_ctx->bit_depth = 8;
845 y4m_ctx->aux_buf = NULL;
846 y4m_ctx->dst_buf = NULL;
847 if (strcmp(y4m_ctx->chroma_type, "420") == 0 ||
848 strcmp(y4m_ctx->chroma_type, "420jpeg") == 0) {
849 y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_v =
850 y4m_ctx->dst_c_dec_v = 2;
851 y4m_ctx->dst_buf_read_sz =
852 y4m_ctx->pic_w * y4m_ctx->pic_h +
853 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
854 /* Natively supported: no conversion required. */
855 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
856 y4m_ctx->convert = y4m_convert_null;
857 } else if (strcmp(y4m_ctx->chroma_type, "420p10") == 0) {
858 y4m_ctx->src_c_dec_h = 2;
859 y4m_ctx->dst_c_dec_h = 2;
860 y4m_ctx->src_c_dec_v = 2;
861 y4m_ctx->dst_c_dec_v = 2;
862 y4m_ctx->dst_buf_read_sz =
863 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
864 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2));
865 /* Natively supported: no conversion required. */
866 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
867 y4m_ctx->convert = y4m_convert_null;
868 y4m_ctx->bit_depth = 10;
870 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I42016;
872 fprintf(stderr, "Unsupported conversion from 420p10 to 420jpeg\n");
875 } else if (strcmp(y4m_ctx->chroma_type, "420p12") == 0) {
876 y4m_ctx->src_c_dec_h = 2;
877 y4m_ctx->dst_c_dec_h = 2;
878 y4m_ctx->src_c_dec_v = 2;
879 y4m_ctx->dst_c_dec_v = 2;
880 y4m_ctx->dst_buf_read_sz =
881 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
882 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2));
883 /* Natively supported: no conversion required. */
884 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
885 y4m_ctx->convert = y4m_convert_null;
886 y4m_ctx->bit_depth = 12;
888 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I42016;
890 fprintf(stderr, "Unsupported conversion from 420p12 to 420jpeg\n");
893 } else if (strcmp(y4m_ctx->chroma_type, "420mpeg2") == 0) {
894 y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_v =
895 y4m_ctx->dst_c_dec_v = 2;
896 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
897 /*Chroma filter required: read into the aux buf first.*/
898 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz =
899 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
900 y4m_ctx->convert = y4m_convert_42xmpeg2_42xjpeg;
901 } else if (strcmp(y4m_ctx->chroma_type, "420paldv") == 0) {
902 y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_v =
903 y4m_ctx->dst_c_dec_v = 2;
904 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
905 /*Chroma filter required: read into the aux buf first.
906 We need to make two filter passes, so we need some extra space in the
908 y4m_ctx->aux_buf_sz =
909 3 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
910 y4m_ctx->aux_buf_read_sz =
911 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
912 y4m_ctx->convert = y4m_convert_42xpaldv_42xjpeg;
913 } else if (strcmp(y4m_ctx->chroma_type, "422jpeg") == 0) {
914 y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = 2;
915 y4m_ctx->src_c_dec_v = 1;
916 y4m_ctx->dst_c_dec_v = 2;
917 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
918 /*Chroma filter required: read into the aux buf first.*/
919 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz =
920 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
921 y4m_ctx->convert = y4m_convert_422jpeg_420jpeg;
922 } else if (strcmp(y4m_ctx->chroma_type, "422") == 0) {
923 y4m_ctx->src_c_dec_h = 2;
924 y4m_ctx->src_c_dec_v = 1;
926 y4m_ctx->dst_c_dec_h = 2;
927 y4m_ctx->dst_c_dec_v = 2;
928 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
929 /*Chroma filter required: read into the aux buf first.
930 We need to make two filter passes, so we need some extra space in the
932 y4m_ctx->aux_buf_read_sz =
933 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
934 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz +
935 ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
936 y4m_ctx->convert = y4m_convert_422_420jpeg;
938 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I422;
940 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
941 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
942 y4m_ctx->dst_buf_read_sz =
943 y4m_ctx->pic_w * y4m_ctx->pic_h +
944 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
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;
949 } else if (strcmp(y4m_ctx->chroma_type, "422p10") == 0) {
950 y4m_ctx->src_c_dec_h = 2;
951 y4m_ctx->src_c_dec_v = 1;
952 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I42216;
954 y4m_ctx->bit_depth = 10;
955 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
956 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
957 y4m_ctx->dst_buf_read_sz =
958 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
959 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h);
960 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
961 y4m_ctx->convert = y4m_convert_null;
963 fprintf(stderr, "Unsupported conversion from 422p10 to 420jpeg\n");
966 } else if (strcmp(y4m_ctx->chroma_type, "422p12") == 0) {
967 y4m_ctx->src_c_dec_h = 2;
968 y4m_ctx->src_c_dec_v = 1;
969 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I42216;
971 y4m_ctx->bit_depth = 12;
972 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
973 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
974 y4m_ctx->dst_buf_read_sz =
975 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
976 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h);
977 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
978 y4m_ctx->convert = y4m_convert_null;
980 fprintf(stderr, "Unsupported conversion from 422p12 to 420jpeg\n");
983 } else if (strcmp(y4m_ctx->chroma_type, "411") == 0) {
984 y4m_ctx->src_c_dec_h = 4;
985 y4m_ctx->dst_c_dec_h = 2;
986 y4m_ctx->src_c_dec_v = 1;
987 y4m_ctx->dst_c_dec_v = 2;
988 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
989 /*Chroma filter required: read into the aux buf first.
990 We need to make two filter passes, so we need some extra space in the
992 y4m_ctx->aux_buf_read_sz = 2 * ((y4m_ctx->pic_w + 3) / 4) * y4m_ctx->pic_h;
993 y4m_ctx->aux_buf_sz =
994 y4m_ctx->aux_buf_read_sz + ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
995 y4m_ctx->convert = y4m_convert_411_420jpeg;
996 fprintf(stderr, "Unsupported conversion from yuv 411\n");
998 } else if (strcmp(y4m_ctx->chroma_type, "444") == 0) {
999 y4m_ctx->src_c_dec_h = 1;
1000 y4m_ctx->src_c_dec_v = 1;
1002 y4m_ctx->dst_c_dec_h = 2;
1003 y4m_ctx->dst_c_dec_v = 2;
1004 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
1005 /*Chroma filter required: read into the aux buf first.
1006 We need to make two filter passes, so we need some extra space in the
1008 y4m_ctx->aux_buf_read_sz = 2 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1009 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz +
1010 ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
1011 y4m_ctx->convert = y4m_convert_444_420jpeg;
1013 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I444;
1015 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
1016 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
1017 y4m_ctx->dst_buf_read_sz = 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1018 /*Natively supported: no conversion required.*/
1019 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1020 y4m_ctx->convert = y4m_convert_null;
1022 } else if (strcmp(y4m_ctx->chroma_type, "444p10") == 0) {
1023 y4m_ctx->src_c_dec_h = 1;
1024 y4m_ctx->src_c_dec_v = 1;
1025 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I44416;
1027 y4m_ctx->bit_depth = 10;
1028 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
1029 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
1030 y4m_ctx->dst_buf_read_sz = 2 * 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1031 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1032 y4m_ctx->convert = y4m_convert_null;
1034 fprintf(stderr, "Unsupported conversion from 444p10 to 420jpeg\n");
1037 } else if (strcmp(y4m_ctx->chroma_type, "444p12") == 0) {
1038 y4m_ctx->src_c_dec_h = 1;
1039 y4m_ctx->src_c_dec_v = 1;
1040 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I44416;
1042 y4m_ctx->bit_depth = 12;
1043 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
1044 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
1045 y4m_ctx->dst_buf_read_sz = 2 * 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1046 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1047 y4m_ctx->convert = y4m_convert_null;
1049 fprintf(stderr, "Unsupported conversion from 444p12 to 420jpeg\n");
1052 } else if (strcmp(y4m_ctx->chroma_type, "mono") == 0) {
1053 y4m_ctx->src_c_dec_h = y4m_ctx->src_c_dec_v = 0;
1054 y4m_ctx->dst_c_dec_h = y4m_ctx->dst_c_dec_v = 2;
1055 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
1056 /*No extra space required, but we need to clear the chroma planes.*/
1057 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1058 y4m_ctx->convert = y4m_convert_mono_420jpeg;
1060 fprintf(stderr, "Unknown chroma sampling type: %s\n", y4m_ctx->chroma_type);
1063 /*The size of the final frame buffers is always computed from the
1064 destination chroma decimation type.*/
1065 y4m_ctx->dst_buf_sz =
1066 y4m_ctx->pic_w * y4m_ctx->pic_h +
1067 2 * ((y4m_ctx->pic_w + y4m_ctx->dst_c_dec_h - 1) / y4m_ctx->dst_c_dec_h) *
1068 ((y4m_ctx->pic_h + y4m_ctx->dst_c_dec_v - 1) / y4m_ctx->dst_c_dec_v);
1069 if (y4m_ctx->bit_depth == 8)
1070 y4m_ctx->dst_buf = (unsigned char *)malloc(y4m_ctx->dst_buf_sz);
1072 y4m_ctx->dst_buf = (unsigned char *)malloc(2 * y4m_ctx->dst_buf_sz);
1074 if (y4m_ctx->aux_buf_sz > 0)
1075 y4m_ctx->aux_buf = (unsigned char *)malloc(y4m_ctx->aux_buf_sz);
1079 void y4m_input_close(y4m_input *_y4m) {
1080 free(_y4m->dst_buf);
1081 free(_y4m->aux_buf);
1084 int y4m_input_fetch_frame(y4m_input *_y4m, FILE *_fin, vpx_image_t *_img) {
1090 int bytes_per_sample = _y4m->bit_depth > 8 ? 2 : 1;
1091 /*Read and skip the frame header.*/
1092 if (!file_read(frame, 6, _fin)) return 0;
1093 if (memcmp(frame, "FRAME", 5)) {
1094 fprintf(stderr, "Loss of framing in Y4M input data\n");
1097 if (frame[5] != '\n') {
1100 for (j = 0; j < 79 && file_read(&c, 1, _fin) && c != '\n'; j++) {
1103 fprintf(stderr, "Error parsing Y4M frame header\n");
1107 /*Read the frame data that needs no conversion.*/
1108 if (!file_read(_y4m->dst_buf, _y4m->dst_buf_read_sz, _fin)) {
1109 fprintf(stderr, "Error reading Y4M frame data.\n");
1112 /*Read the frame data that does need conversion.*/
1113 if (!file_read(_y4m->aux_buf, _y4m->aux_buf_read_sz, _fin)) {
1114 fprintf(stderr, "Error reading Y4M frame data.\n");
1117 /*Now convert the just read frame.*/
1118 (*_y4m->convert)(_y4m, _y4m->dst_buf, _y4m->aux_buf);
1119 /*Fill in the frame buffer pointers.
1120 We don't use vpx_img_wrap() because it forces padding for odd picture
1121 sizes, which would require a separate fread call for every row.*/
1122 memset(_img, 0, sizeof(*_img));
1123 /*Y4M has the planes in Y'CbCr order, which libvpx calls Y, U, and V.*/
1124 _img->fmt = _y4m->vpx_fmt;
1125 _img->w = _img->d_w = _y4m->pic_w;
1126 _img->h = _img->d_h = _y4m->pic_h;
1127 _img->x_chroma_shift = _y4m->dst_c_dec_h >> 1;
1128 _img->y_chroma_shift = _y4m->dst_c_dec_v >> 1;
1129 _img->bps = _y4m->bps;
1131 /*Set up the buffer pointers.*/
1132 pic_sz = _y4m->pic_w * _y4m->pic_h * bytes_per_sample;
1133 c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
1134 c_w *= bytes_per_sample;
1135 c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
1137 _img->stride[VPX_PLANE_Y] = _img->stride[VPX_PLANE_ALPHA] =
1138 _y4m->pic_w * bytes_per_sample;
1139 _img->stride[VPX_PLANE_U] = _img->stride[VPX_PLANE_V] = c_w;
1140 _img->planes[VPX_PLANE_Y] = _y4m->dst_buf;
1141 _img->planes[VPX_PLANE_U] = _y4m->dst_buf + pic_sz;
1142 _img->planes[VPX_PLANE_V] = _y4m->dst_buf + pic_sz + c_sz;
1143 _img->planes[VPX_PLANE_ALPHA] = _y4m->dst_buf + pic_sz + 2 * c_sz;