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

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

Issue 116213006: Update libwebp to 0.4.0 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: After Blink Roll Created 6 years, 11 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
« no previous file with comments | « third_party/libwebp/dec/vp8li.h ('k') | third_party/libwebp/dec/webpi.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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.h"
17 #include "./vp8li.h" 17 #include "./vp8li.h"
18 #include "./webpi.h" 18 #include "./webpi.h"
19 #include "../webp/mux_types.h" // ALPHA_FLAG 19 #include "../webp/mux_types.h" // ALPHA_FLAG
20 20
21 #if defined(__cplusplus) || defined(c_plusplus)
22 extern "C" {
23 #endif
24
25 //------------------------------------------------------------------------------ 21 //------------------------------------------------------------------------------
26 // RIFF layout is: 22 // RIFF layout is:
27 // Offset tag 23 // Offset tag
28 // 0...3 "RIFF" 4-byte tag 24 // 0...3 "RIFF" 4-byte tag
29 // 4...7 size of image data (including metadata) starting at offset 8 25 // 4...7 size of image data (including metadata) starting at offset 8
30 // 8...11 "WEBP" our form-type signature 26 // 8...11 "WEBP" our form-type signature
31 // The RIFF container (12 bytes) is followed by appropriate chunks: 27 // The RIFF container (12 bytes) is followed by appropriate chunks:
32 // 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format 28 // 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format
33 // 16..19 size of the raw VP8 image data, starting at offset 20 29 // 16..19 size of the raw VP8 image data, starting at offset 20
34 // 20.... the VP8 bytes 30 // 20.... the VP8 bytes
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 // RIFF + VP8(L) 274 // RIFF + VP8(L)
279 // RIFF + VP8X + (optional chunks) + VP8(L) 275 // RIFF + VP8X + (optional chunks) + VP8(L)
280 // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. 276 // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
281 // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. 277 // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
282 static VP8StatusCode ParseHeadersInternal(const uint8_t* data, 278 static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
283 size_t data_size, 279 size_t data_size,
284 int* const width, 280 int* const width,
285 int* const height, 281 int* const height,
286 int* const has_alpha, 282 int* const has_alpha,
287 int* const has_animation, 283 int* const has_animation,
284 int* const format,
288 WebPHeaderStructure* const headers) { 285 WebPHeaderStructure* const headers) {
289 int canvas_width = 0; 286 int canvas_width = 0;
290 int canvas_height = 0; 287 int canvas_height = 0;
291 int image_width = 0; 288 int image_width = 0;
292 int image_height = 0; 289 int image_height = 0;
293 int found_riff = 0; 290 int found_riff = 0;
294 int found_vp8x = 0; 291 int found_vp8x = 0;
292 int animation_present = 0;
293 int fragments_present = 0;
294
295 VP8StatusCode status; 295 VP8StatusCode status;
296 WebPHeaderStructure hdrs; 296 WebPHeaderStructure hdrs;
297 297
298 if (data == NULL || data_size < RIFF_HEADER_SIZE) { 298 if (data == NULL || data_size < RIFF_HEADER_SIZE) {
299 return VP8_STATUS_NOT_ENOUGH_DATA; 299 return VP8_STATUS_NOT_ENOUGH_DATA;
300 } 300 }
301 memset(&hdrs, 0, sizeof(hdrs)); 301 memset(&hdrs, 0, sizeof(hdrs));
302 hdrs.data = data; 302 hdrs.data = data;
303 hdrs.data_size = data_size; 303 hdrs.data_size = data_size;
304 304
305 // Skip over RIFF header. 305 // Skip over RIFF header.
306 status = ParseRIFF(&data, &data_size, &hdrs.riff_size); 306 status = ParseRIFF(&data, &data_size, &hdrs.riff_size);
307 if (status != VP8_STATUS_OK) { 307 if (status != VP8_STATUS_OK) {
308 return status; // Wrong RIFF header / insufficient data. 308 return status; // Wrong RIFF header / insufficient data.
309 } 309 }
310 found_riff = (hdrs.riff_size > 0); 310 found_riff = (hdrs.riff_size > 0);
311 311
312 // Skip over VP8X. 312 // Skip over VP8X.
313 { 313 {
314 uint32_t flags = 0; 314 uint32_t flags = 0;
315 int animation_present;
316 status = ParseVP8X(&data, &data_size, &found_vp8x, 315 status = ParseVP8X(&data, &data_size, &found_vp8x,
317 &canvas_width, &canvas_height, &flags); 316 &canvas_width, &canvas_height, &flags);
318 if (status != VP8_STATUS_OK) { 317 if (status != VP8_STATUS_OK) {
319 return status; // Wrong VP8X / insufficient data. 318 return status; // Wrong VP8X / insufficient data.
320 } 319 }
321 animation_present = !!(flags & ANIMATION_FLAG); 320 animation_present = !!(flags & ANIMATION_FLAG);
321 fragments_present = !!(flags & FRAGMENTS_FLAG);
322 if (!found_riff && found_vp8x) { 322 if (!found_riff && found_vp8x) {
323 // Note: This restriction may be removed in the future, if it becomes 323 // Note: This restriction may be removed in the future, if it becomes
324 // necessary to send VP8X chunk to the decoder. 324 // necessary to send VP8X chunk to the decoder.
325 return VP8_STATUS_BITSTREAM_ERROR; 325 return VP8_STATUS_BITSTREAM_ERROR;
326 } 326 }
327 if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG); 327 if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG);
328 if (has_animation != NULL) *has_animation = animation_present; 328 if (has_animation != NULL) *has_animation = animation_present;
329 if (format != NULL) *format = 0; // default = undefined
329 330
330 if (found_vp8x && animation_present && headers == NULL) { 331 if (found_vp8x && (animation_present || fragments_present) &&
332 headers == NULL) {
331 if (width != NULL) *width = canvas_width; 333 if (width != NULL) *width = canvas_width;
332 if (height != NULL) *height = canvas_height; 334 if (height != NULL) *height = canvas_height;
333 return VP8_STATUS_OK; // Just return features from VP8X header. 335 return VP8_STATUS_OK; // Just return features from VP8X header.
334 } 336 }
335 } 337 }
336 338
337 if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA; 339 if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA;
338 340
339 // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH". 341 // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
340 if ((found_riff && found_vp8x) || 342 if ((found_riff && found_vp8x) ||
341 (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) { 343 (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) {
342 status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size, 344 status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
343 &hdrs.alpha_data, &hdrs.alpha_data_size); 345 &hdrs.alpha_data, &hdrs.alpha_data_size);
344 if (status != VP8_STATUS_OK) { 346 if (status != VP8_STATUS_OK) {
345 return status; // Found an invalid chunk size / insufficient data. 347 return status; // Found an invalid chunk size / insufficient data.
346 } 348 }
347 } 349 }
348 350
349 // Skip over VP8/VP8L header. 351 // Skip over VP8/VP8L header.
350 status = ParseVP8Header(&data, &data_size, hdrs.riff_size, 352 status = ParseVP8Header(&data, &data_size, hdrs.riff_size,
351 &hdrs.compressed_size, &hdrs.is_lossless); 353 &hdrs.compressed_size, &hdrs.is_lossless);
352 if (status != VP8_STATUS_OK) { 354 if (status != VP8_STATUS_OK) {
353 return status; // Wrong VP8/VP8L chunk-header / insufficient data. 355 return status; // Wrong VP8/VP8L chunk-header / insufficient data.
354 } 356 }
355 if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) { 357 if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) {
356 return VP8_STATUS_BITSTREAM_ERROR; 358 return VP8_STATUS_BITSTREAM_ERROR;
357 } 359 }
358 360
361 if (format != NULL && !(animation_present || fragments_present)) {
362 *format = hdrs.is_lossless ? 2 : 1;
363 }
364
359 if (!hdrs.is_lossless) { 365 if (!hdrs.is_lossless) {
360 if (data_size < VP8_FRAME_HEADER_SIZE) { 366 if (data_size < VP8_FRAME_HEADER_SIZE) {
361 return VP8_STATUS_NOT_ENOUGH_DATA; 367 return VP8_STATUS_NOT_ENOUGH_DATA;
362 } 368 }
363 // Validates raw VP8 data. 369 // Validates raw VP8 data.
364 if (!VP8GetInfo(data, data_size, (uint32_t)hdrs.compressed_size, 370 if (!VP8GetInfo(data, data_size, (uint32_t)hdrs.compressed_size,
365 &image_width, &image_height)) { 371 &image_width, &image_height)) {
366 return VP8_STATUS_BITSTREAM_ERROR; 372 return VP8_STATUS_BITSTREAM_ERROR;
367 } 373 }
368 } else { 374 } else {
369 if (data_size < VP8L_FRAME_HEADER_SIZE) { 375 if (data_size < VP8L_FRAME_HEADER_SIZE) {
370 return VP8_STATUS_NOT_ENOUGH_DATA; 376 return VP8_STATUS_NOT_ENOUGH_DATA;
371 } 377 }
372 // Validates raw VP8L data. 378 // Validates raw VP8L data.
373 if (!VP8LGetInfo(data, data_size, &image_width, &image_height, has_alpha)) { 379 if (!VP8LGetInfo(data, data_size, &image_width, &image_height, has_alpha)) {
374 return VP8_STATUS_BITSTREAM_ERROR; 380 return VP8_STATUS_BITSTREAM_ERROR;
375 } 381 }
376 } 382 }
377 // Validates image size coherency. TODO(urvang): what about FRGM? 383 // Validates image size coherency.
378 if (found_vp8x) { 384 if (found_vp8x) {
379 if (canvas_width != image_width || canvas_height != image_height) { 385 if (canvas_width != image_width || canvas_height != image_height) {
380 return VP8_STATUS_BITSTREAM_ERROR; 386 return VP8_STATUS_BITSTREAM_ERROR;
381 } 387 }
382 } 388 }
383 if (width != NULL) *width = image_width; 389 if (width != NULL) *width = image_width;
384 if (height != NULL) *height = image_height; 390 if (height != NULL) *height = image_height;
385 if (has_alpha != NULL) { 391 if (has_alpha != NULL) {
386 // If the data did not contain a VP8X/VP8L chunk the only definitive way 392 // If the data did not contain a VP8X/VP8L chunk the only definitive way
387 // to set this is by looking for alpha data (from an ALPH chunk). 393 // to set this is by looking for alpha data (from an ALPH chunk).
388 *has_alpha |= (hdrs.alpha_data != NULL); 394 *has_alpha |= (hdrs.alpha_data != NULL);
389 } 395 }
390 if (headers != NULL) { 396 if (headers != NULL) {
391 *headers = hdrs; 397 *headers = hdrs;
392 headers->offset = data - headers->data; 398 headers->offset = data - headers->data;
393 assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD); 399 assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD);
394 assert(headers->offset == headers->data_size - data_size); 400 assert(headers->offset == headers->data_size - data_size);
395 } 401 }
396 return VP8_STATUS_OK; // Return features from VP8 header. 402 return VP8_STATUS_OK; // Return features from VP8 header.
397 } 403 }
398 404
399 VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) { 405 VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
400 VP8StatusCode status; 406 VP8StatusCode status;
401 int has_animation = 0; 407 int has_animation = 0;
402 assert(headers != NULL); 408 assert(headers != NULL);
403 // fill out headers, ignore width/height/has_alpha. 409 // fill out headers, ignore width/height/has_alpha.
404 status = ParseHeadersInternal(headers->data, headers->data_size, 410 status = ParseHeadersInternal(headers->data, headers->data_size,
405 NULL, NULL, NULL, &has_animation, headers); 411 NULL, NULL, NULL, &has_animation,
412 NULL, headers);
406 if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) { 413 if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
407 // TODO(jzern): full support of animation frames will require API additions. 414 // TODO(jzern): full support of animation frames will require API additions.
408 if (has_animation) { 415 if (has_animation) {
409 status = VP8_STATUS_UNSUPPORTED_FEATURE; 416 status = VP8_STATUS_UNSUPPORTED_FEATURE;
410 } 417 }
411 } 418 }
412 return status; 419 return status;
413 } 420 }
414 421
415 //------------------------------------------------------------------------------ 422 //------------------------------------------------------------------------------
416 // WebPDecParams 423 // WebPDecParams
417 424
418 void WebPResetDecParams(WebPDecParams* const params) { 425 void WebPResetDecParams(WebPDecParams* const params) {
419 if (params) { 426 if (params != NULL) {
420 memset(params, 0, sizeof(*params)); 427 memset(params, 0, sizeof(*params));
421 } 428 }
422 } 429 }
423 430
424 //------------------------------------------------------------------------------ 431 //------------------------------------------------------------------------------
425 // "Into" decoding variants 432 // "Into" decoding variants
426 433
427 // Main flow 434 // Main flow
428 static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size, 435 static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
429 WebPDecParams* const params) { 436 WebPDecParams* const params) {
(...skipping 12 matching lines...) Expand all
442 VP8InitIo(&io); 449 VP8InitIo(&io);
443 io.data = headers.data + headers.offset; 450 io.data = headers.data + headers.offset;
444 io.data_size = headers.data_size - headers.offset; 451 io.data_size = headers.data_size - headers.offset;
445 WebPInitCustomIo(params, &io); // Plug the I/O functions. 452 WebPInitCustomIo(params, &io); // Plug the I/O functions.
446 453
447 if (!headers.is_lossless) { 454 if (!headers.is_lossless) {
448 VP8Decoder* const dec = VP8New(); 455 VP8Decoder* const dec = VP8New();
449 if (dec == NULL) { 456 if (dec == NULL) {
450 return VP8_STATUS_OUT_OF_MEMORY; 457 return VP8_STATUS_OUT_OF_MEMORY;
451 } 458 }
452 #ifdef WEBP_USE_THREAD
453 dec->use_threads_ = params->options && (params->options->use_threads > 0);
454 #else
455 dec->use_threads_ = 0;
456 #endif
457 dec->alpha_data_ = headers.alpha_data; 459 dec->alpha_data_ = headers.alpha_data;
458 dec->alpha_data_size_ = headers.alpha_data_size; 460 dec->alpha_data_size_ = headers.alpha_data_size;
459 461
460 // Decode bitstream header, update io->width/io->height. 462 // Decode bitstream header, update io->width/io->height.
461 if (!VP8GetHeaders(dec, &io)) { 463 if (!VP8GetHeaders(dec, &io)) {
462 status = dec->status_; // An error occurred. Grab error status. 464 status = dec->status_; // An error occurred. Grab error status.
463 } else { 465 } else {
464 // Allocate/check output buffers. 466 // Allocate/check output buffers.
465 status = WebPAllocateDecBuffer(io.width, io.height, params->options, 467 status = WebPAllocateDecBuffer(io.width, io.height, params->options,
466 params->output); 468 params->output);
467 if (status == VP8_STATUS_OK) { // Decode 469 if (status == VP8_STATUS_OK) { // Decode
470 // This change must be done before calling VP8Decode()
471 dec->mt_method_ = VP8GetThreadMethod(params->options, &headers,
472 io.width, io.height);
473 VP8InitDithering(params->options, dec);
468 if (!VP8Decode(dec, &io)) { 474 if (!VP8Decode(dec, &io)) {
469 status = dec->status_; 475 status = dec->status_;
470 } 476 }
471 } 477 }
472 } 478 }
473 VP8Delete(dec); 479 VP8Delete(dec);
474 } else { 480 } else {
475 VP8LDecoder* const dec = VP8LNew(); 481 VP8LDecoder* const dec = VP8LNew();
476 if (dec == NULL) { 482 if (dec == NULL) {
477 return VP8_STATUS_OUT_OF_MEMORY; 483 return VP8_STATUS_OUT_OF_MEMORY;
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 *stride = buf->y_stride; 650 *stride = buf->y_stride;
645 *uv_stride = buf->u_stride; 651 *uv_stride = buf->u_stride;
646 assert(buf->u_stride == buf->v_stride); 652 assert(buf->u_stride == buf->v_stride);
647 } 653 }
648 return out; 654 return out;
649 } 655 }
650 656
651 static void DefaultFeatures(WebPBitstreamFeatures* const features) { 657 static void DefaultFeatures(WebPBitstreamFeatures* const features) {
652 assert(features != NULL); 658 assert(features != NULL);
653 memset(features, 0, sizeof(*features)); 659 memset(features, 0, sizeof(*features));
654 features->bitstream_version = 0;
655 } 660 }
656 661
657 static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size, 662 static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
658 WebPBitstreamFeatures* const features) { 663 WebPBitstreamFeatures* const features) {
659 if (features == NULL || data == NULL) { 664 if (features == NULL || data == NULL) {
660 return VP8_STATUS_INVALID_PARAM; 665 return VP8_STATUS_INVALID_PARAM;
661 } 666 }
662 DefaultFeatures(features); 667 DefaultFeatures(features);
663 668
664 // Only parse enough of the data to retrieve the features. 669 // Only parse enough of the data to retrieve the features.
665 return ParseHeadersInternal(data, data_size, 670 return ParseHeadersInternal(data, data_size,
666 &features->width, &features->height, 671 &features->width, &features->height,
667 &features->has_alpha, &features->has_animation, 672 &features->has_alpha, &features->has_animation,
668 NULL); 673 &features->format, NULL);
669 } 674 }
670 675
671 //------------------------------------------------------------------------------ 676 //------------------------------------------------------------------------------
672 // WebPGetInfo() 677 // WebPGetInfo()
673 678
674 int WebPGetInfo(const uint8_t* data, size_t data_size, 679 int WebPGetInfo(const uint8_t* data, size_t data_size,
675 int* width, int* height) { 680 int* width, int* height) {
676 WebPBitstreamFeatures features; 681 WebPBitstreamFeatures features;
677 682
678 if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) { 683 if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) {
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
796 // disable filter (only for large downscaling ratio). 801 // disable filter (only for large downscaling ratio).
797 io->bypass_filtering = (io->scaled_width < W * 3 / 4) && 802 io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
798 (io->scaled_height < H * 3 / 4); 803 (io->scaled_height < H * 3 / 4);
799 io->fancy_upsampling = 0; 804 io->fancy_upsampling = 0;
800 } 805 }
801 return 1; 806 return 1;
802 } 807 }
803 808
804 //------------------------------------------------------------------------------ 809 //------------------------------------------------------------------------------
805 810
806 #if defined(__cplusplus) || defined(c_plusplus)
807 } // extern "C"
808 #endif
OLDNEW
« no previous file with comments | « third_party/libwebp/dec/vp8li.h ('k') | third_party/libwebp/dec/webpi.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698