summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libwebp/src/demux/demux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/libwebp/src/demux/demux.c')
-rw-r--r--src/3rdparty/libwebp/src/demux/demux.c196
1 files changed, 80 insertions, 116 deletions
diff --git a/src/3rdparty/libwebp/src/demux/demux.c b/src/3rdparty/libwebp/src/demux/demux.c
index 55a7918..0d2989f 100644
--- a/src/3rdparty/libwebp/src/demux/demux.c
+++ b/src/3rdparty/libwebp/src/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;
}