diff options
Diffstat (limited to 'drivers/webpold/mux')
-rw-r--r-- | drivers/webpold/mux/demux.c | 902 | ||||
-rw-r--r-- | drivers/webpold/mux/muxedit.c | 712 | ||||
-rw-r--r-- | drivers/webpold/mux/muxi.h | 271 | ||||
-rw-r--r-- | drivers/webpold/mux/muxinternal.c | 576 | ||||
-rw-r--r-- | drivers/webpold/mux/muxread.c | 411 |
5 files changed, 0 insertions, 2872 deletions
diff --git a/drivers/webpold/mux/demux.c b/drivers/webpold/mux/demux.c deleted file mode 100644 index 501d08f41d..0000000000 --- a/drivers/webpold/mux/demux.c +++ /dev/null @@ -1,902 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// This code is licensed under the same terms as WebM: -// Software License Agreement: http://www.webmproject.org/license/software/ -// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ -// ----------------------------------------------------------------------------- -// -// WebP container demux. -// - -#include "../mux.h" - -#include <stdlib.h> -#include <string.h> - -#include "../decode.h" // WebPGetInfo -#include "../format_constants.h" - -#if defined(__cplusplus) || defined(c_plusplus) -extern "C" { -#endif - -#define MKFOURCC(a, b, c, d) ((uint32_t)(a) | (b) << 8 | (c) << 16 | (d) << 24) - -typedef struct { - size_t start_; // start location of the data - size_t end_; // end location - size_t riff_end_; // riff chunk end location, can be > end_. - size_t buf_size_; // size of the buffer - const uint8_t* buf_; -} MemBuffer; - -typedef struct { - size_t offset_; - size_t size_; -} ChunkData; - -typedef struct Frame { - int x_offset_, y_offset_; - int width_, height_; - int duration_; - int is_tile_; // this is an image fragment from a 'TILE'. - int frame_num_; // the referent frame number for use in assembling tiles. - int complete_; // img_components_ contains a full image. - ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH - struct Frame* next_; -} Frame; - -typedef struct Chunk { - ChunkData data_; - struct Chunk* next_; -} Chunk; - -struct WebPDemuxer { - MemBuffer mem_; - WebPDemuxState state_; - int is_ext_format_; - uint32_t feature_flags_; - int canvas_width_, canvas_height_; - int loop_count_; - int num_frames_; - Frame* frames_; - Chunk* chunks_; // non-image chunks -}; - -typedef enum { - PARSE_OK, - PARSE_NEED_MORE_DATA, - PARSE_ERROR -} ParseStatus; - -typedef struct ChunkParser { - uint8_t id[4]; - ParseStatus (*parse)(WebPDemuxer* const dmux); - int (*valid)(const WebPDemuxer* const dmux); -} ChunkParser; - -static ParseStatus ParseSingleImage(WebPDemuxer* const dmux); -static ParseStatus ParseVP8X(WebPDemuxer* const dmux); -static int IsValidSimpleFormat(const WebPDemuxer* const dmux); -static int IsValidExtendedFormat(const WebPDemuxer* const dmux); - -static const ChunkParser kMasterChunks[] = { - { { 'V', 'P', '8', ' ' }, ParseSingleImage, IsValidSimpleFormat }, - { { 'V', 'P', '8', 'L' }, ParseSingleImage, IsValidSimpleFormat }, - { { 'V', 'P', '8', 'X' }, ParseVP8X, IsValidExtendedFormat }, - { { '0', '0', '0', '0' }, NULL, NULL }, -}; - -// ----------------------------------------------------------------------------- -// MemBuffer - -static int RemapMemBuffer(MemBuffer* const mem, - const uint8_t* data, size_t size) { - if (size < mem->buf_size_) return 0; // can't remap to a shorter buffer! - - mem->buf_ = data; - mem->end_ = mem->buf_size_ = size; - return 1; -} - -static int InitMemBuffer(MemBuffer* const mem, - const uint8_t* data, size_t size) { - memset(mem, 0, sizeof(*mem)); - return RemapMemBuffer(mem, data, size); -} - -// Return the remaining data size available in 'mem'. -static WEBP_INLINE size_t MemDataSize(const MemBuffer* const mem) { - return (mem->end_ - mem->start_); -} - -// Return true if 'size' exceeds the end of the RIFF chunk. -static WEBP_INLINE int SizeIsInvalid(const MemBuffer* const mem, size_t size) { - return (size > mem->riff_end_ - mem->start_); -} - -static WEBP_INLINE void Skip(MemBuffer* const mem, size_t size) { - mem->start_ += size; -} - -static WEBP_INLINE void Rewind(MemBuffer* const mem, size_t size) { - mem->start_ -= size; -} - -static WEBP_INLINE const uint8_t* GetBuffer(MemBuffer* const mem) { - return mem->buf_ + mem->start_; -} - -static WEBP_INLINE uint8_t GetByte(MemBuffer* const mem) { - const uint8_t byte = mem->buf_[mem->start_]; - Skip(mem, 1); - 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 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 int val = ReadLE24s(data); - Skip(mem, 3); - return val; -} - -static WEBP_INLINE uint32_t GetLE32(MemBuffer* const mem) { - const uint8_t* const data = mem->buf_ + mem->start_; - const uint32_t val = ReadLE32(data); - Skip(mem, 4); - return val; -} - -// ----------------------------------------------------------------------------- -// Secondary chunk parsing - -static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) { - Chunk** c = &dmux->chunks_; - while (*c != NULL) c = &(*c)->next_; - *c = chunk; - chunk->next_ = NULL; -} - -// Add a frame to the end of the list, ensuring the last frame is complete. -// Returns true on success, false otherwise. -static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) { - const Frame* last_frame = NULL; - Frame** f = &dmux->frames_; - while (*f != NULL) { - last_frame = *f; - f = &(*f)->next_; - } - if (last_frame != NULL && !last_frame->complete_) return 0; - *f = frame; - frame->next_ = NULL; - return 1; -} - -// Store image bearing chunks to 'frame'. -static ParseStatus StoreFrame(int frame_num, MemBuffer* const mem, - Frame* const frame) { - int alpha_chunks = 0; - int image_chunks = 0; - int done = (MemDataSize(mem) < CHUNK_HEADER_SIZE); - ParseStatus status = PARSE_OK; - - if (done) return PARSE_NEED_MORE_DATA; - - do { - const size_t chunk_start_offset = mem->start_; - const uint32_t fourcc = GetLE32(mem); - const uint32_t payload_size = GetLE32(mem); - const uint32_t payload_size_padded = payload_size + (payload_size & 1); - const size_t payload_available = (payload_size_padded > MemDataSize(mem)) - ? MemDataSize(mem) : payload_size_padded; - const size_t chunk_size = CHUNK_HEADER_SIZE + payload_available; - - if (payload_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; - if (SizeIsInvalid(mem, payload_size_padded)) return PARSE_ERROR; - if (payload_size_padded > MemDataSize(mem)) status = PARSE_NEED_MORE_DATA; - - switch (fourcc) { - case MKFOURCC('A', 'L', 'P', 'H'): - if (alpha_chunks == 0) { - ++alpha_chunks; - frame->img_components_[1].offset_ = chunk_start_offset; - frame->img_components_[1].size_ = chunk_size; - frame->frame_num_ = frame_num; - Skip(mem, payload_available); - } else { - goto Done; - } - break; - case MKFOURCC('V', 'P', '8', ' '): - case MKFOURCC('V', 'P', '8', 'L'): - if (image_chunks == 0) { - int width = 0, height = 0; - ++image_chunks; - frame->img_components_[0].offset_ = chunk_start_offset; - frame->img_components_[0].size_ = chunk_size; - // Extract the width and height from the bitstream, tolerating - // failures when the data is incomplete. - if (!WebPGetInfo(mem->buf_ + frame->img_components_[0].offset_, - frame->img_components_[0].size_, &width, &height) && - status != PARSE_NEED_MORE_DATA) { - return PARSE_ERROR; - } - - frame->width_ = width; - frame->height_ = height; - frame->frame_num_ = frame_num; - frame->complete_ = (status == PARSE_OK); - Skip(mem, payload_available); - } else { - goto Done; - } - break; - Done: - default: - // Restore fourcc/size when moving up one level in parsing. - Rewind(mem, CHUNK_HEADER_SIZE); - done = 1; - break; - } - - if (mem->start_ == mem->riff_end_) { - done = 1; - } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { - status = PARSE_NEED_MORE_DATA; - } - } while (!done && status == PARSE_OK); - - return status; -} - -// Creates a new Frame if 'actual_size' is within bounds and 'mem' contains -// enough data ('min_size') to parse the payload. -// Returns PARSE_OK on success with *frame pointing to the new Frame. -// Returns PARSE_NEED_MORE_DATA with insufficient data, PARSE_ERROR otherwise. -static ParseStatus NewFrame(const MemBuffer* const mem, - uint32_t min_size, uint32_t expected_size, - uint32_t actual_size, Frame** frame) { - if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; - if (actual_size < expected_size) return PARSE_ERROR; - if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; - - *frame = (Frame*)calloc(1, sizeof(**frame)); - return (*frame == NULL) ? PARSE_ERROR : PARSE_OK; -} - -// Parse a 'FRM ' chunk and any image bearing chunks that immediately follow. -// 'frame_chunk_size' is the previously validated, padded chunk size. -static ParseStatus ParseFrame( - WebPDemuxer* const dmux, uint32_t frame_chunk_size) { - const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); - const uint32_t min_size = frame_chunk_size + CHUNK_HEADER_SIZE; - int added_frame = 0; - MemBuffer* const mem = &dmux->mem_; - Frame* frame; - ParseStatus status = - NewFrame(mem, min_size, FRAME_CHUNK_SIZE, frame_chunk_size, &frame); - if (status != PARSE_OK) return status; - - 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'. - status = StoreFrame(dmux->num_frames_ + 1, mem, frame); - if (status != PARSE_ERROR && has_frames && frame->frame_num_ > 0) { - added_frame = AddFrame(dmux, frame); - if (added_frame) { - ++dmux->num_frames_; - } else { - status = PARSE_ERROR; - } - } - - if (!added_frame) free(frame); - return status; -} - -// Parse a 'TILE' chunk and any image bearing chunks that immediately follow. -// 'tile_chunk_size' is the previously validated, padded chunk size. -static ParseStatus ParseTile(WebPDemuxer* const dmux, - uint32_t tile_chunk_size) { - const int has_tiles = !!(dmux->feature_flags_ & TILE_FLAG); - const uint32_t min_size = tile_chunk_size + CHUNK_HEADER_SIZE; - int added_tile = 0; - MemBuffer* const mem = &dmux->mem_; - Frame* frame; - ParseStatus status = - NewFrame(mem, min_size, TILE_CHUNK_SIZE, tile_chunk_size, &frame); - if (status != PARSE_OK) return status; - - frame->is_tile_ = 1; - 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 - // and the tile contains some data. - status = StoreFrame(dmux->num_frames_, mem, frame); - if (status != PARSE_ERROR && has_tiles && frame->frame_num_ > 0) { - // Note num_frames_ is incremented only when all tiles have been consumed. - added_tile = AddFrame(dmux, frame); - if (!added_tile) status = PARSE_ERROR; - } - - if (!added_tile) free(frame); - return status; -} - -// General chunk storage starting with the header at 'start_offset' allowing -// the user to request the payload via a fourcc string. 'size' includes the -// header and the unpadded payload size. -// Returns true on success, false otherwise. -static int StoreChunk(WebPDemuxer* const dmux, - size_t start_offset, uint32_t size) { - Chunk* const chunk = (Chunk*)calloc(1, sizeof(*chunk)); - if (chunk == NULL) return 0; - - chunk->data_.offset_ = start_offset; - chunk->data_.size_ = size; - AddChunk(dmux, chunk); - return 1; -} - -// ----------------------------------------------------------------------------- -// Primary chunk parsing - -static int ReadHeader(MemBuffer* const mem) { - const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE; - uint32_t riff_size; - - // Basic file level validation. - if (MemDataSize(mem) < min_size) return 0; - if (memcmp(GetBuffer(mem), "RIFF", CHUNK_SIZE_BYTES) || - memcmp(GetBuffer(mem) + CHUNK_HEADER_SIZE, "WEBP", CHUNK_SIZE_BYTES)) { - return 0; - } - - riff_size = ReadLE32(GetBuffer(mem) + TAG_SIZE); - if (riff_size < CHUNK_HEADER_SIZE) return 0; - if (riff_size > MAX_CHUNK_PAYLOAD) return 0; - - // There's no point in reading past the end of the RIFF chunk - mem->riff_end_ = riff_size + CHUNK_HEADER_SIZE; - if (mem->buf_size_ > mem->riff_end_) { - mem->buf_size_ = mem->end_ = mem->riff_end_; - } - - Skip(mem, RIFF_HEADER_SIZE); - return 1; -} - -static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { - const size_t min_size = CHUNK_HEADER_SIZE; - MemBuffer* const mem = &dmux->mem_; - Frame* frame; - ParseStatus status; - - if (dmux->frames_ != NULL) return PARSE_ERROR; - if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; - if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; - - frame = (Frame*)calloc(1, sizeof(*frame)); - if (frame == NULL) return PARSE_ERROR; - - status = StoreFrame(1, &dmux->mem_, frame); - if (status != PARSE_ERROR) { - const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG); - // Clear any alpha when the alpha flag is missing. - if (!has_alpha && frame->img_components_[1].size_ > 0) { - frame->img_components_[1].offset_ = 0; - frame->img_components_[1].size_ = 0; - } - - // Use the frame width/height as the canvas values for non-vp8x files. - if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) { - dmux->state_ = WEBP_DEMUX_PARSED_HEADER; - dmux->canvas_width_ = frame->width_; - dmux->canvas_height_ = frame->height_; - } - AddFrame(dmux, frame); - dmux->num_frames_ = 1; - } else { - free(frame); - } - - return status; -} - -static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { - MemBuffer* const mem = &dmux->mem_; - int loop_chunks = 0; - uint32_t vp8x_size; - ParseStatus status = PARSE_OK; - - if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; - - dmux->is_ext_format_ = 1; - Skip(mem, TAG_SIZE); // VP8X - vp8x_size = GetLE32(mem); - if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; - if (vp8x_size < VP8X_CHUNK_SIZE) return PARSE_ERROR; - vp8x_size += vp8x_size & 1; - if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR; - if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA; - - dmux->feature_flags_ = GetByte(mem); - Skip(mem, 3); // Reserved. - dmux->canvas_width_ = 1 + GetLE24s(mem); - dmux->canvas_height_ = 1 + GetLE24s(mem); - if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) { - return PARSE_ERROR; // image final dimension is too large - } - Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data. - dmux->state_ = WEBP_DEMUX_PARSED_HEADER; - - if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR; - if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; - - do { - int store_chunk = 1; - const size_t chunk_start_offset = mem->start_; - const uint32_t fourcc = GetLE32(mem); - const uint32_t chunk_size = GetLE32(mem); - const uint32_t chunk_size_padded = chunk_size + (chunk_size & 1); - - if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; - if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR; - - switch (fourcc) { - case MKFOURCC('V', 'P', '8', 'X'): { - return PARSE_ERROR; - } - case MKFOURCC('A', 'L', 'P', 'H'): - case MKFOURCC('V', 'P', '8', ' '): - case MKFOURCC('V', 'P', '8', 'L'): { - Rewind(mem, CHUNK_HEADER_SIZE); - status = ParseSingleImage(dmux); - break; - } - case MKFOURCC('L', 'O', 'O', 'P'): { - if (chunk_size_padded < LOOP_CHUNK_SIZE) return PARSE_ERROR; - - if (MemDataSize(mem) < chunk_size_padded) { - status = PARSE_NEED_MORE_DATA; - } else if (loop_chunks == 0) { - ++loop_chunks; - dmux->loop_count_ = GetLE16s(mem); - Skip(mem, chunk_size_padded - LOOP_CHUNK_SIZE); - } else { - store_chunk = 0; - goto Skip; - } - break; - } - case MKFOURCC('F', 'R', 'M', ' '): { - status = ParseFrame(dmux, chunk_size_padded); - break; - } - case MKFOURCC('T', 'I', 'L', 'E'): { - if (dmux->num_frames_ == 0) dmux->num_frames_ = 1; - status = ParseTile(dmux, chunk_size_padded); - break; - } - case MKFOURCC('I', 'C', 'C', 'P'): { - store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); - goto Skip; - } - case MKFOURCC('M', 'E', 'T', 'A'): { - store_chunk = !!(dmux->feature_flags_ & META_FLAG); - goto Skip; - } - Skip: - default: { - if (chunk_size_padded <= MemDataSize(mem)) { - if (store_chunk) { - // Store only the chunk header and unpadded size as only the payload - // will be returned to the user. - if (!StoreChunk(dmux, chunk_start_offset, - CHUNK_HEADER_SIZE + chunk_size)) { - return PARSE_ERROR; - } - } - Skip(mem, chunk_size_padded); - } else { - status = PARSE_NEED_MORE_DATA; - } - } - } - - if (mem->start_ == mem->riff_end_) { - break; - } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { - status = PARSE_NEED_MORE_DATA; - } - } while (status == PARSE_OK); - - return status; -} - -// ----------------------------------------------------------------------------- -// Format validation - -static int IsValidSimpleFormat(const WebPDemuxer* const dmux) { - const Frame* const frame = dmux->frames_; - if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; - - if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; - if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0; - - if (frame->width_ <= 0 || frame->height_ <= 0) return 0; - return 1; -} - -static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { - const int has_tiles = !!(dmux->feature_flags_ & TILE_FLAG); - const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); - const Frame* f; - - if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; - - if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; - if (dmux->loop_count_ < 0) return 0; - if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0; - - for (f = dmux->frames_; f != NULL; f = f->next_) { - const int cur_frame_set = f->frame_num_; - int frame_count = 0, tile_count = 0; - - // Check frame properties and if the image is composed of tiles that each - // fragment came from a 'TILE'. - for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) { - const ChunkData* const image = f->img_components_; - const ChunkData* const alpha = f->img_components_ + 1; - - if (!has_tiles && f->is_tile_) return 0; - if (!has_frames && f->frame_num_ > 1) return 0; - if (f->x_offset_ < 0 || f->y_offset_ < 0) return 0; - if (f->complete_) { - if (alpha->size_ == 0 && image->size_ == 0) return 0; - // Ensure alpha precedes image bitstream. - if (alpha->size_ > 0 && alpha->offset_ > image->offset_) { - return 0; - } - - if (f->width_ <= 0 || f->height_ <= 0) return 0; - } else { - // Ensure alpha precedes image bitstream. - if (alpha->size_ > 0 && image->size_ > 0 && - alpha->offset_ > image->offset_) { - return 0; - } - // There shouldn't be any frames after an incomplete one. - if (f->next_ != NULL) return 0; - } - - tile_count += f->is_tile_; - ++frame_count; - } - if (!has_tiles && frame_count > 1) return 0; - if (tile_count > 0 && frame_count != tile_count) return 0; - if (f == NULL) break; - } - return 1; -} - -// ----------------------------------------------------------------------------- -// WebPDemuxer object - -static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) { - dmux->state_ = WEBP_DEMUX_PARSING_HEADER; - dmux->loop_count_ = 1; - dmux->canvas_width_ = -1; - dmux->canvas_height_ = -1; - dmux->mem_ = *mem; -} - -WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial, - WebPDemuxState* state, int version) { - const ChunkParser* parser; - int partial; - ParseStatus status = PARSE_ERROR; - MemBuffer mem; - WebPDemuxer* dmux; - - if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DEMUX_ABI_VERSION)) return NULL; - if (data == NULL || data->bytes_ == NULL || data->size_ == 0) return NULL; - - if (!InitMemBuffer(&mem, data->bytes_, data->size_)) return NULL; - if (!ReadHeader(&mem)) return NULL; - - partial = (mem.buf_size_ < mem.riff_end_); - if (!allow_partial && partial) return NULL; - - dmux = (WebPDemuxer*)calloc(1, sizeof(*dmux)); - if (dmux == NULL) return NULL; - InitDemux(dmux, &mem); - - for (parser = kMasterChunks; parser->parse != NULL; ++parser) { - if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) { - status = parser->parse(dmux); - if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE; - if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR; - break; - } - } - if (state) *state = dmux->state_; - - if (status == PARSE_ERROR) { - WebPDemuxDelete(dmux); - return NULL; - } - return dmux; -} - -void WebPDemuxDelete(WebPDemuxer* dmux) { - Chunk* c; - Frame* f; - if (dmux == NULL) return; - - for (f = dmux->frames_; f != NULL;) { - Frame* const cur_frame = f; - f = f->next_; - free(cur_frame); - } - for (c = dmux->chunks_; c != NULL;) { - Chunk* const cur_chunk = c; - c = c->next_; - free(cur_chunk); - } - free(dmux); -} - -// ----------------------------------------------------------------------------- - -uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) { - if (dmux == NULL) return 0; - - switch (feature) { - case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags_; - case WEBP_FF_CANVAS_WIDTH: return (uint32_t)dmux->canvas_width_; - case WEBP_FF_CANVAS_HEIGHT: return (uint32_t)dmux->canvas_height_; - case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count_; - } - return 0; -} - -// ----------------------------------------------------------------------------- -// Frame iteration - -// Find the first 'frame_num' frame. There may be multiple in a tiled frame. -static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) { - const Frame* f; - for (f = dmux->frames_; f != NULL; f = f->next_) { - if (frame_num == f->frame_num_) break; - } - return f; -} - -// Returns tile 'tile_num' and the total count. -static const Frame* GetTile( - const Frame* const frame_set, int tile_num, int* const count) { - const int this_frame = frame_set->frame_num_; - const Frame* f = frame_set; - const Frame* tile = NULL; - int total; - - for (total = 0; f != NULL && f->frame_num_ == this_frame; f = f->next_) { - if (++total == tile_num) tile = f; - } - *count = total; - return tile; -} - -static const uint8_t* GetFramePayload(const uint8_t* const mem_buf, - const Frame* const frame, - size_t* const data_size) { - *data_size = 0; - if (frame != NULL) { - const ChunkData* const image = frame->img_components_; - const ChunkData* const alpha = frame->img_components_ + 1; - size_t start_offset = image->offset_; - *data_size = image->size_; - - // if alpha exists it precedes image, update the size allowing for - // intervening chunks. - if (alpha->size_ > 0) { - const size_t inter_size = (image->offset_ > 0) - ? image->offset_ - (alpha->offset_ + alpha->size_) - : 0; - start_offset = alpha->offset_; - *data_size += alpha->size_ + inter_size; - } - return mem_buf + start_offset; - } - return NULL; -} - -// Create a whole 'frame' from VP8 (+ alpha) or lossless. -static int SynthesizeFrame(const WebPDemuxer* const dmux, - const Frame* const first_frame, - int tile_num, WebPIterator* const iter) { - const uint8_t* const mem_buf = dmux->mem_.buf_; - int num_tiles; - size_t payload_size = 0; - const Frame* const tile = GetTile(first_frame, tile_num, &num_tiles); - const uint8_t* const payload = GetFramePayload(mem_buf, tile, &payload_size); - if (payload == NULL) return 0; - - iter->frame_num_ = first_frame->frame_num_; - iter->num_frames_ = dmux->num_frames_; - iter->tile_num_ = tile_num; - iter->num_tiles_ = num_tiles; - iter->x_offset_ = tile->x_offset_; - iter->y_offset_ = tile->y_offset_; - iter->width_ = tile->width_; - iter->height_ = tile->height_; - iter->duration_ = tile->duration_; - iter->complete_ = tile->complete_; - iter->tile_.bytes_ = payload; - iter->tile_.size_ = payload_size; - // TODO(jzern): adjust offsets for 'TILE's embedded in 'FRM 's - return 1; -} - -static int SetFrame(int frame_num, WebPIterator* const iter) { - const Frame* frame; - const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; - if (dmux == NULL || frame_num < 0) return 0; - if (frame_num > dmux->num_frames_) return 0; - if (frame_num == 0) frame_num = dmux->num_frames_; - - frame = GetFrame(dmux, frame_num); - return SynthesizeFrame(dmux, frame, 1, iter); -} - -int WebPDemuxGetFrame(const WebPDemuxer* dmux, int frame, WebPIterator* iter) { - if (iter == NULL) return 0; - - memset(iter, 0, sizeof(*iter)); - iter->private_ = (void*)dmux; - return SetFrame(frame, iter); -} - -int WebPDemuxNextFrame(WebPIterator* iter) { - if (iter == NULL) return 0; - return SetFrame(iter->frame_num_ + 1, iter); -} - -int WebPDemuxPrevFrame(WebPIterator* iter) { - if (iter == NULL) return 0; - if (iter->frame_num_ <= 1) return 0; - return SetFrame(iter->frame_num_ - 1, iter); -} - -int WebPDemuxSelectTile(WebPIterator* iter, int tile) { - if (iter != NULL && iter->private_ != NULL && tile > 0) { - const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; - const Frame* const frame = GetFrame(dmux, iter->frame_num_); - if (frame == NULL) return 0; - - return SynthesizeFrame(dmux, frame, tile, iter); - } - return 0; -} - -void WebPDemuxReleaseIterator(WebPIterator* iter) { - (void)iter; -} - -// ----------------------------------------------------------------------------- -// Chunk iteration - -static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) { - const uint8_t* const mem_buf = dmux->mem_.buf_; - const Chunk* c; - int count = 0; - for (c = dmux->chunks_; c != NULL; c = c->next_) { - const uint8_t* const header = mem_buf + c->data_.offset_; - if (!memcmp(header, fourcc, TAG_SIZE)) ++count; - } - return count; -} - -static const Chunk* GetChunk(const WebPDemuxer* const dmux, - const char fourcc[4], int chunk_num) { - const uint8_t* const mem_buf = dmux->mem_.buf_; - const Chunk* c; - int count = 0; - for (c = dmux->chunks_; c != NULL; c = c->next_) { - const uint8_t* const header = mem_buf + c->data_.offset_; - if (!memcmp(header, fourcc, TAG_SIZE)) ++count; - if (count == chunk_num) break; - } - return c; -} - -static int SetChunk(const char fourcc[4], int chunk_num, - WebPChunkIterator* const iter) { - const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; - int count; - - if (dmux == NULL || fourcc == NULL || chunk_num < 0) return 0; - count = ChunkCount(dmux, fourcc); - if (count == 0) return 0; - if (chunk_num == 0) chunk_num = count; - - if (chunk_num <= count) { - const uint8_t* const mem_buf = dmux->mem_.buf_; - const Chunk* const chunk = GetChunk(dmux, fourcc, chunk_num); - iter->chunk_.bytes_ = mem_buf + chunk->data_.offset_ + CHUNK_HEADER_SIZE; - iter->chunk_.size_ = chunk->data_.size_ - CHUNK_HEADER_SIZE; - iter->num_chunks_ = count; - iter->chunk_num_ = chunk_num; - return 1; - } - return 0; -} - -int WebPDemuxGetChunk(const WebPDemuxer* dmux, - const char fourcc[4], int chunk_num, - WebPChunkIterator* iter) { - if (iter == NULL) return 0; - - memset(iter, 0, sizeof(*iter)); - iter->private_ = (void*)dmux; - return SetChunk(fourcc, chunk_num, iter); -} - -int WebPDemuxNextChunk(WebPChunkIterator* iter) { - if (iter != NULL) { - const char* const fourcc = - (const char*)iter->chunk_.bytes_ - CHUNK_HEADER_SIZE; - return SetChunk(fourcc, iter->chunk_num_ + 1, iter); - } - return 0; -} - -int WebPDemuxPrevChunk(WebPChunkIterator* iter) { - if (iter != NULL && iter->chunk_num_ > 1) { - const char* const fourcc = - (const char*)iter->chunk_.bytes_ - CHUNK_HEADER_SIZE; - return SetChunk(fourcc, iter->chunk_num_ - 1, iter); - } - return 0; -} - -void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) { - (void)iter; -} - -#if defined(__cplusplus) || defined(c_plusplus) -} // extern "C" -#endif diff --git a/drivers/webpold/mux/muxedit.c b/drivers/webpold/mux/muxedit.c deleted file mode 100644 index 08629d4ae2..0000000000 --- a/drivers/webpold/mux/muxedit.c +++ /dev/null @@ -1,712 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// This code is licensed under the same terms as WebM: -// Software License Agreement: http://www.webmproject.org/license/software/ -// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ -// ----------------------------------------------------------------------------- -// -// Set and delete APIs for mux. -// -// Authors: Urvang (urvang@google.com) -// Vikas (vikasa@google.com) - -#include <assert.h> -#include "./muxi.h" - -#if defined(__cplusplus) || defined(c_plusplus) -extern "C" { -#endif - -//------------------------------------------------------------------------------ -// Life of a mux object. - -static void MuxInit(WebPMux* const mux) { - if (mux == NULL) return; - memset(mux, 0, sizeof(*mux)); -} - -WebPMux* WebPNewInternal(int version) { - if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) { - return NULL; - } else { - WebPMux* const mux = (WebPMux*)malloc(sizeof(WebPMux)); - // If mux is NULL MuxInit is a noop. - MuxInit(mux); - return mux; - } -} - -static void DeleteAllChunks(WebPChunk** const chunk_list) { - while (*chunk_list) { - *chunk_list = ChunkDelete(*chunk_list); - } -} - -static void MuxRelease(WebPMux* const mux) { - if (mux == NULL) return; - MuxImageDeleteAll(&mux->images_); - DeleteAllChunks(&mux->vp8x_); - DeleteAllChunks(&mux->iccp_); - DeleteAllChunks(&mux->loop_); - DeleteAllChunks(&mux->meta_); - DeleteAllChunks(&mux->unknown_); -} - -void WebPMuxDelete(WebPMux* mux) { - // If mux is NULL MuxRelease is a noop. - MuxRelease(mux); - free(mux); -} - -//------------------------------------------------------------------------------ -// Helper method(s). - -// Handy MACRO, makes MuxSet() very symmetric to MuxGet(). -#define SWITCH_ID_LIST(INDEX, LIST) \ - if (idx == (INDEX)) { \ - err = ChunkAssignData(&chunk, data, copy_data, kChunks[(INDEX)].tag); \ - if (err == WEBP_MUX_OK) { \ - err = ChunkSetNth(&chunk, (LIST), nth); \ - } \ - return err; \ - } - -static WebPMuxError MuxSet(WebPMux* const mux, CHUNK_INDEX idx, uint32_t nth, - const WebPData* const data, int copy_data) { - WebPChunk chunk; - WebPMuxError err = WEBP_MUX_NOT_FOUND; - assert(mux != NULL); - assert(!IsWPI(kChunks[idx].id)); - - ChunkInit(&chunk); - SWITCH_ID_LIST(IDX_VP8X, &mux->vp8x_); - SWITCH_ID_LIST(IDX_ICCP, &mux->iccp_); - SWITCH_ID_LIST(IDX_LOOP, &mux->loop_); - SWITCH_ID_LIST(IDX_META, &mux->meta_); - if (idx == IDX_UNKNOWN && data->size_ > TAG_SIZE) { - // For raw-data unknown chunk, the first four bytes should be the tag to be - // used for the chunk. - const WebPData tmp = { data->bytes_ + TAG_SIZE, data->size_ - TAG_SIZE }; - err = ChunkAssignData(&chunk, &tmp, copy_data, GetLE32(data->bytes_ + 0)); - if (err == WEBP_MUX_OK) - err = ChunkSetNth(&chunk, &mux->unknown_, nth); - } - return err; -} -#undef SWITCH_ID_LIST - -static WebPMuxError MuxAddChunk(WebPMux* const mux, uint32_t nth, uint32_t tag, - const uint8_t* data, size_t size, - int copy_data) { - const CHUNK_INDEX idx = ChunkGetIndexFromTag(tag); - const WebPData chunk_data = { data, size }; - assert(mux != NULL); - assert(size <= MAX_CHUNK_PAYLOAD); - assert(idx != IDX_NIL); - return MuxSet(mux, idx, nth, &chunk_data, copy_data); -} - -// Create data for frame/tile given image data, offsets and duration. -static WebPMuxError CreateFrameTileData(const WebPData* const image, - int x_offset, int y_offset, - int duration, int is_lossless, - int is_frame, - WebPData* const frame_tile) { - int width; - int height; - uint8_t* frame_tile_bytes; - const size_t frame_tile_size = kChunks[is_frame ? IDX_FRAME : IDX_TILE].size; - - const int ok = is_lossless ? - VP8LGetInfo(image->bytes_, image->size_, &width, &height, NULL) : - 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; - - PutLE24(frame_tile_bytes + 0, x_offset / 2); - PutLE24(frame_tile_bytes + 3, y_offset / 2); - - if (is_frame) { - 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; - frame_tile->size_ = frame_tile_size; - return WEBP_MUX_OK; -} - -// 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. -static WebPMuxError GetImageData(const WebPData* const bitstream, - WebPData* const image, WebPData* const alpha, - int* const is_lossless) { - WebPDataInit(alpha); // Default: no alpha. - if (bitstream->size_ < TAG_SIZE || - memcmp(bitstream->bytes_, "RIFF", TAG_SIZE)) { - // It is NOT webp file data. Return input data as is. - *image = *bitstream; - } else { - // It is webp file data. Extract image data from it. - const WebPMuxImage* wpi; - WebPMux* const mux = WebPMuxCreate(bitstream, 0); - if (mux == NULL) return WEBP_MUX_BAD_DATA; - wpi = mux->images_; - assert(wpi != NULL && wpi->img_ != NULL); - *image = wpi->img_->data_; - if (wpi->alpha_ != NULL) { - *alpha = wpi->alpha_->data_; - } - WebPMuxDelete(mux); - } - *is_lossless = VP8LCheckSignature(image->bytes_, image->size_); - return WEBP_MUX_OK; -} - -static WebPMuxError DeleteChunks(WebPChunk** chunk_list, uint32_t tag) { - WebPMuxError err = WEBP_MUX_NOT_FOUND; - assert(chunk_list); - while (*chunk_list) { - WebPChunk* const chunk = *chunk_list; - if (chunk->tag_ == tag) { - *chunk_list = ChunkDelete(chunk); - err = WEBP_MUX_OK; - } else { - chunk_list = &chunk->next_; - } - } - return err; -} - -static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux, CHUNK_INDEX idx) { - const WebPChunkId id = kChunks[idx].id; - WebPChunk** chunk_list; - - if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; - if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT; - - chunk_list = MuxGetChunkListFromId(mux, id); - if (chunk_list == NULL) return WEBP_MUX_INVALID_ARGUMENT; - - return DeleteChunks(chunk_list, kChunks[idx].tag); -} - -static WebPMuxError DeleteLoopCount(WebPMux* const mux) { - return MuxDeleteAllNamedData(mux, IDX_LOOP); -} - -//------------------------------------------------------------------------------ -// Set API(s). - -WebPMuxError WebPMuxSetImage(WebPMux* mux, - const WebPData* bitstream, int copy_data) { - WebPMuxError err; - WebPChunk chunk; - WebPMuxImage wpi; - WebPData image; - WebPData alpha; - int is_lossless; - int image_tag; - - if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL || - bitstream->size_ > MAX_CHUNK_PAYLOAD) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - // If given data is for a whole webp file, - // extract only the VP8/VP8L data from it. - err = GetImageData(bitstream, &image, &alpha, &is_lossless); - if (err != WEBP_MUX_OK) return err; - image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; - - // Delete the existing images. - MuxImageDeleteAll(&mux->images_); - - MuxImageInit(&wpi); - - if (alpha.bytes_ != NULL) { // Add alpha chunk. - ChunkInit(&chunk); - err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag); - if (err != WEBP_MUX_OK) goto Err; - err = ChunkSetNth(&chunk, &wpi.alpha_, 1); - if (err != WEBP_MUX_OK) goto Err; - } - - // Add image chunk. - ChunkInit(&chunk); - err = ChunkAssignData(&chunk, &image, copy_data, image_tag); - if (err != WEBP_MUX_OK) goto Err; - err = ChunkSetNth(&chunk, &wpi.img_, 1); - if (err != WEBP_MUX_OK) goto Err; - - // Add this image to mux. - err = MuxImagePush(&wpi, &mux->images_); - 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* mux, const WebPData* metadata, - int copy_data) { - WebPMuxError err; - - if (mux == NULL || metadata == NULL || metadata->bytes_ == NULL || - metadata->size_ > MAX_CHUNK_PAYLOAD) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - // Delete the existing metadata chunk(s). - err = WebPMuxDeleteMetadata(mux); - if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; - - // Add the given metadata chunk. - return MuxSet(mux, IDX_META, 1, metadata, copy_data); -} - -WebPMuxError WebPMuxSetColorProfile(WebPMux* mux, const WebPData* color_profile, - int copy_data) { - WebPMuxError err; - - if (mux == NULL || color_profile == NULL || color_profile->bytes_ == NULL || - color_profile->size_ > MAX_CHUNK_PAYLOAD) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - // Delete the existing ICCP chunk(s). - err = WebPMuxDeleteColorProfile(mux); - if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; - - // Add the given ICCP chunk. - return MuxSet(mux, IDX_ICCP, 1, color_profile, copy_data); -} - -WebPMuxError WebPMuxSetLoopCount(WebPMux* 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); - if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; - - // Add the given loop count. - data = (uint8_t*)malloc(kChunks[IDX_LOOP].size); - if (data == NULL) return WEBP_MUX_MEMORY_ERROR; - - PutLE16(data, loop_count); - err = MuxAddChunk(mux, 1, kChunks[IDX_LOOP].tag, data, - kChunks[IDX_LOOP].size, 1); - free(data); - return err; -} - -static WebPMuxError MuxPushFrameTileInternal( - 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; - WebPMuxImage wpi; - WebPMuxError err; - WebPData frame_tile; - const int is_frame = (tag == kChunks[IDX_FRAME].tag) ? 1 : 0; - 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. - err = GetImageData(bitstream, &image, &alpha, &is_lossless); - if (err != WEBP_MUX_OK) return err; - image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; - - WebPDataInit(&frame_tile); - ChunkInit(&chunk); - MuxImageInit(&wpi); - - if (alpha.bytes_ != NULL) { - // Add alpha chunk. - err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag); - if (err != WEBP_MUX_OK) goto Err; - err = ChunkSetNth(&chunk, &wpi.alpha_, 1); - if (err != WEBP_MUX_OK) goto Err; - ChunkInit(&chunk); // chunk owned by wpi.alpha_ now. - } - - // Add image chunk. - err = ChunkAssignData(&chunk, &image, copy_data, image_tag); - if (err != WEBP_MUX_OK) goto Err; - err = ChunkSetNth(&chunk, &wpi.img_, 1); - if (err != WEBP_MUX_OK) goto Err; - ChunkInit(&chunk); // chunk owned by wpi.img_ now. - - // Create frame/tile data. - err = CreateFrameTileData(&image, x_offset, y_offset, duration, is_lossless, - is_frame, &frame_tile); - if (err != WEBP_MUX_OK) goto Err; - - // Add frame/tile chunk (with copy_data = 1). - err = ChunkAssignData(&chunk, &frame_tile, 1, tag); - if (err != WEBP_MUX_OK) goto Err; - WebPDataClear(&frame_tile); - err = ChunkSetNth(&chunk, &wpi.header_, 1); - if (err != WEBP_MUX_OK) goto Err; - ChunkInit(&chunk); // chunk owned by wpi.header_ now. - - // Add this WebPMuxImage to mux. - err = MuxImagePush(&wpi, &mux->images_); - if (err != WEBP_MUX_OK) goto Err; - - // All is well. - return WEBP_MUX_OK; - - Err: // Something bad happened. - WebPDataClear(&frame_tile); - ChunkRelease(&chunk); - MuxImageRelease(&wpi); - return err; -} - -WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPData* bitstream, - 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* mux, const WebPData* bitstream, - int x_offset, int y_offset, - int copy_data) { - return MuxPushFrameTileInternal(mux, bitstream, x_offset, y_offset, - 1 /* unused duration */, copy_data, - kChunks[IDX_TILE].tag); -} - -//------------------------------------------------------------------------------ -// Delete API(s). - -WebPMuxError WebPMuxDeleteImage(WebPMux* mux) { - WebPMuxError err; - - if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; - - err = MuxValidateForImage(mux); - if (err != WEBP_MUX_OK) return err; - - // All well, delete image. - MuxImageDeleteAll(&mux->images_); - return WEBP_MUX_OK; -} - -WebPMuxError WebPMuxDeleteMetadata(WebPMux* mux) { - return MuxDeleteAllNamedData(mux, IDX_META); -} - -WebPMuxError WebPMuxDeleteColorProfile(WebPMux* mux) { - return MuxDeleteAllNamedData(mux, IDX_ICCP); -} - -static WebPMuxError DeleteFrameTileInternal(WebPMux* const mux, uint32_t nth, - CHUNK_INDEX idx) { - const WebPChunkId id = kChunks[idx].id; - if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; - - assert(idx == IDX_FRAME || idx == IDX_TILE); - return MuxImageDeleteNth(&mux->images_, nth, id); -} - -WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth) { - return DeleteFrameTileInternal(mux, nth, IDX_FRAME); -} - -WebPMuxError WebPMuxDeleteTile(WebPMux* mux, uint32_t nth) { - return DeleteFrameTileInternal(mux, nth, IDX_TILE); -} - -//------------------------------------------------------------------------------ -// Assembly of the WebP RIFF file. - -static WebPMuxError GetFrameTileInfo(const WebPChunk* const frame_tile_chunk, - 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_; - const size_t expected_data_size = - is_frame ? FRAME_CHUNK_SIZE : TILE_CHUNK_SIZE; - assert(frame_tile_chunk != NULL); - assert(tag == kChunks[IDX_FRAME].tag || tag == kChunks[IDX_TILE].tag); - if (data->size_ != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT; - - *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; -} - -WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk, - int* const width, int* const height) { - const uint32_t tag = image_chunk->tag_; - const WebPData* const data = &image_chunk->data_; - int w, h; - int ok; - assert(image_chunk != NULL); - assert(tag == kChunks[IDX_VP8].tag || tag == kChunks[IDX_VP8L].tag); - ok = (tag == kChunks[IDX_VP8].tag) ? - VP8GetInfo(data->bytes_, data->size_, data->size_, &w, &h) : - VP8LGetInfo(data->bytes_, data->size_, &w, &h, NULL); - if (ok) { - *width = w; - *height = h; - return WEBP_MUX_OK; - } else { - return WEBP_MUX_BAD_DATA; - } -} - -static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi, - int* const x_offset, int* const y_offset, - int* const duration, - int* const width, int* const height) { - const WebPChunk* const image_chunk = wpi->img_; - const WebPChunk* const frame_tile_chunk = wpi->header_; - - // Get offsets and duration from FRM/TILE chunk. - const WebPMuxError err = - GetFrameTileInfo(frame_tile_chunk, x_offset, y_offset, duration); - if (err != WEBP_MUX_OK) return err; - - // Get width and height from VP8/VP8L chunk. - return MuxGetImageWidthHeight(image_chunk, width, height); -} - -static WebPMuxError GetImageCanvasWidthHeight( - const WebPMux* const mux, uint32_t flags, - int* const width, int* const height) { - WebPMuxImage* wpi = NULL; - assert(mux != NULL); - assert(width != NULL && height != NULL); - - wpi = mux->images_; - assert(wpi != NULL); - assert(wpi->img_ != NULL); - - if (wpi->next_) { - 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_) { - int x_offset, y_offset, duration, w, h; - const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset, - &duration, &w, &h); - const int max_x_pos = x_offset + w; - const int max_y_pos = y_offset + h; - if (err != WEBP_MUX_OK) return err; - assert(x_offset < MAX_POSITION_OFFSET); - assert(y_offset < MAX_POSITION_OFFSET); - - if (max_x_pos > max_x) max_x = max_x_pos; - if (max_y_pos > max_y) max_y = max_y_pos; - image_area += w * h; - } - *width = max_x; - *height = max_y; - // Crude check to validate that there are no image overlaps/holes for tile - // images. Check that the aggregated image area for individual tiles exactly - // matches the image area of the constructed canvas. However, the area-match - // is necessary but not sufficient condition. - if ((flags & TILE_FLAG) && (image_area != (max_x * max_y))) { - *width = 0; - *height = 0; - return WEBP_MUX_INVALID_ARGUMENT; - } - } else { - // For a single image, extract the width & height from VP8/VP8L image-data. - int w, h; - const WebPChunk* const image_chunk = wpi->img_; - const WebPMuxError err = MuxGetImageWidthHeight(image_chunk, &w, &h); - if (err != WEBP_MUX_OK) return err; - *width = w; - *height = h; - } - return WEBP_MUX_OK; -} - -// VP8X format: -// Total Size : 10, -// Flags : 4 bytes, -// Width : 3 bytes, -// Height : 3 bytes. -static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { - WebPMuxError err = WEBP_MUX_OK; - uint32_t flags = 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; - - assert(mux != NULL); - images = mux->images_; // First image. - if (images == NULL || images->img_ == NULL || - images->img_->data_.bytes_ == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - // If VP8X chunk(s) is(are) already present, remove them (and later add new - // VP8X chunk with updated flags). - err = MuxDeleteAllNamedData(mux, IDX_VP8X); - if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; - - // Set flags. - if (mux->iccp_ != NULL && mux->iccp_->data_.bytes_ != NULL) { - flags |= ICCP_FLAG; - } - - if (mux->meta_ != NULL && mux->meta_->data_.bytes_ != NULL) { - flags |= META_FLAG; - } - - if (images->header_ != NULL) { - if (images->header_->tag_ == kChunks[IDX_TILE].tag) { - // This is a tiled image. - flags |= TILE_FLAG; - } else if (images->header_->tag_ == kChunks[IDX_FRAME].tag) { - // This is an image with animation. - flags |= ANIMATION_FLAG; - } - } - - if (MuxImageCount(images, WEBP_CHUNK_ALPHA) > 0) { - flags |= ALPHA_FLAG; // Some images have an alpha channel. - } - - if (flags == 0) { - // For Simple Image, VP8X chunk should not be added. - return WEBP_MUX_OK; - } - - 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. - // Note: This 'flags' update must NOT be done for a lossless image - // without a VP8X chunk! - flags |= ALPHA_FLAG; - } - - PutLE32(data + 0, flags); // VP8X chunk flags. - PutLE24(data + 4, width - 1); // canvas width. - PutLE24(data + 7, height - 1); // canvas height. - - err = MuxAddChunk(mux, 1, kChunks[IDX_VP8X].tag, data, data_size, 1); - return err; -} - -WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) { - size_t size = 0; - uint8_t* data = NULL; - uint8_t* dst = NULL; - int num_frames; - int num_loop_chunks; - WebPMuxError err; - - if (mux == NULL || assembled_data == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - // Remove LOOP chunk if unnecessary. - err = WebPMuxNumChunks(mux, kChunks[IDX_LOOP].id, &num_loop_chunks); - if (err != WEBP_MUX_OK) return err; - if (num_loop_chunks >= 1) { - err = WebPMuxNumChunks(mux, kChunks[IDX_FRAME].id, &num_frames); - if (err != WEBP_MUX_OK) return err; - if (num_frames == 0) { - err = DeleteLoopCount(mux); - if (err != WEBP_MUX_OK) return err; - } - } - - // Create VP8X chunk. - err = CreateVP8XChunk(mux); - if (err != WEBP_MUX_OK) return err; - - // Allocate data. - size = ChunksListDiskSize(mux->vp8x_) + ChunksListDiskSize(mux->iccp_) - + ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_) - + ChunksListDiskSize(mux->meta_) + ChunksListDiskSize(mux->unknown_) - + RIFF_HEADER_SIZE; - - data = (uint8_t*)malloc(size); - if (data == NULL) return WEBP_MUX_MEMORY_ERROR; - - // Emit header & chunks. - dst = MuxEmitRiffHeader(data, size); - dst = ChunkListEmit(mux->vp8x_, dst); - dst = ChunkListEmit(mux->iccp_, dst); - dst = ChunkListEmit(mux->loop_, dst); - dst = MuxImageListEmit(mux->images_, dst); - dst = ChunkListEmit(mux->meta_, dst); - dst = ChunkListEmit(mux->unknown_, dst); - assert(dst == data + size); - - // Validate mux. - err = MuxValidate(mux); - if (err != WEBP_MUX_OK) { - free(data); - data = NULL; - size = 0; - } - - // Finalize. - assembled_data->bytes_ = data; - assembled_data->size_ = size; - - return err; -} - -//------------------------------------------------------------------------------ - -#if defined(__cplusplus) || defined(c_plusplus) -} // extern "C" -#endif diff --git a/drivers/webpold/mux/muxi.h b/drivers/webpold/mux/muxi.h deleted file mode 100644 index 2f06f3ed03..0000000000 --- a/drivers/webpold/mux/muxi.h +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// This code is licensed under the same terms as WebM: -// Software License Agreement: http://www.webmproject.org/license/software/ -// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ -// ----------------------------------------------------------------------------- -// -// Internal header for mux library. -// -// Author: Urvang (urvang@google.com) - -#ifndef WEBP_MUX_MUXI_H_ -#define WEBP_MUX_MUXI_H_ - -#include <stdlib.h> -#include "../dec/vp8i.h" -#include "../dec/vp8li.h" -#include "../format_constants.h" -#include "../mux.h" - -#if defined(__cplusplus) || defined(c_plusplus) -extern "C" { -#endif - -//------------------------------------------------------------------------------ -// Defines and constants. - -// Chunk object. -typedef struct WebPChunk WebPChunk; -struct WebPChunk { - uint32_t tag_; - int owner_; // True if *data_ memory is owned internally. - // VP8X, Loop, and other internally created chunks - // like frame/tile are always owned. - WebPData data_; - WebPChunk* next_; -}; - -// MuxImage object. Store a full webp image (including frame/tile chunk, alpha -// chunk and VP8/VP8L chunk), -typedef struct WebPMuxImage WebPMuxImage; -struct WebPMuxImage { - WebPChunk* header_; // Corresponds to WEBP_CHUNK_FRAME/WEBP_CHUNK_TILE. - WebPChunk* alpha_; // Corresponds to WEBP_CHUNK_ALPHA. - WebPChunk* img_; // Corresponds to WEBP_CHUNK_IMAGE. - int is_partial_; // True if only some of the chunks are filled. - WebPMuxImage* next_; -}; - -// Main mux object. Stores data chunks. -struct WebPMux { - WebPMuxImage* images_; - WebPChunk* iccp_; - WebPChunk* meta_; - WebPChunk* loop_; - WebPChunk* vp8x_; - - WebPChunk* unknown_; -}; - -// CHUNK_INDEX enum: used for indexing within 'kChunks' (defined below) only. -// Note: the reason for having two enums ('WebPChunkId' and 'CHUNK_INDEX') is to -// allow two different chunks to have the same id (e.g. WebPChunkId -// 'WEBP_CHUNK_IMAGE' can correspond to CHUNK_INDEX 'IDX_VP8' or 'IDX_VP8L'). -typedef enum { - IDX_VP8X = 0, - IDX_ICCP, - IDX_LOOP, - IDX_FRAME, - IDX_TILE, - IDX_ALPHA, - IDX_VP8, - IDX_VP8L, - IDX_META, - IDX_UNKNOWN, - - IDX_NIL, - IDX_LAST_CHUNK -} CHUNK_INDEX; - -#define NIL_TAG 0x00000000u // To signal void chunk. - -#define MKFOURCC(a, b, c, d) ((uint32_t)(a) | (b) << 8 | (c) << 16 | (d) << 24) - -typedef struct { - uint32_t tag; - WebPChunkId id; - uint32_t size; -} ChunkInfo; - -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 (uint32_t)GetLE16(data) | (GetLE16(data + 2) << 16); -} - -// 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, 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, (int)(val & 0xffff)); - PutLE16(data + 2, (int)(val >> 16)); -} - -static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) { - return CHUNK_HEADER_SIZE + ((chunk_size + 1) & ~1U); -} - -//------------------------------------------------------------------------------ -// Chunk object management. - -// Initialize. -void ChunkInit(WebPChunk* const chunk); - -// Get chunk index from chunk tag. Returns IDX_NIL if not found. -CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag); - -// Get chunk id from chunk tag. Returns WEBP_CHUNK_NIL if not found. -WebPChunkId ChunkGetIdFromTag(uint32_t tag); - -// Search for nth chunk with given 'tag' in the chunk list. -// nth = 0 means "last of the list". -WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag); - -// Fill the chunk with the given data. -WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data, - int copy_data, uint32_t tag); - -// Sets 'chunk' at nth position in the 'chunk_list'. -// nth = 0 has the special meaning "last of the list". -WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list, - uint32_t nth); - -// Releases chunk and returns chunk->next_. -WebPChunk* ChunkRelease(WebPChunk* const chunk); - -// Deletes given chunk & returns chunk->next_. -WebPChunk* ChunkDelete(WebPChunk* const chunk); - -// Size of a chunk including header and padding. -static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) { - const size_t data_size = chunk->data_.size_; - assert(data_size < MAX_CHUNK_PAYLOAD); - return SizeWithPadding(data_size); -} - -// Total size of a list of chunks. -size_t ChunksListDiskSize(const WebPChunk* chunk_list); - -// Write out the given list of chunks into '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. - -// Initialize. -void MuxImageInit(WebPMuxImage* const wpi); - -// Releases image 'wpi' and returns wpi->next. -WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi); - -// Delete image 'wpi' and return the next image in the list or NULL. -// 'wpi' can be NULL. -WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi); - -// Delete all images in 'wpi_list'. -void MuxImageDeleteAll(WebPMuxImage** const wpi_list); - -// Count number of images matching the given tag id in the 'wpi_list'. -int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id); - -// Check if given ID corresponds to an image related chunk. -static WEBP_INLINE int IsWPI(WebPChunkId id) { - switch (id) { - case WEBP_CHUNK_FRAME: - case WEBP_CHUNK_TILE: - case WEBP_CHUNK_ALPHA: - case WEBP_CHUNK_IMAGE: return 1; - default: return 0; - } -} - -// Get a reference to appropriate chunk list within an image given chunk tag. -static WEBP_INLINE WebPChunk** MuxImageGetListFromId( - const WebPMuxImage* const wpi, WebPChunkId id) { - assert(wpi != NULL); - switch (id) { - case WEBP_CHUNK_FRAME: - case WEBP_CHUNK_TILE: return (WebPChunk**)&wpi->header_; - case WEBP_CHUNK_ALPHA: return (WebPChunk**)&wpi->alpha_; - case WEBP_CHUNK_IMAGE: return (WebPChunk**)&wpi->img_; - default: return NULL; - } -} - -// Pushes 'wpi' at the end of 'wpi_list'. -WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list); - -// Delete nth image in the image list with given tag id. -WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth, - WebPChunkId id); - -// Get nth image in the image list with given tag id. -WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth, - WebPChunkId id, WebPMuxImage** wpi); - -// Total size of the given image. -size_t MuxImageDiskSize(const WebPMuxImage* const wpi); - -// Total size of a list of images. -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'. -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. -int MuxHasLosslessImages(const WebPMuxImage* images); - -// Write out RIFF header into 'data', given total data size 'size'. -uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size); - -// 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 -// or if 'id' is not known. -WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id); - -// Validates that the given mux has a single image. -WebPMuxError MuxValidateForImage(const WebPMux* const mux); - -// Validates the given mux object. -WebPMuxError MuxValidate(const WebPMux* const mux); - -//------------------------------------------------------------------------------ - -#if defined(__cplusplus) || defined(c_plusplus) -} // extern "C" -#endif - -#endif /* WEBP_MUX_MUXI_H_ */ diff --git a/drivers/webpold/mux/muxinternal.c b/drivers/webpold/mux/muxinternal.c deleted file mode 100644 index 6c3c4fe60a..0000000000 --- a/drivers/webpold/mux/muxinternal.c +++ /dev/null @@ -1,576 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// This code is licensed under the same terms as WebM: -// Software License Agreement: http://www.webmproject.org/license/software/ -// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ -// ----------------------------------------------------------------------------- -// -// Internal objects and utils for mux. -// -// Authors: Urvang (urvang@google.com) -// Vikas (vikasa@google.com) - -#include <assert.h> -#include "./muxi.h" - -#if defined(__cplusplus) || defined(c_plusplus) -extern "C" { -#endif - -#define UNDEFINED_CHUNK_SIZE (-1) - -const ChunkInfo kChunks[] = { - { 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 } -}; - -//------------------------------------------------------------------------------ -// Life of a chunk object. - -void ChunkInit(WebPChunk* const chunk) { - assert(chunk); - memset(chunk, 0, sizeof(*chunk)); - chunk->tag_ = NIL_TAG; -} - -WebPChunk* ChunkRelease(WebPChunk* const chunk) { - WebPChunk* next; - if (chunk == NULL) return NULL; - if (chunk->owner_) { - WebPDataClear(&chunk->data_); - } - next = chunk->next_; - ChunkInit(chunk); - return next; -} - -//------------------------------------------------------------------------------ -// Chunk misc methods. - -CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag) { - int i; - for (i = 0; kChunks[i].tag != NIL_TAG; ++i) { - if (tag == kChunks[i].tag) return i; - } - return IDX_NIL; -} - -WebPChunkId ChunkGetIdFromTag(uint32_t tag) { - int i; - for (i = 0; kChunks[i].tag != NIL_TAG; ++i) { - if (tag == kChunks[i].tag) return kChunks[i].id; - } - return WEBP_CHUNK_NIL; -} - -//------------------------------------------------------------------------------ -// Chunk search methods. - -// Returns next chunk in the chunk list with the given tag. -static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) { - while (chunk && chunk->tag_ != tag) { - chunk = chunk->next_; - } - return chunk; -} - -WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) { - uint32_t iter = nth; - first = ChunkSearchNextInList(first, tag); - if (!first) return NULL; - - while (--iter != 0) { - WebPChunk* next_chunk = ChunkSearchNextInList(first->next_, tag); - if (next_chunk == NULL) break; - first = next_chunk; - } - return ((nth > 0) && (iter > 0)) ? NULL : first; -} - -// Outputs a pointer to 'prev_chunk->next_', -// where 'prev_chunk' is the pointer to the chunk at position (nth - 1). -// Returns 1 if nth chunk was found, 0 otherwise. -static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth, - WebPChunk*** const location) { - uint32_t count = 0; - assert(chunk_list); - *location = chunk_list; - - while (*chunk_list) { - WebPChunk* const cur_chunk = *chunk_list; - ++count; - if (count == nth) return 1; // Found. - chunk_list = &cur_chunk->next_; - *location = chunk_list; - } - - // *chunk_list is ok to be NULL if adding at last location. - return (nth == 0 || (count == nth - 1)) ? 1 : 0; -} - -//------------------------------------------------------------------------------ -// Chunk writer methods. - -WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data, - int copy_data, uint32_t tag) { - // For internally allocated chunks, always copy data & make it owner of data. - if (tag == kChunks[IDX_VP8X].tag || tag == kChunks[IDX_LOOP].tag) { - copy_data = 1; - } - - ChunkRelease(chunk); - - if (data != NULL) { - if (copy_data) { - // Copy data. - chunk->data_.bytes_ = (uint8_t*)malloc(data->size_); - if (chunk->data_.bytes_ == NULL) return WEBP_MUX_MEMORY_ERROR; - memcpy((uint8_t*)chunk->data_.bytes_, data->bytes_, data->size_); - chunk->data_.size_ = data->size_; - - // Chunk is owner of data. - chunk->owner_ = 1; - } else { - // Don't copy data. - chunk->data_ = *data; - } - } - - chunk->tag_ = tag; - - return WEBP_MUX_OK; -} - -WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list, - uint32_t nth) { - WebPChunk* new_chunk; - - if (!ChunkSearchListToSet(chunk_list, nth, &chunk_list)) { - return WEBP_MUX_NOT_FOUND; - } - - new_chunk = (WebPChunk*)malloc(sizeof(*new_chunk)); - if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR; - *new_chunk = *chunk; - new_chunk->next_ = *chunk_list; - *chunk_list = new_chunk; - return WEBP_MUX_OK; -} - -//------------------------------------------------------------------------------ -// Chunk deletion method(s). - -WebPChunk* ChunkDelete(WebPChunk* const chunk) { - WebPChunk* const next = ChunkRelease(chunk); - free(chunk); - return next; -} - -//------------------------------------------------------------------------------ -// Chunk serialization methods. - -size_t ChunksListDiskSize(const WebPChunk* chunk_list) { - size_t size = 0; - while (chunk_list) { - size += ChunkDiskSize(chunk_list); - chunk_list = chunk_list->next_; - } - return size; -} - -static uint8_t* ChunkEmit(const WebPChunk* const chunk, uint8_t* dst) { - const size_t chunk_size = chunk->data_.size_; - assert(chunk); - assert(chunk->tag_ != NIL_TAG); - PutLE32(dst + 0, chunk->tag_); - PutLE32(dst + TAG_SIZE, (uint32_t)chunk_size); - assert(chunk_size == (uint32_t)chunk_size); - memcpy(dst + CHUNK_HEADER_SIZE, chunk->data_.bytes_, chunk_size); - if (chunk_size & 1) - dst[CHUNK_HEADER_SIZE + chunk_size] = 0; // Add padding. - return dst + ChunkDiskSize(chunk); -} - -uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst) { - while (chunk_list) { - dst = ChunkEmit(chunk_list, dst); - chunk_list = chunk_list->next_; - } - return dst; -} - -//------------------------------------------------------------------------------ -// Manipulation of a WebPData object. - -void WebPDataInit(WebPData* webp_data) { - if (webp_data != NULL) { - memset(webp_data, 0, sizeof(*webp_data)); - } -} - -void WebPDataClear(WebPData* webp_data) { - if (webp_data != NULL) { - free((void*)webp_data->bytes_); - WebPDataInit(webp_data); - } -} - -int WebPDataCopy(const WebPData* src, WebPData* dst) { - if (src == NULL || dst == NULL) return 0; - - WebPDataInit(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. - -void MuxImageInit(WebPMuxImage* const wpi) { - assert(wpi); - memset(wpi, 0, sizeof(*wpi)); -} - -WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) { - WebPMuxImage* next; - if (wpi == NULL) return NULL; - ChunkDelete(wpi->header_); - ChunkDelete(wpi->alpha_); - ChunkDelete(wpi->img_); - - next = wpi->next_; - MuxImageInit(wpi); - return next; -} - -//------------------------------------------------------------------------------ -// MuxImage search methods. - -int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id) { - int count = 0; - const WebPMuxImage* current; - for (current = wpi_list; current != NULL; current = current->next_) { - const WebPChunk* const wpi_chunk = *MuxImageGetListFromId(current, id); - if (wpi_chunk != NULL) { - const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_); - if (wpi_chunk_id == id) ++count; - } - } - return count; -} - -// Outputs a pointer to 'prev_wpi->next_', -// where 'prev_wpi' is the pointer to the image at position (nth - 1). -// Returns 1 if nth image with given id was found, 0 otherwise. -static int SearchImageToGetOrDelete(WebPMuxImage** wpi_list, uint32_t nth, - WebPChunkId id, - WebPMuxImage*** const location) { - uint32_t count = 0; - assert(wpi_list); - *location = wpi_list; - - // Search makes sense only for the following. - assert(id == WEBP_CHUNK_FRAME || id == WEBP_CHUNK_TILE || - id == WEBP_CHUNK_IMAGE); - assert(id != WEBP_CHUNK_IMAGE || nth == 1); - - if (nth == 0) { - nth = MuxImageCount(*wpi_list, id); - if (nth == 0) return 0; // Not found. - } - - while (*wpi_list) { - WebPMuxImage* const cur_wpi = *wpi_list; - const WebPChunk* const wpi_chunk = *MuxImageGetListFromId(cur_wpi, id); - if (wpi_chunk != NULL) { - const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_); - if (wpi_chunk_id == id) { - ++count; - if (count == nth) return 1; // Found. - } - } - wpi_list = &cur_wpi->next_; - *location = wpi_list; - } - return 0; // Not found. -} - -//------------------------------------------------------------------------------ -// MuxImage writer methods. - -WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list) { - WebPMuxImage* new_wpi; - - while (*wpi_list != NULL) { - WebPMuxImage* const cur_wpi = *wpi_list; - if (cur_wpi->next_ == NULL) break; - wpi_list = &cur_wpi->next_; - } - - new_wpi = (WebPMuxImage*)malloc(sizeof(*new_wpi)); - if (new_wpi == NULL) return WEBP_MUX_MEMORY_ERROR; - *new_wpi = *wpi; - new_wpi->next_ = NULL; - - if (*wpi_list != NULL) { - (*wpi_list)->next_ = new_wpi; - } else { - *wpi_list = new_wpi; - } - return WEBP_MUX_OK; -} - -//------------------------------------------------------------------------------ -// MuxImage deletion methods. - -WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) { - // Delete the components of wpi. If wpi is NULL this is a noop. - WebPMuxImage* const next = MuxImageRelease(wpi); - free(wpi); - return next; -} - -void MuxImageDeleteAll(WebPMuxImage** const wpi_list) { - while (*wpi_list) { - *wpi_list = MuxImageDelete(*wpi_list); - } -} - -WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth, - WebPChunkId id) { - assert(wpi_list); - if (!SearchImageToGetOrDelete(wpi_list, nth, id, &wpi_list)) { - return WEBP_MUX_NOT_FOUND; - } - *wpi_list = MuxImageDelete(*wpi_list); - return WEBP_MUX_OK; -} - -//------------------------------------------------------------------------------ -// MuxImage reader methods. - -WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth, - WebPChunkId id, WebPMuxImage** wpi) { - assert(wpi_list); - assert(wpi); - if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth, id, - (WebPMuxImage***)&wpi_list)) { - return WEBP_MUX_NOT_FOUND; - } - *wpi = (WebPMuxImage*)*wpi_list; - return WEBP_MUX_OK; -} - -//------------------------------------------------------------------------------ -// MuxImage serialization methods. - -// Size of an image. -size_t MuxImageDiskSize(const WebPMuxImage* const wpi) { - size_t size = 0; - if (wpi->header_ != NULL) size += ChunkDiskSize(wpi->header_); - if (wpi->alpha_ != NULL) size += ChunkDiskSize(wpi->alpha_); - if (wpi->img_ != NULL) size += ChunkDiskSize(wpi->img_); - return size; -} - -size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list) { - size_t size = 0; - while (wpi_list) { - size += MuxImageDiskSize(wpi_list); - wpi_list = wpi_list->next_; - } - return size; -} - -uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) { - // Ordering of chunks to be emitted is strictly as follows: - // 1. Frame/Tile chunk (if present). - // 2. Alpha chunk (if present). - // 3. VP8/VP8L chunk. - assert(wpi); - if (wpi->header_ != NULL) dst = ChunkEmit(wpi->header_, dst); - if (wpi->alpha_ != NULL) dst = ChunkEmit(wpi->alpha_, dst); - if (wpi->img_ != NULL) dst = ChunkEmit(wpi->img_, dst); - return dst; -} - -uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst) { - while (wpi_list) { - dst = MuxImageEmit(wpi_list, dst); - wpi_list = wpi_list->next_; - } - return dst; -} - -//------------------------------------------------------------------------------ -// Helper methods for mux. - -int MuxHasLosslessImages(const WebPMuxImage* images) { - while (images != NULL) { - assert(images->img_ != NULL); - if (images->img_->tag_ == kChunks[IDX_VP8L].tag) { - return 1; - } - images = images->next_; - } - return 0; -} - -uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size) { - 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, MKFOURCC('W', 'E', 'B', 'P')); - return data + RIFF_HEADER_SIZE; -} - -WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) { - assert(mux != NULL); - switch(id) { - case WEBP_CHUNK_VP8X: return (WebPChunk**)&mux->vp8x_; - case WEBP_CHUNK_ICCP: return (WebPChunk**)&mux->iccp_; - case WEBP_CHUNK_LOOP: return (WebPChunk**)&mux->loop_; - case WEBP_CHUNK_META: return (WebPChunk**)&mux->meta_; - case WEBP_CHUNK_UNKNOWN: return (WebPChunk**)&mux->unknown_; - default: return NULL; - } -} - -WebPMuxError MuxValidateForImage(const WebPMux* const mux) { - const int num_images = MuxImageCount(mux->images_, WEBP_CHUNK_IMAGE); - const int num_frames = MuxImageCount(mux->images_, WEBP_CHUNK_FRAME); - const int num_tiles = MuxImageCount(mux->images_, WEBP_CHUNK_TILE); - - if (num_images == 0) { - // No images in mux. - return WEBP_MUX_NOT_FOUND; - } else if (num_images == 1 && num_frames == 0 && num_tiles == 0) { - // Valid case (single image). - return WEBP_MUX_OK; - } else { - // Frame/Tile case OR an invalid mux. - return WEBP_MUX_INVALID_ARGUMENT; - } -} - -static int IsNotCompatible(int feature, int num_items) { - return (feature != 0) != (num_items > 0); -} - -#define NO_FLAG 0 - -// Test basic constraints: -// retrieval, maximum number of chunks by index (use -1 to skip) -// and feature incompatibility (use NO_FLAG to skip). -// On success returns WEBP_MUX_OK and stores the chunk count in *num. -static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx, - WebPFeatureFlags feature, - WebPFeatureFlags vp8x_flags, - int max, int* num) { - const WebPMuxError err = - WebPMuxNumChunks(mux, kChunks[idx].id, num); - if (err != WEBP_MUX_OK) return err; - if (max > -1 && *num > max) return WEBP_MUX_INVALID_ARGUMENT; - if (feature != NO_FLAG && IsNotCompatible(vp8x_flags & feature, *num)) { - return WEBP_MUX_INVALID_ARGUMENT; - } - return WEBP_MUX_OK; -} - -WebPMuxError MuxValidate(const WebPMux* const mux) { - int num_iccp; - int num_meta; - int num_loop_chunks; - int num_frames; - int num_tiles; - int num_vp8x; - int num_images; - int num_alpha; - uint32_t flags; - WebPMuxError err; - - // Verify mux is not NULL. - if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; - - // Verify mux has at least one image. - if (mux->images_ == NULL) return WEBP_MUX_INVALID_ARGUMENT; - - err = WebPMuxGetFeatures(mux, &flags); - if (err != WEBP_MUX_OK) return err; - - // At most one color profile chunk. - err = ValidateChunk(mux, IDX_ICCP, ICCP_FLAG, flags, 1, &num_iccp); - if (err != WEBP_MUX_OK) return err; - - // At most one XMP metadata. - err = ValidateChunk(mux, IDX_META, META_FLAG, flags, 1, &num_meta); - if (err != WEBP_MUX_OK) return err; - - // Animation: ANIMATION_FLAG, loop chunk and frame chunk(s) are consistent. - // At most one loop chunk. - err = ValidateChunk(mux, IDX_LOOP, NO_FLAG, flags, 1, &num_loop_chunks); - if (err != WEBP_MUX_OK) return err; - err = ValidateChunk(mux, IDX_FRAME, NO_FLAG, flags, -1, &num_frames); - if (err != WEBP_MUX_OK) return err; - - { - const int has_animation = !!(flags & ANIMATION_FLAG); - if (has_animation && (num_loop_chunks == 0 || num_frames == 0)) { - return WEBP_MUX_INVALID_ARGUMENT; - } - if (!has_animation && (num_loop_chunks == 1 || num_frames > 0)) { - return WEBP_MUX_INVALID_ARGUMENT; - } - } - - // Tiling: TILE_FLAG and tile chunk(s) are consistent. - err = ValidateChunk(mux, IDX_TILE, TILE_FLAG, flags, -1, &num_tiles); - if (err != WEBP_MUX_OK) return err; - - // Verify either VP8X chunk is present OR there is only one elem in - // mux->images_. - err = ValidateChunk(mux, IDX_VP8X, NO_FLAG, flags, 1, &num_vp8x); - if (err != WEBP_MUX_OK) return err; - err = ValidateChunk(mux, IDX_VP8, NO_FLAG, flags, -1, &num_images); - if (err != WEBP_MUX_OK) return err; - if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT; - - // ALPHA_FLAG & alpha chunk(s) are consistent. - if (num_vp8x > 0 && MuxHasLosslessImages(mux->images_)) { - // Special case: we have a VP8X chunk as well as some lossless images. - if (!(flags & ALPHA_FLAG)) return WEBP_MUX_INVALID_ARGUMENT; - } else { - err = ValidateChunk(mux, IDX_ALPHA, ALPHA_FLAG, flags, -1, &num_alpha); - if (err != WEBP_MUX_OK) return err; - } - - // num_tiles & num_images are consistent. - if (num_tiles > 0 && num_images != num_tiles) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - return WEBP_MUX_OK; -} - -#undef NO_FLAG - -//------------------------------------------------------------------------------ - -#if defined(__cplusplus) || defined(c_plusplus) -} // extern "C" -#endif diff --git a/drivers/webpold/mux/muxread.c b/drivers/webpold/mux/muxread.c deleted file mode 100644 index 21c3cfbaeb..0000000000 --- a/drivers/webpold/mux/muxread.c +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// This code is licensed under the same terms as WebM: -// Software License Agreement: http://www.webmproject.org/license/software/ -// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ -// ----------------------------------------------------------------------------- -// -// Read APIs for mux. -// -// Authors: Urvang (urvang@google.com) -// Vikas (vikasa@google.com) - -#include <assert.h> -#include "./muxi.h" - -#if defined(__cplusplus) || defined(c_plusplus) -extern "C" { -#endif - -//------------------------------------------------------------------------------ -// Helper method(s). - -// Handy MACRO. -#define SWITCH_ID_LIST(INDEX, LIST) \ - if (idx == (INDEX)) { \ - const WebPChunk* const chunk = ChunkSearchList((LIST), nth, \ - kChunks[(INDEX)].tag); \ - if (chunk) { \ - *data = chunk->data_; \ - return WEBP_MUX_OK; \ - } else { \ - return WEBP_MUX_NOT_FOUND; \ - } \ - } - -static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx, - uint32_t nth, WebPData* const data) { - assert(mux != NULL); - assert(!IsWPI(kChunks[idx].id)); - WebPDataInit(data); - - SWITCH_ID_LIST(IDX_VP8X, mux->vp8x_); - SWITCH_ID_LIST(IDX_ICCP, mux->iccp_); - SWITCH_ID_LIST(IDX_LOOP, mux->loop_); - SWITCH_ID_LIST(IDX_META, mux->meta_); - SWITCH_ID_LIST(IDX_UNKNOWN, mux->unknown_); - return WEBP_MUX_NOT_FOUND; -} -#undef SWITCH_ID_LIST - -// Fill the chunk with the given data (includes chunk header bytes), after some -// verifications. -static WebPMuxError ChunkVerifyAndAssignData(WebPChunk* chunk, - const uint8_t* data, - size_t data_size, size_t riff_size, - int copy_data) { - uint32_t chunk_size; - WebPData chunk_data; - - // Sanity checks. - if (data_size < TAG_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA; - chunk_size = GetLE32(data + TAG_SIZE); - - { - const size_t chunk_disk_size = SizeWithPadding(chunk_size); - if (chunk_disk_size > riff_size) return WEBP_MUX_BAD_DATA; - if (chunk_disk_size > data_size) return WEBP_MUX_NOT_ENOUGH_DATA; - } - - // Data assignment. - chunk_data.bytes_ = data + CHUNK_HEADER_SIZE; - chunk_data.size_ = chunk_size; - return ChunkAssignData(chunk, &chunk_data, copy_data, GetLE32(data + 0)); -} - -//------------------------------------------------------------------------------ -// Create a mux object from WebP-RIFF data. - -WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, - int version) { - size_t riff_size; - uint32_t tag; - const uint8_t* end; - WebPMux* mux = NULL; - WebPMuxImage* wpi = NULL; - const uint8_t* data; - size_t size; - WebPChunk chunk; - ChunkInit(&chunk); - - // Sanity checks. - if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) { - return NULL; // version mismatch - } - if (bitstream == NULL) return NULL; - - data = bitstream->bytes_; - size = bitstream->size_; - - if (data == NULL) return NULL; - if (size < RIFF_HEADER_SIZE) return NULL; - if (GetLE32(data + 0) != MKFOURCC('R', 'I', 'F', 'F') || - GetLE32(data + CHUNK_HEADER_SIZE) != MKFOURCC('W', 'E', 'B', 'P')) { - return NULL; - } - - mux = WebPMuxNew(); - if (mux == NULL) return NULL; - - if (size < RIFF_HEADER_SIZE + TAG_SIZE) goto Err; - - tag = GetLE32(data + RIFF_HEADER_SIZE); - if (tag != kChunks[IDX_VP8].tag && - tag != kChunks[IDX_VP8L].tag && - tag != kChunks[IDX_VP8X].tag) { - goto Err; // First chunk should be VP8, VP8L or VP8X. - } - - riff_size = SizeWithPadding(GetLE32(data + TAG_SIZE)); - if (riff_size > MAX_CHUNK_PAYLOAD || riff_size > size) { - goto Err; - } else { - if (riff_size < size) { // Redundant data after last chunk. - size = riff_size; // To make sure we don't read any data beyond mux_size. - } - } - - end = data + size; - data += RIFF_HEADER_SIZE; - size -= RIFF_HEADER_SIZE; - - wpi = (WebPMuxImage*)malloc(sizeof(*wpi)); - if (wpi == NULL) goto Err; - MuxImageInit(wpi); - - // Loop over chunks. - while (data != end) { - WebPChunkId id; - WebPMuxError err; - - err = ChunkVerifyAndAssignData(&chunk, data, size, riff_size, copy_data); - if (err != WEBP_MUX_OK) goto Err; - - id = ChunkGetIdFromTag(chunk.tag_); - - if (IsWPI(id)) { // An image chunk (frame/tile/alpha/vp8). - WebPChunk** wpi_chunk_ptr = - MuxImageGetListFromId(wpi, id); // Image chunk to set. - assert(wpi_chunk_ptr != NULL); - if (*wpi_chunk_ptr != NULL) goto Err; // Consecutive alpha chunks or - // consecutive frame/tile chunks. - if (ChunkSetNth(&chunk, wpi_chunk_ptr, 1) != WEBP_MUX_OK) goto Err; - if (id == WEBP_CHUNK_IMAGE) { - wpi->is_partial_ = 0; // wpi is completely filled. - // Add this to mux->images_ list. - if (MuxImagePush(wpi, &mux->images_) != WEBP_MUX_OK) goto Err; - MuxImageInit(wpi); // Reset for reading next image. - } else { - wpi->is_partial_ = 1; // wpi is only partially filled. - } - } else { // A non-image chunk. - WebPChunk** chunk_list; - if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before - // getting all chunks of an image. - chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk. - if (chunk_list == NULL) chunk_list = &mux->unknown_; - if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err; - } - { - const size_t data_size = ChunkDiskSize(&chunk); - data += data_size; - size -= data_size; - } - ChunkInit(&chunk); - } - - // Validate mux if complete. - if (MuxValidate(mux) != WEBP_MUX_OK) goto Err; - - MuxImageDelete(wpi); - return mux; // All OK; - - Err: // Something bad happened. - ChunkRelease(&chunk); - MuxImageDelete(wpi); - WebPMuxDelete(mux); - return NULL; -} - -//------------------------------------------------------------------------------ -// Get API(s). - -WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) { - WebPData data; - WebPMuxError err; - - if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT; - *flags = 0; - - // Check if VP8X chunk is present. - err = MuxGet(mux, IDX_VP8X, 1, &data); - if (err == WEBP_MUX_NOT_FOUND) { - // Check if VP8/VP8L chunk is present. - err = WebPMuxGetImage(mux, &data); - WebPDataClear(&data); - return err; - } else if (err != WEBP_MUX_OK) { - return err; - } - - if (data.size_ < CHUNK_SIZE_BYTES) return WEBP_MUX_BAD_DATA; - - // All OK. Fill up flags. - *flags = GetLE32(data.bytes_); - return WEBP_MUX_OK; -} - -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, 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); - PutLE24(dst + CHUNK_HEADER_SIZE + 7, height - 1); - 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* mux, WebPData* bitstream) { - WebPMuxError err; - WebPMuxImage* wpi = NULL; - - if (mux == NULL || bitstream == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - err = MuxValidateForImage(mux); - if (err != WEBP_MUX_OK) return err; - - // All well. Get the image. - err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, WEBP_CHUNK_IMAGE, - &wpi); - assert(err == WEBP_MUX_OK); // Already tested above. - - return SynthesizeBitstream(wpi, bitstream); -} - -WebPMuxError WebPMuxGetMetadata(const WebPMux* mux, WebPData* metadata) { - if (mux == NULL || metadata == NULL) return WEBP_MUX_INVALID_ARGUMENT; - return MuxGet(mux, IDX_META, 1, metadata); -} - -WebPMuxError WebPMuxGetColorProfile(const WebPMux* mux, - WebPData* color_profile) { - if (mux == NULL || color_profile == NULL) return WEBP_MUX_INVALID_ARGUMENT; - return MuxGet(mux, IDX_ICCP, 1, color_profile); -} - -WebPMuxError WebPMuxGetLoopCount(const WebPMux* mux, int* loop_count) { - WebPData image; - WebPMuxError err; - - if (mux == NULL || loop_count == NULL) return WEBP_MUX_INVALID_ARGUMENT; - - 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 = GetLE16(image.bytes_); - - return WEBP_MUX_OK; -} - -static WebPMuxError MuxGetFrameTileInternal( - const WebPMux* const mux, uint32_t nth, WebPData* const bitstream, - int* const x_offset, int* const y_offset, int* const duration, - uint32_t tag) { - const WebPData* frame_tile_data; - WebPMuxError err; - WebPMuxImage* wpi; - - const int is_frame = (tag == kChunks[WEBP_CHUNK_FRAME].tag) ? 1 : 0; - const CHUNK_INDEX idx = is_frame ? IDX_FRAME : IDX_TILE; - const WebPChunkId id = kChunks[idx].id; - - if (mux == NULL || bitstream == NULL || - x_offset == NULL || y_offset == NULL || (is_frame && duration == NULL)) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - // Get the nth WebPMuxImage. - err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, id, &wpi); - if (err != WEBP_MUX_OK) return err; - - // Get frame chunk. - assert(wpi->header_ != NULL); // As MuxImageGetNth() already checked header_. - frame_tile_data = &wpi->header_->data_; - - if (frame_tile_data->size_ < kChunks[idx].size) return WEBP_MUX_BAD_DATA; - *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* mux, uint32_t nth, - WebPData* bitstream, - int* x_offset, int* y_offset, int* duration) { - return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset, - duration, kChunks[IDX_FRAME].tag); -} - -WebPMuxError WebPMuxGetTile(const WebPMux* mux, uint32_t nth, - WebPData* bitstream, - int* x_offset, int* y_offset) { - return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset, NULL, - kChunks[IDX_TILE].tag); -} - -// Get chunk index from chunk id. Returns IDX_NIL if not found. -static CHUNK_INDEX ChunkGetIndexFromId(WebPChunkId id) { - int i; - for (i = 0; kChunks[i].id != WEBP_CHUNK_NIL; ++i) { - if (id == kChunks[i].id) return i; - } - return IDX_NIL; -} - -// Count number of chunks matching 'tag' in the 'chunk_list'. -// If tag == NIL_TAG, any tag will be matched. -static int CountChunks(const WebPChunk* const chunk_list, uint32_t tag) { - int count = 0; - const WebPChunk* current; - for (current = chunk_list; current != NULL; current = current->next_) { - if (tag == NIL_TAG || current->tag_ == tag) { - count++; // Count chunks whose tags match. - } - } - return count; -} - -WebPMuxError WebPMuxNumChunks(const WebPMux* mux, - WebPChunkId id, int* num_elements) { - if (mux == NULL || num_elements == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - if (IsWPI(id)) { - *num_elements = MuxImageCount(mux->images_, id); - } else { - WebPChunk* const* chunk_list = MuxGetChunkListFromId(mux, id); - if (chunk_list == NULL) { - *num_elements = 0; - } else { - const CHUNK_INDEX idx = ChunkGetIndexFromId(id); - *num_elements = CountChunks(*chunk_list, kChunks[idx].tag); - } - } - - return WEBP_MUX_OK; -} - -//------------------------------------------------------------------------------ - -#if defined(__cplusplus) || defined(c_plusplus) -} // extern "C" -#endif |