Merge "Mux API change:"

This commit is contained in:
pascal massimino 2012-06-20 11:11:49 -07:00 committed by Gerrit Code Review
commit 8de9a0847b
8 changed files with 275 additions and 282 deletions

View File

@ -75,7 +75,7 @@ profile & XMP metadata.
int copy_data = 0; int copy_data = 0;
WebPMux* mux = WebPMuxNew(); WebPMux* mux = WebPMuxNew();
// ... (Prepare image data). // ... (Prepare image data).
WebPMuxSetImage(mux, &image, &alpha, copy_data); WebPMuxSetImage(mux, &image, copy_data);
// ... (Prepare ICCP color profile data). // ... (Prepare ICCP color profile data).
WebPMuxSetColorProfile(mux, &icc_profile, copy_data); WebPMuxSetColorProfile(mux, &icc_profile, copy_data);
// ... (Prepare XMP metadata). // ... (Prepare XMP metadata).
@ -92,7 +92,7 @@ Example#2 (pseudo code): Get image & color profile data from a WebP file.
int copy_data = 0; int copy_data = 0;
// ... (Read data from file). // ... (Read data from file).
WebPMux* mux = WebPMuxCreate(&data, copy_data); WebPMux* mux = WebPMuxCreate(&data, copy_data);
WebPMuxGetImage(mux, &image, &alpha); WebPMuxGetImage(mux, &image);
// ... (Consume image; e.g. call WebPDecode() to decode the data). // ... (Consume image; e.g. call WebPDecode() to decode the data).
WebPMuxGetColorProfile(mux, &icc_profile); WebPMuxGetColorProfile(mux, &icc_profile);
// ... (Consume icc_profile). // ... (Consume icc_profile).

View File

@ -162,7 +162,7 @@ static int Decode(const int frame_number, uint32_t* const duration) {
ClearPreviousPic(); ClearPreviousPic();
if (kParams.has_animation) { if (kParams.has_animation) {
if (WebPMuxGetFrame(kParams.mux, frame_number, &image_data, NULL, if (WebPMuxGetFrame(kParams.mux, frame_number, &image_data,
&x_off, &y_off, duration) != WEBP_MUX_OK) { &x_off, &y_off, duration) != WEBP_MUX_OK) {
goto end; goto end;
} }

View File

@ -120,21 +120,6 @@ static int IsNotCompatible(int count1, int count2) {
return (count1 > 0) != (count2 > 0); return (count1 > 0) != (count2 > 0);
} }
// Allocate necessary storage for dst then copy the contents of src.
// Returns 1 on success.
static int WebPDataCopy(const WebPData* const src, WebPData* const dst) {
if (src == NULL || dst == NULL) return 0;
memset(dst, 0, sizeof(*dst));
if (src->bytes_ != NULL && src->size_ != 0) {
dst->bytes_ = (uint8_t*)malloc(src->size_);
if (dst->bytes_ == NULL) return 0;
memcpy((void*)dst->bytes_, src->bytes_, src->size_);
dst->size_ = src->size_;
}
return 1;
}
#define RETURN_IF_ERROR(ERR_MSG) \ #define RETURN_IF_ERROR(ERR_MSG) \
if (err != WEBP_MUX_OK) { \ if (err != WEBP_MUX_OK) { \
fprintf(stderr, ERR_MSG); \ fprintf(stderr, ERR_MSG); \
@ -202,17 +187,15 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
if (nFrames > 0) { if (nFrames > 0) {
int i; int i;
printf("No.: x_offset y_offset duration image_size"); printf("No.: x_offset y_offset duration image_size");
if (flag & ALPHA_FLAG) printf(" alpha_size");
printf("\n"); printf("\n");
for (i = 1; i <= nFrames; i++) { for (i = 1; i <= nFrames; i++) {
uint32_t x_offset, y_offset, duration; uint32_t x_offset, y_offset, duration;
WebPData image, alpha; WebPData bitstream;
err = WebPMuxGetFrame(mux, i, &image, &alpha, err = WebPMuxGetFrame(mux, i, &bitstream,
&x_offset, &y_offset, &duration); &x_offset, &y_offset, &duration);
RETURN_IF_ERROR2("Failed to retrieve frame#%d\n", i); RETURN_IF_ERROR2("Failed to retrieve frame#%d\n", i);
printf("%3d: %8d %8d %8d %10zu", printf("%3d: %8d %8d %8d %10zu",
i, x_offset, y_offset, duration, image.size_); i, x_offset, y_offset, duration, bitstream.size_);
if (flag & ALPHA_FLAG) printf(" %10zu", alpha.size_);
printf("\n"); printf("\n");
} }
} }
@ -227,16 +210,13 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
if (nTiles > 0) { if (nTiles > 0) {
int i; int i;
printf("No.: x_offset y_offset image_size"); printf("No.: x_offset y_offset image_size");
if (flag & ALPHA_FLAG) printf(" alpha_size");
printf("\n"); printf("\n");
for (i = 1; i <= nTiles; i++) { for (i = 1; i <= nTiles; i++) {
uint32_t x_offset, y_offset; uint32_t x_offset, y_offset;
WebPData image, alpha; WebPData bitstream;
err = WebPMuxGetTile(mux, i, &image, &alpha, &x_offset, &y_offset); err = WebPMuxGetTile(mux, i, &bitstream, &x_offset, &y_offset);
RETURN_IF_ERROR2("Failed to retrieve tile#%d\n", i); RETURN_IF_ERROR2("Failed to retrieve tile#%d\n", i);
printf("%3d: %8d %8d %10zu", printf("%3d: %8d %8d %10zu", i, x_offset, y_offset, bitstream.size_);
i, x_offset, y_offset, image.size_);
if (flag & ALPHA_FLAG) printf(" %10zu", alpha.size_);
printf("\n"); printf("\n");
} }
} }
@ -257,10 +237,10 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
} }
if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | TILE_FLAG))) { if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | TILE_FLAG))) {
WebPData image, alpha; WebPData bitstream;
err = WebPMuxGetImage(mux, &image, &alpha); err = WebPMuxGetImage(mux, &bitstream);
RETURN_IF_ERROR("Failed to retrieve the image\n"); RETURN_IF_ERROR("Failed to retrieve the image\n");
printf("Size of the alpha data: %zu\n", alpha.size_); printf("Size of the image (with alpha): %zu\n", bitstream.size_);
} }
return WEBP_MUX_OK; return WEBP_MUX_OK;
@ -335,39 +315,6 @@ static int CreateMux(const char* const filename, WebPMux** mux) {
return 0; return 0;
} }
static int ReadImage(const char* filename,
WebPData* const image_ptr, WebPData* const alpha_ptr) {
WebPData bitstream, image, alpha;
WebPMux* mux;
WebPMuxError err;
int ok = 0;
if (!ReadFileToWebPData(filename, &bitstream)) return 0;
mux = WebPMuxCreate(&bitstream, 1);
free((void*)bitstream.bytes_);
if (mux == NULL) {
fprintf(stderr, "Failed to create mux object from file %s.\n", filename);
return 0;
}
err = WebPMuxGetImage(mux, &image, &alpha);
if (err == WEBP_MUX_OK) {
ok = 1;
ok &= WebPDataCopy(&image, image_ptr);
ok &= WebPDataCopy(&alpha, alpha_ptr);
if (!ok) {
fprintf(stderr, "Error allocating storage for image (%zu bytes) "
"and alpha (%zu bytes) data\n", image.size_, alpha.size_);
WebPDataClear(image_ptr);
WebPDataClear(alpha_ptr);
}
} else {
fprintf(stderr, "Failed to extract image data from file %s. Error: %d\n",
filename, err);
}
WebPMuxDelete(mux);
return ok;
}
static int WriteData(const char* filename, const WebPData* const webpdata) { static int WriteData(const char* filename, const WebPData* const webpdata) {
int ok = 0; int ok = 0;
FILE* fout = strcmp(filename, "-") ? fopen(filename, "wb") : stdout; FILE* fout = strcmp(filename, "-") ? fopen(filename, "wb") : stdout;
@ -731,7 +678,7 @@ static int InitializeConfig(int argc, const char* argv[],
static int GetFrameTile(const WebPMux* mux, static int GetFrameTile(const WebPMux* mux,
const WebPMuxConfig* config, int isFrame) { const WebPMuxConfig* config, int isFrame) {
WebPData image, alpha; WebPData bitstream;
uint32_t x_offset = 0; uint32_t x_offset = 0;
uint32_t y_offset = 0; uint32_t y_offset = 0;
uint32_t duration = 0; uint32_t duration = 0;
@ -746,13 +693,13 @@ static int GetFrameTile(const WebPMux* mux,
} }
if (isFrame) { if (isFrame) {
err = WebPMuxGetFrame(mux, num, &image, &alpha, err = WebPMuxGetFrame(mux, num, &bitstream,
&x_offset, &y_offset, &duration); &x_offset, &y_offset, &duration);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR#%d: Could not get frame %ld.\n", err, num, ErrGet); ERROR_GOTO3("ERROR#%d: Could not get frame %ld.\n", err, num, ErrGet);
} }
} else { } else {
err = WebPMuxGetTile(mux, num, &image, &alpha, &x_offset, &y_offset); err = WebPMuxGetTile(mux, num, &bitstream, &x_offset, &y_offset);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR#%d: Could not get frame %ld.\n", err, num, ErrGet); ERROR_GOTO3("ERROR#%d: Could not get frame %ld.\n", err, num, ErrGet);
} }
@ -763,7 +710,7 @@ static int GetFrameTile(const WebPMux* mux,
err = WEBP_MUX_MEMORY_ERROR; err = WEBP_MUX_MEMORY_ERROR;
ERROR_GOTO2("ERROR#%d: Could not allocate a mux object.\n", err, ErrGet); ERROR_GOTO2("ERROR#%d: Could not allocate a mux object.\n", err, ErrGet);
} }
err = WebPMuxSetImage(mux_single, &image, &alpha, 1); err = WebPMuxSetImage(mux_single, &bitstream, 1);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO2("ERROR#%d: Could not create single image mux object.\n", err, ERROR_GOTO2("ERROR#%d: Could not create single image mux object.\n", err,
ErrGet); ErrGet);
@ -840,21 +787,19 @@ static int Process(const WebPMuxConfig* config) {
ERROR_GOTO2("ERROR#%d: Could not set loop count.\n", err, Err2); ERROR_GOTO2("ERROR#%d: Could not set loop count.\n", err, Err2);
} }
} else if (feature->args_[index].subtype_ == SUBTYPE_FRM) { } else if (feature->args_[index].subtype_ == SUBTYPE_FRM) {
WebPData image, alpha;
uint32_t duration; uint32_t duration;
ok = ReadImage(feature->args_[index].filename_, &image, &alpha); ok = ReadFileToWebPData(feature->args_[index].filename_,
&webpdata);
if (!ok) goto Err2; if (!ok) goto Err2;
ok = ParseFrameArgs(feature->args_[index].params_, ok = ParseFrameArgs(feature->args_[index].params_,
&x_offset, &y_offset, &duration); &x_offset, &y_offset, &duration);
if (!ok) { if (!ok) {
WebPDataClear(&image); WebPDataClear(&webpdata);
WebPDataClear(&alpha);
ERROR_GOTO1("ERROR: Could not parse frame properties.\n", Err2); ERROR_GOTO1("ERROR: Could not parse frame properties.\n", Err2);
} }
err = WebPMuxSetFrame(mux, 0, &image, &alpha, err = WebPMuxSetFrame(mux, 0, &webpdata, x_offset, y_offset,
x_offset, y_offset, duration, 1); duration, 1);
WebPDataClear(&image); WebPDataClear(&webpdata);
WebPDataClear(&alpha);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR#%d: Could not add a frame at index %d.\n", ERROR_GOTO3("ERROR#%d: Could not add a frame at index %d.\n",
err, index, Err2); err, index, Err2);
@ -872,19 +817,16 @@ static int Process(const WebPMuxConfig* config) {
WEBP_MUX_MEMORY_ERROR, Err2); WEBP_MUX_MEMORY_ERROR, Err2);
} }
for (index = 0; index < feature->arg_count_; ++index) { for (index = 0; index < feature->arg_count_; ++index) {
WebPData image, alpha; ok = ReadFileToWebPData(feature->args_[index].filename_, &webpdata);
ok = ReadImage(feature->args_[index].filename_, &image, &alpha);
if (!ok) goto Err2; if (!ok) goto Err2;
ok = ParseTileArgs(feature->args_[index].params_, &x_offset, ok = ParseTileArgs(feature->args_[index].params_, &x_offset,
&y_offset); &y_offset);
if (!ok) { if (!ok) {
WebPDataClear(&image); WebPDataClear(&webpdata);
WebPDataClear(&alpha);
ERROR_GOTO1("ERROR: Could not parse tile properties.\n", Err2); ERROR_GOTO1("ERROR: Could not parse tile properties.\n", Err2);
} }
err = WebPMuxSetTile(mux, 0, &image, &alpha, x_offset, y_offset, 1); err = WebPMuxSetTile(mux, 0, &webpdata, x_offset, y_offset, 1);
WebPDataClear(&image); WebPDataClear(&webpdata);
WebPDataClear(&alpha);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR#%d: Could not add a tile at index %d.\n", ERROR_GOTO3("ERROR#%d: Could not add a tile at index %d.\n",
err, index, Err2); err, index, Err2);

View File

@ -167,27 +167,32 @@ static WebPMuxError CreateDataFromImageInfo(const WebPImageInfo* image_info,
return WEBP_MUX_OK; return WEBP_MUX_OK;
} }
// Outputs image data given data from a webp file (including RIFF header). // Outputs image data given a bitstream. The bitstream can either be a
// single-image WebP file or raw VP8/VP8L data.
// Also outputs 'is_lossless' to be true if the given bitstream is lossless. // Also outputs 'is_lossless' to be true if the given bitstream is lossless.
static WebPMuxError GetImageData(const WebPData* const bitstream, static WebPMuxError GetImageData(const WebPData* const bitstream,
WebPData* const image, WebPData* const alpha, WebPData* const image, WebPData* const alpha,
int* const is_lossless) { int* const is_lossless) {
memset(alpha, 0, sizeof(*alpha)); // Default: no alpha.
if (bitstream->size_ < TAG_SIZE || if (bitstream->size_ < TAG_SIZE ||
memcmp(bitstream->bytes_, "RIFF", TAG_SIZE)) { memcmp(bitstream->bytes_, "RIFF", TAG_SIZE)) {
// It is NOT webp file data. Return input data as is. // It is NOT webp file data. Return input data as is.
*image = *bitstream; *image = *bitstream;
*is_lossless = VP8LCheckSignature(image->bytes_, image->size_);
return WEBP_MUX_OK;
} else { } else {
// It is webp file data. Extract image data from it. // It is webp file data. Extract image data from it.
WebPMuxError err; const WebPMuxImage* wpi;
WebPMux* const mux = WebPMuxCreate(bitstream, 0); WebPMux* const mux = WebPMuxCreate(bitstream, 0);
if (mux == NULL) return WEBP_MUX_BAD_DATA; if (mux == NULL) return WEBP_MUX_BAD_DATA;
err = WebPMuxGetImage(mux, image, alpha); wpi = mux->images_;
assert(wpi != NULL && wpi->img_ != NULL);
*image = wpi->img_->data_;
if (wpi->alpha_ != NULL) {
*alpha = wpi->alpha_->data_;
}
WebPMuxDelete(mux); WebPMuxDelete(mux);
*is_lossless = VP8LCheckSignature(image->bytes_, image->size_);
return err;
} }
*is_lossless = VP8LCheckSignature(image->bytes_, image->size_);
return WEBP_MUX_OK;
} }
static WebPMuxError DeleteChunks(WebPChunk** chunk_list, uint32_t tag) { static WebPMuxError DeleteChunks(WebPChunk** chunk_list, uint32_t tag) {
@ -226,25 +231,23 @@ static WebPMuxError DeleteLoopCount(WebPMux* const mux) {
// Set API(s). // Set API(s).
WebPMuxError WebPMuxSetImage(WebPMux* const mux, WebPMuxError WebPMuxSetImage(WebPMux* const mux,
const WebPData* const image, const WebPData* const bitstream, int copy_data) {
const WebPData* const alpha,
int copy_data) {
WebPMuxError err; WebPMuxError err;
WebPChunk chunk; WebPChunk chunk;
WebPMuxImage wpi; WebPMuxImage wpi;
WebPData image_raw; WebPData image;
const int has_alpha = (alpha != NULL && alpha->bytes_ != NULL); WebPData alpha;
int is_lossless; int is_lossless;
int image_tag; int image_tag;
if (mux == NULL || image == NULL || image->bytes_ == NULL || if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL ||
image->size_ > MAX_CHUNK_PAYLOAD) { bitstream->size_ > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
// If given data is for a whole webp file, // If given data is for a whole webp file,
// extract only the VP8/VP8L data from it. // extract only the VP8/VP8L data from it.
err = GetImageData(image, &image_raw, NULL, &is_lossless); err = GetImageData(bitstream, &image, &alpha, &is_lossless);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) return err;
image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag;
@ -253,25 +256,34 @@ WebPMuxError WebPMuxSetImage(WebPMux* const mux,
MuxImageInit(&wpi); MuxImageInit(&wpi);
if (has_alpha) { // Add alpha chunk. if (alpha.bytes_ != NULL) { // Add alpha chunk.
ChunkInit(&chunk); ChunkInit(&chunk);
err = ChunkAssignDataImageInfo(&chunk, alpha, NULL, copy_data, err = ChunkAssignDataImageInfo(&chunk, &alpha, NULL, copy_data,
kChunks[IDX_ALPHA].tag); kChunks[IDX_ALPHA].tag);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) goto Err;
err = ChunkSetNth(&chunk, &wpi.alpha_, 1); err = ChunkSetNth(&chunk, &wpi.alpha_, 1);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) goto Err;
} }
// Add image chunk. // Add image chunk.
ChunkInit(&chunk); ChunkInit(&chunk);
err = ChunkAssignDataImageInfo(&chunk, &image_raw, NULL, copy_data, err = ChunkAssignDataImageInfo(&chunk, &image, NULL, copy_data, image_tag);
image_tag); if (err != WEBP_MUX_OK) goto Err;
if (err != WEBP_MUX_OK) return err;
err = ChunkSetNth(&chunk, &wpi.img_, 1); err = ChunkSetNth(&chunk, &wpi.img_, 1);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) goto Err;
// Add this image to mux. // Add this image to mux.
return MuxImageSetNth(&wpi, &mux->images_, 1); err = MuxImageSetNth(&wpi, &mux->images_, 1);
if (err != WEBP_MUX_OK) goto Err;
// All OK.
return WEBP_MUX_OK;
Err:
// Something bad happened.
ChunkRelease(&chunk);
MuxImageRelease(&wpi);
return err;
} }
WebPMuxError WebPMuxSetMetadata(WebPMux* const mux, WebPMuxError WebPMuxSetMetadata(WebPMux* const mux,
@ -332,12 +344,12 @@ WebPMuxError WebPMuxSetLoopCount(WebPMux* const mux, uint32_t loop_count) {
} }
static WebPMuxError MuxSetFrameTileInternal( static WebPMuxError MuxSetFrameTileInternal(
WebPMux* const mux, uint32_t nth, WebPMux* const mux, uint32_t nth, const WebPData* const bitstream,
const WebPData* const image, const WebPData* const alpha,
uint32_t x_offset, uint32_t y_offset, uint32_t duration, uint32_t x_offset, uint32_t y_offset, uint32_t duration,
int copy_data, uint32_t tag) { int copy_data, uint32_t tag) {
WebPChunk chunk; WebPChunk chunk;
WebPData image_raw; WebPData image;
WebPData alpha;
WebPMuxImage wpi; WebPMuxImage wpi;
WebPMuxError err; WebPMuxError err;
WebPImageInfo* image_info = NULL; WebPImageInfo* image_info = NULL;
@ -345,44 +357,43 @@ static WebPMuxError MuxSetFrameTileInternal(
size_t frame_tile_size = 0; size_t frame_tile_size = 0;
WebPData frame_tile; WebPData frame_tile;
const int is_frame = (tag == kChunks[IDX_FRAME].tag) ? 1 : 0; const int is_frame = (tag == kChunks[IDX_FRAME].tag) ? 1 : 0;
const int has_alpha = (alpha != NULL && alpha->bytes_ != NULL);
int is_lossless; int is_lossless;
int image_tag; int image_tag;
if (mux == NULL || image == NULL || image->bytes_ == NULL || if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL ||
image->size_ > MAX_CHUNK_PAYLOAD) { bitstream->size_ > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
// If given data is for a whole webp file, // If given data is for a whole webp file,
// extract only the VP8/VP8L data from it. // extract only the VP8/VP8L data from it.
err = GetImageData(image, &image_raw, NULL, &is_lossless); err = GetImageData(bitstream, &image, &alpha, &is_lossless);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) return err;
image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag;
ChunkInit(&chunk); ChunkInit(&chunk);
MuxImageInit(&wpi); MuxImageInit(&wpi);
if (has_alpha) { if (alpha.bytes_ != NULL) {
// Add alpha chunk. // Add alpha chunk.
err = ChunkAssignDataImageInfo(&chunk, alpha, NULL, copy_data, err = ChunkAssignDataImageInfo(&chunk, &alpha, NULL, copy_data,
kChunks[IDX_ALPHA].tag); kChunks[IDX_ALPHA].tag);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) goto Err;
err = ChunkSetNth(&chunk, &wpi.alpha_, 1); err = ChunkSetNth(&chunk, &wpi.alpha_, 1);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) goto Err;
ChunkInit(&chunk); // chunk owned by wpi.alpha_ now. ChunkInit(&chunk); // chunk owned by wpi.alpha_ now.
} }
// Create image_info object. // Create image_info object.
image_info = CreateImageInfo(x_offset, y_offset, duration, &image_raw, image_info = CreateImageInfo(x_offset, y_offset, duration, &image,
is_lossless); is_lossless);
if (image_info == NULL) { if (image_info == NULL) {
MuxImageRelease(&wpi); err = WEBP_MUX_MEMORY_ERROR;
return WEBP_MUX_MEMORY_ERROR; goto Err;
} }
// Add image chunk. // Add image chunk.
err = ChunkAssignDataImageInfo(&chunk, &image_raw, image_info, copy_data, err = ChunkAssignDataImageInfo(&chunk, &image, image_info, copy_data,
image_tag); image_tag);
if (err != WEBP_MUX_OK) goto Err; if (err != WEBP_MUX_OK) goto Err;
image_info = NULL; // Owned by 'chunk' now. image_info = NULL; // Owned by 'chunk' now.
@ -424,23 +435,20 @@ static WebPMuxError MuxSetFrameTileInternal(
// TODO(urvang): Think about whether we need 'nth' while adding a frame or tile. // TODO(urvang): Think about whether we need 'nth' while adding a frame or tile.
WebPMuxError WebPMuxSetFrame(WebPMux* const mux, uint32_t nth, WebPMuxError WebPMuxSetFrame(WebPMux* const mux, uint32_t nth,
const WebPData* const image, const WebPData* const bitstream,
const WebPData* const alpha,
uint32_t x_offset, uint32_t y_offset, uint32_t x_offset, uint32_t y_offset,
uint32_t duration, int copy_data) { uint32_t duration, int copy_data) {
return MuxSetFrameTileInternal(mux, nth, image, alpha, return MuxSetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset,
x_offset, y_offset, duration, duration, copy_data, kChunks[IDX_FRAME].tag);
copy_data, kChunks[IDX_FRAME].tag);
} }
WebPMuxError WebPMuxSetTile(WebPMux* const mux, uint32_t nth, WebPMuxError WebPMuxSetTile(WebPMux* const mux, uint32_t nth,
const WebPData* const image, const WebPData* const bitstream,
const WebPData* const alpha,
uint32_t x_offset, uint32_t y_offset, uint32_t x_offset, uint32_t y_offset,
int copy_data) { int copy_data) {
return MuxSetFrameTileInternal(mux, nth, image, alpha, return MuxSetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset,
x_offset, y_offset, 1, 1 /* unused duration*/, copy_data,
copy_data, kChunks[IDX_TILE].tag); kChunks[IDX_TILE].tag);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -487,17 +495,17 @@ WebPMuxError WebPMuxDeleteTile(WebPMux* const mux, uint32_t nth) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Assembly of the WebP RIFF file. // Assembly of the WebP RIFF file.
static WebPMuxError GetImageWidthHeight(const WebPChunk* const image_chunk, WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk,
int* const width, int* const height) { int* const width, int* const height) {
const uint32_t tag = image_chunk->tag_; const uint32_t tag = image_chunk->tag_;
const WebPData* const data = &image_chunk->data_;
int w, h; int w, h;
int ok; int ok;
assert(image_chunk != NULL); assert(image_chunk != NULL);
assert(tag == kChunks[IDX_VP8].tag || tag == kChunks[IDX_VP8L].tag); assert(tag == kChunks[IDX_VP8].tag || tag == kChunks[IDX_VP8L].tag);
ok = (tag == kChunks[IDX_VP8].tag) ? ok = (tag == kChunks[IDX_VP8].tag) ?
VP8GetInfo(image_chunk->data_, image_chunk->payload_size_, VP8GetInfo(data->bytes_, data->size_, data->size_, &w, &h) :
image_chunk->payload_size_, &w, &h) : VP8LGetInfo(data->bytes_, data->size_, &w, &h, NULL);
VP8LGetInfo(image_chunk->data_, image_chunk->payload_size_, &w, &h, NULL);
if (ok) { if (ok) {
*width = w; *width = w;
*height = h; *height = h;
@ -555,7 +563,7 @@ static WebPMuxError GetImageCanvasWidthHeight(
// For a single image, extract the width & height from VP8/VP8L image-data. // For a single image, extract the width & height from VP8/VP8L image-data.
int w, h; int w, h;
const WebPChunk* const image_chunk = wpi->img_; const WebPChunk* const image_chunk = wpi->img_;
const WebPMuxError err = GetImageWidthHeight(image_chunk, &w, &h); const WebPMuxError err = MuxGetImageWidthHeight(image_chunk, &w, &h);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) return err;
*width = w; *width = w;
*height = h; *height = h;
@ -579,7 +587,8 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
assert(mux != NULL); assert(mux != NULL);
images = mux->images_; // First image. images = mux->images_; // First image.
if (images == NULL || images->img_ == NULL || images->img_->data_ == NULL) { if (images == NULL || images->img_ == NULL ||
images->img_->data_.bytes_ == NULL) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
@ -589,11 +598,11 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
// Set flags. // Set flags.
if (mux->iccp_ != NULL && mux->iccp_->data_ != NULL) { if (mux->iccp_ != NULL && mux->iccp_->data_.bytes_ != NULL) {
flags |= ICCP_FLAG; flags |= ICCP_FLAG;
} }
if (mux->meta_ != NULL && mux->meta_->data_ != NULL) { if (mux->meta_ != NULL && mux->meta_->data_.bytes_ != NULL) {
flags |= META_FLAG; flags |= META_FLAG;
} }
@ -607,7 +616,7 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
} }
} }
if (images->alpha_ != NULL && images->alpha_->data_ != NULL) { if (images->alpha_ != NULL && images->alpha_->data_.bytes_ != NULL) {
// This is an image with alpha channel. // This is an image with alpha channel.
flags |= ALPHA_FLAG; flags |= ALPHA_FLAG;
} }
@ -674,14 +683,8 @@ WebPMuxError WebPMuxAssemble(WebPMux* const mux,
data = (uint8_t*)malloc(size); data = (uint8_t*)malloc(size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR; if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
// Main RIFF header. // Emit header & chunks.
PutLE32(data + 0, mktag('R', 'I', 'F', 'F')); dst = MuxEmitRiffHeader(data, size);
PutLE32(data + TAG_SIZE, (uint32_t)size - CHUNK_HEADER_SIZE);
assert(size == (uint32_t)size);
PutLE32(data + TAG_SIZE + CHUNK_SIZE_BYTES, mktag('W', 'E', 'B', 'P'));
// Chunks.
dst = data + RIFF_HEADER_SIZE;
dst = ChunkListEmit(mux->vp8x_, dst); dst = ChunkListEmit(mux->vp8x_, dst);
dst = ChunkListEmit(mux->iccp_, dst); dst = ChunkListEmit(mux->iccp_, dst);
dst = ChunkListEmit(mux->loop_, dst); dst = ChunkListEmit(mux->loop_, dst);

View File

@ -38,12 +38,11 @@ typedef struct {
typedef struct WebPChunk WebPChunk; typedef struct WebPChunk WebPChunk;
struct WebPChunk { struct WebPChunk {
uint32_t tag_; uint32_t tag_;
size_t payload_size_;
WebPImageInfo* image_info_; WebPImageInfo* image_info_;
int owner_; // True if *data_ memory is owned internally. int owner_; // True if *data_ memory is owned internally.
// VP8X, Loop, and other internally created chunks // VP8X, Loop, and other internally created chunks
// like frame/tile are always owned. // like frame/tile are always owned.
const uint8_t* data_; WebPData data_;
WebPChunk* next_; WebPChunk* next_;
}; };
@ -158,8 +157,9 @@ WebPChunk* ChunkDelete(WebPChunk* const chunk);
// Size of a chunk including header and padding. // Size of a chunk including header and padding.
static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) { static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) {
assert(chunk->payload_size_ < MAX_CHUNK_PAYLOAD); const size_t data_size = chunk->data_.size_;
return SizeWithPadding(chunk->payload_size_); assert(data_size < MAX_CHUNK_PAYLOAD);
return SizeWithPadding(data_size);
} }
// Total size of a list of chunks. // Total size of a list of chunks.
@ -168,6 +168,10 @@ size_t ChunksListDiskSize(const WebPChunk* chunk_list);
// Write out the given list of chunks into 'dst'. // Write out the given list of chunks into 'dst'.
uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst); uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst);
// Get the width & height of image stored in 'image_chunk'.
WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk,
int* const width, int* const height);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// MuxImage object management. // MuxImage object management.
@ -224,17 +228,26 @@ WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth,
WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth, WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth,
WebPChunkId id, WebPMuxImage** wpi); WebPChunkId id, WebPMuxImage** wpi);
// Total size of the given image.
size_t MuxImageDiskSize(const WebPMuxImage* const wpi);
// Total size of a list of images. // Total size of a list of images.
size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list); size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list);
// Write out the given image into 'dst'.
uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst);
// Write out the given list of images into 'dst'. // Write out the given list of images into 'dst'.
uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst); uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst);
//------------------------------------------------------------------------------
// Helper methods for mux.
// Checks if the given image list contains at least one lossless image. // Checks if the given image list contains at least one lossless image.
int MuxHasLosslessImages(const WebPMuxImage* images); int MuxHasLosslessImages(const WebPMuxImage* images);
//------------------------------------------------------------------------------ // Write out RIFF header into 'data', given total data size 'size'.
// Helper methods for mux. uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size);
// Returns the list where chunk with given ID is to be inserted in mux. // Returns the list where chunk with given ID is to be inserted in mux.
// Return value is NULL if this chunk should be inserted in mux->images_ list // Return value is NULL if this chunk should be inserted in mux->images_ list

View File

@ -48,7 +48,7 @@ WebPChunk* ChunkRelease(WebPChunk* const chunk) {
if (chunk == NULL) return NULL; if (chunk == NULL) return NULL;
free(chunk->image_info_); free(chunk->image_info_);
if (chunk->owner_) { if (chunk->owner_) {
free((void*)chunk->data_); WebPDataClear(&chunk->data_);
} }
next = chunk->next_; next = chunk->next_;
ChunkInit(chunk); ChunkInit(chunk);
@ -136,17 +136,16 @@ WebPMuxError ChunkAssignDataImageInfo(WebPChunk* chunk,
if (data != NULL) { if (data != NULL) {
if (copy_data) { if (copy_data) {
// Copy data. // Copy data.
chunk->data_ = (uint8_t*)malloc(data->size_); chunk->data_.bytes_ = (uint8_t*)malloc(data->size_);
if (chunk->data_ == NULL) return WEBP_MUX_MEMORY_ERROR; if (chunk->data_.bytes_ == NULL) return WEBP_MUX_MEMORY_ERROR;
memcpy((uint8_t*)chunk->data_, data->bytes_, data->size_); memcpy((uint8_t*)chunk->data_.bytes_, data->bytes_, data->size_);
chunk->payload_size_ = data->size_; chunk->data_.size_ = data->size_;
// Chunk is owner of data. // Chunk is owner of data.
chunk->owner_ = 1; chunk->owner_ = 1;
} else { } else {
// Don't copy data. // Don't copy data.
chunk->data_ = data->bytes_; chunk->data_ = *data;
chunk->payload_size_ = data->size_;
} }
} }
@ -197,14 +196,15 @@ size_t ChunksListDiskSize(const WebPChunk* chunk_list) {
} }
static uint8_t* ChunkEmit(const WebPChunk* const chunk, uint8_t* dst) { static uint8_t* ChunkEmit(const WebPChunk* const chunk, uint8_t* dst) {
const size_t chunk_size = chunk->data_.size_;
assert(chunk); assert(chunk);
assert(chunk->tag_ != NIL_TAG); assert(chunk->tag_ != NIL_TAG);
PutLE32(dst + 0, chunk->tag_); PutLE32(dst + 0, chunk->tag_);
PutLE32(dst + TAG_SIZE, (uint32_t)chunk->payload_size_); PutLE32(dst + TAG_SIZE, (uint32_t)chunk_size);
assert(chunk->payload_size_ == (uint32_t)chunk->payload_size_); assert(chunk_size == (uint32_t)chunk_size);
memcpy(dst + CHUNK_HEADER_SIZE, chunk->data_, chunk->payload_size_); memcpy(dst + CHUNK_HEADER_SIZE, chunk->data_.bytes_, chunk_size);
if (chunk->payload_size_ & 1) if (chunk_size & 1)
dst[CHUNK_HEADER_SIZE + chunk->payload_size_] = 0; // Add padding. dst[CHUNK_HEADER_SIZE + chunk_size] = 0; // Add padding.
return dst + ChunkDiskSize(chunk); return dst + ChunkDiskSize(chunk);
} }
@ -217,7 +217,7 @@ uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Life of a WebPData object. // Manipulation of a WebPData object.
void WebPDataClear(WebPData* const webp_data) { void WebPDataClear(WebPData* const webp_data) {
if (webp_data != NULL) { if (webp_data != NULL) {
@ -226,6 +226,19 @@ void WebPDataClear(WebPData* const webp_data) {
} }
} }
int WebPDataCopy(const WebPData* const src, WebPData* const dst) {
if (src == NULL || dst == NULL) return 0;
memset(dst, 0, sizeof(*dst));
if (src->bytes_ != NULL && src->size_ != 0) {
dst->bytes_ = (uint8_t*)malloc(src->size_);
if (dst->bytes_ == NULL) return 0;
memcpy((void*)dst->bytes_, src->bytes_, src->size_);
dst->size_ = src->size_;
}
return 1;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Life of a MuxImage object. // Life of a MuxImage object.
@ -383,7 +396,7 @@ WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth,
// MuxImage serialization methods. // MuxImage serialization methods.
// Size of an image. // Size of an image.
static size_t MuxImageDiskSize(const WebPMuxImage* wpi) { size_t MuxImageDiskSize(const WebPMuxImage* const wpi) {
size_t size = 0; size_t size = 0;
if (wpi->header_ != NULL) size += ChunkDiskSize(wpi->header_); if (wpi->header_ != NULL) size += ChunkDiskSize(wpi->header_);
if (wpi->alpha_ != NULL) size += ChunkDiskSize(wpi->alpha_); if (wpi->alpha_ != NULL) size += ChunkDiskSize(wpi->alpha_);
@ -400,7 +413,7 @@ size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list) {
return size; return size;
} }
static 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. Frame/Tile chunk (if present). // 1. Frame/Tile chunk (if present).
// 2. Alpha chunk (if present). // 2. Alpha chunk (if present).
@ -420,6 +433,9 @@ uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst) {
return dst; return dst;
} }
//------------------------------------------------------------------------------
// Helper methods for mux.
int MuxHasLosslessImages(const WebPMuxImage* images) { int MuxHasLosslessImages(const WebPMuxImage* images) {
while (images != NULL) { while (images != NULL) {
assert(images->img_ != NULL); assert(images->img_ != NULL);
@ -431,8 +447,13 @@ int MuxHasLosslessImages(const WebPMuxImage* images) {
return 0; return 0;
} }
//------------------------------------------------------------------------------ uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size) {
// Helper methods for mux. PutLE32(data + 0, mktag('R', 'I', 'F', 'F'));
PutLE32(data + TAG_SIZE, (uint32_t)size - CHUNK_HEADER_SIZE);
assert(size == (uint32_t)size);
PutLE32(data + TAG_SIZE + CHUNK_SIZE_BYTES, mktag('W', 'E', 'B', 'P'));
return data + RIFF_HEADER_SIZE;
}
WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) { WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) {
assert(mux != NULL); assert(mux != NULL);

View File

@ -26,8 +26,7 @@ extern "C" {
const WebPChunk* const chunk = ChunkSearchList((LIST), nth, \ const WebPChunk* const chunk = ChunkSearchList((LIST), nth, \
kChunks[(INDEX)].tag); \ kChunks[(INDEX)].tag); \
if (chunk) { \ if (chunk) { \
data->bytes_ = chunk->data_; \ *data = chunk->data_; \
data->size_ = chunk->payload_size_; \
return WEBP_MUX_OK; \ return WEBP_MUX_OK; \
} else { \ } else { \
return WEBP_MUX_NOT_FOUND; \ return WEBP_MUX_NOT_FOUND; \
@ -199,7 +198,9 @@ WebPMuxError WebPMuxGetFeatures(const WebPMux* const mux, uint32_t* flags) {
err = MuxGet(mux, IDX_VP8X, 1, &data); err = MuxGet(mux, IDX_VP8X, 1, &data);
if (err == WEBP_MUX_NOT_FOUND) { if (err == WEBP_MUX_NOT_FOUND) {
// Check if VP8/VP8L chunk is present. // Check if VP8/VP8L chunk is present.
return WebPMuxGetImage(mux, &data, NULL); err = WebPMuxGetImage(mux, &data);
WebPDataClear(&data);
return err;
} else if (err != WEBP_MUX_OK) { } else if (err != WEBP_MUX_OK) {
return err; return err;
} }
@ -211,12 +212,64 @@ WebPMuxError WebPMuxGetFeatures(const WebPMux* const mux, uint32_t* flags) {
return WEBP_MUX_OK; return WEBP_MUX_OK;
} }
static uint8_t* EmitVP8XChunk(uint8_t* const dst, uint32_t width,
uint32_t height, uint32_t flags) {
const size_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
PutLE32(dst, mktag('V', 'P', '8', 'X'));
PutLE32(dst + TAG_SIZE, VP8X_CHUNK_SIZE);
PutLE32(dst + CHUNK_HEADER_SIZE, flags);
PutLE32(dst + CHUNK_HEADER_SIZE + 4, width);
PutLE32(dst + CHUNK_HEADER_SIZE + 8, height);
return dst + vp8x_size;
}
// Assemble a single image WebP bitstream from 'wpi'.
static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi,
WebPData* const bitstream) {
uint8_t* dst;
// Allocate data.
const int need_vp8x = (wpi->alpha_ != NULL);
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;
// Note: No need to output FRM/TILE chunk for a single image.
const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size +
ChunkDiskSize(wpi->img_);
uint8_t* const data = (uint8_t*)malloc(size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
// Main RIFF header.
dst = MuxEmitRiffHeader(data, size);
if (need_vp8x) {
int w, h;
WebPMuxError err;
assert(wpi->img_ != NULL);
err = MuxGetImageWidthHeight(wpi->img_, &w, &h);
if (err != WEBP_MUX_OK) {
free(data);
return err;
}
dst = EmitVP8XChunk(dst, w, h, ALPHA_FLAG); // VP8X.
dst = ChunkListEmit(wpi->alpha_, dst); // ALPH.
}
// Bitstream.
dst = ChunkListEmit(wpi->img_, dst);
assert(dst == data + size);
// Output.
bitstream->bytes_ = data;
bitstream->size_ = size;
return WEBP_MUX_OK;
}
WebPMuxError WebPMuxGetImage(const WebPMux* const mux, WebPMuxError WebPMuxGetImage(const WebPMux* const mux,
WebPData* const image, WebPData* const alpha) { WebPData* const bitstream) {
WebPMuxError err; WebPMuxError err;
WebPMuxImage* wpi = NULL; WebPMuxImage* wpi = NULL;
if (mux == NULL || (image == NULL && alpha == NULL)) { if (mux == NULL || bitstream == NULL) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
@ -228,24 +281,7 @@ WebPMuxError WebPMuxGetImage(const WebPMux* const mux,
&wpi); &wpi);
assert(err == WEBP_MUX_OK); // Already tested above. assert(err == WEBP_MUX_OK); // Already tested above.
// Get alpha chunk (if present & requested). return SynthesizeBitstream(wpi, bitstream);
if (alpha != NULL) {
memset(alpha, 0, sizeof(*alpha));
if (wpi->alpha_ != NULL) {
alpha->bytes_ = wpi->alpha_->data_;
alpha->size_ = wpi->alpha_->payload_size_;
}
}
// Get image chunk.
if (image != NULL) {
memset(image, 0, sizeof(*image));
if (wpi->img_ != NULL) {
image->bytes_ = wpi->img_->data_;
image->size_ = wpi->img_->payload_size_;
}
}
return WEBP_MUX_OK;
} }
WebPMuxError WebPMuxGetMetadata(const WebPMux* const mux, WebPMuxError WebPMuxGetMetadata(const WebPMux* const mux,
@ -276,11 +312,9 @@ WebPMuxError WebPMuxGetLoopCount(const WebPMux* const mux,
} }
static WebPMuxError MuxGetFrameTileInternal( static WebPMuxError MuxGetFrameTileInternal(
const WebPMux* const mux, uint32_t nth, const WebPMux* const mux, uint32_t nth, WebPData* const bitstream,
WebPData* const image, WebPData* const alpha,
uint32_t* x_offset, uint32_t* y_offset, uint32_t* duration, uint32_t tag) { uint32_t* x_offset, uint32_t* y_offset, uint32_t* duration, uint32_t tag) {
const uint8_t* frame_tile_data; const WebPData* frame_tile_data;
size_t frame_tile_size;
WebPMuxError err; WebPMuxError err;
WebPMuxImage* wpi; WebPMuxImage* wpi;
@ -288,7 +322,7 @@ static WebPMuxError MuxGetFrameTileInternal(
const CHUNK_INDEX idx = is_frame ? IDX_FRAME : IDX_TILE; const CHUNK_INDEX idx = is_frame ? IDX_FRAME : IDX_TILE;
const WebPChunkId id = kChunks[idx].id; const WebPChunkId id = kChunks[idx].id;
if (mux == NULL || image == NULL || if (mux == NULL || bitstream == NULL ||
x_offset == NULL || y_offset == NULL || (is_frame && duration == NULL)) { x_offset == NULL || y_offset == NULL || (is_frame && duration == NULL)) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
@ -298,47 +332,30 @@ static WebPMuxError MuxGetFrameTileInternal(
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) return err;
// Get frame chunk. // Get frame chunk.
assert(wpi->header_ != NULL); // As GetNthImage() already checked header_. assert(wpi->header_ != NULL); // As MuxImageGetNth() already checked header_.
frame_tile_data = wpi->header_->data_; frame_tile_data = &wpi->header_->data_;
frame_tile_size = wpi->header_->payload_size_;
if (frame_tile_size < kChunks[idx].size) return WEBP_MUX_BAD_DATA; if (frame_tile_data->size_ < kChunks[idx].size) return WEBP_MUX_BAD_DATA;
*x_offset = GetLE32(frame_tile_data + 0); *x_offset = GetLE32(frame_tile_data->bytes_ + 0);
*y_offset = GetLE32(frame_tile_data + 4); *y_offset = GetLE32(frame_tile_data->bytes_ + 4);
if (is_frame) *duration = GetLE32(frame_tile_data + 16); if (is_frame) *duration = GetLE32(frame_tile_data->bytes_ + 16);
// Get alpha chunk (if present & requested). return SynthesizeBitstream(wpi, bitstream);
if (alpha != NULL) {
memset(alpha, 0, sizeof(*alpha));
if (wpi->alpha_ != NULL) {
alpha->bytes_ = wpi->alpha_->data_;
alpha->size_ = wpi->alpha_->payload_size_;
}
}
// Get image chunk.
memset(image, 0, sizeof(*image));
if (wpi->img_ != NULL) {
image->bytes_ = wpi->img_->data_;
image->size_ = wpi->img_->payload_size_;
}
return WEBP_MUX_OK;
} }
WebPMuxError WebPMuxGetFrame(const WebPMux* const mux, uint32_t nth, WebPMuxError WebPMuxGetFrame(const WebPMux* const mux, uint32_t nth,
WebPData* const image, WebPData* const alpha, WebPData* const bitstream,
uint32_t* x_offset, uint32_t* y_offset, uint32_t* x_offset, uint32_t* y_offset,
uint32_t* duration) { uint32_t* duration) {
return MuxGetFrameTileInternal(mux, nth, image, alpha, return MuxGetFrameTileInternal(mux, nth, bitstream,
x_offset, y_offset, duration, x_offset, y_offset, duration,
kChunks[IDX_FRAME].tag); kChunks[IDX_FRAME].tag);
} }
WebPMuxError WebPMuxGetTile(const WebPMux* const mux, uint32_t nth, WebPMuxError WebPMuxGetTile(const WebPMux* const mux, uint32_t nth,
WebPData* const image, WebPData* const alpha, WebPData* const bitstream,
uint32_t* x_offset, uint32_t* y_offset) { uint32_t* x_offset, uint32_t* y_offset) {
return MuxGetFrameTileInternal(mux, nth, image, alpha, return MuxGetFrameTileInternal(mux, nth, bitstream,
x_offset, y_offset, NULL, x_offset, y_offset, NULL,
kChunks[IDX_TILE].tag); kChunks[IDX_TILE].tag);
} }

View File

@ -11,14 +11,15 @@
// 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, XMP metadata, Animation & Tiling. // like Color profile, XMP metadata, Animation and Tiling.
// //
// Code Example#1: Creating a MUX with image data, color profile & XMP metadata. // Code Example#1: Creating a MUX with image data, color profile and XMP
// metadata.
// //
// int copy_data = 0; // int copy_data = 0;
// WebPMux* mux = WebPMuxNew(); // WebPMux* mux = WebPMuxNew();
// // ... (Prepare image data). // // ... (Prepare image data).
// WebPMuxSetImage(mux, &image, &alpha, copy_data); // WebPMuxSetImage(mux, &image, copy_data);
// // ... (Prepare ICCP color profile data). // // ... (Prepare ICCP color profile data).
// WebPMuxSetColorProfile(mux, &icc_profile, copy_data); // WebPMuxSetColorProfile(mux, &icc_profile, copy_data);
// // ... (Prepare XMP metadata). // // ... (Prepare XMP metadata).
@ -29,12 +30,12 @@
// // ... (Consume output_data; e.g. write output_data.bytes_ to file). // // ... (Consume output_data; e.g. write output_data.bytes_ to file).
// WebPDataClear(&output_data); // WebPDataClear(&output_data);
// //
// Code Example#2: Get image & color profile data from a WebP file. // Code Example#2: Get image and color profile data from a WebP file.
// //
// int copy_data = 0; // int copy_data = 0;
// // ... (Read data from file). // // ... (Read data from file).
// WebPMux* mux = WebPMuxCreate(&data, copy_data); // WebPMux* mux = WebPMuxCreate(&data, copy_data);
// WebPMuxGetImage(mux, &image, &alpha); // WebPMuxGetImage(mux, &image);
// // ... (Consume image; e.g. call WebPDecode() to decode the data). // // ... (Consume image; e.g. call WebPDecode() to decode the data).
// WebPMuxGetColorProfile(mux, &icc_profile); // WebPMuxGetColorProfile(mux, &icc_profile);
// // ... (Consume icc_data). // // ... (Consume icc_data).
@ -97,12 +98,16 @@ typedef struct {
} WebPData; } WebPData;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Life of a WebPData object. // Manipulation of a WebPData object.
// Clears the contents of the 'webp_data' object by calling free(). Does not // Clears the contents of the 'webp_data' object by calling free(). Does not
// deallocate the object itself. // deallocate the object itself.
WEBP_EXTERN(void) WebPDataClear(WebPData* const webp_data); WEBP_EXTERN(void) WebPDataClear(WebPData* const webp_data);
// Allocates necessary storage for 'dst' and copies the contents of 'src'.
// Returns true on success.
WEBP_EXTERN(int) WebPDataCopy(const WebPData* const src, WebPData* const dst);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Life of a Mux object // Life of a Mux object
@ -147,34 +152,31 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* const bitstream,
// will be removed. // 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
// image - (in) the image data. The data can be either a VP8/VP8L // bitstream - (in) can either be a raw VP8/VP8L bitstream or a single-image
// bitstream or a single-image WebP file (non-animated & non-tiled) // WebP file (non-animated and non-tiled)
// alpha - (in) the alpha data of the image (if present)
// copy_data - (in) value 1 indicates given data WILL copied to the mux, and // copy_data - (in) value 1 indicates given data WILL copied to the mux, and
// value 0 indicates data will NOT be copied. // value 0 indicates data will NOT be copied.
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or data is NULL. // WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error. // WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success. // WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxSetImage( WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(
WebPMux* const mux, WebPMux* const mux, const WebPData* const bitstream, int copy_data);
const WebPData* const image, const WebPData* const alpha,
int copy_data);
// Gets a reference to the image in the mux object. // Gets image data from the mux object.
// The caller should NOT free the returned data. // The content of 'bitstream' is allocated using malloc(), and NOT
// owned by the 'mux' object. It MUST be deallocated by the caller by calling
// WebPDataClear().
// Parameters: // Parameters:
// mux - (in) object from which the image is to be fetched // mux - (in) object from which the image is to be fetched
// image - (out) the image data // bitstream - (out) the image data
// alpha - (out) the alpha data of the image (if present)
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if either mux or both image & alpha are NULL // WEBP_MUX_INVALID_ARGUMENT - if either mux or bitstream is NULL
// OR mux contains animation/tiling. // OR mux contains animation/tiling.
// WEBP_MUX_NOT_FOUND - if image is not present in mux object. // WEBP_MUX_NOT_FOUND - if image is not present in mux object.
// WEBP_MUX_OK - on success. // WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxGetImage(const WebPMux* const mux, WEBP_EXTERN(WebPMuxError) WebPMuxGetImage(const WebPMux* const mux,
WebPData* const image, WebPData* const bitstream);
WebPData* const alpha);
// Deletes the image in the mux object. // Deletes the image in the mux object.
// Parameters: // Parameters:
@ -197,7 +199,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxDeleteImage(WebPMux* const mux);
// copy_data - (in) value 1 indicates given data WILL copied to the mux, and // copy_data - (in) value 1 indicates given data WILL copied to the mux, and
// value 0 indicates data will NOT be copied. // value 0 indicates data will NOT be copied.
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or data is NULL. // WEBP_MUX_INVALID_ARGUMENT - if mux or metadata is NULL.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error. // WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success. // WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxSetMetadata( WEBP_EXTERN(WebPMuxError) WebPMuxSetMetadata(
@ -235,7 +237,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxDeleteMetadata(WebPMux* const mux);
// copy_data - (in) value 1 indicates given data WILL copied to the mux, and // copy_data - (in) value 1 indicates given data WILL copied to the mux, and
// value 0 indicates data will NOT be copied. // value 0 indicates data will NOT be copied.
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or data is NULL // WEBP_MUX_INVALID_ARGUMENT - if mux or color_profile is NULL
// WEBP_MUX_MEMORY_ERROR - on memory allocation error // WEBP_MUX_MEMORY_ERROR - on memory allocation error
// WEBP_MUX_OK - on success // WEBP_MUX_OK - on success
WEBP_EXTERN(WebPMuxError) WebPMuxSetColorProfile( WEBP_EXTERN(WebPMuxError) WebPMuxSetColorProfile(
@ -270,23 +272,21 @@ WEBP_EXTERN(WebPMuxError) WebPMuxDeleteColorProfile(WebPMux* const mux);
// Parameters: // Parameters:
// mux - (in/out) object to which an animation frame is to be added // mux - (in/out) object to which an animation frame is to be added
// nth - (in) The position at which the frame is to be added. // nth - (in) The position at which the frame is to be added.
// image - (in) the raw VP8/VP8L image data corresponding to frame image. The // bitstream - (in) the image data corresponding to the frame. It can either
// data can be either a VP8/VP8L bitstream or a single-image WebP file // be a raw VP8/VP8L bitstream or a single-image WebP file
// (non-animated & non-tiled) // (non-animated and non-tiled)
// alpha - (in) the alpha data corresponding to frame image (if present)
// x_offset - (in) x-offset of the frame to be added // x_offset - (in) x-offset of the frame to be added
// y_offset - (in) y-offset of the frame to be added // y_offset - (in) y-offset of the frame to be added
// duration - (in) duration of the frame to be added (in milliseconds) // duration - (in) duration of the frame to be added (in milliseconds)
// copy_data - (in) value 1 indicates given data WILL copied to the mux, and // copy_data - (in) value 1 indicates given data WILL copied to the mux, and
// value 0 indicates data will NOT be copied. // value 0 indicates data will NOT be copied.
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or data is NULL // WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL
// WEBP_MUX_NOT_FOUND - If we have less than (nth-1) frames before adding. // WEBP_MUX_NOT_FOUND - If we have less than (nth-1) frames before adding.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error. // WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success. // WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxSetFrame( WEBP_EXTERN(WebPMuxError) WebPMuxSetFrame(
WebPMux* const mux, uint32_t nth, WebPMux* const mux, uint32_t nth, const WebPData* const bitstream,
const WebPData* const image, const WebPData* const alpha,
uint32_t x_offset, uint32_t y_offset, uint32_t duration, uint32_t x_offset, uint32_t y_offset, uint32_t duration,
int copy_data); int copy_data);
@ -299,26 +299,26 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetFrame(
// uint32_t duration; // uint32_t duration;
// } FrameInfo; // } FrameInfo;
// Gets a reference to the nth animation frame from the mux object. // Gets the nth animation frame from the mux object.
// The caller should NOT free the returned data. // The content of 'bitstream' is allocated using malloc(), and NOT
// owned by the 'mux' object. It MUST be deallocated by the caller by calling
// WebPDataClear().
// nth=0 has a special meaning - last position. // nth=0 has a special meaning - last position.
// Parameters: // Parameters:
// mux - (in) object from which the info is to be fetched // mux - (in) object from which the info is to be fetched
// nth - (in) index of the frame in the mux object // nth - (in) index of the frame in the mux object
// image - (out) the image data // bitstream - (out) the image data
// alpha - (out) the alpha data corresponding to frame image (if present)
// x_offset - (out) x-offset of the returned frame // x_offset - (out) x-offset of the returned frame
// y_offset - (out) y-offset of the returned frame // y_offset - (out) y-offset of the returned frame
// duration - (out) duration of the returned frame (in milliseconds) // duration - (out) duration of the returned frame (in milliseconds)
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if either mux, image, x_offset, // WEBP_MUX_INVALID_ARGUMENT - if either mux, bitstream, x_offset,
// y_offset, or duration is NULL // y_offset, or duration is NULL
// WEBP_MUX_NOT_FOUND - if there are less than nth frames in the mux object. // WEBP_MUX_NOT_FOUND - if there are less than nth frames in the mux object.
// WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid. // WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid.
// WEBP_MUX_OK - on success. // WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxGetFrame( WEBP_EXTERN(WebPMuxError) WebPMuxGetFrame(
const WebPMux* const mux, uint32_t nth, const WebPMux* const mux, uint32_t nth, WebPData* const bitstream,
WebPData* const image, WebPData* const alpha,
uint32_t* x_offset, uint32_t* y_offset, uint32_t* duration); uint32_t* x_offset, uint32_t* y_offset, uint32_t* duration);
// Deletes an animation frame from the mux object. // Deletes an animation frame from the mux object.
@ -365,44 +365,41 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetLoopCount(const WebPMux* const mux,
// Parameters: // Parameters:
// mux - (in/out) object to which a tile is to be added // mux - (in/out) object to which a tile is to be added
// nth - (in) The position at which the tile is to be added. // nth - (in) The position at which the tile is to be added.
// image - (in) the raw VP8/VP8L image data corresponding to tile image. The // bitstream - (in) the image data corresponding to the frame. It can either
// data can be either a VP8/VP8L bitstream or a single-image WebP file // be a raw VP8/VP8L bitstream or a single-image WebP file
// (non-animated & non-tiled) // (non-animated and non-tiled)
// alpha - (in) the alpha data corresponding to tile image (if present)
// x_offset - (in) x-offset of the tile to be added // x_offset - (in) x-offset of the tile to be added
// y_offset - (in) y-offset of the tile to be added // y_offset - (in) y-offset of the tile to be added
// copy_data - (in) value 1 indicates given data WILL copied to the mux, and // copy_data - (in) value 1 indicates given data WILL copied to the mux, and
// value 0 indicates data will NOT be copied. // value 0 indicates data will NOT be copied.
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or data is NULL // WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL
// WEBP_MUX_NOT_FOUND - If we have less than (nth-1) tiles before adding. // WEBP_MUX_NOT_FOUND - If we have less than (nth-1) tiles before adding.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error. // WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success. // WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxSetTile( WEBP_EXTERN(WebPMuxError) WebPMuxSetTile(
WebPMux* const mux, uint32_t nth, WebPMux* const mux, uint32_t nth, const WebPData* const bitstream,
const WebPData* const image, const WebPData* const alpha, uint32_t x_offset, uint32_t y_offset, int copy_data);
uint32_t x_offset, uint32_t y_offset,
int copy_data);
// Gets a reference to the nth tile from the mux object. // Gets the nth tile from the mux object.
// The caller should NOT free the returned data. // The content of 'bitstream' is allocated using malloc(), and NOT
// owned by the 'mux' object. It MUST be deallocated by the caller by calling
// WebPDataClear().
// nth=0 has a special meaning - last position. // nth=0 has a special meaning - last position.
// Parameters: // Parameters:
// mux - (in) object from which the info is to be fetched // mux - (in) object from which the info is to be fetched
// nth - (in) index of the tile in the mux object // nth - (in) index of the tile in the mux object
// image - (out) the image data // bitstream - (out) the image data
// alpha - (out) the alpha data corresponding to tile image (if present)
// x_offset - (out) x-offset of the returned tile // x_offset - (out) x-offset of the returned tile
// y_offset - (out) y-offset of the returned tile // y_offset - (out) y-offset of the returned tile
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if either mux, image, x_offset or // WEBP_MUX_INVALID_ARGUMENT - if either mux, bitstream, x_offset or
// y_offset is NULL // y_offset is NULL
// WEBP_MUX_NOT_FOUND - if there are less than nth tiles in the mux object. // WEBP_MUX_NOT_FOUND - if there are less than nth tiles in the mux object.
// WEBP_MUX_BAD_DATA - if nth tile chunk in mux is invalid. // WEBP_MUX_BAD_DATA - if nth tile chunk in mux is invalid.
// WEBP_MUX_OK - on success. // WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxGetTile( WEBP_EXTERN(WebPMuxError) WebPMuxGetTile(
const WebPMux* const mux, uint32_t nth, const WebPMux* const mux, uint32_t nth, WebPData* const bitstream,
WebPData* const image, WebPData* const alpha,
uint32_t* x_offset, uint32_t* y_offset); uint32_t* x_offset, uint32_t* y_offset);
// Deletes a tile from the mux object. // Deletes a tile from the mux object.
@ -427,7 +424,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxDeleteTile(WebPMux* const mux, uint32_t nth);
// mux object. This will be an OR of various flag values. // mux object. This will be an OR of various flag values.
// Enum 'WebPFeatureFlags' can be used to test individual flag values. // Enum 'WebPFeatureFlags' can be used to test individual flag values.
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or flags is NULL // WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL
// WEBP_MUX_NOT_FOUND - if VP8X chunk is not present in mux object. // WEBP_MUX_NOT_FOUND - if VP8X chunk is not present in mux object.
// WEBP_MUX_BAD_DATA - if VP8X chunk in mux is invalid. // WEBP_MUX_BAD_DATA - if VP8X chunk in mux is invalid.
// WEBP_MUX_OK - on success. // WEBP_MUX_OK - on success.