make width/height coding match the spec

* width/height in VP8X chunk is 24bit now
* Added some more constants #defines

Change-Id: I2f8ca7f965a247bccd341dd079ed2abf549c39d7
This commit is contained in:
Pascal Massimino 2012-06-28 00:20:28 -07:00
parent 637a314f97
commit e012dfd90f
7 changed files with 59 additions and 30 deletions

View File

@ -38,15 +38,19 @@ extern "C" {
// 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk. // 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk.
// 16..19 size of the VP8X chunk starting at offset 20. // 16..19 size of the VP8X chunk starting at offset 20.
// 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..27 Width of the Canvas Image. // 24..26 Width of the Canvas Image.
// 28..31 Height of the Canvas Image. // 27..29 Height of the Canvas Image.
// There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8, // There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8,
// META ...) // META ...)
// All 32-bits sizes are in little-endian order. // All sizes are in little-endian order.
// Note: chunk data must be padded to multiple of 2 in size // Note: chunk data size must be padded to multiple of 2 when written.
static WEBP_INLINE uint32_t get_le24(const uint8_t* const data) {
return data[0] | (data[1] << 8) | (data[2] << 16);
}
static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) { static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) {
return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); return (uint32_t)get_le24(data) | (data[3] << 24);
} }
// Validates the RIFF container (if detected) and skips over it. // Validates the RIFF container (if detected) and skips over it.
@ -115,10 +119,10 @@ static VP8StatusCode ParseVP8X(const uint8_t** data, size_t* data_size,
*flags = get_le32(*data + 8); *flags = get_le32(*data + 8);
} }
if (width != NULL) { if (width != NULL) {
*width = get_le32(*data + 12); *width = 1 + get_le24(*data + 12);
} }
if (height != NULL) { if (height != NULL) {
*height = get_le32(*data + 16); *height = 1 + get_le24(*data + 15);
} }
// Skip over VP8X header bytes. // Skip over VP8X header bytes.
*data += vp8x_size; *data += vp8x_size;

View File

@ -22,10 +22,14 @@ extern "C" {
// Helper functions // Helper functions
// TODO(later): Move to webp/format_constants.h? // TODO(later): Move to webp/format_constants.h?
static void PutLE32(uint8_t* const data, uint32_t val) { static void PutLE24(uint8_t* const data, uint32_t val) {
data[0] = (val >> 0) & 0xff; data[0] = (val >> 0) & 0xff;
data[1] = (val >> 8) & 0xff; data[1] = (val >> 8) & 0xff;
data[2] = (val >> 16) & 0xff; data[2] = (val >> 16) & 0xff;
}
static void PutLE32(uint8_t* const data, uint32_t val) {
PutLE24(data, val);
data[3] = (val >> 24) & 0xff; data[3] = (val >> 24) & 0xff;
} }
@ -65,6 +69,8 @@ static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) {
uint32_t flags = 0; uint32_t flags = 0;
assert(IsVP8XNeeded(enc)); assert(IsVP8XNeeded(enc));
assert(pic->width >= 1 && pic->height >= 1);
assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE);
if (enc->has_alpha_) { if (enc->has_alpha_) {
flags |= ALPHA_FLAG_BIT; flags |= ALPHA_FLAG_BIT;
@ -72,8 +78,8 @@ static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) {
PutLE32(vp8x + TAG_SIZE, VP8X_CHUNK_SIZE); PutLE32(vp8x + TAG_SIZE, VP8X_CHUNK_SIZE);
PutLE32(vp8x + CHUNK_HEADER_SIZE, flags); PutLE32(vp8x + CHUNK_HEADER_SIZE, flags);
PutLE32(vp8x + CHUNK_HEADER_SIZE + 4, pic->width); PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1);
PutLE32(vp8x + CHUNK_HEADER_SIZE + 8, pic->height); PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1);
if(!pic->writer(vp8x, sizeof(vp8x), pic)) { if(!pic->writer(vp8x, sizeof(vp8x), pic)) {
return VP8_ENC_ERROR_BAD_WRITE; return VP8_ENC_ERROR_BAD_WRITE;
} }
@ -274,12 +280,6 @@ static int EmitPartitionsSize(const VP8Encoder* const enc,
#define KTRAILER_SIZE 8 #define KTRAILER_SIZE 8
static void PutLE24(uint8_t* buf, size_t value) {
buf[0] = (value >> 0) & 0xff;
buf[1] = (value >> 8) & 0xff;
buf[2] = (value >> 16) & 0xff;
}
static int WriteExtensions(VP8Encoder* const enc) { static int WriteExtensions(VP8Encoder* const enc) {
uint8_t buffer[KTRAILER_SIZE]; uint8_t buffer[KTRAILER_SIZE];
VP8BitWriter* const bw = &enc->bw_; VP8BitWriter* const bw = &enc->bw_;

View File

@ -133,9 +133,19 @@ static WEBP_INLINE uint8_t GetByte(MemBuffer* const mem) {
return byte; return byte;
} }
static WEBP_INLINE int ReadLE24s(const uint8_t* const data) {
return (int)(data[0] << 0) | (data[1] << 8) | (data[2] << 16);
}
static WEBP_INLINE uint32_t ReadLE32(const uint8_t* const data) { static WEBP_INLINE uint32_t ReadLE32(const uint8_t* const data) {
return (uint32_t)(data[0] << 0 | (data[1] << 8) | return (uint32_t)ReadLE24s(data) | (data[3] << 24);
(data[2] << 16) | (data[3] << 24)); }
static WEBP_INLINE int GetLE24s(MemBuffer* const mem) {
const uint8_t* const data = mem->buf_ + mem->start_;
const uint32_t val = ReadLE24s(data);
Skip(mem, 3);
return val;
} }
static WEBP_INLINE uint32_t GetLE32(MemBuffer* const mem) { static WEBP_INLINE uint32_t GetLE32(MemBuffer* const mem) {
@ -432,8 +442,8 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
dmux->feature_flags_ = GetByte(mem); dmux->feature_flags_ = GetByte(mem);
Skip(mem, 3); // Reserved. Skip(mem, 3); // Reserved.
dmux->canvas_width_ = GetLE32s(mem); dmux->canvas_width_ = 1 + GetLE24s(mem);
dmux->canvas_height_ = GetLE32s(mem); dmux->canvas_height_ = 1 + GetLE24s(mem);
Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data. Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data.
dmux->state_ = WEBP_DEMUX_PARSED_HEADER; dmux->state_ = WEBP_DEMUX_PARSED_HEADER;

View File

@ -569,10 +569,10 @@ static WebPMuxError GetImageCanvasWidthHeight(
} }
// VP8X format: // VP8X format:
// Total Size : 12, // Total Size : 10,
// Flags : 4 bytes, // Flags : 4 bytes,
// Width : 4 bytes, // Width : 3 bytes,
// Height : 4 bytes. // Height : 3 bytes.
static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
WebPMuxError err = WEBP_MUX_OK; WebPMuxError err = WEBP_MUX_OK;
uint32_t flags = 0; uint32_t flags = 0;
@ -635,8 +635,8 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
} }
PutLE32(data + 0, flags); // VP8X chunk flags. PutLE32(data + 0, flags); // VP8X chunk flags.
PutLE32(data + 4, width); // canvas width. PutLE24(data + 4, width - 1); // canvas width.
PutLE32(data + 8, height); // canvas height. PutLE24(data + 7, height - 1); // canvas height.
err = MuxAddChunk(mux, 1, kChunks[IDX_VP8X].tag, data, data_size, NULL, 1); err = MuxAddChunk(mux, 1, kChunks[IDX_VP8X].tag, data, data_size, NULL, 1);
return err; return err;

View File

@ -108,11 +108,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 data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
} }
static WEBP_INLINE void PutLE16(uint8_t* const data, uint16_t val) { static WEBP_INLINE void PutLE16(uint8_t* const data, uint32_t val) {
data[0] = (val >> 0) & 0xff; data[0] = (val >> 0) & 0xff;
data[1] = (val >> 8) & 0xff; data[1] = (val >> 8) & 0xff;
} }
static WEBP_INLINE void PutLE24(uint8_t* const data, uint32_t val) {
PutLE16(data, val);
data[2] = (val >> 16);
}
static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) { static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
PutLE16(data, val); PutLE16(data, val);
PutLE16(data + 2, val >> 16); PutLE16(data + 2, val >> 16);

View File

@ -215,11 +215,13 @@ WebPMuxError WebPMuxGetFeatures(const WebPMux* const mux, uint32_t* flags) {
static uint8_t* EmitVP8XChunk(uint8_t* const dst, uint32_t width, static uint8_t* EmitVP8XChunk(uint8_t* const dst, uint32_t width,
uint32_t height, uint32_t flags) { uint32_t height, uint32_t flags) {
const size_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; 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);
PutLE32(dst, mktag('V', 'P', '8', 'X')); PutLE32(dst, mktag('V', 'P', '8', 'X'));
PutLE32(dst + TAG_SIZE, VP8X_CHUNK_SIZE); PutLE32(dst + TAG_SIZE, VP8X_CHUNK_SIZE);
PutLE32(dst + CHUNK_HEADER_SIZE, flags); PutLE32(dst + CHUNK_HEADER_SIZE, flags);
PutLE32(dst + CHUNK_HEADER_SIZE + 4, width); PutLE24(dst + CHUNK_HEADER_SIZE + 4, width - 1);
PutLE32(dst + CHUNK_HEADER_SIZE + 8, height); PutLE24(dst + CHUNK_HEADER_SIZE + 7, height - 1);
return dst + vp8x_size; return dst + vp8x_size;
} }

View File

@ -64,9 +64,17 @@ 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 FRAME_CHUNK_SIZE 20 // Size of a FRM chunk. #define FRAME_CHUNK_SIZE 20 // Size of a FRM chunk.
#define LOOP_CHUNK_SIZE 4 // Size of a LOOP chunk. #define LOOP_CHUNK_SIZE 4 // Size of a LOOP chunk.
#define TILE_CHUNK_SIZE 8 // Size of a LOOP chunk. #define TILE_CHUNK_SIZE 8 // Size of a TILE chunk.
#define VP8X_CHUNK_SIZE 12 // Size of a VP8X chunk. #define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk.
#define TILING_FLAG_BIT 0x01 // Set if tiles are possibly used.
#define ANIMATION_FLAG_BIT 0x02 // Set if some animation is expected
#define ICC_FLAG_BIT 0x04 // Whether ICC is present or not.
#define METADATA_FLAG_BIT 0x08 // Set if some META chunk is possibly present.
#define ALPHA_FLAG_BIT 0x10 // Should be same as the ALPHA_FLAG in mux.h #define ALPHA_FLAG_BIT 0x10 // Should be same as the ALPHA_FLAG in mux.h
#define ROTATION_FLAG_BITS 0xe0 // all 3 bits for rotation + symmetry
#define MAX_CANVAS_SIZE (1 << 24) // 24 bit max for VP8X width/height.
// 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.