mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-13 14:34:33 +02:00
More spec/code matching in mux:
- Match offsets, duration, width/height for frames/tiles and enforce some constraints. - Note that this also means using 'int's instead of 'uint32_t's for 16-bit and 24-bit fields. Change-Id: If0b229ad9fce296372d961104aa36731a3b1304b
This commit is contained in:
@ -133,17 +133,30 @@ static WEBP_INLINE uint8_t GetByte(MemBuffer* const mem) {
|
||||
return byte;
|
||||
}
|
||||
|
||||
// Read 16, 24 or 32 bits stored in little-endian order.
|
||||
static WEBP_INLINE int ReadLE16s(const uint8_t* const data) {
|
||||
return (int)(data[0] << 0) | (data[1] << 8);
|
||||
}
|
||||
|
||||
static WEBP_INLINE int ReadLE24s(const uint8_t* const data) {
|
||||
return (int)(data[0] << 0) | (data[1] << 8) | (data[2] << 16);
|
||||
return ReadLE16s(data) | (data[2] << 16);
|
||||
}
|
||||
|
||||
static WEBP_INLINE uint32_t ReadLE32(const uint8_t* const data) {
|
||||
return (uint32_t)ReadLE24s(data) | (data[3] << 24);
|
||||
}
|
||||
|
||||
// In addition to reading, skip the read bytes.
|
||||
static WEBP_INLINE int GetLE16s(MemBuffer* const mem) {
|
||||
const uint8_t* const data = mem->buf_ + mem->start_;
|
||||
const int val = ReadLE16s(data);
|
||||
Skip(mem, 2);
|
||||
return val;
|
||||
}
|
||||
|
||||
static WEBP_INLINE int GetLE24s(MemBuffer* const mem) {
|
||||
const uint8_t* const data = mem->buf_ + mem->start_;
|
||||
const uint32_t val = ReadLE24s(data);
|
||||
const int val = ReadLE24s(data);
|
||||
Skip(mem, 3);
|
||||
return val;
|
||||
}
|
||||
@ -155,10 +168,6 @@ static WEBP_INLINE uint32_t GetLE32(MemBuffer* const mem) {
|
||||
return val;
|
||||
}
|
||||
|
||||
static WEBP_INLINE int GetLE32s(MemBuffer* const mem) {
|
||||
return (int)GetLE32(mem);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Secondary chunk parsing
|
||||
|
||||
@ -289,12 +298,15 @@ static ParseStatus ParseFrame(
|
||||
NewFrame(mem, min_size, FRAME_CHUNK_SIZE, frame_chunk_size, &frame);
|
||||
if (status != PARSE_OK) return status;
|
||||
|
||||
frame->x_offset_ = GetLE32s(mem);
|
||||
frame->y_offset_ = GetLE32s(mem);
|
||||
frame->width_ = GetLE32s(mem);
|
||||
frame->height_ = GetLE32s(mem);
|
||||
frame->duration_ = GetLE32s(mem);
|
||||
frame->x_offset_ = 2 * GetLE24s(mem);
|
||||
frame->y_offset_ = 2 * GetLE24s(mem);
|
||||
frame->width_ = 1 + GetLE24s(mem);
|
||||
frame->height_ = 1 + GetLE24s(mem);
|
||||
frame->duration_ = 1 + GetLE24s(mem);
|
||||
Skip(mem, frame_chunk_size - FRAME_CHUNK_SIZE); // skip any trailing data.
|
||||
if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) {
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
|
||||
// Store a (potentially partial) frame only if the animation flag is set
|
||||
// and there is some data in 'frame'.
|
||||
@ -326,8 +338,8 @@ static ParseStatus ParseTile(WebPDemuxer* const dmux,
|
||||
if (status != PARSE_OK) return status;
|
||||
|
||||
frame->is_tile_ = 1;
|
||||
frame->x_offset_ = GetLE32s(mem);
|
||||
frame->y_offset_ = GetLE32s(mem);
|
||||
frame->x_offset_ = 2 * GetLE24s(mem);
|
||||
frame->y_offset_ = 2 * GetLE24s(mem);
|
||||
Skip(mem, tile_chunk_size - TILE_CHUNK_SIZE); // skip any trailing data.
|
||||
|
||||
// Store a (potentially partial) tile only if the tile flag is set
|
||||
@ -481,7 +493,7 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
|
||||
status = PARSE_NEED_MORE_DATA;
|
||||
} else if (loop_chunks == 0) {
|
||||
++loop_chunks;
|
||||
dmux->loop_count_ = GetLE32s(mem);
|
||||
dmux->loop_count_ = GetLE16s(mem);
|
||||
Skip(mem, chunk_size_padded - LOOP_CHUNK_SIZE);
|
||||
} else {
|
||||
store_chunk = 0;
|
||||
|
@ -19,11 +19,11 @@ extern "C" {
|
||||
|
||||
// Object to store metadata about images.
|
||||
typedef struct {
|
||||
uint32_t x_offset_;
|
||||
uint32_t y_offset_;
|
||||
uint32_t duration_;
|
||||
uint32_t width_;
|
||||
uint32_t height_;
|
||||
int x_offset_;
|
||||
int y_offset_;
|
||||
int duration_;
|
||||
int width_;
|
||||
int height_;
|
||||
} WebPImageInfo;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -115,8 +115,8 @@ static WebPMuxError MuxAddChunk(WebPMux* const mux, uint32_t nth, uint32_t tag,
|
||||
|
||||
// Create data for frame/tile given image data, offsets and duration.
|
||||
static WebPMuxError CreateFrameTileData(const WebPData* const image,
|
||||
uint32_t x_offset, uint32_t y_offset,
|
||||
uint32_t duration, int is_lossless,
|
||||
int x_offset, int y_offset,
|
||||
int duration, int is_lossless,
|
||||
int is_frame,
|
||||
WebPData* const frame_tile) {
|
||||
int width;
|
||||
@ -129,16 +129,19 @@ static WebPMuxError CreateFrameTileData(const WebPData* const image,
|
||||
VP8GetInfo(image->bytes_, image->size_, image->size_, &width, &height);
|
||||
if (!ok) return WEBP_MUX_INVALID_ARGUMENT;
|
||||
|
||||
assert(width > 0 && height > 0 && duration > 0);
|
||||
// Note: assertion on upper bounds is done in PutLE24().
|
||||
|
||||
frame_tile_bytes = (uint8_t*)malloc(frame_tile_size);
|
||||
if (frame_tile_bytes == NULL) return WEBP_MUX_MEMORY_ERROR;
|
||||
|
||||
PutLE32(frame_tile_bytes + 0, x_offset);
|
||||
PutLE32(frame_tile_bytes + 4, y_offset);
|
||||
PutLE24(frame_tile_bytes + 0, x_offset / 2);
|
||||
PutLE24(frame_tile_bytes + 3, y_offset / 2);
|
||||
|
||||
if (is_frame) {
|
||||
PutLE32(frame_tile_bytes + 8, (uint32_t)width);
|
||||
PutLE32(frame_tile_bytes + 12, (uint32_t)height);
|
||||
PutLE32(frame_tile_bytes + 16, duration);
|
||||
PutLE24(frame_tile_bytes + 6, width - 1);
|
||||
PutLE24(frame_tile_bytes + 9, height - 1);
|
||||
PutLE24(frame_tile_bytes + 12, duration - 1);
|
||||
}
|
||||
|
||||
frame_tile->bytes_ = frame_tile_bytes;
|
||||
@ -300,11 +303,12 @@ WebPMuxError WebPMuxSetColorProfile(WebPMux* const mux,
|
||||
return MuxSet(mux, IDX_ICCP, 1, color_profile, copy_data);
|
||||
}
|
||||
|
||||
WebPMuxError WebPMuxSetLoopCount(WebPMux* const mux, uint32_t loop_count) {
|
||||
WebPMuxError WebPMuxSetLoopCount(WebPMux* const mux, int loop_count) {
|
||||
WebPMuxError err;
|
||||
uint8_t* data = NULL;
|
||||
|
||||
if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
||||
if (loop_count >= MAX_LOOP_COUNT) return WEBP_MUX_INVALID_ARGUMENT;
|
||||
|
||||
// Delete the existing LOOP chunk(s).
|
||||
err = DeleteLoopCount(mux);
|
||||
@ -314,7 +318,7 @@ WebPMuxError WebPMuxSetLoopCount(WebPMux* const mux, uint32_t loop_count) {
|
||||
data = (uint8_t*)malloc(kChunks[IDX_LOOP].size);
|
||||
if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
|
||||
|
||||
PutLE32(data, loop_count);
|
||||
PutLE16(data, loop_count);
|
||||
err = MuxAddChunk(mux, 1, kChunks[IDX_LOOP].tag, data,
|
||||
kChunks[IDX_LOOP].size, 1);
|
||||
free(data);
|
||||
@ -322,8 +326,8 @@ WebPMuxError WebPMuxSetLoopCount(WebPMux* const mux, uint32_t loop_count) {
|
||||
}
|
||||
|
||||
static WebPMuxError MuxPushFrameTileInternal(
|
||||
WebPMux* const mux, const WebPData* const bitstream, uint32_t x_offset,
|
||||
uint32_t y_offset, uint32_t duration, int copy_data, uint32_t tag) {
|
||||
WebPMux* const mux, const WebPData* const bitstream, int x_offset,
|
||||
int y_offset, int duration, int copy_data, uint32_t tag) {
|
||||
WebPChunk chunk;
|
||||
WebPData image;
|
||||
WebPData alpha;
|
||||
@ -334,10 +338,20 @@ static WebPMuxError MuxPushFrameTileInternal(
|
||||
int is_lossless;
|
||||
int image_tag;
|
||||
|
||||
// Sanity checks.
|
||||
if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL ||
|
||||
bitstream->size_ > MAX_CHUNK_PAYLOAD) {
|
||||
return WEBP_MUX_INVALID_ARGUMENT;
|
||||
}
|
||||
if (x_offset < 0 || x_offset >= MAX_POSITION_OFFSET ||
|
||||
y_offset < 0 || y_offset >= MAX_POSITION_OFFSET ||
|
||||
duration <= 0 || duration > MAX_DURATION) {
|
||||
return WEBP_MUX_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
// Snap offsets to even positions.
|
||||
x_offset &= ~1;
|
||||
y_offset &= ~1;
|
||||
|
||||
// If given data is for a whole webp file,
|
||||
// extract only the VP8/VP8L data from it.
|
||||
@ -394,15 +408,15 @@ static WebPMuxError MuxPushFrameTileInternal(
|
||||
|
||||
WebPMuxError WebPMuxPushFrame(WebPMux* const mux,
|
||||
const WebPData* const bitstream,
|
||||
uint32_t x_offset, uint32_t y_offset,
|
||||
uint32_t duration, int copy_data) {
|
||||
int x_offset, int y_offset,
|
||||
int duration, int copy_data) {
|
||||
return MuxPushFrameTileInternal(mux, bitstream, x_offset, y_offset,
|
||||
duration, copy_data, kChunks[IDX_FRAME].tag);
|
||||
}
|
||||
|
||||
WebPMuxError WebPMuxPushTile(WebPMux* const mux,
|
||||
const WebPData* const bitstream,
|
||||
uint32_t x_offset, uint32_t y_offset,
|
||||
int x_offset, int y_offset,
|
||||
int copy_data) {
|
||||
return MuxPushFrameTileInternal(mux, bitstream, x_offset, y_offset,
|
||||
1 /* unused duration */, copy_data,
|
||||
@ -454,9 +468,8 @@ WebPMuxError WebPMuxDeleteTile(WebPMux* const mux, uint32_t nth) {
|
||||
// Assembly of the WebP RIFF file.
|
||||
|
||||
static WebPMuxError GetFrameTileInfo(const WebPChunk* const frame_tile_chunk,
|
||||
uint32_t* const x_offset,
|
||||
uint32_t* const y_offset,
|
||||
uint32_t* const duration) {
|
||||
int* const x_offset, int* const y_offset,
|
||||
int* const duration) {
|
||||
const uint32_t tag = frame_tile_chunk->tag_;
|
||||
const int is_frame = (tag == kChunks[IDX_FRAME].tag);
|
||||
const WebPData* const data = &frame_tile_chunk->data_;
|
||||
@ -466,9 +479,9 @@ static WebPMuxError GetFrameTileInfo(const WebPChunk* const frame_tile_chunk,
|
||||
assert(tag == kChunks[IDX_FRAME].tag || tag == kChunks[IDX_TILE].tag);
|
||||
if (data->size_ != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT;
|
||||
|
||||
*x_offset = GetLE32(data->bytes_ + 0);
|
||||
*y_offset = GetLE32(data->bytes_ + 4);
|
||||
if (is_frame) *duration = GetLE32(data->bytes_ + 16);
|
||||
*x_offset = 2 * GetLE24(data->bytes_ + 0);
|
||||
*y_offset = 2 * GetLE24(data->bytes_ + 3);
|
||||
if (is_frame) *duration = 1 + GetLE24(data->bytes_ + 12);
|
||||
return WEBP_MUX_OK;
|
||||
}
|
||||
|
||||
@ -497,7 +510,7 @@ static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi,
|
||||
const WebPChunk* const image_chunk = wpi->img_;
|
||||
const WebPChunk* const frame_tile_chunk = wpi->header_;
|
||||
WebPMuxError err;
|
||||
uint32_t x_offset, y_offset, duration;
|
||||
int x_offset, y_offset, duration;
|
||||
int width, height;
|
||||
|
||||
memset(image_info, 0, sizeof(*image_info));
|
||||
@ -520,8 +533,8 @@ static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi,
|
||||
}
|
||||
|
||||
static WebPMuxError GetImageCanvasWidthHeight(
|
||||
const WebPMux* const mux,
|
||||
uint32_t flags, uint32_t* width, uint32_t* height) {
|
||||
const WebPMux* const mux, uint32_t flags,
|
||||
int* const width, int* const height) {
|
||||
WebPMuxImage* wpi = NULL;
|
||||
assert(mux != NULL);
|
||||
assert(width && height);
|
||||
@ -531,25 +544,21 @@ static WebPMuxError GetImageCanvasWidthHeight(
|
||||
assert(wpi->img_ != NULL);
|
||||
|
||||
if (wpi->next_) {
|
||||
uint32_t max_x = 0;
|
||||
uint32_t max_y = 0;
|
||||
uint64_t image_area = 0;
|
||||
int max_x = 0;
|
||||
int max_y = 0;
|
||||
int64_t image_area = 0;
|
||||
// Aggregate the bounding box for animation frames & tiled images.
|
||||
for (; wpi != NULL; wpi = wpi->next_) {
|
||||
WebPImageInfo image_info;
|
||||
const WebPMuxError err = GetImageInfo(wpi, &image_info);
|
||||
const uint32_t max_x_pos = image_info.x_offset_ + image_info.width_;
|
||||
const uint32_t max_y_pos = image_info.y_offset_ + image_info.height_;
|
||||
const int max_x_pos = image_info.x_offset_ + image_info.width_;
|
||||
const int max_y_pos = image_info.y_offset_ + image_info.height_;
|
||||
if (err != WEBP_MUX_OK) return err;
|
||||
assert(image_info.x_offset_ < MAX_POSITION_OFFSET);
|
||||
assert(image_info.y_offset_ < MAX_POSITION_OFFSET);
|
||||
|
||||
if (max_x_pos < image_info.x_offset_) { // Overflow occurred.
|
||||
return WEBP_MUX_INVALID_ARGUMENT;
|
||||
}
|
||||
if (max_y_pos < image_info.y_offset_) { // Overflow occurred.
|
||||
return WEBP_MUX_INVALID_ARGUMENT;
|
||||
}
|
||||
if (max_x_pos > max_x) max_x = max_x_pos;
|
||||
if (max_y_pos > max_y) max_y = max_y_pos;
|
||||
if (max_x_pos > max_x) max_x = max_x_pos;
|
||||
if (max_y_pos > max_y) max_y = max_y_pos;
|
||||
image_area += (image_info.width_ * image_info.height_);
|
||||
}
|
||||
*width = max_x;
|
||||
@ -583,8 +592,8 @@ static WebPMuxError GetImageCanvasWidthHeight(
|
||||
static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
|
||||
WebPMuxError err = WEBP_MUX_OK;
|
||||
uint32_t flags = 0;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
uint8_t data[VP8X_CHUNK_SIZE];
|
||||
const size_t data_size = VP8X_CHUNK_SIZE;
|
||||
const WebPMuxImage* images = NULL;
|
||||
@ -632,6 +641,13 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
|
||||
err = GetImageCanvasWidthHeight(mux, flags, &width, &height);
|
||||
if (err != WEBP_MUX_OK) return err;
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
return WEBP_MUX_INVALID_ARGUMENT;
|
||||
}
|
||||
if (width > MAX_CANVAS_SIZE || height > MAX_CANVAS_SIZE) {
|
||||
return WEBP_MUX_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (MuxHasLosslessImages(images)) {
|
||||
// We have a file with a VP8X chunk having some lossless images.
|
||||
// As lossless images implicitly contain alpha, force ALPHA_FLAG to be true.
|
||||
|
@ -80,8 +80,7 @@ typedef enum {
|
||||
|
||||
#define NIL_TAG 0x00000000u // To signal void chunk.
|
||||
|
||||
#define mktag(c1, c2, c3, c4) \
|
||||
((uint32_t)c1 | (c2 << 8) | (c3 << 16) | (c4 << 24))
|
||||
#define MKFOURCC(a, b, c, d) ((uint32_t)(a) | (b) << 8 | (c) << 16 | (d) << 24)
|
||||
|
||||
typedef struct {
|
||||
uint32_t tag;
|
||||
@ -94,23 +93,35 @@ extern const ChunkInfo kChunks[IDX_LAST_CHUNK];
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper functions.
|
||||
|
||||
// Read 16, 24 or 32 bits stored in little-endian order.
|
||||
static WEBP_INLINE int GetLE16(const uint8_t* const data) {
|
||||
return (int)(data[0] << 0) | (data[1] << 8);
|
||||
}
|
||||
|
||||
static WEBP_INLINE int GetLE24(const uint8_t* const data) {
|
||||
return GetLE16(data) | (data[2] << 16);
|
||||
}
|
||||
|
||||
static WEBP_INLINE uint32_t GetLE32(const uint8_t* const data) {
|
||||
return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
|
||||
return (uint32_t)GetLE16(data) | (GetLE16(data + 2) << 16);
|
||||
}
|
||||
|
||||
static WEBP_INLINE void PutLE16(uint8_t* const data, uint32_t val) {
|
||||
data[0] = (val >> 0) & 0xff;
|
||||
data[1] = (val >> 8) & 0xff;
|
||||
// Store 16, 24 or 32 bits in little-endian order.
|
||||
static WEBP_INLINE void PutLE16(uint8_t* const data, int val) {
|
||||
assert(val < (1 << 16));
|
||||
data[0] = (val >> 0);
|
||||
data[1] = (val >> 8);
|
||||
}
|
||||
|
||||
static WEBP_INLINE void PutLE24(uint8_t* const data, uint32_t val) {
|
||||
PutLE16(data, val);
|
||||
static WEBP_INLINE void PutLE24(uint8_t* const data, int val) {
|
||||
assert(val < (1 << 24));
|
||||
PutLE16(data, val & 0xffff);
|
||||
data[2] = (val >> 16);
|
||||
}
|
||||
|
||||
static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
|
||||
PutLE16(data, val);
|
||||
PutLE16(data + 2, val >> 16);
|
||||
PutLE16(data, (int)(val & 0xffff));
|
||||
PutLE16(data + 2, (int)(val >> 16));
|
||||
}
|
||||
|
||||
static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) {
|
||||
|
@ -20,16 +20,16 @@ extern "C" {
|
||||
#define UNDEFINED_CHUNK_SIZE (-1)
|
||||
|
||||
const ChunkInfo kChunks[] = {
|
||||
{ mktag('V', 'P', '8', 'X'), WEBP_CHUNK_VP8X, VP8X_CHUNK_SIZE },
|
||||
{ mktag('I', 'C', 'C', 'P'), WEBP_CHUNK_ICCP, UNDEFINED_CHUNK_SIZE },
|
||||
{ mktag('L', 'O', 'O', 'P'), WEBP_CHUNK_LOOP, LOOP_CHUNK_SIZE },
|
||||
{ mktag('F', 'R', 'M', ' '), WEBP_CHUNK_FRAME, FRAME_CHUNK_SIZE },
|
||||
{ mktag('T', 'I', 'L', 'E'), WEBP_CHUNK_TILE, TILE_CHUNK_SIZE },
|
||||
{ mktag('A', 'L', 'P', 'H'), WEBP_CHUNK_ALPHA, UNDEFINED_CHUNK_SIZE },
|
||||
{ mktag('V', 'P', '8', ' '), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
|
||||
{ mktag('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
|
||||
{ mktag('M', 'E', 'T', 'A'), WEBP_CHUNK_META, UNDEFINED_CHUNK_SIZE },
|
||||
{ mktag('U', 'N', 'K', 'N'), WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE },
|
||||
{ MKFOURCC('V', 'P', '8', 'X'), WEBP_CHUNK_VP8X, VP8X_CHUNK_SIZE },
|
||||
{ MKFOURCC('I', 'C', 'C', 'P'), WEBP_CHUNK_ICCP, UNDEFINED_CHUNK_SIZE },
|
||||
{ MKFOURCC('L', 'O', 'O', 'P'), WEBP_CHUNK_LOOP, LOOP_CHUNK_SIZE },
|
||||
{ MKFOURCC('F', 'R', 'M', ' '), WEBP_CHUNK_FRAME, FRAME_CHUNK_SIZE },
|
||||
{ MKFOURCC('T', 'I', 'L', 'E'), WEBP_CHUNK_TILE, TILE_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', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
|
||||
{ MKFOURCC('M', 'E', 'T', 'A'), WEBP_CHUNK_META, UNDEFINED_CHUNK_SIZE },
|
||||
{ MKFOURCC('U', 'N', 'K', 'N'), WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE },
|
||||
|
||||
{ NIL_TAG, WEBP_CHUNK_NIL, UNDEFINED_CHUNK_SIZE }
|
||||
};
|
||||
@ -426,10 +426,10 @@ int MuxHasLosslessImages(const WebPMuxImage* images) {
|
||||
}
|
||||
|
||||
uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size) {
|
||||
PutLE32(data + 0, mktag('R', 'I', 'F', 'F'));
|
||||
PutLE32(data + 0, MKFOURCC('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'));
|
||||
PutLE32(data + TAG_SIZE + CHUNK_SIZE_BYTES, MKFOURCC('W', 'E', 'B', 'P'));
|
||||
return data + RIFF_HEADER_SIZE;
|
||||
}
|
||||
|
||||
|
@ -97,8 +97,8 @@ WebPMux* WebPMuxCreateInternal(const WebPData* const bitstream, int copy_data,
|
||||
|
||||
if (data == NULL) return NULL;
|
||||
if (size < RIFF_HEADER_SIZE) return NULL;
|
||||
if (GetLE32(data + 0) != mktag('R', 'I', 'F', 'F') ||
|
||||
GetLE32(data + CHUNK_HEADER_SIZE) != mktag('W', 'E', 'B', 'P')) {
|
||||
if (GetLE32(data + 0) != MKFOURCC('R', 'I', 'F', 'F') ||
|
||||
GetLE32(data + CHUNK_HEADER_SIZE) != MKFOURCC('W', 'E', 'B', 'P')) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -213,13 +213,13 @@ WebPMuxError WebPMuxGetFeatures(const WebPMux* const mux, uint32_t* flags) {
|
||||
return WEBP_MUX_OK;
|
||||
}
|
||||
|
||||
static uint8_t* EmitVP8XChunk(uint8_t* const dst, uint32_t width,
|
||||
uint32_t height, uint32_t flags) {
|
||||
static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width,
|
||||
int height, uint32_t flags) {
|
||||
const size_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
|
||||
assert(width >= 1 && height >= 1);
|
||||
assert(width <= MAX_CANVAS_SIZE && height <= MAX_CANVAS_SIZE);
|
||||
assert(width * (uint64_t)height < MAX_IMAGE_AREA);
|
||||
PutLE32(dst, mktag('V', 'P', '8', 'X'));
|
||||
PutLE32(dst, MKFOURCC('V', 'P', '8', 'X'));
|
||||
PutLE32(dst + TAG_SIZE, VP8X_CHUNK_SIZE);
|
||||
PutLE32(dst + CHUNK_HEADER_SIZE, flags);
|
||||
PutLE24(dst + CHUNK_HEADER_SIZE + 4, width - 1);
|
||||
@ -301,7 +301,7 @@ WebPMuxError WebPMuxGetColorProfile(const WebPMux* const mux,
|
||||
}
|
||||
|
||||
WebPMuxError WebPMuxGetLoopCount(const WebPMux* const mux,
|
||||
uint32_t* loop_count) {
|
||||
int* const loop_count) {
|
||||
WebPData image;
|
||||
WebPMuxError err;
|
||||
|
||||
@ -310,14 +310,15 @@ WebPMuxError WebPMuxGetLoopCount(const WebPMux* const mux,
|
||||
err = MuxGet(mux, IDX_LOOP, 1, &image);
|
||||
if (err != WEBP_MUX_OK) return err;
|
||||
if (image.size_ < kChunks[WEBP_CHUNK_LOOP].size) return WEBP_MUX_BAD_DATA;
|
||||
*loop_count = GetLE32(image.bytes_);
|
||||
*loop_count = GetLE16(image.bytes_);
|
||||
|
||||
return WEBP_MUX_OK;
|
||||
}
|
||||
|
||||
static WebPMuxError MuxGetFrameTileInternal(
|
||||
const WebPMux* const mux, uint32_t nth, WebPData* const bitstream,
|
||||
uint32_t* x_offset, uint32_t* y_offset, uint32_t* duration, uint32_t tag) {
|
||||
int* const x_offset, int* const y_offset, int* const duration,
|
||||
uint32_t tag) {
|
||||
const WebPData* frame_tile_data;
|
||||
WebPMuxError err;
|
||||
WebPMuxImage* wpi;
|
||||
@ -340,27 +341,24 @@ static WebPMuxError MuxGetFrameTileInternal(
|
||||
frame_tile_data = &wpi->header_->data_;
|
||||
|
||||
if (frame_tile_data->size_ < kChunks[idx].size) return WEBP_MUX_BAD_DATA;
|
||||
*x_offset = GetLE32(frame_tile_data->bytes_ + 0);
|
||||
*y_offset = GetLE32(frame_tile_data->bytes_ + 4);
|
||||
if (is_frame) *duration = GetLE32(frame_tile_data->bytes_ + 16);
|
||||
*x_offset = 2 * GetLE24(frame_tile_data->bytes_ + 0);
|
||||
*y_offset = 2 * GetLE24(frame_tile_data->bytes_ + 3);
|
||||
if (is_frame) *duration = 1 + GetLE24(frame_tile_data->bytes_ + 12);
|
||||
|
||||
return SynthesizeBitstream(wpi, bitstream);
|
||||
}
|
||||
|
||||
WebPMuxError WebPMuxGetFrame(const WebPMux* const mux, uint32_t nth,
|
||||
WebPData* const bitstream,
|
||||
uint32_t* x_offset, uint32_t* y_offset,
|
||||
uint32_t* duration) {
|
||||
return MuxGetFrameTileInternal(mux, nth, bitstream,
|
||||
x_offset, y_offset, duration,
|
||||
kChunks[IDX_FRAME].tag);
|
||||
WebPData* const bitstream, int* const x_offset,
|
||||
int* const y_offset, int* const duration) {
|
||||
return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset,
|
||||
duration, kChunks[IDX_FRAME].tag);
|
||||
}
|
||||
|
||||
WebPMuxError WebPMuxGetTile(const WebPMux* const mux, uint32_t nth,
|
||||
WebPData* const bitstream,
|
||||
uint32_t* x_offset, uint32_t* y_offset) {
|
||||
return MuxGetFrameTileInternal(mux, nth, bitstream,
|
||||
x_offset, y_offset, NULL,
|
||||
int* const x_offset, int* const y_offset) {
|
||||
return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset, NULL,
|
||||
kChunks[IDX_TILE].tag);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user