| OLD | NEW |
| 1 // Copyright 2010 Google Inc. All Rights Reserved. | 1 // Copyright 2010 Google Inc. All Rights Reserved. |
| 2 // | 2 // |
| 3 // Use of this source code is governed by a BSD-style license | 3 // Use of this source code is governed by a BSD-style license |
| 4 // that can be found in the COPYING file in the root of the source | 4 // that can be found in the COPYING file in the root of the source |
| 5 // tree. An additional intellectual property rights grant can be found | 5 // tree. An additional intellectual property rights grant can be found |
| 6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
| 7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
| 8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
| 9 // | 9 // |
| 10 // Main decoding functions for WEBP images. | 10 // Main decoding functions for WEBP images. |
| 11 // | 11 // |
| 12 // Author: Skal (pascal.massimino@gmail.com) | 12 // Author: Skal (pascal.massimino@gmail.com) |
| 13 | 13 |
| 14 #include <stdlib.h> | 14 #include <stdlib.h> |
| 15 | 15 |
| 16 #include "./vp8i.h" | 16 #include "./vp8i_dec.h" |
| 17 #include "./vp8li.h" | 17 #include "./vp8li_dec.h" |
| 18 #include "./webpi.h" | 18 #include "./webpi_dec.h" |
| 19 #include "../utils/utils.h" | 19 #include "../utils/utils.h" |
| 20 #include "../webp/mux_types.h" // ALPHA_FLAG | 20 #include "../webp/mux_types.h" // ALPHA_FLAG |
| 21 | 21 |
| 22 //------------------------------------------------------------------------------ | 22 //------------------------------------------------------------------------------ |
| 23 // RIFF layout is: | 23 // RIFF layout is: |
| 24 // Offset tag | 24 // Offset tag |
| 25 // 0...3 "RIFF" 4-byte tag | 25 // 0...3 "RIFF" 4-byte tag |
| 26 // 4...7 size of image data (including metadata) starting at offset 8 | 26 // 4...7 size of image data (including metadata) starting at offset 8 |
| 27 // 8...11 "WEBP" our form-type signature | 27 // 8...11 "WEBP" our form-type signature |
| 28 // The RIFF container (12 bytes) is followed by appropriate chunks: | 28 // The RIFF container (12 bytes) is followed by appropriate chunks: |
| 29 // 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format | 29 // 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format |
| 30 // 16..19 size of the raw VP8 image data, starting at offset 20 | 30 // 16..19 size of the raw VP8 image data, starting at offset 20 |
| 31 // 20.... the VP8 bytes | 31 // 20.... the VP8 bytes |
| 32 // Or, | 32 // Or, |
| 33 // 12..15 "VP8L": 4-bytes tags, signaling the use of VP8L lossless format | 33 // 12..15 "VP8L": 4-bytes tags, signaling the use of VP8L lossless format |
| 34 // 16..19 size of the raw VP8L image data, starting at offset 20 | 34 // 16..19 size of the raw VP8L image data, starting at offset 20 |
| 35 // 20.... the VP8L bytes | 35 // 20.... the VP8L bytes |
| 36 // Or, | 36 // Or, |
| 37 // 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk. | 37 // 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk. |
| 38 // 16..19 size of the VP8X chunk starting at offset 20. | 38 // 16..19 size of the VP8X chunk starting at offset 20. |
| 39 // 20..23 VP8X flags bit-map corresponding to the chunk-types present. | 39 // 20..23 VP8X flags bit-map corresponding to the chunk-types present. |
| 40 // 24..26 Width of the Canvas Image. | 40 // 24..26 Width of the Canvas Image. |
| 41 // 27..29 Height of the Canvas Image. | 41 // 27..29 Height of the Canvas Image. |
| 42 // There can be extra chunks after the "VP8X" chunk (ICCP, FRGM, ANMF, VP8, | 42 // There can be extra chunks after the "VP8X" chunk (ICCP, ANMF, VP8, VP8L, |
| 43 // VP8L, XMP, EXIF ...) | 43 // XMP, EXIF ...) |
| 44 // All sizes are in little-endian order. | 44 // All sizes are in little-endian order. |
| 45 // Note: chunk data size must be padded to multiple of 2 when written. | 45 // Note: chunk data size must be padded to multiple of 2 when written. |
| 46 | 46 |
| 47 // Validates the RIFF container (if detected) and skips over it. | 47 // Validates the RIFF container (if detected) and skips over it. |
| 48 // If a RIFF container is detected, returns: | 48 // If a RIFF container is detected, returns: |
| 49 // VP8_STATUS_BITSTREAM_ERROR for invalid header, | 49 // VP8_STATUS_BITSTREAM_ERROR for invalid header, |
| 50 // VP8_STATUS_NOT_ENOUGH_DATA for truncated data if have_all_data is true, | 50 // VP8_STATUS_NOT_ENOUGH_DATA for truncated data if have_all_data is true, |
| 51 // and VP8_STATUS_OK otherwise. | 51 // and VP8_STATUS_OK otherwise. |
| 52 // In case there are not enough bytes (partial RIFF container), return 0 for | 52 // In case there are not enough bytes (partial RIFF container), return 0 for |
| 53 // *riff_size. Else return the RIFF size extracted from the header. | 53 // *riff_size. Else return the RIFF size extracted from the header. |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 int* const has_animation, | 282 int* const has_animation, |
| 283 int* const format, | 283 int* const format, |
| 284 WebPHeaderStructure* const headers) { | 284 WebPHeaderStructure* const headers) { |
| 285 int canvas_width = 0; | 285 int canvas_width = 0; |
| 286 int canvas_height = 0; | 286 int canvas_height = 0; |
| 287 int image_width = 0; | 287 int image_width = 0; |
| 288 int image_height = 0; | 288 int image_height = 0; |
| 289 int found_riff = 0; | 289 int found_riff = 0; |
| 290 int found_vp8x = 0; | 290 int found_vp8x = 0; |
| 291 int animation_present = 0; | 291 int animation_present = 0; |
| 292 int fragments_present = 0; | |
| 293 const int have_all_data = (headers != NULL) ? headers->have_all_data : 0; | 292 const int have_all_data = (headers != NULL) ? headers->have_all_data : 0; |
| 294 | 293 |
| 295 VP8StatusCode status; | 294 VP8StatusCode status; |
| 296 WebPHeaderStructure hdrs; | 295 WebPHeaderStructure hdrs; |
| 297 | 296 |
| 298 if (data == NULL || data_size < RIFF_HEADER_SIZE) { | 297 if (data == NULL || data_size < RIFF_HEADER_SIZE) { |
| 299 return VP8_STATUS_NOT_ENOUGH_DATA; | 298 return VP8_STATUS_NOT_ENOUGH_DATA; |
| 300 } | 299 } |
| 301 memset(&hdrs, 0, sizeof(hdrs)); | 300 memset(&hdrs, 0, sizeof(hdrs)); |
| 302 hdrs.data = data; | 301 hdrs.data = data; |
| 303 hdrs.data_size = data_size; | 302 hdrs.data_size = data_size; |
| 304 | 303 |
| 305 // Skip over RIFF header. | 304 // Skip over RIFF header. |
| 306 status = ParseRIFF(&data, &data_size, have_all_data, &hdrs.riff_size); | 305 status = ParseRIFF(&data, &data_size, have_all_data, &hdrs.riff_size); |
| 307 if (status != VP8_STATUS_OK) { | 306 if (status != VP8_STATUS_OK) { |
| 308 return status; // Wrong RIFF header / insufficient data. | 307 return status; // Wrong RIFF header / insufficient data. |
| 309 } | 308 } |
| 310 found_riff = (hdrs.riff_size > 0); | 309 found_riff = (hdrs.riff_size > 0); |
| 311 | 310 |
| 312 // Skip over VP8X. | 311 // Skip over VP8X. |
| 313 { | 312 { |
| 314 uint32_t flags = 0; | 313 uint32_t flags = 0; |
| 315 status = ParseVP8X(&data, &data_size, &found_vp8x, | 314 status = ParseVP8X(&data, &data_size, &found_vp8x, |
| 316 &canvas_width, &canvas_height, &flags); | 315 &canvas_width, &canvas_height, &flags); |
| 317 if (status != VP8_STATUS_OK) { | 316 if (status != VP8_STATUS_OK) { |
| 318 return status; // Wrong VP8X / insufficient data. | 317 return status; // Wrong VP8X / insufficient data. |
| 319 } | 318 } |
| 320 animation_present = !!(flags & ANIMATION_FLAG); | 319 animation_present = !!(flags & ANIMATION_FLAG); |
| 321 fragments_present = !!(flags & FRAGMENTS_FLAG); | |
| 322 if (!found_riff && found_vp8x) { | 320 if (!found_riff && found_vp8x) { |
| 323 // Note: This restriction may be removed in the future, if it becomes | 321 // Note: This restriction may be removed in the future, if it becomes |
| 324 // necessary to send VP8X chunk to the decoder. | 322 // necessary to send VP8X chunk to the decoder. |
| 325 return VP8_STATUS_BITSTREAM_ERROR; | 323 return VP8_STATUS_BITSTREAM_ERROR; |
| 326 } | 324 } |
| 327 if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG); | 325 if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG); |
| 328 if (has_animation != NULL) *has_animation = animation_present; | 326 if (has_animation != NULL) *has_animation = animation_present; |
| 329 if (format != NULL) *format = 0; // default = undefined | 327 if (format != NULL) *format = 0; // default = undefined |
| 330 | 328 |
| 331 if (found_vp8x && (animation_present || fragments_present) && | 329 if (found_vp8x && animation_present && headers == NULL) { |
| 332 headers == NULL) { | |
| 333 if (width != NULL) *width = canvas_width; | 330 if (width != NULL) *width = canvas_width; |
| 334 if (height != NULL) *height = canvas_height; | 331 if (height != NULL) *height = canvas_height; |
| 335 return VP8_STATUS_OK; // Just return features from VP8X header. | 332 return VP8_STATUS_OK; // Just return features from VP8X header. |
| 336 } | 333 } |
| 337 } | 334 } |
| 338 | 335 |
| 339 if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA; | 336 if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA; |
| 340 | 337 |
| 341 // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH". | 338 // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH". |
| 342 if ((found_riff && found_vp8x) || | 339 if ((found_riff && found_vp8x) || |
| 343 (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) { | 340 (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) { |
| 344 status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size, | 341 status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size, |
| 345 &hdrs.alpha_data, &hdrs.alpha_data_size); | 342 &hdrs.alpha_data, &hdrs.alpha_data_size); |
| 346 if (status != VP8_STATUS_OK) { | 343 if (status != VP8_STATUS_OK) { |
| 347 return status; // Found an invalid chunk size / insufficient data. | 344 return status; // Found an invalid chunk size / insufficient data. |
| 348 } | 345 } |
| 349 } | 346 } |
| 350 | 347 |
| 351 // Skip over VP8/VP8L header. | 348 // Skip over VP8/VP8L header. |
| 352 status = ParseVP8Header(&data, &data_size, have_all_data, hdrs.riff_size, | 349 status = ParseVP8Header(&data, &data_size, have_all_data, hdrs.riff_size, |
| 353 &hdrs.compressed_size, &hdrs.is_lossless); | 350 &hdrs.compressed_size, &hdrs.is_lossless); |
| 354 if (status != VP8_STATUS_OK) { | 351 if (status != VP8_STATUS_OK) { |
| 355 return status; // Wrong VP8/VP8L chunk-header / insufficient data. | 352 return status; // Wrong VP8/VP8L chunk-header / insufficient data. |
| 356 } | 353 } |
| 357 if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) { | 354 if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) { |
| 358 return VP8_STATUS_BITSTREAM_ERROR; | 355 return VP8_STATUS_BITSTREAM_ERROR; |
| 359 } | 356 } |
| 360 | 357 |
| 361 if (format != NULL && !(animation_present || fragments_present)) { | 358 if (format != NULL && !animation_present) { |
| 362 *format = hdrs.is_lossless ? 2 : 1; | 359 *format = hdrs.is_lossless ? 2 : 1; |
| 363 } | 360 } |
| 364 | 361 |
| 365 if (!hdrs.is_lossless) { | 362 if (!hdrs.is_lossless) { |
| 366 if (data_size < VP8_FRAME_HEADER_SIZE) { | 363 if (data_size < VP8_FRAME_HEADER_SIZE) { |
| 367 return VP8_STATUS_NOT_ENOUGH_DATA; | 364 return VP8_STATUS_NOT_ENOUGH_DATA; |
| 368 } | 365 } |
| 369 // Validates raw VP8 data. | 366 // Validates raw VP8 data. |
| 370 if (!VP8GetInfo(data, data_size, (uint32_t)hdrs.compressed_size, | 367 if (!VP8GetInfo(data, data_size, (uint32_t)hdrs.compressed_size, |
| 371 &image_width, &image_height)) { | 368 &image_width, &image_height)) { |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 825 if (io->use_scaling) { | 822 if (io->use_scaling) { |
| 826 // disable filter (only for large downscaling ratio). | 823 // disable filter (only for large downscaling ratio). |
| 827 io->bypass_filtering = (io->scaled_width < W * 3 / 4) && | 824 io->bypass_filtering = (io->scaled_width < W * 3 / 4) && |
| 828 (io->scaled_height < H * 3 / 4); | 825 (io->scaled_height < H * 3 / 4); |
| 829 io->fancy_upsampling = 0; | 826 io->fancy_upsampling = 0; |
| 830 } | 827 } |
| 831 return 1; | 828 return 1; |
| 832 } | 829 } |
| 833 | 830 |
| 834 //------------------------------------------------------------------------------ | 831 //------------------------------------------------------------------------------ |
| OLD | NEW |