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
This commit is contained in:
Urvang Joshi 2012-10-31 17:49:15 -07:00
parent 81b8a741ed
commit a00a3daf5b
11 changed files with 219 additions and 212 deletions

View File

@ -8,9 +8,9 @@ Description:
============ ============
WebP Mux: library to create a WebP container object for features like WebP Mux: library to create a WebP container object for features like
color profile, metadata, animation and tiling. A reference command line color profile, metadata, animation and fragmented images. A reference command
tool 'webpmux' and WebP container specification 'doc/webp-container-spec.txt' line tool 'webpmux' and WebP container specification
are also provided in this package. 'doc/webp-container-spec.txt' are also provided in this package.
WebP Mux tool: 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 Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT
webpmux -set SET_OPTIONS INPUT -o OUTPUT webpmux -set SET_OPTIONS INPUT -o OUTPUT
webpmux -strip STRIP_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 -frame FRAME_OPTIONS [-frame...] -loop LOOP_COUNT -o OUTPUT
webpmux -info INPUT webpmux -info INPUT
webpmux [-h|-help] webpmux [-h|-help]
@ -35,7 +35,7 @@ GET_OPTIONS:
icc Get ICC profile. icc Get ICC profile.
exif Get EXIF metadata. exif Get EXIF metadata.
xmp Get XMP metadata. xmp Get XMP metadata.
tile n Get nth tile. frgm n Get nth fragment.
frame n Get nth frame. frame n Get nth frame.
SET_OPTIONS: SET_OPTIONS:
@ -53,11 +53,11 @@ STRIP_OPTIONS:
exif Strip EXIF metadata. exif Strip EXIF metadata.
xmp Strip XMP metadata. xmp Strip XMP metadata.
TILE_OPTIONS(i): FRAGMENT_OPTIONS(i):
Create tiled image. Create fragmented image.
file_i +xi+yi file_i +xi+yi
where: 'file_i' is the i'th tile (WebP format), where: 'file_i' is the i'th fragment (WebP format),
'xi','yi' specify the image offset for this tile. 'xi','yi' specify the image offset for this fragment.
FRAME_OPTIONS(i): FRAME_OPTIONS(i):
Create animation. Create animation.
@ -75,8 +75,8 @@ WebP Mux API:
============== ==============
The WebP Mux API contains methods for adding data to and reading data from 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 WebPMux (a WebP container object). This API currently supports XMP/EXIF
metadata, ICC profile, animation and tiling. Other features will be added metadata, ICC profile, animation and fragmented images. Other features
in subsequent releases. will be added in subsequent releases.
Example#1 (pseudo code): Creating a WebPMux object with image data, color Example#1 (pseudo code): Creating a WebPMux object with image data, color
profile and XMP metadata. profile and XMP metadata.

View File

@ -183,7 +183,7 @@ static int Decode(int* const duration) {
"Frame offsets not yet supported! Forcing offset to 0,0\n"); "Frame offsets not yet supported! Forcing offset to 0,0\n");
} }
output_buffer->colorspace = MODE_RGBA; 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); config) == VP8_STATUS_OK);
if (!ok) { if (!ok) {
fprintf(stderr, "Decoding of frame #%d failed!\n", iter->frame_num); fprintf(stderr, "Decoding of frame #%d failed!\n", iter->frame_num);
@ -298,8 +298,8 @@ int main(int argc, char *argv[]) {
goto Error; goto Error;
} }
if (WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & TILE_FLAG) { if (WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & FRAGMENTS_FLAG) {
fprintf(stderr, "Tiling is not supported for now!\n"); fprintf(stderr, "Image fragments are not supported for now!\n");
goto Error; goto Error;
} }

View File

@ -17,11 +17,11 @@
/* Usage examples: /* Usage examples:
Create container WebP file: Create container WebP file:
webpmux -tile tile_1.webp +0+0 \ webpmux -frgm fragment_1.webp +0+0 \
-tile tile_2.webp +960+0 \ -frgm fragment_2.webp +960+0 \
-tile tile_3.webp +0+576 \ -frgm fragment_3.webp +0+576 \
-tile tile_4.webp +960+576 \ -frgm fragment_4.webp +960+576 \
-o out_tile_container.webp -o out_fragment_container.webp
webpmux -frame anim_1.webp +0+0+0 \ webpmux -frame anim_1.webp +0+0+0 \
-frame anim_2.webp +25+25+100 \ -frame anim_2.webp +25+25+100 \
@ -35,7 +35,7 @@
webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp
Extract relevant data from WebP container file: 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 frame n in.webp -o out_frame.webp
webpmux -get icc in.webp -o image_profile.icc webpmux -get icc in.webp -o image_profile.icc
webpmux -get exif in.webp -o image_metadata.exif webpmux -get exif in.webp -o image_metadata.exif
@ -87,8 +87,8 @@ typedef enum {
FEATURE_EXIF, FEATURE_EXIF,
FEATURE_XMP, FEATURE_XMP,
FEATURE_ICCP, FEATURE_ICCP,
FEATURE_FRM, FEATURE_ANMF,
FEATURE_TILE, FEATURE_FRGM,
LAST_FEATURE LAST_FEATURE
} FeatureType; } FeatureType;
@ -98,7 +98,7 @@ static const char* const kFourccList[LAST_FEATURE] = {
static const char* const kDescriptions[LAST_FEATURE] = { static const char* const kDescriptions[LAST_FEATURE] = {
NULL, "EXIF metadata", "XMP metadata", "ICC profile", NULL, "EXIF metadata", "XMP metadata", "ICC profile",
"Animation frame", "Tile fragment" "Animation frame", "Image fragment"
}; };
typedef struct { typedef struct {
@ -197,17 +197,17 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
// Print the features present. // Print the features present.
printf("Features present:"); printf("Features present:");
if (flag & ANIMATION_FLAG) printf(" animation"); 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 & ICCP_FLAG) printf(" icc profile");
if (flag & EXIF_FLAG) printf(" EXIF metadata"); if (flag & EXIF_FLAG) printf(" EXIF metadata");
if (flag & XMP_FLAG) printf(" XMP metadata"); if (flag & XMP_FLAG) printf(" XMP metadata");
if (flag & ALPHA_FLAG) printf(" transparency"); if (flag & ALPHA_FLAG) printf(" transparency");
printf("\n"); printf("\n");
if ((flag & ANIMATION_FLAG) || (flag & TILE_FLAG)) { if ((flag & ANIMATION_FLAG) || (flag & FRAGMENTS_FLAG)) {
const int is_anim = !!(flag & ANIMATION_FLAG); const int is_anim = !!(flag & ANIMATION_FLAG);
const WebPChunkId id = is_anim ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM; 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; int nFrames;
if (is_anim) { if (is_anim) {
@ -259,7 +259,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
printf("Size of the XMP metadata: %zu\n", xmp.size); 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; WebPMuxFrameInfo image;
err = WebPMuxGetFrame(mux, 1, &image); err = WebPMuxGetFrame(mux, 1, &image);
RETURN_IF_ERROR("Failed to retrieve the image\n"); 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("Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT\n");
printf(" webpmux -set SET_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 -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(" webpmux -frame FRAME_OPTIONS [-frame...]");
printf(" -loop LOOP_COUNT -o OUTPUT\n"); printf(" -loop LOOP_COUNT -o OUTPUT\n");
printf(" webpmux -info INPUT\n"); printf(" webpmux -info INPUT\n");
@ -285,7 +285,7 @@ static void PrintHelp(void) {
printf(" icc Get ICC profile.\n"); printf(" icc Get ICC profile.\n");
printf(" exif Get EXIF metadata.\n"); printf(" exif Get EXIF metadata.\n");
printf(" xmp Get XMP 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(" frame n Get nth frame.\n");
printf("\n"); printf("\n");
@ -306,11 +306,12 @@ static void PrintHelp(void) {
printf(" xmp Strip XMP metadata.\n"); printf(" xmp Strip XMP metadata.\n");
printf("\n"); printf("\n");
printf("TILE_OPTIONS(i):\n"); printf("FRAGMENT_OPTIONS(i):\n");
printf(" Create tiled image.\n"); printf(" Create fragmented image.\n");
printf(" file_i +xi+yi\n"); printf(" file_i +xi+yi\n");
printf(" where: 'file_i' is the i'th tile (WebP format),\n"); printf(" where: 'file_i' is the i'th fragment (WebP format),\n");
printf(" 'xi','yi' specify the image offset for this tile.\n"); printf(" 'xi','yi' specify the image offset for this fragment."
"\n");
printf("\n"); printf("\n");
printf("FRAME_OPTIONS(i):\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); &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); 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[], static int ValidateCommandLine(int argc, const char* argv[],
int* num_feature_args) { int* num_feature_args) {
int num_frame_args; int num_frame_args;
int num_tile_args; int num_frgm_args;
int num_loop_args; int num_loop_args;
int ok = 1; int ok = 1;
@ -432,7 +433,7 @@ static int ValidateCommandLine(int argc, const char* argv[],
// Compound checks. // Compound checks.
num_frame_args = CountOccurrences(argv, argc, "-frame"); 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"); num_loop_args = CountOccurrences(argv, argc, "-loop");
if (num_loop_args > 1) { 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", ERROR_GOTO1("ERROR: Both frames and loop count have to be specified.\n",
ErrValidate); ErrValidate);
} }
if (num_frame_args > 0 && num_tile_args > 0) { if (num_frame_args > 0 && num_frgm_args > 0) {
ERROR_GOTO1("ERROR: Only one of frames & tiles can be specified at a time." ERROR_GOTO1("ERROR: Only one of frames & fragments can be specified at a "
"\n", ErrValidate); "time.\n", ErrValidate);
} }
assert(ok == 1); 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). // Single argument ('set' action for ICCP/EXIF/XMP, OR a 'get' action).
*num_feature_args = 1; *num_feature_args = 1;
} else { } else {
// Multiple arguments ('set' action for animation or tiling). // Multiple arguments ('set' action for animation or fragmented image).
if (num_frame_args > 0) { if (num_frame_args > 0) {
*num_feature_args = num_frame_args + num_loop_args; *num_feature_args = num_frame_args + num_loop_args;
} else { } 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 { } else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} }
if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_FRM) { if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) {
feature->type_ = FEATURE_FRM; feature->type_ = FEATURE_ANMF;
} else { } else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
} }
@ -539,8 +540,8 @@ static int ParseCommandLine(int argc, const char* argv[],
} else { } else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} }
if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_FRM) { if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) {
feature->type_ = FEATURE_FRM; feature->type_ = FEATURE_ANMF;
} else { } else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); 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]; arg->params_ = argv[i + 1];
++feature_arg_index; ++feature_arg_index;
i += 2; i += 2;
} else if (!strcmp(argv[i], "-tile")) { } else if (!strcmp(argv[i], "-frgm")) {
CHECK_NUM_ARGS_LESS(3, ErrParse); CHECK_NUM_ARGS_LESS(3, ErrParse);
if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) { if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
config->action_type_ = ACTION_SET; config->action_type_ = ACTION_SET;
} else { } else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} }
if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_TILE) { if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_FRGM) {
feature->type_ = FEATURE_TILE; feature->type_ = FEATURE_FRGM;
} else { } else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
} }
@ -607,11 +608,11 @@ static int ParseCommandLine(int argc, const char* argv[],
++i; ++i;
} }
} else if ((!strcmp(argv[i], "frame") || } else if ((!strcmp(argv[i], "frame") ||
!strcmp(argv[i], "tile")) && !strcmp(argv[i], "frgm")) &&
(config->action_type_ == ACTION_GET)) { (config->action_type_ == ACTION_GET)) {
CHECK_NUM_ARGS_LESS(2, ErrParse); CHECK_NUM_ARGS_LESS(2, ErrParse);
feature->type_ = (!strcmp(argv[i], "frame")) ? FEATURE_FRM : feature->type_ = (!strcmp(argv[i], "frame")) ? FEATURE_ANMF :
FEATURE_TILE; FEATURE_FRGM;
arg->params_ = argv[i + 1]; arg->params_ = argv[i + 1];
++feature_arg_index; ++feature_arg_index;
i += 2; i += 2;
@ -649,8 +650,8 @@ static int ValidateConfig(WebPMuxConfig* config) {
if (config->input_ == NULL) { if (config->input_ == NULL) {
if (config->action_type_ != ACTION_SET) { if (config->action_type_ != ACTION_SET) {
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2); ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
} else if (feature->type_ != FEATURE_FRM && } else if (feature->type_ != FEATURE_ANMF &&
feature->type_ != FEATURE_TILE) { feature->type_ != FEATURE_FRGM) {
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2); ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
} }
} }
@ -708,7 +709,7 @@ static int InitializeConfig(int argc, const char* argv[],
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Processing. // Processing.
static int GetFrameTile(const WebPMux* mux, static int GetFrameFragment(const WebPMux* mux,
const WebPMuxConfig* config, int isFrame) { const WebPMuxConfig* config, int isFrame) {
WebPMuxError err = WEBP_MUX_OK; WebPMuxError err = WEBP_MUX_OK;
WebPMux* mux_single = NULL; WebPMux* mux_single = NULL;
@ -720,7 +721,7 @@ static int GetFrameTile(const WebPMux* mux,
num = strtol(config->feature_.args_[0].params_, NULL, 10); num = strtol(config->feature_.args_[0].params_, NULL, 10);
if (num < 0) { 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); err = WebPMuxGetFrame(mux, num, &info);
@ -764,10 +765,10 @@ static int Process(const WebPMuxConfig* config) {
ok = CreateMux(config->input_, &mux); ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2; if (!ok) goto Err2;
switch (feature->type_) { switch (feature->type_) {
case FEATURE_FRM: case FEATURE_ANMF:
case FEATURE_TILE: case FEATURE_FRGM:
ok = GetFrameTile(mux, config, ok = GetFrameFragment(mux, config,
(feature->type_ == FEATURE_FRM) ? 1 : 0); (feature->type_ == FEATURE_ANMF) ? 1 : 0);
break; break;
case FEATURE_ICCP: case FEATURE_ICCP:
@ -789,7 +790,7 @@ static int Process(const WebPMuxConfig* config) {
case ACTION_SET: case ACTION_SET:
switch (feature->type_) { switch (feature->type_) {
case FEATURE_FRM: case FEATURE_ANMF:
mux = WebPMuxNew(); mux = WebPMuxNew();
if (mux == NULL) { if (mux == NULL) {
ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n", ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
@ -829,27 +830,28 @@ static int Process(const WebPMuxConfig* config) {
} }
break; break;
case FEATURE_TILE: case FEATURE_FRGM:
mux = WebPMuxNew(); mux = WebPMuxNew();
if (mux == NULL) { if (mux == NULL) {
ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n", ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
ErrorString(WEBP_MUX_MEMORY_ERROR), Err2); ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
} }
for (index = 0; index < feature->arg_count_; ++index) { for (index = 0; index < feature->arg_count_; ++index) {
WebPMuxFrameInfo tile; WebPMuxFrameInfo frgm;
frgm.id = WEBP_CHUNK_FRGM;
ok = ReadFileToWebPData(feature->args_[index].filename_, ok = ReadFileToWebPData(feature->args_[index].filename_,
&tile.bitstream); &frgm.bitstream);
if (!ok) goto Err2; if (!ok) goto Err2;
ok = ParseTileArgs(feature->args_[index].params_, &tile); ok = ParseFragmentArgs(feature->args_[index].params_, &frgm);
if (!ok) { if (!ok) {
WebPDataClear(&tile.bitstream); WebPDataClear(&frgm.bitstream);
ERROR_GOTO1("ERROR: Could not parse tile properties.\n", Err2); ERROR_GOTO1("ERROR: Could not parse fragment properties.\n",
Err2);
} }
tile.id = WEBP_CHUNK_FRGM; err = WebPMuxPushFrame(mux, &frgm, 1);
err = WebPMuxPushFrame(mux, &tile, 1); WebPDataClear(&frgm.bitstream);
WebPDataClear(&tile.bitstream);
if (err != WEBP_MUX_OK) { 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); ErrorString(err), index, Err2);
} }
} }

View File

@ -21,9 +21,9 @@ webpmux \- command line tool to create WebP Mux/container file.
.B \-o .B \-o
.I OUTPUT .I OUTPUT
.br .br
.B webpmux \-tile .B webpmux \-frgm
.I TILE_OPTIONS .I FRAGMENT_OPTIONS
.B [\-tile...] \-o .B [\-frgm...] \-o
.I OUTPUT .I OUTPUT
.br .br
.B webpmux \-frame .B webpmux \-frame
@ -56,8 +56,8 @@ Get EXIF metadata.
.B xmp .B xmp
Get XMP metadata. Get XMP metadata.
.TP .TP
.B tile n .B frgm n
Get nth tile. Get nth fragment.
.TP .TP
.B frame n .B frame n
Get nth frame. Get nth frame.
@ -90,11 +90,11 @@ Strip EXIF metadata.
.B xmp .B xmp
Strip XMP metadata. Strip XMP metadata.
.SS TILE_OPTIONS (\-tile) .SS FRAGMENT_OPTIONS (\-frgm)
.TP .TP
.B file_i +xi+yi .B file_i +xi+yi
Where: 'file_i' is the i'th tile (WebP format) and 'xi','yi' specify the image Where: 'file_i' is the i'th fragment (WebP format) and 'xi','yi' specify the
offset for this tile. image offset for this fragment.
.SS FRAME_OPTIONS (\-frame) .SS FRAME_OPTIONS (\-frame)
.TP .TP

View File

@ -40,8 +40,8 @@ extern "C" {
// 20..23 VP8X flags bit-map corresponding to the chunk-types present. // 20..23 VP8X flags bit-map corresponding to the chunk-types present.
// 24..26 Width of the Canvas Image. // 24..26 Width of the Canvas Image.
// 27..29 Height of the Canvas Image. // 27..29 Height of the Canvas Image.
// There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8, // There can be extra chunks after the "VP8X" chunk (ICCP, FRGM, ANMF, VP8,
// XMP, EXIF ...) // VP8L, XMP, EXIF ...)
// All sizes are in little-endian order. // All sizes are in little-endian order.
// Note: chunk data size must be padded to multiple of 2 when written. // Note: chunk data size must be padded to multiple of 2 when written.

View File

@ -39,8 +39,8 @@ typedef struct Frame {
int x_offset_, y_offset_; int x_offset_, y_offset_;
int width_, height_; int width_, height_;
int duration_; int duration_;
int is_tile_; // this is an image fragment from a tile. int is_fragment_; // this is a frame fragment (and not a full frame).
int frame_num_; // the referent frame number for use in assembling tiles. int frame_num_; // the referent frame number for use in assembling fragments.
int complete_; // img_components_ contains a full image. int complete_; // img_components_ contains a full image.
ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH
struct Frame* next_; struct Frame* next_;
@ -327,35 +327,36 @@ static ParseStatus ParseFrame(
} }
// Parse a 'FRGM' chunk and any image bearing chunks that immediately follow. // Parse a 'FRGM' chunk and any image bearing chunks that immediately follow.
// 'tile_chunk_size' is the previously validated, padded chunk size. // 'fragment_chunk_size' is the previously validated, padded chunk size.
static ParseStatus ParseTile(WebPDemuxer* const dmux, static ParseStatus ParseFragment(WebPDemuxer* const dmux,
uint32_t tile_chunk_size) { uint32_t fragment_chunk_size) {
const int has_tiles = !!(dmux->feature_flags_ & TILE_FLAG); const int has_fragments = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
const uint32_t padding = (FRGM_CHUNK_SIZE & 1); const uint32_t padding = (FRGM_CHUNK_SIZE & 1);
const uint32_t frgm_payload_size = const uint32_t frgm_payload_size =
tile_chunk_size - (FRGM_CHUNK_SIZE + padding); fragment_chunk_size - (FRGM_CHUNK_SIZE + padding);
int added_tile = 0; int added_fragment = 0;
MemBuffer* const mem = &dmux->mem_; MemBuffer* const mem = &dmux->mem_;
Frame* frame; Frame* frame;
ParseStatus status = 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; if (status != PARSE_OK) return status;
frame->is_tile_ = 1; frame->is_fragment_ = 1;
frame->x_offset_ = 2 * GetLE24s(mem); frame->x_offset_ = 2 * GetLE24s(mem);
frame->y_offset_ = 2 * GetLE24s(mem); frame->y_offset_ = 2 * GetLE24s(mem);
Skip(mem, padding); Skip(mem, padding);
// Store a tile only if the tile flag is set and all data for this tile // Store a fragment only if the fragments flag is set and all data for this
// is available. // fragment is available.
status = StoreFrame(dmux->num_frames_, frgm_payload_size, mem, frame); status = StoreFrame(dmux->num_frames_, frgm_payload_size, mem, frame);
if (status != PARSE_ERROR && has_tiles && frame->frame_num_ > 0) { if (status != PARSE_ERROR && has_fragments && frame->frame_num_ > 0) {
// Note num_frames_ is incremented only when all tiles have been consumed. // Note num_frames_ is incremented only when all fragments have been
added_tile = AddFrame(dmux, frame); // consumed.
if (!added_tile) status = PARSE_ERROR; added_fragment = AddFrame(dmux, frame);
if (!added_fragment) status = PARSE_ERROR;
} }
if (!added_tile) free(frame); if (!added_fragment) free(frame);
return status; return status;
} }
@ -513,7 +514,7 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
} }
case MKFOURCC('F', 'R', 'G', 'M'): { case MKFOURCC('F', 'R', 'G', 'M'): {
if (dmux->num_frames_ == 0) dmux->num_frames_ = 1; if (dmux->num_frames_ == 0) dmux->num_frames_ = 1;
status = ParseTile(dmux, chunk_size_padded); status = ParseFragment(dmux, chunk_size_padded);
break; break;
} }
case MKFOURCC('I', 'C', 'C', 'P'): { case MKFOURCC('I', 'C', 'C', 'P'): {
@ -571,7 +572,7 @@ static int IsValidSimpleFormat(const WebPDemuxer* const dmux) {
} }
static int IsValidExtendedFormat(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 int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG);
const Frame* f; const Frame* f;
@ -583,15 +584,15 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
for (f = dmux->frames_; f != NULL; f = f->next_) { for (f = dmux->frames_; f != NULL; f = f->next_) {
const int cur_frame_set = f->frame_num_; 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 // Check frame properties and if the image is composed of fragments that
// fragment came from a tile. // each fragment came from a fragment.
for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) { for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
const ChunkData* const image = f->img_components_; const ChunkData* const image = f->img_components_;
const ChunkData* const alpha = f->img_components_ + 1; 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 (!has_frames && f->frame_num_ > 1) return 0;
if (f->x_offset_ < 0 || f->y_offset_ < 0) return 0; if (f->x_offset_ < 0 || f->y_offset_ < 0) return 0;
if (f->complete_) { if (f->complete_) {
@ -612,11 +613,11 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
if (f->next_ != NULL) return 0; if (f->next_ != NULL) return 0;
} }
tile_count += f->is_tile_; fragment_count += f->is_fragment_;
++frame_count; ++frame_count;
} }
if (!has_tiles && frame_count > 1) return 0; if (!has_fragments && frame_count > 1) return 0;
if (tile_count > 0 && frame_count != tile_count) return 0; if (fragment_count > 0 && frame_count != fragment_count) return 0;
if (f == NULL) break; if (f == NULL) break;
} }
return 1; return 1;
@ -706,7 +707,8 @@ uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Frame iteration // 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) { static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) {
const Frame* f; const Frame* f;
for (f = dmux->frames_; f != NULL; f = f->next_) { 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; return f;
} }
// Returns tile 'tile_num' and the total count. // Returns fragment 'fragment_num' and the total count.
static const Frame* GetTile( static const Frame* GetFragment(
const Frame* const frame_set, int tile_num, int* const count) { const Frame* const frame_set, int fragment_num, int* const count) {
const int this_frame = frame_set->frame_num_; const int this_frame = frame_set->frame_num_;
const Frame* f = frame_set; const Frame* f = frame_set;
const Frame* tile = NULL; const Frame* fragment = NULL;
int total; int total;
for (total = 0; f != NULL && f->frame_num_ == this_frame; f = f->next_) { 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; *count = total;
return tile; return fragment;
} }
static const uint8_t* GetFramePayload(const uint8_t* const mem_buf, 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. // Create a whole 'frame' from VP8 (+ alpha) or lossless.
static int SynthesizeFrame(const WebPDemuxer* const dmux, static int SynthesizeFrame(const WebPDemuxer* const dmux,
const Frame* const first_frame, 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_; const uint8_t* const mem_buf = dmux->mem_.buf_;
int num_tiles; int num_fragments;
size_t payload_size = 0; size_t payload_size = 0;
const Frame* const tile = GetTile(first_frame, tile_num, &num_tiles); const Frame* const fragment =
const uint8_t* const payload = GetFramePayload(mem_buf, tile, &payload_size); GetFragment(first_frame, fragment_num, &num_fragments);
const uint8_t* const payload =
GetFramePayload(mem_buf, fragment, &payload_size);
if (payload == NULL) return 0; if (payload == NULL) return 0;
iter->frame_num = first_frame->frame_num_; iter->frame_num = first_frame->frame_num_;
iter->num_frames = dmux->num_frames_; iter->num_frames = dmux->num_frames_;
iter->tile_num = tile_num; iter->fragment_num = fragment_num;
iter->num_tiles = num_tiles; iter->num_fragments = num_fragments;
iter->x_offset = tile->x_offset_; iter->x_offset = fragment->x_offset_;
iter->y_offset = tile->y_offset_; iter->y_offset = fragment->y_offset_;
iter->width = tile->width_; iter->width = fragment->width_;
iter->height = tile->height_; iter->height = fragment->height_;
iter->duration = tile->duration_; iter->duration = fragment->duration_;
iter->complete = tile->complete_; iter->complete = fragment->complete_;
iter->tile.bytes = payload; iter->fragment.bytes = payload;
iter->tile.size = payload_size; iter->fragment.size = payload_size;
// TODO(jzern): adjust offsets for 'FRGM's embedded in 'ANMF's // TODO(jzern): adjust offsets for 'FRGM's embedded in 'ANMF's
return 1; return 1;
} }
@ -811,13 +815,13 @@ int WebPDemuxPrevFrame(WebPIterator* iter) {
return SetFrame(iter->frame_num - 1, iter); return SetFrame(iter->frame_num - 1, iter);
} }
int WebPDemuxSelectTile(WebPIterator* iter, int tile) { int WebPDemuxSelectFragment(WebPIterator* iter, int fragment_num) {
if (iter != NULL && iter->private_ != NULL && tile > 0) { if (iter != NULL && iter->private_ != NULL && fragment_num > 0) {
const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_;
const Frame* const frame = GetFrame(dmux, iter->frame_num); const Frame* const frame = GetFrame(dmux, iter->frame_num);
if (frame == NULL) return 0; if (frame == NULL) return 0;
return SynthesizeFrame(dmux, frame, tile, iter); return SynthesizeFrame(dmux, frame, fragment_num, iter);
} }
return 0; return 0;
} }

View File

@ -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. // Create data for frame/tile given image data, offsets and duration.
static WebPMuxError CreateFrameTileData(const WebPData* const image, static WebPMuxError CreateFrameFragmentData(const WebPData* const image,
int x_offset, int y_offset, int x_offset, int y_offset,
int duration, int is_lossless, int duration, int is_lossless,
int is_frame, int is_frame,
WebPData* const frame_tile) { WebPData* const frame_frgm) {
int width; int width;
int height; int height;
uint8_t* frame_tile_bytes; uint8_t* frame_frgm_bytes;
const size_t frame_tile_size = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].size; const size_t frame_frgm_size = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].size;
const int ok = is_lossless ? const int ok = is_lossless ?
VP8LGetInfo(image->bytes, image->size, &width, &height, NULL) : 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); assert(width > 0 && height > 0 && duration > 0);
// Note: assertion on upper bounds is done in PutLE24(). // Note: assertion on upper bounds is done in PutLE24().
frame_tile_bytes = (uint8_t*)malloc(frame_tile_size); frame_frgm_bytes = (uint8_t*)malloc(frame_frgm_size);
if (frame_tile_bytes == NULL) return WEBP_MUX_MEMORY_ERROR; if (frame_frgm_bytes == NULL) return WEBP_MUX_MEMORY_ERROR;
PutLE24(frame_tile_bytes + 0, x_offset / 2); PutLE24(frame_frgm_bytes + 0, x_offset / 2);
PutLE24(frame_tile_bytes + 3, y_offset / 2); PutLE24(frame_frgm_bytes + 3, y_offset / 2);
if (is_frame) { if (is_frame) {
PutLE24(frame_tile_bytes + 6, width - 1); PutLE24(frame_frgm_bytes + 6, width - 1);
PutLE24(frame_tile_bytes + 9, height - 1); PutLE24(frame_frgm_bytes + 9, height - 1);
PutLE24(frame_tile_bytes + 12, duration - 1); PutLE24(frame_frgm_bytes + 12, duration - 1);
} }
frame_tile->bytes = frame_tile_bytes; frame_frgm->bytes = frame_frgm_bytes;
frame_tile->size = frame_tile_size; frame_frgm->size = frame_frgm_size;
return WEBP_MUX_OK; 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 y_offset = frame->y_offset & ~1;
const int duration = is_frame ? frame->duration : 1 /* unused */; const int duration = is_frame ? frame->duration : 1 /* unused */;
const uint32_t tag = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].tag; 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 || if (x_offset < 0 || x_offset >= MAX_POSITION_OFFSET ||
y_offset < 0 || y_offset >= MAX_POSITION_OFFSET || y_offset < 0 || y_offset >= MAX_POSITION_OFFSET ||
(duration <= 0 || duration > MAX_DURATION)) { (duration <= 0 || duration > MAX_DURATION)) {
err = WEBP_MUX_INVALID_ARGUMENT; err = WEBP_MUX_INVALID_ARGUMENT;
goto Err; goto Err;
} }
err = CreateFrameTileData(&wpi.img_->data_, x_offset, y_offset, duration, err = CreateFrameFragmentData(&wpi.img_->data_, x_offset, y_offset,
is_lossless, is_frame, &frame_tile); duration, is_lossless, is_frame, &frame_frgm);
if (err != WEBP_MUX_OK) goto Err; if (err != WEBP_MUX_OK) goto Err;
// Add frame/tile chunk (with copy_data = 1). // Add frame/fragment chunk (with copy_data = 1).
err = AddDataToChunkList(&frame_tile, 1, tag, &wpi.header_); err = AddDataToChunkList(&frame_frgm, 1, tag, &wpi.header_);
WebPDataClear(&frame_tile); // frame_tile owned by wpi.header_ now. WebPDataClear(&frame_frgm); // frame_frgm owned by wpi.header_ now.
if (err != WEBP_MUX_OK) goto Err; if (err != WEBP_MUX_OK) goto Err;
} }
@ -394,15 +394,15 @@ WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Assembly of the WebP RIFF file. // Assembly of the WebP RIFF file.
static WebPMuxError GetFrameTileInfo(const WebPChunk* const frame_tile_chunk, static WebPMuxError GetFrameFragmentInfo(
int* const x_offset, int* const y_offset, const WebPChunk* const frame_frgm_chunk,
int* const duration) { int* const x_offset, int* const y_offset, int* const duration) {
const uint32_t tag = frame_tile_chunk->tag_; const uint32_t tag = frame_frgm_chunk->tag_;
const int is_frame = (tag == kChunks[IDX_ANMF].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 = const size_t expected_data_size =
is_frame ? ANMF_CHUNK_SIZE : FRGM_CHUNK_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); assert(tag == kChunks[IDX_ANMF].tag || tag == kChunks[IDX_FRGM].tag);
if (data->size != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT; 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 duration,
int* const width, int* const height) { int* const width, int* const height) {
const WebPChunk* const image_chunk = wpi->img_; 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. // Get offsets and duration from ANMF/FRGM chunk.
const WebPMuxError err = 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; if (err != WEBP_MUX_OK) return err;
// Get width and height from VP8/VP8L chunk. // Get width and height from VP8/VP8L chunk.
@ -463,7 +463,7 @@ static WebPMuxError GetImageCanvasWidthHeight(
int max_x = 0; int max_x = 0;
int max_y = 0; int max_y = 0;
int64_t image_area = 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_) { for (; wpi != NULL; wpi = wpi->next_) {
int x_offset, y_offset, duration, w, h; int x_offset, y_offset, duration, w, h;
const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset, const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset,
@ -480,11 +480,11 @@ static WebPMuxError GetImageCanvasWidthHeight(
} }
*width = max_x; *width = max_x;
*height = max_y; *height = max_y;
// Crude check to validate that there are no image overlaps/holes for tile // Crude check to validate that there are no image overlaps/holes for
// images. Check that the aggregated image area for individual tiles exactly // fragmented images. Check that the aggregated image area for individual
// matches the image area of the constructed canvas. However, the area-match // fragments exactly matches the image area of the constructed canvas.
// is necessary but not sufficient condition. // However, the area-match is necessary but not sufficient condition.
if ((flags & TILE_FLAG) && (image_area != (max_x * max_y))) { if ((flags & FRAGMENTS_FLAG) && (image_area != (max_x * max_y))) {
*width = 0; *width = 0;
*height = 0; *height = 0;
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
@ -539,8 +539,8 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
} }
if (images->header_ != NULL) { if (images->header_ != NULL) {
if (images->header_->tag_ == kChunks[IDX_FRGM].tag) { if (images->header_->tag_ == kChunks[IDX_FRGM].tag) {
// This is a tiled image. // This is a fragmented image.
flags |= TILE_FLAG; flags |= FRAGMENTS_FLAG;
} else if (images->header_->tag_ == kChunks[IDX_ANMF].tag) { } else if (images->header_->tag_ == kChunks[IDX_ANMF].tag) {
// This is an image with animation. // This is an image with animation.
flags |= ANIMATION_FLAG; flags |= ANIMATION_FLAG;

View File

@ -476,16 +476,16 @@ WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) {
WebPMuxError MuxValidateForImage(const WebPMux* const mux) { WebPMuxError MuxValidateForImage(const WebPMux* const mux) {
const int num_images = MuxImageCount(mux->images_, WEBP_CHUNK_IMAGE); const int num_images = MuxImageCount(mux->images_, WEBP_CHUNK_IMAGE);
const int num_frames = MuxImageCount(mux->images_, WEBP_CHUNK_ANMF); 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) { if (num_images == 0) {
// No images in mux. // No images in mux.
return WEBP_MUX_NOT_FOUND; 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). // Valid case (single image).
return WEBP_MUX_OK; return WEBP_MUX_OK;
} else { } else {
// Frame/Tile case OR an invalid mux. // Frame/Fragment case OR an invalid mux.
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
} }
@ -520,7 +520,7 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
int num_xmp; int num_xmp;
int num_loop_chunks; int num_loop_chunks;
int num_frames; int num_frames;
int num_tiles; int num_fragments;
int num_vp8x; int num_vp8x;
int num_images; int num_images;
int num_alpha; int num_alpha;
@ -565,8 +565,8 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
} }
} }
// Tiling: TILE_FLAG and tile chunk(s) are consistent. // Fragmentation: FRAGMENTS_FLAG and FRGM chunk(s) are consistent.
err = ValidateChunk(mux, IDX_FRGM, TILE_FLAG, flags, -1, &num_tiles); err = ValidateChunk(mux, IDX_FRGM, FRAGMENTS_FLAG, flags, -1, &num_fragments);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) return err;
// Verify either VP8X chunk is present OR there is only one elem in // 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; if (err != WEBP_MUX_OK) return err;
} }
// num_tiles & num_images are consistent. // num_fragments & num_images are consistent.
if (num_tiles > 0 && num_images != num_tiles) { if (num_fragments > 0 && num_images != num_fragments) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }

View File

@ -364,19 +364,19 @@ static WebPMuxError MuxGetImageInternal(const WebPMuxImage* const wpi,
return SynthesizeBitstream(wpi, &info->bitstream); return SynthesizeBitstream(wpi, &info->bitstream);
} }
static WebPMuxError MuxGetFrameTileInternal(const WebPMuxImage* const wpi, static WebPMuxError MuxGetFrameFragmentInternal(const WebPMuxImage* const wpi,
WebPMuxFrameInfo* const frame) { WebPMuxFrameInfo* const frame) {
const int is_frame = (wpi->header_->tag_ == kChunks[IDX_ANMF].tag); const int is_frame = (wpi->header_->tag_ == kChunks[IDX_ANMF].tag);
const CHUNK_INDEX idx = is_frame ? IDX_ANMF : IDX_FRGM; 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(). assert(wpi->header_ != NULL); // Already checked by WebPMuxGetFrame().
// Get frame/tile chunk. // Get frame/fragment chunk.
frame_tile_data = &wpi->header_->data_; frame_frgm_data = &wpi->header_->data_;
if (frame_tile_data->size < kChunks[idx].size) return WEBP_MUX_BAD_DATA; if (frame_frgm_data->size < kChunks[idx].size) return WEBP_MUX_BAD_DATA;
// Extract info. // Extract info.
frame->x_offset = 2 * GetLE24(frame_tile_data->bytes + 0); frame->x_offset = 2 * GetLE24(frame_frgm_data->bytes + 0);
frame->y_offset = 2 * GetLE24(frame_tile_data->bytes + 3); frame->y_offset = 2 * GetLE24(frame_frgm_data->bytes + 3);
frame->duration = is_frame ? 1 + GetLE24(frame_tile_data->bytes + 12) : 1; frame->duration = is_frame ? 1 + GetLE24(frame_frgm_data->bytes + 12) : 1;
frame->id = ChunkGetIdFromTag(wpi->header_->tag_); frame->id = ChunkGetIdFromTag(wpi->header_->tag_);
return SynthesizeBitstream(wpi, &frame->bitstream); return SynthesizeBitstream(wpi, &frame->bitstream);
} }
@ -399,7 +399,7 @@ WebPMuxError WebPMuxGetFrame(
if (wpi->header_ == NULL) { if (wpi->header_ == NULL) {
return MuxGetImageInternal(wpi, frame); return MuxGetImageInternal(wpi, frame);
} else { } else {
return MuxGetFrameTileInternal(wpi, frame); return MuxGetFrameFragmentInternal(wpi, frame);
} }
} }

View File

@ -83,7 +83,7 @@ typedef enum {
#define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height. #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_LOOP_COUNT (1 << 16) // maximum value for loop-count
#define MAX_DURATION (1 << 24) // maximum duration #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 // Maximum chunk payload is such that adding the header and padding won't
// overflow a uint32_t. // overflow a uint32_t.

View File

@ -11,7 +11,7 @@
// Vikas (vikasa@google.com) // Vikas (vikasa@google.com)
// This API allows manipulation of WebP container images containing features // 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 // Code Example#1: Creating a MUX with image data, color profile and XMP
// metadata. // metadata.
@ -82,7 +82,7 @@ enum WebPMuxError {
// Flag values for different features used in VP8X chunk. // Flag values for different features used in VP8X chunk.
enum WebPFeatureFlags { enum WebPFeatureFlags {
TILE_FLAG = 0x00000001, FRAGMENTS_FLAG = 0x00000001,
ANIMATION_FLAG = 0x00000002, ANIMATION_FLAG = 0x00000002,
XMP_FLAG = 0x00000004, XMP_FLAG = 0x00000004,
EXIF_FLAG = 0x00000008, EXIF_FLAG = 0x00000008,
@ -233,12 +233,12 @@ struct WebPMuxFrameInfo {
uint32_t pad[3]; // padding for later use uint32_t pad[3]; // padding for later use
}; };
// Sets the (non-animated and non-tiled) image in the mux object. // Sets the (non-animated and non-fragmented) image in the mux object.
// Note: Any existing images (including frames/tiles) will be removed. // Note: Any existing images (including frames/fragments) will be removed.
// Parameters: // Parameters:
// mux - (in/out) object in which the image is to be set // 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 // 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 // copy_data - (in) value 1 indicates given data WILL be copied to the mux
// and value 0 indicates data will NOT be copied. // and value 0 indicates data will NOT be copied.
// Returns: // Returns:
@ -250,8 +250,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(
// Adds a frame at the end of the mux object. // 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 // 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() // (2) For setting a non-animated non-fragmented image, use
// instead. // WebPMuxSetImage() instead.
// (3) Type of frame being pushed must be same as the frames in mux. // (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 // (4) As WebP only supports even offsets, any odd offset will be snapped
// to an even location using: offset &= ~1 // to an even location using: offset &= ~1
@ -428,22 +428,23 @@ WEBP_EXTERN(uint32_t) WebPDemuxGetI(
struct WebPIterator { struct WebPIterator {
int frame_num; int frame_num;
int num_frames; int num_frames;
int tile_num; int fragment_num;
int num_tiles; int num_fragments;
int x_offset, y_offset; // offset relative to the canvas. 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 duration; // display duration in milliseconds.
int complete; // true if 'tile_' contains a full frame. partial images may int complete; // true if 'fragment' contains a full frame. partial images
// still be decoded with the WebP incremental decoder. // may still be decoded with the WebP incremental decoder.
WebPData tile; // The frame or tile given by 'frame_num_' and 'tile_num_'. WebPData fragment; // The frame or fragment given by 'frame_num' and
// 'fragment_num'.
uint32_t pad[4]; // padding for later use uint32_t pad[4]; // padding for later use
void* private_; // for internal use only. void* private_; // for internal use only.
}; };
// Retrieves frame 'frame_number' from 'dmux'. // Retrieves frame 'frame_number' from 'dmux'.
// 'iter->tile_' points to the first tile on return from this function. // 'iter->fragment' points to the first fragment on return from this function.
// Individual tiles may be extracted using WebPDemuxSetTile(). // Individual fragments may be extracted using WebPDemuxSetFragment().
// Setting 'frame_number' equal to 0 will return the last frame of the image. // 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. // Returns false if 'dmux' is NULL or frame 'frame_number' is not present.
// Call WebPDemuxReleaseIterator() when use of the iterator is complete. // Call WebPDemuxReleaseIterator() when use of the iterator is complete.
@ -451,14 +452,14 @@ struct WebPIterator {
WEBP_EXTERN(int) WebPDemuxGetFrame( WEBP_EXTERN(int) WebPDemuxGetFrame(
const WebPDemuxer* dmux, int frame_number, WebPIterator* iter); const WebPDemuxer* dmux, int frame_number, WebPIterator* iter);
// Sets 'iter->tile_' to point to the next ('iter->frame_num_' + 1) or previous // Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or
// ('iter->frame_num_' - 1) frame. These functions do not loop. // previous ('iter->frame_num' - 1) frame. These functions do not loop.
// Returns true on success, false otherwise. // Returns true on success, false otherwise.
WEBP_EXTERN(int) WebPDemuxNextFrame(WebPIterator* iter); WEBP_EXTERN(int) WebPDemuxNextFrame(WebPIterator* iter);
WEBP_EXTERN(int) WebPDemuxPrevFrame(WebPIterator* iter); WEBP_EXTERN(int) WebPDemuxPrevFrame(WebPIterator* iter);
// Sets 'iter->tile_' to reflect tile number 'tile_number'. // Sets 'iter->fragment' to reflect fragment number 'fragment_num'.
// Returns true if tile 'tile_number' is present, false otherwise. // Returns true if fragment 'fragment_num' is present, false otherwise.
WEBP_EXTERN(int) WebPDemuxSelectTile(WebPIterator* iter, int tile_number); WEBP_EXTERN(int) WebPDemuxSelectTile(WebPIterator* iter, int tile_number);
// Releases any memory associated with 'iter'. // Releases any memory associated with 'iter'.
@ -493,8 +494,8 @@ WEBP_EXTERN(int) WebPDemuxGetChunk(const WebPDemuxer* dmux,
const char fourcc[4], int chunk_number, const char fourcc[4], int chunk_number,
WebPChunkIterator* iter); WebPChunkIterator* iter);
// Sets 'iter->chunk_' to point to the next ('iter->chunk_num_' + 1) or previous // Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous
// ('iter->chunk_num_' - 1) chunk. These functions do not loop. // ('iter->chunk_num' - 1) chunk. These functions do not loop.
// Returns true on success, false otherwise. // Returns true on success, false otherwise.
WEBP_EXTERN(int) WebPDemuxNextChunk(WebPChunkIterator* iter); WEBP_EXTERN(int) WebPDemuxNextChunk(WebPChunkIterator* iter);
WEBP_EXTERN(int) WebPDemuxPrevChunk(WebPChunkIterator* iter); WEBP_EXTERN(int) WebPDemuxPrevChunk(WebPChunkIterator* iter);