mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 12:28:26 +01:00
Merge "remove mention of fragment, frgm, FRGM, etc."
This commit is contained in:
commit
6029c7fe68
@ -488,10 +488,6 @@ int main(int argc, char *argv[]) {
|
|||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & FRAGMENTS_FLAG) {
|
|
||||||
fprintf(stderr, "Image fragments are not supported for now!\n");
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
kParams.canvas_width = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_WIDTH);
|
kParams.canvas_width = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_WIDTH);
|
||||||
kParams.canvas_height = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_HEIGHT);
|
kParams.canvas_height = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_HEIGHT);
|
||||||
if (kParams.print_info) {
|
if (kParams.print_info) {
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
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 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
|
||||||
@ -89,17 +88,16 @@ typedef enum {
|
|||||||
FEATURE_XMP,
|
FEATURE_XMP,
|
||||||
FEATURE_ICCP,
|
FEATURE_ICCP,
|
||||||
FEATURE_ANMF,
|
FEATURE_ANMF,
|
||||||
FEATURE_FRGM,
|
|
||||||
LAST_FEATURE
|
LAST_FEATURE
|
||||||
} FeatureType;
|
} FeatureType;
|
||||||
|
|
||||||
static const char* const kFourccList[LAST_FEATURE] = {
|
static const char* const kFourccList[LAST_FEATURE] = {
|
||||||
NULL, "EXIF", "XMP ", "ICCP", "ANMF", "FRGM"
|
NULL, "EXIF", "XMP ", "ICCP", "ANMF"
|
||||||
};
|
};
|
||||||
|
|
||||||
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", "Image fragment"
|
"Animation frame"
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -183,7 +181,6 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
|||||||
printf("Canvas size: %d x %d\n", width, height);
|
printf("Canvas size: %d x %d\n", width, height);
|
||||||
|
|
||||||
err = WebPMuxGetFeatures(mux, &flag);
|
err = WebPMuxGetFeatures(mux, &flag);
|
||||||
if (flag & FRAGMENTS_FLAG) err = WEBP_MUX_INVALID_ARGUMENT;
|
|
||||||
RETURN_IF_ERROR("Failed to retrieve features\n");
|
RETURN_IF_ERROR("Failed to retrieve features\n");
|
||||||
|
|
||||||
if (flag == 0) {
|
if (flag == 0) {
|
||||||
@ -194,26 +191,22 @@ 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 & 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 & FRAGMENTS_FLAG)) {
|
if (flag & ANIMATION_FLAG) {
|
||||||
const int is_anim = !!(flag & ANIMATION_FLAG);
|
const WebPChunkId id = WEBP_CHUNK_ANMF;
|
||||||
const WebPChunkId id = is_anim ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
|
const char* const type_str = "frame";
|
||||||
const char* const type_str = is_anim ? "frame" : "fragment";
|
|
||||||
int nFrames;
|
int nFrames;
|
||||||
|
|
||||||
if (is_anim) {
|
|
||||||
WebPMuxAnimParams params;
|
WebPMuxAnimParams params;
|
||||||
err = WebPMuxGetAnimationParams(mux, ¶ms);
|
err = WebPMuxGetAnimationParams(mux, ¶ms);
|
||||||
assert(err == WEBP_MUX_OK);
|
assert(err == WEBP_MUX_OK);
|
||||||
printf("Background color : 0x%.8X Loop Count : %d\n",
|
printf("Background color : 0x%.8X Loop Count : %d\n",
|
||||||
params.bgcolor, params.loop_count);
|
params.bgcolor, params.loop_count);
|
||||||
}
|
|
||||||
|
|
||||||
err = WebPMuxNumChunks(mux, id, &nFrames);
|
err = WebPMuxNumChunks(mux, id, &nFrames);
|
||||||
assert(err == WEBP_MUX_OK);
|
assert(err == WEBP_MUX_OK);
|
||||||
@ -222,7 +215,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
|||||||
if (nFrames > 0) {
|
if (nFrames > 0) {
|
||||||
int i;
|
int i;
|
||||||
printf("No.: width height alpha x_offset y_offset ");
|
printf("No.: width height alpha x_offset y_offset ");
|
||||||
if (is_anim) printf("duration dispose blend ");
|
printf("duration dispose blend ");
|
||||||
printf("image_size compression\n");
|
printf("image_size compression\n");
|
||||||
for (i = 1; i <= nFrames; i++) {
|
for (i = 1; i <= nFrames; i++) {
|
||||||
WebPMuxFrameInfo frame;
|
WebPMuxFrameInfo frame;
|
||||||
@ -236,7 +229,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
|||||||
printf("%3d: %5d %5d %5s %8d %8d ", i, features.width,
|
printf("%3d: %5d %5d %5s %8d %8d ", i, features.width,
|
||||||
features.height, features.has_alpha ? "yes" : "no",
|
features.height, features.has_alpha ? "yes" : "no",
|
||||||
frame.x_offset, frame.y_offset);
|
frame.x_offset, frame.y_offset);
|
||||||
if (is_anim) {
|
{
|
||||||
const char* const dispose =
|
const char* const dispose =
|
||||||
(frame.dispose_method == WEBP_MUX_DISPOSE_NONE) ? "none"
|
(frame.dispose_method == WEBP_MUX_DISPOSE_NONE) ? "none"
|
||||||
: "background";
|
: "background";
|
||||||
@ -276,7 +269,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
|||||||
printf("Size of the XMP metadata: %d\n", (int)xmp.size);
|
printf("Size of the XMP metadata: %d\n", (int)xmp.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | FRAGMENTS_FLAG))) {
|
if ((flag & ALPHA_FLAG) && !(flag & ANIMATION_FLAG)) {
|
||||||
WebPMuxFrameInfo image;
|
WebPMuxFrameInfo image;
|
||||||
err = WebPMuxGetFrame(mux, 1, &image);
|
err = WebPMuxGetFrame(mux, 1, &image);
|
||||||
if (err == WEBP_MUX_OK) {
|
if (err == WEBP_MUX_OK) {
|
||||||
@ -453,13 +446,6 @@ static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ParseFragmentArgs(const char* args, WebPMuxFrameInfo* const info) {
|
|
||||||
const int ok =
|
|
||||||
(sscanf(args, "+%d+%d", &info->x_offset, &info->y_offset) == 2);
|
|
||||||
if (ok) WarnAboutOddOffset(info);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) {
|
static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) {
|
||||||
uint32_t a, r, g, b;
|
uint32_t a, r, g, b;
|
||||||
if (sscanf(args, "%u,%u,%u,%u", &a, &r, &g, &b) != 4) return 0;
|
if (sscanf(args, "%u,%u,%u,%u", &a, &r, &g, &b) != 4) return 0;
|
||||||
@ -488,7 +474,6 @@ 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_frgm_args;
|
|
||||||
int num_loop_args;
|
int num_loop_args;
|
||||||
int num_bgcolor_args;
|
int num_bgcolor_args;
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
@ -515,7 +500,6 @@ 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_frgm_args = CountOccurrences(argv, argc, "-frgm");
|
|
||||||
num_loop_args = CountOccurrences(argv, argc, "-loop");
|
num_loop_args = CountOccurrences(argv, argc, "-loop");
|
||||||
num_bgcolor_args = CountOccurrences(argv, argc, "-bgcolor");
|
num_bgcolor_args = CountOccurrences(argv, argc, "-bgcolor");
|
||||||
|
|
||||||
@ -530,22 +514,14 @@ static int ValidateCommandLine(int argc, const char* argv[],
|
|||||||
ERROR_GOTO1("ERROR: Loop count and background color are relevant only in "
|
ERROR_GOTO1("ERROR: Loop count and background color are relevant only in "
|
||||||
"case of animation.\n", ErrValidate);
|
"case of animation.\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);
|
assert(ok == 1);
|
||||||
if (num_frame_args == 0 && num_frgm_args == 0) {
|
if (num_frame_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 fragmented image).
|
// Multiple arguments ('set' action for animation)
|
||||||
if (num_frame_args > 0) {
|
|
||||||
*num_feature_args = num_frame_args + num_loop_args + num_bgcolor_args;
|
*num_feature_args = num_frame_args + num_loop_args + num_bgcolor_args;
|
||||||
} else {
|
|
||||||
*num_feature_args = num_frgm_args;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrValidate:
|
ErrValidate:
|
||||||
@ -698,8 +674,7 @@ static int ParseCommandLine(int argc, const char* argv[],
|
|||||||
} else if (!strcmp(argv[i], "frame") &&
|
} else if (!strcmp(argv[i], "frame") &&
|
||||||
(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_ANMF :
|
feature->type_ = FEATURE_ANMF;
|
||||||
FEATURE_FRGM;
|
|
||||||
arg->params_ = argv[i + 1];
|
arg->params_ = argv[i + 1];
|
||||||
++feature_arg_index;
|
++feature_arg_index;
|
||||||
i += 2;
|
i += 2;
|
||||||
@ -737,8 +712,7 @@ 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_ANMF &&
|
} else if (feature->type_ != FEATURE_ANMF) {
|
||||||
feature->type_ != FEATURE_FRGM) {
|
|
||||||
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
|
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -790,14 +764,13 @@ static int InitializeConfig(int argc, const char* argv[],
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Processing.
|
// Processing.
|
||||||
|
|
||||||
static int GetFrameFragment(const WebPMux* mux,
|
static int GetFrame(const WebPMux* mux, const WebPMuxConfig* config) {
|
||||||
const WebPMuxConfig* config, int is_frame) {
|
|
||||||
WebPMuxError err = WEBP_MUX_OK;
|
WebPMuxError err = WEBP_MUX_OK;
|
||||||
WebPMux* mux_single = NULL;
|
WebPMux* mux_single = NULL;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
int parse_error = 0;
|
int parse_error = 0;
|
||||||
const WebPChunkId id = is_frame ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
|
const WebPChunkId id = WEBP_CHUNK_ANMF;
|
||||||
WebPMuxFrameInfo info;
|
WebPMuxFrameInfo info;
|
||||||
WebPDataInit(&info.bitstream);
|
WebPDataInit(&info.bitstream);
|
||||||
|
|
||||||
@ -848,9 +821,7 @@ static int Process(const WebPMuxConfig* config) {
|
|||||||
if (!ok) goto Err2;
|
if (!ok) goto Err2;
|
||||||
switch (feature->type_) {
|
switch (feature->type_) {
|
||||||
case FEATURE_ANMF:
|
case FEATURE_ANMF:
|
||||||
case FEATURE_FRGM:
|
ok = GetFrame(mux, config);
|
||||||
ok = GetFrameFragment(mux, config,
|
|
||||||
(feature->type_ == FEATURE_ANMF) ? 1 : 0);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FEATURE_ICCP:
|
case FEATURE_ICCP:
|
||||||
@ -942,35 +913,6 @@ static int Process(const WebPMuxConfig* config) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FEATURE_FRGM: {
|
|
||||||
int i;
|
|
||||||
mux = WebPMuxNew();
|
|
||||||
if (mux == NULL) {
|
|
||||||
ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
|
|
||||||
ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
|
|
||||||
}
|
|
||||||
for (i = 0; i < feature->arg_count_; ++i) {
|
|
||||||
WebPMuxFrameInfo frgm;
|
|
||||||
frgm.id = WEBP_CHUNK_FRGM;
|
|
||||||
ok = ReadFileToWebPData(feature->args_[i].filename_,
|
|
||||||
&frgm.bitstream);
|
|
||||||
if (!ok) goto Err2;
|
|
||||||
ok = ParseFragmentArgs(feature->args_[i].params_, &frgm);
|
|
||||||
if (!ok) {
|
|
||||||
WebPDataClear(&frgm.bitstream);
|
|
||||||
ERROR_GOTO1("ERROR: Could not parse fragment properties.\n",
|
|
||||||
Err2);
|
|
||||||
}
|
|
||||||
err = WebPMuxPushFrame(mux, &frgm, 1);
|
|
||||||
WebPDataClear(&frgm.bitstream);
|
|
||||||
if (err != WEBP_MUX_OK) {
|
|
||||||
ERROR_GOTO3("ERROR (%s): Could not add a fragment at index %d.\n",
|
|
||||||
ErrorString(err), i, Err2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case FEATURE_ICCP:
|
case FEATURE_ICCP:
|
||||||
case FEATURE_EXIF:
|
case FEATURE_EXIF:
|
||||||
case FEATURE_XMP: {
|
case FEATURE_XMP: {
|
||||||
|
@ -39,8 +39,8 @@
|
|||||||
// 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, FRGM, ANMF, VP8,
|
// There can be extra chunks after the "VP8X" chunk (ICCP, ANMF, VP8, VP8L,
|
||||||
// VP8L, XMP, EXIF ...)
|
// 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.
|
||||||
|
|
||||||
@ -289,7 +289,6 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
|
|||||||
int found_riff = 0;
|
int found_riff = 0;
|
||||||
int found_vp8x = 0;
|
int found_vp8x = 0;
|
||||||
int animation_present = 0;
|
int animation_present = 0;
|
||||||
int fragments_present = 0;
|
|
||||||
const int have_all_data = (headers != NULL) ? headers->have_all_data : 0;
|
const int have_all_data = (headers != NULL) ? headers->have_all_data : 0;
|
||||||
|
|
||||||
VP8StatusCode status;
|
VP8StatusCode status;
|
||||||
@ -318,7 +317,6 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
|
|||||||
return status; // Wrong VP8X / insufficient data.
|
return status; // Wrong VP8X / insufficient data.
|
||||||
}
|
}
|
||||||
animation_present = !!(flags & ANIMATION_FLAG);
|
animation_present = !!(flags & ANIMATION_FLAG);
|
||||||
fragments_present = !!(flags & FRAGMENTS_FLAG);
|
|
||||||
if (!found_riff && found_vp8x) {
|
if (!found_riff && found_vp8x) {
|
||||||
// Note: This restriction may be removed in the future, if it becomes
|
// Note: This restriction may be removed in the future, if it becomes
|
||||||
// necessary to send VP8X chunk to the decoder.
|
// necessary to send VP8X chunk to the decoder.
|
||||||
@ -330,8 +328,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
|
|||||||
|
|
||||||
image_width = canvas_width;
|
image_width = canvas_width;
|
||||||
image_height = canvas_height;
|
image_height = canvas_height;
|
||||||
if (found_vp8x && (animation_present || fragments_present) &&
|
if (found_vp8x && animation_present && headers == NULL) {
|
||||||
headers == NULL) {
|
|
||||||
status = VP8_STATUS_OK;
|
status = VP8_STATUS_OK;
|
||||||
goto ReturnWidthHeight; // Just return features from VP8X header.
|
goto ReturnWidthHeight; // Just return features from VP8X header.
|
||||||
}
|
}
|
||||||
@ -362,7 +359,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
|
|||||||
return VP8_STATUS_BITSTREAM_ERROR;
|
return VP8_STATUS_BITSTREAM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format != NULL && !(animation_present || fragments_present)) {
|
if (format != NULL && !animation_present) {
|
||||||
*format = hdrs.is_lossless ? 2 : 1;
|
*format = hdrs.is_lossless ? 2 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,7 +590,6 @@ static int CheckFrameBounds(const Frame* const frame, int exact,
|
|||||||
|
|
||||||
static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
||||||
const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
|
const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
|
||||||
const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
|
|
||||||
const Frame* f = dmux->frames_;
|
const Frame* f = dmux->frames_;
|
||||||
|
|
||||||
if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
|
if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
|
||||||
@ -598,7 +597,7 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
|||||||
if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
|
if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
|
||||||
if (dmux->loop_count_ < 0) return 0;
|
if (dmux->loop_count_ < 0) return 0;
|
||||||
if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
|
if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
|
||||||
if (is_fragmented) return 0;
|
if (dmux->feature_flags_ & ~ALL_VALID_FLAGS) return 0; // invalid bitstream
|
||||||
|
|
||||||
while (f != NULL) {
|
while (f != NULL) {
|
||||||
const int cur_frame_set = f->frame_num_;
|
const int cur_frame_set = f->frame_num_;
|
||||||
|
@ -93,34 +93,32 @@ static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag, uint32_t nth,
|
|||||||
}
|
}
|
||||||
#undef SWITCH_ID_LIST
|
#undef SWITCH_ID_LIST
|
||||||
|
|
||||||
// Create data for frame/fragment given image data, offsets and duration.
|
// Create data for frame given image data, offsets and duration.
|
||||||
static WebPMuxError CreateFrameFragmentData(
|
static WebPMuxError CreateFrameData(
|
||||||
int width, int height, const WebPMuxFrameInfo* const info, int is_frame,
|
int width, int height, const WebPMuxFrameInfo* const info,
|
||||||
WebPData* const frame_frgm) {
|
WebPData* const frame) {
|
||||||
uint8_t* frame_frgm_bytes;
|
uint8_t* frame_bytes;
|
||||||
const size_t frame_frgm_size = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].size;
|
const size_t frame_size = kChunks[IDX_ANMF].size;
|
||||||
|
|
||||||
assert(width > 0 && height > 0 && info->duration >= 0);
|
assert(width > 0 && height > 0 && info->duration >= 0);
|
||||||
assert(info->dispose_method == (info->dispose_method & 1));
|
assert(info->dispose_method == (info->dispose_method & 1));
|
||||||
// Note: assertion on upper bounds is done in PutLE24().
|
// Note: assertion on upper bounds is done in PutLE24().
|
||||||
|
|
||||||
frame_frgm_bytes = (uint8_t*)WebPSafeMalloc(1ULL, frame_frgm_size);
|
frame_bytes = (uint8_t*)WebPSafeMalloc(1ULL, frame_size);
|
||||||
if (frame_frgm_bytes == NULL) return WEBP_MUX_MEMORY_ERROR;
|
if (frame_bytes == NULL) return WEBP_MUX_MEMORY_ERROR;
|
||||||
|
|
||||||
PutLE24(frame_frgm_bytes + 0, info->x_offset / 2);
|
PutLE24(frame_bytes + 0, info->x_offset / 2);
|
||||||
PutLE24(frame_frgm_bytes + 3, info->y_offset / 2);
|
PutLE24(frame_bytes + 3, info->y_offset / 2);
|
||||||
|
|
||||||
if (is_frame) {
|
PutLE24(frame_bytes + 6, width - 1);
|
||||||
PutLE24(frame_frgm_bytes + 6, width - 1);
|
PutLE24(frame_bytes + 9, height - 1);
|
||||||
PutLE24(frame_frgm_bytes + 9, height - 1);
|
PutLE24(frame_bytes + 12, info->duration);
|
||||||
PutLE24(frame_frgm_bytes + 12, info->duration);
|
frame_bytes[15] =
|
||||||
frame_frgm_bytes[15] =
|
|
||||||
(info->blend_method == WEBP_MUX_NO_BLEND ? 2 : 0) |
|
(info->blend_method == WEBP_MUX_NO_BLEND ? 2 : 0) |
|
||||||
(info->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? 1 : 0);
|
(info->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? 1 : 0);
|
||||||
}
|
|
||||||
|
|
||||||
frame_frgm->bytes = frame_frgm_bytes;
|
frame->bytes = frame_bytes;
|
||||||
frame_frgm->size = frame_frgm_size;
|
frame->size = frame_size;
|
||||||
return WEBP_MUX_OK;
|
return WEBP_MUX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,23 +262,16 @@ WebPMuxError WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame,
|
WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info,
|
||||||
int copy_data) {
|
int copy_data) {
|
||||||
WebPMuxImage wpi;
|
WebPMuxImage wpi;
|
||||||
WebPMuxError err;
|
WebPMuxError err;
|
||||||
int is_frame;
|
const WebPData* const bitstream = &info->bitstream;
|
||||||
const WebPData* const bitstream = &frame->bitstream;
|
|
||||||
|
|
||||||
// Sanity checks.
|
// Sanity checks.
|
||||||
if (mux == NULL || frame == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
if (mux == NULL || info == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
|
|
||||||
is_frame = (frame->id == WEBP_CHUNK_ANMF);
|
if (info->id != WEBP_CHUNK_ANMF) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
if (!(is_frame || (frame->id == WEBP_CHUNK_FRGM))) {
|
|
||||||
return WEBP_MUX_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
if (frame->id == WEBP_CHUNK_FRGM) { // Dead experiment.
|
|
||||||
return WEBP_MUX_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bitstream->bytes == NULL || bitstream->size > MAX_CHUNK_PAYLOAD) {
|
if (bitstream->bytes == NULL || bitstream->size > MAX_CHUNK_PAYLOAD) {
|
||||||
return WEBP_MUX_INVALID_ARGUMENT;
|
return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
@ -290,7 +281,7 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame,
|
|||||||
const WebPMuxImage* const image = mux->images_;
|
const WebPMuxImage* const image = mux->images_;
|
||||||
const uint32_t image_id = (image->header_ != NULL) ?
|
const uint32_t image_id = (image->header_ != NULL) ?
|
||||||
ChunkGetIdFromTag(image->header_->tag_) : WEBP_CHUNK_IMAGE;
|
ChunkGetIdFromTag(image->header_->tag_) : WEBP_CHUNK_IMAGE;
|
||||||
if (image_id != frame->id) {
|
if (image_id != info->id) {
|
||||||
return WEBP_MUX_INVALID_ARGUMENT; // Conflicting frame types.
|
return WEBP_MUX_INVALID_ARGUMENT; // Conflicting frame types.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,16 +292,11 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame,
|
|||||||
assert(wpi.img_ != NULL); // As SetAlphaAndImageChunks() was successful.
|
assert(wpi.img_ != NULL); // As SetAlphaAndImageChunks() was successful.
|
||||||
|
|
||||||
{
|
{
|
||||||
WebPData frame_frgm;
|
WebPData frame;
|
||||||
const uint32_t tag = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].tag;
|
const uint32_t tag = kChunks[IDX_ANMF].tag;
|
||||||
WebPMuxFrameInfo tmp = *frame;
|
WebPMuxFrameInfo tmp = *info;
|
||||||
tmp.x_offset &= ~1; // Snap offsets to even.
|
tmp.x_offset &= ~1; // Snap offsets to even.
|
||||||
tmp.y_offset &= ~1;
|
tmp.y_offset &= ~1;
|
||||||
if (!is_frame) { // Reset unused values.
|
|
||||||
tmp.duration = 1;
|
|
||||||
tmp.dispose_method = WEBP_MUX_DISPOSE_NONE;
|
|
||||||
tmp.blend_method = WEBP_MUX_BLEND;
|
|
||||||
}
|
|
||||||
if (tmp.x_offset < 0 || tmp.x_offset >= MAX_POSITION_OFFSET ||
|
if (tmp.x_offset < 0 || tmp.x_offset >= MAX_POSITION_OFFSET ||
|
||||||
tmp.y_offset < 0 || tmp.y_offset >= MAX_POSITION_OFFSET ||
|
tmp.y_offset < 0 || tmp.y_offset >= MAX_POSITION_OFFSET ||
|
||||||
(tmp.duration < 0 || tmp.duration >= MAX_DURATION) ||
|
(tmp.duration < 0 || tmp.duration >= MAX_DURATION) ||
|
||||||
@ -318,12 +304,11 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame,
|
|||||||
err = WEBP_MUX_INVALID_ARGUMENT;
|
err = WEBP_MUX_INVALID_ARGUMENT;
|
||||||
goto Err;
|
goto Err;
|
||||||
}
|
}
|
||||||
err = CreateFrameFragmentData(wpi.width_, wpi.height_, &tmp, is_frame,
|
err = CreateFrameData(wpi.width_, wpi.height_, &tmp, &frame);
|
||||||
&frame_frgm);
|
|
||||||
if (err != WEBP_MUX_OK) goto Err;
|
if (err != WEBP_MUX_OK) goto Err;
|
||||||
// Add frame/fragment chunk (with copy_data = 1).
|
// Add frame chunk (with copy_data = 1).
|
||||||
err = AddDataToChunkList(&frame_frgm, 1, tag, &wpi.header_);
|
err = AddDataToChunkList(&frame, 1, tag, &wpi.header_);
|
||||||
WebPDataClear(&frame_frgm); // frame_frgm owned by wpi.header_ now.
|
WebPDataClear(&frame); // frame owned by wpi.header_ now.
|
||||||
if (err != WEBP_MUX_OK) goto Err;
|
if (err != WEBP_MUX_OK) goto Err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,21 +387,18 @@ WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth) {
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Assembly of the WebP RIFF file.
|
// Assembly of the WebP RIFF file.
|
||||||
|
|
||||||
static WebPMuxError GetFrameFragmentInfo(
|
static WebPMuxError GetFrameInfo(
|
||||||
const WebPChunk* const frame_frgm_chunk,
|
const WebPChunk* const frame_chunk,
|
||||||
int* const x_offset, int* const y_offset, int* const duration) {
|
int* const x_offset, int* const y_offset, int* const duration) {
|
||||||
const uint32_t tag = frame_frgm_chunk->tag_;
|
const WebPData* const data = &frame_chunk->data_;
|
||||||
const int is_frame = (tag == kChunks[IDX_ANMF].tag);
|
const size_t expected_data_size = ANMF_CHUNK_SIZE;
|
||||||
const WebPData* const data = &frame_frgm_chunk->data_;
|
assert(frame_chunk->tag_ == kChunks[IDX_ANMF].tag);
|
||||||
const size_t expected_data_size =
|
assert(frame_chunk != NULL);
|
||||||
is_frame ? ANMF_CHUNK_SIZE : FRGM_CHUNK_SIZE;
|
|
||||||
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;
|
if (data->size != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
|
|
||||||
*x_offset = 2 * GetLE24(data->bytes + 0);
|
*x_offset = 2 * GetLE24(data->bytes + 0);
|
||||||
*y_offset = 2 * GetLE24(data->bytes + 3);
|
*y_offset = 2 * GetLE24(data->bytes + 3);
|
||||||
if (is_frame) *duration = GetLE24(data->bytes + 12);
|
*duration = GetLE24(data->bytes + 12);
|
||||||
return WEBP_MUX_OK;
|
return WEBP_MUX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,13 +406,13 @@ static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi,
|
|||||||
int* const x_offset, int* const y_offset,
|
int* const x_offset, int* const y_offset,
|
||||||
int* const duration,
|
int* const duration,
|
||||||
int* const width, int* const height) {
|
int* const width, int* const height) {
|
||||||
const WebPChunk* const frame_frgm_chunk = wpi->header_;
|
const WebPChunk* const frame_chunk = wpi->header_;
|
||||||
WebPMuxError err;
|
WebPMuxError err;
|
||||||
assert(wpi != NULL);
|
assert(wpi != NULL);
|
||||||
assert(frame_frgm_chunk != NULL);
|
assert(frame_chunk != NULL);
|
||||||
|
|
||||||
// Get offsets and duration from ANMF/FRGM chunk.
|
// Get offsets and duration from ANMF chunk.
|
||||||
err = GetFrameFragmentInfo(frame_frgm_chunk, x_offset, y_offset, duration);
|
err = GetFrameInfo(frame_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.
|
||||||
@ -441,7 +423,6 @@ static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi,
|
|||||||
|
|
||||||
// Returns the tightest dimension for the canvas considering the image list.
|
// Returns the tightest dimension for the canvas considering the image list.
|
||||||
static WebPMuxError GetAdjustedCanvasSize(const WebPMux* const mux,
|
static WebPMuxError GetAdjustedCanvasSize(const WebPMux* const mux,
|
||||||
uint32_t flags,
|
|
||||||
int* const width, int* const height) {
|
int* const width, int* const height) {
|
||||||
WebPMuxImage* wpi = NULL;
|
WebPMuxImage* wpi = NULL;
|
||||||
assert(mux != NULL);
|
assert(mux != NULL);
|
||||||
@ -452,12 +433,10 @@ static WebPMuxError GetAdjustedCanvasSize(const WebPMux* const mux,
|
|||||||
assert(wpi->img_ != NULL);
|
assert(wpi->img_ != NULL);
|
||||||
|
|
||||||
if (wpi->next_ != NULL) {
|
if (wpi->next_ != NULL) {
|
||||||
int max_x = 0;
|
int max_x = 0, max_y = 0;
|
||||||
int max_y = 0;
|
|
||||||
int64_t image_area = 0;
|
|
||||||
// if we have a chain of wpi's, header_ is necessarily set
|
// if we have a chain of wpi's, header_ is necessarily set
|
||||||
assert(wpi->header_ != NULL);
|
assert(wpi->header_ != NULL);
|
||||||
// Aggregate the bounding box for animation frames & fragmented images.
|
// Aggregate the bounding box for animation frames.
|
||||||
for (; wpi != NULL; wpi = wpi->next_) {
|
for (; wpi != NULL; wpi = wpi->next_) {
|
||||||
int x_offset = 0, y_offset = 0, duration = 0, w = 0, h = 0;
|
int x_offset = 0, y_offset = 0, duration = 0, w = 0, h = 0;
|
||||||
const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset,
|
const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset,
|
||||||
@ -470,19 +449,9 @@ static WebPMuxError GetAdjustedCanvasSize(const WebPMux* const mux,
|
|||||||
|
|
||||||
if (max_x_pos > max_x) max_x = max_x_pos;
|
if (max_x_pos > max_x) max_x = max_x_pos;
|
||||||
if (max_y_pos > max_y) max_y = max_y_pos;
|
if (max_y_pos > max_y) max_y = max_y_pos;
|
||||||
image_area += w * h;
|
|
||||||
}
|
}
|
||||||
*width = max_x;
|
*width = max_x;
|
||||||
*height = max_y;
|
*height = 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;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// For a single image, canvas dimensions are same as image dimensions.
|
// For a single image, canvas dimensions are same as image dimensions.
|
||||||
*width = wpi->width_;
|
*width = wpi->width_;
|
||||||
@ -528,10 +497,7 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
|
|||||||
flags |= XMP_FLAG;
|
flags |= XMP_FLAG;
|
||||||
}
|
}
|
||||||
if (images->header_ != NULL) {
|
if (images->header_ != NULL) {
|
||||||
if (images->header_->tag_ == kChunks[IDX_FRGM].tag) {
|
if (images->header_->tag_ == kChunks[IDX_ANMF].tag) {
|
||||||
// This is a fragmented image.
|
|
||||||
flags |= FRAGMENTS_FLAG;
|
|
||||||
} 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;
|
||||||
}
|
}
|
||||||
@ -540,7 +506,7 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
|
|||||||
flags |= ALPHA_FLAG; // Some images have an alpha channel.
|
flags |= ALPHA_FLAG; // Some images have an alpha channel.
|
||||||
}
|
}
|
||||||
|
|
||||||
err = GetAdjustedCanvasSize(mux, flags, &width, &height);
|
err = GetAdjustedCanvasSize(mux, &width, &height);
|
||||||
if (err != WEBP_MUX_OK) return err;
|
if (err != WEBP_MUX_OK) return err;
|
||||||
|
|
||||||
if (width <= 0 || height <= 0) {
|
if (width <= 0 || height <= 0) {
|
||||||
@ -580,31 +546,26 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
|
|||||||
// Cleans up 'mux' by removing any unnecessary chunks.
|
// Cleans up 'mux' by removing any unnecessary chunks.
|
||||||
static WebPMuxError MuxCleanup(WebPMux* const mux) {
|
static WebPMuxError MuxCleanup(WebPMux* const mux) {
|
||||||
int num_frames;
|
int num_frames;
|
||||||
int num_fragments;
|
|
||||||
int num_anim_chunks;
|
int num_anim_chunks;
|
||||||
|
|
||||||
// If we have an image with a single fragment or frame, and its rectangle
|
// If we have an image with a single frame, and its rectangle
|
||||||
// covers the whole canvas, convert it to a non-animated non-fragmented image
|
// covers the whole canvas, convert it to a non-animated image
|
||||||
// (to avoid writing FRGM/ANMF chunk unnecessarily).
|
// (to avoid writing ANMF chunk unnecessarily).
|
||||||
WebPMuxError err = WebPMuxNumChunks(mux, kChunks[IDX_ANMF].id, &num_frames);
|
WebPMuxError err = WebPMuxNumChunks(mux, kChunks[IDX_ANMF].id, &num_frames);
|
||||||
if (err != WEBP_MUX_OK) return err;
|
if (err != WEBP_MUX_OK) return err;
|
||||||
err = WebPMuxNumChunks(mux, kChunks[IDX_FRGM].id, &num_fragments);
|
if (num_frames == 1) {
|
||||||
if (err != WEBP_MUX_OK) return err;
|
WebPMuxImage* frame = NULL;
|
||||||
if (num_frames == 1 || num_fragments == 1) {
|
err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, &frame);
|
||||||
WebPMuxImage* frame_frag;
|
assert(err == WEBP_MUX_OK); // We know that one frame does exist.
|
||||||
err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, &frame_frag);
|
assert(frame != NULL);
|
||||||
assert(err == WEBP_MUX_OK); // We know that one frame/fragment does exist.
|
if (frame->header_ != NULL &&
|
||||||
assert(frame_frag != NULL);
|
|
||||||
if (frame_frag->header_ != NULL &&
|
|
||||||
((mux->canvas_width_ == 0 && mux->canvas_height_ == 0) ||
|
((mux->canvas_width_ == 0 && mux->canvas_height_ == 0) ||
|
||||||
(frame_frag->width_ == mux->canvas_width_ &&
|
(frame->width_ == mux->canvas_width_ &&
|
||||||
frame_frag->height_ == mux->canvas_height_))) {
|
frame->height_ == mux->canvas_height_))) {
|
||||||
assert(frame_frag->header_->tag_ == kChunks[IDX_ANMF].tag ||
|
assert(frame->header_->tag_ == kChunks[IDX_ANMF].tag);
|
||||||
frame_frag->header_->tag_ == kChunks[IDX_FRGM].tag);
|
ChunkDelete(frame->header_); // Removes ANMF chunk.
|
||||||
ChunkDelete(frame_frag->header_); // Removes ANMF/FRGM chunk.
|
frame->header_ = NULL;
|
||||||
frame_frag->header_ = NULL;
|
|
||||||
num_frames = 0;
|
num_frames = 0;
|
||||||
num_fragments = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove ANIM chunk if this is a non-animated image.
|
// Remove ANIM chunk if this is a non-animated image.
|
||||||
|
@ -36,16 +36,16 @@ struct WebPChunk {
|
|||||||
uint32_t tag_;
|
uint32_t tag_;
|
||||||
int owner_; // True if *data_ memory is owned internally.
|
int owner_; // True if *data_ memory is owned internally.
|
||||||
// VP8X, ANIM, and other internally created chunks
|
// VP8X, ANIM, and other internally created chunks
|
||||||
// like ANMF/FRGM are always owned.
|
// like ANMF are always owned.
|
||||||
WebPData data_;
|
WebPData data_;
|
||||||
WebPChunk* next_;
|
WebPChunk* next_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// MuxImage object. Store a full WebP image (including ANMF/FRGM chunk, ALPH
|
// MuxImage object. Store a full WebP image (including ANMF chunk, ALPH
|
||||||
// chunk and VP8/VP8L chunk),
|
// chunk and VP8/VP8L chunk),
|
||||||
typedef struct WebPMuxImage WebPMuxImage;
|
typedef struct WebPMuxImage WebPMuxImage;
|
||||||
struct WebPMuxImage {
|
struct WebPMuxImage {
|
||||||
WebPChunk* header_; // Corresponds to WEBP_CHUNK_ANMF/WEBP_CHUNK_FRGM.
|
WebPChunk* header_; // Corresponds to WEBP_CHUNK_ANMF.
|
||||||
WebPChunk* alpha_; // Corresponds to WEBP_CHUNK_ALPHA.
|
WebPChunk* alpha_; // Corresponds to WEBP_CHUNK_ALPHA.
|
||||||
WebPChunk* img_; // Corresponds to WEBP_CHUNK_IMAGE.
|
WebPChunk* img_; // Corresponds to WEBP_CHUNK_IMAGE.
|
||||||
WebPChunk* unknown_; // Corresponds to WEBP_CHUNK_UNKNOWN.
|
WebPChunk* unknown_; // Corresponds to WEBP_CHUNK_UNKNOWN.
|
||||||
@ -79,7 +79,6 @@ typedef enum {
|
|||||||
IDX_ICCP,
|
IDX_ICCP,
|
||||||
IDX_ANIM,
|
IDX_ANIM,
|
||||||
IDX_ANMF,
|
IDX_ANMF,
|
||||||
IDX_FRGM,
|
|
||||||
IDX_ALPHA,
|
IDX_ALPHA,
|
||||||
IDX_VP8,
|
IDX_VP8,
|
||||||
IDX_VP8L,
|
IDX_VP8L,
|
||||||
@ -185,7 +184,6 @@ int MuxImageFinalize(WebPMuxImage* const wpi);
|
|||||||
static WEBP_INLINE int IsWPI(WebPChunkId id) {
|
static WEBP_INLINE int IsWPI(WebPChunkId id) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case WEBP_CHUNK_ANMF:
|
case WEBP_CHUNK_ANMF:
|
||||||
case WEBP_CHUNK_FRGM:
|
|
||||||
case WEBP_CHUNK_ALPHA:
|
case WEBP_CHUNK_ALPHA:
|
||||||
case WEBP_CHUNK_IMAGE: return 1;
|
case WEBP_CHUNK_IMAGE: return 1;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
|
@ -23,7 +23,6 @@ const ChunkInfo kChunks[] = {
|
|||||||
{ MKFOURCC('I', 'C', 'C', 'P'), WEBP_CHUNK_ICCP, UNDEFINED_CHUNK_SIZE },
|
{ MKFOURCC('I', 'C', 'C', 'P'), WEBP_CHUNK_ICCP, UNDEFINED_CHUNK_SIZE },
|
||||||
{ MKFOURCC('A', 'N', 'I', 'M'), WEBP_CHUNK_ANIM, ANIM_CHUNK_SIZE },
|
{ MKFOURCC('A', 'N', 'I', 'M'), WEBP_CHUNK_ANIM, ANIM_CHUNK_SIZE },
|
||||||
{ MKFOURCC('A', 'N', 'M', 'F'), WEBP_CHUNK_ANMF, ANMF_CHUNK_SIZE },
|
{ MKFOURCC('A', 'N', 'M', 'F'), WEBP_CHUNK_ANMF, ANMF_CHUNK_SIZE },
|
||||||
{ MKFOURCC('F', 'R', 'G', 'M'), WEBP_CHUNK_FRGM, FRGM_CHUNK_SIZE },
|
|
||||||
{ MKFOURCC('A', 'L', 'P', 'H'), WEBP_CHUNK_ALPHA, UNDEFINED_CHUNK_SIZE },
|
{ MKFOURCC('A', 'L', 'P', 'H'), WEBP_CHUNK_ALPHA, UNDEFINED_CHUNK_SIZE },
|
||||||
{ MKFOURCC('V', 'P', '8', ' '), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
|
{ MKFOURCC('V', 'P', '8', ' '), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
|
||||||
{ MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
|
{ MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
|
||||||
@ -251,8 +250,7 @@ static WebPChunk** GetChunkListFromId(const WebPMuxImage* const wpi,
|
|||||||
WebPChunkId id) {
|
WebPChunkId id) {
|
||||||
assert(wpi != NULL);
|
assert(wpi != NULL);
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case WEBP_CHUNK_ANMF:
|
case WEBP_CHUNK_ANMF: return (WebPChunk**)&wpi->header_;
|
||||||
case WEBP_CHUNK_FRGM: return (WebPChunk**)&wpi->header_;
|
|
||||||
case WEBP_CHUNK_ALPHA: return (WebPChunk**)&wpi->alpha_;
|
case WEBP_CHUNK_ALPHA: return (WebPChunk**)&wpi->alpha_;
|
||||||
case WEBP_CHUNK_IMAGE: return (WebPChunk**)&wpi->img_;
|
case WEBP_CHUNK_IMAGE: return (WebPChunk**)&wpi->img_;
|
||||||
default: return NULL;
|
default: return NULL;
|
||||||
@ -372,13 +370,12 @@ size_t MuxImageDiskSize(const WebPMuxImage* const wpi) {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case as ANMF/FRGM chunk encapsulates other image chunks.
|
// Special case as ANMF chunk encapsulates other image chunks.
|
||||||
static uint8_t* ChunkEmitSpecial(const WebPChunk* const header,
|
static uint8_t* ChunkEmitSpecial(const WebPChunk* const header,
|
||||||
size_t total_size, uint8_t* dst) {
|
size_t total_size, uint8_t* dst) {
|
||||||
const size_t header_size = header->data_.size;
|
const size_t header_size = header->data_.size;
|
||||||
const size_t offset_to_next = total_size - CHUNK_HEADER_SIZE;
|
const size_t offset_to_next = total_size - CHUNK_HEADER_SIZE;
|
||||||
assert(header->tag_ == kChunks[IDX_ANMF].tag ||
|
assert(header->tag_ == kChunks[IDX_ANMF].tag);
|
||||||
header->tag_ == kChunks[IDX_FRGM].tag);
|
|
||||||
PutLE32(dst + 0, header->tag_);
|
PutLE32(dst + 0, header->tag_);
|
||||||
PutLE32(dst + TAG_SIZE, (uint32_t)offset_to_next);
|
PutLE32(dst + TAG_SIZE, (uint32_t)offset_to_next);
|
||||||
assert(header_size == (uint32_t)header_size);
|
assert(header_size == (uint32_t)header_size);
|
||||||
@ -391,7 +388,7 @@ static uint8_t* ChunkEmitSpecial(const WebPChunk* const header,
|
|||||||
|
|
||||||
uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) {
|
uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) {
|
||||||
// Ordering of chunks to be emitted is strictly as follows:
|
// Ordering of chunks to be emitted is strictly as follows:
|
||||||
// 1. ANMF/FRGM chunk (if present).
|
// 1. ANMF chunk (if present).
|
||||||
// 2. ALPH chunk (if present).
|
// 2. ALPH chunk (if present).
|
||||||
// 3. VP8/VP8L chunk.
|
// 3. VP8/VP8L chunk.
|
||||||
assert(wpi);
|
assert(wpi);
|
||||||
@ -465,7 +462,6 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
|
|||||||
int num_xmp;
|
int num_xmp;
|
||||||
int num_anim;
|
int num_anim;
|
||||||
int num_frames;
|
int num_frames;
|
||||||
int num_fragments;
|
|
||||||
int num_vp8x;
|
int num_vp8x;
|
||||||
int num_images;
|
int num_images;
|
||||||
int num_alpha;
|
int num_alpha;
|
||||||
@ -510,10 +506,6 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// Verify either VP8X chunk is present OR there is only one elem in
|
||||||
// mux->images_.
|
// mux->images_.
|
||||||
err = ValidateChunk(mux, IDX_VP8X, NO_FLAG, flags, 1, &num_vp8x);
|
err = ValidateChunk(mux, IDX_VP8X, NO_FLAG, flags, 1, &num_vp8x);
|
||||||
@ -537,11 +529,6 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
|
|||||||
if (flags & ALPHA_FLAG) return WEBP_MUX_INVALID_ARGUMENT;
|
if (flags & ALPHA_FLAG) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// num_fragments & num_images are consistent.
|
|
||||||
if (num_fragments > 0 && num_images != num_fragments) {
|
|
||||||
return WEBP_MUX_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return WEBP_MUX_OK;
|
return WEBP_MUX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,17 +104,15 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data,
|
|||||||
size_t subchunk_size;
|
size_t subchunk_size;
|
||||||
ChunkInit(&subchunk);
|
ChunkInit(&subchunk);
|
||||||
|
|
||||||
assert(chunk->tag_ == kChunks[IDX_ANMF].tag ||
|
assert(chunk->tag_ == kChunks[IDX_ANMF].tag);
|
||||||
chunk->tag_ == kChunks[IDX_FRGM].tag);
|
|
||||||
assert(!wpi->is_partial_);
|
assert(!wpi->is_partial_);
|
||||||
|
|
||||||
// ANMF/FRGM.
|
// ANMF.
|
||||||
{
|
{
|
||||||
const size_t hdr_size = (chunk->tag_ == kChunks[IDX_ANMF].tag) ?
|
const size_t hdr_size = ANMF_CHUNK_SIZE;
|
||||||
ANMF_CHUNK_SIZE : FRGM_CHUNK_SIZE;
|
|
||||||
const WebPData temp = { bytes, hdr_size };
|
const WebPData temp = { bytes, hdr_size };
|
||||||
// Each of ANMF and FRGM chunk contain a header at the beginning. So, its
|
// Each of ANMF chunk contain a header at the beginning. So, its size should
|
||||||
// size should at least be 'hdr_size'.
|
// be at least 'hdr_size'.
|
||||||
if (size < hdr_size) goto Fail;
|
if (size < hdr_size) goto Fail;
|
||||||
ChunkAssignData(&subchunk, &temp, copy_data, chunk->tag_);
|
ChunkAssignData(&subchunk, &temp, copy_data, chunk->tag_);
|
||||||
}
|
}
|
||||||
@ -292,16 +290,15 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
|
|||||||
static WebPMuxError ValidateForSingleImage(const WebPMux* const mux) {
|
static WebPMuxError ValidateForSingleImage(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_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_fragments == 0) {
|
} else if (num_images == 1 && num_frames == 0) {
|
||||||
// Valid case (single image).
|
// Valid case (single image).
|
||||||
return WEBP_MUX_OK;
|
return WEBP_MUX_OK;
|
||||||
} else {
|
} else {
|
||||||
// Frame/Fragment case OR an invalid mux.
|
// Frame case OR an invalid mux.
|
||||||
return WEBP_MUX_INVALID_ARGUMENT;
|
return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,7 +376,7 @@ static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi,
|
|||||||
const int need_vp8x = (wpi->alpha_ != NULL);
|
const int need_vp8x = (wpi->alpha_ != NULL);
|
||||||
const size_t vp8x_size = need_vp8x ? CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE : 0;
|
const size_t vp8x_size = need_vp8x ? CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE : 0;
|
||||||
const size_t alpha_size = need_vp8x ? ChunkDiskSize(wpi->alpha_) : 0;
|
const size_t alpha_size = need_vp8x ? ChunkDiskSize(wpi->alpha_) : 0;
|
||||||
// Note: No need to output ANMF/FRGM chunk for a single image.
|
// Note: No need to output ANMF chunk for a single image.
|
||||||
const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size +
|
const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size +
|
||||||
ChunkDiskSize(wpi->img_);
|
ChunkDiskSize(wpi->img_);
|
||||||
uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size);
|
uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size);
|
||||||
@ -436,29 +433,24 @@ static WebPMuxError MuxGetImageInternal(const WebPMuxImage* const wpi,
|
|||||||
return SynthesizeBitstream(wpi, &info->bitstream);
|
return SynthesizeBitstream(wpi, &info->bitstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WebPMuxError MuxGetFrameFragmentInternal(const WebPMuxImage* const wpi,
|
static WebPMuxError MuxGetFrameInternal(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 WebPData* frame_data;
|
||||||
const WebPData* frame_frgm_data;
|
|
||||||
if (!is_frame) return WEBP_MUX_INVALID_ARGUMENT;
|
if (!is_frame) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
assert(wpi->header_ != NULL); // Already checked by WebPMuxGetFrame().
|
assert(wpi->header_ != NULL); // Already checked by WebPMuxGetFrame().
|
||||||
// Get frame/fragment chunk.
|
// Get frame chunk.
|
||||||
frame_frgm_data = &wpi->header_->data_;
|
frame_data = &wpi->header_->data_;
|
||||||
if (frame_frgm_data->size < kChunks[idx].size) return WEBP_MUX_BAD_DATA;
|
if (frame_data->size < kChunks[IDX_ANMF].size) return WEBP_MUX_BAD_DATA;
|
||||||
// Extract info.
|
// Extract info.
|
||||||
frame->x_offset = 2 * GetLE24(frame_frgm_data->bytes + 0);
|
frame->x_offset = 2 * GetLE24(frame_data->bytes + 0);
|
||||||
frame->y_offset = 2 * GetLE24(frame_frgm_data->bytes + 3);
|
frame->y_offset = 2 * GetLE24(frame_data->bytes + 3);
|
||||||
if (is_frame) {
|
{
|
||||||
const uint8_t bits = frame_frgm_data->bytes[15];
|
const uint8_t bits = frame_data->bytes[15];
|
||||||
frame->duration = GetLE24(frame_frgm_data->bytes + 12);
|
frame->duration = GetLE24(frame_data->bytes + 12);
|
||||||
frame->dispose_method =
|
frame->dispose_method =
|
||||||
(bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
|
(bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
|
||||||
frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
|
frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
|
||||||
} else { // Defaults for unused values.
|
|
||||||
frame->duration = 1;
|
|
||||||
frame->dispose_method = WEBP_MUX_DISPOSE_NONE;
|
|
||||||
frame->blend_method = WEBP_MUX_BLEND;
|
|
||||||
}
|
}
|
||||||
frame->id = ChunkGetIdFromTag(wpi->header_->tag_);
|
frame->id = ChunkGetIdFromTag(wpi->header_->tag_);
|
||||||
return SynthesizeBitstream(wpi, &frame->bitstream);
|
return SynthesizeBitstream(wpi, &frame->bitstream);
|
||||||
@ -482,7 +474,7 @@ WebPMuxError WebPMuxGetFrame(
|
|||||||
if (wpi->header_ == NULL) {
|
if (wpi->header_ == NULL) {
|
||||||
return MuxGetImageInternal(wpi, frame);
|
return MuxGetImageInternal(wpi, frame);
|
||||||
} else {
|
} else {
|
||||||
return MuxGetFrameFragmentInternal(wpi, frame);
|
return MuxGetFrameInternal(wpi, frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,14 +72,13 @@ typedef enum {
|
|||||||
#define RIFF_HEADER_SIZE 12 // Size of the RIFF header ("RIFFnnnnWEBP").
|
#define RIFF_HEADER_SIZE 12 // Size of the RIFF header ("RIFFnnnnWEBP").
|
||||||
#define ANMF_CHUNK_SIZE 16 // Size of an ANMF chunk.
|
#define ANMF_CHUNK_SIZE 16 // Size of an ANMF chunk.
|
||||||
#define ANIM_CHUNK_SIZE 6 // Size of an ANIM chunk.
|
#define ANIM_CHUNK_SIZE 6 // Size of an ANIM chunk.
|
||||||
#define FRGM_CHUNK_SIZE 6 // Size of a FRGM chunk.
|
|
||||||
#define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk.
|
#define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk.
|
||||||
|
|
||||||
#define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height.
|
#define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height.
|
||||||
#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/fragment x/y offset
|
#define MAX_POSITION_OFFSET (1 << 24) // maximum frame 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.
|
||||||
|
@ -21,13 +21,13 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WEBP_MUX_ABI_VERSION 0x0106 // MAJOR(8b) + MINOR(8b)
|
#define WEBP_MUX_ABI_VERSION 0x0107 // MAJOR(8b) + MINOR(8b)
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Mux API
|
// Mux API
|
||||||
//
|
//
|
||||||
// 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 fragmented images.
|
// like color profile, metadata, animation.
|
||||||
//
|
//
|
||||||
// Code Example#1: Create a WebPMux object with image data, color profile and
|
// Code Example#1: Create a WebPMux object with image data, color profile and
|
||||||
// XMP metadata.
|
// XMP metadata.
|
||||||
@ -85,7 +85,7 @@ typedef enum WebPChunkId {
|
|||||||
WEBP_CHUNK_ICCP, // ICCP
|
WEBP_CHUNK_ICCP, // ICCP
|
||||||
WEBP_CHUNK_ANIM, // ANIM
|
WEBP_CHUNK_ANIM, // ANIM
|
||||||
WEBP_CHUNK_ANMF, // ANMF
|
WEBP_CHUNK_ANMF, // ANMF
|
||||||
WEBP_CHUNK_FRGM, // FRGM
|
WEBP_CHUNK_DEPRECATED, // (deprecated from FRGM)
|
||||||
WEBP_CHUNK_ALPHA, // ALPH
|
WEBP_CHUNK_ALPHA, // ALPH
|
||||||
WEBP_CHUNK_IMAGE, // VP8/VP8L
|
WEBP_CHUNK_IMAGE, // VP8/VP8L
|
||||||
WEBP_CHUNK_EXIF, // EXIF
|
WEBP_CHUNK_EXIF, // EXIF
|
||||||
@ -142,7 +142,7 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
|
|||||||
// Non-image chunks.
|
// Non-image chunks.
|
||||||
|
|
||||||
// Note: Only non-image related chunks should be managed through chunk APIs.
|
// Note: Only non-image related chunks should be managed through chunk APIs.
|
||||||
// (Image related chunks are: "ANMF", "FRGM", "VP8 ", "VP8L" and "ALPH").
|
// (Image related chunks are: "ANMF", "VP8 ", "VP8L" and "ALPH").
|
||||||
// To add, get and delete images, use WebPMuxSetImage(), WebPMuxPushFrame(),
|
// To add, get and delete images, use WebPMuxSetImage(), WebPMuxPushFrame(),
|
||||||
// WebPMuxGetFrame() and WebPMuxDeleteFrame().
|
// WebPMuxGetFrame() and WebPMuxDeleteFrame().
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxDeleteChunk(
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Images.
|
// Images.
|
||||||
|
|
||||||
// Encapsulates data about a single frame/fragment.
|
// Encapsulates data about a single frame.
|
||||||
struct WebPMuxFrameInfo {
|
struct WebPMuxFrameInfo {
|
||||||
WebPData bitstream; // image data: can be a raw VP8/VP8L bitstream
|
WebPData bitstream; // image data: can be a raw VP8/VP8L bitstream
|
||||||
// or a single-image WebP file.
|
// or a single-image WebP file.
|
||||||
@ -203,19 +203,19 @@ struct WebPMuxFrameInfo {
|
|||||||
int y_offset; // y-offset of the frame.
|
int y_offset; // y-offset of the frame.
|
||||||
int duration; // duration of the frame (in milliseconds).
|
int duration; // duration of the frame (in milliseconds).
|
||||||
|
|
||||||
WebPChunkId id; // frame type: should be one of WEBP_CHUNK_ANMF,
|
WebPChunkId id; // frame type: should be one of WEBP_CHUNK_ANMF
|
||||||
// WEBP_CHUNK_FRGM or WEBP_CHUNK_IMAGE
|
// or WEBP_CHUNK_IMAGE
|
||||||
WebPMuxAnimDispose dispose_method; // Disposal method for the frame.
|
WebPMuxAnimDispose dispose_method; // Disposal method for the frame.
|
||||||
WebPMuxAnimBlend blend_method; // Blend operation for the frame.
|
WebPMuxAnimBlend blend_method; // Blend operation for the frame.
|
||||||
uint32_t pad[1]; // padding for later use
|
uint32_t pad[1]; // padding for later use
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sets the (non-animated and non-fragmented) image in the mux object.
|
// Sets the (non-animated) image in the mux object.
|
||||||
// Note: Any existing images (including frames/fragments) will be removed.
|
// Note: Any existing images (including frames) 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 be a raw VP8/VP8L bitstream or a single-image
|
// bitstream - (in) can be a raw VP8/VP8L bitstream or a single-image
|
||||||
// WebP file (non-animated and non-fragmented)
|
// WebP file (non-animated)
|
||||||
// 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
|
||||||
// object and value 0 indicates data will NOT be copied.
|
// object and value 0 indicates data will NOT be copied.
|
||||||
// Returns:
|
// Returns:
|
||||||
@ -226,9 +226,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(
|
|||||||
WebPMux* mux, const WebPData* bitstream, int copy_data);
|
WebPMux* mux, const WebPData* bitstream, int copy_data);
|
||||||
|
|
||||||
// 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 WEBP_CHUNK_ANMF
|
||||||
// (2) For setting a non-animated non-fragmented image, use
|
// (2) For setting a non-animated image, use WebPMuxSetImage() 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
|
||||||
|
@ -31,12 +31,13 @@ typedef struct WebPData WebPData;
|
|||||||
|
|
||||||
// VP8X Feature Flags.
|
// VP8X Feature Flags.
|
||||||
typedef enum WebPFeatureFlags {
|
typedef enum WebPFeatureFlags {
|
||||||
FRAGMENTS_FLAG = 0x00000001,
|
|
||||||
ANIMATION_FLAG = 0x00000002,
|
ANIMATION_FLAG = 0x00000002,
|
||||||
XMP_FLAG = 0x00000004,
|
XMP_FLAG = 0x00000004,
|
||||||
EXIF_FLAG = 0x00000008,
|
EXIF_FLAG = 0x00000008,
|
||||||
ALPHA_FLAG = 0x00000010,
|
ALPHA_FLAG = 0x00000010,
|
||||||
ICCP_FLAG = 0x00000020
|
ICCP_FLAG = 0x00000020,
|
||||||
|
|
||||||
|
ALL_VALID_FLAGS = 0x0000003e
|
||||||
} WebPFeatureFlags;
|
} WebPFeatureFlags;
|
||||||
|
|
||||||
// Dispose method (animation only). Indicates how the area used by the current
|
// Dispose method (animation only). Indicates how the area used by the current
|
||||||
|
Loading…
Reference in New Issue
Block a user