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