Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: third_party/libwebp/dec/webp.c

Issue 10832153: libwebp: update snapshot to v0.2.0-rc1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2010 Google Inc. 1 // Copyright 2010 Google Inc. All Rights Reserved.
2 // 2 //
3 // This code is licensed under the same terms as WebM: 3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/ 4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // ----------------------------------------------------------------------------- 6 // -----------------------------------------------------------------------------
7 // 7 //
8 // Main decoding functions for WEBP images. 8 // Main decoding functions for WEBP images.
9 // 9 //
10 // Author: Skal (pascal.massimino@gmail.com) 10 // Author: Skal (pascal.massimino@gmail.com)
11 11
12 #include <stdlib.h> 12 #include <stdlib.h>
13 #include "vp8i.h" 13
14 #include "webpi.h" 14 #include "./vp8i.h"
15 #include "./vp8li.h"
16 #include "./webpi.h"
17 #include "../webp/format_constants.h"
15 18
16 #if defined(__cplusplus) || defined(c_plusplus) 19 #if defined(__cplusplus) || defined(c_plusplus)
17 extern "C" { 20 extern "C" {
18 #endif 21 #endif
19 22
20 //------------------------------------------------------------------------------ 23 //------------------------------------------------------------------------------
21 // RIFF layout is: 24 // RIFF layout is:
22 // Offset tag 25 // Offset tag
23 // 0...3 "RIFF" 4-byte tag 26 // 0...3 "RIFF" 4-byte tag
24 // 4...7 size of image data (including metadata) starting at offset 8 27 // 4...7 size of image data (including metadata) starting at offset 8
25 // 8...11 "WEBP" our form-type signature 28 // 8...11 "WEBP" our form-type signature
26 // The RIFF container (12 bytes) is followed by appropriate chunks: 29 // The RIFF container (12 bytes) is followed by appropriate chunks:
27 // 12..15 "VP8 ": 4-bytes tags, describing the raw video format used 30 // 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format
28 // 16..19 size of the raw VP8 image data, starting at offset 20 31 // 16..19 size of the raw VP8 image data, starting at offset 20
29 // 20.... the VP8 bytes 32 // 20.... the VP8 bytes
30 // Or, 33 // Or,
34 // 12..15 "VP8L": 4-bytes tags, signaling the use of VP8L lossless format
35 // 16..19 size of the raw VP8L image data, starting at offset 20
36 // 20.... the VP8L bytes
37 // Or,
31 // 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk. 38 // 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk.
32 // 16..19 size of the VP8X chunk starting at offset 20. 39 // 16..19 size of the VP8X chunk starting at offset 20.
33 // 20..23 VP8X flags bit-map corresponding to the chunk-types present. 40 // 20..23 VP8X flags bit-map corresponding to the chunk-types present.
34 // 24..27 Width of the Canvas Image. 41 // 24..26 Width of the Canvas Image.
35 // 28..31 Height of the Canvas Image. 42 // 27..29 Height of the Canvas Image.
36 // There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8, 43 // There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8,
37 // META ...) 44 // META ...)
38 // All 32-bits sizes are in little-endian order. 45 // All sizes are in little-endian order.
39 // Note: chunk data must be padded to multiple of 2 in size 46 // Note: chunk data size must be padded to multiple of 2 when written.
40 47
41 static inline uint32_t get_le32(const uint8_t* const data) { 48 static WEBP_INLINE uint32_t get_le24(const uint8_t* const data) {
42 return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); 49 return data[0] | (data[1] << 8) | (data[2] << 16);
43 } 50 }
44 51
45 VP8StatusCode WebPParseRIFF(const uint8_t** data, uint32_t* data_size, 52 static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) {
46 uint32_t* riff_size) { 53 return (uint32_t)get_le24(data) | (data[3] << 24);
47 assert(data); 54 }
48 assert(data_size);
49 assert(riff_size);
50 55
51 if (*data_size >= RIFF_HEADER_SIZE && 56 // Validates the RIFF container (if detected) and skips over it.
52 !memcmp(*data, "RIFF", TAG_SIZE)) { 57 // If a RIFF container is detected,
58 // Returns VP8_STATUS_BITSTREAM_ERROR for invalid header, and
59 // VP8_STATUS_OK otherwise.
60 // In case there are not enough bytes (partial RIFF container), return 0 for
61 // *riff_size. Else return the RIFF size extracted from the header.
62 static VP8StatusCode ParseRIFF(const uint8_t** const data,
63 size_t* const data_size,
64 size_t* const riff_size) {
65 assert(data != NULL);
66 assert(data_size != NULL);
67 assert(riff_size != NULL);
68
69 *riff_size = 0; // Default: no RIFF present.
70 if (*data_size >= RIFF_HEADER_SIZE && !memcmp(*data, "RIFF", TAG_SIZE)) {
53 if (memcmp(*data + 8, "WEBP", TAG_SIZE)) { 71 if (memcmp(*data + 8, "WEBP", TAG_SIZE)) {
54 return VP8_STATUS_BITSTREAM_ERROR; // Wrong image file signature. 72 return VP8_STATUS_BITSTREAM_ERROR; // Wrong image file signature.
55 } else { 73 } else {
56 *riff_size = get_le32(*data + TAG_SIZE); 74 const uint32_t size = get_le32(*data + TAG_SIZE);
57 // Check that we have at least one chunk (i.e "WEBP" + "VP8?nnnn"). 75 // Check that we have at least one chunk (i.e "WEBP" + "VP8?nnnn").
58 if (*riff_size < TAG_SIZE + CHUNK_HEADER_SIZE) { 76 if (size < TAG_SIZE + CHUNK_HEADER_SIZE) {
59 return VP8_STATUS_BITSTREAM_ERROR; 77 return VP8_STATUS_BITSTREAM_ERROR;
60 } 78 }
61 // We have a RIFF container. Skip it. 79 // We have a RIFF container. Skip it.
80 *riff_size = size;
62 *data += RIFF_HEADER_SIZE; 81 *data += RIFF_HEADER_SIZE;
63 *data_size -= RIFF_HEADER_SIZE; 82 *data_size -= RIFF_HEADER_SIZE;
64 } 83 }
65 } else {
66 *riff_size = 0; // Did not get full RIFF Header.
67 } 84 }
68 return VP8_STATUS_OK; 85 return VP8_STATUS_OK;
69 } 86 }
70 87
71 VP8StatusCode WebPParseVP8X(const uint8_t** data, uint32_t* data_size, 88 // Validates the VP8X header and skips over it.
72 uint32_t* bytes_skipped, 89 // Returns VP8_STATUS_BITSTREAM_ERROR for invalid VP8X header,
73 int* width, int* height, uint32_t* flags) { 90 // VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
74 assert(data); 91 // VP8_STATUS_OK otherwise.
75 assert(data_size); 92 // If a VP8X chunk is found, found_vp8x is set to true and *width_ptr,
76 assert(bytes_skipped); 93 // *height_ptr and *flags_ptr are set to the corresponding values extracted
94 // from the VP8X chunk.
95 static VP8StatusCode ParseVP8X(const uint8_t** const data,
96 size_t* const data_size,
97 int* const found_vp8x,
98 int* const width_ptr, int* const height_ptr,
99 uint32_t* const flags_ptr) {
100 const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
101 assert(data != NULL);
102 assert(data_size != NULL);
103 assert(found_vp8x != NULL);
77 104
78 *bytes_skipped = 0; 105 *found_vp8x = 0;
79 106
80 if (*data_size < CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE) { 107 if (*data_size < CHUNK_HEADER_SIZE) {
81 return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data. 108 return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
82 } 109 }
83 110
84 if (!memcmp(*data, "VP8X", TAG_SIZE)) { 111 if (!memcmp(*data, "VP8X", TAG_SIZE)) {
112 int width, height;
113 uint32_t flags;
85 const uint32_t chunk_size = get_le32(*data + TAG_SIZE); 114 const uint32_t chunk_size = get_le32(*data + TAG_SIZE);
86 if (chunk_size != VP8X_CHUNK_SIZE) { 115 if (chunk_size != VP8X_CHUNK_SIZE) {
87 return VP8_STATUS_BITSTREAM_ERROR; // Wrong chunk size. 116 return VP8_STATUS_BITSTREAM_ERROR; // Wrong chunk size.
88 } 117 }
89 if (flags) { 118
90 *flags = get_le32(*data + 8); 119 // Verify if enough data is available to validate the VP8X chunk.
120 if (*data_size < vp8x_size) {
121 return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
91 } 122 }
92 if (width) { 123 flags = get_le32(*data + 8);
93 *width = get_le32(*data + 12); 124 width = 1 + get_le24(*data + 12);
125 height = 1 + get_le24(*data + 15);
126 if (width * (uint64_t)height >= MAX_IMAGE_AREA) {
127 return VP8_STATUS_BITSTREAM_ERROR; // image is too large
94 } 128 }
95 if (height) { 129
96 *height = get_le32(*data + 16); 130 if (flags_ptr != NULL) *flags_ptr = flags;
97 } 131 if (width_ptr != NULL) *width_ptr = width;
98 // We have consumed 20 bytes from VP8X. Skip them. 132 if (height_ptr != NULL) *height_ptr = height;
99 *bytes_skipped = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; 133 // Skip over VP8X header bytes.
100 *data += *bytes_skipped; 134 *data += vp8x_size;
101 *data_size -= *bytes_skipped; 135 *data_size -= vp8x_size;
136 *found_vp8x = 1;
102 } 137 }
103 return VP8_STATUS_OK; 138 return VP8_STATUS_OK;
104 } 139 }
105 140
106 VP8StatusCode WebPParseOptionalChunks(const uint8_t** data, uint32_t* data_size, 141 // Skips to the next VP8/VP8L chunk header in the data given the size of the
107 uint32_t riff_size, 142 // RIFF chunk 'riff_size'.
108 uint32_t* bytes_skipped) { 143 // Returns VP8_STATUS_BITSTREAM_ERROR if any invalid chunk size is encountered,
144 // VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
145 // VP8_STATUS_OK otherwise.
146 // If an alpha chunk is found, *alpha_data and *alpha_size are set
147 // appropriately.
148 static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
149 size_t* const data_size,
150 size_t const riff_size,
151 const uint8_t** const alpha_data,
152 size_t* const alpha_size) {
109 const uint8_t* buf; 153 const uint8_t* buf;
110 uint32_t buf_size; 154 size_t buf_size;
111 155 uint32_t total_size = TAG_SIZE + // "WEBP".
112 assert(data); 156 CHUNK_HEADER_SIZE + // "VP8Xnnnn".
113 assert(data_size); 157 VP8X_CHUNK_SIZE; // data.
114 assert(bytes_skipped); 158 assert(data != NULL);
115 159 assert(data_size != NULL);
116 buf = *data; 160 buf = *data;
117 buf_size = *data_size; 161 buf_size = *data_size;
118 *bytes_skipped = 0; 162
163 assert(alpha_data != NULL);
164 assert(alpha_size != NULL);
165 *alpha_data = NULL;
166 *alpha_size = 0;
119 167
120 while (1) { 168 while (1) {
121 uint32_t chunk_size; 169 uint32_t chunk_size;
122 uint32_t cur_skip_size; 170 uint32_t disk_chunk_size; // chunk_size with padding
123 const uint32_t bytes_skipped_header = TAG_SIZE + // "WEBP". 171
124 CHUNK_HEADER_SIZE + // "VP8Xnnnn".
125 VP8X_CHUNK_SIZE; // Data.
126 *data = buf; 172 *data = buf;
127 *data_size = buf_size; 173 *data_size = buf_size;
128 174
129 if (buf_size < CHUNK_HEADER_SIZE) { // Insufficient data. 175 if (buf_size < CHUNK_HEADER_SIZE) { // Insufficient data.
130 return VP8_STATUS_NOT_ENOUGH_DATA; 176 return VP8_STATUS_NOT_ENOUGH_DATA;
131 } 177 }
132 178
133 chunk_size = get_le32(buf + TAG_SIZE); 179 chunk_size = get_le32(buf + TAG_SIZE);
134 cur_skip_size = CHUNK_HEADER_SIZE + chunk_size; 180 // For odd-sized chunk-payload, there's one byte padding at the end.
181 disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1;
182 total_size += disk_chunk_size;
135 183
136 // Check that total bytes skipped along with current chunk size 184 // Check that total bytes skipped so far does not exceed riff_size.
137 // does not exceed riff_size. 185 if (riff_size > 0 && (total_size > riff_size)) {
138 if (riff_size > 0 && 186 return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
139 (bytes_skipped_header + *bytes_skipped + cur_skip_size > riff_size)) {
140 return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
141 } 187 }
142 188
143 if (buf_size < cur_skip_size) { // Insufficient data. 189 if (buf_size < disk_chunk_size) { // Insufficient data.
144 return VP8_STATUS_NOT_ENOUGH_DATA; 190 return VP8_STATUS_NOT_ENOUGH_DATA;
145 } 191 }
146 192
147 if (!memcmp(buf, "VP8 ", TAG_SIZE)) { // A valid VP8 header. 193 if (!memcmp(buf, "ALPH", TAG_SIZE)) { // A valid ALPH header.
194 *alpha_data = buf + CHUNK_HEADER_SIZE;
195 *alpha_size = chunk_size;
196 } else if (!memcmp(buf, "VP8 ", TAG_SIZE) ||
197 !memcmp(buf, "VP8L", TAG_SIZE)) { // A valid VP8/VP8L header.
148 return VP8_STATUS_OK; // Found. 198 return VP8_STATUS_OK; // Found.
149 } 199 }
150 200
151 // We have a full & valid chunk; skip it. 201 // We have a full and valid chunk; skip it.
152 buf += cur_skip_size; 202 buf += disk_chunk_size;
153 buf_size -= cur_skip_size; 203 buf_size -= disk_chunk_size;
154 *bytes_skipped += cur_skip_size;
155 } 204 }
156 } 205 }
157 206
158 VP8StatusCode WebPParseVP8Header(const uint8_t** data, uint32_t* data_size, 207 // Validates the VP8/VP8L Header ("VP8 nnnn" or "VP8L nnnn") and skips over it.
159 uint32_t riff_size, uint32_t* bytes_skipped, 208 // Returns VP8_STATUS_BITSTREAM_ERROR for invalid (chunk larger than
160 uint32_t* vp8_chunk_size) { 209 // riff_size) VP8/VP8L header,
161 assert(data); 210 // VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
162 assert(data_size); 211 // VP8_STATUS_OK otherwise.
163 assert(bytes_skipped); 212 // If a VP8/VP8L chunk is found, *chunk_size is set to the total number of bytes
164 assert(vp8_chunk_size); 213 // extracted from the VP8/VP8L chunk header.
165 214 // The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data.
166 *bytes_skipped = 0; 215 static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
167 *vp8_chunk_size = 0; 216 size_t* const data_size,
217 size_t riff_size,
218 size_t* const chunk_size,
219 int* const is_lossless) {
220 const uint8_t* const data = *data_ptr;
221 const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE);
222 const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE);
223 const uint32_t minimal_size =
224 TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" OR
225 // "WEBP" + "VP8Lnnnn"
226 assert(data != NULL);
227 assert(data_size != NULL);
228 assert(chunk_size != NULL);
229 assert(is_lossless != NULL);
168 230
169 if (*data_size < CHUNK_HEADER_SIZE) { 231 if (*data_size < CHUNK_HEADER_SIZE) {
170 return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data. 232 return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
171 } 233 }
172 234
173 if (!memcmp(*data, "VP8 ", TAG_SIZE)) { 235 if (is_vp8 || is_vp8l) {
174 *vp8_chunk_size = get_le32(*data + TAG_SIZE); 236 // Bitstream contains VP8/VP8L header.
175 if (riff_size >= TAG_SIZE + CHUNK_HEADER_SIZE && // "WEBP" + "VP8 nnnn". 237 const uint32_t size = get_le32(data + TAG_SIZE);
176 (*vp8_chunk_size > riff_size - (TAG_SIZE + CHUNK_HEADER_SIZE))) { 238 if ((riff_size >= minimal_size) && (size > riff_size - minimal_size)) {
177 return VP8_STATUS_BITSTREAM_ERROR; // Inconsistent size information. 239 return VP8_STATUS_BITSTREAM_ERROR; // Inconsistent size information.
178 } 240 }
179 // We have consumed CHUNK_HEADER_SIZE bytes from VP8 Header. Skip them. 241 // Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header.
180 *bytes_skipped = CHUNK_HEADER_SIZE; 242 *chunk_size = size;
181 *data += *bytes_skipped; 243 *data_ptr += CHUNK_HEADER_SIZE;
182 *data_size -= *bytes_skipped; 244 *data_size -= CHUNK_HEADER_SIZE;
183 } 245 *is_lossless = is_vp8l;
184 return VP8_STATUS_OK; 246 } else {
185 } 247 // Raw VP8/VP8L bitstream (no header).
186 248 *is_lossless = VP8LCheckSignature(data, *data_size);
187 VP8StatusCode WebPParseHeaders(const uint8_t** data, uint32_t* data_size, 249 *chunk_size = *data_size;
188 uint32_t* vp8_size, uint32_t* bytes_skipped) {
189 const uint8_t* buf;
190 uint32_t buf_size;
191 uint32_t riff_size;
192 uint32_t vp8_size_tmp;
193 uint32_t optional_data_size;
194 uint32_t vp8x_skip_size;
195 uint32_t vp8_skip_size;
196 VP8StatusCode status;
197
198 assert(data);
199 assert(data_size);
200 assert(vp8_size);
201 assert(bytes_skipped);
202
203 buf = *data;
204 buf_size = *data_size;
205
206 *vp8_size = 0;
207 *bytes_skipped = 0;
208
209 if (buf == NULL || buf_size < RIFF_HEADER_SIZE) {
210 return VP8_STATUS_NOT_ENOUGH_DATA;
211 } 250 }
212 251
213 // Skip over RIFF header.
214 if (WebPParseRIFF(&buf, &buf_size, &riff_size) != VP8_STATUS_OK) {
215 return VP8_STATUS_BITSTREAM_ERROR; // Wrong RIFF Header.
216 }
217
218 // Skip over VP8X header.
219 status = WebPParseVP8X(&buf, &buf_size, &vp8x_skip_size, NULL, NULL, NULL);
220 if (status != VP8_STATUS_OK) {
221 return status; // Wrong VP8X Chunk / Insufficient data.
222 }
223 if (vp8x_skip_size > 0) {
224 // Skip over optional chunks.
225 status = WebPParseOptionalChunks(&buf, &buf_size, riff_size,
226 &optional_data_size);
227 if (status != VP8_STATUS_OK) {
228 return status; // Found an invalid chunk size / Insufficient data.
229 }
230 }
231
232 // Skip over VP8 chunk header.
233 status = WebPParseVP8Header(&buf, &buf_size, riff_size, &vp8_skip_size,
234 &vp8_size_tmp);
235 if (status != VP8_STATUS_OK) {
236 return status; // Invalid VP8 header / Insufficient data.
237 }
238 if (vp8_skip_size > 0) {
239 *vp8_size = vp8_size_tmp;
240 }
241
242 *bytes_skipped = buf - *data;
243 assert(*bytes_skipped == *data_size - buf_size);
244 *data = buf;
245 *data_size = buf_size;
246 return VP8_STATUS_OK; 252 return VP8_STATUS_OK;
247 } 253 }
248 254
249 //------------------------------------------------------------------------------ 255 //------------------------------------------------------------------------------
256
257 // Fetch '*width', '*height', '*has_alpha' and fill out 'headers' based on
258 // 'data'. All the output parameters may be NULL. If 'headers' is NULL only the
259 // minimal amount will be read to fetch the remaining parameters.
260 // If 'headers' is non-NULL this function will attempt to locate both alpha
261 // data (with or without a VP8X chunk) and the bitstream chunk (VP8/VP8L).
262 // Note: The following chunk sequences (before the raw VP8/VP8L data) are
263 // considered valid by this function:
264 // RIFF + VP8(L)
265 // RIFF + VP8X + (optional chunks) + VP8(L)
266 // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
267 // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
268 static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
269 size_t data_size,
270 int* const width,
271 int* const height,
272 int* const has_alpha,
273 WebPHeaderStructure* const headers) {
274 int found_riff = 0;
275 int found_vp8x = 0;
276 VP8StatusCode status;
277 WebPHeaderStructure hdrs;
278
279 if (data == NULL || data_size < RIFF_HEADER_SIZE) {
280 return VP8_STATUS_NOT_ENOUGH_DATA;
281 }
282 memset(&hdrs, 0, sizeof(hdrs));
283 hdrs.data = data;
284 hdrs.data_size = data_size;
285
286 // Skip over RIFF header.
287 status = ParseRIFF(&data, &data_size, &hdrs.riff_size);
288 if (status != VP8_STATUS_OK) {
289 return status; // Wrong RIFF header / insufficient data.
290 }
291 found_riff = (hdrs.riff_size > 0);
292
293 // Skip over VP8X.
294 {
295 uint32_t flags = 0;
296 status = ParseVP8X(&data, &data_size, &found_vp8x, width, height, &flags);
297 if (status != VP8_STATUS_OK) {
298 return status; // Wrong VP8X / insufficient data.
299 }
300 if (!found_riff && found_vp8x) {
301 // Note: This restriction may be removed in the future, if it becomes
302 // necessary to send VP8X chunk to the decoder.
303 return VP8_STATUS_BITSTREAM_ERROR;
304 }
305 if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG_BIT);
306 if (found_vp8x && headers == NULL) {
307 return VP8_STATUS_OK; // Return features from VP8X header.
308 }
309 }
310
311 if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA;
312
313 // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
314 if ((found_riff && found_vp8x) ||
315 (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) {
316 status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
317 &hdrs.alpha_data, &hdrs.alpha_data_size);
318 if (status != VP8_STATUS_OK) {
319 return status; // Found an invalid chunk size / insufficient data.
320 }
321 }
322
323 // Skip over VP8/VP8L header.
324 status = ParseVP8Header(&data, &data_size, hdrs.riff_size,
325 &hdrs.compressed_size, &hdrs.is_lossless);
326 if (status != VP8_STATUS_OK) {
327 return status; // Wrong VP8/VP8L chunk-header / insufficient data.
328 }
329 if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) {
330 return VP8_STATUS_BITSTREAM_ERROR;
331 }
332
333 if (!hdrs.is_lossless) {
334 if (data_size < VP8_FRAME_HEADER_SIZE) {
335 return VP8_STATUS_NOT_ENOUGH_DATA;
336 }
337 // Validates raw VP8 data.
338 if (!VP8GetInfo(data, data_size,
339 (uint32_t)hdrs.compressed_size, width, height)) {
340 return VP8_STATUS_BITSTREAM_ERROR;
341 }
342 } else {
343 if (data_size < VP8L_FRAME_HEADER_SIZE) {
344 return VP8_STATUS_NOT_ENOUGH_DATA;
345 }
346 // Validates raw VP8L data.
347 if (!VP8LGetInfo(data, data_size, width, height, has_alpha)) {
348 return VP8_STATUS_BITSTREAM_ERROR;
349 }
350 }
351
352 if (has_alpha != NULL) {
353 // If the data did not contain a VP8X/VP8L chunk the only definitive way
354 // to set this is by looking for alpha data (from an ALPH chunk).
355 *has_alpha |= (hdrs.alpha_data != NULL);
356 }
357 if (headers != NULL) {
358 *headers = hdrs;
359 headers->offset = data - headers->data;
360 assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD);
361 assert(headers->offset == headers->data_size - data_size);
362 }
363 return VP8_STATUS_OK; // Return features from VP8 header.
364 }
365
366 VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
367 assert(headers != NULL);
368 // fill out headers, ignore width/height/has_alpha.
369 return ParseHeadersInternal(headers->data, headers->data_size,
370 NULL, NULL, NULL, headers);
371 }
372
373 //------------------------------------------------------------------------------
250 // WebPDecParams 374 // WebPDecParams
251 375
252 void WebPResetDecParams(WebPDecParams* const params) { 376 void WebPResetDecParams(WebPDecParams* const params) {
253 if (params) { 377 if (params) {
254 memset(params, 0, sizeof(*params)); 378 memset(params, 0, sizeof(*params));
255 } 379 }
256 } 380 }
257 381
258 //------------------------------------------------------------------------------ 382 //------------------------------------------------------------------------------
259 // "Into" decoding variants 383 // "Into" decoding variants
260 384
261 // Main flow 385 // Main flow
262 static VP8StatusCode DecodeInto(const uint8_t* data, uint32_t data_size, 386 static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
263 WebPDecParams* const params) { 387 WebPDecParams* const params) {
264 VP8Decoder* dec = VP8New(); 388 VP8StatusCode status;
265 VP8StatusCode status = VP8_STATUS_OK;
266 VP8Io io; 389 VP8Io io;
390 WebPHeaderStructure headers;
267 391
268 assert(params); 392 headers.data = data;
269 if (dec == NULL) { 393 headers.data_size = data_size;
270 return VP8_STATUS_INVALID_PARAM; 394 status = WebPParseHeaders(&headers); // Process Pre-VP8 chunks.
395 if (status != VP8_STATUS_OK) {
396 return status;
271 } 397 }
272 398
399 assert(params != NULL);
273 VP8InitIo(&io); 400 VP8InitIo(&io);
274 io.data = data; 401 io.data = headers.data + headers.offset;
275 io.data_size = data_size; 402 io.data_size = headers.data_size - headers.offset;
276 WebPInitCustomIo(params, &io); // Plug the I/O functions. 403 WebPInitCustomIo(params, &io); // Plug the I/O functions.
277 404
405 if (!headers.is_lossless) {
406 VP8Decoder* const dec = VP8New();
407 if (dec == NULL) {
408 return VP8_STATUS_OUT_OF_MEMORY;
409 }
278 #ifdef WEBP_USE_THREAD 410 #ifdef WEBP_USE_THREAD
279 dec->use_threads_ = params->options && (params->options->use_threads > 0); 411 dec->use_threads_ = params->options && (params->options->use_threads > 0);
280 #else 412 #else
281 dec->use_threads_ = 0; 413 dec->use_threads_ = 0;
282 #endif 414 #endif
415 dec->alpha_data_ = headers.alpha_data;
416 dec->alpha_data_size_ = headers.alpha_data_size;
283 417
284 // Decode bitstream header, update io->width/io->height. 418 // Decode bitstream header, update io->width/io->height.
285 if (!VP8GetHeaders(dec, &io)) { 419 if (!VP8GetHeaders(dec, &io)) {
286 status = VP8_STATUS_BITSTREAM_ERROR; 420 status = dec->status_; // An error occurred. Grab error status.
287 } else { 421 } else {
288 // Allocate/check output buffers. 422 // Allocate/check output buffers.
289 status = WebPAllocateDecBuffer(io.width, io.height, params->options, 423 status = WebPAllocateDecBuffer(io.width, io.height, params->options,
290 params->output); 424 params->output);
291 if (status == VP8_STATUS_OK) { 425 if (status == VP8_STATUS_OK) { // Decode
292 // Decode 426 if (!VP8Decode(dec, &io)) {
293 if (!VP8Decode(dec, &io)) { 427 status = dec->status_;
294 status = dec->status_; 428 }
295 } 429 }
296 } 430 }
431 VP8Delete(dec);
432 } else {
433 VP8LDecoder* const dec = VP8LNew();
434 if (dec == NULL) {
435 return VP8_STATUS_OUT_OF_MEMORY;
436 }
437 if (!VP8LDecodeHeader(dec, &io)) {
438 status = dec->status_; // An error occurred. Grab error status.
439 } else {
440 // Allocate/check output buffers.
441 status = WebPAllocateDecBuffer(io.width, io.height, params->options,
442 params->output);
443 if (status == VP8_STATUS_OK) { // Decode
444 if (!VP8LDecodeImage(dec)) {
445 status = dec->status_;
446 }
447 }
448 }
449 VP8LDelete(dec);
297 } 450 }
298 VP8Delete(dec); 451
299 if (status != VP8_STATUS_OK) { 452 if (status != VP8_STATUS_OK) {
300 WebPFreeDecBuffer(params->output); 453 WebPFreeDecBuffer(params->output);
301 } 454 }
302 return status; 455 return status;
303 } 456 }
304 457
305 // Helpers 458 // Helpers
306 static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace, 459 static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
307 const uint8_t* data, uint32_t data_size, 460 const uint8_t* const data,
308 uint8_t* rgba, int stride, int size) { 461 size_t data_size,
462 uint8_t* const rgba,
463 int stride, size_t size) {
309 WebPDecParams params; 464 WebPDecParams params;
310 WebPDecBuffer buf; 465 WebPDecBuffer buf;
311 if (rgba == NULL) { 466 if (rgba == NULL) {
312 return NULL; 467 return NULL;
313 } 468 }
314 WebPInitDecBuffer(&buf); 469 WebPInitDecBuffer(&buf);
315 WebPResetDecParams(&params); 470 WebPResetDecParams(&params);
316 params.output = &buf; 471 params.output = &buf;
317 buf.colorspace = colorspace; 472 buf.colorspace = colorspace;
318 buf.u.RGBA.rgba = rgba; 473 buf.u.RGBA.rgba = rgba;
319 buf.u.RGBA.stride = stride; 474 buf.u.RGBA.stride = stride;
320 buf.u.RGBA.size = size; 475 buf.u.RGBA.size = size;
321 buf.is_external_memory = 1; 476 buf.is_external_memory = 1;
322 if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) { 477 if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
323 return NULL; 478 return NULL;
324 } 479 }
325 return rgba; 480 return rgba;
326 } 481 }
327 482
328 uint8_t* WebPDecodeRGBInto(const uint8_t* data, uint32_t data_size, 483 uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size,
329 uint8_t* output, int size, int stride) { 484 uint8_t* output, size_t size, int stride) {
330 return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size); 485 return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size);
331 } 486 }
332 487
333 uint8_t* WebPDecodeRGBAInto(const uint8_t* data, uint32_t data_size, 488 uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size,
334 uint8_t* output, int size, int stride) { 489 uint8_t* output, size_t size, int stride) {
335 return DecodeIntoRGBABuffer(MODE_RGBA, data, data_size, output, stride, size); 490 return DecodeIntoRGBABuffer(MODE_RGBA, data, data_size, output, stride, size);
336 } 491 }
337 492
338 uint8_t* WebPDecodeARGBInto(const uint8_t* data, uint32_t data_size, 493 uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size,
339 uint8_t* output, int size, int stride) { 494 uint8_t* output, size_t size, int stride) {
340 return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size); 495 return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size);
341 } 496 }
342 497
343 uint8_t* WebPDecodeBGRInto(const uint8_t* data, uint32_t data_size, 498 uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size,
344 uint8_t* output, int size, int stride) { 499 uint8_t* output, size_t size, int stride) {
345 return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size); 500 return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size);
346 } 501 }
347 502
348 uint8_t* WebPDecodeBGRAInto(const uint8_t* data, uint32_t data_size, 503 uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size,
349 uint8_t* output, int size, int stride) { 504 uint8_t* output, size_t size, int stride) {
350 return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size); 505 return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size);
351 } 506 }
352 507
353 uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size, 508 uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
354 uint8_t* luma, int luma_size, int luma_stride, 509 uint8_t* luma, size_t luma_size, int luma_stride,
355 uint8_t* u, int u_size, int u_stride, 510 uint8_t* u, size_t u_size, int u_stride,
356 uint8_t* v, int v_size, int v_stride) { 511 uint8_t* v, size_t v_size, int v_stride) {
357 WebPDecParams params; 512 WebPDecParams params;
358 WebPDecBuffer output; 513 WebPDecBuffer output;
359 if (luma == NULL) return NULL; 514 if (luma == NULL) return NULL;
360 WebPInitDecBuffer(&output); 515 WebPInitDecBuffer(&output);
361 WebPResetDecParams(&params); 516 WebPResetDecParams(&params);
362 params.output = &output; 517 params.output = &output;
363 output.colorspace = MODE_YUV; 518 output.colorspace = MODE_YUV;
364 output.u.YUVA.y = luma; 519 output.u.YUVA.y = luma;
365 output.u.YUVA.y_stride = luma_stride; 520 output.u.YUVA.y_stride = luma_stride;
366 output.u.YUVA.y_size = luma_size; 521 output.u.YUVA.y_size = luma_size;
367 output.u.YUVA.u = u; 522 output.u.YUVA.u = u;
368 output.u.YUVA.u_stride = u_stride; 523 output.u.YUVA.u_stride = u_stride;
369 output.u.YUVA.u_size = u_size; 524 output.u.YUVA.u_size = u_size;
370 output.u.YUVA.v = v; 525 output.u.YUVA.v = v;
371 output.u.YUVA.v_stride = v_stride; 526 output.u.YUVA.v_stride = v_stride;
372 output.u.YUVA.v_size = v_size; 527 output.u.YUVA.v_size = v_size;
373 output.is_external_memory = 1; 528 output.is_external_memory = 1;
374 if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) { 529 if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
375 return NULL; 530 return NULL;
376 } 531 }
377 return luma; 532 return luma;
378 } 533 }
379 534
380 //------------------------------------------------------------------------------ 535 //------------------------------------------------------------------------------
381 536
382 static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* data, 537 static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* const data,
383 uint32_t data_size, int* width, int* height, 538 size_t data_size, int* const width, int* const height,
384 WebPDecBuffer* keep_info) { 539 WebPDecBuffer* const keep_info) {
385 WebPDecParams params; 540 WebPDecParams params;
386 WebPDecBuffer output; 541 WebPDecBuffer output;
387 542
388 WebPInitDecBuffer(&output); 543 WebPInitDecBuffer(&output);
389 WebPResetDecParams(&params); 544 WebPResetDecParams(&params);
390 params.output = &output; 545 params.output = &output;
391 output.colorspace = mode; 546 output.colorspace = mode;
392 547
393 // Retrieve (and report back) the required dimensions from bitstream. 548 // Retrieve (and report back) the required dimensions from bitstream.
394 if (!WebPGetInfo(data, data_size, &output.width, &output.height)) { 549 if (!WebPGetInfo(data, data_size, &output.width, &output.height)) {
395 return NULL; 550 return NULL;
396 } 551 }
397 if (width) *width = output.width; 552 if (width != NULL) *width = output.width;
398 if (height) *height = output.height; 553 if (height != NULL) *height = output.height;
399 554
400 // Decode 555 // Decode
401 if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) { 556 if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
402 return NULL; 557 return NULL;
403 } 558 }
404 if (keep_info) { // keep track of the side-info 559 if (keep_info != NULL) { // keep track of the side-info
405 WebPCopyDecBuffer(&output, keep_info); 560 WebPCopyDecBuffer(&output, keep_info);
406 } 561 }
407 // return decoded samples (don't clear 'output'!) 562 // return decoded samples (don't clear 'output'!)
408 return (mode >= MODE_YUV) ? output.u.YUVA.y : output.u.RGBA.rgba; 563 return WebPIsRGBMode(mode) ? output.u.RGBA.rgba : output.u.YUVA.y;
409 } 564 }
410 565
411 uint8_t* WebPDecodeRGB(const uint8_t* data, uint32_t data_size, 566 uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
412 int* width, int* height) { 567 int* width, int* height) {
413 return Decode(MODE_RGB, data, data_size, width, height, NULL); 568 return Decode(MODE_RGB, data, data_size, width, height, NULL);
414 } 569 }
415 570
416 uint8_t* WebPDecodeRGBA(const uint8_t* data, uint32_t data_size, 571 uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
417 int* width, int* height) { 572 int* width, int* height) {
418 return Decode(MODE_RGBA, data, data_size, width, height, NULL); 573 return Decode(MODE_RGBA, data, data_size, width, height, NULL);
419 } 574 }
420 575
421 uint8_t* WebPDecodeARGB(const uint8_t* data, uint32_t data_size, 576 uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size,
422 int* width, int* height) { 577 int* width, int* height) {
423 return Decode(MODE_ARGB, data, data_size, width, height, NULL); 578 return Decode(MODE_ARGB, data, data_size, width, height, NULL);
424 } 579 }
425 580
426 uint8_t* WebPDecodeBGR(const uint8_t* data, uint32_t data_size, 581 uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
427 int* width, int* height) { 582 int* width, int* height) {
428 return Decode(MODE_BGR, data, data_size, width, height, NULL); 583 return Decode(MODE_BGR, data, data_size, width, height, NULL);
429 } 584 }
430 585
431 uint8_t* WebPDecodeBGRA(const uint8_t* data, uint32_t data_size, 586 uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
432 int* width, int* height) { 587 int* width, int* height) {
433 return Decode(MODE_BGRA, data, data_size, width, height, NULL); 588 return Decode(MODE_BGRA, data, data_size, width, height, NULL);
434 } 589 }
435 590
436 uint8_t* WebPDecodeYUV(const uint8_t* data, uint32_t data_size, 591 uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
437 int* width, int* height, uint8_t** u, uint8_t** v, 592 int* width, int* height, uint8_t** u, uint8_t** v,
438 int* stride, int* uv_stride) { 593 int* stride, int* uv_stride) {
439 WebPDecBuffer output; // only to preserve the side-infos 594 WebPDecBuffer output; // only to preserve the side-infos
440 uint8_t* const out = Decode(MODE_YUV, data, data_size, 595 uint8_t* const out = Decode(MODE_YUV, data, data_size,
441 width, height, &output); 596 width, height, &output);
442 597
443 if (out) { 598 if (out != NULL) {
444 const WebPYUVABuffer* const buf = &output.u.YUVA; 599 const WebPYUVABuffer* const buf = &output.u.YUVA;
445 *u = buf->u; 600 *u = buf->u;
446 *v = buf->v; 601 *v = buf->v;
447 *stride = buf->y_stride; 602 *stride = buf->y_stride;
448 *uv_stride = buf->u_stride; 603 *uv_stride = buf->u_stride;
449 assert(buf->u_stride == buf->v_stride); 604 assert(buf->u_stride == buf->v_stride);
450 } 605 }
451 return out; 606 return out;
452 } 607 }
453 608
454 static void DefaultFeatures(WebPBitstreamFeatures* const features) { 609 static void DefaultFeatures(WebPBitstreamFeatures* const features) {
455 assert(features); 610 assert(features != NULL);
456 memset(features, 0, sizeof(*features)); 611 memset(features, 0, sizeof(*features));
457 features->bitstream_version = 0; 612 features->bitstream_version = 0;
458 } 613 }
459 614
460 static VP8StatusCode GetFeatures(const uint8_t* data, uint32_t data_size, 615 static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
461 WebPBitstreamFeatures* const features) { 616 WebPBitstreamFeatures* const features) {
462 uint32_t vp8_chunk_size = 0; 617 if (features == NULL || data == NULL) {
463 uint32_t riff_size = 0;
464 uint32_t flags = 0;
465 uint32_t vp8x_skip_size = 0;
466 uint32_t vp8_skip_size = 0;
467 VP8StatusCode status;
468
469 if (features == NULL) {
470 return VP8_STATUS_INVALID_PARAM; 618 return VP8_STATUS_INVALID_PARAM;
471 } 619 }
472 DefaultFeatures(features); 620 DefaultFeatures(features);
473 621
474 if (data == NULL) { 622 // Only parse enough of the data to retrieve width/height/has_alpha.
475 return VP8_STATUS_INVALID_PARAM; 623 return ParseHeadersInternal(data, data_size,
476 } 624 &features->width, &features->height,
477 625 &features->has_alpha, NULL);
478 // Skip over RIFF header.
479 status = WebPParseRIFF(&data, &data_size, &riff_size);
480 if (status != VP8_STATUS_OK) {
481 return status; // Wrong RIFF Header / Insufficient data.
482 }
483
484 // Skip over VP8X.
485 status = WebPParseVP8X(&data, &data_size, &vp8x_skip_size, &features->width,
486 &features->height, &flags);
487 if (status != VP8_STATUS_OK) {
488 return status; // Wrong VP8X / insufficient data.
489
490 }
491 if (vp8x_skip_size > 0) {
492 return VP8_STATUS_OK; // Return features from VP8X header.
493 }
494
495 // Skip over VP8 header.
496 status = WebPParseVP8Header(&data, &data_size, riff_size, &vp8_skip_size,
497 &vp8_chunk_size);
498 if (status != VP8_STATUS_OK) {
499 return status; // Wrong VP8 Chunk-header / insufficient data.
500 }
501 if (vp8_skip_size == 0) {
502 vp8_chunk_size = data_size; // No VP8 chunk wrapper over raw VP8 data.
503 }
504
505 // Validates raw VP8 data.
506 if (!VP8GetInfo(data, data_size, vp8_chunk_size,
507 &features->width, &features->height, &features->has_alpha)) {
508 return VP8_STATUS_BITSTREAM_ERROR;
509 }
510
511 return VP8_STATUS_OK; // Return features from VP8 header.
512 } 626 }
513 627
514 //------------------------------------------------------------------------------ 628 //------------------------------------------------------------------------------
515 // WebPGetInfo() 629 // WebPGetInfo()
516 630
517 int WebPGetInfo(const uint8_t* data, uint32_t data_size, 631 int WebPGetInfo(const uint8_t* data, size_t data_size,
518 int* width, int* height) { 632 int* width, int* height) {
519 WebPBitstreamFeatures features; 633 WebPBitstreamFeatures features;
520 634
521 if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) { 635 if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) {
522 return 0; 636 return 0;
523 } 637 }
524 638
525 if (width) { 639 if (width != NULL) {
526 *width = features.width; 640 *width = features.width;
527 } 641 }
528 if (height) { 642 if (height != NULL) {
529 *height = features.height; 643 *height = features.height;
530 } 644 }
531 645
532 return 1; 646 return 1;
533 } 647 }
534 648
535 //------------------------------------------------------------------------------ 649 //------------------------------------------------------------------------------
536 // Advance decoding API 650 // Advance decoding API
537 651
538 int WebPInitDecoderConfigInternal(WebPDecoderConfig* const config, 652 int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
539 int version) { 653 int version) {
540 if (version != WEBP_DECODER_ABI_VERSION) { 654 if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
541 return 0; // version mismatch 655 return 0; // version mismatch
542 } 656 }
543 if (config == NULL) { 657 if (config == NULL) {
544 return 0; 658 return 0;
545 } 659 }
546 memset(config, 0, sizeof(*config)); 660 memset(config, 0, sizeof(*config));
547 DefaultFeatures(&config->input); 661 DefaultFeatures(&config->input);
548 WebPInitDecBuffer(&config->output); 662 WebPInitDecBuffer(&config->output);
549 return 1; 663 return 1;
550 } 664 }
551 665
552 VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, uint32_t data_size, 666 VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size,
553 WebPBitstreamFeatures* const features, 667 WebPBitstreamFeatures* features,
554 int version) { 668 int version) {
555 VP8StatusCode status; 669 VP8StatusCode status;
556 if (version != WEBP_DECODER_ABI_VERSION) { 670 if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
557 return VP8_STATUS_INVALID_PARAM; // version mismatch 671 return VP8_STATUS_INVALID_PARAM; // version mismatch
558 } 672 }
559 if (features == NULL) { 673 if (features == NULL) {
560 return VP8_STATUS_INVALID_PARAM; 674 return VP8_STATUS_INVALID_PARAM;
561 } 675 }
562 676
563 status = GetFeatures(data, data_size, features); 677 status = GetFeatures(data, data_size, features);
564 if (status == VP8_STATUS_NOT_ENOUGH_DATA) { 678 if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
565 return VP8_STATUS_BITSTREAM_ERROR; // Not enough data treated as error. 679 return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error.
566 } 680 }
567 return status; 681 return status;
568 } 682 }
569 683
570 VP8StatusCode WebPDecode(const uint8_t* data, uint32_t data_size, 684 VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
571 WebPDecoderConfig* const config) { 685 WebPDecoderConfig* config) {
572 WebPDecParams params; 686 WebPDecParams params;
573 VP8StatusCode status; 687 VP8StatusCode status;
574 688
575 if (!config) { 689 if (config == NULL) {
576 return VP8_STATUS_INVALID_PARAM; 690 return VP8_STATUS_INVALID_PARAM;
577 } 691 }
578 692
579 status = GetFeatures(data, data_size, &config->input); 693 status = GetFeatures(data, data_size, &config->input);
580 if (status != VP8_STATUS_OK) { 694 if (status != VP8_STATUS_OK) {
581 if (status == VP8_STATUS_NOT_ENOUGH_DATA) { 695 if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
582 return VP8_STATUS_BITSTREAM_ERROR; // Not enough data treated as error. 696 return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error.
583 } 697 }
584 return status; 698 return status;
585 } 699 }
586 700
587 WebPResetDecParams(&params); 701 WebPResetDecParams(&params);
588 params.output = &config->output; 702 params.output = &config->output;
589 params.options = &config->options; 703 params.options = &config->options;
590 status = DecodeInto(data, data_size, &params); 704 status = DecodeInto(data, data_size, &params);
591 705
592 return status; 706 return status;
593 } 707 }
594 708
709 //------------------------------------------------------------------------------
710 // Cropping and rescaling.
711
712 int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
713 VP8Io* const io, WEBP_CSP_MODE src_colorspace) {
714 const int W = io->width;
715 const int H = io->height;
716 int x = 0, y = 0, w = W, h = H;
717
718 // Cropping
719 io->use_cropping = (options != NULL) && (options->use_cropping > 0);
720 if (io->use_cropping) {
721 w = options->crop_width;
722 h = options->crop_height;
723 x = options->crop_left;
724 y = options->crop_top;
725 if (!WebPIsRGBMode(src_colorspace)) { // only snap for YUV420 or YUV422
726 x &= ~1;
727 y &= ~1; // TODO(later): only for YUV420, not YUV422.
728 }
729 if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
730 return 0; // out of frame boundary error
731 }
732 }
733 io->crop_left = x;
734 io->crop_top = y;
735 io->crop_right = x + w;
736 io->crop_bottom = y + h;
737 io->mb_w = w;
738 io->mb_h = h;
739
740 // Scaling
741 io->use_scaling = (options != NULL) && (options->use_scaling > 0);
742 if (io->use_scaling) {
743 if (options->scaled_width <= 0 || options->scaled_height <= 0) {
744 return 0;
745 }
746 io->scaled_width = options->scaled_width;
747 io->scaled_height = options->scaled_height;
748 }
749
750 // Filter
751 io->bypass_filtering = options && options->bypass_filtering;
752
753 // Fancy upsampler
754 #ifdef FANCY_UPSAMPLING
755 io->fancy_upsampling = (options == NULL) || (!options->no_fancy_upsampling);
756 #endif
757
758 if (io->use_scaling) {
759 // disable filter (only for large downscaling ratio).
760 io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
761 (io->scaled_height < H * 3 / 4);
762 io->fancy_upsampling = 0;
763 }
764 return 1;
765 }
766
767 //------------------------------------------------------------------------------
768
595 #if defined(__cplusplus) || defined(c_plusplus) 769 #if defined(__cplusplus) || defined(c_plusplus)
596 } // extern "C" 770 } // extern "C"
597 #endif 771 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698