19aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// Copyright 2010 Google Inc.
29aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
39aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// This code is licensed under the same terms as WebM:
49aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//  Software License Agreement:  http://www.webmproject.org/license/software/
59aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//  Additional IP Rights Grant:  http://www.webmproject.org/license/additional/
69aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// -----------------------------------------------------------------------------
79aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
89aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// Main decoding functions for WEBP images.
99aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
109aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// Author: Skal (pascal.massimino@gmail.com)
119aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
129aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include <stdlib.h>
139aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include "vp8i.h"
1403d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora#include "webpi.h"
159aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
169aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#if defined(__cplusplus) || defined(c_plusplus)
179aea642eefa7a641ab8b89d953251939221d2719Eric Hassoldextern "C" {
189aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#endif
199aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
209aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//-----------------------------------------------------------------------------
219aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// RIFF layout is:
229aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//   0ffset  tag
239aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//   0...3   "RIFF" 4-byte tag
249aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//   4...7   size of image data (including metadata) starting at offset 8
259aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//   8...11  "WEBP"   our form-type signature
269aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//   12..15  "VP8 ": 4-bytes tags, describing the raw video format used
279aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//   16..19  size of the raw VP8 image data, starting at offset 20
289aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//   20....  the VP8 bytes
299aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// There can be extra chunks after the "VP8 " chunk (ICMT, ICOP, ...)
309aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// All 32-bits sizes are in little-endian order.
319aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// Note: chunk data must be padded to multiple of 2 in size
329aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
339aea642eefa7a641ab8b89d953251939221d2719Eric Hassoldstatic inline uint32_t get_le32(const uint8_t* const data) {
349aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
359aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
369aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
379aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// If a RIFF container is detected, validate it and skip over it.
3803d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arorauint32_t WebPCheckRIFFHeader(const uint8_t** data_ptr,
39466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                             uint32_t* data_size_ptr) {
409aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  uint32_t chunk_size = 0xffffffffu;
419aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  if (*data_size_ptr >= 10 + 20 && !memcmp(*data_ptr, "RIFF", 4)) {
429aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    if (memcmp(*data_ptr + 8, "WEBP", 4)) {
439aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      return 0;  // wrong image file signature
449aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    } else {
459aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      const uint32_t riff_size = get_le32(*data_ptr + 4);
4603d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora      if (riff_size < 12) {
4703d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora        return 0;   // we should have at least one chunk
4803d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora      }
499aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      if (memcmp(*data_ptr + 12, "VP8 ", 4)) {
509aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        return 0;   // invalid compression format
519aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      }
529aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      chunk_size = get_le32(*data_ptr + 16);
5303d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora      if (chunk_size > riff_size - 12) {
549aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        return 0;  // inconsistent size information.
559aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      }
5603d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora      // We have a RIFF container. Skip it.
579aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      *data_ptr += 20;
589aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      *data_size_ptr -= 20;
5903d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora      // Note: we don't report error for odd-sized chunks.
609aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    }
619aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    return chunk_size;
629aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
639aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  return *data_size_ptr;
649aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
659aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
669aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//-----------------------------------------------------------------------------
67466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// WebPDecParams
6803d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora
69466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Aroravoid WebPResetDecParams(WebPDecParams* const params) {
70466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (params) {
71466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    memset(params, 0, sizeof(*params));
7203d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora  }
7303d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora}
7403d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora
759aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//-----------------------------------------------------------------------------
76466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// "Into" decoding variants
779aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
78466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// Main flow
79466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic VP8StatusCode DecodeInto(const uint8_t* data, uint32_t data_size,
80466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                                WebPDecParams* const params) {
819aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  VP8Decoder* dec = VP8New();
82466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  VP8StatusCode status = VP8_STATUS_OK;
839aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  VP8Io io;
849aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
85466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  assert(params);
869aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  if (dec == NULL) {
87466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return VP8_STATUS_INVALID_PARAM;
889aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
899aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
909aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  VP8InitIo(&io);
919aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  io.data = data;
929aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  io.data_size = data_size;
93466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPInitCustomIo(params, &io);  // Plug the I/O functions.
949aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
95466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  // Decode bitstream header, update io->width/io->height.
969aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  if (!VP8GetHeaders(dec, &io)) {
97466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    status = VP8_STATUS_BITSTREAM_ERROR;
98466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  } else {
99466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    // Allocate/check output buffers.
100466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    status = WebPAllocateDecBuffer(io.width, io.height, params->options,
101466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                                   params->output);
102466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    if (status == VP8_STATUS_OK) {
103466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      // Decode
104466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      if (!VP8Decode(dec, &io)) {
105466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora        status = dec->status_;
106466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      }
107466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    }
1089aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
1099aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  VP8Delete(dec);
110466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (status != VP8_STATUS_OK) {
111466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    WebPFreeDecBuffer(params->output);
112466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
113466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return status;
1149aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
1159aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
116466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// Helpers
117466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
118466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                                     const uint8_t* data, uint32_t data_size,
119466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                                     uint8_t* rgba, int stride, int size) {
12003d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora  WebPDecParams params;
121466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPDecBuffer buf;
122466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (rgba == NULL) {
1239aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    return NULL;
1249aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
125466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPInitDecBuffer(&buf);
126466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPResetDecParams(&params);
127466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  params.output = &buf;
128466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  buf.colorspace    = colorspace;
129466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  buf.u.RGBA.rgba   = rgba;
130466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  buf.u.RGBA.stride = stride;
131466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  buf.u.RGBA.size   = size;
132466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  buf.is_external_memory = 1;
133466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
134466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return NULL;
135466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
136466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return rgba;
137466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
1389aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
139466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorauint8_t* WebPDecodeRGBInto(const uint8_t* data, uint32_t data_size,
140466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                           uint8_t* output, int size, int stride) {
141466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size);
1429aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
1439aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1449aea642eefa7a641ab8b89d953251939221d2719Eric Hassolduint8_t* WebPDecodeRGBAInto(const uint8_t* data, uint32_t data_size,
145466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                            uint8_t* output, int size, int stride) {
146466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return DecodeIntoRGBABuffer(MODE_RGBA, data, data_size, output, stride, size);
147466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
1489aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
149466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorauint8_t* WebPDecodeARGBInto(const uint8_t* data, uint32_t data_size,
150466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                            uint8_t* output, int size, int stride) {
151466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size);
1529aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
1539aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1549aea642eefa7a641ab8b89d953251939221d2719Eric Hassolduint8_t* WebPDecodeBGRInto(const uint8_t* data, uint32_t data_size,
155466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                           uint8_t* output, int size, int stride) {
156466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size);
1579aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
1589aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1599aea642eefa7a641ab8b89d953251939221d2719Eric Hassolduint8_t* WebPDecodeBGRAInto(const uint8_t* data, uint32_t data_size,
160466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                            uint8_t* output, int size, int stride) {
161466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size);
1629aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
1639aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1649aea642eefa7a641ab8b89d953251939221d2719Eric Hassolduint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size,
1659aea642eefa7a641ab8b89d953251939221d2719Eric Hassold                           uint8_t* luma, int luma_size, int luma_stride,
1669aea642eefa7a641ab8b89d953251939221d2719Eric Hassold                           uint8_t* u, int u_size, int u_stride,
1679aea642eefa7a641ab8b89d953251939221d2719Eric Hassold                           uint8_t* v, int v_size, int v_stride) {
16803d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora  WebPDecParams params;
169466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPDecBuffer output;
170466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (luma == NULL) return NULL;
171466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPInitDecBuffer(&output);
172466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPResetDecParams(&params);
173466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  params.output = &output;
174466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.colorspace      = MODE_YUV;
175466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.u.YUVA.y        = luma;
176466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.u.YUVA.y_stride = luma_stride;
177466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.u.YUVA.y_size   = luma_size;
178466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.u.YUVA.u        = u;
179466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.u.YUVA.u_stride = u_stride;
180466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.u.YUVA.u_size   = u_size;
181466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.u.YUVA.v        = v;
182466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.u.YUVA.v_stride = v_stride;
183466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.u.YUVA.v_size   = v_size;
184466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.is_external_memory = 1;
185466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
1869aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    return NULL;
1879aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
188466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return luma;
1899aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
1909aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1919aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//-----------------------------------------------------------------------------
1929aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
19303d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arorastatic uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* data,
19403d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora                       uint32_t data_size, int* width, int* height,
195466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                       WebPDecBuffer* keep_info) {
19603d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora  WebPDecParams params;
197466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPDecBuffer output;
198466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
199466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPInitDecBuffer(&output);
200466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPResetDecParams(&params);
201466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  params.output = &output;
202466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  output.colorspace = mode;
2039aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
204466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  // Retrieve (and report back) the required dimensions from bitstream.
205466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (!WebPGetInfo(data, data_size, &output.width, &output.height)) {
2069aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    return NULL;
2079aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
208466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (width) *width = output.width;
209466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (height) *height = output.height;
2109aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
211466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  // Decode
212466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
213466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return NULL;
2149aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
215466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (keep_info) {    // keep track of the side-info
216466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    WebPCopyDecBuffer(&output, keep_info);
2179aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
218466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  // return decoded samples (don't clear 'output'!)
219466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return (mode >= MODE_YUV) ? output.u.YUVA.y : output.u.RGBA.rgba;
2209aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
2219aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
2229aea642eefa7a641ab8b89d953251939221d2719Eric Hassolduint8_t* WebPDecodeRGB(const uint8_t* data, uint32_t data_size,
223466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                       int* width, int* height) {
2249aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  return Decode(MODE_RGB, data, data_size, width, height, NULL);
2259aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
2269aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
2279aea642eefa7a641ab8b89d953251939221d2719Eric Hassolduint8_t* WebPDecodeRGBA(const uint8_t* data, uint32_t data_size,
228466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                        int* width, int* height) {
2299aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  return Decode(MODE_RGBA, data, data_size, width, height, NULL);
2309aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
2319aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
232466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorauint8_t* WebPDecodeARGB(const uint8_t* data, uint32_t data_size,
233466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                        int* width, int* height) {
234466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return Decode(MODE_ARGB, data, data_size, width, height, NULL);
235466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
236466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
2379aea642eefa7a641ab8b89d953251939221d2719Eric Hassolduint8_t* WebPDecodeBGR(const uint8_t* data, uint32_t data_size,
238466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                       int* width, int* height) {
2399aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  return Decode(MODE_BGR, data, data_size, width, height, NULL);
2409aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
2419aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
2429aea642eefa7a641ab8b89d953251939221d2719Eric Hassolduint8_t* WebPDecodeBGRA(const uint8_t* data, uint32_t data_size,
243466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                        int* width, int* height) {
2449aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  return Decode(MODE_BGRA, data, data_size, width, height, NULL);
2459aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
2469aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
2479aea642eefa7a641ab8b89d953251939221d2719Eric Hassolduint8_t* WebPDecodeYUV(const uint8_t* data, uint32_t data_size,
248466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                       int* width, int* height, uint8_t** u, uint8_t** v,
249466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                       int* stride, int* uv_stride) {
250466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPDecBuffer output;   // only to preserve the side-infos
2519aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  uint8_t* const out = Decode(MODE_YUV, data, data_size,
252466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                              width, height, &output);
2539aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
2549aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  if (out) {
255466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    const WebPYUVABuffer* const buf = &output.u.YUVA;
256466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    *u = buf->u;
257466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    *v = buf->v;
258466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    *stride = buf->y_stride;
259466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    *uv_stride = buf->u_stride;
260466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    assert(buf->u_stride == buf->v_stride);
2619aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
2629aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  return out;
2639aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
2649aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
2659aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//-----------------------------------------------------------------------------
2669aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// WebPGetInfo()
2679aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
2689aea642eefa7a641ab8b89d953251939221d2719Eric Hassoldint WebPGetInfo(const uint8_t* data, uint32_t data_size,
269466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                int* width, int* height) {
27003d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Arora  const uint32_t chunk_size = WebPCheckRIFFHeader(&data, &data_size);
2719aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  if (!chunk_size) {
2729aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    return 0;         // unsupported RIFF header
2739aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
2749aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  // Validate raw video data
275466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return VP8GetInfo(data, data_size, chunk_size, width, height, NULL);
276466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
277466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
278466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic void DefaultFeatures(WebPBitstreamFeatures* const features) {
279466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  assert(features);
280466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  memset(features, 0, sizeof(*features));
281466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  features->bitstream_version = 0;
282466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
283466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
284466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arorastatic VP8StatusCode GetFeatures(const uint8_t** data, uint32_t* data_size,
285466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                                 WebPBitstreamFeatures* const features) {
286466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  uint32_t chunk_size;
287466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (features == NULL) {
288466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return VP8_STATUS_INVALID_PARAM;
2899aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
290466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  DefaultFeatures(features);
291466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (data == NULL || *data == NULL || data_size == 0) {
292466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return VP8_STATUS_INVALID_PARAM;
293466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
294466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  chunk_size = WebPCheckRIFFHeader(data, data_size);
295466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (chunk_size == 0) {
296466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return VP8_STATUS_BITSTREAM_ERROR;   // unsupported RIFF header
297466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
298466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (!VP8GetInfo(*data, *data_size, chunk_size,
299466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                  &features->width, &features->height, &features->has_alpha)) {
300466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return VP8_STATUS_BITSTREAM_ERROR;
301466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
302466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return VP8_STATUS_OK;
303466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
3049aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
305466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora//-----------------------------------------------------------------------------
306466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora// Advance decoding API
3079aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
308466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Aroraint WebPInitDecoderConfigInternal(WebPDecoderConfig* const config,
309466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                                  int version) {
310466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (version != WEBP_DECODER_ABI_VERSION) {
311466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return 0;   // version mismatch
312466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
313466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (config == NULL) {
314466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return 0;
315466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
316466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  memset(config, 0, sizeof(*config));
317466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  DefaultFeatures(&config->input);
318466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPInitDecBuffer(&config->output);
319466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return 1;
320466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
3219aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
322466727975bcc57c0c5597bcd0747a2fe4777b303Vikas AroraVP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, uint32_t data_size,
323466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                                      WebPBitstreamFeatures* const features,
324466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                            int version) {
325466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (version != WEBP_DECODER_ABI_VERSION) {
326466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return VP8_STATUS_INVALID_PARAM;   // version mismatch
327466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
328466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (features == NULL) {
329466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return VP8_STATUS_INVALID_PARAM;
330466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
331466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return GetFeatures(&data, &data_size, features);
332466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
333466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
334466727975bcc57c0c5597bcd0747a2fe4777b303Vikas AroraVP8StatusCode WebPDecode(const uint8_t* data, uint32_t data_size,
335466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                         WebPDecoderConfig* const config) {
336466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPDecParams params;
337466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  VP8StatusCode status;
3389aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
339466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (!config) {
340466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return VP8_STATUS_INVALID_PARAM;
3419aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
342466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
343466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  status = GetFeatures(&data, &data_size, &config->input);
344466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (status != VP8_STATUS_OK) {
345466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return status;
346466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
347466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
348466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPResetDecParams(&params);
349466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  params.output = &config->output;
350466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  params.options = &config->options;
351466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  status = DecodeInto(data, data_size, &params);
352466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
353466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return status;
3549aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
3559aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
3569aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#if defined(__cplusplus) || defined(c_plusplus)
3579aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}    // extern "C"
3589aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#endif
359