Add a simple cleanup step in mux assembly:

In particular, this removes any unnecessary FRGM/ANMF/ANIM chunks, and
indirectly leads to removal of unnecessary VP8X chunks as well.
This is especially useful for GIF to WebP conversion - it saves 56 bytes
(ANMF: 16+8 bytes, ANIM: 6+8 bytes, VP8X: 10+8 bytes) for non-animated GIFs.

Change-Id: I3b50a96ca585844c421b0fa4cd8593e52c3f95c5
This commit is contained in:
Urvang Joshi 2012-11-07 13:16:09 -08:00
parent 51bb1e5de7
commit 74356eb558

View File

@ -585,31 +585,55 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
return err; return err;
} }
// Cleans up 'mux' by removing any unnecessary chunks.
static WebPMuxError MuxCleanup(WebPMux* const mux) {
int num_frames;
int num_fragments;
int num_anim_chunks;
// If we have an image with single fragment or frame, convert it to a
// non-animated non-fragmented image (to avoid writing FRGM/ANMF chunk
// unnecessarily).
WebPMuxError err = WebPMuxNumChunks(mux, kChunks[IDX_ANMF].id, &num_frames);
if (err != WEBP_MUX_OK) return err;
err = WebPMuxNumChunks(mux, kChunks[IDX_FRGM].id, &num_fragments);
if (err != WEBP_MUX_OK) return err;
if (num_frames == 1 || num_fragments == 1) {
WebPMuxImage* frame_frag;
err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, &frame_frag);
assert(err == WEBP_MUX_OK); // We know that one frame/fragment does exist.
if (frame_frag->header_ != NULL) {
assert(frame_frag->header_->tag_ == kChunks[IDX_ANMF].tag ||
frame_frag->header_->tag_ == kChunks[IDX_FRGM].tag);
ChunkDelete(frame_frag->header_); // Removes ANMF/FRGM chunk.
frame_frag->header_ = NULL;
}
num_frames = 0;
num_fragments = 0;
}
// Remove ANIM chunk if this is a non-animated image.
err = WebPMuxNumChunks(mux, kChunks[IDX_ANIM].id, &num_anim_chunks);
if (err != WEBP_MUX_OK) return err;
if (num_anim_chunks >= 1 && num_frames == 0) {
err = MuxDeleteAllNamedData(mux, kChunks[IDX_ANIM].tag);
if (err != WEBP_MUX_OK) return err;
}
return WEBP_MUX_OK;
}
WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) { WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) {
size_t size = 0; size_t size = 0;
uint8_t* data = NULL; uint8_t* data = NULL;
uint8_t* dst = NULL; uint8_t* dst = NULL;
int num_frames;
int num_anim_chunks;
WebPMuxError err; WebPMuxError err;
if (mux == NULL || assembled_data == NULL) { if (mux == NULL || assembled_data == NULL) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
// Remove ANIM chunk if unnecessary. // Finalize mux.
err = WebPMuxNumChunks(mux, kChunks[IDX_ANIM].id, &num_anim_chunks); err = MuxCleanup(mux);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) return err;
if (num_anim_chunks >= 1) {
err = WebPMuxNumChunks(mux, kChunks[IDX_ANMF].id, &num_frames);
if (err != WEBP_MUX_OK) return err;
if (num_frames == 0) {
err = MuxDeleteAllNamedData(mux, kChunks[IDX_ANIM].tag);
if (err != WEBP_MUX_OK) return err;
}
}
// Create VP8X chunk.
err = CreateVP8XChunk(mux); err = CreateVP8XChunk(mux);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) return err;
@ -641,7 +665,7 @@ WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) {
size = 0; size = 0;
} }
// Finalize. // Finalize data.
assembled_data->bytes = data; assembled_data->bytes = data;
assembled_data->size = size; assembled_data->size = size;