diff options
Diffstat (limited to 'drivers/webp/demux/demux.c')
-rw-r--r-- | drivers/webp/demux/demux.c | 151 |
1 files changed, 80 insertions, 71 deletions
diff --git a/drivers/webp/demux/demux.c b/drivers/webp/demux/demux.c index 3717e21165..df93c5b379 100644 --- a/drivers/webp/demux/demux.c +++ b/drivers/webp/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; @@ -564,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) { @@ -597,16 +602,13 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { 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_) { @@ -631,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; } @@ -659,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; @@ -675,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; @@ -746,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_) { @@ -756,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) { @@ -797,31 +823,25 @@ 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; return 1; @@ -837,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) { @@ -859,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; } |