| 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 |