OLD | NEW |
1 // Copyright 2010 Google Inc. All Rights Reserved. | 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 | 13 |
14 #include "./vp8i.h" | 14 #include "./vp8i.h" |
15 #include "./vp8li.h" | 15 #include "./vp8li.h" |
16 #include "./webpi.h" | 16 #include "./webpi.h" |
17 #include "../webp/format_constants.h" | 17 #include "../webp/mux_types.h" // ALPHA_FLAG |
18 | 18 |
19 #if defined(__cplusplus) || defined(c_plusplus) | 19 #if defined(__cplusplus) || defined(c_plusplus) |
20 extern "C" { | 20 extern "C" { |
21 #endif | 21 #endif |
22 | 22 |
23 //------------------------------------------------------------------------------ | 23 //------------------------------------------------------------------------------ |
24 // RIFF layout is: | 24 // RIFF layout is: |
25 // Offset tag | 25 // Offset tag |
26 // 0...3 "RIFF" 4-byte tag | 26 // 0...3 "RIFF" 4-byte tag |
27 // 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 |
28 // 8...11 "WEBP" our form-type signature | 28 // 8...11 "WEBP" our form-type signature |
29 // The RIFF container (12 bytes) is followed by appropriate chunks: | 29 // The RIFF container (12 bytes) is followed by appropriate chunks: |
30 // 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format | 30 // 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format |
31 // 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 |
32 // 20.... the VP8 bytes | 32 // 20.... the VP8 bytes |
33 // Or, | 33 // Or, |
34 // 12..15 "VP8L": 4-bytes tags, signaling the use of VP8L lossless format | 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 | 35 // 16..19 size of the raw VP8L image data, starting at offset 20 |
36 // 20.... the VP8L bytes | 36 // 20.... the VP8L bytes |
37 // Or, | 37 // Or, |
38 // 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk. | 38 // 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk. |
39 // 16..19 size of the VP8X chunk starting at offset 20. | 39 // 16..19 size of the VP8X chunk starting at offset 20. |
40 // 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. |
41 // 24..26 Width of the Canvas Image. | 41 // 24..26 Width of the Canvas Image. |
42 // 27..29 Height of the Canvas Image. | 42 // 27..29 Height of the Canvas Image. |
43 // There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8, | 43 // There can be extra chunks after the "VP8X" chunk (ICCP, FRGM, ANMF, VP8, |
44 // META ...) | 44 // VP8L, XMP, EXIF ...) |
45 // All sizes are in little-endian order. | 45 // All sizes are in little-endian order. |
46 // Note: chunk data size must be padded to multiple of 2 when written. | 46 // Note: chunk data size must be padded to multiple of 2 when written. |
47 | 47 |
48 static WEBP_INLINE uint32_t get_le24(const uint8_t* const data) { | 48 static WEBP_INLINE uint32_t get_le24(const uint8_t* const data) { |
49 return data[0] | (data[1] << 8) | (data[2] << 16); | 49 return data[0] | (data[1] << 8) | (data[2] << 16); |
50 } | 50 } |
51 | 51 |
52 static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) { | 52 static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) { |
53 return (uint32_t)get_le24(data) | (data[3] << 24); | 53 return (uint32_t)get_le24(data) | (data[3] << 24); |
54 } | 54 } |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 // considered valid by this function: | 269 // considered valid by this function: |
270 // RIFF + VP8(L) | 270 // RIFF + VP8(L) |
271 // RIFF + VP8X + (optional chunks) + VP8(L) | 271 // RIFF + VP8X + (optional chunks) + VP8(L) |
272 // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. | 272 // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. |
273 // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. | 273 // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. |
274 static VP8StatusCode ParseHeadersInternal(const uint8_t* data, | 274 static VP8StatusCode ParseHeadersInternal(const uint8_t* data, |
275 size_t data_size, | 275 size_t data_size, |
276 int* const width, | 276 int* const width, |
277 int* const height, | 277 int* const height, |
278 int* const has_alpha, | 278 int* const has_alpha, |
| 279 int* const has_animation, |
279 WebPHeaderStructure* const headers) { | 280 WebPHeaderStructure* const headers) { |
280 int found_riff = 0; | 281 int found_riff = 0; |
281 int found_vp8x = 0; | 282 int found_vp8x = 0; |
282 VP8StatusCode status; | 283 VP8StatusCode status; |
283 WebPHeaderStructure hdrs; | 284 WebPHeaderStructure hdrs; |
284 | 285 |
285 if (data == NULL || data_size < RIFF_HEADER_SIZE) { | 286 if (data == NULL || data_size < RIFF_HEADER_SIZE) { |
286 return VP8_STATUS_NOT_ENOUGH_DATA; | 287 return VP8_STATUS_NOT_ENOUGH_DATA; |
287 } | 288 } |
288 memset(&hdrs, 0, sizeof(hdrs)); | 289 memset(&hdrs, 0, sizeof(hdrs)); |
(...skipping 12 matching lines...) Expand all Loading... |
301 uint32_t flags = 0; | 302 uint32_t flags = 0; |
302 status = ParseVP8X(&data, &data_size, &found_vp8x, width, height, &flags); | 303 status = ParseVP8X(&data, &data_size, &found_vp8x, width, height, &flags); |
303 if (status != VP8_STATUS_OK) { | 304 if (status != VP8_STATUS_OK) { |
304 return status; // Wrong VP8X / insufficient data. | 305 return status; // Wrong VP8X / insufficient data. |
305 } | 306 } |
306 if (!found_riff && found_vp8x) { | 307 if (!found_riff && found_vp8x) { |
307 // Note: This restriction may be removed in the future, if it becomes | 308 // Note: This restriction may be removed in the future, if it becomes |
308 // necessary to send VP8X chunk to the decoder. | 309 // necessary to send VP8X chunk to the decoder. |
309 return VP8_STATUS_BITSTREAM_ERROR; | 310 return VP8_STATUS_BITSTREAM_ERROR; |
310 } | 311 } |
311 if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG_BIT); | 312 if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG); |
| 313 if (has_animation != NULL) *has_animation = !!(flags & ANIMATION_FLAG); |
312 if (found_vp8x && headers == NULL) { | 314 if (found_vp8x && headers == NULL) { |
313 return VP8_STATUS_OK; // Return features from VP8X header. | 315 return VP8_STATUS_OK; // Return features from VP8X header. |
314 } | 316 } |
315 } | 317 } |
316 | 318 |
317 if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA; | 319 if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA; |
318 | 320 |
319 // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH". | 321 // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH". |
320 if ((found_riff && found_vp8x) || | 322 if ((found_riff && found_vp8x) || |
321 (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) { | 323 (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 if (headers != NULL) { | 365 if (headers != NULL) { |
364 *headers = hdrs; | 366 *headers = hdrs; |
365 headers->offset = data - headers->data; | 367 headers->offset = data - headers->data; |
366 assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD); | 368 assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD); |
367 assert(headers->offset == headers->data_size - data_size); | 369 assert(headers->offset == headers->data_size - data_size); |
368 } | 370 } |
369 return VP8_STATUS_OK; // Return features from VP8 header. | 371 return VP8_STATUS_OK; // Return features from VP8 header. |
370 } | 372 } |
371 | 373 |
372 VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) { | 374 VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) { |
| 375 VP8StatusCode status; |
| 376 int has_animation = 0; |
373 assert(headers != NULL); | 377 assert(headers != NULL); |
374 // fill out headers, ignore width/height/has_alpha. | 378 // fill out headers, ignore width/height/has_alpha. |
375 return ParseHeadersInternal(headers->data, headers->data_size, | 379 status = ParseHeadersInternal(headers->data, headers->data_size, |
376 NULL, NULL, NULL, headers); | 380 NULL, NULL, NULL, &has_animation, headers); |
| 381 if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) { |
| 382 // TODO(jzern): full support of animation frames will require API additions. |
| 383 if (has_animation) { |
| 384 status = VP8_STATUS_UNSUPPORTED_FEATURE; |
| 385 } |
| 386 } |
| 387 return status; |
377 } | 388 } |
378 | 389 |
379 //------------------------------------------------------------------------------ | 390 //------------------------------------------------------------------------------ |
380 // WebPDecParams | 391 // WebPDecParams |
381 | 392 |
382 void WebPResetDecParams(WebPDecParams* const params) { | 393 void WebPResetDecParams(WebPDecParams* const params) { |
383 if (params) { | 394 if (params) { |
384 memset(params, 0, sizeof(*params)); | 395 memset(params, 0, sizeof(*params)); |
385 } | 396 } |
386 } | 397 } |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 features->bitstream_version = 0; | 629 features->bitstream_version = 0; |
619 } | 630 } |
620 | 631 |
621 static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size, | 632 static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size, |
622 WebPBitstreamFeatures* const features) { | 633 WebPBitstreamFeatures* const features) { |
623 if (features == NULL || data == NULL) { | 634 if (features == NULL || data == NULL) { |
624 return VP8_STATUS_INVALID_PARAM; | 635 return VP8_STATUS_INVALID_PARAM; |
625 } | 636 } |
626 DefaultFeatures(features); | 637 DefaultFeatures(features); |
627 | 638 |
628 // Only parse enough of the data to retrieve width/height/has_alpha. | 639 // Only parse enough of the data to retrieve the features. |
629 return ParseHeadersInternal(data, data_size, | 640 return ParseHeadersInternal(data, data_size, |
630 &features->width, &features->height, | 641 &features->width, &features->height, |
631 &features->has_alpha, NULL); | 642 &features->has_alpha, &features->has_animation, |
| 643 NULL); |
632 } | 644 } |
633 | 645 |
634 //------------------------------------------------------------------------------ | 646 //------------------------------------------------------------------------------ |
635 // WebPGetInfo() | 647 // WebPGetInfo() |
636 | 648 |
637 int WebPGetInfo(const uint8_t* data, size_t data_size, | 649 int WebPGetInfo(const uint8_t* data, size_t data_size, |
638 int* width, int* height) { | 650 int* width, int* height) { |
639 WebPBitstreamFeatures features; | 651 WebPBitstreamFeatures features; |
640 | 652 |
641 if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) { | 653 if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) { |
(...skipping 23 matching lines...) Expand all Loading... |
665 } | 677 } |
666 memset(config, 0, sizeof(*config)); | 678 memset(config, 0, sizeof(*config)); |
667 DefaultFeatures(&config->input); | 679 DefaultFeatures(&config->input); |
668 WebPInitDecBuffer(&config->output); | 680 WebPInitDecBuffer(&config->output); |
669 return 1; | 681 return 1; |
670 } | 682 } |
671 | 683 |
672 VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size, | 684 VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size, |
673 WebPBitstreamFeatures* features, | 685 WebPBitstreamFeatures* features, |
674 int version) { | 686 int version) { |
675 VP8StatusCode status; | |
676 if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { | 687 if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { |
677 return VP8_STATUS_INVALID_PARAM; // version mismatch | 688 return VP8_STATUS_INVALID_PARAM; // version mismatch |
678 } | 689 } |
679 if (features == NULL) { | 690 if (features == NULL) { |
680 return VP8_STATUS_INVALID_PARAM; | 691 return VP8_STATUS_INVALID_PARAM; |
681 } | 692 } |
682 | 693 return GetFeatures(data, data_size, features); |
683 status = GetFeatures(data, data_size, features); | |
684 if (status == VP8_STATUS_NOT_ENOUGH_DATA) { | |
685 return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error. | |
686 } | |
687 return status; | |
688 } | 694 } |
689 | 695 |
690 VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size, | 696 VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size, |
691 WebPDecoderConfig* config) { | 697 WebPDecoderConfig* config) { |
692 WebPDecParams params; | 698 WebPDecParams params; |
693 VP8StatusCode status; | 699 VP8StatusCode status; |
694 | 700 |
695 if (config == NULL) { | 701 if (config == NULL) { |
696 return VP8_STATUS_INVALID_PARAM; | 702 return VP8_STATUS_INVALID_PARAM; |
697 } | 703 } |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
768 io->fancy_upsampling = 0; | 774 io->fancy_upsampling = 0; |
769 } | 775 } |
770 return 1; | 776 return 1; |
771 } | 777 } |
772 | 778 |
773 //------------------------------------------------------------------------------ | 779 //------------------------------------------------------------------------------ |
774 | 780 |
775 #if defined(__cplusplus) || defined(c_plusplus) | 781 #if defined(__cplusplus) || defined(c_plusplus) |
776 } // extern "C" | 782 } // extern "C" |
777 #endif | 783 #endif |
OLD | NEW |