diff options
Diffstat (limited to 'drivers/webp/mux/muxread.c')
-rw-r--r-- | drivers/webp/mux/muxread.c | 437 |
1 files changed, 154 insertions, 283 deletions
diff --git a/drivers/webp/mux/muxread.c b/drivers/webp/mux/muxread.c index 6003a25b71..21c3cfbaeb 100644 --- a/drivers/webp/mux/muxread.c +++ b/drivers/webp/mux/muxread.c @@ -1,10 +1,8 @@ // Copyright 2011 Google Inc. All Rights Reserved. // -// 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. +// 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/ // ----------------------------------------------------------------------------- // // Read APIs for mux. @@ -14,7 +12,10 @@ #include <assert.h> #include "./muxi.h" -#include "../utils/utils.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif //------------------------------------------------------------------------------ // Helper method(s). @@ -40,9 +41,8 @@ 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_ANIM, mux->anim_); - SWITCH_ID_LIST(IDX_EXIF, mux->exif_); - SWITCH_ID_LIST(IDX_XMP, mux->xmp_); + SWITCH_ID_LIST(IDX_LOOP, mux->loop_); + SWITCH_ID_LIST(IDX_META, mux->meta_); SWITCH_ID_LIST(IDX_UNKNOWN, mux->unknown_); return WEBP_MUX_NOT_FOUND; } @@ -50,9 +50,10 @@ 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 ChunkVerifyAndAssign(WebPChunk* chunk, - const uint8_t* data, size_t data_size, - size_t riff_size, int copy_data) { +static WebPMuxError ChunkVerifyAndAssignData(WebPChunk* chunk, + const uint8_t* data, + size_t data_size, size_t riff_size, + int copy_data) { uint32_t chunk_size; WebPData chunk_data; @@ -67,103 +68,11 @@ static WebPMuxError ChunkVerifyAndAssign(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. @@ -185,8 +94,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; @@ -226,48 +135,42 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, // Loop over chunks. while (data != end) { - size_t data_size; WebPChunkId id; - WebPChunk** chunk_list; - if (ChunkVerifyAndAssign(&chunk, data, size, riff_size, - copy_data) != WEBP_MUX_OK) { - goto Err; - } - data_size = ChunkDiskSize(&chunk); + WebPMuxError err; + + err = ChunkVerifyAndAssignData(&chunk, data, size, riff_size, copy_data); + if (err != WEBP_MUX_OK) goto Err; + id = ChunkGetIdFromTag(chunk.tag_); - 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; + + 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) { 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. - break; - case WEBP_CHUNK_ANMF: -#ifdef WEBP_EXPERIMENTAL_FEATURES - case WEBP_CHUNK_FRGM: -#endif - 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; - break; + } 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; } - data += data_size; - size -= data_size; ChunkInit(&chunk); } @@ -287,66 +190,29 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, //------------------------------------------------------------------------------ // Get API(s). -// 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; - } -} - -// 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; +WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) { WebPData data; - assert(mux != NULL); + WebPMuxError err; + + if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT; + *flags = 0; // Check if VP8X chunk is present. - 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 { // Single image case. - const WebPMuxImage* const wpi = mux->images_; - WebPMuxError err = ValidateForSingleImage(mux); - if (err != WEBP_MUX_OK) return err; - assert(wpi != NULL); - w = wpi->width_; - h = wpi->height_; - if (wpi->has_alpha_) f |= ALPHA_FLAG; + 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 (w * (uint64_t)h >= MAX_IMAGE_AREA) return WEBP_MUX_BAD_DATA; - 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); -} + if (data.size_ < CHUNK_SIZE_BYTES) return WEBP_MUX_BAD_DATA; -WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) { - if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT; - return MuxGetCanvasInfo(mux, NULL, NULL, flags); + // All OK. Fill up flags. + *flags = GetLE32(data.bytes_); + return WEBP_MUX_OK; } static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width, @@ -364,7 +230,7 @@ static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width, } // Assemble a single image WebP bitstream from 'wpi'. -static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi, +static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi, WebPData* const bitstream) { uint8_t* dst; @@ -372,7 +238,7 @@ static WebPMuxError SynthesizeBitstream(const 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 ANMF/FRGM chunk for a single image. + // Note: No need to output FRM/TILE 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); @@ -382,7 +248,15 @@ static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi, dst = MuxEmitRiffHeader(data, size); if (need_vp8x) { - dst = EmitVP8XChunk(dst, wpi->width_, wpi->height_, ALPHA_FLAG); // 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 = ChunkListEmit(wpi->alpha_, dst); // ALPH. } @@ -391,117 +265,107 @@ static WebPMuxError SynthesizeBitstream(const 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 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; - } - idx = ChunkGetIndexFromFourCC(fourcc); - if (IsWPI(kChunks[idx].id)) { // An image chunk. +WebPMuxError WebPMuxGetImage(const WebPMux* mux, WebPData* bitstream) { + WebPMuxError err; + WebPMuxImage* wpi = NULL; + + if (mux == NULL || bitstream == NULL) { 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; } + + 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); } -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 WebPMuxGetMetadata(const WebPMux* mux, WebPData* metadata) { + if (mux == NULL || metadata == NULL) return WEBP_MUX_INVALID_ARGUMENT; + return MuxGet(mux, IDX_META, 1, metadata); } -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; -#ifndef WEBP_EXPERIMENTAL_FEATURES - if (!is_frame) return WEBP_MUX_INVALID_ARGUMENT; -#endif - 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); +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); } -WebPMuxError WebPMuxGetFrame( - const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame) { +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 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 err; WebPMuxImage* wpi; - // Sanity checks. - if (mux == NULL || frame == NULL) { + 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)) { return WEBP_MUX_INVALID_ARGUMENT; } // Get the nth WebPMuxImage. - err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, &wpi); + err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, id, &wpi); if (err != WEBP_MUX_OK) return err; - // Get frame info. - if (wpi->header_ == NULL) { - return MuxGetImageInternal(wpi, frame); - } else { - return MuxGetFrameFragmentInternal(wpi, frame); - } -} + // Get frame chunk. + assert(wpi->header_ != NULL); // As MuxImageGetNth() already checked header_. + frame_tile_data = &wpi->header_->data_; -WebPMuxError WebPMuxGetAnimationParams(const WebPMux* mux, - WebPMuxAnimParams* params) { - WebPData anim; - WebPMuxError err; + 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); - if (mux == NULL || params == NULL) return WEBP_MUX_INVALID_ARGUMENT; + return SynthesizeBitstream(wpi, bitstream); +} - 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 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); +} - return WEBP_MUX_OK; +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); } // 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 (CHUNK_INDEX)i; + if (id == kChunks[i].id) return i; } return IDX_NIL; } @@ -529,8 +393,12 @@ WebPMuxError WebPMuxNumChunks(const WebPMux* mux, *num_elements = MuxImageCount(mux->images_, id); } else { WebPChunk* const* chunk_list = MuxGetChunkListFromId(mux, id); - const CHUNK_INDEX idx = ChunkGetIndexFromId(id); - *num_elements = CountChunks(*chunk_list, kChunks[idx].tag); + if (chunk_list == NULL) { + *num_elements = 0; + } else { + const CHUNK_INDEX idx = ChunkGetIndexFromId(id); + *num_elements = CountChunks(*chunk_list, kChunks[idx].tag); + } } return WEBP_MUX_OK; @@ -538,3 +406,6 @@ WebPMuxError WebPMuxNumChunks(const WebPMux* mux, //------------------------------------------------------------------------------ +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif |