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