summaryrefslogtreecommitdiff
path: root/drivers/webp/mux/muxread.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/webp/mux/muxread.c')
-rw-r--r--drivers/webp/mux/muxread.c449
1 files changed, 291 insertions, 158 deletions
diff --git a/drivers/webp/mux/muxread.c b/drivers/webp/mux/muxread.c
index 21c3cfbaeb..8957a1e46e 100644
--- a/drivers/webp/mux/muxread.c
+++ b/drivers/webp/mux/muxread.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Read APIs for mux.
@@ -12,10 +14,7 @@
#include <assert.h>
#include "./muxi.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "../utils/utils.h"
//------------------------------------------------------------------------------
// Helper method(s).
@@ -41,8 +40,9 @@ static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx,
SWITCH_ID_LIST(IDX_VP8X, mux->vp8x_);
SWITCH_ID_LIST(IDX_ICCP, mux->iccp_);
- SWITCH_ID_LIST(IDX_LOOP, mux->loop_);
- SWITCH_ID_LIST(IDX_META, mux->meta_);
+ SWITCH_ID_LIST(IDX_ANIM, mux->anim_);
+ SWITCH_ID_LIST(IDX_EXIF, mux->exif_);
+ SWITCH_ID_LIST(IDX_XMP, mux->xmp_);
SWITCH_ID_LIST(IDX_UNKNOWN, mux->unknown_);
return WEBP_MUX_NOT_FOUND;
}
@@ -50,15 +50,14 @@ static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx,
// Fill the chunk with the given data (includes chunk header bytes), after some
// verifications.
-static WebPMuxError ChunkVerifyAndAssignData(WebPChunk* chunk,
- const uint8_t* data,
- size_t data_size, size_t riff_size,
- int copy_data) {
+static WebPMuxError ChunkVerifyAndAssign(WebPChunk* chunk,
+ const uint8_t* data, size_t data_size,
+ size_t riff_size, int copy_data) {
uint32_t chunk_size;
WebPData chunk_data;
// Sanity checks.
- if (data_size < TAG_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA;
+ if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA;
chunk_size = GetLE32(data + TAG_SIZE);
{
@@ -68,11 +67,103 @@ static WebPMuxError ChunkVerifyAndAssignData(WebPChunk* chunk,
}
// Data assignment.
- chunk_data.bytes_ = data + CHUNK_HEADER_SIZE;
- chunk_data.size_ = chunk_size;
+ chunk_data.bytes = data + CHUNK_HEADER_SIZE;
+ chunk_data.size = chunk_size;
return ChunkAssignData(chunk, &chunk_data, copy_data, GetLE32(data + 0));
}
+int MuxImageFinalize(WebPMuxImage* const wpi) {
+ const WebPChunk* const img = wpi->img_;
+ const WebPData* const image = &img->data_;
+ const int is_lossless = (img->tag_ == kChunks[IDX_VP8L].tag);
+ int w, h;
+ int vp8l_has_alpha = 0;
+ const int ok = is_lossless ?
+ VP8LGetInfo(image->bytes, image->size, &w, &h, &vp8l_has_alpha) :
+ VP8GetInfo(image->bytes, image->size, image->size, &w, &h);
+ assert(img != NULL);
+ if (ok) {
+ // Ignore ALPH chunk accompanying VP8L.
+ if (is_lossless && (wpi->alpha_ != NULL)) {
+ ChunkDelete(wpi->alpha_);
+ wpi->alpha_ = NULL;
+ }
+ wpi->width_ = w;
+ wpi->height_ = h;
+ wpi->has_alpha_ = vp8l_has_alpha || (wpi->alpha_ != NULL);
+ }
+ return ok;
+}
+
+static int MuxImageParse(const WebPChunk* const chunk, int copy_data,
+ WebPMuxImage* const wpi) {
+ const uint8_t* bytes = chunk->data_.bytes;
+ size_t size = chunk->data_.size;
+ const uint8_t* const last = bytes + size;
+ WebPChunk subchunk;
+ size_t subchunk_size;
+ ChunkInit(&subchunk);
+
+ assert(chunk->tag_ == kChunks[IDX_ANMF].tag ||
+ chunk->tag_ == kChunks[IDX_FRGM].tag);
+ assert(!wpi->is_partial_);
+
+ // ANMF/FRGM.
+ {
+ const size_t hdr_size = (chunk->tag_ == kChunks[IDX_ANMF].tag) ?
+ ANMF_CHUNK_SIZE : FRGM_CHUNK_SIZE;
+ const WebPData temp = { bytes, hdr_size };
+ // Each of ANMF and FRGM chunk contain a header at the beginning. So, its
+ // size should at least be 'hdr_size'.
+ if (size < hdr_size) goto Fail;
+ ChunkAssignData(&subchunk, &temp, copy_data, chunk->tag_);
+ }
+ ChunkSetNth(&subchunk, &wpi->header_, 1);
+ wpi->is_partial_ = 1; // Waiting for ALPH and/or VP8/VP8L chunks.
+
+ // Rest of the chunks.
+ subchunk_size = ChunkDiskSize(&subchunk) - CHUNK_HEADER_SIZE;
+ bytes += subchunk_size;
+ size -= subchunk_size;
+
+ while (bytes != last) {
+ ChunkInit(&subchunk);
+ if (ChunkVerifyAndAssign(&subchunk, bytes, size, size,
+ copy_data) != WEBP_MUX_OK) {
+ goto Fail;
+ }
+ switch (ChunkGetIdFromTag(subchunk.tag_)) {
+ case WEBP_CHUNK_ALPHA:
+ if (wpi->alpha_ != NULL) goto Fail; // Consecutive ALPH chunks.
+ if (ChunkSetNth(&subchunk, &wpi->alpha_, 1) != WEBP_MUX_OK) goto Fail;
+ wpi->is_partial_ = 1; // Waiting for a VP8 chunk.
+ break;
+ case WEBP_CHUNK_IMAGE:
+ if (ChunkSetNth(&subchunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Fail;
+ if (!MuxImageFinalize(wpi)) goto Fail;
+ wpi->is_partial_ = 0; // wpi is completely filled.
+ break;
+ case WEBP_CHUNK_UNKNOWN:
+ if (wpi->is_partial_) goto Fail; // Encountered an unknown chunk
+ // before some image chunks.
+ if (ChunkSetNth(&subchunk, &wpi->unknown_, 0) != WEBP_MUX_OK) goto Fail;
+ break;
+ default:
+ goto Fail;
+ break;
+ }
+ subchunk_size = ChunkDiskSize(&subchunk);
+ bytes += subchunk_size;
+ size -= subchunk_size;
+ }
+ if (wpi->is_partial_) goto Fail;
+ return 1;
+
+ Fail:
+ ChunkRelease(&subchunk);
+ return 0;
+}
+
//------------------------------------------------------------------------------
// Create a mux object from WebP-RIFF data.
@@ -94,8 +185,8 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
}
if (bitstream == NULL) return NULL;
- data = bitstream->bytes_;
- size = bitstream->size_;
+ data = bitstream->bytes;
+ size = bitstream->size;
if (data == NULL) return NULL;
if (size < RIFF_HEADER_SIZE) return NULL;
@@ -129,48 +220,55 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
data += RIFF_HEADER_SIZE;
size -= RIFF_HEADER_SIZE;
- wpi = (WebPMuxImage*)malloc(sizeof(*wpi));
+ wpi = (WebPMuxImage*)WebPSafeMalloc(1ULL, sizeof(*wpi));
if (wpi == NULL) goto Err;
MuxImageInit(wpi);
// Loop over chunks.
while (data != end) {
+ size_t data_size;
WebPChunkId id;
- WebPMuxError err;
-
- err = ChunkVerifyAndAssignData(&chunk, data, size, riff_size, copy_data);
- if (err != WEBP_MUX_OK) goto Err;
-
+ WebPChunk** chunk_list;
+ if (ChunkVerifyAndAssign(&chunk, data, size, riff_size,
+ copy_data) != WEBP_MUX_OK) {
+ goto Err;
+ }
+ data_size = ChunkDiskSize(&chunk);
id = ChunkGetIdFromTag(chunk.tag_);
-
- if (IsWPI(id)) { // An image chunk (frame/tile/alpha/vp8).
- WebPChunk** wpi_chunk_ptr =
- MuxImageGetListFromId(wpi, id); // Image chunk to set.
- assert(wpi_chunk_ptr != NULL);
- if (*wpi_chunk_ptr != NULL) goto Err; // Consecutive alpha chunks or
- // consecutive frame/tile chunks.
- if (ChunkSetNth(&chunk, wpi_chunk_ptr, 1) != WEBP_MUX_OK) goto Err;
- if (id == WEBP_CHUNK_IMAGE) {
+ switch (id) {
+ case WEBP_CHUNK_ALPHA:
+ if (wpi->alpha_ != NULL) goto Err; // Consecutive ALPH chunks.
+ if (ChunkSetNth(&chunk, &wpi->alpha_, 1) != WEBP_MUX_OK) goto Err;
+ wpi->is_partial_ = 1; // Waiting for a VP8 chunk.
+ break;
+ case WEBP_CHUNK_IMAGE:
+ if (ChunkSetNth(&chunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Err;
+ if (!MuxImageFinalize(wpi)) goto Err;
wpi->is_partial_ = 0; // wpi is completely filled.
+ PushImage:
// Add this to mux->images_ list.
if (MuxImagePush(wpi, &mux->images_) != WEBP_MUX_OK) goto Err;
MuxImageInit(wpi); // Reset for reading next image.
- } else {
- wpi->is_partial_ = 1; // wpi is only partially filled.
- }
- } else { // A non-image chunk.
- WebPChunk** chunk_list;
- if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before
- // getting all chunks of an image.
- chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk.
- if (chunk_list == NULL) chunk_list = &mux->unknown_;
- if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err;
- }
- {
- const size_t data_size = ChunkDiskSize(&chunk);
- data += data_size;
- size -= data_size;
+ break;
+ case WEBP_CHUNK_ANMF:
+ if (wpi->is_partial_) goto Err; // Previous wpi is still incomplete.
+ if (!MuxImageParse(&chunk, copy_data, wpi)) goto Err;
+ ChunkRelease(&chunk);
+ goto PushImage;
+ break;
+ default: // A non-image chunk.
+ if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before
+ // getting all chunks of an image.
+ chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk.
+ if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err;
+ if (id == WEBP_CHUNK_VP8X) { // grab global specs
+ mux->canvas_width_ = GetLE24(data + 12) + 1;
+ mux->canvas_height_ = GetLE24(data + 15) + 1;
+ }
+ break;
}
+ data += data_size;
+ size -= data_size;
ChunkInit(&chunk);
}
@@ -190,31 +288,74 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
//------------------------------------------------------------------------------
// Get API(s).
-WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) {
- WebPData data;
- WebPMuxError err;
+// Validates that the given mux has a single image.
+static WebPMuxError ValidateForSingleImage(const WebPMux* const mux) {
+ const int num_images = MuxImageCount(mux->images_, WEBP_CHUNK_IMAGE);
+ const int num_frames = MuxImageCount(mux->images_, WEBP_CHUNK_ANMF);
+ const int num_fragments = MuxImageCount(mux->images_, WEBP_CHUNK_FRGM);
+
+ if (num_images == 0) {
+ // No images in mux.
+ return WEBP_MUX_NOT_FOUND;
+ } else if (num_images == 1 && num_frames == 0 && num_fragments == 0) {
+ // Valid case (single image).
+ return WEBP_MUX_OK;
+ } else {
+ // Frame/Fragment case OR an invalid mux.
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+}
- if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT;
- *flags = 0;
+// Get the canvas width, height and flags after validating that VP8X/VP8/VP8L
+// chunk and canvas size are valid.
+static WebPMuxError MuxGetCanvasInfo(const WebPMux* const mux,
+ int* width, int* height, uint32_t* flags) {
+ int w, h;
+ uint32_t f = 0;
+ WebPData data;
+ assert(mux != NULL);
// Check if VP8X chunk is present.
- err = MuxGet(mux, IDX_VP8X, 1, &data);
- if (err == WEBP_MUX_NOT_FOUND) {
- // Check if VP8/VP8L chunk is present.
- err = WebPMuxGetImage(mux, &data);
- WebPDataClear(&data);
- return err;
- } else if (err != WEBP_MUX_OK) {
- return err;
+ if (MuxGet(mux, IDX_VP8X, 1, &data) == WEBP_MUX_OK) {
+ if (data.size < VP8X_CHUNK_SIZE) return WEBP_MUX_BAD_DATA;
+ f = GetLE32(data.bytes + 0);
+ w = GetLE24(data.bytes + 4) + 1;
+ h = GetLE24(data.bytes + 7) + 1;
+ } else {
+ const WebPMuxImage* const wpi = mux->images_;
+ // Grab user-forced canvas size as default.
+ w = mux->canvas_width_;
+ h = mux->canvas_height_;
+ if (w == 0 && h == 0 && ValidateForSingleImage(mux) == WEBP_MUX_OK) {
+ // single image and not forced canvas size => use dimension of first frame
+ assert(wpi != NULL);
+ w = wpi->width_;
+ h = wpi->height_;
+ }
+ if (wpi != NULL) {
+ if (wpi->has_alpha_) f |= ALPHA_FLAG;
+ }
}
+ if (w * (uint64_t)h >= MAX_IMAGE_AREA) return WEBP_MUX_BAD_DATA;
- if (data.size_ < CHUNK_SIZE_BYTES) return WEBP_MUX_BAD_DATA;
-
- // All OK. Fill up flags.
- *flags = GetLE32(data.bytes_);
+ if (width != NULL) *width = w;
+ if (height != NULL) *height = h;
+ if (flags != NULL) *flags = f;
return WEBP_MUX_OK;
}
+WebPMuxError WebPMuxGetCanvasSize(const WebPMux* mux, int* width, int* height) {
+ if (mux == NULL || width == NULL || height == NULL) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ return MuxGetCanvasInfo(mux, width, height, NULL);
+}
+
+WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) {
+ if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ return MuxGetCanvasInfo(mux, NULL, NULL, flags);
+}
+
static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width,
int height, uint32_t flags) {
const size_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
@@ -230,7 +371,7 @@ static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width,
}
// Assemble a single image WebP bitstream from 'wpi'.
-static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi,
+static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi,
WebPData* const bitstream) {
uint8_t* dst;
@@ -238,25 +379,17 @@ static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi,
const int need_vp8x = (wpi->alpha_ != NULL);
const size_t vp8x_size = need_vp8x ? CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE : 0;
const size_t alpha_size = need_vp8x ? ChunkDiskSize(wpi->alpha_) : 0;
- // Note: No need to output FRM/TILE chunk for a single image.
+ // Note: No need to output ANMF/FRGM chunk for a single image.
const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size +
ChunkDiskSize(wpi->img_);
- uint8_t* const data = (uint8_t*)malloc(size);
+ uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
// Main RIFF header.
dst = MuxEmitRiffHeader(data, size);
if (need_vp8x) {
- int w, h;
- WebPMuxError err;
- assert(wpi->img_ != NULL);
- err = MuxGetImageWidthHeight(wpi->img_, &w, &h);
- if (err != WEBP_MUX_OK) {
- free(data);
- return err;
- }
- dst = EmitVP8XChunk(dst, w, h, ALPHA_FLAG); // VP8X.
+ dst = EmitVP8XChunk(dst, wpi->width_, wpi->height_, ALPHA_FLAG); // VP8X.
dst = ChunkListEmit(wpi->alpha_, dst); // ALPH.
}
@@ -265,107 +398,115 @@ static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi,
assert(dst == data + size);
// Output.
- bitstream->bytes_ = data;
- bitstream->size_ = size;
+ bitstream->bytes = data;
+ bitstream->size = size;
return WEBP_MUX_OK;
}
-WebPMuxError WebPMuxGetImage(const WebPMux* mux, WebPData* bitstream) {
- WebPMuxError err;
- WebPMuxImage* wpi = NULL;
-
- if (mux == NULL || bitstream == NULL) {
+WebPMuxError WebPMuxGetChunk(const WebPMux* mux, const char fourcc[4],
+ WebPData* chunk_data) {
+ CHUNK_INDEX idx;
+ if (mux == NULL || fourcc == NULL || chunk_data == NULL) {
return WEBP_MUX_INVALID_ARGUMENT;
}
-
- err = MuxValidateForImage(mux);
- if (err != WEBP_MUX_OK) return err;
-
- // All well. Get the image.
- err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, WEBP_CHUNK_IMAGE,
- &wpi);
- assert(err == WEBP_MUX_OK); // Already tested above.
-
- return SynthesizeBitstream(wpi, bitstream);
-}
-
-WebPMuxError WebPMuxGetMetadata(const WebPMux* mux, WebPData* metadata) {
- if (mux == NULL || metadata == NULL) return WEBP_MUX_INVALID_ARGUMENT;
- return MuxGet(mux, IDX_META, 1, metadata);
+ idx = ChunkGetIndexFromFourCC(fourcc);
+ if (IsWPI(kChunks[idx].id)) { // An image chunk.
+ return WEBP_MUX_INVALID_ARGUMENT;
+ } else if (idx != IDX_UNKNOWN) { // A known chunk type.
+ return MuxGet(mux, idx, 1, chunk_data);
+ } else { // An unknown chunk type.
+ const WebPChunk* const chunk =
+ ChunkSearchList(mux->unknown_, 1, ChunkGetTagFromFourCC(fourcc));
+ if (chunk == NULL) return WEBP_MUX_NOT_FOUND;
+ *chunk_data = chunk->data_;
+ return WEBP_MUX_OK;
+ }
}
-WebPMuxError WebPMuxGetColorProfile(const WebPMux* mux,
- WebPData* color_profile) {
- if (mux == NULL || color_profile == NULL) return WEBP_MUX_INVALID_ARGUMENT;
- return MuxGet(mux, IDX_ICCP, 1, color_profile);
+static WebPMuxError MuxGetImageInternal(const WebPMuxImage* const wpi,
+ WebPMuxFrameInfo* const info) {
+ // Set some defaults for unrelated fields.
+ info->x_offset = 0;
+ info->y_offset = 0;
+ info->duration = 1;
+ info->dispose_method = WEBP_MUX_DISPOSE_NONE;
+ info->blend_method = WEBP_MUX_BLEND;
+ // Extract data for related fields.
+ info->id = ChunkGetIdFromTag(wpi->img_->tag_);
+ return SynthesizeBitstream(wpi, &info->bitstream);
}
-WebPMuxError WebPMuxGetLoopCount(const WebPMux* mux, int* loop_count) {
- WebPData image;
- WebPMuxError err;
-
- if (mux == NULL || loop_count == NULL) return WEBP_MUX_INVALID_ARGUMENT;
-
- err = MuxGet(mux, IDX_LOOP, 1, &image);
- if (err != WEBP_MUX_OK) return err;
- if (image.size_ < kChunks[WEBP_CHUNK_LOOP].size) return WEBP_MUX_BAD_DATA;
- *loop_count = GetLE16(image.bytes_);
-
- return WEBP_MUX_OK;
+static WebPMuxError MuxGetFrameFragmentInternal(const WebPMuxImage* const wpi,
+ WebPMuxFrameInfo* const frame) {
+ const int is_frame = (wpi->header_->tag_ == kChunks[IDX_ANMF].tag);
+ const CHUNK_INDEX idx = is_frame ? IDX_ANMF : IDX_FRGM;
+ const WebPData* frame_frgm_data;
+ if (!is_frame) return WEBP_MUX_INVALID_ARGUMENT;
+ assert(wpi->header_ != NULL); // Already checked by WebPMuxGetFrame().
+ // Get frame/fragment chunk.
+ frame_frgm_data = &wpi->header_->data_;
+ if (frame_frgm_data->size < kChunks[idx].size) return WEBP_MUX_BAD_DATA;
+ // Extract info.
+ frame->x_offset = 2 * GetLE24(frame_frgm_data->bytes + 0);
+ frame->y_offset = 2 * GetLE24(frame_frgm_data->bytes + 3);
+ if (is_frame) {
+ const uint8_t bits = frame_frgm_data->bytes[15];
+ frame->duration = GetLE24(frame_frgm_data->bytes + 12);
+ frame->dispose_method =
+ (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
+ frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
+ } else { // Defaults for unused values.
+ frame->duration = 1;
+ frame->dispose_method = WEBP_MUX_DISPOSE_NONE;
+ frame->blend_method = WEBP_MUX_BLEND;
+ }
+ frame->id = ChunkGetIdFromTag(wpi->header_->tag_);
+ return SynthesizeBitstream(wpi, &frame->bitstream);
}
-static WebPMuxError MuxGetFrameTileInternal(
- const WebPMux* const mux, uint32_t nth, WebPData* const bitstream,
- int* const x_offset, int* const y_offset, int* const duration,
- uint32_t tag) {
- const WebPData* frame_tile_data;
+WebPMuxError WebPMuxGetFrame(
+ const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame) {
WebPMuxError err;
WebPMuxImage* wpi;
- const int is_frame = (tag == kChunks[WEBP_CHUNK_FRAME].tag) ? 1 : 0;
- const CHUNK_INDEX idx = is_frame ? IDX_FRAME : IDX_TILE;
- const WebPChunkId id = kChunks[idx].id;
-
- if (mux == NULL || bitstream == NULL ||
- x_offset == NULL || y_offset == NULL || (is_frame && duration == NULL)) {
+ // Sanity checks.
+ if (mux == NULL || frame == NULL) {
return WEBP_MUX_INVALID_ARGUMENT;
}
// Get the nth WebPMuxImage.
- err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, id, &wpi);
+ err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, &wpi);
if (err != WEBP_MUX_OK) return err;
- // Get frame chunk.
- assert(wpi->header_ != NULL); // As MuxImageGetNth() already checked header_.
- frame_tile_data = &wpi->header_->data_;
+ // Get frame info.
+ if (wpi->header_ == NULL) {
+ return MuxGetImageInternal(wpi, frame);
+ } else {
+ return MuxGetFrameFragmentInternal(wpi, frame);
+ }
+}
- if (frame_tile_data->size_ < kChunks[idx].size) return WEBP_MUX_BAD_DATA;
- *x_offset = 2 * GetLE24(frame_tile_data->bytes_ + 0);
- *y_offset = 2 * GetLE24(frame_tile_data->bytes_ + 3);
- if (is_frame) *duration = 1 + GetLE24(frame_tile_data->bytes_ + 12);
+WebPMuxError WebPMuxGetAnimationParams(const WebPMux* mux,
+ WebPMuxAnimParams* params) {
+ WebPData anim;
+ WebPMuxError err;
- return SynthesizeBitstream(wpi, bitstream);
-}
+ if (mux == NULL || params == NULL) return WEBP_MUX_INVALID_ARGUMENT;
-WebPMuxError WebPMuxGetFrame(const WebPMux* mux, uint32_t nth,
- WebPData* bitstream,
- int* x_offset, int* y_offset, int* duration) {
- return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset,
- duration, kChunks[IDX_FRAME].tag);
-}
+ err = MuxGet(mux, IDX_ANIM, 1, &anim);
+ if (err != WEBP_MUX_OK) return err;
+ if (anim.size < kChunks[WEBP_CHUNK_ANIM].size) return WEBP_MUX_BAD_DATA;
+ params->bgcolor = GetLE32(anim.bytes);
+ params->loop_count = GetLE16(anim.bytes + 4);
-WebPMuxError WebPMuxGetTile(const WebPMux* mux, uint32_t nth,
- WebPData* bitstream,
- int* x_offset, int* y_offset) {
- return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset, NULL,
- kChunks[IDX_TILE].tag);
+ return WEBP_MUX_OK;
}
// Get chunk index from chunk id. Returns IDX_NIL if not found.
static CHUNK_INDEX ChunkGetIndexFromId(WebPChunkId id) {
int i;
for (i = 0; kChunks[i].id != WEBP_CHUNK_NIL; ++i) {
- if (id == kChunks[i].id) return i;
+ if (id == kChunks[i].id) return (CHUNK_INDEX)i;
}
return IDX_NIL;
}
@@ -393,19 +534,11 @@ WebPMuxError WebPMuxNumChunks(const WebPMux* mux,
*num_elements = MuxImageCount(mux->images_, id);
} else {
WebPChunk* const* chunk_list = MuxGetChunkListFromId(mux, id);
- if (chunk_list == NULL) {
- *num_elements = 0;
- } else {
- const CHUNK_INDEX idx = ChunkGetIndexFromId(id);
- *num_elements = CountChunks(*chunk_list, kChunks[idx].tag);
- }
+ const CHUNK_INDEX idx = ChunkGetIndexFromId(id);
+ *num_elements = CountChunks(*chunk_list, kChunks[idx].tag);
}
return WEBP_MUX_OK;
}
//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif