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(¶ms); 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, ¶ms) != 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(¶ms); 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, ¶ms) != 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(¶ms); 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, ¶ms) != 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(¶ms); 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.output = &config->output; 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.options = &config->options; 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status = DecodeInto(data, data_size, ¶ms); 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