Path: blob/master/thirdparty/libwebp/src/dec/io_dec.c
21212 views
// Copyright 2011 Google Inc. All Rights Reserved.1//2// Use of this source code is governed by a BSD-style license3// that can be found in the COPYING file in the root of the source4// tree. An additional intellectual property rights grant can be found5// in the file PATENTS. All contributing project authors may6// be found in the AUTHORS file in the root of the source tree.7// -----------------------------------------------------------------------------8//9// functions for sample output.10//11// Author: Skal ([email protected])1213#include <assert.h>14#include <stddef.h>15#include <stdlib.h>16#include <string.h>1718#include "src/dec/vp8_dec.h"19#include "src/webp/types.h"20#include "src/dec/vp8i_dec.h"21#include "src/dec/webpi_dec.h"22#include "src/dsp/cpu.h"23#include "src/dsp/dsp.h"24#include "src/dsp/yuv.h"25#include "src/utils/rescaler_utils.h"26#include "src/utils/utils.h"27#include "src/webp/decode.h"2829//------------------------------------------------------------------------------30// Main YUV<->RGB conversion functions3132static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {33WebPDecBuffer* output = p->output;34const WebPYUVABuffer* const buf = &output->u.YUVA;35uint8_t* const y_dst = buf->y + (ptrdiff_t)io->mb_y * buf->y_stride;36uint8_t* const u_dst = buf->u + (ptrdiff_t)(io->mb_y >> 1) * buf->u_stride;37uint8_t* const v_dst = buf->v + (ptrdiff_t)(io->mb_y >> 1) * buf->v_stride;38const int mb_w = io->mb_w;39const int mb_h = io->mb_h;40const int uv_w = (mb_w + 1) / 2;41const int uv_h = (mb_h + 1) / 2;42WebPCopyPlane(io->y, io->y_stride, y_dst, buf->y_stride, mb_w, mb_h);43WebPCopyPlane(io->u, io->uv_stride, u_dst, buf->u_stride, uv_w, uv_h);44WebPCopyPlane(io->v, io->uv_stride, v_dst, buf->v_stride, uv_w, uv_h);45return io->mb_h;46}4748// Point-sampling U/V sampler.49static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {50WebPDecBuffer* const output = p->output;51WebPRGBABuffer* const buf = &output->u.RGBA;52uint8_t* const dst = buf->rgba + (ptrdiff_t)io->mb_y * buf->stride;53WebPSamplerProcessPlane(io->y, io->y_stride,54io->u, io->v, io->uv_stride,55dst, buf->stride, io->mb_w, io->mb_h,56WebPSamplers[output->colorspace]);57return io->mb_h;58}5960//------------------------------------------------------------------------------61// Fancy upsampling6263#ifdef FANCY_UPSAMPLING64static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {65int num_lines_out = io->mb_h; // a priori guess66const WebPRGBABuffer* const buf = &p->output->u.RGBA;67uint8_t* dst = buf->rgba + (ptrdiff_t)io->mb_y * buf->stride;68WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace];69const uint8_t* cur_y = io->y;70const uint8_t* cur_u = io->u;71const uint8_t* cur_v = io->v;72const uint8_t* top_u = p->tmp_u;73const uint8_t* top_v = p->tmp_v;74int y = io->mb_y;75const int y_end = io->mb_y + io->mb_h;76const int mb_w = io->mb_w;77const int uv_w = (mb_w + 1) / 2;7879if (y == 0) {80// First line is special cased. We mirror the u/v samples at boundary.81upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, mb_w);82} else {83// We can finish the left-over line from previous call.84upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v,85dst - buf->stride, dst, mb_w);86++num_lines_out;87}88// Loop over each output pairs of row.89for (; y + 2 < y_end; y += 2) {90top_u = cur_u;91top_v = cur_v;92cur_u += io->uv_stride;93cur_v += io->uv_stride;94dst += 2 * buf->stride;95cur_y += 2 * io->y_stride;96upsample(cur_y - io->y_stride, cur_y,97top_u, top_v, cur_u, cur_v,98dst - buf->stride, dst, mb_w);99}100// move to last row101cur_y += io->y_stride;102if (io->crop_top + y_end < io->crop_bottom) {103// Save the unfinished samples for next call (as we're not done yet).104memcpy(p->tmp_y, cur_y, mb_w * sizeof(*p->tmp_y));105memcpy(p->tmp_u, cur_u, uv_w * sizeof(*p->tmp_u));106memcpy(p->tmp_v, cur_v, uv_w * sizeof(*p->tmp_v));107// The fancy upsampler leaves a row unfinished behind108// (except for the very last row)109num_lines_out--;110} else {111// Process the very last row of even-sized picture112if (!(y_end & 1)) {113upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v,114dst + buf->stride, NULL, mb_w);115}116}117return num_lines_out;118}119120#endif /* FANCY_UPSAMPLING */121122//------------------------------------------------------------------------------123124static void FillAlphaPlane(uint8_t* dst, int w, int h, int stride) {125int j;126for (j = 0; j < h; ++j) {127memset(dst, 0xff, w * sizeof(*dst));128dst += stride;129}130}131132static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p,133int expected_num_lines_out) {134const uint8_t* alpha = io->a;135const WebPYUVABuffer* const buf = &p->output->u.YUVA;136const int mb_w = io->mb_w;137const int mb_h = io->mb_h;138uint8_t* dst = buf->a + (ptrdiff_t)io->mb_y * buf->a_stride;139int j;140(void)expected_num_lines_out;141assert(expected_num_lines_out == mb_h);142if (alpha != NULL) {143for (j = 0; j < mb_h; ++j) {144memcpy(dst, alpha, mb_w * sizeof(*dst));145alpha += io->width;146dst += buf->a_stride;147}148} else if (buf->a != NULL) {149// the user requested alpha, but there is none, set it to opaque.150FillAlphaPlane(dst, mb_w, mb_h, buf->a_stride);151}152return 0;153}154155static int GetAlphaSourceRow(const VP8Io* const io,156const uint8_t** alpha, int* const num_rows) {157int start_y = io->mb_y;158*num_rows = io->mb_h;159160// Compensate for the 1-line delay of the fancy upscaler.161// This is similar to EmitFancyRGB().162if (io->fancy_upsampling) {163if (start_y == 0) {164// We don't process the last row yet. It'll be done during the next call.165--*num_rows;166} else {167--start_y;168// Fortunately, *alpha data is persistent, so we can go back169// one row and finish alpha blending, now that the fancy upscaler170// completed the YUV->RGB interpolation.171*alpha -= io->width;172}173if (io->crop_top + io->mb_y + io->mb_h == io->crop_bottom) {174// If it's the very last call, we process all the remaining rows!175*num_rows = io->crop_bottom - io->crop_top - start_y;176}177}178return start_y;179}180181static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p,182int expected_num_lines_out) {183const uint8_t* alpha = io->a;184if (alpha != NULL) {185const int mb_w = io->mb_w;186const WEBP_CSP_MODE colorspace = p->output->colorspace;187const int alpha_first =188(colorspace == MODE_ARGB || colorspace == MODE_Argb);189const WebPRGBABuffer* const buf = &p->output->u.RGBA;190int num_rows;191const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);192uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)start_y * buf->stride;193uint8_t* const dst = base_rgba + (alpha_first ? 0 : 3);194const int has_alpha = WebPDispatchAlpha(alpha, io->width, mb_w,195num_rows, dst, buf->stride);196(void)expected_num_lines_out;197assert(expected_num_lines_out == num_rows);198// has_alpha is true if there's non-trivial alpha to premultiply with.199if (has_alpha && WebPIsPremultipliedMode(colorspace)) {200WebPApplyAlphaMultiply(base_rgba, alpha_first,201mb_w, num_rows, buf->stride);202}203}204return 0;205}206207static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,208int expected_num_lines_out) {209const uint8_t* alpha = io->a;210if (alpha != NULL) {211const int mb_w = io->mb_w;212const WEBP_CSP_MODE colorspace = p->output->colorspace;213const WebPRGBABuffer* const buf = &p->output->u.RGBA;214int num_rows;215const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);216uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)start_y * buf->stride;217#if (WEBP_SWAP_16BIT_CSP == 1)218uint8_t* alpha_dst = base_rgba;219#else220uint8_t* alpha_dst = base_rgba + 1;221#endif222uint32_t alpha_mask = 0x0f;223int i, j;224for (j = 0; j < num_rows; ++j) {225for (i = 0; i < mb_w; ++i) {226// Fill in the alpha value (converted to 4 bits).227const uint32_t alpha_value = alpha[i] >> 4;228alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;229alpha_mask &= alpha_value;230}231alpha += io->width;232alpha_dst += buf->stride;233}234(void)expected_num_lines_out;235assert(expected_num_lines_out == num_rows);236if (alpha_mask != 0x0f && WebPIsPremultipliedMode(colorspace)) {237WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride);238}239}240return 0;241}242243//------------------------------------------------------------------------------244// YUV rescaling (no final RGB conversion needed)245246#if !defined(WEBP_REDUCE_SIZE)247static int Rescale(const uint8_t* src, int src_stride,248int new_lines, WebPRescaler* const wrk) {249int num_lines_out = 0;250while (new_lines > 0) { // import new contributions of source rows.251const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride);252src += lines_in * src_stride;253new_lines -= lines_in;254num_lines_out += WebPRescalerExport(wrk); // emit output row(s)255}256return num_lines_out;257}258259static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {260const int mb_h = io->mb_h;261const int uv_mb_h = (mb_h + 1) >> 1;262WebPRescaler* const scaler = p->scaler_y;263int num_lines_out = 0;264if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) {265// Before rescaling, we premultiply the luma directly into the io->y266// internal buffer. This is OK since these samples are not used for267// intra-prediction (the top samples are saved in cache_y/u/v).268// But we need to cast the const away, though.269WebPMultRows((uint8_t*)io->y, io->y_stride,270io->a, io->width, io->mb_w, mb_h, 0);271}272num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler);273Rescale(io->u, io->uv_stride, uv_mb_h, p->scaler_u);274Rescale(io->v, io->uv_stride, uv_mb_h, p->scaler_v);275return num_lines_out;276}277278static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p,279int expected_num_lines_out) {280const WebPYUVABuffer* const buf = &p->output->u.YUVA;281uint8_t* const dst_a = buf->a + (ptrdiff_t)p->last_y * buf->a_stride;282if (io->a != NULL) {283uint8_t* const dst_y = buf->y + (ptrdiff_t)p->last_y * buf->y_stride;284const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a);285assert(expected_num_lines_out == num_lines_out);286if (num_lines_out > 0) { // unmultiply the Y287WebPMultRows(dst_y, buf->y_stride, dst_a, buf->a_stride,288p->scaler_a->dst_width, num_lines_out, 1);289}290} else if (buf->a != NULL) {291// the user requested alpha, but there is none, set it to opaque.292assert(p->last_y + expected_num_lines_out <= io->scaled_height);293FillAlphaPlane(dst_a, io->scaled_width, expected_num_lines_out,294buf->a_stride);295}296return 0;297}298299static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {300const int has_alpha = WebPIsAlphaMode(p->output->colorspace);301const WebPYUVABuffer* const buf = &p->output->u.YUVA;302const int out_width = io->scaled_width;303const int out_height = io->scaled_height;304const int uv_out_width = (out_width + 1) >> 1;305const int uv_out_height = (out_height + 1) >> 1;306const int uv_in_width = (io->mb_w + 1) >> 1;307const int uv_in_height = (io->mb_h + 1) >> 1;308// scratch memory for luma rescaler309const size_t work_size = 2 * (size_t)out_width;310const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones311uint64_t total_size;312size_t rescaler_size;313rescaler_t* work;314WebPRescaler* scalers;315const int num_rescalers = has_alpha ? 4 : 3;316317total_size = ((uint64_t)work_size + 2 * uv_work_size) * sizeof(*work);318if (has_alpha) {319total_size += (uint64_t)work_size * sizeof(*work);320}321rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;322total_size += rescaler_size;323if (!CheckSizeOverflow(total_size)) {324return 0;325}326327p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);328if (p->memory == NULL) {329return 0; // memory error330}331work = (rescaler_t*)p->memory;332333scalers = (WebPRescaler*)WEBP_ALIGN(334(const uint8_t*)work + total_size - rescaler_size);335p->scaler_y = &scalers[0];336p->scaler_u = &scalers[1];337p->scaler_v = &scalers[2];338p->scaler_a = has_alpha ? &scalers[3] : NULL;339340if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,341buf->y, out_width, out_height, buf->y_stride, 1,342work) ||343!WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,344buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,345work + work_size) ||346!WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,347buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,348work + work_size + uv_work_size)) {349return 0;350}351p->emit = EmitRescaledYUV;352353if (has_alpha) {354if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,355buf->a, out_width, out_height, buf->a_stride, 1,356work + work_size + 2 * uv_work_size)) {357return 0;358}359p->emit_alpha = EmitRescaledAlphaYUV;360WebPInitAlphaProcessing();361}362return 1;363}364365//------------------------------------------------------------------------------366// RGBA rescaling367368static int ExportRGB(WebPDecParams* const p, int y_pos) {369const WebPYUV444Converter convert =370WebPYUV444Converters[p->output->colorspace];371const WebPRGBABuffer* const buf = &p->output->u.RGBA;372uint8_t* dst = buf->rgba + (ptrdiff_t)y_pos * buf->stride;373int num_lines_out = 0;374// For RGB rescaling, because of the YUV420, current scan position375// U/V can be +1/-1 line from the Y one. Hence the double test.376while (WebPRescalerHasPendingOutput(p->scaler_y) &&377WebPRescalerHasPendingOutput(p->scaler_u)) {378assert(y_pos + num_lines_out < p->output->height);379assert(p->scaler_u->y_accum == p->scaler_v->y_accum);380WebPRescalerExportRow(p->scaler_y);381WebPRescalerExportRow(p->scaler_u);382WebPRescalerExportRow(p->scaler_v);383convert(p->scaler_y->dst, p->scaler_u->dst, p->scaler_v->dst,384dst, p->scaler_y->dst_width);385dst += buf->stride;386++num_lines_out;387}388return num_lines_out;389}390391static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {392const int mb_h = io->mb_h;393const int uv_mb_h = (mb_h + 1) >> 1;394int j = 0, uv_j = 0;395int num_lines_out = 0;396while (j < mb_h) {397const int y_lines_in =398WebPRescalerImport(p->scaler_y, mb_h - j,399io->y + (ptrdiff_t)j * io->y_stride, io->y_stride);400j += y_lines_in;401if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) {402const int u_lines_in = WebPRescalerImport(403p->scaler_u, uv_mb_h - uv_j, io->u + (ptrdiff_t)uv_j * io->uv_stride,404io->uv_stride);405const int v_lines_in = WebPRescalerImport(406p->scaler_v, uv_mb_h - uv_j, io->v + (ptrdiff_t)uv_j * io->uv_stride,407io->uv_stride);408(void)v_lines_in; // remove a gcc warning409assert(u_lines_in == v_lines_in);410uv_j += u_lines_in;411}412num_lines_out += ExportRGB(p, p->last_y + num_lines_out);413}414return num_lines_out;415}416417static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {418const WebPRGBABuffer* const buf = &p->output->u.RGBA;419uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)y_pos * buf->stride;420const WEBP_CSP_MODE colorspace = p->output->colorspace;421const int alpha_first =422(colorspace == MODE_ARGB || colorspace == MODE_Argb);423uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);424int num_lines_out = 0;425const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);426uint32_t non_opaque = 0;427const int width = p->scaler_a->dst_width;428429while (WebPRescalerHasPendingOutput(p->scaler_a) &&430num_lines_out < max_lines_out) {431assert(y_pos + num_lines_out < p->output->height);432WebPRescalerExportRow(p->scaler_a);433non_opaque |= WebPDispatchAlpha(p->scaler_a->dst, 0, width, 1, dst, 0);434dst += buf->stride;435++num_lines_out;436}437if (is_premult_alpha && non_opaque) {438WebPApplyAlphaMultiply(base_rgba, alpha_first,439width, num_lines_out, buf->stride);440}441return num_lines_out;442}443444static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,445int max_lines_out) {446const WebPRGBABuffer* const buf = &p->output->u.RGBA;447uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)y_pos * buf->stride;448#if (WEBP_SWAP_16BIT_CSP == 1)449uint8_t* alpha_dst = base_rgba;450#else451uint8_t* alpha_dst = base_rgba + 1;452#endif453int num_lines_out = 0;454const WEBP_CSP_MODE colorspace = p->output->colorspace;455const int width = p->scaler_a->dst_width;456const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);457uint32_t alpha_mask = 0x0f;458459while (WebPRescalerHasPendingOutput(p->scaler_a) &&460num_lines_out < max_lines_out) {461int i;462assert(y_pos + num_lines_out < p->output->height);463WebPRescalerExportRow(p->scaler_a);464for (i = 0; i < width; ++i) {465// Fill in the alpha value (converted to 4 bits).466const uint32_t alpha_value = p->scaler_a->dst[i] >> 4;467alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;468alpha_mask &= alpha_value;469}470alpha_dst += buf->stride;471++num_lines_out;472}473if (is_premult_alpha && alpha_mask != 0x0f) {474WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride);475}476return num_lines_out;477}478479static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p,480int expected_num_out_lines) {481if (io->a != NULL) {482WebPRescaler* const scaler = p->scaler_a;483int lines_left = expected_num_out_lines;484const int y_end = p->last_y + lines_left;485while (lines_left > 0) {486const int64_t row_offset = (ptrdiff_t)scaler->src_y - io->mb_y;487WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y,488io->a + row_offset * io->width, io->width);489lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left);490}491}492return 0;493}494495static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {496const int has_alpha = WebPIsAlphaMode(p->output->colorspace);497const int out_width = io->scaled_width;498const int out_height = io->scaled_height;499const int uv_in_width = (io->mb_w + 1) >> 1;500const int uv_in_height = (io->mb_h + 1) >> 1;501// scratch memory for one rescaler502const size_t work_size = 2 * (size_t)out_width;503rescaler_t* work; // rescalers work area504uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion505uint64_t tmp_size1, tmp_size2, total_size;506size_t rescaler_size;507WebPRescaler* scalers;508const int num_rescalers = has_alpha ? 4 : 3;509510tmp_size1 = (uint64_t)num_rescalers * work_size;511tmp_size2 = (uint64_t)num_rescalers * out_width;512total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);513rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;514total_size += rescaler_size;515if (!CheckSizeOverflow(total_size)) {516return 0;517}518519p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);520if (p->memory == NULL) {521return 0; // memory error522}523work = (rescaler_t*)p->memory;524tmp = (uint8_t*)(work + tmp_size1);525526scalers = (WebPRescaler*)WEBP_ALIGN(527(const uint8_t*)work + total_size - rescaler_size);528p->scaler_y = &scalers[0];529p->scaler_u = &scalers[1];530p->scaler_v = &scalers[2];531p->scaler_a = has_alpha ? &scalers[3] : NULL;532533if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,534tmp + 0 * out_width, out_width, out_height, 0, 1,535work + 0 * work_size) ||536!WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,537tmp + 1 * out_width, out_width, out_height, 0, 1,538work + 1 * work_size) ||539!WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,540tmp + 2 * out_width, out_width, out_height, 0, 1,541work + 2 * work_size)) {542return 0;543}544p->emit = EmitRescaledRGB;545WebPInitYUV444Converters();546547if (has_alpha) {548if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,549tmp + 3 * out_width, out_width, out_height, 0, 1,550work + 3 * work_size)) {551return 0;552}553p->emit_alpha = EmitRescaledAlphaRGB;554if (p->output->colorspace == MODE_RGBA_4444 ||555p->output->colorspace == MODE_rgbA_4444) {556p->emit_alpha_row = ExportAlphaRGBA4444;557} else {558p->emit_alpha_row = ExportAlpha;559}560WebPInitAlphaProcessing();561}562return 1;563}564565#endif // WEBP_REDUCE_SIZE566567//------------------------------------------------------------------------------568// Default custom functions569570static int CustomSetup(VP8Io* io) {571WebPDecParams* const p = (WebPDecParams*)io->opaque;572const WEBP_CSP_MODE colorspace = p->output->colorspace;573const int is_rgb = WebPIsRGBMode(colorspace);574const int is_alpha = WebPIsAlphaMode(colorspace);575576p->memory = NULL;577p->emit = NULL;578p->emit_alpha = NULL;579p->emit_alpha_row = NULL;580if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) {581return 0;582}583if (is_alpha && WebPIsPremultipliedMode(colorspace)) {584WebPInitUpsamplers();585}586if (io->use_scaling) {587#if !defined(WEBP_REDUCE_SIZE)588const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);589if (!ok) {590return 0; // memory error591}592#else593return 0; // rescaling support not compiled594#endif595} else {596if (is_rgb) {597WebPInitSamplers();598p->emit = EmitSampledRGB; // default599if (io->fancy_upsampling) {600#ifdef FANCY_UPSAMPLING601const int uv_width = (io->mb_w + 1) >> 1;602p->memory = WebPSafeMalloc(1ULL, (size_t)(io->mb_w + 2 * uv_width));603if (p->memory == NULL) {604return 0; // memory error.605}606p->tmp_y = (uint8_t*)p->memory;607p->tmp_u = p->tmp_y + io->mb_w;608p->tmp_v = p->tmp_u + uv_width;609p->emit = EmitFancyRGB;610WebPInitUpsamplers();611#endif612}613} else {614p->emit = EmitYUV;615}616if (is_alpha) { // need transparency output617p->emit_alpha =618(colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ?619EmitAlphaRGBA4444620: is_rgb ? EmitAlphaRGB621: EmitAlphaYUV;622if (is_rgb) {623WebPInitAlphaProcessing();624}625}626}627628return 1;629}630631//------------------------------------------------------------------------------632633static int CustomPut(const VP8Io* io) {634WebPDecParams* const p = (WebPDecParams*)io->opaque;635const int mb_w = io->mb_w;636const int mb_h = io->mb_h;637int num_lines_out;638assert(!(io->mb_y & 1));639640if (mb_w <= 0 || mb_h <= 0) {641return 0;642}643num_lines_out = p->emit(io, p);644if (p->emit_alpha != NULL) {645p->emit_alpha(io, p, num_lines_out);646}647p->last_y += num_lines_out;648return 1;649}650651//------------------------------------------------------------------------------652653static void CustomTeardown(const VP8Io* io) {654WebPDecParams* const p = (WebPDecParams*)io->opaque;655WebPSafeFree(p->memory);656p->memory = NULL;657}658659//------------------------------------------------------------------------------660// Main entry point661662void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) {663io->put = CustomPut;664io->setup = CustomSetup;665io->teardown = CustomTeardown;666io->opaque = params;667}668669//------------------------------------------------------------------------------670671672