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