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