| Index: third_party/libwebp/demux/demux.c
|
| diff --git a/third_party/libwebp/demux/demux.c b/third_party/libwebp/demux/demux.c
|
| index 55a7918fbf3362cb998a70ef9eb0bcf69b47ebd6..0d2989f6f49d5c841a9993ad297ac66d38ea5db3 100644
|
| --- a/third_party/libwebp/demux/demux.c
|
| +++ b/third_party/libwebp/demux/demux.c
|
| @@ -24,8 +24,8 @@
|
| #include "../webp/format_constants.h"
|
|
|
| #define DMUX_MAJ_VERSION 0
|
| -#define DMUX_MIN_VERSION 2
|
| -#define DMUX_REV_VERSION 2
|
| +#define DMUX_MIN_VERSION 3
|
| +#define DMUX_REV_VERSION 0
|
|
|
| typedef struct {
|
| size_t start_; // start location of the data
|
| @@ -47,8 +47,7 @@ typedef struct Frame {
|
| int duration_;
|
| WebPMuxAnimDispose dispose_method_;
|
| WebPMuxAnimBlend blend_method_;
|
| - int is_fragment_; // this is a frame fragment (and not a full frame).
|
| - int frame_num_; // the referent frame number for use in assembling fragments.
|
| + int frame_num_;
|
| int complete_; // img_components_ contains a full image.
|
| ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH
|
| struct Frame* next_;
|
| @@ -193,6 +192,19 @@ static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) {
|
| return 1;
|
| }
|
|
|
| +static void SetFrameInfo(size_t start_offset, size_t size,
|
| + int frame_num, int complete,
|
| + const WebPBitstreamFeatures* const features,
|
| + Frame* const frame) {
|
| + frame->img_components_[0].offset_ = start_offset;
|
| + frame->img_components_[0].size_ = size;
|
| + frame->width_ = features->width;
|
| + frame->height_ = features->height;
|
| + frame->has_alpha_ |= features->has_alpha;
|
| + frame->frame_num_ = frame_num;
|
| + frame->complete_ = complete;
|
| +}
|
| +
|
| // Store image bearing chunks to 'frame'.
|
| static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
|
| MemBuffer* const mem, Frame* const frame) {
|
| @@ -248,13 +260,8 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
|
| return PARSE_ERROR;
|
| }
|
| ++image_chunks;
|
| - frame->img_components_[0].offset_ = chunk_start_offset;
|
| - frame->img_components_[0].size_ = chunk_size;
|
| - frame->width_ = features.width;
|
| - frame->height_ = features.height;
|
| - frame->has_alpha_ |= features.has_alpha;
|
| - frame->frame_num_ = frame_num;
|
| - frame->complete_ = (status == PARSE_OK);
|
| + SetFrameInfo(chunk_start_offset, chunk_size, frame_num,
|
| + status == PARSE_OK, &features, frame);
|
| Skip(mem, payload_available);
|
| } else {
|
| goto Done;
|
| @@ -337,42 +344,6 @@ static ParseStatus ParseAnimationFrame(
|
| return status;
|
| }
|
|
|
| -#ifdef WEBP_EXPERIMENTAL_FEATURES
|
| -// Parse a 'FRGM' chunk and any image bearing chunks that immediately follow.
|
| -// 'fragment_chunk_size' is the previously validated, padded chunk size.
|
| -static ParseStatus ParseFragment(WebPDemuxer* const dmux,
|
| - uint32_t fragment_chunk_size) {
|
| - const int frame_num = 1; // All fragments belong to the 1st (and only) frame.
|
| - const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
|
| - const uint32_t frgm_payload_size = fragment_chunk_size - FRGM_CHUNK_SIZE;
|
| - int added_fragment = 0;
|
| - MemBuffer* const mem = &dmux->mem_;
|
| - Frame* frame;
|
| - ParseStatus status =
|
| - NewFrame(mem, FRGM_CHUNK_SIZE, fragment_chunk_size, &frame);
|
| - if (status != PARSE_OK) return status;
|
| -
|
| - frame->is_fragment_ = 1;
|
| - frame->x_offset_ = 2 * ReadLE24s(mem);
|
| - frame->y_offset_ = 2 * ReadLE24s(mem);
|
| -
|
| - // Store a fragment only if the 'fragments' flag is set and there is some
|
| - // data available.
|
| - status = StoreFrame(frame_num, frgm_payload_size, mem, frame);
|
| - if (status != PARSE_ERROR && is_fragmented && frame->frame_num_ > 0) {
|
| - added_fragment = AddFrame(dmux, frame);
|
| - if (!added_fragment) {
|
| - status = PARSE_ERROR;
|
| - } else {
|
| - dmux->num_frames_ = 1;
|
| - }
|
| - }
|
| -
|
| - if (!added_fragment) WebPSafeFree(frame);
|
| - return status;
|
| -}
|
| -#endif // WEBP_EXPERIMENTAL_FEATURES
|
| -
|
| // General chunk storage, starting with the header at 'start_offset', allowing
|
| // the user to request the payload via a fourcc string. 'size' includes the
|
| // header and the unpadded payload size.
|
| @@ -513,12 +484,6 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
|
| status = ParseAnimationFrame(dmux, chunk_size_padded);
|
| break;
|
| }
|
| -#ifdef WEBP_EXPERIMENTAL_FEATURES
|
| - case MKFOURCC('F', 'R', 'G', 'M'): {
|
| - status = ParseFragment(dmux, chunk_size_padded);
|
| - break;
|
| - }
|
| -#endif
|
| case MKFOURCC('I', 'C', 'C', 'P'): {
|
| store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG);
|
| goto Skip;
|
| @@ -606,8 +571,6 @@ static int IsValidSimpleFormat(const WebPDemuxer* const dmux) {
|
|
|
| // If 'exact' is true, check that the image resolution matches the canvas.
|
| // If 'exact' is false, check that the x/y offsets do not exceed the canvas.
|
| -// TODO(jzern): this is insufficient in the fragmented image case if the
|
| -// expectation is that the fragments completely cover the canvas.
|
| static int CheckFrameBounds(const Frame* const frame, int exact,
|
| int canvas_width, int canvas_height) {
|
| if (exact) {
|
| @@ -635,22 +598,17 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
| if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
|
| if (dmux->loop_count_ < 0) return 0;
|
| if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
|
| -#ifndef WEBP_EXPERIMENTAL_FEATURES
|
| if (is_fragmented) return 0;
|
| -#endif
|
|
|
| while (f != NULL) {
|
| const int cur_frame_set = f->frame_num_;
|
| - int frame_count = 0, fragment_count = 0;
|
| + int frame_count = 0;
|
|
|
| - // Check frame properties and if the image is composed of fragments that
|
| - // each fragment came from a fragment.
|
| + // Check frame properties.
|
| for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
|
| const ChunkData* const image = f->img_components_;
|
| const ChunkData* const alpha = f->img_components_ + 1;
|
|
|
| - if (is_fragmented && !f->is_fragment_) return 0;
|
| - if (!is_fragmented && f->is_fragment_) return 0;
|
| if (!is_animation && f->frame_num_ > 1) return 0;
|
|
|
| if (f->complete_) {
|
| @@ -675,16 +633,13 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
| }
|
|
|
| if (f->width_ > 0 && f->height_ > 0 &&
|
| - !CheckFrameBounds(f, !(is_animation || is_fragmented),
|
| + !CheckFrameBounds(f, !is_animation,
|
| dmux->canvas_width_, dmux->canvas_height_)) {
|
| return 0;
|
| }
|
|
|
| - fragment_count += f->is_fragment_;
|
| ++frame_count;
|
| }
|
| - if (!is_fragmented && frame_count > 1) return 0;
|
| - if (fragment_count > 0 && frame_count != fragment_count) return 0;
|
| }
|
| return 1;
|
| }
|
| @@ -703,6 +658,41 @@ static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) {
|
| dmux->mem_ = *mem;
|
| }
|
|
|
| +static ParseStatus CreateRawImageDemuxer(MemBuffer* const mem,
|
| + WebPDemuxer** demuxer) {
|
| + WebPBitstreamFeatures features;
|
| + const VP8StatusCode status =
|
| + WebPGetFeatures(mem->buf_, mem->buf_size_, &features);
|
| + *demuxer = NULL;
|
| + if (status != VP8_STATUS_OK) {
|
| + return (status == VP8_STATUS_NOT_ENOUGH_DATA) ? PARSE_NEED_MORE_DATA
|
| + : PARSE_ERROR;
|
| + }
|
| +
|
| + {
|
| + WebPDemuxer* const dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux));
|
| + Frame* const frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame));
|
| + if (dmux == NULL || frame == NULL) goto Error;
|
| + InitDemux(dmux, mem);
|
| + SetFrameInfo(0, mem->buf_size_, 1 /*frame_num*/, 1 /*complete*/, &features,
|
| + frame);
|
| + if (!AddFrame(dmux, frame)) goto Error;
|
| + dmux->state_ = WEBP_DEMUX_DONE;
|
| + dmux->canvas_width_ = frame->width_;
|
| + dmux->canvas_height_ = frame->height_;
|
| + dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0;
|
| + dmux->num_frames_ = 1;
|
| + assert(IsValidSimpleFormat(dmux));
|
| + *demuxer = dmux;
|
| + return PARSE_OK;
|
| +
|
| + Error:
|
| + WebPSafeFree(dmux);
|
| + WebPSafeFree(frame);
|
| + return PARSE_ERROR;
|
| + }
|
| +}
|
| +
|
| WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
|
| WebPDemuxState* state, int version) {
|
| const ChunkParser* parser;
|
| @@ -719,6 +709,15 @@ WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
|
| if (!InitMemBuffer(&mem, data->bytes, data->size)) return NULL;
|
| status = ReadHeader(&mem);
|
| if (status != PARSE_OK) {
|
| + // If parsing of the webp file header fails attempt to handle a raw
|
| + // VP8/VP8L frame. Note 'allow_partial' is ignored in this case.
|
| + if (status == PARSE_ERROR) {
|
| + status = CreateRawImageDemuxer(&mem, &dmux);
|
| + if (status == PARSE_OK) {
|
| + if (state != NULL) *state = WEBP_DEMUX_DONE;
|
| + return dmux;
|
| + }
|
| + }
|
| if (state != NULL) {
|
| *state = (status == PARSE_NEED_MORE_DATA) ? WEBP_DEMUX_PARSING_HEADER
|
| : WEBP_DEMUX_PARSE_ERROR;
|
| @@ -790,8 +789,6 @@ uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) {
|
| // -----------------------------------------------------------------------------
|
| // Frame iteration
|
|
|
| -// Find the first 'frame_num' frame. There may be multiple such frames in a
|
| -// fragmented frame.
|
| static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) {
|
| const Frame* f;
|
| for (f = dmux->frames_; f != NULL; f = f->next_) {
|
| @@ -800,21 +797,6 @@ static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) {
|
| return f;
|
| }
|
|
|
| -// Returns fragment 'fragment_num' and the total count.
|
| -static const Frame* GetFragment(
|
| - const Frame* const frame_set, int fragment_num, int* const count) {
|
| - const int this_frame = frame_set->frame_num_;
|
| - const Frame* f = frame_set;
|
| - const Frame* fragment = NULL;
|
| - int total;
|
| -
|
| - for (total = 0; f != NULL && f->frame_num_ == this_frame; f = f->next_) {
|
| - if (++total == fragment_num) fragment = f;
|
| - }
|
| - *count = total;
|
| - return fragment;
|
| -}
|
| -
|
| static const uint8_t* GetFramePayload(const uint8_t* const mem_buf,
|
| const Frame* const frame,
|
| size_t* const data_size) {
|
| @@ -841,34 +823,27 @@ static const uint8_t* GetFramePayload(const uint8_t* const mem_buf,
|
|
|
| // Create a whole 'frame' from VP8 (+ alpha) or lossless.
|
| static int SynthesizeFrame(const WebPDemuxer* const dmux,
|
| - const Frame* const first_frame,
|
| - int fragment_num, WebPIterator* const iter) {
|
| + const Frame* const frame,
|
| + WebPIterator* const iter) {
|
| const uint8_t* const mem_buf = dmux->mem_.buf_;
|
| - int num_fragments;
|
| size_t payload_size = 0;
|
| - const Frame* const fragment =
|
| - GetFragment(first_frame, fragment_num, &num_fragments);
|
| - const uint8_t* const payload =
|
| - GetFramePayload(mem_buf, fragment, &payload_size);
|
| + const uint8_t* const payload = GetFramePayload(mem_buf, frame, &payload_size);
|
| if (payload == NULL) return 0;
|
| - assert(first_frame != NULL);
|
| + assert(frame != NULL);
|
|
|
| - iter->frame_num = first_frame->frame_num_;
|
| + iter->frame_num = frame->frame_num_;
|
| iter->num_frames = dmux->num_frames_;
|
| - iter->fragment_num = fragment_num;
|
| - iter->num_fragments = num_fragments;
|
| - iter->x_offset = fragment->x_offset_;
|
| - iter->y_offset = fragment->y_offset_;
|
| - iter->width = fragment->width_;
|
| - iter->height = fragment->height_;
|
| - iter->has_alpha = fragment->has_alpha_;
|
| - iter->duration = fragment->duration_;
|
| - iter->dispose_method = fragment->dispose_method_;
|
| - iter->blend_method = fragment->blend_method_;
|
| - iter->complete = fragment->complete_;
|
| + iter->x_offset = frame->x_offset_;
|
| + iter->y_offset = frame->y_offset_;
|
| + iter->width = frame->width_;
|
| + iter->height = frame->height_;
|
| + iter->has_alpha = frame->has_alpha_;
|
| + iter->duration = frame->duration_;
|
| + iter->dispose_method = frame->dispose_method_;
|
| + iter->blend_method = frame->blend_method_;
|
| + iter->complete = frame->complete_;
|
| iter->fragment.bytes = payload;
|
| iter->fragment.size = payload_size;
|
| - // TODO(jzern): adjust offsets for 'FRGM's embedded in 'ANMF's
|
| return 1;
|
| }
|
|
|
| @@ -882,7 +857,7 @@ static int SetFrame(int frame_num, WebPIterator* const iter) {
|
| frame = GetFrame(dmux, frame_num);
|
| if (frame == NULL) return 0;
|
|
|
| - return SynthesizeFrame(dmux, frame, 1, iter);
|
| + return SynthesizeFrame(dmux, frame, iter);
|
| }
|
|
|
| int WebPDemuxGetFrame(const WebPDemuxer* dmux, int frame, WebPIterator* iter) {
|
| @@ -904,17 +879,6 @@ int WebPDemuxPrevFrame(WebPIterator* iter) {
|
| return SetFrame(iter->frame_num - 1, iter);
|
| }
|
|
|
| -int WebPDemuxSelectFragment(WebPIterator* iter, int fragment_num) {
|
| - if (iter != NULL && iter->private_ != NULL && fragment_num > 0) {
|
| - const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_;
|
| - const Frame* const frame = GetFrame(dmux, iter->frame_num);
|
| - if (frame == NULL) return 0;
|
| -
|
| - return SynthesizeFrame(dmux, frame, fragment_num, iter);
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| void WebPDemuxReleaseIterator(WebPIterator* iter) {
|
| (void)iter;
|
| }
|
|
|