From 81b8a741ed5a3d3d913f640f3bfda44ee6caf76d Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Wed, 31 Oct 2012 17:19:31 -0700 Subject: [PATCH 1/2] Design change in ANMF and FRGM chunks: - Make ANMF and FRGM chunks hierarchical so that they encompass all chunks of that frame. - Use this in demuxer: stop parsing a frame if all image data for it isn't available yet. Thus, we have a frame-level incremental support; that is, all frames that are fully available can be parsed. - Note: We still keep incremental support for single images - so that they can be decoded with incremental decoding. Change-Id: Id1585b16b06caee1d84009c42a25d2de29fa6135 --- src/mux/demux.c | 44 +++++++------- src/mux/muxinternal.c | 21 ++++++- src/mux/muxread.c | 129 +++++++++++++++++++++++++++++++----------- 3 files changed, 141 insertions(+), 53 deletions(-) diff --git a/src/mux/demux.c b/src/mux/demux.c index 4f7a5d37..fb25d002 100644 --- a/src/mux/demux.c +++ b/src/mux/demux.c @@ -194,11 +194,11 @@ static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) { } // Store image bearing chunks to 'frame'. -static ParseStatus StoreFrame(int frame_num, MemBuffer* const mem, - Frame* const frame) { +static ParseStatus StoreFrame(int frame_num, uint32_t min_size, + MemBuffer* const mem, Frame* const frame) { int alpha_chunks = 0; int image_chunks = 0; - int done = (MemDataSize(mem) < CHUNK_HEADER_SIZE); + int done = (MemDataSize(mem) < min_size); ParseStatus status = PARSE_OK; if (done) return PARSE_NEED_MORE_DATA; @@ -275,10 +275,10 @@ static ParseStatus StoreFrame(int frame_num, MemBuffer* const mem, // Returns PARSE_OK on success with *frame pointing to the new Frame. // Returns PARSE_NEED_MORE_DATA with insufficient data, PARSE_ERROR otherwise. static ParseStatus NewFrame(const MemBuffer* const mem, - uint32_t min_size, uint32_t expected_size, - uint32_t actual_size, Frame** frame) { + uint32_t min_size, uint32_t actual_size, + Frame** frame) { if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; - if (actual_size < expected_size) return PARSE_ERROR; + if (actual_size < min_size) return PARSE_ERROR; if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; *frame = (Frame*)calloc(1, sizeof(**frame)); @@ -290,12 +290,14 @@ static ParseStatus NewFrame(const MemBuffer* const mem, static ParseStatus ParseFrame( WebPDemuxer* const dmux, uint32_t frame_chunk_size) { const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); - const uint32_t min_size = frame_chunk_size + CHUNK_HEADER_SIZE; + const uint32_t padding = (ANMF_CHUNK_SIZE & 1); + const uint32_t anmf_payload_size = + frame_chunk_size - (ANMF_CHUNK_SIZE + padding); int added_frame = 0; MemBuffer* const mem = &dmux->mem_; Frame* frame; ParseStatus status = - NewFrame(mem, min_size, ANMF_CHUNK_SIZE, frame_chunk_size, &frame); + NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame); if (status != PARSE_OK) return status; frame->x_offset_ = 2 * GetLE24s(mem); @@ -303,14 +305,14 @@ static ParseStatus ParseFrame( frame->width_ = 1 + GetLE24s(mem); frame->height_ = 1 + GetLE24s(mem); frame->duration_ = 1 + GetLE24s(mem); - Skip(mem, frame_chunk_size - ANMF_CHUNK_SIZE); // skip any trailing data. + Skip(mem, padding); if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) { return PARSE_ERROR; } - // Store a (potentially partial) frame only if the animation flag is set - // and there is some data in 'frame'. - status = StoreFrame(dmux->num_frames_ + 1, mem, frame); + // Store a frame only if the animation flag is set and all data for this frame + // is available. + status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame); if (status != PARSE_ERROR && has_frames && frame->frame_num_ > 0) { added_frame = AddFrame(dmux, frame); if (added_frame) { @@ -329,22 +331,24 @@ static ParseStatus ParseFrame( static ParseStatus ParseTile(WebPDemuxer* const dmux, uint32_t tile_chunk_size) { const int has_tiles = !!(dmux->feature_flags_ & TILE_FLAG); - const uint32_t min_size = tile_chunk_size + CHUNK_HEADER_SIZE; + const uint32_t padding = (FRGM_CHUNK_SIZE & 1); + const uint32_t frgm_payload_size = + tile_chunk_size - (FRGM_CHUNK_SIZE + padding); int added_tile = 0; MemBuffer* const mem = &dmux->mem_; Frame* frame; ParseStatus status = - NewFrame(mem, min_size, FRGM_CHUNK_SIZE, tile_chunk_size, &frame); + NewFrame(mem, FRGM_CHUNK_SIZE, tile_chunk_size, &frame); if (status != PARSE_OK) return status; frame->is_tile_ = 1; frame->x_offset_ = 2 * GetLE24s(mem); frame->y_offset_ = 2 * GetLE24s(mem); - Skip(mem, tile_chunk_size - FRGM_CHUNK_SIZE); // skip any trailing data. + Skip(mem, padding); - // Store a (potentially partial) tile only if the tile flag is set - // and the tile contains some data. - status = StoreFrame(dmux->num_frames_, mem, frame); + // Store a tile only if the tile flag is set and all data for this tile + // is available. + status = StoreFrame(dmux->num_frames_, frgm_payload_size, mem, frame); if (status != PARSE_ERROR && has_tiles && frame->frame_num_ > 0) { // Note num_frames_ is incremented only when all tiles have been consumed. added_tile = AddFrame(dmux, frame); @@ -411,7 +415,9 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { frame = (Frame*)calloc(1, sizeof(*frame)); if (frame == NULL) return PARSE_ERROR; - status = StoreFrame(1, &dmux->mem_, frame); + // For the single image case, we allow parsing of a partial frame. But we need + // at least CHUNK_HEADER_SIZE for parsing. + status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame); if (status != PARSE_ERROR) { const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG); // Clear any alpha when the alpha flag is missing. diff --git a/src/mux/muxinternal.c b/src/mux/muxinternal.c index bddb1418..51fce0fd 100644 --- a/src/mux/muxinternal.c +++ b/src/mux/muxinternal.c @@ -399,13 +399,32 @@ size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list) { return size; } +// Special case as ANMF/FRGM chunk encapsulates other image chunks. +static uint8_t* ChunkEmitSpecial(const WebPChunk* const header, + size_t total_size, uint8_t* dst) { + const size_t header_size = header->data_.size; + const size_t offset_to_next = total_size - CHUNK_HEADER_SIZE; + assert(header->tag_ == kChunks[IDX_ANMF].tag || + header->tag_ == kChunks[IDX_FRGM].tag); + PutLE32(dst + 0, header->tag_); + PutLE32(dst + TAG_SIZE, (uint32_t)offset_to_next); + assert(header_size == (uint32_t)header_size); + memcpy(dst + CHUNK_HEADER_SIZE, header->data_.bytes, header_size); + if (header_size & 1) { + dst[CHUNK_HEADER_SIZE + header_size] = 0; // Add padding. + } + return dst + ChunkDiskSize(header); +} + uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) { // Ordering of chunks to be emitted is strictly as follows: // 1. ANMF/FRGM chunk (if present). // 2. ALPH chunk (if present). // 3. VP8/VP8L chunk. assert(wpi); - if (wpi->header_ != NULL) dst = ChunkEmit(wpi->header_, dst); + if (wpi->header_ != NULL) { + dst = ChunkEmitSpecial(wpi->header_, MuxImageDiskSize(wpi), dst); + } if (wpi->alpha_ != NULL) dst = ChunkEmit(wpi->alpha_, dst); if (wpi->img_ != NULL) dst = ChunkEmit(wpi->img_, dst); return dst; diff --git a/src/mux/muxread.c b/src/mux/muxread.c index e16f087d..24633bf1 100644 --- a/src/mux/muxread.c +++ b/src/mux/muxread.c @@ -51,10 +51,9 @@ 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; @@ -74,6 +73,66 @@ static WebPMuxError ChunkVerifyAndAssignData(WebPChunk* chunk, return ChunkAssignData(chunk, &chunk_data, copy_data, GetLE32(data + 0)); } +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 }; + 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; + wpi->is_partial_ = 0; // wpi is completely filled. + 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. @@ -136,42 +195,46 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, // 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; 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: + case WEBP_CHUNK_FRGM: + 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 (chunk_list == NULL) chunk_list = &mux->unknown_; + if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err; + break; } + data += data_size; + size -= data_size; ChunkInit(&chunk); } From a00a3daf5bf94893b973f274d7eb32d0130872c3 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Wed, 31 Oct 2012 17:49:15 -0700 Subject: [PATCH 2/2] Use 'frgm' instead of 'tile' in webpmux parameters - Also, use the term 'fragments' instead of 'tiling' in code - This makes code consistent with the spec. Change-Id: Ibeccffc35db23bbedb88cc5e18e29e51621931f8 --- README.mux | 22 +++---- examples/vwebp.c | 6 +- examples/webpmux.c | 118 ++++++++++++++++++------------------ man/webpmux.1 | 16 ++--- src/dec/webp.c | 4 +- src/mux/demux.c | 108 +++++++++++++++++---------------- src/mux/muxedit.c | 76 +++++++++++------------ src/mux/muxinternal.c | 16 ++--- src/mux/muxread.c | 20 +++--- src/webp/format_constants.h | 2 +- src/webp/mux.h | 43 ++++++------- 11 files changed, 219 insertions(+), 212 deletions(-) diff --git a/README.mux b/README.mux index 184fb429..4156f1a8 100644 --- a/README.mux +++ b/README.mux @@ -8,9 +8,9 @@ Description: ============ WebP Mux: library to create a WebP container object for features like -color profile, metadata, animation and tiling. A reference command line -tool 'webpmux' and WebP container specification 'doc/webp-container-spec.txt' -are also provided in this package. +color profile, metadata, animation and fragmented images. A reference command +line tool 'webpmux' and WebP container specification +'doc/webp-container-spec.txt' are also provided in this package. WebP Mux tool: ============== @@ -25,7 +25,7 @@ A list of options is available using the -help command line flag: Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT webpmux -set SET_OPTIONS INPUT -o OUTPUT webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT - webpmux -tile TILE_OPTIONS [-tile...] -o OUTPUT + webpmux -frgm FRAGMENT_OPTIONS [-frgm...] -o OUTPUT webpmux -frame FRAME_OPTIONS [-frame...] -loop LOOP_COUNT -o OUTPUT webpmux -info INPUT webpmux [-h|-help] @@ -35,7 +35,7 @@ GET_OPTIONS: icc Get ICC profile. exif Get EXIF metadata. xmp Get XMP metadata. - tile n Get nth tile. + frgm n Get nth fragment. frame n Get nth frame. SET_OPTIONS: @@ -53,11 +53,11 @@ STRIP_OPTIONS: exif Strip EXIF metadata. xmp Strip XMP metadata. -TILE_OPTIONS(i): - Create tiled image. +FRAGMENT_OPTIONS(i): + Create fragmented image. file_i +xi+yi - where: 'file_i' is the i'th tile (WebP format), - 'xi','yi' specify the image offset for this tile. + where: 'file_i' is the i'th fragment (WebP format), + 'xi','yi' specify the image offset for this fragment. FRAME_OPTIONS(i): Create animation. @@ -75,8 +75,8 @@ WebP Mux API: ============== The WebP Mux API contains methods for adding data to and reading data from WebPMux (a WebP container object). This API currently supports XMP/EXIF -metadata, ICC profile, animation and tiling. Other features will be added -in subsequent releases. +metadata, ICC profile, animation and fragmented images. Other features +will be added in subsequent releases. Example#1 (pseudo code): Creating a WebPMux object with image data, color profile and XMP metadata. diff --git a/examples/vwebp.c b/examples/vwebp.c index f2f211d9..ec5f5834 100644 --- a/examples/vwebp.c +++ b/examples/vwebp.c @@ -183,7 +183,7 @@ static int Decode(int* const duration) { "Frame offsets not yet supported! Forcing offset to 0,0\n"); } output_buffer->colorspace = MODE_RGBA; - ok = (WebPDecode(iter->tile.bytes, iter->tile.size, + ok = (WebPDecode(iter->fragment.bytes, iter->fragment.size, config) == VP8_STATUS_OK); if (!ok) { fprintf(stderr, "Decoding of frame #%d failed!\n", iter->frame_num); @@ -298,8 +298,8 @@ int main(int argc, char *argv[]) { goto Error; } - if (WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & TILE_FLAG) { - fprintf(stderr, "Tiling is not supported for now!\n"); + if (WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & FRAGMENTS_FLAG) { + fprintf(stderr, "Image fragments are not supported for now!\n"); goto Error; } diff --git a/examples/webpmux.c b/examples/webpmux.c index 3ad753fe..7fb90173 100644 --- a/examples/webpmux.c +++ b/examples/webpmux.c @@ -17,11 +17,11 @@ /* Usage examples: Create container WebP file: - webpmux -tile tile_1.webp +0+0 \ - -tile tile_2.webp +960+0 \ - -tile tile_3.webp +0+576 \ - -tile tile_4.webp +960+576 \ - -o out_tile_container.webp + webpmux -frgm fragment_1.webp +0+0 \ + -frgm fragment_2.webp +960+0 \ + -frgm fragment_3.webp +0+576 \ + -frgm fragment_4.webp +960+576 \ + -o out_fragment_container.webp webpmux -frame anim_1.webp +0+0+0 \ -frame anim_2.webp +25+25+100 \ @@ -35,7 +35,7 @@ webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp Extract relevant data from WebP container file: - webpmux -get tile n in.webp -o out_tile.webp + webpmux -get frgm n in.webp -o out_fragment.webp webpmux -get frame n in.webp -o out_frame.webp webpmux -get icc in.webp -o image_profile.icc webpmux -get exif in.webp -o image_metadata.exif @@ -87,8 +87,8 @@ typedef enum { FEATURE_EXIF, FEATURE_XMP, FEATURE_ICCP, - FEATURE_FRM, - FEATURE_TILE, + FEATURE_ANMF, + FEATURE_FRGM, LAST_FEATURE } FeatureType; @@ -98,7 +98,7 @@ static const char* const kFourccList[LAST_FEATURE] = { static const char* const kDescriptions[LAST_FEATURE] = { NULL, "EXIF metadata", "XMP metadata", "ICC profile", - "Animation frame", "Tile fragment" + "Animation frame", "Image fragment" }; typedef struct { @@ -197,17 +197,17 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) { // Print the features present. printf("Features present:"); if (flag & ANIMATION_FLAG) printf(" animation"); - if (flag & TILE_FLAG) printf(" tiling"); + if (flag & FRAGMENTS_FLAG) printf(" image fragments"); if (flag & ICCP_FLAG) printf(" icc profile"); if (flag & EXIF_FLAG) printf(" EXIF metadata"); if (flag & XMP_FLAG) printf(" XMP metadata"); if (flag & ALPHA_FLAG) printf(" transparency"); printf("\n"); - if ((flag & ANIMATION_FLAG) || (flag & TILE_FLAG)) { + if ((flag & ANIMATION_FLAG) || (flag & FRAGMENTS_FLAG)) { const int is_anim = !!(flag & ANIMATION_FLAG); const WebPChunkId id = is_anim ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM; - const char* const type_str = is_anim ? "frame" : "tile"; + const char* const type_str = is_anim ? "frame" : "fragment"; int nFrames; if (is_anim) { @@ -259,7 +259,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) { printf("Size of the XMP metadata: %zu\n", xmp.size); } - if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | TILE_FLAG))) { + if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | FRAGMENTS_FLAG))) { WebPMuxFrameInfo image; err = WebPMuxGetFrame(mux, 1, &image); RETURN_IF_ERROR("Failed to retrieve the image\n"); @@ -273,7 +273,7 @@ static void PrintHelp(void) { printf("Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT\n"); printf(" webpmux -set SET_OPTIONS INPUT -o OUTPUT\n"); printf(" webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT\n"); - printf(" webpmux -tile TILE_OPTIONS [-tile...] -o OUTPUT\n"); + printf(" webpmux -frgm FRAGMENT_OPTIONS [-frgm...] -o OUTPUT\n"); printf(" webpmux -frame FRAME_OPTIONS [-frame...]"); printf(" -loop LOOP_COUNT -o OUTPUT\n"); printf(" webpmux -info INPUT\n"); @@ -285,7 +285,7 @@ static void PrintHelp(void) { printf(" icc Get ICC profile.\n"); printf(" exif Get EXIF metadata.\n"); printf(" xmp Get XMP metadata.\n"); - printf(" tile n Get nth tile.\n"); + printf(" frgm n Get nth fragment.\n"); printf(" frame n Get nth frame.\n"); printf("\n"); @@ -306,11 +306,12 @@ static void PrintHelp(void) { printf(" xmp Strip XMP metadata.\n"); printf("\n"); - printf("TILE_OPTIONS(i):\n"); - printf(" Create tiled image.\n"); + printf("FRAGMENT_OPTIONS(i):\n"); + printf(" Create fragmented image.\n"); printf(" file_i +xi+yi\n"); - printf(" where: 'file_i' is the i'th tile (WebP format),\n"); - printf(" 'xi','yi' specify the image offset for this tile.\n"); + printf(" where: 'file_i' is the i'th fragment (WebP format),\n"); + printf(" 'xi','yi' specify the image offset for this fragment." + "\n"); printf("\n"); printf("FRAME_OPTIONS(i):\n"); @@ -382,7 +383,7 @@ static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) { &info->x_offset, &info->y_offset, &info->duration) == 3); } -static int ParseTileArgs(const char* args, WebPMuxFrameInfo* const info) { +static int ParseFragmentArgs(const char* args, WebPMuxFrameInfo* const info) { return (sscanf(args, "+%d+%d", &info->x_offset, &info->y_offset) == 2); } @@ -406,7 +407,7 @@ static void DeleteConfig(WebPMuxConfig* config) { static int ValidateCommandLine(int argc, const char* argv[], int* num_feature_args) { int num_frame_args; - int num_tile_args; + int num_frgm_args; int num_loop_args; int ok = 1; @@ -432,7 +433,7 @@ static int ValidateCommandLine(int argc, const char* argv[], // Compound checks. num_frame_args = CountOccurrences(argv, argc, "-frame"); - num_tile_args = CountOccurrences(argv, argc, "-tile"); + num_frgm_args = CountOccurrences(argv, argc, "-frgm"); num_loop_args = CountOccurrences(argv, argc, "-loop"); if (num_loop_args > 1) { @@ -443,21 +444,21 @@ static int ValidateCommandLine(int argc, const char* argv[], ERROR_GOTO1("ERROR: Both frames and loop count have to be specified.\n", ErrValidate); } - if (num_frame_args > 0 && num_tile_args > 0) { - ERROR_GOTO1("ERROR: Only one of frames & tiles can be specified at a time." - "\n", ErrValidate); + if (num_frame_args > 0 && num_frgm_args > 0) { + ERROR_GOTO1("ERROR: Only one of frames & fragments can be specified at a " + "time.\n", ErrValidate); } assert(ok == 1); - if (num_frame_args == 0 && num_tile_args == 0) { + if (num_frame_args == 0 && num_frgm_args == 0) { // Single argument ('set' action for ICCP/EXIF/XMP, OR a 'get' action). *num_feature_args = 1; } else { - // Multiple arguments ('set' action for animation or tiling). + // Multiple arguments ('set' action for animation or fragmented image). if (num_frame_args > 0) { *num_feature_args = num_frame_args + num_loop_args; } else { - *num_feature_args = num_tile_args; + *num_feature_args = num_frgm_args; } } @@ -522,8 +523,8 @@ static int ParseCommandLine(int argc, const char* argv[], } else { ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); } - if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_FRM) { - feature->type_ = FEATURE_FRM; + if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) { + feature->type_ = FEATURE_ANMF; } else { ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); } @@ -539,8 +540,8 @@ static int ParseCommandLine(int argc, const char* argv[], } else { ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); } - if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_FRM) { - feature->type_ = FEATURE_FRM; + if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) { + feature->type_ = FEATURE_ANMF; } else { ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); } @@ -548,15 +549,15 @@ static int ParseCommandLine(int argc, const char* argv[], arg->params_ = argv[i + 1]; ++feature_arg_index; i += 2; - } else if (!strcmp(argv[i], "-tile")) { + } else if (!strcmp(argv[i], "-frgm")) { CHECK_NUM_ARGS_LESS(3, ErrParse); if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) { config->action_type_ = ACTION_SET; } else { ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); } - if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_TILE) { - feature->type_ = FEATURE_TILE; + if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_FRGM) { + feature->type_ = FEATURE_FRGM; } else { ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); } @@ -607,11 +608,11 @@ static int ParseCommandLine(int argc, const char* argv[], ++i; } } else if ((!strcmp(argv[i], "frame") || - !strcmp(argv[i], "tile")) && + !strcmp(argv[i], "frgm")) && (config->action_type_ == ACTION_GET)) { CHECK_NUM_ARGS_LESS(2, ErrParse); - feature->type_ = (!strcmp(argv[i], "frame")) ? FEATURE_FRM : - FEATURE_TILE; + feature->type_ = (!strcmp(argv[i], "frame")) ? FEATURE_ANMF : + FEATURE_FRGM; arg->params_ = argv[i + 1]; ++feature_arg_index; i += 2; @@ -649,8 +650,8 @@ static int ValidateConfig(WebPMuxConfig* config) { if (config->input_ == NULL) { if (config->action_type_ != ACTION_SET) { ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2); - } else if (feature->type_ != FEATURE_FRM && - feature->type_ != FEATURE_TILE) { + } else if (feature->type_ != FEATURE_ANMF && + feature->type_ != FEATURE_FRGM) { ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2); } } @@ -708,8 +709,8 @@ static int InitializeConfig(int argc, const char* argv[], //------------------------------------------------------------------------------ // Processing. -static int GetFrameTile(const WebPMux* mux, - const WebPMuxConfig* config, int isFrame) { +static int GetFrameFragment(const WebPMux* mux, + const WebPMuxConfig* config, int isFrame) { WebPMuxError err = WEBP_MUX_OK; WebPMux* mux_single = NULL; long num = 0; @@ -720,7 +721,7 @@ static int GetFrameTile(const WebPMux* mux, num = strtol(config->feature_.args_[0].params_, NULL, 10); if (num < 0) { - ERROR_GOTO1("ERROR: Frame/Tile index must be non-negative.\n", ErrGet); + ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet); } err = WebPMuxGetFrame(mux, num, &info); @@ -764,10 +765,10 @@ static int Process(const WebPMuxConfig* config) { ok = CreateMux(config->input_, &mux); if (!ok) goto Err2; switch (feature->type_) { - case FEATURE_FRM: - case FEATURE_TILE: - ok = GetFrameTile(mux, config, - (feature->type_ == FEATURE_FRM) ? 1 : 0); + case FEATURE_ANMF: + case FEATURE_FRGM: + ok = GetFrameFragment(mux, config, + (feature->type_ == FEATURE_ANMF) ? 1 : 0); break; case FEATURE_ICCP: @@ -789,7 +790,7 @@ static int Process(const WebPMuxConfig* config) { case ACTION_SET: switch (feature->type_) { - case FEATURE_FRM: + case FEATURE_ANMF: mux = WebPMuxNew(); if (mux == NULL) { ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n", @@ -829,27 +830,28 @@ static int Process(const WebPMuxConfig* config) { } break; - case FEATURE_TILE: + case FEATURE_FRGM: mux = WebPMuxNew(); if (mux == NULL) { ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n", ErrorString(WEBP_MUX_MEMORY_ERROR), Err2); } for (index = 0; index < feature->arg_count_; ++index) { - WebPMuxFrameInfo tile; + WebPMuxFrameInfo frgm; + frgm.id = WEBP_CHUNK_FRGM; ok = ReadFileToWebPData(feature->args_[index].filename_, - &tile.bitstream); + &frgm.bitstream); if (!ok) goto Err2; - ok = ParseTileArgs(feature->args_[index].params_, &tile); + ok = ParseFragmentArgs(feature->args_[index].params_, &frgm); if (!ok) { - WebPDataClear(&tile.bitstream); - ERROR_GOTO1("ERROR: Could not parse tile properties.\n", Err2); + WebPDataClear(&frgm.bitstream); + ERROR_GOTO1("ERROR: Could not parse fragment properties.\n", + Err2); } - tile.id = WEBP_CHUNK_FRGM; - err = WebPMuxPushFrame(mux, &tile, 1); - WebPDataClear(&tile.bitstream); + err = WebPMuxPushFrame(mux, &frgm, 1); + WebPDataClear(&frgm.bitstream); if (err != WEBP_MUX_OK) { - ERROR_GOTO3("ERROR (%s): Could not add a tile at index %d.\n", + ERROR_GOTO3("ERROR (%s): Could not add a fragment at index %d.\n", ErrorString(err), index, Err2); } } diff --git a/man/webpmux.1 b/man/webpmux.1 index c60e89ad..5af6c8ea 100644 --- a/man/webpmux.1 +++ b/man/webpmux.1 @@ -21,9 +21,9 @@ webpmux \- command line tool to create WebP Mux/container file. .B \-o .I OUTPUT .br -.B webpmux \-tile -.I TILE_OPTIONS -.B [\-tile...] \-o +.B webpmux \-frgm +.I FRAGMENT_OPTIONS +.B [\-frgm...] \-o .I OUTPUT .br .B webpmux \-frame @@ -56,8 +56,8 @@ Get EXIF metadata. .B xmp Get XMP metadata. .TP -.B tile n -Get nth tile. +.B frgm n +Get nth fragment. .TP .B frame n Get nth frame. @@ -90,11 +90,11 @@ Strip EXIF metadata. .B xmp Strip XMP metadata. -.SS TILE_OPTIONS (\-tile) +.SS FRAGMENT_OPTIONS (\-frgm) .TP .B file_i +xi+yi -Where: 'file_i' is the i'th tile (WebP format) and 'xi','yi' specify the image -offset for this tile. +Where: 'file_i' is the i'th fragment (WebP format) and 'xi','yi' specify the +image offset for this fragment. .SS FRAME_OPTIONS (\-frame) .TP diff --git a/src/dec/webp.c b/src/dec/webp.c index a29f92d9..cb95ee73 100644 --- a/src/dec/webp.c +++ b/src/dec/webp.c @@ -40,8 +40,8 @@ extern "C" { // 20..23 VP8X flags bit-map corresponding to the chunk-types present. // 24..26 Width of the Canvas Image. // 27..29 Height of the Canvas Image. -// There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8, -// XMP, EXIF ...) +// There can be extra chunks after the "VP8X" chunk (ICCP, FRGM, ANMF, VP8, +// VP8L, XMP, EXIF ...) // All sizes are in little-endian order. // Note: chunk data size must be padded to multiple of 2 when written. diff --git a/src/mux/demux.c b/src/mux/demux.c index fb25d002..4d8c18ba 100644 --- a/src/mux/demux.c +++ b/src/mux/demux.c @@ -39,8 +39,8 @@ typedef struct Frame { int x_offset_, y_offset_; int width_, height_; int duration_; - int is_tile_; // this is an image fragment from a tile. - int frame_num_; // the referent frame number for use in assembling tiles. + 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 complete_; // img_components_ contains a full image. ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH struct Frame* next_; @@ -327,35 +327,36 @@ static ParseStatus ParseFrame( } // Parse a 'FRGM' chunk and any image bearing chunks that immediately follow. -// 'tile_chunk_size' is the previously validated, padded chunk size. -static ParseStatus ParseTile(WebPDemuxer* const dmux, - uint32_t tile_chunk_size) { - const int has_tiles = !!(dmux->feature_flags_ & TILE_FLAG); +// 'fragment_chunk_size' is the previously validated, padded chunk size. +static ParseStatus ParseFragment(WebPDemuxer* const dmux, + uint32_t fragment_chunk_size) { + const int has_fragments = !!(dmux->feature_flags_ & FRAGMENTS_FLAG); const uint32_t padding = (FRGM_CHUNK_SIZE & 1); const uint32_t frgm_payload_size = - tile_chunk_size - (FRGM_CHUNK_SIZE + padding); - int added_tile = 0; + fragment_chunk_size - (FRGM_CHUNK_SIZE + padding); + int added_fragment = 0; MemBuffer* const mem = &dmux->mem_; Frame* frame; ParseStatus status = - NewFrame(mem, FRGM_CHUNK_SIZE, tile_chunk_size, &frame); + NewFrame(mem, FRGM_CHUNK_SIZE, fragment_chunk_size, &frame); if (status != PARSE_OK) return status; - frame->is_tile_ = 1; + frame->is_fragment_ = 1; frame->x_offset_ = 2 * GetLE24s(mem); frame->y_offset_ = 2 * GetLE24s(mem); Skip(mem, padding); - // Store a tile only if the tile flag is set and all data for this tile - // is available. + // Store a fragment only if the fragments flag is set and all data for this + // fragment is available. status = StoreFrame(dmux->num_frames_, frgm_payload_size, mem, frame); - if (status != PARSE_ERROR && has_tiles && frame->frame_num_ > 0) { - // Note num_frames_ is incremented only when all tiles have been consumed. - added_tile = AddFrame(dmux, frame); - if (!added_tile) status = PARSE_ERROR; + if (status != PARSE_ERROR && has_fragments && frame->frame_num_ > 0) { + // Note num_frames_ is incremented only when all fragments have been + // consumed. + added_fragment = AddFrame(dmux, frame); + if (!added_fragment) status = PARSE_ERROR; } - if (!added_tile) free(frame); + if (!added_fragment) free(frame); return status; } @@ -513,7 +514,7 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { } case MKFOURCC('F', 'R', 'G', 'M'): { if (dmux->num_frames_ == 0) dmux->num_frames_ = 1; - status = ParseTile(dmux, chunk_size_padded); + status = ParseFragment(dmux, chunk_size_padded); break; } case MKFOURCC('I', 'C', 'C', 'P'): { @@ -571,7 +572,7 @@ static int IsValidSimpleFormat(const WebPDemuxer* const dmux) { } static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { - const int has_tiles = !!(dmux->feature_flags_ & TILE_FLAG); + const int has_fragments = !!(dmux->feature_flags_ & FRAGMENTS_FLAG); const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); const Frame* f; @@ -583,15 +584,15 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { for (f = dmux->frames_; f != NULL; f = f->next_) { const int cur_frame_set = f->frame_num_; - int frame_count = 0, tile_count = 0; + int frame_count = 0, fragment_count = 0; - // Check frame properties and if the image is composed of tiles that each - // fragment came from a tile. + // Check frame properties and if the image is composed of fragments that + // each fragment came from a fragment. 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 (!has_tiles && f->is_tile_) return 0; + if (!has_fragments && f->is_fragment_) return 0; if (!has_frames && f->frame_num_ > 1) return 0; if (f->x_offset_ < 0 || f->y_offset_ < 0) return 0; if (f->complete_) { @@ -612,11 +613,11 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { if (f->next_ != NULL) return 0; } - tile_count += f->is_tile_; + fragment_count += f->is_fragment_; ++frame_count; } - if (!has_tiles && frame_count > 1) return 0; - if (tile_count > 0 && frame_count != tile_count) return 0; + if (!has_fragments && frame_count > 1) return 0; + if (fragment_count > 0 && frame_count != fragment_count) return 0; if (f == NULL) break; } return 1; @@ -706,7 +707,8 @@ uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) { // ----------------------------------------------------------------------------- // Frame iteration -// Find the first 'frame_num' frame. There may be multiple in a tiled frame. +// 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_) { @@ -715,19 +717,19 @@ static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) { return f; } -// Returns tile 'tile_num' and the total count. -static const Frame* GetTile( - const Frame* const frame_set, int tile_num, int* const count) { +// 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* tile = NULL; + const Frame* fragment = NULL; int total; for (total = 0; f != NULL && f->frame_num_ == this_frame; f = f->next_) { - if (++total == tile_num) tile = f; + if (++total == fragment_num) fragment = f; } *count = total; - return tile; + return fragment; } static const uint8_t* GetFramePayload(const uint8_t* const mem_buf, @@ -757,26 +759,28 @@ 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 tile_num, WebPIterator* const iter) { + int fragment_num, WebPIterator* const iter) { const uint8_t* const mem_buf = dmux->mem_.buf_; - int num_tiles; + int num_fragments; size_t payload_size = 0; - const Frame* const tile = GetTile(first_frame, tile_num, &num_tiles); - const uint8_t* const payload = GetFramePayload(mem_buf, tile, &payload_size); + const Frame* const fragment = + GetFragment(first_frame, fragment_num, &num_fragments); + const uint8_t* const payload = + GetFramePayload(mem_buf, fragment, &payload_size); if (payload == NULL) return 0; - iter->frame_num = first_frame->frame_num_; - iter->num_frames = dmux->num_frames_; - iter->tile_num = tile_num; - iter->num_tiles = num_tiles; - iter->x_offset = tile->x_offset_; - iter->y_offset = tile->y_offset_; - iter->width = tile->width_; - iter->height = tile->height_; - iter->duration = tile->duration_; - iter->complete = tile->complete_; - iter->tile.bytes = payload; - iter->tile.size = payload_size; + iter->frame_num = first_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->duration = fragment->duration_; + iter->complete = fragment->complete_; + iter->fragment.bytes = payload; + iter->fragment.size = payload_size; // TODO(jzern): adjust offsets for 'FRGM's embedded in 'ANMF's return 1; } @@ -811,13 +815,13 @@ int WebPDemuxPrevFrame(WebPIterator* iter) { return SetFrame(iter->frame_num - 1, iter); } -int WebPDemuxSelectTile(WebPIterator* iter, int tile) { - if (iter != NULL && iter->private_ != NULL && tile > 0) { +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, tile, iter); + return SynthesizeFrame(dmux, frame, fragment_num, iter); } return 0; } diff --git a/src/mux/muxedit.c b/src/mux/muxedit.c index 82978533..295368fb 100644 --- a/src/mux/muxedit.c +++ b/src/mux/muxedit.c @@ -109,15 +109,15 @@ static WebPMuxError MuxAddChunk(WebPMux* const mux, uint32_t nth, uint32_t tag, } // Create data for frame/tile given image data, offsets and duration. -static WebPMuxError CreateFrameTileData(const WebPData* const image, - int x_offset, int y_offset, - int duration, int is_lossless, - int is_frame, - WebPData* const frame_tile) { +static WebPMuxError CreateFrameFragmentData(const WebPData* const image, + int x_offset, int y_offset, + int duration, int is_lossless, + int is_frame, + WebPData* const frame_frgm) { int width; int height; - uint8_t* frame_tile_bytes; - const size_t frame_tile_size = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].size; + uint8_t* frame_frgm_bytes; + const size_t frame_frgm_size = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].size; const int ok = is_lossless ? VP8LGetInfo(image->bytes, image->size, &width, &height, NULL) : @@ -127,20 +127,20 @@ static WebPMuxError CreateFrameTileData(const WebPData* const image, assert(width > 0 && height > 0 && duration > 0); // Note: assertion on upper bounds is done in PutLE24(). - frame_tile_bytes = (uint8_t*)malloc(frame_tile_size); - if (frame_tile_bytes == NULL) return WEBP_MUX_MEMORY_ERROR; + frame_frgm_bytes = (uint8_t*)malloc(frame_frgm_size); + if (frame_frgm_bytes == NULL) return WEBP_MUX_MEMORY_ERROR; - PutLE24(frame_tile_bytes + 0, x_offset / 2); - PutLE24(frame_tile_bytes + 3, y_offset / 2); + PutLE24(frame_frgm_bytes + 0, x_offset / 2); + PutLE24(frame_frgm_bytes + 3, y_offset / 2); if (is_frame) { - PutLE24(frame_tile_bytes + 6, width - 1); - PutLE24(frame_tile_bytes + 9, height - 1); - PutLE24(frame_tile_bytes + 12, duration - 1); + PutLE24(frame_frgm_bytes + 6, width - 1); + PutLE24(frame_frgm_bytes + 9, height - 1); + PutLE24(frame_frgm_bytes + 12, duration - 1); } - frame_tile->bytes = frame_tile_bytes; - frame_tile->size = frame_tile_size; + frame_frgm->bytes = frame_frgm_bytes; + frame_frgm->size = frame_frgm_size; return WEBP_MUX_OK; } @@ -334,19 +334,19 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame, const int y_offset = frame->y_offset & ~1; const int duration = is_frame ? frame->duration : 1 /* unused */; const uint32_t tag = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].tag; - WebPData frame_tile; + WebPData frame_frgm; if (x_offset < 0 || x_offset >= MAX_POSITION_OFFSET || y_offset < 0 || y_offset >= MAX_POSITION_OFFSET || (duration <= 0 || duration > MAX_DURATION)) { err = WEBP_MUX_INVALID_ARGUMENT; goto Err; } - err = CreateFrameTileData(&wpi.img_->data_, x_offset, y_offset, duration, - is_lossless, is_frame, &frame_tile); + err = CreateFrameFragmentData(&wpi.img_->data_, x_offset, y_offset, + duration, is_lossless, is_frame, &frame_frgm); if (err != WEBP_MUX_OK) goto Err; - // Add frame/tile chunk (with copy_data = 1). - err = AddDataToChunkList(&frame_tile, 1, tag, &wpi.header_); - WebPDataClear(&frame_tile); // frame_tile owned by wpi.header_ now. + // Add frame/fragment chunk (with copy_data = 1). + err = AddDataToChunkList(&frame_frgm, 1, tag, &wpi.header_); + WebPDataClear(&frame_frgm); // frame_frgm owned by wpi.header_ now. if (err != WEBP_MUX_OK) goto Err; } @@ -394,15 +394,15 @@ WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth) { //------------------------------------------------------------------------------ // Assembly of the WebP RIFF file. -static WebPMuxError GetFrameTileInfo(const WebPChunk* const frame_tile_chunk, - int* const x_offset, int* const y_offset, - int* const duration) { - const uint32_t tag = frame_tile_chunk->tag_; +static WebPMuxError GetFrameFragmentInfo( + const WebPChunk* const frame_frgm_chunk, + int* const x_offset, int* const y_offset, int* const duration) { + const uint32_t tag = frame_frgm_chunk->tag_; const int is_frame = (tag == kChunks[IDX_ANMF].tag); - const WebPData* const data = &frame_tile_chunk->data_; + const WebPData* const data = &frame_frgm_chunk->data_; const size_t expected_data_size = is_frame ? ANMF_CHUNK_SIZE : FRGM_CHUNK_SIZE; - assert(frame_tile_chunk != NULL); + assert(frame_frgm_chunk != NULL); assert(tag == kChunks[IDX_ANMF].tag || tag == kChunks[IDX_FRGM].tag); if (data->size != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT; @@ -437,11 +437,11 @@ static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi, int* const duration, int* const width, int* const height) { const WebPChunk* const image_chunk = wpi->img_; - const WebPChunk* const frame_tile_chunk = wpi->header_; + const WebPChunk* const frame_frgm_chunk = wpi->header_; // Get offsets and duration from ANMF/FRGM chunk. const WebPMuxError err = - GetFrameTileInfo(frame_tile_chunk, x_offset, y_offset, duration); + GetFrameFragmentInfo(frame_frgm_chunk, x_offset, y_offset, duration); if (err != WEBP_MUX_OK) return err; // Get width and height from VP8/VP8L chunk. @@ -463,7 +463,7 @@ static WebPMuxError GetImageCanvasWidthHeight( int max_x = 0; int max_y = 0; int64_t image_area = 0; - // Aggregate the bounding box for animation frames & tiled images. + // Aggregate the bounding box for animation frames & fragmented images. for (; wpi != NULL; wpi = wpi->next_) { int x_offset, y_offset, duration, w, h; const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset, @@ -480,11 +480,11 @@ static WebPMuxError GetImageCanvasWidthHeight( } *width = max_x; *height = max_y; - // Crude check to validate that there are no image overlaps/holes for tile - // images. Check that the aggregated image area for individual tiles exactly - // matches the image area of the constructed canvas. However, the area-match - // is necessary but not sufficient condition. - if ((flags & TILE_FLAG) && (image_area != (max_x * max_y))) { + // Crude check to validate that there are no image overlaps/holes for + // fragmented images. Check that the aggregated image area for individual + // fragments exactly matches the image area of the constructed canvas. + // However, the area-match is necessary but not sufficient condition. + if ((flags & FRAGMENTS_FLAG) && (image_area != (max_x * max_y))) { *width = 0; *height = 0; return WEBP_MUX_INVALID_ARGUMENT; @@ -539,8 +539,8 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { } if (images->header_ != NULL) { if (images->header_->tag_ == kChunks[IDX_FRGM].tag) { - // This is a tiled image. - flags |= TILE_FLAG; + // This is a fragmented image. + flags |= FRAGMENTS_FLAG; } else if (images->header_->tag_ == kChunks[IDX_ANMF].tag) { // This is an image with animation. flags |= ANIMATION_FLAG; diff --git a/src/mux/muxinternal.c b/src/mux/muxinternal.c index 51fce0fd..f1f31f90 100644 --- a/src/mux/muxinternal.c +++ b/src/mux/muxinternal.c @@ -476,16 +476,16 @@ WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) { WebPMuxError MuxValidateForImage(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_tiles = MuxImageCount(mux->images_, WEBP_CHUNK_FRGM); + 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_tiles == 0) { + } else if (num_images == 1 && num_frames == 0 && num_fragments == 0) { // Valid case (single image). return WEBP_MUX_OK; } else { - // Frame/Tile case OR an invalid mux. + // Frame/Fragment case OR an invalid mux. return WEBP_MUX_INVALID_ARGUMENT; } } @@ -520,7 +520,7 @@ WebPMuxError MuxValidate(const WebPMux* const mux) { int num_xmp; int num_loop_chunks; int num_frames; - int num_tiles; + int num_fragments; int num_vp8x; int num_images; int num_alpha; @@ -565,8 +565,8 @@ WebPMuxError MuxValidate(const WebPMux* const mux) { } } - // Tiling: TILE_FLAG and tile chunk(s) are consistent. - err = ValidateChunk(mux, IDX_FRGM, TILE_FLAG, flags, -1, &num_tiles); + // Fragmentation: FRAGMENTS_FLAG and FRGM chunk(s) are consistent. + err = ValidateChunk(mux, IDX_FRGM, FRAGMENTS_FLAG, flags, -1, &num_fragments); if (err != WEBP_MUX_OK) return err; // Verify either VP8X chunk is present OR there is only one elem in @@ -586,8 +586,8 @@ WebPMuxError MuxValidate(const WebPMux* const mux) { if (err != WEBP_MUX_OK) return err; } - // num_tiles & num_images are consistent. - if (num_tiles > 0 && num_images != num_tiles) { + // num_fragments & num_images are consistent. + if (num_fragments > 0 && num_images != num_fragments) { return WEBP_MUX_INVALID_ARGUMENT; } diff --git a/src/mux/muxread.c b/src/mux/muxread.c index 24633bf1..7ae904f7 100644 --- a/src/mux/muxread.c +++ b/src/mux/muxread.c @@ -364,19 +364,19 @@ static WebPMuxError MuxGetImageInternal(const WebPMuxImage* const wpi, return SynthesizeBitstream(wpi, &info->bitstream); } -static WebPMuxError MuxGetFrameTileInternal(const WebPMuxImage* const wpi, - WebPMuxFrameInfo* const frame) { +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_tile_data; + const WebPData* frame_frgm_data; assert(wpi->header_ != NULL); // Already checked by WebPMuxGetFrame(). - // Get frame/tile chunk. - frame_tile_data = &wpi->header_->data_; - if (frame_tile_data->size < kChunks[idx].size) return WEBP_MUX_BAD_DATA; + // 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_tile_data->bytes + 0); - frame->y_offset = 2 * GetLE24(frame_tile_data->bytes + 3); - frame->duration = is_frame ? 1 + GetLE24(frame_tile_data->bytes + 12) : 1; + frame->x_offset = 2 * GetLE24(frame_frgm_data->bytes + 0); + frame->y_offset = 2 * GetLE24(frame_frgm_data->bytes + 3); + frame->duration = is_frame ? 1 + GetLE24(frame_frgm_data->bytes + 12) : 1; frame->id = ChunkGetIdFromTag(wpi->header_->tag_); return SynthesizeBitstream(wpi, &frame->bitstream); } @@ -399,7 +399,7 @@ WebPMuxError WebPMuxGetFrame( if (wpi->header_ == NULL) { return MuxGetImageInternal(wpi, frame); } else { - return MuxGetFrameTileInternal(wpi, frame); + return MuxGetFrameFragmentInternal(wpi, frame); } } diff --git a/src/webp/format_constants.h b/src/webp/format_constants.h index 779932b0..1926d4f6 100644 --- a/src/webp/format_constants.h +++ b/src/webp/format_constants.h @@ -83,7 +83,7 @@ typedef enum { #define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height. #define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count #define MAX_DURATION (1 << 24) // maximum duration -#define MAX_POSITION_OFFSET (1 << 24) // maximum frame/tile x/y offset +#define MAX_POSITION_OFFSET (1 << 24) // maximum frame/fragment x/y offset // Maximum chunk payload is such that adding the header and padding won't // overflow a uint32_t. diff --git a/src/webp/mux.h b/src/webp/mux.h index 62dc2afe..127a1170 100644 --- a/src/webp/mux.h +++ b/src/webp/mux.h @@ -11,7 +11,7 @@ // Vikas (vikasa@google.com) // This API allows manipulation of WebP container images containing features -// like color profile, metadata, animation and tiling. +// like color profile, metadata, animation and fragmented images. // // Code Example#1: Creating a MUX with image data, color profile and XMP // metadata. @@ -82,7 +82,7 @@ enum WebPMuxError { // Flag values for different features used in VP8X chunk. enum WebPFeatureFlags { - TILE_FLAG = 0x00000001, + FRAGMENTS_FLAG = 0x00000001, ANIMATION_FLAG = 0x00000002, XMP_FLAG = 0x00000004, EXIF_FLAG = 0x00000008, @@ -233,12 +233,12 @@ struct WebPMuxFrameInfo { uint32_t pad[3]; // padding for later use }; -// Sets the (non-animated and non-tiled) image in the mux object. -// Note: Any existing images (including frames/tiles) will be removed. +// Sets the (non-animated and non-fragmented) image in the mux object. +// Note: Any existing images (including frames/fragments) will be removed. // Parameters: // mux - (in/out) object in which the image is to be set // bitstream - (in) can either be a raw VP8/VP8L bitstream or a single-image -// WebP file (non-animated and non-tiled) +// WebP file (non-animated and non-fragmented) // copy_data - (in) value 1 indicates given data WILL be copied to the mux // and value 0 indicates data will NOT be copied. // Returns: @@ -250,8 +250,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetImage( // Adds a frame at the end of the mux object. // Notes: (1) frame.id should be one of WEBP_CHUNK_ANMF or WEBP_CHUNK_FRGM -// (2) For setting a non-animated non-tiled image, use WebPMuxSetImage() -// instead. +// (2) For setting a non-animated non-fragmented image, use +// WebPMuxSetImage() instead. // (3) Type of frame being pushed must be same as the frames in mux. // (4) As WebP only supports even offsets, any odd offset will be snapped // to an even location using: offset &= ~1 @@ -428,22 +428,23 @@ WEBP_EXTERN(uint32_t) WebPDemuxGetI( struct WebPIterator { int frame_num; int num_frames; - int tile_num; - int num_tiles; + int fragment_num; + int num_fragments; int x_offset, y_offset; // offset relative to the canvas. - int width, height; // dimensions of this frame or tile. + int width, height; // dimensions of this frame or fragment. int duration; // display duration in milliseconds. - int complete; // true if 'tile_' contains a full frame. partial images may - // still be decoded with the WebP incremental decoder. - WebPData tile; // The frame or tile given by 'frame_num_' and 'tile_num_'. + int complete; // true if 'fragment' contains a full frame. partial images + // may still be decoded with the WebP incremental decoder. + WebPData fragment; // The frame or fragment given by 'frame_num' and + // 'fragment_num'. uint32_t pad[4]; // padding for later use void* private_; // for internal use only. }; // Retrieves frame 'frame_number' from 'dmux'. -// 'iter->tile_' points to the first tile on return from this function. -// Individual tiles may be extracted using WebPDemuxSetTile(). +// 'iter->fragment' points to the first fragment on return from this function. +// Individual fragments may be extracted using WebPDemuxSetFragment(). // Setting 'frame_number' equal to 0 will return the last frame of the image. // Returns false if 'dmux' is NULL or frame 'frame_number' is not present. // Call WebPDemuxReleaseIterator() when use of the iterator is complete. @@ -451,14 +452,14 @@ struct WebPIterator { WEBP_EXTERN(int) WebPDemuxGetFrame( const WebPDemuxer* dmux, int frame_number, WebPIterator* iter); -// Sets 'iter->tile_' to point to the next ('iter->frame_num_' + 1) or previous -// ('iter->frame_num_' - 1) frame. These functions do not loop. +// Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or +// previous ('iter->frame_num' - 1) frame. These functions do not loop. // Returns true on success, false otherwise. WEBP_EXTERN(int) WebPDemuxNextFrame(WebPIterator* iter); WEBP_EXTERN(int) WebPDemuxPrevFrame(WebPIterator* iter); -// Sets 'iter->tile_' to reflect tile number 'tile_number'. -// Returns true if tile 'tile_number' is present, false otherwise. +// Sets 'iter->fragment' to reflect fragment number 'fragment_num'. +// Returns true if fragment 'fragment_num' is present, false otherwise. WEBP_EXTERN(int) WebPDemuxSelectTile(WebPIterator* iter, int tile_number); // Releases any memory associated with 'iter'. @@ -493,8 +494,8 @@ WEBP_EXTERN(int) WebPDemuxGetChunk(const WebPDemuxer* dmux, const char fourcc[4], int chunk_number, WebPChunkIterator* iter); -// Sets 'iter->chunk_' to point to the next ('iter->chunk_num_' + 1) or previous -// ('iter->chunk_num_' - 1) chunk. These functions do not loop. +// Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous +// ('iter->chunk_num' - 1) chunk. These functions do not loop. // Returns true on success, false otherwise. WEBP_EXTERN(int) WebPDemuxNextChunk(WebPChunkIterator* iter); WEBP_EXTERN(int) WebPDemuxPrevChunk(WebPChunkIterator* iter);