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) {
57 for (p = _tags;; p = q) {
58 /*Skip any leading spaces.*/
59 while (*p == ' ') p++;
60 /*If that's all we have, stop.*/
61 if (p[0] == '\0') break;
62 /*Find the end of this tag.*/
63 for (q = p + 1; *q != '\0' && *q != ' '; q++) {
68 if (sscanf(p + 1, "%d", &_y4m->pic_w) != 1) return -1;
72 if (sscanf(p + 1, "%d", &_y4m->pic_h) != 1) return -1;
76 if (sscanf(p + 1, "%d:%d", &_y4m->fps_n, &_y4m->fps_d) != 2) {
82 _y4m->interlace = p[1];
86 if (sscanf(p + 1, "%d:%d", &_y4m->par_n, &_y4m->par_d) != 2) {
92 if (q - p > 16) return -1;
93 memcpy(_y4m->chroma_type, p + 1, q - p - 1);
94 _y4m->chroma_type[q - p - 1] = '\0';
97 /*Ignore unknown tags.*/
103 // Copy a single tag into the buffer, along with a null character.
104 // Returns 0 if any file IO errors occur.
105 static int copy_tag(char *buf, size_t buf_len, char *end_tag, FILE *file) {
107 assert(buf_len >= 1);
108 // Skip leading space characters.
110 if (!file_read(buf, 1, file)) {
113 } while (buf[0] == ' ');
115 // If we hit the newline, treat this as the "empty" tag.
116 if (buf[0] == '\n') {
122 // Copy over characters until a space is hit, or the buffer is exhausted.
123 for (i = 1; i < buf_len; ++i) {
124 if (!file_read(buf + i, 1, file)) {
127 if (buf[i] == ' ' || buf[i] == '\n') {
132 fprintf(stderr, "Error: Y4M header tags must be less than %lu characters\n",
141 /* Returns 1 if tags were parsed successfully, 0 otherwise. */
142 static int parse_tags(y4m_input *y4m_ctx, FILE *file) {
144 char end; /* Character denoting the end of the tag, ' ' or '\n'. */
145 /* Set Y4M tags to defaults, updating them as processing occurs. Mandatory
146 fields are marked with -1 and will be checked after the tags are parsed. */
149 y4m_ctx->fps_n = -1; /* Also serves as marker for fps_d */
152 y4m_ctx->interlace = '?';
153 snprintf(y4m_ctx->chroma_type, sizeof(y4m_ctx->chroma_type), "420");
155 /* Find one tag at a time. */
157 if (!copy_tag(tag, sizeof(tag), &end, file)) {
160 /* y4m_parse_tags returns 0 on success. */
161 if (y4m_parse_tags(y4m_ctx, tag)) {
164 } while (end != '\n');
166 /* Check the mandatory fields. */
167 if (y4m_ctx->pic_w == -1) {
168 fprintf(stderr, "Width field missing\n");
171 if (y4m_ctx->pic_h == -1) {
172 fprintf(stderr, "Height field missing\n");
175 if (y4m_ctx->fps_n == -1) {
176 fprintf(stderr, "FPS field missing\n");
182 /*All anti-aliasing filters in the following conversion functions are based on
183 one of two window functions:
184 The 6-tap Lanczos window (for down-sampling and shifts):
185 sinc(\pi*t)*sinc(\pi*t/3), |t|<3 (sinc(t)==sin(t)/t)
187 The 4-tap Mitchell window (for up-sampling):
188 7|t|^3-12|t|^2+16/3, |t|<1
189 -(7/3)|x|^3+12|x|^2-20|x|+32/3, |t|<2
191 The number of taps is intentionally kept small to reduce computational
192 overhead and limit ringing.
194 The taps from these filters are scaled so that their sum is 1, and the
195 result is scaled by 128 and rounded to integers to create a filter whose
196 intermediate values fit inside 16 bits.
197 Coefficients are rounded in such a way as to ensure their sum is still 128,
198 which is usually equivalent to normal rounding.
200 Conversions which require both horizontal and vertical filtering could
201 have these steps pipelined, for less memory consumption and better cache
202 performance, but we do them separately for simplicity.*/
203 #define OC_MINI(_a, _b) ((_a) > (_b) ? (_b) : (_a))
204 #define OC_MAXI(_a, _b) ((_a) < (_b) ? (_b) : (_a))
205 #define OC_CLAMPI(_a, _b, _c) (OC_MAXI(_a, OC_MINI(_b, _c)))
207 /*420jpeg chroma samples are sited like:
208 Y-------Y-------Y-------Y-------
212 Y-------Y-------Y-------Y-------
216 Y-------Y-------Y-------Y-------
220 Y-------Y-------Y-------Y-------
225 420mpeg2 chroma samples are sited like:
226 Y-------Y-------Y-------Y-------
230 Y-------Y-------Y-------Y-------
234 Y-------Y-------Y-------Y-------
238 Y-------Y-------Y-------Y-------
243 We use a resampling filter to shift the site locations one quarter pixel (at
244 the chroma plane's resolution) to the right.
245 The 4:2:2 modes look exactly the same, except there are twice as many chroma
246 lines, and they are vertically co-sited with the luma samples in both the
247 mpeg2 and jpeg cases (thus requiring no vertical resampling).*/
248 static void y4m_42xmpeg2_42xjpeg_helper(unsigned char *_dst,
249 const unsigned char *_src, int _c_w,
253 for (y = 0; y < _c_h; y++) {
254 /*Filter: [4 -17 114 35 -9 1]/128, derived from a 6-tap Lanczos
256 for (x = 0; x < OC_MINI(_c_w, 2); x++) {
257 _dst[x] = (unsigned char)OC_CLAMPI(
259 (4 * _src[0] - 17 * _src[OC_MAXI(x - 1, 0)] + 114 * _src[x] +
260 35 * _src[OC_MINI(x + 1, _c_w - 1)] -
261 9 * _src[OC_MINI(x + 2, _c_w - 1)] + _src[OC_MINI(x + 3, _c_w - 1)] +
266 for (; x < _c_w - 3; x++) {
267 _dst[x] = (unsigned char)OC_CLAMPI(
269 (4 * _src[x - 2] - 17 * _src[x - 1] + 114 * _src[x] +
270 35 * _src[x + 1] - 9 * _src[x + 2] + _src[x + 3] + 64) >>
274 for (; x < _c_w; x++) {
275 _dst[x] = (unsigned char)OC_CLAMPI(
277 (4 * _src[x - 2] - 17 * _src[x - 1] + 114 * _src[x] +
278 35 * _src[OC_MINI(x + 1, _c_w - 1)] -
279 9 * _src[OC_MINI(x + 2, _c_w - 1)] + _src[_c_w - 1] + 64) >>
288 /*This format is only used for interlaced content, but is included for
291 420jpeg chroma samples are sited like:
292 Y-------Y-------Y-------Y-------
296 Y-------Y-------Y-------Y-------
300 Y-------Y-------Y-------Y-------
304 Y-------Y-------Y-------Y-------
309 420paldv chroma samples are sited like:
310 YR------Y-------YR------Y-------
314 YB------Y-------YB------Y-------
318 YR------Y-------YR------Y-------
322 YB------Y-------YB------Y-------
327 We use a resampling filter to shift the site locations one quarter pixel (at
328 the chroma plane's resolution) to the right.
329 Then we use another filter to move the C_r location down one quarter pixel,
330 and the C_b location up one quarter pixel.*/
331 static void y4m_convert_42xpaldv_42xjpeg(y4m_input *_y4m, unsigned char *_dst,
332 unsigned char *_aux) {
340 /*Skip past the luma data.*/
341 _dst += _y4m->pic_w * _y4m->pic_h;
342 /*Compute the size of each chroma plane.*/
343 c_w = (_y4m->pic_w + 1) / 2;
344 c_h = (_y4m->pic_h + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
346 tmp = _aux + 2 * c_sz;
347 for (pli = 1; pli < 3; pli++) {
348 /*First do the horizontal re-sampling.
349 This is the same as the mpeg2 case, except that after the horizontal
350 case, we need to apply a second vertical filter.*/
351 y4m_42xmpeg2_42xjpeg_helper(tmp, _aux, c_w, c_h);
355 /*Slide C_b up a quarter-pel.
356 This is the same filter used above, but in the other order.*/
357 for (x = 0; x < c_w; x++) {
358 for (y = 0; y < OC_MINI(c_h, 3); y++) {
359 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
361 (tmp[0] - 9 * tmp[OC_MAXI(y - 2, 0) * c_w] +
362 35 * tmp[OC_MAXI(y - 1, 0) * c_w] + 114 * tmp[y * c_w] -
363 17 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] +
364 4 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] + 64) >>
368 for (; y < c_h - 2; y++) {
369 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
371 (tmp[(y - 3) * c_w] - 9 * tmp[(y - 2) * c_w] +
372 35 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w] -
373 17 * tmp[(y + 1) * c_w] + 4 * tmp[(y + 2) * c_w] + 64) >>
377 for (; y < c_h; y++) {
378 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
380 (tmp[(y - 3) * c_w] - 9 * tmp[(y - 2) * c_w] +
381 35 * tmp[(y - 1) * c_w] + 114 * tmp[y * c_w] -
382 17 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] +
383 4 * tmp[(c_h - 1) * c_w] + 64) >>
395 /*Slide C_r down a quarter-pel.
396 This is the same as the horizontal filter.*/
397 for (x = 0; x < c_w; x++) {
398 for (y = 0; y < OC_MINI(c_h, 2); y++) {
399 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
401 (4 * tmp[0] - 17 * tmp[OC_MAXI(y - 1, 0) * c_w] +
402 114 * tmp[y * c_w] + 35 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] -
403 9 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] +
404 tmp[OC_MINI(y + 3, c_h - 1) * c_w] + 64) >>
408 for (; y < c_h - 3; y++) {
409 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
411 (4 * tmp[(y - 2) * c_w] - 17 * tmp[(y - 1) * c_w] +
412 114 * tmp[y * c_w] + 35 * tmp[(y + 1) * c_w] -
413 9 * tmp[(y + 2) * c_w] + tmp[(y + 3) * c_w] + 64) >>
417 for (; y < c_h; y++) {
418 _dst[y * c_w] = (unsigned char)OC_CLAMPI(
420 (4 * tmp[(y - 2) * c_w] - 17 * tmp[(y - 1) * c_w] +
421 114 * tmp[y * c_w] + 35 * tmp[OC_MINI(y + 1, c_h - 1) * c_w] -
422 9 * tmp[OC_MINI(y + 2, c_h - 1) * c_w] + tmp[(c_h - 1) * c_w] +
433 /*For actual interlaced material, this would have to be done separately on
434 each field, and the shift amounts would be different.
435 C_r moves down 1/8, C_b up 3/8 in the top field, and C_r moves down 3/8,
436 C_b up 1/8 in the bottom field.
437 The corresponding filters would be:
438 Down 1/8 (reverse order for up): [3 -11 125 15 -4 0]/128
439 Down 3/8 (reverse order for up): [4 -19 98 56 -13 2]/128*/
443 /*Perform vertical filtering to reduce a single plane from 4:2:2 to 4:2:0.
444 This is used as a helper by several converation routines.*/
445 static void y4m_422jpeg_420jpeg_helper(unsigned char *_dst,
446 const unsigned char *_src, int _c_w,
450 /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/
451 for (x = 0; x < _c_w; x++) {
452 for (y = 0; y < OC_MINI(_c_h, 2); y += 2) {
453 _dst[(y >> 1) * _c_w] =
455 (64 * _src[0] + 78 * _src[OC_MINI(1, _c_h - 1) * _c_w] -
456 17 * _src[OC_MINI(2, _c_h - 1) * _c_w] +
457 3 * _src[OC_MINI(3, _c_h - 1) * _c_w] + 64) >>
461 for (; y < _c_h - 3; y += 2) {
462 _dst[(y >> 1) * _c_w] =
464 (3 * (_src[(y - 2) * _c_w] + _src[(y + 3) * _c_w]) -
465 17 * (_src[(y - 1) * _c_w] + _src[(y + 2) * _c_w]) +
466 78 * (_src[y * _c_w] + _src[(y + 1) * _c_w]) + 64) >>
470 for (; y < _c_h; y += 2) {
471 _dst[(y >> 1) * _c_w] = OC_CLAMPI(
473 (3 * (_src[(y - 2) * _c_w] + _src[(_c_h - 1) * _c_w]) -
474 17 * (_src[(y - 1) * _c_w] + _src[OC_MINI(y + 2, _c_h - 1) * _c_w]) +
475 78 * (_src[y * _c_w] + _src[OC_MINI(y + 1, _c_h - 1) * _c_w]) +
485 /*420jpeg chroma samples are sited like:
486 Y-------Y-------Y-------Y-------
490 Y-------Y-------Y-------Y-------
494 Y-------Y-------Y-------Y-------
498 Y-------Y-------Y-------Y-------
503 422jpeg chroma samples are sited like:
504 Y---BR--Y-------Y---BR--Y-------
508 Y---BR--Y-------Y---BR--Y-------
512 Y---BR--Y-------Y---BR--Y-------
516 Y---BR--Y-------Y---BR--Y-------
521 We use a resampling filter to decimate the chroma planes by two in the
522 vertical direction.*/
523 static void y4m_convert_422jpeg_420jpeg(y4m_input *_y4m, unsigned char *_dst,
524 unsigned char *_aux) {
532 /*Skip past the luma data.*/
533 _dst += _y4m->pic_w * _y4m->pic_h;
534 /*Compute the size of each chroma plane.*/
535 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
537 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
538 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
540 dst_c_sz = dst_c_w * dst_c_h;
541 for (pli = 1; pli < 3; pli++) {
542 y4m_422jpeg_420jpeg_helper(_dst, _aux, c_w, c_h);
548 /*420jpeg chroma samples are sited like:
549 Y-------Y-------Y-------Y-------
553 Y-------Y-------Y-------Y-------
557 Y-------Y-------Y-------Y-------
561 Y-------Y-------Y-------Y-------
566 422 chroma samples are sited like:
567 YBR-----Y-------YBR-----Y-------
571 YBR-----Y-------YBR-----Y-------
575 YBR-----Y-------YBR-----Y-------
579 YBR-----Y-------YBR-----Y-------
584 We use a resampling filter to shift the original site locations one quarter
585 pixel (at the original chroma resolution) to the right.
586 Then we use a second resampling filter to decimate the chroma planes by two
587 in the vertical direction.*/
588 static void y4m_convert_422_420jpeg(y4m_input *_y4m, unsigned char *_dst,
589 unsigned char *_aux) {
597 /*Skip past the luma data.*/
598 _dst += _y4m->pic_w * _y4m->pic_h;
599 /*Compute the size of each chroma plane.*/
600 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
602 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
604 dst_c_sz = c_w * dst_c_h;
605 tmp = _aux + 2 * c_sz;
606 for (pli = 1; pli < 3; pli++) {
607 /*In reality, the horizontal and vertical steps could be pipelined, for
608 less memory consumption and better cache performance, but we do them
609 separately for simplicity.*/
610 /*First do horizontal filtering (convert to 422jpeg)*/
611 y4m_42xmpeg2_42xjpeg_helper(tmp, _aux, c_w, c_h);
612 /*Now do the vertical filtering.*/
613 y4m_422jpeg_420jpeg_helper(_dst, tmp, c_w, c_h);
619 /*420jpeg chroma samples are sited like:
620 Y-------Y-------Y-------Y-------
624 Y-------Y-------Y-------Y-------
628 Y-------Y-------Y-------Y-------
632 Y-------Y-------Y-------Y-------
637 411 chroma samples are sited like:
638 YBR-----Y-------Y-------Y-------
642 YBR-----Y-------Y-------Y-------
646 YBR-----Y-------Y-------Y-------
650 YBR-----Y-------Y-------Y-------
655 We use a filter to resample at site locations one eighth pixel (at the source
656 chroma plane's horizontal resolution) and five eighths of a pixel to the
658 Then we use another filter to decimate the planes by 2 in the vertical
660 static void y4m_convert_411_420jpeg(y4m_input *_y4m, unsigned char *_dst,
661 unsigned char *_aux) {
673 /*Skip past the luma data.*/
674 _dst += _y4m->pic_w * _y4m->pic_h;
675 /*Compute the size of each chroma plane.*/
676 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
678 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
679 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
681 dst_c_sz = dst_c_w * dst_c_h;
682 tmp_sz = dst_c_w * c_h;
683 tmp = _aux + 2 * c_sz;
684 for (pli = 1; pli < 3; pli++) {
685 /*In reality, the horizontal and vertical steps could be pipelined, for
686 less memory consumption and better cache performance, but we do them
687 separately for simplicity.*/
688 /*First do horizontal filtering (convert to 422jpeg)*/
689 for (y = 0; y < c_h; y++) {
690 /*Filters: [1 110 18 -1]/128 and [-3 50 86 -5]/128, both derived from a
691 4-tap Mitchell window.*/
692 for (x = 0; x < OC_MINI(c_w, 1); x++) {
693 tmp[x << 1] = (unsigned char)OC_CLAMPI(
695 (111 * _aux[0] + 18 * _aux[OC_MINI(1, c_w - 1)] -
696 _aux[OC_MINI(2, c_w - 1)] + 64) >>
699 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
701 (47 * _aux[0] + 86 * _aux[OC_MINI(1, c_w - 1)] -
702 5 * _aux[OC_MINI(2, c_w - 1)] + 64) >>
706 for (; x < c_w - 2; x++) {
708 (unsigned char)OC_CLAMPI(0,
709 (_aux[x - 1] + 110 * _aux[x] +
710 18 * _aux[x + 1] - _aux[x + 2] + 64) >>
713 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
715 (-3 * _aux[x - 1] + 50 * _aux[x] + 86 * _aux[x + 1] -
716 5 * _aux[x + 2] + 64) >>
720 for (; x < c_w; x++) {
721 tmp[x << 1] = (unsigned char)OC_CLAMPI(
723 (_aux[x - 1] + 110 * _aux[x] + 18 * _aux[OC_MINI(x + 1, c_w - 1)] -
724 _aux[c_w - 1] + 64) >>
727 if ((x << 1 | 1) < dst_c_w) {
728 tmp[x << 1 | 1] = (unsigned char)OC_CLAMPI(
730 (-3 * _aux[x - 1] + 50 * _aux[x] +
731 86 * _aux[OC_MINI(x + 1, c_w - 1)] - 5 * _aux[c_w - 1] + 64) >>
740 /*Now do the vertical filtering.*/
741 y4m_422jpeg_420jpeg_helper(_dst, tmp, dst_c_w, c_h);
746 /*Convert 444 to 420jpeg.*/
747 static void y4m_convert_444_420jpeg(y4m_input *_y4m, unsigned char *_dst,
748 unsigned char *_aux) {
760 /*Skip past the luma data.*/
761 _dst += _y4m->pic_w * _y4m->pic_h;
762 /*Compute the size of each chroma plane.*/
763 c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
765 dst_c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
766 dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
768 dst_c_sz = dst_c_w * dst_c_h;
769 tmp_sz = dst_c_w * c_h;
770 tmp = _aux + 2 * c_sz;
771 for (pli = 1; pli < 3; pli++) {
772 /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/
773 for (y = 0; y < c_h; y++) {
774 for (x = 0; x < OC_MINI(c_w, 2); x += 2) {
775 tmp[x >> 1] = OC_CLAMPI(0,
776 (64 * _aux[0] + 78 * _aux[OC_MINI(1, c_w - 1)] -
777 17 * _aux[OC_MINI(2, c_w - 1)] +
778 3 * _aux[OC_MINI(3, c_w - 1)] + 64) >>
782 for (; x < c_w - 3; x += 2) {
783 tmp[x >> 1] = OC_CLAMPI(0,
784 (3 * (_aux[x - 2] + _aux[x + 3]) -
785 17 * (_aux[x - 1] + _aux[x + 2]) +
786 78 * (_aux[x] + _aux[x + 1]) + 64) >>
790 for (; x < c_w; x += 2) {
793 (3 * (_aux[x - 2] + _aux[c_w - 1]) -
794 17 * (_aux[x - 1] + _aux[OC_MINI(x + 2, c_w - 1)]) +
795 78 * (_aux[x] + _aux[OC_MINI(x + 1, c_w - 1)]) + 64) >>
803 /*Now do the vertical filtering.*/
804 y4m_422jpeg_420jpeg_helper(_dst, tmp, dst_c_w, c_h);
809 /*The image is padded with empty chroma components at 4:2:0.*/
810 static void y4m_convert_mono_420jpeg(y4m_input *_y4m, unsigned char *_dst,
811 unsigned char *_aux) {
814 _dst += _y4m->pic_w * _y4m->pic_h;
815 c_sz = ((_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h) *
816 ((_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v);
817 memset(_dst, 128, c_sz * 2);
820 /*No conversion function needed.*/
821 static void y4m_convert_null(y4m_input *_y4m, unsigned char *_dst,
822 unsigned char *_aux) {
828 static const char TAG[] = "YUV4MPEG2";
830 int y4m_input_open(y4m_input *y4m_ctx, FILE *file, char *skip_buffer,
831 int num_skip, int only_420) {
832 // File must start with |TAG|.
833 char tag_buffer[9]; // 9 == strlen(TAG)
834 // Read as much as possible from |skip_buffer|, which were characters
835 // that were previously read from the file to do input-type detection.
836 assert(num_skip >= 0 && num_skip <= 8);
838 memcpy(tag_buffer, skip_buffer, num_skip);
840 // Start reading from the file now that the |skip_buffer| is depleted.
841 if (!file_read(tag_buffer + num_skip, 9 - num_skip, file)) {
844 if (memcmp(TAG, tag_buffer, 9) != 0) {
845 fprintf(stderr, "Error parsing header: must start with %s\n", TAG);
848 // Next character must be a space.
849 if (!file_read(tag_buffer, 1, file) || tag_buffer[0] != ' ') {
850 fprintf(stderr, "Error parsing header: space must follow %s\n", TAG);
853 if (!parse_tags(y4m_ctx, file)) {
854 fprintf(stderr, "Error parsing %s header.\n", TAG);
856 if (y4m_ctx->interlace == '?') {
858 "Warning: Input video interlacing format unknown; "
859 "assuming progressive scan.\n");
860 } else if (y4m_ctx->interlace != 'p') {
862 "Input video is interlaced; "
863 "Only progressive scan handled.\n");
866 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I420;
868 y4m_ctx->bit_depth = 8;
869 y4m_ctx->aux_buf = NULL;
870 y4m_ctx->dst_buf = NULL;
871 if (strcmp(y4m_ctx->chroma_type, "420") == 0 ||
872 strcmp(y4m_ctx->chroma_type, "420jpeg") == 0 ||
873 strcmp(y4m_ctx->chroma_type, "420mpeg2") == 0) {
874 y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_v =
875 y4m_ctx->dst_c_dec_v = 2;
876 y4m_ctx->dst_buf_read_sz =
877 y4m_ctx->pic_w * y4m_ctx->pic_h +
878 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
879 /* Natively supported: no conversion required. */
880 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
881 y4m_ctx->convert = y4m_convert_null;
882 } else if (strcmp(y4m_ctx->chroma_type, "420p10") == 0) {
883 y4m_ctx->src_c_dec_h = 2;
884 y4m_ctx->dst_c_dec_h = 2;
885 y4m_ctx->src_c_dec_v = 2;
886 y4m_ctx->dst_c_dec_v = 2;
887 y4m_ctx->dst_buf_read_sz =
888 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
889 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2));
890 /* Natively supported: no conversion required. */
891 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
892 y4m_ctx->convert = y4m_convert_null;
893 y4m_ctx->bit_depth = 10;
895 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I42016;
897 fprintf(stderr, "Unsupported conversion from 420p10 to 420jpeg\n");
900 } else if (strcmp(y4m_ctx->chroma_type, "420p12") == 0) {
901 y4m_ctx->src_c_dec_h = 2;
902 y4m_ctx->dst_c_dec_h = 2;
903 y4m_ctx->src_c_dec_v = 2;
904 y4m_ctx->dst_c_dec_v = 2;
905 y4m_ctx->dst_buf_read_sz =
906 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
907 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2));
908 /* Natively supported: no conversion required. */
909 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
910 y4m_ctx->convert = y4m_convert_null;
911 y4m_ctx->bit_depth = 12;
913 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I42016;
915 fprintf(stderr, "Unsupported conversion from 420p12 to 420jpeg\n");
918 } else if (strcmp(y4m_ctx->chroma_type, "420paldv") == 0) {
919 y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_v =
920 y4m_ctx->dst_c_dec_v = 2;
921 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
922 /*Chroma filter required: read into the aux buf first.
923 We need to make two filter passes, so we need some extra space in the
925 y4m_ctx->aux_buf_sz =
926 3 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
927 y4m_ctx->aux_buf_read_sz =
928 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
929 y4m_ctx->convert = y4m_convert_42xpaldv_42xjpeg;
930 } else if (strcmp(y4m_ctx->chroma_type, "422jpeg") == 0) {
931 y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = 2;
932 y4m_ctx->src_c_dec_v = 1;
933 y4m_ctx->dst_c_dec_v = 2;
934 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
935 /*Chroma filter required: read into the aux buf first.*/
936 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz =
937 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
938 y4m_ctx->convert = y4m_convert_422jpeg_420jpeg;
939 } else if (strcmp(y4m_ctx->chroma_type, "422") == 0) {
940 y4m_ctx->src_c_dec_h = 2;
941 y4m_ctx->src_c_dec_v = 1;
943 y4m_ctx->dst_c_dec_h = 2;
944 y4m_ctx->dst_c_dec_v = 2;
945 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
946 /*Chroma filter required: read into the aux buf first.
947 We need to make two filter passes, so we need some extra space in the
949 y4m_ctx->aux_buf_read_sz =
950 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
951 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz +
952 ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
953 y4m_ctx->convert = y4m_convert_422_420jpeg;
955 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I422;
957 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
958 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
959 y4m_ctx->dst_buf_read_sz =
960 y4m_ctx->pic_w * y4m_ctx->pic_h +
961 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
962 /*Natively supported: no conversion required.*/
963 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
964 y4m_ctx->convert = y4m_convert_null;
966 } else if (strcmp(y4m_ctx->chroma_type, "422p10") == 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 = 10;
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 422p10 to 420jpeg\n");
983 } else if (strcmp(y4m_ctx->chroma_type, "422p12") == 0) {
984 y4m_ctx->src_c_dec_h = 2;
985 y4m_ctx->src_c_dec_v = 1;
986 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I42216;
988 y4m_ctx->bit_depth = 12;
989 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
990 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
991 y4m_ctx->dst_buf_read_sz =
992 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
993 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h);
994 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
995 y4m_ctx->convert = y4m_convert_null;
997 fprintf(stderr, "Unsupported conversion from 422p12 to 420jpeg\n");
1000 } else if (strcmp(y4m_ctx->chroma_type, "411") == 0) {
1001 y4m_ctx->src_c_dec_h = 4;
1002 y4m_ctx->dst_c_dec_h = 2;
1003 y4m_ctx->src_c_dec_v = 1;
1004 y4m_ctx->dst_c_dec_v = 2;
1005 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
1006 /*Chroma filter required: read into the aux buf first.
1007 We need to make two filter passes, so we need some extra space in the
1009 y4m_ctx->aux_buf_read_sz = 2 * ((y4m_ctx->pic_w + 3) / 4) * y4m_ctx->pic_h;
1010 y4m_ctx->aux_buf_sz =
1011 y4m_ctx->aux_buf_read_sz + ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
1012 y4m_ctx->convert = y4m_convert_411_420jpeg;
1013 fprintf(stderr, "Unsupported conversion from yuv 411\n");
1015 } else if (strcmp(y4m_ctx->chroma_type, "444") == 0) {
1016 y4m_ctx->src_c_dec_h = 1;
1017 y4m_ctx->src_c_dec_v = 1;
1019 y4m_ctx->dst_c_dec_h = 2;
1020 y4m_ctx->dst_c_dec_v = 2;
1021 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
1022 /*Chroma filter required: read into the aux buf first.
1023 We need to make two filter passes, so we need some extra space in the
1025 y4m_ctx->aux_buf_read_sz = 2 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1026 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz +
1027 ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
1028 y4m_ctx->convert = y4m_convert_444_420jpeg;
1030 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I444;
1032 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
1033 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
1034 y4m_ctx->dst_buf_read_sz = 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1035 /*Natively supported: no conversion required.*/
1036 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1037 y4m_ctx->convert = y4m_convert_null;
1039 } else if (strcmp(y4m_ctx->chroma_type, "444p10") == 0) {
1040 y4m_ctx->src_c_dec_h = 1;
1041 y4m_ctx->src_c_dec_v = 1;
1042 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I44416;
1044 y4m_ctx->bit_depth = 10;
1045 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
1046 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
1047 y4m_ctx->dst_buf_read_sz = 2 * 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1048 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1049 y4m_ctx->convert = y4m_convert_null;
1051 fprintf(stderr, "Unsupported conversion from 444p10 to 420jpeg\n");
1054 } else if (strcmp(y4m_ctx->chroma_type, "444p12") == 0) {
1055 y4m_ctx->src_c_dec_h = 1;
1056 y4m_ctx->src_c_dec_v = 1;
1057 y4m_ctx->vpx_fmt = VPX_IMG_FMT_I44416;
1059 y4m_ctx->bit_depth = 12;
1060 y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
1061 y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
1062 y4m_ctx->dst_buf_read_sz = 2 * 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
1063 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1064 y4m_ctx->convert = y4m_convert_null;
1066 fprintf(stderr, "Unsupported conversion from 444p12 to 420jpeg\n");
1069 } else if (strcmp(y4m_ctx->chroma_type, "mono") == 0) {
1070 y4m_ctx->src_c_dec_h = y4m_ctx->src_c_dec_v = 0;
1071 y4m_ctx->dst_c_dec_h = y4m_ctx->dst_c_dec_v = 2;
1072 y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
1073 /*No extra space required, but we need to clear the chroma planes.*/
1074 y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
1075 y4m_ctx->convert = y4m_convert_mono_420jpeg;
1077 fprintf(stderr, "Unknown chroma sampling type: %s\n", y4m_ctx->chroma_type);
1080 /*The size of the final frame buffers is always computed from the
1081 destination chroma decimation type.*/
1082 y4m_ctx->dst_buf_sz =
1083 y4m_ctx->pic_w * y4m_ctx->pic_h +
1084 2 * ((y4m_ctx->pic_w + y4m_ctx->dst_c_dec_h - 1) / y4m_ctx->dst_c_dec_h) *
1085 ((y4m_ctx->pic_h + y4m_ctx->dst_c_dec_v - 1) / y4m_ctx->dst_c_dec_v);
1086 if (y4m_ctx->bit_depth == 8)
1087 y4m_ctx->dst_buf = (unsigned char *)malloc(y4m_ctx->dst_buf_sz);
1089 y4m_ctx->dst_buf = (unsigned char *)malloc(2 * y4m_ctx->dst_buf_sz);
1091 if (y4m_ctx->aux_buf_sz > 0)
1092 y4m_ctx->aux_buf = (unsigned char *)malloc(y4m_ctx->aux_buf_sz);
1096 void y4m_input_close(y4m_input *_y4m) {
1097 free(_y4m->dst_buf);
1098 free(_y4m->aux_buf);
1101 int y4m_input_fetch_frame(y4m_input *_y4m, FILE *_fin, vpx_image_t *_img) {
1107 int bytes_per_sample = _y4m->bit_depth > 8 ? 2 : 1;
1108 /*Read and skip the frame header.*/
1109 if (!file_read(frame, 6, _fin)) return 0;
1110 if (memcmp(frame, "FRAME", 5)) {
1111 fprintf(stderr, "Loss of framing in Y4M input data\n");
1114 if (frame[5] != '\n') {
1117 for (j = 0; j < 79 && file_read(&c, 1, _fin) && c != '\n'; j++) {
1120 fprintf(stderr, "Error parsing Y4M frame header\n");
1124 /*Read the frame data that needs no conversion.*/
1125 if (!file_read(_y4m->dst_buf, _y4m->dst_buf_read_sz, _fin)) {
1126 fprintf(stderr, "Error reading Y4M frame data.\n");
1129 /*Read the frame data that does need conversion.*/
1130 if (!file_read(_y4m->aux_buf, _y4m->aux_buf_read_sz, _fin)) {
1131 fprintf(stderr, "Error reading Y4M frame data.\n");
1134 /*Now convert the just read frame.*/
1135 (*_y4m->convert)(_y4m, _y4m->dst_buf, _y4m->aux_buf);
1136 /*Fill in the frame buffer pointers.
1137 We don't use vpx_img_wrap() because it forces padding for odd picture
1138 sizes, which would require a separate fread call for every row.*/
1139 memset(_img, 0, sizeof(*_img));
1140 /*Y4M has the planes in Y'CbCr order, which libvpx calls Y, U, and V.*/
1141 _img->fmt = _y4m->vpx_fmt;
1142 _img->w = _img->d_w = _y4m->pic_w;
1143 _img->h = _img->d_h = _y4m->pic_h;
1144 _img->x_chroma_shift = _y4m->dst_c_dec_h >> 1;
1145 _img->y_chroma_shift = _y4m->dst_c_dec_v >> 1;
1146 _img->bps = _y4m->bps;
1148 /*Set up the buffer pointers.*/
1149 pic_sz = _y4m->pic_w * _y4m->pic_h * bytes_per_sample;
1150 c_w = (_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h;
1151 c_w *= bytes_per_sample;
1152 c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
1154 _img->stride[VPX_PLANE_Y] = _img->stride[VPX_PLANE_ALPHA] =
1155 _y4m->pic_w * bytes_per_sample;
1156 _img->stride[VPX_PLANE_U] = _img->stride[VPX_PLANE_V] = c_w;
1157 _img->planes[VPX_PLANE_Y] = _y4m->dst_buf;
1158 _img->planes[VPX_PLANE_U] = _y4m->dst_buf + pic_sz;
1159 _img->planes[VPX_PLANE_V] = _y4m->dst_buf + pic_sz + c_sz;
1160 _img->planes[VPX_PLANE_ALPHA] = _y4m->dst_buf + pic_sz + 2 * c_sz;