2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
11 * Based on code from the OggTheora software codec source code,
12 * Copyright (C) 2002-2010 The Xiph.Org Foundation and contributors.
19 #include "aom/aom_integer.h"
20 #include "aom_ports/msvc.h"
23 // Reads 'size' bytes from 'file' into 'buf' with some fault tolerance.
24 // Returns true on success.
25 static int file_read(void *buf
, size_t size
, FILE *file
) {
26 const int kMaxRetries
= 5;
31 const size_t n
= fread((uint8_t *)buf
+ len
, 1, size
- len
, file
);
33 file_error
= ferror(file
);
35 if (errno
== EINTR
|| errno
== EAGAIN
) {
39 fprintf(stderr
, "Error reading file: %u of %u bytes read, %d: %s\n",
40 (uint32_t)len
, (uint32_t)size
, errno
, strerror(errno
));
44 } while (!feof(file
) && len
< size
&& ++retry_count
< kMaxRetries
);
46 if (!feof(file
) && len
!= size
) {
48 "Error reading file: %u of %u bytes read,"
49 " error: %d, retries: %d, %d: %s\n",
50 (uint32_t)len
, (uint32_t)size
, file_error
, retry_count
, errno
,
56 // Stores the color range in 'y4m_ctx', returning 1 if successfully parsed,
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) {
63 if (strcmp(buf
, "FULL") == 0) {
64 y4m_ctx
->color_range
= AOM_CR_FULL_RANGE
;
67 fprintf(stderr
, "Unknown color range value: %s\n", 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);
75 return 1; // No support for other metadata, just ignore them.
78 static int y4m_parse_tags(y4m_input
*_y4m
, char *_tags
) {
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
++) {
92 if (sscanf(p
+ 1, "%d", &_y4m
->pic_w
) != 1) return -1;
95 if (sscanf(p
+ 1, "%d", &_y4m
->pic_h
) != 1) return -1;
98 if (sscanf(p
+ 1, "%d:%d", &_y4m
->fps_n
, &_y4m
->fps_d
) != 2) {
103 _y4m
->interlace
= p
[1];
106 if (sscanf(p
+ 1, "%d:%d", &_y4m
->par_n
, &_y4m
->par_d
) != 2) {
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';
116 if (!parse_metadata(_y4m
, p
+ 1)) return -1;
118 default: break; /*Ignore unknown tags.*/
124 // Copy a single tag into the buffer, along with a null character.
125 // Returns 0 if any file IO errors occur.
126 static int copy_tag(char *buf
, size_t buf_len
, char *end_tag
, FILE *file
) {
128 assert(buf_len
>= 1);
129 // Skip leading space characters.
131 if (!file_read(buf
, 1, file
)) {
134 } while (buf
[0] == ' ');
136 // If we hit the newline, treat this as the "empty" tag.
137 if (buf
[0] == '\n') {
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
)) {
148 if (buf
[i
] == ' ' || buf
[i
] == '\n') {
153 fprintf(stderr
, "Error: Y4M header tags must be less than %lu characters\n",
162 // Returns 1 if tags were parsed successfully, 0 otherwise.
163 static int parse_tags(y4m_input
*y4m_ctx
, FILE *file
) {
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.
170 y4m_ctx
->fps_n
= -1; // Also serves as marker for fps_d
173 y4m_ctx
->interlace
= '?';
174 y4m_ctx
->color_range
= AOM_CR_STUDIO_RANGE
;
175 snprintf(y4m_ctx
->chroma_type
, sizeof(y4m_ctx
->chroma_type
), "420");
177 // Find one tag at a time.
179 if (!copy_tag(tag
, sizeof(tag
), &end
, file
)) {
182 // y4m_parse_tags returns 0 on success.
183 if (y4m_parse_tags(y4m_ctx
, tag
)) {
186 } while (end
!= '\n');
188 // Check the mandatory fields.
189 if (y4m_ctx
->pic_w
== -1) {
190 fprintf(stderr
, "Width field missing\n");
193 if (y4m_ctx
->pic_h
== -1) {
194 fprintf(stderr
, "Height field missing\n");
197 if (y4m_ctx
->fps_n
== -1) {
198 fprintf(stderr
, "FPS field missing\n");
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)
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
213 The number of taps is intentionally kept small to reduce computational
214 overhead and limit ringing.
216 The taps from these filters are scaled so that their sum is 1, and the
217 result is scaled by 128 and rounded to integers to create a filter whose
218 intermediate values fit inside 16 bits.
219 Coefficients are rounded in such a way as to ensure their sum is still 128,
220 which is usually equivalent to normal rounding.
222 Conversions which require both horizontal and vertical filtering could
223 have these steps pipelined, for less memory consumption and better cache
224 performance, but we do them separately for simplicity.*/
225 #define OC_MINI(_a, _b) ((_a) > (_b) ? (_b) : (_a))
226 #define OC_MAXI(_a, _b) ((_a) < (_b) ? (_b) : (_a))
227 #define OC_CLAMPI(_a, _b, _c) (OC_MAXI(_a, OC_MINI(_b, _c)))
229 /*420jpeg chroma samples are sited like:
230 Y-------Y-------Y-------Y-------
234 Y-------Y-------Y-------Y-------
238 Y-------Y-------Y-------Y-------
242 Y-------Y-------Y-------Y-------
247 420mpeg2 chroma samples are sited like:
248 Y-------Y-------Y-------Y-------
252 Y-------Y-------Y-------Y-------
256 Y-------Y-------Y-------Y-------
260 Y-------Y-------Y-------Y-------
265 We use a resampling filter to shift the site locations one quarter pixel (at
266 the chroma plane's resolution) to the right.
267 The 4:2:2 modes look exactly the same, except there are twice as many chroma
268 lines, and they are vertically co-sited with the luma samples in both the
269 mpeg2 and jpeg cases (thus requiring no vertical resampling).*/
270 static void y4m_42xmpeg2_42xjpeg_helper(unsigned char *_dst
,
271 const unsigned char *_src
, int _c_w
,
275 for (y
= 0; y
< _c_h
; y
++) {
276 /*Filter: [4 -17 114 35 -9 1]/128, derived from a 6-tap Lanczos
278 for (x
= 0; x
< OC_MINI(_c_w
, 2); x
++) {
279 _dst
[x
] = (unsigned char)OC_CLAMPI(
281 (4 * _src
[0] - 17 * _src
[OC_MAXI(x
- 1, 0)] + 114 * _src
[x
] +
282 35 * _src
[OC_MINI(x
+ 1, _c_w
- 1)] -
283 9 * _src
[OC_MINI(x
+ 2, _c_w
- 1)] + _src
[OC_MINI(x
+ 3, _c_w
- 1)] +
288 for (; x
< _c_w
- 3; x
++) {
289 _dst
[x
] = (unsigned char)OC_CLAMPI(
291 (4 * _src
[x
- 2] - 17 * _src
[x
- 1] + 114 * _src
[x
] +
292 35 * _src
[x
+ 1] - 9 * _src
[x
+ 2] + _src
[x
+ 3] + 64) >>
296 for (; x
< _c_w
; x
++) {
297 _dst
[x
] = (unsigned char)OC_CLAMPI(
299 (4 * _src
[x
- 2] - 17 * _src
[x
- 1] + 114 * _src
[x
] +
300 35 * _src
[OC_MINI(x
+ 1, _c_w
- 1)] -
301 9 * _src
[OC_MINI(x
+ 2, _c_w
- 1)] + _src
[_c_w
- 1] + 64) >>
310 /*This format is only used for interlaced content, but is included for
313 420jpeg chroma samples are sited like:
314 Y-------Y-------Y-------Y-------
318 Y-------Y-------Y-------Y-------
322 Y-------Y-------Y-------Y-------
326 Y-------Y-------Y-------Y-------
331 420paldv chroma samples are sited like:
332 YR------Y-------YR------Y-------
336 YB------Y-------YB------Y-------
340 YR------Y-------YR------Y-------
344 YB------Y-------YB------Y-------
349 We use a resampling filter to shift the site locations one quarter pixel (at
350 the chroma plane's resolution) to the right.
351 Then we use another filter to move the C_r location down one quarter pixel,
352 and the C_b location up one quarter pixel.*/
353 static void y4m_convert_42xpaldv_42xjpeg(y4m_input
*_y4m
, unsigned char *_dst
,
354 unsigned char *_aux
) {
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
;
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
);
377 /*Slide C_b up a quarter-pel.
378 This is the same filter used above, but in the other order.*/
379 for (x
= 0; x
< c_w
; x
++) {
380 for (y
= 0; y
< OC_MINI(c_h
, 3); y
++) {
381 _dst
[y
* c_w
] = (unsigned char)OC_CLAMPI(
383 (tmp
[0] - 9 * tmp
[OC_MAXI(y
- 2, 0) * c_w
] +
384 35 * tmp
[OC_MAXI(y
- 1, 0) * c_w
] + 114 * tmp
[y
* c_w
] -
385 17 * tmp
[OC_MINI(y
+ 1, c_h
- 1) * c_w
] +
386 4 * tmp
[OC_MINI(y
+ 2, c_h
- 1) * c_w
] + 64) >>
390 for (; y
< c_h
- 2; y
++) {
391 _dst
[y
* c_w
] = (unsigned char)OC_CLAMPI(
393 (tmp
[(y
- 3) * c_w
] - 9 * tmp
[(y
- 2) * c_w
] +
394 35 * tmp
[(y
- 1) * c_w
] + 114 * tmp
[y
* c_w
] -
395 17 * tmp
[(y
+ 1) * c_w
] + 4 * tmp
[(y
+ 2) * c_w
] + 64) >>
399 for (; y
< c_h
; y
++) {
400 _dst
[y
* c_w
] = (unsigned char)OC_CLAMPI(
402 (tmp
[(y
- 3) * c_w
] - 9 * tmp
[(y
- 2) * c_w
] +
403 35 * tmp
[(y
- 1) * c_w
] + 114 * tmp
[y
* c_w
] -
404 17 * tmp
[OC_MINI(y
+ 1, c_h
- 1) * c_w
] +
405 4 * tmp
[(c_h
- 1) * c_w
] + 64) >>
416 /*Slide C_r down a quarter-pel.
417 This is the same as the horizontal filter.*/
418 for (x
= 0; x
< c_w
; x
++) {
419 for (y
= 0; y
< OC_MINI(c_h
, 2); y
++) {
420 _dst
[y
* c_w
] = (unsigned char)OC_CLAMPI(
422 (4 * tmp
[0] - 17 * tmp
[OC_MAXI(y
- 1, 0) * c_w
] +
423 114 * tmp
[y
* c_w
] + 35 * tmp
[OC_MINI(y
+ 1, c_h
- 1) * c_w
] -
424 9 * tmp
[OC_MINI(y
+ 2, c_h
- 1) * c_w
] +
425 tmp
[OC_MINI(y
+ 3, c_h
- 1) * c_w
] + 64) >>
429 for (; y
< c_h
- 3; y
++) {
430 _dst
[y
* c_w
] = (unsigned char)OC_CLAMPI(
432 (4 * tmp
[(y
- 2) * c_w
] - 17 * tmp
[(y
- 1) * c_w
] +
433 114 * tmp
[y
* c_w
] + 35 * tmp
[(y
+ 1) * c_w
] -
434 9 * tmp
[(y
+ 2) * c_w
] + tmp
[(y
+ 3) * c_w
] + 64) >>
438 for (; y
< c_h
; y
++) {
439 _dst
[y
* c_w
] = (unsigned char)OC_CLAMPI(
441 (4 * tmp
[(y
- 2) * c_w
] - 17 * tmp
[(y
- 1) * c_w
] +
442 114 * tmp
[y
* c_w
] + 35 * tmp
[OC_MINI(y
+ 1, c_h
- 1) * c_w
] -
443 9 * tmp
[OC_MINI(y
+ 2, c_h
- 1) * c_w
] + tmp
[(c_h
- 1) * c_w
] +
453 /*For actual interlaced material, this would have to be done separately on
454 each field, and the shift amounts would be different.
455 C_r moves down 1/8, C_b up 3/8 in the top field, and C_r moves down 3/8,
456 C_b up 1/8 in the bottom field.
457 The corresponding filters would be:
458 Down 1/8 (reverse order for up): [3 -11 125 15 -4 0]/128
459 Down 3/8 (reverse order for up): [4 -19 98 56 -13 2]/128*/
463 /*Perform vertical filtering to reduce a single plane from 4:2:2 to 4:2:0.
464 This is used as a helper by several conversion routines.*/
465 static void y4m_422jpeg_420jpeg_helper(unsigned char *_dst
,
466 const unsigned char *_src
, int _c_w
,
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
] =
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) >>
481 for (; y
< _c_h
- 3; y
+= 2) {
482 _dst
[(y
>> 1) * _c_w
] =
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) >>
490 for (; y
< _c_h
; y
+= 2) {
491 _dst
[(y
>> 1) * _c_w
] = OC_CLAMPI(
493 (3 * (_src
[(y
- 2) * _c_w
] + _src
[(_c_h
- 1) * _c_w
]) -
494 17 * (_src
[(y
- 1) * _c_w
] + _src
[OC_MINI(y
+ 2, _c_h
- 1) * _c_w
]) +
495 78 * (_src
[y
* _c_w
] + _src
[OC_MINI(y
+ 1, _c_h
- 1) * _c_w
]) +
505 /*420jpeg chroma samples are sited like:
506 Y-------Y-------Y-------Y-------
510 Y-------Y-------Y-------Y-------
514 Y-------Y-------Y-------Y-------
518 Y-------Y-------Y-------Y-------
523 422jpeg chroma samples are sited like:
524 Y---BR--Y-------Y---BR--Y-------
528 Y---BR--Y-------Y---BR--Y-------
532 Y---BR--Y-------Y---BR--Y-------
536 Y---BR--Y-------Y---BR--Y-------
541 We use a resampling filter to decimate the chroma planes by two in the
542 vertical direction.*/
543 static void y4m_convert_422jpeg_420jpeg(y4m_input
*_y4m
, unsigned char *_dst
,
544 unsigned char *_aux
) {
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
;
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
;
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
);
568 /*420jpeg chroma samples are sited like:
569 Y-------Y-------Y-------Y-------
573 Y-------Y-------Y-------Y-------
577 Y-------Y-------Y-------Y-------
581 Y-------Y-------Y-------Y-------
586 422 chroma samples are sited like:
587 YBR-----Y-------YBR-----Y-------
591 YBR-----Y-------YBR-----Y-------
595 YBR-----Y-------YBR-----Y-------
599 YBR-----Y-------YBR-----Y-------
604 We use a resampling filter to shift the original site locations one quarter
605 pixel (at the original chroma resolution) to the right.
606 Then we use a second resampling filter to decimate the chroma planes by two
607 in the vertical direction.*/
608 static void y4m_convert_422_420jpeg(y4m_input
*_y4m
, unsigned char *_dst
,
609 unsigned char *_aux
) {
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
;
622 dst_c_h
= (_y4m
->pic_h
+ _y4m
->dst_c_dec_v
- 1) / _y4m
->dst_c_dec_v
;
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
);
639 /*420jpeg chroma samples are sited like:
640 Y-------Y-------Y-------Y-------
644 Y-------Y-------Y-------Y-------
648 Y-------Y-------Y-------Y-------
652 Y-------Y-------Y-------Y-------
657 411 chroma samples are sited like:
658 YBR-----Y-------Y-------Y-------
662 YBR-----Y-------Y-------Y-------
666 YBR-----Y-------Y-------Y-------
670 YBR-----Y-------Y-------Y-------
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
678 Then we use another filter to decimate the planes by 2 in the vertical
680 static void y4m_convert_411_420jpeg(y4m_input
*_y4m
, unsigned char *_dst
,
681 unsigned char *_aux
) {
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
;
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
;
701 dst_c_sz
= dst_c_w
* dst_c_h
;
702 tmp_sz
= dst_c_w
* c_h
;
703 tmp
= _aux
+ 2 * c_sz
;
704 for (pli
= 1; pli
< 3; pli
++) {
705 /*In reality, the horizontal and vertical steps could be pipelined, for
706 less memory consumption and better cache performance, but we do them
707 separately for simplicity.*/
708 /*First do horizontal filtering (convert to 422jpeg)*/
709 for (y
= 0; y
< c_h
; y
++) {
710 /*Filters: [1 110 18 -1]/128 and [-3 50 86 -5]/128, both derived from a
711 4-tap Mitchell window.*/
712 for (x
= 0; x
< OC_MINI(c_w
, 1); x
++) {
713 tmp
[x
<< 1] = (unsigned char)OC_CLAMPI(
715 (111 * _aux
[0] + 18 * _aux
[OC_MINI(1, c_w
- 1)] -
716 _aux
[OC_MINI(2, c_w
- 1)] + 64) >>
719 tmp
[x
<< 1 | 1] = (unsigned char)OC_CLAMPI(
721 (47 * _aux
[0] + 86 * _aux
[OC_MINI(1, c_w
- 1)] -
722 5 * _aux
[OC_MINI(2, c_w
- 1)] + 64) >>
726 for (; x
< c_w
- 2; x
++) {
728 (unsigned char)OC_CLAMPI(0,
729 (_aux
[x
- 1] + 110 * _aux
[x
] +
730 18 * _aux
[x
+ 1] - _aux
[x
+ 2] + 64) >>
733 tmp
[x
<< 1 | 1] = (unsigned char)OC_CLAMPI(
735 (-3 * _aux
[x
- 1] + 50 * _aux
[x
] + 86 * _aux
[x
+ 1] -
736 5 * _aux
[x
+ 2] + 64) >>
740 for (; x
< c_w
; x
++) {
741 tmp
[x
<< 1] = (unsigned char)OC_CLAMPI(
743 (_aux
[x
- 1] + 110 * _aux
[x
] + 18 * _aux
[OC_MINI(x
+ 1, c_w
- 1)] -
744 _aux
[c_w
- 1] + 64) >>
747 if ((x
<< 1 | 1) < dst_c_w
) {
748 tmp
[x
<< 1 | 1] = (unsigned char)OC_CLAMPI(
750 (-3 * _aux
[x
- 1] + 50 * _aux
[x
] +
751 86 * _aux
[OC_MINI(x
+ 1, c_w
- 1)] - 5 * _aux
[c_w
- 1] + 64) >>
760 /*Now do the vertical filtering.*/
761 y4m_422jpeg_420jpeg_helper(_dst
, tmp
, dst_c_w
, c_h
);
766 /*Convert 444 to 420jpeg.*/
767 static void y4m_convert_444_420jpeg(y4m_input
*_y4m
, unsigned char *_dst
,
768 unsigned char *_aux
) {
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
;
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
;
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) >>
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) >>
810 for (; x
< c_w
; x
+= 2) {
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) >>
823 /*Now do the vertical filtering.*/
824 y4m_422jpeg_420jpeg_helper(_dst
, tmp
, dst_c_w
, c_h
);
829 /*The image is padded with empty chroma components at 4:2:0.*/
830 static void y4m_convert_mono_420jpeg(y4m_input
*_y4m
, unsigned char *_dst
,
831 unsigned char *_aux
) {
834 _dst
+= _y4m
->pic_w
* _y4m
->pic_h
;
835 c_sz
= ((_y4m
->pic_w
+ _y4m
->dst_c_dec_h
- 1) / _y4m
->dst_c_dec_h
) *
836 ((_y4m
->pic_h
+ _y4m
->dst_c_dec_v
- 1) / _y4m
->dst_c_dec_v
);
837 memset(_dst
, 128, c_sz
* 2);
840 /*No conversion function needed.*/
841 static void y4m_convert_null(y4m_input
*_y4m
, unsigned char *_dst
,
842 unsigned char *_aux
) {
848 static const char TAG
[] = "YUV4MPEG2";
850 int y4m_input_open(y4m_input
*y4m_ctx
, FILE *file
, char *skip_buffer
,
851 int num_skip
, aom_chroma_sample_position_t csp
,
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);
859 memcpy(tag_buffer
, skip_buffer
, num_skip
);
861 // Start reading from the file now that the |skip_buffer| is depleted.
862 if (!file_read(tag_buffer
+ num_skip
, 9 - num_skip
, file
)) {
865 if (memcmp(TAG
, tag_buffer
, 9) != 0) {
866 fprintf(stderr
, "Error parsing header: must start with %s\n", TAG
);
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
);
874 if (!parse_tags(y4m_ctx
, file
)) {
875 fprintf(stderr
, "Error parsing %s header.\n", TAG
);
878 if (y4m_ctx
->interlace
== '?') {
880 "Warning: Input video interlacing format unknown; "
881 "assuming progressive scan.\n");
882 } else if (y4m_ctx
->interlace
!= 'p') {
884 "Input video is interlaced; "
885 "Only progressive scan handled.\n");
888 /* Only support vertical chroma sample position if the input format is
889 * already 420mpeg2. Colocated is not supported in Y4M.
891 if (csp
== AOM_CSP_VERTICAL
&&
892 strcmp(y4m_ctx
->chroma_type
, "420mpeg2") != 0) {
894 "Vertical chroma sample position only supported "
895 "for 420mpeg2 input\n");
898 if (csp
== AOM_CSP_COLOCATED
) {
899 // TODO(any): check the right way to handle this in y4m
901 "Ignoring colocated chroma sample position for reading in Y4M\n");
903 y4m_ctx
->aom_fmt
= AOM_IMG_FMT_I420
;
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;
932 y4m_ctx
->aom_fmt
= AOM_IMG_FMT_I42016
;
934 fprintf(stderr
, "Unsupported conversion from 420p10 to 420jpeg\n");
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;
950 y4m_ctx
->aom_fmt
= AOM_IMG_FMT_I42016
;
952 fprintf(stderr
, "Unsupported conversion from 420p12 to 420jpeg\n");
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
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;
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
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
;
992 y4m_ctx
->aom_fmt
= AOM_IMG_FMT_I422
;
994 y4m_ctx
->dst_c_dec_h
= y4m_ctx
->src_c_dec_h
;
995 y4m_ctx
->dst_c_dec_v
= y4m_ctx
->src_c_dec_v
;
996 y4m_ctx
->dst_buf_read_sz
=
997 y4m_ctx
->pic_w
* y4m_ctx
->pic_h
+
998 2 * ((y4m_ctx
->pic_w
+ 1) / 2) * y4m_ctx
->pic_h
;
999 /*Natively supported: no conversion required.*/
1000 y4m_ctx
->aux_buf_sz
= y4m_ctx
->aux_buf_read_sz
= 0;
1001 y4m_ctx
->convert
= y4m_convert_null
;
1003 } else if (strcmp(y4m_ctx
->chroma_type
, "422p10") == 0) {
1004 y4m_ctx
->src_c_dec_h
= 2;
1005 y4m_ctx
->src_c_dec_v
= 1;
1006 y4m_ctx
->aom_fmt
= AOM_IMG_FMT_I42216
;
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
;
1017 fprintf(stderr
, "Unsupported conversion from 422p10 to 420jpeg\n");
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
;
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
;
1034 fprintf(stderr
, "Unsupported conversion from 422p12 to 420jpeg\n");
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
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;
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
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
;
1065 y4m_ctx
->aom_fmt
= AOM_IMG_FMT_I444
;
1067 y4m_ctx
->dst_c_dec_h
= y4m_ctx
->src_c_dec_h
;
1068 y4m_ctx
->dst_c_dec_v
= y4m_ctx
->src_c_dec_v
;
1069 y4m_ctx
->dst_buf_read_sz
= 3 * y4m_ctx
->pic_w
* y4m_ctx
->pic_h
;
1070 /*Natively supported: no conversion required.*/
1071 y4m_ctx
->aux_buf_sz
= y4m_ctx
->aux_buf_read_sz
= 0;
1072 y4m_ctx
->convert
= y4m_convert_null
;
1074 } else if (strcmp(y4m_ctx
->chroma_type
, "444p10") == 0) {
1075 y4m_ctx
->src_c_dec_h
= 1;
1076 y4m_ctx
->src_c_dec_v
= 1;
1077 y4m_ctx
->aom_fmt
= AOM_IMG_FMT_I44416
;
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
;
1086 fprintf(stderr
, "Unsupported conversion from 444p10 to 420jpeg\n");
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
;
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
;
1101 fprintf(stderr
, "Unsupported conversion from 444p12 to 420jpeg\n");
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;
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
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
;
1120 fprintf(stderr
, "Unsupported format: 444A\n");
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
;
1131 fprintf(stderr
, "Unknown chroma sampling type: %s\n", y4m_ctx
->chroma_type
);
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
);
1143 y4m_ctx
->dst_buf
= (unsigned char *)malloc(2 * y4m_ctx
->dst_buf_sz
);
1145 if (y4m_ctx
->aux_buf_sz
> 0)
1146 y4m_ctx
->aux_buf
= (unsigned char *)malloc(y4m_ctx
->aux_buf_sz
);
1150 void y4m_input_close(y4m_input
*_y4m
) {
1151 free(_y4m
->dst_buf
);
1152 free(_y4m
->aux_buf
);
1155 int y4m_input_fetch_frame(y4m_input
*_y4m
, FILE *_fin
, aom_image_t
*_img
) {
1161 int bytes_per_sample
= _y4m
->bit_depth
> 8 ? 2 : 1;
1162 /*Read and skip the frame header.*/
1163 if (!file_read(frame
, 6, _fin
)) return 0;
1164 if (memcmp(frame
, "FRAME", 5)) {
1165 fprintf(stderr
, "Loss of framing in Y4M input data\n");
1168 if (frame
[5] != '\n') {
1171 for (j
= 0; j
< 79 && file_read(&c
, 1, _fin
) && c
!= '\n'; j
++) {
1174 fprintf(stderr
, "Error parsing Y4M frame header\n");
1178 /*Read the frame data that needs no conversion.*/
1179 if (!file_read(_y4m
->dst_buf
, _y4m
->dst_buf_read_sz
, _fin
)) {
1180 fprintf(stderr
, "Error reading Y4M frame data.\n");
1183 /*Read the frame data that does need conversion.*/
1184 if (!file_read(_y4m
->aux_buf
, _y4m
->aux_buf_read_sz
, _fin
)) {
1185 fprintf(stderr
, "Error reading Y4M frame data.\n");
1188 /*Now convert the just read frame.*/
1189 (*_y4m
->convert
)(_y4m
, _y4m
->dst_buf
, _y4m
->aux_buf
);
1190 /*Fill in the frame buffer pointers.
1191 We don't use aom_img_wrap() because it forces padding for odd picture
1192 sizes, which would require a separate fread call for every row.*/
1193 memset(_img
, 0, sizeof(*_img
));
1194 /*Y4M has the planes in Y'CbCr order, which libaom calls Y, U, and V.*/
1195 _img
->fmt
= _y4m
->aom_fmt
;
1196 _img
->w
= _img
->d_w
= _y4m
->pic_w
;
1197 _img
->h
= _img
->d_h
= _y4m
->pic_h
;
1198 _img
->x_chroma_shift
= _y4m
->dst_c_dec_h
>> 1;
1199 _img
->y_chroma_shift
= _y4m
->dst_c_dec_v
>> 1;
1200 _img
->bps
= _y4m
->bps
;
1202 /*Set up the buffer pointers.*/
1203 pic_sz
= _y4m
->pic_w
* _y4m
->pic_h
* bytes_per_sample
;
1204 c_w
= (_y4m
->pic_w
+ _y4m
->dst_c_dec_h
- 1) / _y4m
->dst_c_dec_h
;
1205 c_w
*= bytes_per_sample
;
1206 c_h
= (_y4m
->pic_h
+ _y4m
->dst_c_dec_v
- 1) / _y4m
->dst_c_dec_v
;
1208 _img
->stride
[AOM_PLANE_Y
] = _y4m
->pic_w
* bytes_per_sample
;
1209 _img
->stride
[AOM_PLANE_U
] = _img
->stride
[AOM_PLANE_V
] = c_w
;
1210 _img
->planes
[AOM_PLANE_Y
] = _y4m
->dst_buf
;
1211 _img
->planes
[AOM_PLANE_U
] = _y4m
->dst_buf
+ pic_sz
;
1212 _img
->planes
[AOM_PLANE_V
] = _y4m
->dst_buf
+ pic_sz
+ c_sz
;