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