15a50414796e9a458925c7a13a15055d02406bf43Vikas Arora// Copyright 2011 Google Inc. All Rights Reserved.
2466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//
3466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// This code is licensed under the same terms as WebM:
4466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//  Software License Agreement:  http://www.webmproject.org/license/software/
5466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//  Additional IP Rights Grant:  http://www.webmproject.org/license/additional/
6466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// -----------------------------------------------------------------------------
7466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//
8466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// functions for sample output.
9466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//
10466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// Author: Skal (pascal.massimino@gmail.com)
11466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
12466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#include <assert.h>
13466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#include <stdlib.h>
145a50414796e9a458925c7a13a15055d02406bf43Vikas Arora#include "../dec/vp8i.h"
155a50414796e9a458925c7a13a15055d02406bf43Vikas Arora#include "./webpi.h"
165a50414796e9a458925c7a13a15055d02406bf43Vikas Arora#include "../dsp/dsp.h"
175a50414796e9a458925c7a13a15055d02406bf43Vikas Arora#include "../dsp/yuv.h"
18466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
19466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#if defined(__cplusplus) || defined(c_plusplus)
20466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Aroraextern "C" {
21466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#endif
22466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
23466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//------------------------------------------------------------------------------
24466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// Main YUV<->RGB conversion functions
25466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
26466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
27466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPDecBuffer* output = p->output;
28466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const WebPYUVABuffer* const buf = &output->u.YUVA;
29466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  uint8_t* const y_dst = buf->y + io->mb_y * buf->y_stride;
30466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  uint8_t* const u_dst = buf->u + (io->mb_y >> 1) * buf->u_stride;
31466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  uint8_t* const v_dst = buf->v + (io->mb_y >> 1) * buf->v_stride;
32466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int mb_w = io->mb_w;
33466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int mb_h = io->mb_h;
34466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int uv_w = (mb_w + 1) / 2;
355a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const int uv_h = (mb_h + 1) / 2;
36466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int j;
37466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  for (j = 0; j < mb_h; ++j) {
38466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    memcpy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w);
39466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
405a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  for (j = 0; j < uv_h; ++j) {
41466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    memcpy(u_dst + j * buf->u_stride, io->u + j * io->uv_stride, uv_w);
42466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    memcpy(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w);
43466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
44466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return io->mb_h;
45466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
46466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
47466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// Point-sampling U/V sampler.
48466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
49466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPDecBuffer* output = p->output;
50466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const WebPRGBABuffer* const buf = &output->u.RGBA;
51466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
52466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* y_src = io->y;
53466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* u_src = io->u;
54466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* v_src = io->v;
555a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const WebPSampleLinePairFunc sample = WebPSamplers[output->colorspace];
56466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int mb_w = io->mb_w;
57466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int last = io->mb_h - 1;
58466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int j;
59466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  for (j = 0; j < last; j += 2) {
60466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    sample(y_src, y_src + io->y_stride, u_src, v_src,
61466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora           dst, dst + buf->stride, mb_w);
62466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    y_src += 2 * io->y_stride;
63466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    u_src += io->uv_stride;
64466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    v_src += io->uv_stride;
65466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    dst += 2 * buf->stride;
66466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
67466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (j == last) {  // Just do the last line twice
68466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    sample(y_src, y_src, u_src, v_src, dst, dst, mb_w);
69466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
70466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return io->mb_h;
71466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
72466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
73466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//------------------------------------------------------------------------------
74466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// YUV444 -> RGB conversion
75466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
76466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#if 0   // TODO(skal): this is for future rescaling.
77466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int EmitRGB(const VP8Io* const io, WebPDecParams* const p) {
78466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPDecBuffer* output = p->output;
79466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const WebPRGBABuffer* const buf = &output->u.RGBA;
80466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
81466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* y_src = io->y;
82466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* u_src = io->u;
83466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* v_src = io->v;
845a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const WebPYUV444Converter convert = WebPYUV444Converters[output->colorspace];
85466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int mb_w = io->mb_w;
86466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int last = io->mb_h;
87466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int j;
88466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  for (j = 0; j < last; ++j) {
89466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    convert(y_src, u_src, v_src, dst, mb_w);
90466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    y_src += io->y_stride;
91466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    u_src += io->uv_stride;
92466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    v_src += io->uv_stride;
93466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    dst += buf->stride;
94466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
95466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return io->mb_h;
96466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
97466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#endif
98466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
99466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//------------------------------------------------------------------------------
100466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// Fancy upsampling
101466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
102466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#ifdef FANCY_UPSAMPLING
103466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
104466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int num_lines_out = io->mb_h;   // a priori guess
105466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const WebPRGBABuffer* const buf = &p->output->u.RGBA;
106466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
1075a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace];
108466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* cur_y = io->y;
109466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* cur_u = io->u;
110466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* cur_v = io->v;
111466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* top_u = p->tmp_u;
112466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* top_v = p->tmp_v;
113466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int y = io->mb_y;
114466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int y_end = io->mb_y + io->mb_h;
115466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int mb_w = io->mb_w;
116466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int uv_w = (mb_w + 1) / 2;
117466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
118466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (y == 0) {
119466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    // First line is special cased. We mirror the u/v samples at boundary.
120466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    upsample(NULL, cur_y, cur_u, cur_v, cur_u, cur_v, NULL, dst, mb_w);
121466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  } else {
122466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    // We can finish the left-over line from previous call.
123466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v,
124466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora             dst - buf->stride, dst, mb_w);
1255a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    ++num_lines_out;
126466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
127466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  // Loop over each output pairs of row.
128466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  for (; y + 2 < y_end; y += 2) {
129466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    top_u = cur_u;
130466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    top_v = cur_v;
131466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    cur_u += io->uv_stride;
132466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    cur_v += io->uv_stride;
133466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    dst += 2 * buf->stride;
134466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    cur_y += 2 * io->y_stride;
135466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    upsample(cur_y - io->y_stride, cur_y,
136466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora             top_u, top_v, cur_u, cur_v,
137466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora             dst - buf->stride, dst, mb_w);
138466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
139466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  // move to last row
140466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  cur_y += io->y_stride;
141466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (io->crop_top + y_end < io->crop_bottom) {
142466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    // Save the unfinished samples for next call (as we're not done yet).
143466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    memcpy(p->tmp_y, cur_y, mb_w * sizeof(*p->tmp_y));
144466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    memcpy(p->tmp_u, cur_u, uv_w * sizeof(*p->tmp_u));
145466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    memcpy(p->tmp_v, cur_v, uv_w * sizeof(*p->tmp_v));
146466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    // The fancy upsampler leaves a row unfinished behind
147466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    // (except for the very last row)
148466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    num_lines_out--;
149466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  } else {
150466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    // Process the very last row of even-sized picture
151466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    if (!(y_end & 1)) {
152466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v,
153466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora              dst + buf->stride, NULL, mb_w);
154466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    }
155466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
156466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return num_lines_out;
157466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
158466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
159466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#endif    /* FANCY_UPSAMPLING */
160466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
161466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//------------------------------------------------------------------------------
162466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
163466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
1645a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const uint8_t* alpha = io->a;
1655a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const WebPYUVABuffer* const buf = &p->output->u.YUVA;
166466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int mb_w = io->mb_w;
167466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int mb_h = io->mb_h;
168466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  uint8_t* dst = buf->a + io->mb_y * buf->a_stride;
1695a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  int j;
1705a50414796e9a458925c7a13a15055d02406bf43Vikas Arora
1715a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  if (alpha != NULL) {
172466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    for (j = 0; j < mb_h; ++j) {
173466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      memcpy(dst, alpha, mb_w * sizeof(*dst));
174466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      alpha += io->width;
175466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      dst += buf->a_stride;
176466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    }
1775a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  } else if (buf->a != NULL) {
1785a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    // the user requested alpha, but there is none, set it to opaque.
1795a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    for (j = 0; j < mb_h; ++j) {
1805a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      memset(dst, 0xff, mb_w * sizeof(*dst));
1815a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      dst += buf->a_stride;
1825a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    }
183466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
184466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return 0;
185466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
186466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
1875a50414796e9a458925c7a13a15055d02406bf43Vikas Arorastatic int GetAlphaSourceRow(const VP8Io* const io,
1885a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                             const uint8_t** alpha, int* const num_rows) {
1895a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  int start_y = io->mb_y;
1905a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  *num_rows = io->mb_h;
1915a50414796e9a458925c7a13a15055d02406bf43Vikas Arora
1925a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  // Compensate for the 1-line delay of the fancy upscaler.
1935a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  // This is similar to EmitFancyRGB().
1945a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  if (io->fancy_upsampling) {
1955a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    if (start_y == 0) {
1965a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      // We don't process the last row yet. It'll be done during the next call.
1975a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      --*num_rows;
1985a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    } else {
1995a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      --start_y;
2005a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      // Fortunately, *alpha data is persistent, so we can go back
2015a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      // one row and finish alpha blending, now that the fancy upscaler
2025a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      // completed the YUV->RGB interpolation.
2035a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      *alpha -= io->width;
2045a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    }
2055a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    if (io->crop_top + io->mb_y + io->mb_h == io->crop_bottom) {
2065a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      // If it's the very last call, we process all the remaing rows!
2075a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      *num_rows = io->crop_bottom - io->crop_top - start_y;
2085a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    }
2095a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  }
2105a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  return start_y;
2115a50414796e9a458925c7a13a15055d02406bf43Vikas Arora}
2125a50414796e9a458925c7a13a15055d02406bf43Vikas Arora
213466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
214466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const uint8_t* alpha = io->a;
2155a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  if (alpha != NULL) {
2165a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const int mb_w = io->mb_w;
2175a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    int i, j;
2185a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const WEBP_CSP_MODE colorspace = p->output->colorspace;
2195a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const int alpha_first =
2205a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        (colorspace == MODE_ARGB || colorspace == MODE_Argb);
2215a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const WebPRGBABuffer* const buf = &p->output->u.RGBA;
2225a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    int num_rows;
2235a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
2245a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    uint32_t alpha_mask = 0xff;
2255a50414796e9a458925c7a13a15055d02406bf43Vikas Arora
2265a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    {
2275a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
2285a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
2295a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      for (j = 0; j < num_rows; ++j) {
2305a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        for (i = 0; i < mb_w; ++i) {
2315a50414796e9a458925c7a13a15055d02406bf43Vikas Arora          const uint32_t alpha_value = alpha[i];
2325a50414796e9a458925c7a13a15055d02406bf43Vikas Arora          dst[4 * i] = alpha_value;
2335a50414796e9a458925c7a13a15055d02406bf43Vikas Arora          alpha_mask &= alpha_value;
2345a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        }
2355a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        alpha += io->width;
2365a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        dst += buf->stride;
2375a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      }
2385a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      // alpha_mask is < 0xff if there's non-trivial alpha to premultiply with.
2395a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      if (alpha_mask != 0xff && WebPIsPremultipliedMode(colorspace)) {
2405a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        WebPApplyAlphaMultiply(base_rgba, alpha_first,
2415a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                               mb_w, num_rows, buf->stride);
242466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      }
243466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    }
244466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
245466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return 0;
246466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
247466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
2485a50414796e9a458925c7a13a15055d02406bf43Vikas Arorastatic int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) {
2495a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const uint8_t* alpha = io->a;
2505a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  if (alpha != NULL) {
2515a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const int mb_w = io->mb_w;
2525a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    int i, j;
2535a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const WebPRGBABuffer* const buf = &p->output->u.RGBA;
2545a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    int num_rows;
2555a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
2565a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    uint32_t alpha_mask = 0x0f;
2575a50414796e9a458925c7a13a15055d02406bf43Vikas Arora
2585a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    {
2595a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
2605a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      uint8_t* alpha_dst = base_rgba + 1;
2615a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      for (j = 0; j < num_rows; ++j) {
2625a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        for (i = 0; i < mb_w; ++i) {
2635a50414796e9a458925c7a13a15055d02406bf43Vikas Arora          // Fill in the alpha value (converted to 4 bits).
2645a50414796e9a458925c7a13a15055d02406bf43Vikas Arora          const uint32_t alpha_value = alpha[i] >> 4;
2655a50414796e9a458925c7a13a15055d02406bf43Vikas Arora          alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
2665a50414796e9a458925c7a13a15055d02406bf43Vikas Arora          alpha_mask &= alpha_value;
2675a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        }
2685a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        alpha += io->width;
2695a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        alpha_dst += buf->stride;
270466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      }
2715a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      if (alpha_mask != 0x0f && p->output->colorspace == MODE_rgbA_4444) {
2725a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride);
273466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      }
274466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    }
275466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
2765a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  return 0;
277466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
278466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
279466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//------------------------------------------------------------------------------
280466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// YUV rescaling (no final RGB conversion needed)
281466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
282466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int Rescale(const uint8_t* src, int src_stride,
283466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                   int new_lines, WebPRescaler* const wrk) {
284466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int num_lines_out = 0;
2855a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  while (new_lines > 0) {    // import new contributions of source rows.
2865a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride);
2875a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    src += lines_in * src_stride;
2885a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    new_lines -= lines_in;
2895a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    num_lines_out += WebPRescalerExport(wrk);    // emit output row(s)
290466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
291466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return num_lines_out;
292466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
293466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
294466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
295466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int mb_h = io->mb_h;
296466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int uv_mb_h = (mb_h + 1) >> 1;
297466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int num_lines_out = Rescale(io->y, io->y_stride, mb_h, &p->scaler_y);
298466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u);
299466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v);
300466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return num_lines_out;
301466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
302466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
303466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
3045a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  if (io->a != NULL) {
305466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    Rescale(io->a, io->width, io->mb_h, &p->scaler_a);
306466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
307466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return 0;
308466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
309466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
310466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
3115a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
312466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const WebPYUVABuffer* const buf = &p->output->u.YUVA;
313466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int out_width  = io->scaled_width;
314466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int out_height = io->scaled_height;
315466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int uv_out_width  = (out_width + 1) >> 1;
316466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int uv_out_height = (out_height + 1) >> 1;
317466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int uv_in_width  = (io->mb_w + 1) >> 1;
318466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int uv_in_height = (io->mb_h + 1) >> 1;
319466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const size_t work_size = 2 * out_width;   // scratch memory for luma rescaler
320466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const size_t uv_work_size = 2 * uv_out_width;  // and for each u/v ones
321466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  size_t tmp_size;
322466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int32_t* work;
323466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
324466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  tmp_size = work_size + 2 * uv_work_size;
325466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (has_alpha) {
326466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    tmp_size += work_size;
327466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
328466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  p->memory = calloc(1, tmp_size * sizeof(*work));
329466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (p->memory == NULL) {
330466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return 0;   // memory error
331466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
332466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  work = (int32_t*)p->memory;
3335a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
3345a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   buf->y, out_width, out_height, buf->y_stride, 1,
3355a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   io->mb_w, out_width, io->mb_h, out_height,
3365a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   work);
3375a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
3385a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
3395a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   uv_in_width, uv_out_width,
3405a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   uv_in_height, uv_out_height,
3415a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   work + work_size);
3425a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
3435a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
3445a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   uv_in_width, uv_out_width,
3455a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   uv_in_height, uv_out_height,
3465a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   work + work_size + uv_work_size);
347466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  p->emit = EmitRescaledYUV;
3485a50414796e9a458925c7a13a15055d02406bf43Vikas Arora
349466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (has_alpha) {
3505a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
3515a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                     buf->a, out_width, out_height, buf->a_stride, 1,
3525a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                     io->mb_w, out_width, io->mb_h, out_height,
3535a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                     work + work_size + 2 * uv_work_size);
354466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    p->emit_alpha = EmitRescaledAlphaYUV;
355466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
356466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return 1;
357466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
358466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
359466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//------------------------------------------------------------------------------
360466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// RGBA rescaling
361466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
362466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int ExportRGB(WebPDecParams* const p, int y_pos) {
3635a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const WebPYUV444Converter convert =
3645a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      WebPYUV444Converters[p->output->colorspace];
365466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const WebPRGBABuffer* const buf = &p->output->u.RGBA;
366466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride;
367466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int num_lines_out = 0;
368466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  // For RGB rescaling, because of the YUV420, current scan position
369466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  // U/V can be +1/-1 line from the Y one.  Hence the double test.
3705a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  while (WebPRescalerHasPendingOutput(&p->scaler_y) &&
3715a50414796e9a458925c7a13a15055d02406bf43Vikas Arora         WebPRescalerHasPendingOutput(&p->scaler_u)) {
372466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    assert(p->last_y + y_pos + num_lines_out < p->output->height);
373466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
3745a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    WebPRescalerExportRow(&p->scaler_y);
3755a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    WebPRescalerExportRow(&p->scaler_u);
3765a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    WebPRescalerExportRow(&p->scaler_v);
377466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst,
378466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora            dst, p->scaler_y.dst_width);
379466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    dst += buf->stride;
3805a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    ++num_lines_out;
381466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
382466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return num_lines_out;
383466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
384466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
385466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
386466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int mb_h = io->mb_h;
387466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int uv_mb_h = (mb_h + 1) >> 1;
388466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int j = 0, uv_j = 0;
389466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int num_lines_out = 0;
390466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  while (j < mb_h) {
3915a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const int y_lines_in =
3925a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        WebPRescalerImport(&p->scaler_y, mb_h - j,
3935a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                           io->y + j * io->y_stride, io->y_stride);
3945a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const int u_lines_in =
3955a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j,
3965a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                           io->u + uv_j * io->uv_stride, io->uv_stride);
3975a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    const int v_lines_in =
3985a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j,
3995a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                           io->v + uv_j * io->uv_stride, io->uv_stride);
400466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    (void)v_lines_in;   // remove a gcc warning
401466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    assert(u_lines_in == v_lines_in);
402466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    j += y_lines_in;
403466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    uv_j += u_lines_in;
404466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    num_lines_out += ExportRGB(p, num_lines_out);
405466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
406466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return num_lines_out;
407466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
408466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
409466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int ExportAlpha(WebPDecParams* const p, int y_pos) {
410466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const WebPRGBABuffer* const buf = &p->output->u.RGBA;
4115a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
4125a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const WEBP_CSP_MODE colorspace = p->output->colorspace;
4135a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const int alpha_first =
4145a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      (colorspace == MODE_ARGB || colorspace == MODE_Argb);
4155a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
416466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int num_lines_out = 0;
4175a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
4185a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  uint32_t alpha_mask = 0xff;
4195a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const int width = p->scaler_a.dst_width;
4205a50414796e9a458925c7a13a15055d02406bf43Vikas Arora
4215a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
422466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    int i;
423466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    assert(p->last_y + y_pos + num_lines_out < p->output->height);
4245a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    WebPRescalerExportRow(&p->scaler_a);
4255a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    for (i = 0; i < width; ++i) {
4265a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      const uint32_t alpha_value = p->scaler_a.dst[i];
4275a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      dst[4 * i] = alpha_value;
4285a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      alpha_mask &= alpha_value;
429466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    }
430466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    dst += buf->stride;
4315a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    ++num_lines_out;
4325a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  }
4335a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  if (is_premult_alpha && alpha_mask != 0xff) {
4345a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    WebPApplyAlphaMultiply(base_rgba, alpha_first,
4355a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                           width, num_lines_out, buf->stride);
4365a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  }
4375a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  return num_lines_out;
4385a50414796e9a458925c7a13a15055d02406bf43Vikas Arora}
4395a50414796e9a458925c7a13a15055d02406bf43Vikas Arora
4405a50414796e9a458925c7a13a15055d02406bf43Vikas Arorastatic int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
4415a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const WebPRGBABuffer* const buf = &p->output->u.RGBA;
4425a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
4435a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  uint8_t* alpha_dst = base_rgba + 1;
4445a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  int num_lines_out = 0;
4455a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const WEBP_CSP_MODE colorspace = p->output->colorspace;
4465a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const int width = p->scaler_a.dst_width;
4475a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
4485a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  uint32_t alpha_mask = 0x0f;
4495a50414796e9a458925c7a13a15055d02406bf43Vikas Arora
4505a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
4515a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    int i;
4525a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    assert(p->last_y + y_pos + num_lines_out < p->output->height);
4535a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    WebPRescalerExportRow(&p->scaler_a);
4545a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    for (i = 0; i < width; ++i) {
4555a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      // Fill in the alpha value (converted to 4 bits).
4565a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      const uint32_t alpha_value = p->scaler_a.dst[i] >> 4;
4575a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
4585a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      alpha_mask &= alpha_value;
4595a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    }
4605a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    alpha_dst += buf->stride;
4615a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    ++num_lines_out;
4625a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  }
4635a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  if (is_premult_alpha && alpha_mask != 0x0f) {
4645a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride);
465466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
466466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return num_lines_out;
467466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
468466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
469466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
4705a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  if (io->a != NULL) {
4715a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    WebPRescaler* const scaler = &p->scaler_a;
4725a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    int j = 0;
4735a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    int pos = 0;
474466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    while (j < io->mb_h) {
4755a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      j += WebPRescalerImport(scaler, io->mb_h - j,
4765a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                              io->a + j * io->width, io->width);
4775a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      pos += p->emit_alpha_row(p, pos);
478466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    }
479466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
480466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return 0;
481466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
482466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
483466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
4845a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
485466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int out_width  = io->scaled_width;
486466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int out_height = io->scaled_height;
487466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int uv_in_width  = (io->mb_w + 1) >> 1;
488466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int uv_in_height = (io->mb_h + 1) >> 1;
489466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const size_t work_size = 2 * out_width;   // scratch memory for one rescaler
490466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int32_t* work;  // rescalers work area
491466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  uint8_t* tmp;   // tmp storage for scaled YUV444 samples before RGB conversion
492466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  size_t tmp_size1, tmp_size2;
493466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
494466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  tmp_size1 = 3 * work_size;
495466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  tmp_size2 = 3 * out_width;
496466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (has_alpha) {
497466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    tmp_size1 += work_size;
498466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    tmp_size2 += out_width;
499466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
500466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  p->memory =
501466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp));
502466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (p->memory == NULL) {
503466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return 0;   // memory error
504466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
505466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  work = (int32_t*)p->memory;
506466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  tmp = (uint8_t*)(work + tmp_size1);
5075a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
5085a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   tmp + 0 * out_width, out_width, out_height, 0, 1,
5095a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   io->mb_w, out_width, io->mb_h, out_height,
5105a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   work + 0 * work_size);
5115a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
5125a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   tmp + 1 * out_width, out_width, out_height, 0, 1,
5135a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
5145a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   work + 1 * work_size);
5155a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
5165a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   tmp + 2 * out_width, out_width, out_height, 0, 1,
5175a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
5185a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                   work + 2 * work_size);
519466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  p->emit = EmitRescaledRGB;
520466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
521466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (has_alpha) {
5225a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
5235a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                     tmp + 3 * out_width, out_width, out_height, 0, 1,
5245a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                     io->mb_w, out_width, io->mb_h, out_height,
5255a50414796e9a458925c7a13a15055d02406bf43Vikas Arora                     work + 3 * work_size);
526466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    p->emit_alpha = EmitRescaledAlphaRGB;
5275a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    if (p->output->colorspace == MODE_RGBA_4444 ||
5285a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        p->output->colorspace == MODE_rgbA_4444) {
5295a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      p->emit_alpha_row = ExportAlphaRGBA4444;
5305a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    } else {
5315a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      p->emit_alpha_row = ExportAlpha;
5325a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    }
533466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
534466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return 1;
535466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
536466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
537466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//------------------------------------------------------------------------------
538466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// Default custom functions
539466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
540466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int CustomSetup(VP8Io* io) {
541466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPDecParams* const p = (WebPDecParams*)io->opaque;
5425a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const WEBP_CSP_MODE colorspace = p->output->colorspace;
5435a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const int is_rgb = WebPIsRGBMode(colorspace);
5445a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  const int is_alpha = WebPIsAlphaMode(colorspace);
545466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
546466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  p->memory = NULL;
547466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  p->emit = NULL;
548466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  p->emit_alpha = NULL;
5495a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  p->emit_alpha_row = NULL;
5505a50414796e9a458925c7a13a15055d02406bf43Vikas Arora  if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) {
551466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return 0;
552466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
553466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
554466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (io->use_scaling) {
555466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
556466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    if (!ok) {
557466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      return 0;    // memory error
558466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    }
559466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  } else {
560466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    if (is_rgb) {
561466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      p->emit = EmitSampledRGB;   // default
562466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#ifdef FANCY_UPSAMPLING
563466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      if (io->fancy_upsampling) {
564466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora        const int uv_width = (io->mb_w + 1) >> 1;
565466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora        p->memory = malloc(io->mb_w + 2 * uv_width);
566466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora        if (p->memory == NULL) {
567466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora          return 0;   // memory error.
568466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora        }
569466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora        p->tmp_y = (uint8_t*)p->memory;
570466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora        p->tmp_u = p->tmp_y + io->mb_w;
571466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora        p->tmp_v = p->tmp_u + uv_width;
572466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora        p->emit = EmitFancyRGB;
5735a50414796e9a458925c7a13a15055d02406bf43Vikas Arora        WebPInitUpsamplers();
574466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      }
575466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#endif
576466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    } else {
577466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      p->emit = EmitYUV;
578466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    }
5795a50414796e9a458925c7a13a15055d02406bf43Vikas Arora    if (is_alpha) {  // need transparency output
5805a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      if (WebPIsPremultipliedMode(colorspace)) WebPInitPremultiply();
5815a50414796e9a458925c7a13a15055d02406bf43Vikas Arora      p->emit_alpha =
5825a50414796e9a458925c7a13a15055d02406bf43Vikas Arora          (colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ?
5835a50414796e9a458925c7a13a15055d02406bf43Vikas Arora              EmitAlphaRGBA4444
5845a50414796e9a458925c7a13a15055d02406bf43Vikas Arora          : is_rgb ? EmitAlphaRGB
5855a50414796e9a458925c7a13a15055d02406bf43Vikas Arora          : EmitAlphaYUV;
586466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    }
587466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
588466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
589466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (is_rgb) {
590466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    VP8YUVInit();
591466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
592466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return 1;
593466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
594466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
595466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//------------------------------------------------------------------------------
596466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
597466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic int CustomPut(const VP8Io* io) {
598466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPDecParams* p = (WebPDecParams*)io->opaque;
599466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int mb_w = io->mb_w;
600466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const int mb_h = io->mb_h;
601466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  int num_lines_out;
602466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  assert(!(io->mb_y & 1));
603466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
604466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (mb_w <= 0 || mb_h <= 0) {
605466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return 0;
606466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
607466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  num_lines_out = p->emit(io, p);
608466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (p->emit_alpha) {
609466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    p->emit_alpha(io, p);
610466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
611466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  p->last_y += num_lines_out;
612466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return 1;
613466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
614466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
615466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//------------------------------------------------------------------------------
616466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
617466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic void CustomTeardown(const VP8Io* io) {
618466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPDecParams* const p = (WebPDecParams*)io->opaque;
619466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  free(p->memory);
620466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  p->memory = NULL;
621466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
622466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
623466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//------------------------------------------------------------------------------
624466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// Main entry point
625466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
626466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Aroravoid WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) {
627466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  io->put      = CustomPut;
628466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  io->setup    = CustomSetup;
629466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  io->teardown = CustomTeardown;
630466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  io->opaque   = params;
631466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
632466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
633466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//------------------------------------------------------------------------------
634466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
635466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#if defined(__cplusplus) || defined(c_plusplus)
636466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}    // extern "C"
637466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#endif
638