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

Side by Side Diff: third_party/libwebp/demux/demux.c

Issue 1546003002: libwebp: update to 0.5.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase around clang-cl fix Created 4 years, 12 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
OLDNEW
1 // Copyright 2012 Google Inc. All Rights Reserved. 1 // Copyright 2012 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 // WebP container demux. 10 // WebP container demux.
11 // 11 //
12 12
13 #ifdef HAVE_CONFIG_H 13 #ifdef HAVE_CONFIG_H
14 #include "../webp/config.h" 14 #include "../webp/config.h"
15 #endif 15 #endif
16 16
17 #include <assert.h> 17 #include <assert.h>
18 #include <stdlib.h> 18 #include <stdlib.h>
19 #include <string.h> 19 #include <string.h>
20 20
21 #include "../utils/utils.h" 21 #include "../utils/utils.h"
22 #include "../webp/decode.h" // WebPGetFeatures 22 #include "../webp/decode.h" // WebPGetFeatures
23 #include "../webp/demux.h" 23 #include "../webp/demux.h"
24 #include "../webp/format_constants.h" 24 #include "../webp/format_constants.h"
25 25
26 #define DMUX_MAJ_VERSION 0 26 #define DMUX_MAJ_VERSION 0
27 #define DMUX_MIN_VERSION 2 27 #define DMUX_MIN_VERSION 3
28 #define DMUX_REV_VERSION 2 28 #define DMUX_REV_VERSION 0
29 29
30 typedef struct { 30 typedef struct {
31 size_t start_; // start location of the data 31 size_t start_; // start location of the data
32 size_t end_; // end location 32 size_t end_; // end location
33 size_t riff_end_; // riff chunk end location, can be > end_. 33 size_t riff_end_; // riff chunk end location, can be > end_.
34 size_t buf_size_; // size of the buffer 34 size_t buf_size_; // size of the buffer
35 const uint8_t* buf_; 35 const uint8_t* buf_;
36 } MemBuffer; 36 } MemBuffer;
37 37
38 typedef struct { 38 typedef struct {
39 size_t offset_; 39 size_t offset_;
40 size_t size_; 40 size_t size_;
41 } ChunkData; 41 } ChunkData;
42 42
43 typedef struct Frame { 43 typedef struct Frame {
44 int x_offset_, y_offset_; 44 int x_offset_, y_offset_;
45 int width_, height_; 45 int width_, height_;
46 int has_alpha_; 46 int has_alpha_;
47 int duration_; 47 int duration_;
48 WebPMuxAnimDispose dispose_method_; 48 WebPMuxAnimDispose dispose_method_;
49 WebPMuxAnimBlend blend_method_; 49 WebPMuxAnimBlend blend_method_;
50 int is_fragment_; // this is a frame fragment (and not a full frame). 50 int frame_num_;
51 int frame_num_; // the referent frame number for use in assembling fragments.
52 int complete_; // img_components_ contains a full image. 51 int complete_; // img_components_ contains a full image.
53 ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH 52 ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH
54 struct Frame* next_; 53 struct Frame* next_;
55 } Frame; 54 } Frame;
56 55
57 typedef struct Chunk { 56 typedef struct Chunk {
58 ChunkData data_; 57 ChunkData data_;
59 struct Chunk* next_; 58 struct Chunk* next_;
60 } Chunk; 59 } Chunk;
61 60
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) { 185 static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) {
187 const Frame* const last_frame = *dmux->frames_tail_; 186 const Frame* const last_frame = *dmux->frames_tail_;
188 if (last_frame != NULL && !last_frame->complete_) return 0; 187 if (last_frame != NULL && !last_frame->complete_) return 0;
189 188
190 *dmux->frames_tail_ = frame; 189 *dmux->frames_tail_ = frame;
191 frame->next_ = NULL; 190 frame->next_ = NULL;
192 dmux->frames_tail_ = &frame->next_; 191 dmux->frames_tail_ = &frame->next_;
193 return 1; 192 return 1;
194 } 193 }
195 194
195 static void SetFrameInfo(size_t start_offset, size_t size,
196 int frame_num, int complete,
197 const WebPBitstreamFeatures* const features,
198 Frame* const frame) {
199 frame->img_components_[0].offset_ = start_offset;
200 frame->img_components_[0].size_ = size;
201 frame->width_ = features->width;
202 frame->height_ = features->height;
203 frame->has_alpha_ |= features->has_alpha;
204 frame->frame_num_ = frame_num;
205 frame->complete_ = complete;
206 }
207
196 // Store image bearing chunks to 'frame'. 208 // Store image bearing chunks to 'frame'.
197 static ParseStatus StoreFrame(int frame_num, uint32_t min_size, 209 static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
198 MemBuffer* const mem, Frame* const frame) { 210 MemBuffer* const mem, Frame* const frame) {
199 int alpha_chunks = 0; 211 int alpha_chunks = 0;
200 int image_chunks = 0; 212 int image_chunks = 0;
201 int done = (MemDataSize(mem) < min_size); 213 int done = (MemDataSize(mem) < min_size);
202 ParseStatus status = PARSE_OK; 214 ParseStatus status = PARSE_OK;
203 215
204 if (done) return PARSE_NEED_MORE_DATA; 216 if (done) return PARSE_NEED_MORE_DATA;
205 217
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 WebPGetFeatures(mem->buf_ + chunk_start_offset, chunk_size, 253 WebPGetFeatures(mem->buf_ + chunk_start_offset, chunk_size,
242 &features); 254 &features);
243 if (status == PARSE_NEED_MORE_DATA && 255 if (status == PARSE_NEED_MORE_DATA &&
244 vp8_status == VP8_STATUS_NOT_ENOUGH_DATA) { 256 vp8_status == VP8_STATUS_NOT_ENOUGH_DATA) {
245 return PARSE_NEED_MORE_DATA; 257 return PARSE_NEED_MORE_DATA;
246 } else if (vp8_status != VP8_STATUS_OK) { 258 } else if (vp8_status != VP8_STATUS_OK) {
247 // We have enough data, and yet WebPGetFeatures() failed. 259 // We have enough data, and yet WebPGetFeatures() failed.
248 return PARSE_ERROR; 260 return PARSE_ERROR;
249 } 261 }
250 ++image_chunks; 262 ++image_chunks;
251 frame->img_components_[0].offset_ = chunk_start_offset; 263 SetFrameInfo(chunk_start_offset, chunk_size, frame_num,
252 frame->img_components_[0].size_ = chunk_size; 264 status == PARSE_OK, &features, frame);
253 frame->width_ = features.width;
254 frame->height_ = features.height;
255 frame->has_alpha_ |= features.has_alpha;
256 frame->frame_num_ = frame_num;
257 frame->complete_ = (status == PARSE_OK);
258 Skip(mem, payload_available); 265 Skip(mem, payload_available);
259 } else { 266 } else {
260 goto Done; 267 goto Done;
261 } 268 }
262 break; 269 break;
263 Done: 270 Done:
264 default: 271 default:
265 // Restore fourcc/size when moving up one level in parsing. 272 // Restore fourcc/size when moving up one level in parsing.
266 Rewind(mem, CHUNK_HEADER_SIZE); 273 Rewind(mem, CHUNK_HEADER_SIZE);
267 done = 1; 274 done = 1;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 ++dmux->num_frames_; 337 ++dmux->num_frames_;
331 } else { 338 } else {
332 status = PARSE_ERROR; 339 status = PARSE_ERROR;
333 } 340 }
334 } 341 }
335 342
336 if (!added_frame) WebPSafeFree(frame); 343 if (!added_frame) WebPSafeFree(frame);
337 return status; 344 return status;
338 } 345 }
339 346
340 #ifdef WEBP_EXPERIMENTAL_FEATURES
341 // Parse a 'FRGM' chunk and any image bearing chunks that immediately follow.
342 // 'fragment_chunk_size' is the previously validated, padded chunk size.
343 static ParseStatus ParseFragment(WebPDemuxer* const dmux,
344 uint32_t fragment_chunk_size) {
345 const int frame_num = 1; // All fragments belong to the 1st (and only) frame.
346 const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
347 const uint32_t frgm_payload_size = fragment_chunk_size - FRGM_CHUNK_SIZE;
348 int added_fragment = 0;
349 MemBuffer* const mem = &dmux->mem_;
350 Frame* frame;
351 ParseStatus status =
352 NewFrame(mem, FRGM_CHUNK_SIZE, fragment_chunk_size, &frame);
353 if (status != PARSE_OK) return status;
354
355 frame->is_fragment_ = 1;
356 frame->x_offset_ = 2 * ReadLE24s(mem);
357 frame->y_offset_ = 2 * ReadLE24s(mem);
358
359 // Store a fragment only if the 'fragments' flag is set and there is some
360 // data available.
361 status = StoreFrame(frame_num, frgm_payload_size, mem, frame);
362 if (status != PARSE_ERROR && is_fragmented && frame->frame_num_ > 0) {
363 added_fragment = AddFrame(dmux, frame);
364 if (!added_fragment) {
365 status = PARSE_ERROR;
366 } else {
367 dmux->num_frames_ = 1;
368 }
369 }
370
371 if (!added_fragment) WebPSafeFree(frame);
372 return status;
373 }
374 #endif // WEBP_EXPERIMENTAL_FEATURES
375
376 // General chunk storage, starting with the header at 'start_offset', allowing 347 // General chunk storage, starting with the header at 'start_offset', allowing
377 // the user to request the payload via a fourcc string. 'size' includes the 348 // the user to request the payload via a fourcc string. 'size' includes the
378 // header and the unpadded payload size. 349 // header and the unpadded payload size.
379 // Returns true on success, false otherwise. 350 // Returns true on success, false otherwise.
380 static int StoreChunk(WebPDemuxer* const dmux, 351 static int StoreChunk(WebPDemuxer* const dmux,
381 size_t start_offset, uint32_t size) { 352 size_t start_offset, uint32_t size) {
382 Chunk* const chunk = (Chunk*)WebPSafeCalloc(1ULL, sizeof(*chunk)); 353 Chunk* const chunk = (Chunk*)WebPSafeCalloc(1ULL, sizeof(*chunk));
383 if (chunk == NULL) return 0; 354 if (chunk == NULL) return 0;
384 355
385 chunk->data_.offset_ = start_offset; 356 chunk->data_.offset_ = start_offset;
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 store_chunk = 0; 477 store_chunk = 0;
507 goto Skip; 478 goto Skip;
508 } 479 }
509 break; 480 break;
510 } 481 }
511 case MKFOURCC('A', 'N', 'M', 'F'): { 482 case MKFOURCC('A', 'N', 'M', 'F'): {
512 if (anim_chunks == 0) return PARSE_ERROR; // 'ANIM' precedes frames. 483 if (anim_chunks == 0) return PARSE_ERROR; // 'ANIM' precedes frames.
513 status = ParseAnimationFrame(dmux, chunk_size_padded); 484 status = ParseAnimationFrame(dmux, chunk_size_padded);
514 break; 485 break;
515 } 486 }
516 #ifdef WEBP_EXPERIMENTAL_FEATURES
517 case MKFOURCC('F', 'R', 'G', 'M'): {
518 status = ParseFragment(dmux, chunk_size_padded);
519 break;
520 }
521 #endif
522 case MKFOURCC('I', 'C', 'C', 'P'): { 487 case MKFOURCC('I', 'C', 'C', 'P'): {
523 store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); 488 store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG);
524 goto Skip; 489 goto Skip;
525 } 490 }
526 case MKFOURCC('E', 'X', 'I', 'F'): { 491 case MKFOURCC('E', 'X', 'I', 'F'): {
527 store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG); 492 store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG);
528 goto Skip; 493 goto Skip;
529 } 494 }
530 case MKFOURCC('X', 'M', 'P', ' '): { 495 case MKFOURCC('X', 'M', 'P', ' '): {
531 store_chunk = !!(dmux->feature_flags_ & XMP_FLAG); 496 store_chunk = !!(dmux->feature_flags_ & XMP_FLAG);
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 564
600 if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; 565 if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
601 if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0; 566 if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0;
602 567
603 if (frame->width_ <= 0 || frame->height_ <= 0) return 0; 568 if (frame->width_ <= 0 || frame->height_ <= 0) return 0;
604 return 1; 569 return 1;
605 } 570 }
606 571
607 // If 'exact' is true, check that the image resolution matches the canvas. 572 // If 'exact' is true, check that the image resolution matches the canvas.
608 // If 'exact' is false, check that the x/y offsets do not exceed the canvas. 573 // If 'exact' is false, check that the x/y offsets do not exceed the canvas.
609 // TODO(jzern): this is insufficient in the fragmented image case if the
610 // expectation is that the fragments completely cover the canvas.
611 static int CheckFrameBounds(const Frame* const frame, int exact, 574 static int CheckFrameBounds(const Frame* const frame, int exact,
612 int canvas_width, int canvas_height) { 575 int canvas_width, int canvas_height) {
613 if (exact) { 576 if (exact) {
614 if (frame->x_offset_ != 0 || frame->y_offset_ != 0) { 577 if (frame->x_offset_ != 0 || frame->y_offset_ != 0) {
615 return 0; 578 return 0;
616 } 579 }
617 if (frame->width_ != canvas_width || frame->height_ != canvas_height) { 580 if (frame->width_ != canvas_width || frame->height_ != canvas_height) {
618 return 0; 581 return 0;
619 } 582 }
620 } else { 583 } else {
621 if (frame->x_offset_ < 0 || frame->y_offset_ < 0) return 0; 584 if (frame->x_offset_ < 0 || frame->y_offset_ < 0) return 0;
622 if (frame->width_ + frame->x_offset_ > canvas_width) return 0; 585 if (frame->width_ + frame->x_offset_ > canvas_width) return 0;
623 if (frame->height_ + frame->y_offset_ > canvas_height) return 0; 586 if (frame->height_ + frame->y_offset_ > canvas_height) return 0;
624 } 587 }
625 return 1; 588 return 1;
626 } 589 }
627 590
628 static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { 591 static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
629 const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); 592 const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
630 const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG); 593 const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
631 const Frame* f = dmux->frames_; 594 const Frame* f = dmux->frames_;
632 595
633 if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; 596 if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
634 597
635 if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; 598 if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
636 if (dmux->loop_count_ < 0) return 0; 599 if (dmux->loop_count_ < 0) return 0;
637 if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0; 600 if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
638 #ifndef WEBP_EXPERIMENTAL_FEATURES
639 if (is_fragmented) return 0; 601 if (is_fragmented) return 0;
640 #endif
641 602
642 while (f != NULL) { 603 while (f != NULL) {
643 const int cur_frame_set = f->frame_num_; 604 const int cur_frame_set = f->frame_num_;
644 int frame_count = 0, fragment_count = 0; 605 int frame_count = 0;
645 606
646 // Check frame properties and if the image is composed of fragments that 607 // Check frame properties.
647 // each fragment came from a fragment.
648 for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) { 608 for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
649 const ChunkData* const image = f->img_components_; 609 const ChunkData* const image = f->img_components_;
650 const ChunkData* const alpha = f->img_components_ + 1; 610 const ChunkData* const alpha = f->img_components_ + 1;
651 611
652 if (is_fragmented && !f->is_fragment_) return 0;
653 if (!is_fragmented && f->is_fragment_) return 0;
654 if (!is_animation && f->frame_num_ > 1) return 0; 612 if (!is_animation && f->frame_num_ > 1) return 0;
655 613
656 if (f->complete_) { 614 if (f->complete_) {
657 if (alpha->size_ == 0 && image->size_ == 0) return 0; 615 if (alpha->size_ == 0 && image->size_ == 0) return 0;
658 // Ensure alpha precedes image bitstream. 616 // Ensure alpha precedes image bitstream.
659 if (alpha->size_ > 0 && alpha->offset_ > image->offset_) { 617 if (alpha->size_ > 0 && alpha->offset_ > image->offset_) {
660 return 0; 618 return 0;
661 } 619 }
662 620
663 if (f->width_ <= 0 || f->height_ <= 0) return 0; 621 if (f->width_ <= 0 || f->height_ <= 0) return 0;
664 } else { 622 } else {
665 // There shouldn't be a partial frame in a complete file. 623 // There shouldn't be a partial frame in a complete file.
666 if (dmux->state_ == WEBP_DEMUX_DONE) return 0; 624 if (dmux->state_ == WEBP_DEMUX_DONE) return 0;
667 625
668 // Ensure alpha precedes image bitstream. 626 // Ensure alpha precedes image bitstream.
669 if (alpha->size_ > 0 && image->size_ > 0 && 627 if (alpha->size_ > 0 && image->size_ > 0 &&
670 alpha->offset_ > image->offset_) { 628 alpha->offset_ > image->offset_) {
671 return 0; 629 return 0;
672 } 630 }
673 // There shouldn't be any frames after an incomplete one. 631 // There shouldn't be any frames after an incomplete one.
674 if (f->next_ != NULL) return 0; 632 if (f->next_ != NULL) return 0;
675 } 633 }
676 634
677 if (f->width_ > 0 && f->height_ > 0 && 635 if (f->width_ > 0 && f->height_ > 0 &&
678 !CheckFrameBounds(f, !(is_animation || is_fragmented), 636 !CheckFrameBounds(f, !is_animation,
679 dmux->canvas_width_, dmux->canvas_height_)) { 637 dmux->canvas_width_, dmux->canvas_height_)) {
680 return 0; 638 return 0;
681 } 639 }
682 640
683 fragment_count += f->is_fragment_;
684 ++frame_count; 641 ++frame_count;
685 } 642 }
686 if (!is_fragmented && frame_count > 1) return 0;
687 if (fragment_count > 0 && frame_count != fragment_count) return 0;
688 } 643 }
689 return 1; 644 return 1;
690 } 645 }
691 646
692 // ----------------------------------------------------------------------------- 647 // -----------------------------------------------------------------------------
693 // WebPDemuxer object 648 // WebPDemuxer object
694 649
695 static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) { 650 static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) {
696 dmux->state_ = WEBP_DEMUX_PARSING_HEADER; 651 dmux->state_ = WEBP_DEMUX_PARSING_HEADER;
697 dmux->loop_count_ = 1; 652 dmux->loop_count_ = 1;
698 dmux->bgcolor_ = 0xFFFFFFFF; // White background by default. 653 dmux->bgcolor_ = 0xFFFFFFFF; // White background by default.
699 dmux->canvas_width_ = -1; 654 dmux->canvas_width_ = -1;
700 dmux->canvas_height_ = -1; 655 dmux->canvas_height_ = -1;
701 dmux->frames_tail_ = &dmux->frames_; 656 dmux->frames_tail_ = &dmux->frames_;
702 dmux->chunks_tail_ = &dmux->chunks_; 657 dmux->chunks_tail_ = &dmux->chunks_;
703 dmux->mem_ = *mem; 658 dmux->mem_ = *mem;
704 } 659 }
705 660
661 static ParseStatus CreateRawImageDemuxer(MemBuffer* const mem,
662 WebPDemuxer** demuxer) {
663 WebPBitstreamFeatures features;
664 const VP8StatusCode status =
665 WebPGetFeatures(mem->buf_, mem->buf_size_, &features);
666 *demuxer = NULL;
667 if (status != VP8_STATUS_OK) {
668 return (status == VP8_STATUS_NOT_ENOUGH_DATA) ? PARSE_NEED_MORE_DATA
669 : PARSE_ERROR;
670 }
671
672 {
673 WebPDemuxer* const dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux));
674 Frame* const frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame));
675 if (dmux == NULL || frame == NULL) goto Error;
676 InitDemux(dmux, mem);
677 SetFrameInfo(0, mem->buf_size_, 1 /*frame_num*/, 1 /*complete*/, &features,
678 frame);
679 if (!AddFrame(dmux, frame)) goto Error;
680 dmux->state_ = WEBP_DEMUX_DONE;
681 dmux->canvas_width_ = frame->width_;
682 dmux->canvas_height_ = frame->height_;
683 dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0;
684 dmux->num_frames_ = 1;
685 assert(IsValidSimpleFormat(dmux));
686 *demuxer = dmux;
687 return PARSE_OK;
688
689 Error:
690 WebPSafeFree(dmux);
691 WebPSafeFree(frame);
692 return PARSE_ERROR;
693 }
694 }
695
706 WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial, 696 WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
707 WebPDemuxState* state, int version) { 697 WebPDemuxState* state, int version) {
708 const ChunkParser* parser; 698 const ChunkParser* parser;
709 int partial; 699 int partial;
710 ParseStatus status = PARSE_ERROR; 700 ParseStatus status = PARSE_ERROR;
711 MemBuffer mem; 701 MemBuffer mem;
712 WebPDemuxer* dmux; 702 WebPDemuxer* dmux;
713 703
714 if (state != NULL) *state = WEBP_DEMUX_PARSE_ERROR; 704 if (state != NULL) *state = WEBP_DEMUX_PARSE_ERROR;
715 705
716 if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DEMUX_ABI_VERSION)) return NULL; 706 if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DEMUX_ABI_VERSION)) return NULL;
717 if (data == NULL || data->bytes == NULL || data->size == 0) return NULL; 707 if (data == NULL || data->bytes == NULL || data->size == 0) return NULL;
718 708
719 if (!InitMemBuffer(&mem, data->bytes, data->size)) return NULL; 709 if (!InitMemBuffer(&mem, data->bytes, data->size)) return NULL;
720 status = ReadHeader(&mem); 710 status = ReadHeader(&mem);
721 if (status != PARSE_OK) { 711 if (status != PARSE_OK) {
712 // If parsing of the webp file header fails attempt to handle a raw
713 // VP8/VP8L frame. Note 'allow_partial' is ignored in this case.
714 if (status == PARSE_ERROR) {
715 status = CreateRawImageDemuxer(&mem, &dmux);
716 if (status == PARSE_OK) {
717 if (state != NULL) *state = WEBP_DEMUX_DONE;
718 return dmux;
719 }
720 }
722 if (state != NULL) { 721 if (state != NULL) {
723 *state = (status == PARSE_NEED_MORE_DATA) ? WEBP_DEMUX_PARSING_HEADER 722 *state = (status == PARSE_NEED_MORE_DATA) ? WEBP_DEMUX_PARSING_HEADER
724 : WEBP_DEMUX_PARSE_ERROR; 723 : WEBP_DEMUX_PARSE_ERROR;
725 } 724 }
726 return NULL; 725 return NULL;
727 } 726 }
728 727
729 partial = (mem.buf_size_ < mem.riff_end_); 728 partial = (mem.buf_size_ < mem.riff_end_);
730 if (!allow_partial && partial) return NULL; 729 if (!allow_partial && partial) return NULL;
731 730
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
783 case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count_; 782 case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count_;
784 case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor_; 783 case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor_;
785 case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames_; 784 case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames_;
786 } 785 }
787 return 0; 786 return 0;
788 } 787 }
789 788
790 // ----------------------------------------------------------------------------- 789 // -----------------------------------------------------------------------------
791 // Frame iteration 790 // Frame iteration
792 791
793 // Find the first 'frame_num' frame. There may be multiple such frames in a
794 // fragmented frame.
795 static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) { 792 static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) {
796 const Frame* f; 793 const Frame* f;
797 for (f = dmux->frames_; f != NULL; f = f->next_) { 794 for (f = dmux->frames_; f != NULL; f = f->next_) {
798 if (frame_num == f->frame_num_) break; 795 if (frame_num == f->frame_num_) break;
799 } 796 }
800 return f; 797 return f;
801 } 798 }
802 799
803 // Returns fragment 'fragment_num' and the total count.
804 static const Frame* GetFragment(
805 const Frame* const frame_set, int fragment_num, int* const count) {
806 const int this_frame = frame_set->frame_num_;
807 const Frame* f = frame_set;
808 const Frame* fragment = NULL;
809 int total;
810
811 for (total = 0; f != NULL && f->frame_num_ == this_frame; f = f->next_) {
812 if (++total == fragment_num) fragment = f;
813 }
814 *count = total;
815 return fragment;
816 }
817
818 static const uint8_t* GetFramePayload(const uint8_t* const mem_buf, 800 static const uint8_t* GetFramePayload(const uint8_t* const mem_buf,
819 const Frame* const frame, 801 const Frame* const frame,
820 size_t* const data_size) { 802 size_t* const data_size) {
821 *data_size = 0; 803 *data_size = 0;
822 if (frame != NULL) { 804 if (frame != NULL) {
823 const ChunkData* const image = frame->img_components_; 805 const ChunkData* const image = frame->img_components_;
824 const ChunkData* const alpha = frame->img_components_ + 1; 806 const ChunkData* const alpha = frame->img_components_ + 1;
825 size_t start_offset = image->offset_; 807 size_t start_offset = image->offset_;
826 *data_size = image->size_; 808 *data_size = image->size_;
827 809
828 // if alpha exists it precedes image, update the size allowing for 810 // if alpha exists it precedes image, update the size allowing for
829 // intervening chunks. 811 // intervening chunks.
830 if (alpha->size_ > 0) { 812 if (alpha->size_ > 0) {
831 const size_t inter_size = (image->offset_ > 0) 813 const size_t inter_size = (image->offset_ > 0)
832 ? image->offset_ - (alpha->offset_ + alpha->size_) 814 ? image->offset_ - (alpha->offset_ + alpha->size_)
833 : 0; 815 : 0;
834 start_offset = alpha->offset_; 816 start_offset = alpha->offset_;
835 *data_size += alpha->size_ + inter_size; 817 *data_size += alpha->size_ + inter_size;
836 } 818 }
837 return mem_buf + start_offset; 819 return mem_buf + start_offset;
838 } 820 }
839 return NULL; 821 return NULL;
840 } 822 }
841 823
842 // Create a whole 'frame' from VP8 (+ alpha) or lossless. 824 // Create a whole 'frame' from VP8 (+ alpha) or lossless.
843 static int SynthesizeFrame(const WebPDemuxer* const dmux, 825 static int SynthesizeFrame(const WebPDemuxer* const dmux,
844 const Frame* const first_frame, 826 const Frame* const frame,
845 int fragment_num, WebPIterator* const iter) { 827 WebPIterator* const iter) {
846 const uint8_t* const mem_buf = dmux->mem_.buf_; 828 const uint8_t* const mem_buf = dmux->mem_.buf_;
847 int num_fragments;
848 size_t payload_size = 0; 829 size_t payload_size = 0;
849 const Frame* const fragment = 830 const uint8_t* const payload = GetFramePayload(mem_buf, frame, &payload_size);
850 GetFragment(first_frame, fragment_num, &num_fragments);
851 const uint8_t* const payload =
852 GetFramePayload(mem_buf, fragment, &payload_size);
853 if (payload == NULL) return 0; 831 if (payload == NULL) return 0;
854 assert(first_frame != NULL); 832 assert(frame != NULL);
855 833
856 iter->frame_num = first_frame->frame_num_; 834 iter->frame_num = frame->frame_num_;
857 iter->num_frames = dmux->num_frames_; 835 iter->num_frames = dmux->num_frames_;
858 iter->fragment_num = fragment_num; 836 iter->x_offset = frame->x_offset_;
859 iter->num_fragments = num_fragments; 837 iter->y_offset = frame->y_offset_;
860 iter->x_offset = fragment->x_offset_; 838 iter->width = frame->width_;
861 iter->y_offset = fragment->y_offset_; 839 iter->height = frame->height_;
862 iter->width = fragment->width_; 840 iter->has_alpha = frame->has_alpha_;
863 iter->height = fragment->height_; 841 iter->duration = frame->duration_;
864 iter->has_alpha = fragment->has_alpha_; 842 iter->dispose_method = frame->dispose_method_;
865 iter->duration = fragment->duration_; 843 iter->blend_method = frame->blend_method_;
866 iter->dispose_method = fragment->dispose_method_; 844 iter->complete = frame->complete_;
867 iter->blend_method = fragment->blend_method_;
868 iter->complete = fragment->complete_;
869 iter->fragment.bytes = payload; 845 iter->fragment.bytes = payload;
870 iter->fragment.size = payload_size; 846 iter->fragment.size = payload_size;
871 // TODO(jzern): adjust offsets for 'FRGM's embedded in 'ANMF's
872 return 1; 847 return 1;
873 } 848 }
874 849
875 static int SetFrame(int frame_num, WebPIterator* const iter) { 850 static int SetFrame(int frame_num, WebPIterator* const iter) {
876 const Frame* frame; 851 const Frame* frame;
877 const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; 852 const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_;
878 if (dmux == NULL || frame_num < 0) return 0; 853 if (dmux == NULL || frame_num < 0) return 0;
879 if (frame_num > dmux->num_frames_) return 0; 854 if (frame_num > dmux->num_frames_) return 0;
880 if (frame_num == 0) frame_num = dmux->num_frames_; 855 if (frame_num == 0) frame_num = dmux->num_frames_;
881 856
882 frame = GetFrame(dmux, frame_num); 857 frame = GetFrame(dmux, frame_num);
883 if (frame == NULL) return 0; 858 if (frame == NULL) return 0;
884 859
885 return SynthesizeFrame(dmux, frame, 1, iter); 860 return SynthesizeFrame(dmux, frame, iter);
886 } 861 }
887 862
888 int WebPDemuxGetFrame(const WebPDemuxer* dmux, int frame, WebPIterator* iter) { 863 int WebPDemuxGetFrame(const WebPDemuxer* dmux, int frame, WebPIterator* iter) {
889 if (iter == NULL) return 0; 864 if (iter == NULL) return 0;
890 865
891 memset(iter, 0, sizeof(*iter)); 866 memset(iter, 0, sizeof(*iter));
892 iter->private_ = (void*)dmux; 867 iter->private_ = (void*)dmux;
893 return SetFrame(frame, iter); 868 return SetFrame(frame, iter);
894 } 869 }
895 870
896 int WebPDemuxNextFrame(WebPIterator* iter) { 871 int WebPDemuxNextFrame(WebPIterator* iter) {
897 if (iter == NULL) return 0; 872 if (iter == NULL) return 0;
898 return SetFrame(iter->frame_num + 1, iter); 873 return SetFrame(iter->frame_num + 1, iter);
899 } 874 }
900 875
901 int WebPDemuxPrevFrame(WebPIterator* iter) { 876 int WebPDemuxPrevFrame(WebPIterator* iter) {
902 if (iter == NULL) return 0; 877 if (iter == NULL) return 0;
903 if (iter->frame_num <= 1) return 0; 878 if (iter->frame_num <= 1) return 0;
904 return SetFrame(iter->frame_num - 1, iter); 879 return SetFrame(iter->frame_num - 1, iter);
905 } 880 }
906 881
907 int WebPDemuxSelectFragment(WebPIterator* iter, int fragment_num) {
908 if (iter != NULL && iter->private_ != NULL && fragment_num > 0) {
909 const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_;
910 const Frame* const frame = GetFrame(dmux, iter->frame_num);
911 if (frame == NULL) return 0;
912
913 return SynthesizeFrame(dmux, frame, fragment_num, iter);
914 }
915 return 0;
916 }
917
918 void WebPDemuxReleaseIterator(WebPIterator* iter) { 882 void WebPDemuxReleaseIterator(WebPIterator* iter) {
919 (void)iter; 883 (void)iter;
920 } 884 }
921 885
922 // ----------------------------------------------------------------------------- 886 // -----------------------------------------------------------------------------
923 // Chunk iteration 887 // Chunk iteration
924 888
925 static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) { 889 static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) {
926 const uint8_t* const mem_buf = dmux->mem_.buf_; 890 const uint8_t* const mem_buf = dmux->mem_.buf_;
927 const Chunk* c; 891 const Chunk* c;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
993 (const char*)iter->chunk.bytes - CHUNK_HEADER_SIZE; 957 (const char*)iter->chunk.bytes - CHUNK_HEADER_SIZE;
994 return SetChunk(fourcc, iter->chunk_num - 1, iter); 958 return SetChunk(fourcc, iter->chunk_num - 1, iter);
995 } 959 }
996 return 0; 960 return 0;
997 } 961 }
998 962
999 void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) { 963 void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) {
1000 (void)iter; 964 (void)iter;
1001 } 965 }
1002 966
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698