VP8StatusCode WebPAllocateDecBuffer(int w, int h, const WebPDecoderOptions* const options, WebPDecBuffer* const out) { VP8StatusCode status; if (out == NULL || w <= 0 || h <= 0) { return VP8_STATUS_INVALID_PARAM; } if (options != NULL) { // First, apply options if there is any. if (options->use_cropping) { const int cw = options->crop_width; const int ch = options->crop_height; const int x = options->crop_left & ~1; const int y = options->crop_top & ~1; if (x < 0 || y < 0 || cw <= 0 || ch <= 0 || x + cw > w || y + ch > h) { return VP8_STATUS_INVALID_PARAM; // out of frame boundary. } w = cw; h = ch; } if (options->use_scaling) { int scaled_width = options->scaled_width; int scaled_height = options->scaled_height; if (!WebPRescalerGetScaledDimensions( w, h, &scaled_width, &scaled_height)) { return VP8_STATUS_INVALID_PARAM; } w = scaled_width; h = scaled_height; } } out->width = w; out->height = h; // Then, allocate buffer for real. status = AllocateBuffer(out); if (status != VP8_STATUS_OK) return status; // Use the stride trick if vertical flip is needed. if (options != NULL && options->flip) { status = WebPFlipBuffer(out); } return status; }
// Main flow static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size, WebPDecParams* const params) { VP8StatusCode status; VP8Io io; WebPHeaderStructure headers; headers.data = data; headers.data_size = data_size; headers.have_all_data = 1; status = WebPParseHeaders(&headers); // Process Pre-VP8 chunks. if (status != VP8_STATUS_OK) { return status; } assert(params != NULL); VP8InitIo(&io); io.data = headers.data + headers.offset; io.data_size = headers.data_size - headers.offset; WebPInitCustomIo(params, &io); // Plug the I/O functions. if (!headers.is_lossless) { VP8Decoder* const dec = VP8New(); if (dec == NULL) { return VP8_STATUS_OUT_OF_MEMORY; } dec->alpha_data_ = headers.alpha_data; dec->alpha_data_size_ = headers.alpha_data_size; // Decode bitstream header, update io->width/io->height. if (!VP8GetHeaders(dec, &io)) { status = dec->status_; // An error occurred. Grab error status. } else { // Allocate/check output buffers. status = WebPAllocateDecBuffer(io.width, io.height, params->options, params->output); if (status == VP8_STATUS_OK) { // Decode // This change must be done before calling VP8Decode() dec->mt_method_ = VP8GetThreadMethod(params->options, &headers, io.width, io.height); VP8InitDithering(params->options, dec); if (!VP8Decode(dec, &io)) { status = dec->status_; } } } VP8Delete(dec); } else { VP8LDecoder* const dec = VP8LNew(); if (dec == NULL) { return VP8_STATUS_OUT_OF_MEMORY; } if (!VP8LDecodeHeader(dec, &io)) { status = dec->status_; // An error occurred. Grab error status. } else { // Allocate/check output buffers. status = WebPAllocateDecBuffer(io.width, io.height, params->options, params->output); if (status == VP8_STATUS_OK) { // Decode if (!VP8LDecodeImage(dec)) { status = dec->status_; } } } VP8LDelete(dec); } if (status != VP8_STATUS_OK) { WebPFreeDecBuffer(params->output); } else { if (params->options != NULL && params->options->flip) { // This restores the original stride values if options->flip was used // during the call to WebPAllocateDecBuffer above. status = WebPFlipBuffer(params->output); } } return status; }