diff --git a/examples/webpmux.c b/examples/webpmux.c index 51333b06..c5454d16 100644 --- a/examples/webpmux.c +++ b/examples/webpmux.c @@ -199,13 +199,12 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) { printf("No.: x_offset y_offset duration image_size"); printf("\n"); for (i = 1; i <= nFrames; i++) { - int x_offset, y_offset, duration; - WebPData bitstream; - err = WebPMuxGetFrame(mux, i, &bitstream, - &x_offset, &y_offset, &duration); + WebPMuxFrameInfo frame; + err = WebPMuxGetFrame(mux, i, &frame); RETURN_IF_ERROR2("Failed to retrieve frame#%d\n", i); - printf("%3d: %8d %8d %8d %10zu", - i, x_offset, y_offset, duration, bitstream.size_); + printf("%3d: %8d %8d %8d %10zu", i, frame.x_offset_, frame.y_offset_, + frame.duration_, frame.bitstream_.size_); + WebPDataClear(&frame.bitstream_); printf("\n"); } } @@ -222,11 +221,12 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) { printf("No.: x_offset y_offset image_size"); printf("\n"); for (i = 1; i <= nTiles; i++) { - int x_offset, y_offset; - WebPData bitstream; - err = WebPMuxGetTile(mux, i, &bitstream, &x_offset, &y_offset); + WebPMuxFrameInfo tile; + err = WebPMuxGetTile(mux, i, &tile); RETURN_IF_ERROR2("Failed to retrieve tile#%d\n", i); - printf("%3d: %8d %8d %10zu", i, x_offset, y_offset, bitstream.size_); + printf("%3d: %8d %8d %10zu", + i, tile.x_offset_, tile.y_offset_, tile.bitstream_.size_); + WebPDataClear(&tile.bitstream_); printf("\n"); } } @@ -355,14 +355,13 @@ static int WriteWebP(WebPMux* const mux, const char* filename) { return ok; } -static int ParseFrameArgs(const char* args, int* const x_offset, - int* const y_offset, int* const duration) { - return (sscanf(args, "+%d+%d+%d", x_offset, y_offset, duration) == 3); +static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) { + return (sscanf(args, "+%d+%d+%d", + &info->x_offset_, &info->y_offset_, &info->duration_) == 3); } -static int ParseTileArgs(const char* args, - int* const x_offset, int* const y_offset) { - return (sscanf(args, "+%d+%d", x_offset, y_offset) == 2); +static int ParseTileArgs(const char* args, WebPMuxFrameInfo* const info) { + return (sscanf(args, "+%d+%d", &info->x_offset_, &info->y_offset_) == 2); } //------------------------------------------------------------------------------ @@ -688,14 +687,12 @@ static int InitializeConfig(int argc, const char* argv[], static int GetFrameTile(const WebPMux* mux, const WebPMuxConfig* config, int isFrame) { - WebPData bitstream; - int x_offset = 0; - int y_offset = 0; - int duration = 0; WebPMuxError err = WEBP_MUX_OK; WebPMux* mux_single = NULL; long num = 0; int ok = 1; + WebPMuxFrameInfo info; + WebPDataInit(&info.bitstream_); num = strtol(config->feature_.args_[0].params_, NULL, 10); if (num < 0) { @@ -703,14 +700,13 @@ static int GetFrameTile(const WebPMux* mux, } if (isFrame) { - err = WebPMuxGetFrame(mux, num, &bitstream, - &x_offset, &y_offset, &duration); + err = WebPMuxGetFrame(mux, num, &info); if (err != WEBP_MUX_OK) { ERROR_GOTO3("ERROR (%s): Could not get frame %ld.\n", ErrorString(err), num, ErrGet); } } else { - err = WebPMuxGetTile(mux, num, &bitstream, &x_offset, &y_offset); + err = WebPMuxGetTile(mux, num, &info); if (err != WEBP_MUX_OK) { ERROR_GOTO3("ERROR (%s): Could not get frame %ld.\n", ErrorString(err), num, ErrGet); @@ -723,7 +719,7 @@ static int GetFrameTile(const WebPMux* mux, ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n", ErrorString(err), ErrGet); } - err = WebPMuxSetImage(mux_single, &bitstream, 1); + err = WebPMuxSetImage(mux_single, &info.bitstream_, 1); if (err != WEBP_MUX_OK) { ERROR_GOTO2("ERROR (%s): Could not create single image mux object.\n", ErrorString(err), ErrGet); @@ -731,6 +727,7 @@ static int GetFrameTile(const WebPMux* mux, ok = WriteWebP(mux_single, config->output_); ErrGet: + WebPDataClear(&info.bitstream_); WebPMuxDelete(mux_single); return ok; } @@ -738,10 +735,7 @@ static int GetFrameTile(const WebPMux* mux, // Read and process config. static int Process(const WebPMuxConfig* config) { WebPMux* mux = NULL; - WebPData webpdata; WebPData metadata, color_profile; - int x_offset = 0; - int y_offset = 0; WebPMuxError err = WEBP_MUX_OK; int index = 0; int ok = 1; @@ -761,20 +755,20 @@ static int Process(const WebPMuxConfig* config) { break; case FEATURE_ICCP: - err = WebPMuxGetColorProfile(mux, &webpdata); + err = WebPMuxGetColorProfile(mux, &color_profile); if (err != WEBP_MUX_OK) { ERROR_GOTO2("ERROR (%s): Could not get color profile.\n", ErrorString(err), Err2); } - ok = WriteData(config->output_, &webpdata); + ok = WriteData(config->output_, &color_profile); break; case FEATURE_XMP: - err = WebPMuxGetMetadata(mux, &webpdata); + err = WebPMuxGetMetadata(mux, &metadata); if (err != WEBP_MUX_OK) { ERROR_GOTO2("ERROR (%s): Could not get XMP metadata.\n", ErrorString(err), Err2); } - ok = WriteData(config->output_, &webpdata); + ok = WriteData(config->output_, &metadata); break; default: @@ -803,19 +797,17 @@ static int Process(const WebPMuxConfig* config) { ErrorString(err), Err2); } } else if (feature->args_[index].subtype_ == SUBTYPE_FRM) { - int duration; + WebPMuxFrameInfo frame; ok = ReadFileToWebPData(feature->args_[index].filename_, - &webpdata); + &frame.bitstream_); if (!ok) goto Err2; - ok = ParseFrameArgs(feature->args_[index].params_, - &x_offset, &y_offset, &duration); + ok = ParseFrameArgs(feature->args_[index].params_, &frame); if (!ok) { - WebPDataClear(&webpdata); + WebPDataClear(&frame.bitstream_); ERROR_GOTO1("ERROR: Could not parse frame properties.\n", Err2); } - err = WebPMuxPushFrame(mux, &webpdata, x_offset, y_offset, - duration, 1); - WebPDataClear(&webpdata); + err = WebPMuxPushFrame(mux, &frame, 1); + WebPDataClear(&frame.bitstream_); if (err != WEBP_MUX_OK) { ERROR_GOTO3("ERROR (%s): Could not add a frame at index %d.\n", ErrorString(err), index, Err2); @@ -833,16 +825,17 @@ static int Process(const WebPMuxConfig* config) { ErrorString(WEBP_MUX_MEMORY_ERROR), Err2); } for (index = 0; index < feature->arg_count_; ++index) { - ok = ReadFileToWebPData(feature->args_[index].filename_, &webpdata); + WebPMuxFrameInfo tile; + ok = ReadFileToWebPData(feature->args_[index].filename_, + &tile.bitstream_); if (!ok) goto Err2; - ok = ParseTileArgs(feature->args_[index].params_, &x_offset, - &y_offset); + ok = ParseTileArgs(feature->args_[index].params_, &tile); if (!ok) { - WebPDataClear(&webpdata); + WebPDataClear(&tile.bitstream_); ERROR_GOTO1("ERROR: Could not parse tile properties.\n", Err2); } - err = WebPMuxPushTile(mux, &webpdata, x_offset, y_offset, 1); - WebPDataClear(&webpdata); + err = WebPMuxPushTile(mux, &tile, 1); + WebPDataClear(&tile.bitstream_); if (err != WEBP_MUX_OK) { ERROR_GOTO3("ERROR (%s): Could not add a tile at index %d.\n", ErrorString(err), index, Err2); diff --git a/src/mux/muxedit.c b/src/mux/muxedit.c index 08629d4a..c7b50ae7 100644 --- a/src/mux/muxedit.c +++ b/src/mux/muxedit.c @@ -317,8 +317,10 @@ WebPMuxError WebPMuxSetLoopCount(WebPMux* mux, int loop_count) { } static WebPMuxError MuxPushFrameTileInternal( - WebPMux* const mux, const WebPData* const bitstream, int x_offset, - int y_offset, int duration, int copy_data, uint32_t tag) { + WebPMux* const mux, const WebPMuxFrameInfo* const frame_tile_info, + int copy_data, uint32_t tag) { + const WebPData* bitstream; + int x_offset, y_offset, duration; WebPChunk chunk; WebPData image; WebPData alpha; @@ -330,13 +332,21 @@ static WebPMuxError MuxPushFrameTileInternal( int image_tag; // Sanity checks. - if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL || - bitstream->size_ > MAX_CHUNK_PAYLOAD) { + if (mux == NULL || frame_tile_info == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + bitstream = &frame_tile_info->bitstream_; + x_offset = frame_tile_info->x_offset_; + y_offset = frame_tile_info->y_offset_; + duration = is_frame ? frame_tile_info->duration_ : 1 /* unused */; + + if (bitstream->bytes_ == NULL || bitstream->size_ > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } if (x_offset < 0 || x_offset >= MAX_POSITION_OFFSET || y_offset < 0 || y_offset >= MAX_POSITION_OFFSET || - duration <= 0 || duration > MAX_DURATION) { + (is_frame && (duration <= 0 || duration > MAX_DURATION))) { return WEBP_MUX_INVALID_ARGUMENT; } @@ -397,18 +407,17 @@ static WebPMuxError MuxPushFrameTileInternal( return err; } -WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPData* bitstream, - int x_offset, int y_offset, - int duration, int copy_data) { - return MuxPushFrameTileInternal(mux, bitstream, x_offset, y_offset, - duration, copy_data, kChunks[IDX_FRAME].tag); +WebPMuxError WebPMuxPushFrame(WebPMux* mux, + const WebPMuxFrameInfo* frame, + int copy_data) { + return MuxPushFrameTileInternal(mux, frame, copy_data, + kChunks[IDX_FRAME].tag); } -WebPMuxError WebPMuxPushTile(WebPMux* mux, const WebPData* bitstream, - int x_offset, int y_offset, +WebPMuxError WebPMuxPushTile(WebPMux* mux, + const WebPMuxFrameInfo* tile, int copy_data) { - return MuxPushFrameTileInternal(mux, bitstream, x_offset, y_offset, - 1 /* unused duration */, copy_data, + return MuxPushFrameTileInternal(mux, tile /*unused duration*/, copy_data, kChunks[IDX_TILE].tag); } diff --git a/src/mux/muxread.c b/src/mux/muxread.c index 21c3cfba..5d135115 100644 --- a/src/mux/muxread.c +++ b/src/mux/muxread.c @@ -315,9 +315,8 @@ WebPMuxError WebPMuxGetLoopCount(const WebPMux* mux, int* loop_count) { } 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 WebPMux* const mux, uint32_t nth, + WebPMuxFrameInfo* const frame_tile_info, uint32_t tag) { const WebPData* frame_tile_data; WebPMuxError err; WebPMuxImage* wpi; @@ -326,8 +325,7 @@ static WebPMuxError MuxGetFrameTileInternal( 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)) { + if (mux == NULL || frame_tile_info == NULL) { return WEBP_MUX_INVALID_ARGUMENT; } @@ -340,25 +338,23 @@ static WebPMuxError MuxGetFrameTileInternal( frame_tile_data = &wpi->header_->data_; 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); + frame_tile_info->x_offset_ = 2 * GetLE24(frame_tile_data->bytes_ + 0); + frame_tile_info->y_offset_ = 2 * GetLE24(frame_tile_data->bytes_ + 3); + if (is_frame) { + frame_tile_info->duration_ = 1 + GetLE24(frame_tile_data->bytes_ + 12); + } - return SynthesizeBitstream(wpi, bitstream); + return SynthesizeBitstream(wpi, &frame_tile_info->bitstream_); } 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); + WebPMuxFrameInfo* frame) { + return MuxGetFrameTileInternal(mux, nth, frame, kChunks[IDX_FRAME].tag); } 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); + WebPMuxFrameInfo* tile) { + return MuxGetFrameTileInternal(mux, nth, tile, kChunks[IDX_TILE].tag); } // Get chunk index from chunk id. Returns IDX_NIL if not found. diff --git a/src/webp/mux.h b/src/webp/mux.h index 5139af80..cdfc441e 100644 --- a/src/webp/mux.h +++ b/src/webp/mux.h @@ -174,7 +174,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(WebPMux* mux, // bitstream - (out) the image data // Returns: // WEBP_MUX_INVALID_ARGUMENT - if either mux or bitstream is NULL -// OR mux contains animation/tiling. +// or if mux contains animation/tiling. // WEBP_MUX_NOT_FOUND - if image is not present in mux object. // WEBP_MUX_OK - on success. WEBP_EXTERN(WebPMuxError) WebPMuxGetImage(const WebPMux* mux, @@ -185,7 +185,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetImage(const WebPMux* mux, // mux - (in/out) object from which the image is to be deleted // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux is NULL -// OR if mux contains animation/tiling. +// or if mux contains animation/tiling. // WEBP_MUX_NOT_FOUND - if image is not present in mux object. // WEBP_MUX_OK - on success. WEBP_EXTERN(WebPMuxError) WebPMuxDeleteImage(WebPMux* mux); @@ -271,55 +271,48 @@ WEBP_EXTERN(WebPMuxError) WebPMuxDeleteColorProfile(WebPMux* mux); //------------------------------------------------------------------------------ // Animation. +// Encapsulates data about a single frame/tile. +typedef struct { + WebPData bitstream_; // image data: can either be a raw VP8/VP8L bitstream + // or a single-image WebP file. + int x_offset_; // x-offset of the frame. + int y_offset_; // y-offset of the frame. + int duration_; // duration of the frame (in milliseconds). + uint32_t pad[3]; // padding for later use +} WebPMuxFrameInfo; + // Adds an animation frame at the end of the mux object. // Note: as WebP only supports even offsets, any odd offset will be snapped to // an even location using: offset &= ~1 // Parameters: // mux - (in/out) object to which an animation frame is to be added -// bitstream - (in) the image data corresponding to the frame. It can either -// be a raw VP8/VP8L bitstream or a single-image WebP file -// (non-animated and non-tiled) -// x_offset - (in) x-offset of the frame to be added -// y_offset - (in) y-offset of the frame to be added -// duration - (in) duration of the frame to be added (in milliseconds) +// frame - (in) frame data. // copy_data - (in) value 1 indicates given data WILL copied to the mux, and // value 0 indicates data will NOT be copied. // Returns: -// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL +// WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL +// or if content of 'frame' is invalid. // WEBP_MUX_MEMORY_ERROR - on memory allocation error. // WEBP_MUX_OK - on success. WEBP_EXTERN(WebPMuxError) WebPMuxPushFrame( - WebPMux* mux, const WebPData* bitstream, - int x_offset, int y_offset, int duration, int copy_data); - -// TODO(urvang): Create a struct as follows to reduce argument list size: -// typedef struct { -// WebPData bitstream; -// int x_offset, y_offset; -// int duration; -// } FrameInfo; + WebPMux* mux, const WebPMuxFrameInfo* frame, int copy_data); // Gets the nth animation frame from the mux object. -// The content of 'bitstream' is allocated using malloc(), and NOT +// The content of 'frame->bitstream_' is allocated using malloc(), and NOT // owned by the 'mux' object. It MUST be deallocated by the caller by calling // WebPDataClear(). // nth=0 has a special meaning - last position. // Parameters: // mux - (in) object from which the info is to be fetched // nth - (in) index of the frame in the mux object -// bitstream - (out) the image data -// x_offset - (out) x-offset of the returned frame -// y_offset - (out) y-offset of the returned frame -// duration - (out) duration of the returned frame (in milliseconds) +// frame - (out) data of the returned frame // Returns: -// WEBP_MUX_INVALID_ARGUMENT - if either mux, bitstream, x_offset, -// y_offset, or duration is NULL +// WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL // WEBP_MUX_NOT_FOUND - if there are less than nth frames in the mux object. // WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid. // WEBP_MUX_OK - on success. WEBP_EXTERN(WebPMuxError) WebPMuxGetFrame( - const WebPMux* mux, uint32_t nth, WebPData* bitstream, - int* x_offset, int* y_offset, int* duration); + const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame); // Deletes an animation frame from the mux object. // nth=0 has a special meaning - last position. @@ -364,41 +357,33 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetLoopCount(const WebPMux* mux, // an even location using: offset &= ~1 // Parameters: // mux - (in/out) object to which a tile is to be added. -// bitstream - (in) the image data corresponding to the frame. It can either -// be a raw VP8/VP8L bitstream or a single-image WebP file -// (non-animated and non-tiled) -// x_offset - (in) x-offset of the tile to be added -// y_offset - (in) y-offset of the tile to be added +// tile - (in) tile data. // copy_data - (in) value 1 indicates given data WILL copied to the mux, and // value 0 indicates data will NOT be copied. // Returns: -// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL +// WEBP_MUX_INVALID_ARGUMENT - if mux or tile is NULL +// or if content of 'tile' is invalid. // WEBP_MUX_MEMORY_ERROR - on memory allocation error. // WEBP_MUX_OK - on success. WEBP_EXTERN(WebPMuxError) WebPMuxPushTile( - WebPMux* mux, const WebPData* bitstream, - int x_offset, int y_offset, int copy_data); + WebPMux* mux, const WebPMuxFrameInfo* tile, int copy_data); // Gets the nth tile from the mux object. -// The content of 'bitstream' is allocated using malloc(), and NOT +// The content of 'tile->bitstream_' is allocated using malloc(), and NOT // owned by the 'mux' object. It MUST be deallocated by the caller by calling // WebPDataClear(). // nth=0 has a special meaning - last position. // Parameters: // mux - (in) object from which the info is to be fetched // nth - (in) index of the tile in the mux object -// bitstream - (out) the image data -// x_offset - (out) x-offset of the returned tile -// y_offset - (out) y-offset of the returned tile +// tile - (out) data of the returned tile // Returns: -// WEBP_MUX_INVALID_ARGUMENT - if either mux, bitstream, x_offset or -// y_offset is NULL +// WEBP_MUX_INVALID_ARGUMENT - if either mux or tile is NULL // WEBP_MUX_NOT_FOUND - if there are less than nth tiles in the mux object. // WEBP_MUX_BAD_DATA - if nth tile chunk in mux is invalid. // WEBP_MUX_OK - on success. WEBP_EXTERN(WebPMuxError) WebPMuxGetTile( - const WebPMux* mux, uint32_t nth, WebPData* bitstream, - int* x_offset, int* y_offset); + const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* tile); // Deletes a tile from the mux object. // nth=0 has a special meaning - last position