15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2010 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)// Main decoding functions for WEBP images.
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 "./vp8li.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "./webpi.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "../webp/mux_types.h"  // ALPHA_FLAG
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RIFF layout is:
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   Offset  tag
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   0...3   "RIFF" 4-byte tag
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   4...7   size of image data (including metadata) starting at offset 8
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   8...11  "WEBP"   our form-type signature
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The RIFF container (12 bytes) is followed by appropriate chunks:
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   12..15  "VP8 ": 4-bytes tags, signaling the use of VP8 video format
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   16..19  size of the raw VP8 image data, starting at offset 20
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   20....  the VP8 bytes
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Or,
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   12..15  "VP8L": 4-bytes tags, signaling the use of VP8L lossless format
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   16..19  size of the raw VP8L image data, starting at offset 20
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   20....  the VP8L bytes
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Or,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   12..15  "VP8X": 4-bytes tags, describing the extended-VP8 chunk.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   16..19  size of the VP8X chunk starting at offset 20.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   20..23  VP8X flags bit-map corresponding to the chunk-types present.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   24..26  Width of the Canvas Image.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   27..29  Height of the Canvas Image.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// There can be extra chunks after the "VP8X" chunk (ICCP, FRGM, ANMF, VP8,
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// VP8L, XMP, EXIF  ...)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All sizes are in little-endian order.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: chunk data size must be padded to multiple of 2 when written.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static WEBP_INLINE uint32_t get_le24(const uint8_t* const data) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return data[0] | (data[1] << 8) | (data[2] << 16);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (uint32_t)get_le24(data) | (data[3] << 24);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Validates the RIFF container (if detected) and skips over it.
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// If a RIFF container is detected, returns:
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//     VP8_STATUS_BITSTREAM_ERROR for invalid header,
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//     VP8_STATUS_NOT_ENOUGH_DATA for truncated data if have_all_data is true,
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// and VP8_STATUS_OK otherwise.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In case there are not enough bytes (partial RIFF container), return 0 for
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// *riff_size. Else return the RIFF size extracted from the header.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static VP8StatusCode ParseRIFF(const uint8_t** const data,
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               size_t* const data_size, int have_all_data,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               size_t* const riff_size) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(data != NULL);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(data_size != NULL);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(riff_size != NULL);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *riff_size = 0;  // Default: no RIFF present.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*data_size >= RIFF_HEADER_SIZE && !memcmp(*data, "RIFF", TAG_SIZE)) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (memcmp(*data + 8, "WEBP", TAG_SIZE)) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_BITSTREAM_ERROR;  // Wrong image file signature.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const uint32_t size = get_le32(*data + TAG_SIZE);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Check that we have at least one chunk (i.e "WEBP" + "VP8?nnnn").
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (size < TAG_SIZE + CHUNK_HEADER_SIZE) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return VP8_STATUS_BITSTREAM_ERROR;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (size > MAX_CHUNK_PAYLOAD) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return VP8_STATUS_BITSTREAM_ERROR;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (have_all_data && (size > *data_size - CHUNK_HEADER_SIZE)) {
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return VP8_STATUS_NOT_ENOUGH_DATA;  // Truncated bitstream.
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We have a RIFF container. Skip it.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *riff_size = size;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *data += RIFF_HEADER_SIZE;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *data_size -= RIFF_HEADER_SIZE;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return VP8_STATUS_OK;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Validates the VP8X header and skips over it.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns VP8_STATUS_BITSTREAM_ERROR for invalid VP8X header,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         VP8_STATUS_OK otherwise.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If a VP8X chunk is found, found_vp8x is set to true and *width_ptr,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// *height_ptr and *flags_ptr are set to the corresponding values extracted
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from the VP8X chunk.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static VP8StatusCode ParseVP8X(const uint8_t** const data,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               size_t* const data_size,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int* const found_vp8x,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int* const width_ptr, int* const height_ptr,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               uint32_t* const flags_ptr) {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(data != NULL);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(data_size != NULL);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(found_vp8x != NULL);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *found_vp8x = 0;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*data_size < CHUNK_HEADER_SIZE) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return VP8_STATUS_NOT_ENOUGH_DATA;  // Insufficient data.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!memcmp(*data, "VP8X", TAG_SIZE)) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int width, height;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t flags;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const uint32_t chunk_size = get_le32(*data + TAG_SIZE);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (chunk_size != VP8X_CHUNK_SIZE) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_BITSTREAM_ERROR;  // Wrong chunk size.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Verify if enough data is available to validate the VP8X chunk.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (*data_size < vp8x_size) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_NOT_ENOUGH_DATA;  // Insufficient data.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    flags = get_le32(*data + 8);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    width = 1 + get_le24(*data + 12);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    height = 1 + get_le24(*data + 15);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (width * (uint64_t)height >= MAX_IMAGE_AREA) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_BITSTREAM_ERROR;  // image is too large
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (flags_ptr != NULL) *flags_ptr = flags;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (width_ptr != NULL) *width_ptr = width;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (height_ptr != NULL) *height_ptr = height;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip over VP8X header bytes.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *data += vp8x_size;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *data_size -= vp8x_size;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *found_vp8x = 1;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return VP8_STATUS_OK;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Skips to the next VP8/VP8L chunk header in the data given the size of the
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RIFF chunk 'riff_size'.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns VP8_STATUS_BITSTREAM_ERROR if any invalid chunk size is encountered,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         VP8_STATUS_OK otherwise.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If an alpha chunk is found, *alpha_data and *alpha_size are set
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// appropriately.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         size_t* const data_size,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         size_t const riff_size,
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const uint8_t** const alpha_data,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         size_t* const alpha_size) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint8_t* buf;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t buf_size;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32_t total_size = TAG_SIZE +           // "WEBP".
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        CHUNK_HEADER_SIZE +  // "VP8Xnnnn".
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        VP8X_CHUNK_SIZE;     // data.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(data != NULL);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(data_size != NULL);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buf = *data;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buf_size = *data_size;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(alpha_data != NULL);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(alpha_size != NULL);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *alpha_data = NULL;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *alpha_size = 0;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (1) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t chunk_size;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t disk_chunk_size;   // chunk_size with padding
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *data = buf;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *data_size = buf_size;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buf_size < CHUNK_HEADER_SIZE) {  // Insufficient data.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_NOT_ENOUGH_DATA;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chunk_size = get_le32(buf + TAG_SIZE);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (chunk_size > MAX_CHUNK_PAYLOAD) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_BITSTREAM_ERROR;          // Not a valid chunk size.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For odd-sized chunk-payload, there's one byte padding at the end.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    total_size += disk_chunk_size;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check that total bytes skipped so far does not exceed riff_size.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (riff_size > 0 && (total_size > riff_size)) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_BITSTREAM_ERROR;          // Not a valid chunk size.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Start of a (possibly incomplete) VP8/VP8L chunk implies that we have
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // parsed all the optional chunks.
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Note: This check must occur before the check 'buf_size < disk_chunk_size'
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // below to allow incomplete VP8/VP8L chunks.
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!memcmp(buf, "VP8 ", TAG_SIZE) ||
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        !memcmp(buf, "VP8L", TAG_SIZE)) {
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return VP8_STATUS_OK;
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buf_size < disk_chunk_size) {             // Insufficient data.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_NOT_ENOUGH_DATA;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!memcmp(buf, "ALPH", TAG_SIZE)) {         // A valid ALPH header.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *alpha_data = buf + CHUNK_HEADER_SIZE;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *alpha_size = chunk_size;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We have a full and valid chunk; skip it.
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buf += disk_chunk_size;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buf_size -= disk_chunk_size;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Validates the VP8/VP8L Header ("VP8 nnnn" or "VP8L nnnn") and skips over it.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns VP8_STATUS_BITSTREAM_ERROR for invalid (chunk larger than
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         riff_size) VP8/VP8L header,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         VP8_STATUS_OK otherwise.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If a VP8/VP8L chunk is found, *chunk_size is set to the total number of bytes
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// extracted from the VP8/VP8L chunk header.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                    size_t* const data_size, int have_all_data,
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                    size_t riff_size, size_t* const chunk_size,
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    int* const is_lossless) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint8_t* const data = *data_ptr;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint32_t minimal_size =
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TAG_SIZE + CHUNK_HEADER_SIZE;  // "WEBP" + "VP8 nnnn" OR
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     // "WEBP" + "VP8Lnnnn"
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(data != NULL);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(data_size != NULL);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(chunk_size != NULL);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(is_lossless != NULL);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*data_size < CHUNK_HEADER_SIZE) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return VP8_STATUS_NOT_ENOUGH_DATA;  // Insufficient data.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_vp8 || is_vp8l) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Bitstream contains VP8/VP8L header.
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const uint32_t size = get_le32(data + TAG_SIZE);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((riff_size >= minimal_size) && (size > riff_size - minimal_size)) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_BITSTREAM_ERROR;  // Inconsistent size information.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (have_all_data && (size > *data_size - CHUNK_HEADER_SIZE)) {
2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return VP8_STATUS_NOT_ENOUGH_DATA;  // Truncated bitstream.
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *chunk_size = size;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *data_ptr += CHUNK_HEADER_SIZE;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *data_size -= CHUNK_HEADER_SIZE;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *is_lossless = is_vp8l;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Raw VP8/VP8L bitstream (no header).
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *is_lossless = VP8LCheckSignature(data, *data_size);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *chunk_size = *data_size;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return VP8_STATUS_OK;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Fetch '*width', '*height', '*has_alpha' and fill out 'headers' based on
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'data'. All the output parameters may be NULL. If 'headers' is NULL only the
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// minimal amount will be read to fetch the remaining parameters.
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If 'headers' is non-NULL this function will attempt to locate both alpha
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// data (with or without a VP8X chunk) and the bitstream chunk (VP8/VP8L).
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: The following chunk sequences (before the raw VP8/VP8L data) are
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// considered valid by this function:
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RIFF + VP8(L)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RIFF + VP8X + (optional chunks) + VP8(L)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// VP8(L)     <-- Not a valid WebP format: only allowed for internal purpose.
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          size_t data_size,
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          int* const width,
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          int* const height,
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          int* const has_alpha,
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          int* const has_animation,
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          int* const format,
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          WebPHeaderStructure* const headers) {
2927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int canvas_width = 0;
2937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int canvas_height = 0;
2947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int image_width = 0;
2957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int image_height = 0;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int found_riff = 0;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int found_vp8x = 0;
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int animation_present = 0;
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int fragments_present = 0;
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int have_all_data = (headers != NULL) ? headers->have_all_data : 0;
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VP8StatusCode status;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPHeaderStructure hdrs;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data == NULL || data_size < RIFF_HEADER_SIZE) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return VP8_STATUS_NOT_ENOUGH_DATA;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&hdrs, 0, sizeof(hdrs));
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hdrs.data = data;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hdrs.data_size = data_size;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Skip over RIFF header.
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  status = ParseRIFF(&data, &data_size, have_all_data, &hdrs.riff_size);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != VP8_STATUS_OK) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status;   // Wrong RIFF header / insufficient data.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  found_riff = (hdrs.riff_size > 0);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Skip over VP8X.
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t flags = 0;
3227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    status = ParseVP8X(&data, &data_size, &found_vp8x,
3237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                       &canvas_width, &canvas_height, &flags);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status != VP8_STATUS_OK) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;  // Wrong VP8X / insufficient data.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    animation_present = !!(flags & ANIMATION_FLAG);
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fragments_present = !!(flags & FRAGMENTS_FLAG);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!found_riff && found_vp8x) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note: This restriction may be removed in the future, if it becomes
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // necessary to send VP8X chunk to the decoder.
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_BITSTREAM_ERROR;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG);
3357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (has_animation != NULL) *has_animation = animation_present;
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (format != NULL) *format = 0;   // default = undefined
3377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (found_vp8x && (animation_present || fragments_present) &&
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        headers == NULL) {
3407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (width != NULL) *width = canvas_width;
3417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (height != NULL) *height = canvas_height;
3427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return VP8_STATUS_OK;  // Just return features from VP8X header.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((found_riff && found_vp8x) ||
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 &hdrs.alpha_data, &hdrs.alpha_data_size);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status != VP8_STATUS_OK) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;  // Found an invalid chunk size / insufficient data.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Skip over VP8/VP8L header.
3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  status = ParseVP8Header(&data, &data_size, have_all_data, hdrs.riff_size,
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &hdrs.compressed_size, &hdrs.is_lossless);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != VP8_STATUS_OK) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status;  // Wrong VP8/VP8L chunk-header / insufficient data.
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return VP8_STATUS_BITSTREAM_ERROR;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (format != NULL && !(animation_present || fragments_present)) {
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *format = hdrs.is_lossless ? 2 : 1;
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!hdrs.is_lossless) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (data_size < VP8_FRAME_HEADER_SIZE) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_NOT_ENOUGH_DATA;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Validates raw VP8 data.
3777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!VP8GetInfo(data, data_size, (uint32_t)hdrs.compressed_size,
3787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    &image_width, &image_height)) {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_BITSTREAM_ERROR;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (data_size < VP8L_FRAME_HEADER_SIZE) {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_NOT_ENOUGH_DATA;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Validates raw VP8L data.
3867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!VP8LGetInfo(data, data_size, &image_width, &image_height, has_alpha)) {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_BITSTREAM_ERROR;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Validates image size coherency.
3917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (found_vp8x) {
3927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (canvas_width != image_width || canvas_height != image_height) {
3937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return VP8_STATUS_BITSTREAM_ERROR;
3947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
3957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (width != NULL) *width = image_width;
3977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (height != NULL) *height = image_height;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_alpha != NULL) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the data did not contain a VP8X/VP8L chunk the only definitive way
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to set this is by looking for alpha data (from an ALPH chunk).
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *has_alpha |= (hdrs.alpha_data != NULL);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (headers != NULL) {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *headers = hdrs;
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    headers->offset = data - headers->data;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert(headers->offset == headers->data_size - data_size);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return VP8_STATUS_OK;  // Return features from VP8 header.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VP8StatusCode status;
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int has_animation = 0;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(headers != NULL);
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // fill out headers, ignore width/height/has_alpha.
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  status = ParseHeadersInternal(headers->data, headers->data_size,
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                NULL, NULL, NULL, &has_animation,
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                NULL, headers);
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(jzern): full support of animation frames will require API additions.
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (has_animation) {
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      status = VP8_STATUS_UNSUPPORTED_FEATURE;
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return status;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WebPDecParams
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebPResetDecParams(WebPDecParams* const params) {
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (params != NULL) {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(params, 0, sizeof(*params));
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "Into" decoding variants
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Main flow
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                WebPDecParams* const params) {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VP8StatusCode status;
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VP8Io io;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPHeaderStructure headers;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  headers.data = data;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  headers.data_size = data_size;
4505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  headers.have_all_data = 1;
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status = WebPParseHeaders(&headers);   // Process Pre-VP8 chunks.
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != VP8_STATUS_OK) {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(params != NULL);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VP8InitIo(&io);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io.data = headers.data + headers.offset;
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io.data_size = headers.data_size - headers.offset;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPInitCustomIo(params, &io);  // Plug the I/O functions.
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!headers.is_lossless) {
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VP8Decoder* const dec = VP8New();
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dec == NULL) {
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_OUT_OF_MEMORY;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dec->alpha_data_ = headers.alpha_data;
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dec->alpha_data_size_ = headers.alpha_data_size;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Decode bitstream header, update io->width/io->height.
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!VP8GetHeaders(dec, &io)) {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status = dec->status_;   // An error occurred. Grab error status.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Allocate/check output buffers.
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status = WebPAllocateDecBuffer(io.width, io.height, params->options,
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     params->output);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (status == VP8_STATUS_OK) {  // Decode
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // This change must be done before calling VP8Decode()
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        dec->mt_method_ = VP8GetThreadMethod(params->options, &headers,
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                             io.width, io.height);
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        VP8InitDithering(params->options, dec);
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!VP8Decode(dec, &io)) {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          status = dec->status_;
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VP8Delete(dec);
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VP8LDecoder* const dec = VP8LNew();
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dec == NULL) {
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_OUT_OF_MEMORY;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!VP8LDecodeHeader(dec, &io)) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status = dec->status_;   // An error occurred. Grab error status.
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Allocate/check output buffers.
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status = WebPAllocateDecBuffer(io.width, io.height, params->options,
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     params->output);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (status == VP8_STATUS_OK) {  // Decode
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!VP8LDecodeImage(dec)) {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          status = dec->status_;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VP8LDelete(dec);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != VP8_STATUS_OK) {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WebPFreeDecBuffer(params->output);
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if WEBP_DECODER_ABI_VERSION > 0x0203
5135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (params->options != NULL && params->options->flip) {
5145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    status = WebPFlipBuffer(params->output);
5155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
5165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return status;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helpers
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const uint8_t* const data,
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     size_t data_size,
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     uint8_t* const rgba,
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     int stride, size_t size) {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPDecParams params;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPDecBuffer buf;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rgba == NULL) {
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPInitDecBuffer(&buf);
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPResetDecParams(&params);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.output = &buf;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buf.colorspace    = colorspace;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buf.u.RGBA.rgba   = rgba;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buf.u.RGBA.stride = stride;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buf.u.RGBA.size   = size;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buf.is_external_memory = 1;
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rgba;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size,
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           uint8_t* output, size_t size, int stride) {
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size);
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size,
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            uint8_t* output, size_t size, int stride) {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DecodeIntoRGBABuffer(MODE_RGBA, data, data_size, output, stride, size);
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size,
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            uint8_t* output, size_t size, int stride) {
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size,
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           uint8_t* output, size_t size, int stride) {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size);
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size,
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            uint8_t* output, size_t size, int stride) {
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size);
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           uint8_t* luma, size_t luma_size, int luma_stride,
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           uint8_t* u, size_t u_size, int u_stride,
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           uint8_t* v, size_t v_size, int v_stride) {
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPDecParams params;
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPDecBuffer output;
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (luma == NULL) return NULL;
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPInitDecBuffer(&output);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPResetDecParams(&params);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.output = &output;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.colorspace      = MODE_YUV;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.u.YUVA.y        = luma;
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.u.YUVA.y_stride = luma_stride;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.u.YUVA.y_size   = luma_size;
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.u.YUVA.u        = u;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.u.YUVA.u_stride = u_stride;
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.u.YUVA.u_size   = u_size;
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.u.YUVA.v        = v;
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.u.YUVA.v_stride = v_stride;
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.u.YUVA.v_size   = v_size;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.is_external_memory = 1;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return luma;
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* const data,
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       size_t data_size, int* const width, int* const height,
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       WebPDecBuffer* const keep_info) {
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPDecParams params;
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPDecBuffer output;
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPInitDecBuffer(&output);
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPResetDecParams(&params);
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.output = &output;
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.colorspace = mode;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Retrieve (and report back) the required dimensions from bitstream.
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!WebPGetInfo(data, data_size, &output.width, &output.height)) {
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (width != NULL) *width = output.width;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (height != NULL) *height = output.height;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Decode
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (keep_info != NULL) {    // keep track of the side-info
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WebPCopyDecBuffer(&output, keep_info);
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // return decoded samples (don't clear 'output'!)
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return WebPIsRGBMode(mode) ? output.u.RGBA.rgba : output.u.YUVA.y;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int* width, int* height) {
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Decode(MODE_RGB, data, data_size, width, height, NULL);
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int* width, int* height) {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Decode(MODE_RGBA, data, data_size, width, height, NULL);
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size,
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int* width, int* height) {
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Decode(MODE_ARGB, data, data_size, width, height, NULL);
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int* width, int* height) {
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Decode(MODE_BGR, data, data_size, width, height, NULL);
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int* width, int* height) {
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Decode(MODE_BGRA, data, data_size, width, height, NULL);
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int* width, int* height, uint8_t** u, uint8_t** v,
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int* stride, int* uv_stride) {
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPDecBuffer output;   // only to preserve the side-infos
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8_t* const out = Decode(MODE_YUV, data, data_size,
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              width, height, &output);
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (out != NULL) {
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WebPYUVABuffer* const buf = &output.u.YUVA;
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *u = buf->u;
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *v = buf->v;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *stride = buf->y_stride;
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *uv_stride = buf->u_stride;
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert(buf->u_stride == buf->v_stride);
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return out;
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void DefaultFeatures(WebPBitstreamFeatures* const features) {
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(features != NULL);
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(features, 0, sizeof(*features));
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 WebPBitstreamFeatures* const features) {
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (features == NULL || data == NULL) {
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return VP8_STATUS_INVALID_PARAM;
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DefaultFeatures(features);
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Only parse enough of the data to retrieve the features.
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ParseHeadersInternal(data, data_size,
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &features->width, &features->height,
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              &features->has_alpha, &features->has_animation,
6875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              &features->format, NULL);
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WebPGetInfo()
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int WebPGetInfo(const uint8_t* data, size_t data_size,
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                int* width, int* height) {
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPBitstreamFeatures features;
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) {
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (width != NULL) {
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *width  = features.width;
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (height != NULL) {
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *height = features.height;
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 1;
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Advance decoding API
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  int version) {
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;   // version mismatch
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (config == NULL) {
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(config, 0, sizeof(*config));
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DefaultFeatures(&config->input);
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPInitDecBuffer(&config->output);
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 1;
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size,
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      WebPBitstreamFeatures* features,
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      int version) {
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return VP8_STATUS_INVALID_PARAM;   // version mismatch
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (features == NULL) {
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return VP8_STATUS_INVALID_PARAM;
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return GetFeatures(data, data_size, features);
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         WebPDecoderConfig* config) {
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPDecParams params;
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VP8StatusCode status;
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (config == NULL) {
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return VP8_STATUS_INVALID_PARAM;
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status = GetFeatures(data, data_size, &config->input);
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != VP8_STATUS_OK) {
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return VP8_STATUS_BITSTREAM_ERROR;  // Not-enough-data treated as error.
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status;
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPResetDecParams(&params);
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.output = &config->output;
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.options = &config->options;
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status = DecodeInto(data, data_size, &params);
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return status;
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Cropping and rescaling.
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          VP8Io* const io, WEBP_CSP_MODE src_colorspace) {
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int W = io->width;
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int H = io->height;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x = 0, y = 0, w = W, h = H;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cropping
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io->use_cropping = (options != NULL) && (options->use_cropping > 0);
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (io->use_cropping) {
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    w = options->crop_width;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    h = options->crop_height;
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = options->crop_left;
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    y = options->crop_top;
7815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!WebPIsRGBMode(src_colorspace)) {   // only snap for YUV420
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      x &= ~1;
7835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      y &= ~1;
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;  // out of frame boundary error
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io->crop_left   = x;
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io->crop_top    = y;
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io->crop_right  = x + w;
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io->crop_bottom = y + h;
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io->mb_w = w;
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io->mb_h = h;
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Scaling
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io->use_scaling = (options != NULL) && (options->use_scaling > 0);
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (io->use_scaling) {
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (options->scaled_width <= 0 || options->scaled_height <= 0) {
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io->scaled_width = options->scaled_width;
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io->scaled_height = options->scaled_height;
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Filter
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io->bypass_filtering = options && options->bypass_filtering;
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fancy upsampler
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef FANCY_UPSAMPLING
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io->fancy_upsampling = (options == NULL) || (!options->no_fancy_upsampling);
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (io->use_scaling) {
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // disable filter (only for large downscaling ratio).
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           (io->scaled_height < H * 3 / 4);
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io->fancy_upsampling = 0;
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 1;
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825