Support for unknown chunks in mux library

WebPMuxSetChunk/WebPMuxGetChunk/WebPMuxDeleteChunk now correctly handle
unknown chunks.

Change-Id: I2b75106ef08260f2bce03eb1782924b620643746
This commit is contained in:
Urvang Joshi 2013-07-17 16:34:50 -07:00
parent 7d60bbc6d9
commit faa4b07eda
4 changed files with 24 additions and 56 deletions

View File

@ -75,17 +75,18 @@ void WebPMuxDelete(WebPMux* mux) {
// Handy MACRO, makes MuxSet() very symmetric to MuxGet(). // Handy MACRO, makes MuxSet() very symmetric to MuxGet().
#define SWITCH_ID_LIST(INDEX, LIST) \ #define SWITCH_ID_LIST(INDEX, LIST) \
if (idx == (INDEX)) { \ if (idx == (INDEX)) { \
err = ChunkAssignData(&chunk, data, copy_data, kChunks[(INDEX)].tag); \ err = ChunkAssignData(&chunk, data, copy_data, tag); \
if (err == WEBP_MUX_OK) { \ if (err == WEBP_MUX_OK) { \
err = ChunkSetNth(&chunk, (LIST), nth); \ err = ChunkSetNth(&chunk, (LIST), nth); \
} \ } \
return err; \ return err; \
} }
static WebPMuxError MuxSet(WebPMux* const mux, CHUNK_INDEX idx, uint32_t nth, static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag, uint32_t nth,
const WebPData* const data, int copy_data) { const WebPData* const data, int copy_data) {
WebPChunk chunk; WebPChunk chunk;
WebPMuxError err = WEBP_MUX_NOT_FOUND; WebPMuxError err = WEBP_MUX_NOT_FOUND;
const CHUNK_INDEX idx = ChunkGetIndexFromTag(tag);
assert(mux != NULL); assert(mux != NULL);
assert(!IsWPI(kChunks[idx].id)); assert(!IsWPI(kChunks[idx].id));
@ -95,29 +96,11 @@ static WebPMuxError MuxSet(WebPMux* const mux, CHUNK_INDEX idx, uint32_t nth,
SWITCH_ID_LIST(IDX_ANIM, &mux->anim_); SWITCH_ID_LIST(IDX_ANIM, &mux->anim_);
SWITCH_ID_LIST(IDX_EXIF, &mux->exif_); SWITCH_ID_LIST(IDX_EXIF, &mux->exif_);
SWITCH_ID_LIST(IDX_XMP, &mux->xmp_); SWITCH_ID_LIST(IDX_XMP, &mux->xmp_);
if (idx == IDX_UNKNOWN && data->size > TAG_SIZE) { SWITCH_ID_LIST(IDX_UNKNOWN, &mux->unknown_);
// For raw-data unknown chunk, the first four bytes should be the tag to be
// used for the chunk.
const WebPData tmp = { data->bytes + TAG_SIZE, data->size - TAG_SIZE };
err = ChunkAssignData(&chunk, &tmp, copy_data, GetLE32(data->bytes + 0));
if (err == WEBP_MUX_OK)
err = ChunkSetNth(&chunk, &mux->unknown_, nth);
}
return err; return err;
} }
#undef SWITCH_ID_LIST #undef SWITCH_ID_LIST
static WebPMuxError MuxAddChunk(WebPMux* const mux, uint32_t nth, uint32_t tag,
const uint8_t* data, size_t size,
int copy_data) {
const CHUNK_INDEX idx = ChunkGetIndexFromTag(tag);
const WebPData chunk_data = { data, size };
assert(mux != NULL);
assert(size <= MAX_CHUNK_PAYLOAD);
assert(idx != IDX_NIL);
return MuxSet(mux, idx, nth, &chunk_data, copy_data);
}
// Create data for frame/fragment given image data, offsets and duration. // Create data for frame/fragment given image data, offsets and duration.
static WebPMuxError CreateFrameFragmentData( static WebPMuxError CreateFrameFragmentData(
const WebPData* const image, int x_offset, int y_offset, int duration, const WebPData* const image, int x_offset, int y_offset, int duration,
@ -200,15 +183,9 @@ static WebPMuxError DeleteChunks(WebPChunk** chunk_list, uint32_t tag) {
static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux, uint32_t tag) { static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux, uint32_t tag) {
const WebPChunkId id = ChunkGetIdFromTag(tag); const WebPChunkId id = ChunkGetIdFromTag(tag);
WebPChunk** chunk_list;
assert(mux != NULL); assert(mux != NULL);
if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT; if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT;
return DeleteChunks(MuxGetChunkListFromId(mux, id), tag);
chunk_list = MuxGetChunkListFromId(mux, id);
if (chunk_list == NULL) return WEBP_MUX_INVALID_ARGUMENT;
return DeleteChunks(chunk_list, tag);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -231,7 +208,7 @@ WebPMuxError WebPMuxSetChunk(WebPMux* mux, const char fourcc[4],
if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
// Add the given chunk. // Add the given chunk.
return MuxSet(mux, idx, 1, chunk_data, copy_data); return MuxSet(mux, tag, 1, chunk_data, copy_data);
} }
// Creates a chunk from given 'data' and sets it as 1st chunk in 'chunk_list'. // Creates a chunk from given 'data' and sets it as 1st chunk in 'chunk_list'.
@ -381,6 +358,7 @@ WebPMuxError WebPMuxSetAnimationParams(WebPMux* mux,
const WebPMuxAnimParams* params) { const WebPMuxAnimParams* params) {
WebPMuxError err; WebPMuxError err;
uint8_t data[ANIM_CHUNK_SIZE]; uint8_t data[ANIM_CHUNK_SIZE];
const WebPData anim = { data, ANIM_CHUNK_SIZE };
if (mux == NULL || params == NULL) return WEBP_MUX_INVALID_ARGUMENT; if (mux == NULL || params == NULL) return WEBP_MUX_INVALID_ARGUMENT;
if (params->loop_count < 0 || params->loop_count >= MAX_LOOP_COUNT) { if (params->loop_count < 0 || params->loop_count >= MAX_LOOP_COUNT) {
@ -394,7 +372,7 @@ WebPMuxError WebPMuxSetAnimationParams(WebPMux* mux,
// Set the animation parameters. // Set the animation parameters.
PutLE32(data, params->bgcolor); PutLE32(data, params->bgcolor);
PutLE16(data + 4, params->loop_count); PutLE16(data + 4, params->loop_count);
return MuxAddChunk(mux, 1, kChunks[IDX_ANIM].tag, data, sizeof(data), 1); return MuxSet(mux, kChunks[IDX_ANIM].tag, 1, &anim, 1);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -534,7 +512,7 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
int width = 0; int width = 0;
int height = 0; int height = 0;
uint8_t data[VP8X_CHUNK_SIZE]; uint8_t data[VP8X_CHUNK_SIZE];
const size_t data_size = VP8X_CHUNK_SIZE; const WebPData vp8x = { data, VP8X_CHUNK_SIZE };
const WebPMuxImage* images = NULL; const WebPMuxImage* images = NULL;
assert(mux != NULL); assert(mux != NULL);
@ -599,8 +577,7 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
PutLE24(data + 4, width - 1); // canvas width. PutLE24(data + 4, width - 1); // canvas width.
PutLE24(data + 7, height - 1); // canvas height. PutLE24(data + 7, height - 1); // canvas height.
err = MuxAddChunk(mux, 1, kChunks[IDX_VP8X].tag, data, data_size, 1); return MuxSet(mux, kChunks[IDX_VP8X].tag, 1, &vp8x, 1);
return err;
} }
// Cleans up 'mux' by removing any unnecessary chunks. // Cleans up 'mux' by removing any unnecessary chunks.

View File

@ -101,10 +101,10 @@ extern const ChunkInfo kChunks[IDX_LAST_CHUNK];
// Initialize. // Initialize.
void ChunkInit(WebPChunk* const chunk); void ChunkInit(WebPChunk* const chunk);
// Get chunk index from chunk tag. Returns IDX_NIL if not found. // Get chunk index from chunk tag. Returns IDX_UNKNOWN if not found.
CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag); CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag);
// Get chunk id from chunk tag. Returns WEBP_CHUNK_NIL if not found. // Get chunk id from chunk tag. Returns WEBP_CHUNK_UNKNOWN if not found.
WebPChunkId ChunkGetIdFromTag(uint32_t tag); WebPChunkId ChunkGetIdFromTag(uint32_t tag);
// Convert a fourcc string to a tag. // Convert a fourcc string to a tag.
@ -207,8 +207,6 @@ int MuxHasLosslessImages(const WebPMuxImage* images);
uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size); uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size);
// Returns the list where chunk with given ID is to be inserted in mux. // Returns the list where chunk with given ID is to be inserted in mux.
// Return value is NULL if this chunk should be inserted in mux->images_ list
// or if 'id' is not known.
WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id); WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id);
// Validates the given mux object. // Validates the given mux object.

View File

@ -33,7 +33,7 @@ const ChunkInfo kChunks[] = {
{ MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE }, { MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
{ MKFOURCC('E', 'X', 'I', 'F'), WEBP_CHUNK_EXIF, UNDEFINED_CHUNK_SIZE }, { MKFOURCC('E', 'X', 'I', 'F'), WEBP_CHUNK_EXIF, UNDEFINED_CHUNK_SIZE },
{ MKFOURCC('X', 'M', 'P', ' '), WEBP_CHUNK_XMP, UNDEFINED_CHUNK_SIZE }, { MKFOURCC('X', 'M', 'P', ' '), WEBP_CHUNK_XMP, UNDEFINED_CHUNK_SIZE },
{ MKFOURCC('U', 'N', 'K', 'N'), WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE }, { NIL_TAG, WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE },
{ NIL_TAG, WEBP_CHUNK_NIL, UNDEFINED_CHUNK_SIZE } { NIL_TAG, WEBP_CHUNK_NIL, UNDEFINED_CHUNK_SIZE }
}; };
@ -72,7 +72,7 @@ CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag) {
for (i = 0; kChunks[i].tag != NIL_TAG; ++i) { for (i = 0; kChunks[i].tag != NIL_TAG; ++i) {
if (tag == kChunks[i].tag) return i; if (tag == kChunks[i].tag) return i;
} }
return IDX_NIL; return IDX_UNKNOWN;
} }
WebPChunkId ChunkGetIdFromTag(uint32_t tag) { WebPChunkId ChunkGetIdFromTag(uint32_t tag) {
@ -80,7 +80,7 @@ WebPChunkId ChunkGetIdFromTag(uint32_t tag) {
for (i = 0; kChunks[i].tag != NIL_TAG; ++i) { for (i = 0; kChunks[i].tag != NIL_TAG; ++i) {
if (tag == kChunks[i].tag) return kChunks[i].id; if (tag == kChunks[i].tag) return kChunks[i].id;
} }
return WEBP_CHUNK_NIL; return WEBP_CHUNK_UNKNOWN;
} }
uint32_t ChunkGetTagFromFourCC(const char fourcc[4]) { uint32_t ChunkGetTagFromFourCC(const char fourcc[4]) {
@ -89,8 +89,7 @@ uint32_t ChunkGetTagFromFourCC(const char fourcc[4]) {
CHUNK_INDEX ChunkGetIndexFromFourCC(const char fourcc[4]) { CHUNK_INDEX ChunkGetIndexFromFourCC(const char fourcc[4]) {
const uint32_t tag = ChunkGetTagFromFourCC(fourcc); const uint32_t tag = ChunkGetTagFromFourCC(fourcc);
const CHUNK_INDEX idx = ChunkGetIndexFromTag(tag); return ChunkGetIndexFromTag(tag);
return (idx == IDX_NIL) ? IDX_UNKNOWN : idx;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -421,8 +420,7 @@ WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) {
case WEBP_CHUNK_ANIM: return (WebPChunk**)&mux->anim_; case WEBP_CHUNK_ANIM: return (WebPChunk**)&mux->anim_;
case WEBP_CHUNK_EXIF: return (WebPChunk**)&mux->exif_; case WEBP_CHUNK_EXIF: return (WebPChunk**)&mux->exif_;
case WEBP_CHUNK_XMP: return (WebPChunk**)&mux->xmp_; case WEBP_CHUNK_XMP: return (WebPChunk**)&mux->xmp_;
case WEBP_CHUNK_UNKNOWN: return (WebPChunk**)&mux->unknown_; default: return (WebPChunk**)&mux->unknown_;
default: return NULL;
} }
} }

View File

@ -237,7 +237,6 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before
// getting all chunks of an image. // getting all chunks of an image.
chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk. 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; if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err;
break; break;
} }
@ -502,13 +501,9 @@ WebPMuxError WebPMuxNumChunks(const WebPMux* mux,
*num_elements = MuxImageCount(mux->images_, id); *num_elements = MuxImageCount(mux->images_, id);
} else { } else {
WebPChunk* const* chunk_list = MuxGetChunkListFromId(mux, id); WebPChunk* const* chunk_list = MuxGetChunkListFromId(mux, id);
if (chunk_list == NULL) {
*num_elements = 0;
} else {
const CHUNK_INDEX idx = ChunkGetIndexFromId(id); const CHUNK_INDEX idx = ChunkGetIndexFromId(id);
*num_elements = CountChunks(*chunk_list, kChunks[idx].tag); *num_elements = CountChunks(*chunk_list, kChunks[idx].tag);
} }
}
return WEBP_MUX_OK; return WEBP_MUX_OK;
} }