1793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Copyright 2011 Google Inc. All Rights Reserved. 2793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// 3793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Use of this source code is governed by a BSD-style license 4793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// that can be found in the COPYING file in the root of the source 5793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// tree. An additional intellectual property rights grant can be found 6793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// in the file PATENTS. All contributing project authors may 7793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// be found in the AUTHORS file in the root of the source tree. 8793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// ----------------------------------------------------------------------------- 9793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// 10793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// functions for sample output. 11793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// 12793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Author: Skal (pascal.massimino@gmail.com) 13793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 14793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include <assert.h> 15793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include <stdlib.h> 16793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "../dec/vp8i.h" 17793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "./webpi.h" 18793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "../dsp/dsp.h" 19793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "../dsp/yuv.h" 20793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 21793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#if defined(__cplusplus) || defined(c_plusplus) 22793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerextern "C" { 23793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif 24793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 25793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//------------------------------------------------------------------------------ 26793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Main YUV<->RGB conversion functions 27793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 28793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int EmitYUV(const VP8Io* const io, WebPDecParams* const p) { 29793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPDecBuffer* output = p->output; 30793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPYUVABuffer* const buf = &output->u.YUVA; 31793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* const y_dst = buf->y + io->mb_y * buf->y_stride; 32793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* const u_dst = buf->u + (io->mb_y >> 1) * buf->u_stride; 33793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* const v_dst = buf->v + (io->mb_y >> 1) * buf->v_stride; 34793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_w = io->mb_w; 35793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_h = io->mb_h; 36793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_w = (mb_w + 1) / 2; 37793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_h = (mb_h + 1) / 2; 38793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int j; 39793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (j = 0; j < mb_h; ++j) { 40793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler memcpy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w); 41793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 42793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (j = 0; j < uv_h; ++j) { 43793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler memcpy(u_dst + j * buf->u_stride, io->u + j * io->uv_stride, uv_w); 44793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler memcpy(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w); 45793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 46793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return io->mb_h; 47793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 48793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 49793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Point-sampling U/V sampler. 50793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) { 51793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPDecBuffer* output = p->output; 52793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPRGBABuffer* const buf = &output->u.RGBA; 53793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* dst = buf->rgba + io->mb_y * buf->stride; 54793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* y_src = io->y; 55793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* u_src = io->u; 56793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* v_src = io->v; 57793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPSampleLinePairFunc sample = WebPSamplers[output->colorspace]; 58793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_w = io->mb_w; 59793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int last = io->mb_h - 1; 60793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int j; 61793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (j = 0; j < last; j += 2) { 62793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler sample(y_src, y_src + io->y_stride, u_src, v_src, 63793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst, dst + buf->stride, mb_w); 64793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler y_src += 2 * io->y_stride; 65793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler u_src += io->uv_stride; 66793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler v_src += io->uv_stride; 67793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst += 2 * buf->stride; 68793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 69793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (j == last) { // Just do the last line twice 70793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler sample(y_src, y_src, u_src, v_src, dst, dst, mb_w); 71793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 72793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return io->mb_h; 73793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 74793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 75793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//------------------------------------------------------------------------------ 76793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// YUV444 -> RGB conversion 77793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 78793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#if 0 // TODO(skal): this is for future rescaling. 79793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int EmitRGB(const VP8Io* const io, WebPDecParams* const p) { 80793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPDecBuffer* output = p->output; 81793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPRGBABuffer* const buf = &output->u.RGBA; 82793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* dst = buf->rgba + io->mb_y * buf->stride; 83793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* y_src = io->y; 84793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* u_src = io->u; 85793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* v_src = io->v; 86793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPYUV444Converter convert = WebPYUV444Converters[output->colorspace]; 87793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_w = io->mb_w; 88793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int last = io->mb_h; 89793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int j; 90793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (j = 0; j < last; ++j) { 91793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler convert(y_src, u_src, v_src, dst, mb_w); 92793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler y_src += io->y_stride; 93793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler u_src += io->uv_stride; 94793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler v_src += io->uv_stride; 95793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst += buf->stride; 96793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 97793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return io->mb_h; 98793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 99793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif 100793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 101793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//------------------------------------------------------------------------------ 102793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Fancy upsampling 103793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 104793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef FANCY_UPSAMPLING 105793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) { 106793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int num_lines_out = io->mb_h; // a priori guess 107793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPRGBABuffer* const buf = &p->output->u.RGBA; 108793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* dst = buf->rgba + io->mb_y * buf->stride; 109793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace]; 110793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* cur_y = io->y; 111793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* cur_u = io->u; 112793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* cur_v = io->v; 113793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* top_u = p->tmp_u; 114793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* top_v = p->tmp_v; 115793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int y = io->mb_y; 116793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int y_end = io->mb_y + io->mb_h; 117793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_w = io->mb_w; 118793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_w = (mb_w + 1) / 2; 119793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 120793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (y == 0) { 121793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // First line is special cased. We mirror the u/v samples at boundary. 122793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler upsample(NULL, cur_y, cur_u, cur_v, cur_u, cur_v, NULL, dst, mb_w); 123793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } else { 124793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // We can finish the left-over line from previous call. 125793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v, 126793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst - buf->stride, dst, mb_w); 127793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler ++num_lines_out; 128793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 129793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // Loop over each output pairs of row. 130793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (; y + 2 < y_end; y += 2) { 131793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler top_u = cur_u; 132793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler top_v = cur_v; 133793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cur_u += io->uv_stride; 134793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cur_v += io->uv_stride; 135793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst += 2 * buf->stride; 136793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cur_y += 2 * io->y_stride; 137793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler upsample(cur_y - io->y_stride, cur_y, 138793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler top_u, top_v, cur_u, cur_v, 139793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst - buf->stride, dst, mb_w); 140793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 141793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // move to last row 142793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cur_y += io->y_stride; 143793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (io->crop_top + y_end < io->crop_bottom) { 144793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // Save the unfinished samples for next call (as we're not done yet). 145793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler memcpy(p->tmp_y, cur_y, mb_w * sizeof(*p->tmp_y)); 146793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler memcpy(p->tmp_u, cur_u, uv_w * sizeof(*p->tmp_u)); 147793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler memcpy(p->tmp_v, cur_v, uv_w * sizeof(*p->tmp_v)); 148793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // The fancy upsampler leaves a row unfinished behind 149793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // (except for the very last row) 150793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler num_lines_out--; 151793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } else { 152793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // Process the very last row of even-sized picture 153793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (!(y_end & 1)) { 154793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, 155793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst + buf->stride, NULL, mb_w); 156793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 157793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 158793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return num_lines_out; 159793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 160793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 161793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif /* FANCY_UPSAMPLING */ 162793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 163793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//------------------------------------------------------------------------------ 164793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 165793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p) { 166793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* alpha = io->a; 167793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPYUVABuffer* const buf = &p->output->u.YUVA; 168793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_w = io->mb_w; 169793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_h = io->mb_h; 170793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* dst = buf->a + io->mb_y * buf->a_stride; 171793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int j; 172793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 173793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (alpha != NULL) { 174793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (j = 0; j < mb_h; ++j) { 175793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler memcpy(dst, alpha, mb_w * sizeof(*dst)); 176793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler alpha += io->width; 177793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst += buf->a_stride; 178793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 179793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } else if (buf->a != NULL) { 180793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // the user requested alpha, but there is none, set it to opaque. 181793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (j = 0; j < mb_h; ++j) { 182793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler memset(dst, 0xff, mb_w * sizeof(*dst)); 183793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst += buf->a_stride; 184793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 185793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 186793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 187793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 188793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 189793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int GetAlphaSourceRow(const VP8Io* const io, 190793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t** alpha, int* const num_rows) { 191793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int start_y = io->mb_y; 192793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler *num_rows = io->mb_h; 193793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 194793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // Compensate for the 1-line delay of the fancy upscaler. 195793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // This is similar to EmitFancyRGB(). 196793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (io->fancy_upsampling) { 197793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (start_y == 0) { 198793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // We don't process the last row yet. It'll be done during the next call. 199793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler --*num_rows; 200793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } else { 201793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler --start_y; 202793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // Fortunately, *alpha data is persistent, so we can go back 203793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // one row and finish alpha blending, now that the fancy upscaler 204793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // completed the YUV->RGB interpolation. 205793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler *alpha -= io->width; 206793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 207793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (io->crop_top + io->mb_y + io->mb_h == io->crop_bottom) { 208793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // If it's the very last call, we process all the remaining rows! 209793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler *num_rows = io->crop_bottom - io->crop_top - start_y; 210793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 211793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 212793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return start_y; 213793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 214793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 215793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) { 216793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* alpha = io->a; 217793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (alpha != NULL) { 218793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_w = io->mb_w; 219793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WEBP_CSP_MODE colorspace = p->output->colorspace; 220793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int alpha_first = 221793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler (colorspace == MODE_ARGB || colorspace == MODE_Argb); 222793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPRGBABuffer* const buf = &p->output->u.RGBA; 223793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int num_rows; 224793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows); 225793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; 226793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* dst = base_rgba + (alpha_first ? 0 : 3); 227793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint32_t alpha_mask = 0xff; 228793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int i, j; 229793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 230793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (j = 0; j < num_rows; ++j) { 231793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (i = 0; i < mb_w; ++i) { 232793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint32_t alpha_value = alpha[i]; 233793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst[4 * i] = alpha_value; 234793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler alpha_mask &= alpha_value; 235793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 236793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler alpha += io->width; 237793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst += buf->stride; 238793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 239793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // alpha_mask is < 0xff if there's non-trivial alpha to premultiply with. 240793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (alpha_mask != 0xff && WebPIsPremultipliedMode(colorspace)) { 241793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPApplyAlphaMultiply(base_rgba, alpha_first, 242793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler mb_w, num_rows, buf->stride); 243793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 244793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 245793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 246793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 247793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 248793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) { 249793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint8_t* alpha = io->a; 250793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (alpha != NULL) { 251793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_w = io->mb_w; 252793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WEBP_CSP_MODE colorspace = p->output->colorspace; 253793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPRGBABuffer* const buf = &p->output->u.RGBA; 254793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int num_rows; 255793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows); 256793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; 257793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* alpha_dst = base_rgba + 1; 258793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint32_t alpha_mask = 0x0f; 259793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int i, j; 260793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 261793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (j = 0; j < num_rows; ++j) { 262793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (i = 0; i < mb_w; ++i) { 263793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // Fill in the alpha value (converted to 4 bits). 264793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint32_t alpha_value = alpha[i] >> 4; 265793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; 266793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler alpha_mask &= alpha_value; 267793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 268793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler alpha += io->width; 269793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler alpha_dst += buf->stride; 270793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 271793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (alpha_mask != 0x0f && WebPIsPremultipliedMode(colorspace)) { 272793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride); 273793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 274793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 275793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 276793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 277793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 278793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//------------------------------------------------------------------------------ 279793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// YUV rescaling (no final RGB conversion needed) 280793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 281793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int Rescale(const uint8_t* src, int src_stride, 282793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int new_lines, WebPRescaler* const wrk) { 283793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int num_lines_out = 0; 284793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler while (new_lines > 0) { // import new contributions of source rows. 285793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride); 286793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler src += lines_in * src_stride; 287793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler new_lines -= lines_in; 288793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler num_lines_out += WebPRescalerExport(wrk); // emit output row(s) 289793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 290793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return num_lines_out; 291793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 292793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 293793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { 294793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_h = io->mb_h; 295793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_mb_h = (mb_h + 1) >> 1; 296793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int num_lines_out = Rescale(io->y, io->y_stride, mb_h, &p->scaler_y); 297793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u); 298793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v); 299793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return num_lines_out; 300793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 301793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 302793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) { 303793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (io->a != NULL) { 304793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Rescale(io->a, io->width, io->mb_h, &p->scaler_a); 305793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 306793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 307793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 308793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 309793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) { 310793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int has_alpha = WebPIsAlphaMode(p->output->colorspace); 311793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPYUVABuffer* const buf = &p->output->u.YUVA; 312793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int out_width = io->scaled_width; 313793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int out_height = io->scaled_height; 314793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_out_width = (out_width + 1) >> 1; 315793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_out_height = (out_height + 1) >> 1; 316793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_in_width = (io->mb_w + 1) >> 1; 317793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_in_height = (io->mb_h + 1) >> 1; 318793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const size_t work_size = 2 * out_width; // scratch memory for luma rescaler 319793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones 320793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler size_t tmp_size; 321793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int32_t* work; 322793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 323793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp_size = work_size + 2 * uv_work_size; 324793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (has_alpha) { 325793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp_size += work_size; 326793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 327793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->memory = calloc(1, tmp_size * sizeof(*work)); 328793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (p->memory == NULL) { 329793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; // memory error 330793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 331793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler work = (int32_t*)p->memory; 332793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, 333793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler buf->y, out_width, out_height, buf->y_stride, 1, 334793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->mb_w, out_width, io->mb_h, out_height, 335793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler work); 336793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, 337793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler buf->u, uv_out_width, uv_out_height, buf->u_stride, 1, 338793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uv_in_width, uv_out_width, 339793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uv_in_height, uv_out_height, 340793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler work + work_size); 341793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, 342793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler buf->v, uv_out_width, uv_out_height, buf->v_stride, 1, 343793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uv_in_width, uv_out_width, 344793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uv_in_height, uv_out_height, 345793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler work + work_size + uv_work_size); 346793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit = EmitRescaledYUV; 347793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 348793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (has_alpha) { 349793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, 350793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler buf->a, out_width, out_height, buf->a_stride, 1, 351793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->mb_w, out_width, io->mb_h, out_height, 352793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler work + work_size + 2 * uv_work_size); 353793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit_alpha = EmitRescaledAlphaYUV; 354793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 355793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 1; 356793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 357793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 358793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//------------------------------------------------------------------------------ 359793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// RGBA rescaling 360793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 361793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int ExportRGB(WebPDecParams* const p, int y_pos) { 362793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPYUV444Converter convert = 363793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPYUV444Converters[p->output->colorspace]; 364793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPRGBABuffer* const buf = &p->output->u.RGBA; 365793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride; 366793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int num_lines_out = 0; 367793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // For RGB rescaling, because of the YUV420, current scan position 368793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // U/V can be +1/-1 line from the Y one. Hence the double test. 369793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler while (WebPRescalerHasPendingOutput(&p->scaler_y) && 370793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerHasPendingOutput(&p->scaler_u)) { 371793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler assert(p->last_y + y_pos + num_lines_out < p->output->height); 372793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler assert(p->scaler_u.y_accum == p->scaler_v.y_accum); 373793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerExportRow(&p->scaler_y); 374793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerExportRow(&p->scaler_u); 375793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerExportRow(&p->scaler_v); 376793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst, 377793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst, p->scaler_y.dst_width); 378793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst += buf->stride; 379793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler ++num_lines_out; 380793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 381793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return num_lines_out; 382793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 383793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 384793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) { 385793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_h = io->mb_h; 386793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_mb_h = (mb_h + 1) >> 1; 387793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int j = 0, uv_j = 0; 388793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int num_lines_out = 0; 389793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler while (j < mb_h) { 390793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int y_lines_in = 391793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerImport(&p->scaler_y, mb_h - j, 392793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->y + j * io->y_stride, io->y_stride); 393793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int u_lines_in = 394793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j, 395793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->u + uv_j * io->uv_stride, io->uv_stride); 396793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int v_lines_in = 397793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j, 398793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->v + uv_j * io->uv_stride, io->uv_stride); 399793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler (void)v_lines_in; // remove a gcc warning 400793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler assert(u_lines_in == v_lines_in); 401793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler j += y_lines_in; 402793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uv_j += u_lines_in; 403793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler num_lines_out += ExportRGB(p, num_lines_out); 404793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 405793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return num_lines_out; 406793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 407793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 408793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int ExportAlpha(WebPDecParams* const p, int y_pos) { 409793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPRGBABuffer* const buf = &p->output->u.RGBA; 410793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride; 411793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WEBP_CSP_MODE colorspace = p->output->colorspace; 412793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int alpha_first = 413793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler (colorspace == MODE_ARGB || colorspace == MODE_Argb); 414793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* dst = base_rgba + (alpha_first ? 0 : 3); 415793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int num_lines_out = 0; 416793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); 417793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint32_t alpha_mask = 0xff; 418793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int width = p->scaler_a.dst_width; 419793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 420793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler while (WebPRescalerHasPendingOutput(&p->scaler_a)) { 421793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int i; 422793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler assert(p->last_y + y_pos + num_lines_out < p->output->height); 423793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerExportRow(&p->scaler_a); 424793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (i = 0; i < width; ++i) { 425793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint32_t alpha_value = p->scaler_a.dst[i]; 426793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst[4 * i] = alpha_value; 427793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler alpha_mask &= alpha_value; 428793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 429793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler dst += buf->stride; 430793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler ++num_lines_out; 431793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 432793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (is_premult_alpha && alpha_mask != 0xff) { 433793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPApplyAlphaMultiply(base_rgba, alpha_first, 434793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler width, num_lines_out, buf->stride); 435793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 436793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return num_lines_out; 437793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 438793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 439793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) { 440793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WebPRGBABuffer* const buf = &p->output->u.RGBA; 441793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride; 442793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* alpha_dst = base_rgba + 1; 443793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int num_lines_out = 0; 444793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WEBP_CSP_MODE colorspace = p->output->colorspace; 445793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int width = p->scaler_a.dst_width; 446793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); 447793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint32_t alpha_mask = 0x0f; 448793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 449793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler while (WebPRescalerHasPendingOutput(&p->scaler_a)) { 450793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int i; 451793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler assert(p->last_y + y_pos + num_lines_out < p->output->height); 452793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerExportRow(&p->scaler_a); 453793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (i = 0; i < width; ++i) { 454793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler // Fill in the alpha value (converted to 4 bits). 455793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uint32_t alpha_value = p->scaler_a.dst[i] >> 4; 456793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; 457793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler alpha_mask &= alpha_value; 458793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 459793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler alpha_dst += buf->stride; 460793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler ++num_lines_out; 461793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 462793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (is_premult_alpha && alpha_mask != 0x0f) { 463793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride); 464793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 465793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return num_lines_out; 466793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 467793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 468793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) { 469793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (io->a != NULL) { 470793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescaler* const scaler = &p->scaler_a; 471793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int j = 0; 472793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int pos = 0; 473793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler while (j < io->mb_h) { 474793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler j += WebPRescalerImport(scaler, io->mb_h - j, 475793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->a + j * io->width, io->width); 476793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler pos += p->emit_alpha_row(p, pos); 477793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 478793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 479793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 480793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 481793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 482793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) { 483793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int has_alpha = WebPIsAlphaMode(p->output->colorspace); 484793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int out_width = io->scaled_width; 485793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int out_height = io->scaled_height; 486793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_in_width = (io->mb_w + 1) >> 1; 487793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_in_height = (io->mb_h + 1) >> 1; 488793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const size_t work_size = 2 * out_width; // scratch memory for one rescaler 489793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int32_t* work; // rescalers work area 490793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion 491793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler size_t tmp_size1, tmp_size2; 492793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 493793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp_size1 = 3 * work_size; 494793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp_size2 = 3 * out_width; 495793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (has_alpha) { 496793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp_size1 += work_size; 497793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp_size2 += out_width; 498793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 499793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->memory = calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp)); 500793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (p->memory == NULL) { 501793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; // memory error 502793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 503793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler work = (int32_t*)p->memory; 504793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp = (uint8_t*)(work + tmp_size1); 505793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, 506793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp + 0 * out_width, out_width, out_height, 0, 1, 507793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->mb_w, out_width, io->mb_h, out_height, 508793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler work + 0 * work_size); 509793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, 510793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp + 1 * out_width, out_width, out_height, 0, 1, 511793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->mb_w, 2 * out_width, io->mb_h, 2 * out_height, 512793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler work + 1 * work_size); 513793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, 514793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp + 2 * out_width, out_width, out_height, 0, 1, 515793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->mb_w, 2 * out_width, io->mb_h, 2 * out_height, 516793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler work + 2 * work_size); 517793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit = EmitRescaledRGB; 518793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 519793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (has_alpha) { 520793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, 521793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp + 3 * out_width, out_width, out_height, 0, 1, 522793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->mb_w, out_width, io->mb_h, out_height, 523793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler work + 3 * work_size); 524793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit_alpha = EmitRescaledAlphaRGB; 525793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (p->output->colorspace == MODE_RGBA_4444 || 526793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->output->colorspace == MODE_rgbA_4444) { 527793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit_alpha_row = ExportAlphaRGBA4444; 528793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } else { 529793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit_alpha_row = ExportAlpha; 530793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 531793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 532793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 1; 533793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 534793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 535793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//------------------------------------------------------------------------------ 536793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Default custom functions 537793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 538793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int CustomSetup(VP8Io* io) { 539793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPDecParams* const p = (WebPDecParams*)io->opaque; 540793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const WEBP_CSP_MODE colorspace = p->output->colorspace; 541793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int is_rgb = WebPIsRGBMode(colorspace); 542793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int is_alpha = WebPIsAlphaMode(colorspace); 543793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 544793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->memory = NULL; 545793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit = NULL; 546793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit_alpha = NULL; 547793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit_alpha_row = NULL; 548793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) { 549793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 550793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 551793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 552793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (io->use_scaling) { 553793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p); 554793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (!ok) { 555793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; // memory error 556793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 557793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } else { 558793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (is_rgb) { 559793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit = EmitSampledRGB; // default 560793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef FANCY_UPSAMPLING 561793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (io->fancy_upsampling) { 562793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int uv_width = (io->mb_w + 1) >> 1; 563793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->memory = malloc(io->mb_w + 2 * uv_width); 564793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (p->memory == NULL) { 565793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; // memory error. 566793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 567793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->tmp_y = (uint8_t*)p->memory; 568793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->tmp_u = p->tmp_y + io->mb_w; 569793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->tmp_v = p->tmp_u + uv_width; 570793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit = EmitFancyRGB; 571793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPInitUpsamplers(); 572793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 573793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif 574793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } else { 575793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit = EmitYUV; 576793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 577793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (is_alpha) { // need transparency output 578793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (WebPIsPremultipliedMode(colorspace)) WebPInitPremultiply(); 579793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit_alpha = 580793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler (colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ? 581793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler EmitAlphaRGBA4444 582793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler : is_rgb ? EmitAlphaRGB 583793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler : EmitAlphaYUV; 584793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 585793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 586793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 587793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (is_rgb) { 588793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler VP8YUVInit(); 589793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 590793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 1; 591793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 592793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 593793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//------------------------------------------------------------------------------ 594793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 595793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int CustomPut(const VP8Io* io) { 596793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPDecParams* const p = (WebPDecParams*)io->opaque; 597793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_w = io->mb_w; 598793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const int mb_h = io->mb_h; 599793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int num_lines_out; 600793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler assert(!(io->mb_y & 1)); 601793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 602793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (mb_w <= 0 || mb_h <= 0) { 603793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 604793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 605793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler num_lines_out = p->emit(io, p); 606793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (p->emit_alpha) { 607793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->emit_alpha(io, p); 608793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 609793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->last_y += num_lines_out; 610793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 1; 611793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 612793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 613793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//------------------------------------------------------------------------------ 614793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 615793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic void CustomTeardown(const VP8Io* io) { 616793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler WebPDecParams* const p = (WebPDecParams*)io->opaque; 617793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler free(p->memory); 618793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler p->memory = NULL; 619793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 620793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 621793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//------------------------------------------------------------------------------ 622793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Main entry point 623793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 624793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslervoid WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) { 625793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->put = CustomPut; 626793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->setup = CustomSetup; 627793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->teardown = CustomTeardown; 628793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler io->opaque = params; 629793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 630793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 631793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//------------------------------------------------------------------------------ 632793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 633793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#if defined(__cplusplus) || defined(c_plusplus) 634793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} // extern "C" 635793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif 636