15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2011 Google Inc. All Rights Reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// that can be found in the COPYING file in the root of the source
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// tree. An additional intellectual property rights grant can be found
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// in the file PATENTS. All contributing project authors may
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// be found in the AUTHORS file in the root of the source tree.
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -----------------------------------------------------------------------------
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Everything about WebPDecBuffer
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Skal (pascal.massimino@gmail.com)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "./vp8i.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "./webpi.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../utils/utils.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WebPDecBuffer
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Number of bytes per pixel for the different color-spaces.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kModeBpp[MODE_LAST] = {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  3, 4, 3, 4, 4, 2, 2,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  4, 4, 4, 2,    // pre-multiplied modes
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  1, 1 };
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Convert to an integer to handle both the unsigned/signed enum cases
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// without the need for casting to remove type limit warnings.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int IsValidColorspace(int webp_csp_mode) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int ok = 1;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const WEBP_CSP_MODE mode = buffer->colorspace;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int width = buffer->width;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int height = buffer->height;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsValidColorspace(mode)) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = 0;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!WebPIsRGBMode(mode)) {   // YUV checks
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WebPYUVABuffer* const buf = &buffer->u.YUVA;
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const int y_stride = abs(buf->y_stride);
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const int u_stride = abs(buf->u_stride);
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const int v_stride = abs(buf->v_stride);
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const int a_stride = abs(buf->a_stride);
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const uint64_t y_size = (uint64_t)y_stride * height;
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const uint64_t u_size = (uint64_t)u_stride * ((height + 1) / 2);
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const uint64_t v_size = (uint64_t)v_stride * ((height + 1) / 2);
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const uint64_t a_size = (uint64_t)a_stride * height;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok &= (y_size <= buf->y_size);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok &= (u_size <= buf->u_size);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok &= (v_size <= buf->v_size);
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ok &= (y_stride >= width);
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ok &= (u_stride >= (width + 1) / 2);
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ok &= (v_stride >= (width + 1) / 2);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok &= (buf->y != NULL);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok &= (buf->u != NULL);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok &= (buf->v != NULL);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mode == MODE_YUVA) {
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ok &= (a_stride >= width);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ok &= (a_size <= buf->a_size);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ok &= (buf->a != NULL);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {    // RGB checks
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WebPRGBABuffer* const buf = &buffer->u.RGBA;
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const int stride = abs(buf->stride);
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const uint64_t size = (uint64_t)stride * height;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok &= (size <= buf->size);
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ok &= (stride >= width * kModeBpp[mode]);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok &= (buf->rgba != NULL);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int w = buffer->width;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int h = buffer->height;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const WEBP_CSP_MODE mode = buffer->colorspace;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (w <= 0 || h <= 0 || !IsValidColorspace(mode)) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return VP8_STATUS_INVALID_PARAM;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!buffer->is_external_memory && buffer->private_memory == NULL) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8_t* output;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int uv_stride = 0, a_stride = 0;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint64_t uv_size = 0, a_size = 0, total_size;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We need memory and it hasn't been allocated yet.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // => initialize output buffer, now that dimensions are known.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int stride = w * kModeBpp[mode];
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const uint64_t size = (uint64_t)stride * h;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!WebPIsRGBMode(mode)) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uv_stride = (w + 1) / 2;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uv_size = (uint64_t)uv_stride * ((h + 1) / 2);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (mode == MODE_YUVA) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        a_stride = w;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        a_size = (uint64_t)a_stride * h;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    total_size = size + 2 * uv_size + a_size;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Security/sanity checks
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output));
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (output == NULL) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_OUT_OF_MEMORY;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buffer->private_memory = output;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!WebPIsRGBMode(mode)) {   // YUVA initialization
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WebPYUVABuffer* const buf = &buffer->u.YUVA;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->y = output;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->y_stride = stride;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->y_size = (size_t)size;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->u = output + size;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->u_stride = uv_stride;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->u_size = (size_t)uv_size;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->v = output + size + uv_size;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->v_stride = uv_stride;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->v_size = (size_t)uv_size;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (mode == MODE_YUVA) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        buf->a = output + size + 2 * uv_size;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->a_size = (size_t)a_size;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->a_stride = a_stride;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {  // RGBA initialization
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WebPRGBABuffer* const buf = &buffer->u.RGBA;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->rgba = output;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->stride = stride;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf->size = (size_t)size;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CheckDecBuffer(buffer);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (buffer == NULL) {
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return VP8_STATUS_INVALID_PARAM;
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (WebPIsRGBMode(buffer->colorspace)) {
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    WebPRGBABuffer* const buf = &buffer->u.RGBA;
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    buf->rgba += (buffer->height - 1) * buf->stride;
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    buf->stride = -buf->stride;
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else {
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    WebPYUVABuffer* const buf = &buffer->u.YUVA;
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const int H = buffer->height;
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    buf->y += (H - 1) * buf->y_stride;
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    buf->y_stride = -buf->y_stride;
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    buf->u += ((H - 1) >> 1) * buf->u_stride;
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    buf->u_stride = -buf->u_stride;
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    buf->v += ((H - 1) >> 1) * buf->v_stride;
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    buf->v_stride = -buf->v_stride;
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (buf->a != NULL) {
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      buf->a += (H - 1) * buf->a_stride;
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      buf->a_stride = -buf->a_stride;
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return VP8_STATUS_OK;
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VP8StatusCode WebPAllocateDecBuffer(int w, int h,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const WebPDecoderOptions* const options,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    WebPDecBuffer* const out) {
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VP8StatusCode status;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (out == NULL || w <= 0 || h <= 0) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return VP8_STATUS_INVALID_PARAM;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (options != NULL) {    // First, apply options if there is any.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (options->use_cropping) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const int cw = options->crop_width;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const int ch = options->crop_height;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const int x = options->crop_left & ~1;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const int y = options->crop_top & ~1;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (x < 0 || y < 0 || cw <= 0 || ch <= 0 || x + cw > w || y + ch > h) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return VP8_STATUS_INVALID_PARAM;   // out of frame boundary.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      w = cw;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      h = ch;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (options->use_scaling) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (options->scaled_width <= 0 || options->scaled_height <= 0) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return VP8_STATUS_INVALID_PARAM;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      w = options->scaled_width;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      h = options->scaled_height;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->width = w;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->height = h;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Then, allocate buffer for real.
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  status = AllocateBuffer(out);
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (status != VP8_STATUS_OK) return status;
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if WEBP_DECODER_ABI_VERSION > 0x0203
1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Use the stride trick if vertical flip is needed.
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (options != NULL && options->flip) {
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    status = WebPFlipBuffer(out);
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return status;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// constructors / destructors
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;  // version mismatch
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (buffer == NULL) return 0;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(buffer, 0, sizeof(*buffer));
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 1;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebPFreeDecBuffer(WebPDecBuffer* buffer) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (buffer != NULL) {
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!buffer->is_external_memory) {
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      WebPSafeFree(buffer->private_memory);
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buffer->private_memory = NULL;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebPCopyDecBuffer(const WebPDecBuffer* const src,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       WebPDecBuffer* const dst) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (src != NULL && dst != NULL) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *dst = *src;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (src->private_memory != NULL) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dst->is_external_memory = 1;   // dst buffer doesn't own the memory.
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dst->private_memory = NULL;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copy and transfer ownership from src to dst (beware of parameter order!)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (src != NULL && dst != NULL) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *dst = *src;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (src->private_memory != NULL) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      src->is_external_memory = 1;   // src relinquishes ownership
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      src->private_memory = NULL;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
252