mirror of
https://github.com/webmproject/libwebp.git
synced 2025-04-20 07:46:45 +02:00
demux,cosmetics: rm struct member '_' suffix
This is a follow up to: ee8e8c62 Fix member naming for VP8LHistogram This better matches Google style and clears some clang-tidy warnings. Change-Id: Ida41ca82445800552573ff5ebbde743cf8fa6eff
This commit is contained in:
parent
295804e4b9
commit
3f54b1aa12
@ -39,18 +39,18 @@ static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst,
|
|||||||
int num_pixels);
|
int num_pixels);
|
||||||
|
|
||||||
struct WebPAnimDecoder {
|
struct WebPAnimDecoder {
|
||||||
WebPDemuxer* demux_; // Demuxer created from given WebP bitstream.
|
WebPDemuxer* demux; // Demuxer created from given WebP bitstream.
|
||||||
WebPDecoderConfig config_; // Decoder config.
|
WebPDecoderConfig config; // Decoder config.
|
||||||
// Note: we use a pointer to a function blending multiple pixels at a time to
|
// Note: we use a pointer to a function blending multiple pixels at a time to
|
||||||
// allow possible inlining of per-pixel blending function.
|
// allow possible inlining of per-pixel blending function.
|
||||||
BlendRowFunc blend_func_; // Pointer to the chose blend row function.
|
BlendRowFunc blend_func; // Pointer to the chose blend row function.
|
||||||
WebPAnimInfo info_; // Global info about the animation.
|
WebPAnimInfo info; // Global info about the animation.
|
||||||
uint8_t* curr_frame_; // Current canvas (not disposed).
|
uint8_t* curr_frame; // Current canvas (not disposed).
|
||||||
uint8_t* prev_frame_disposed_; // Previous canvas (properly disposed).
|
uint8_t* prev_frame_disposed; // Previous canvas (properly disposed).
|
||||||
int prev_frame_timestamp_; // Previous frame timestamp (milliseconds).
|
int prev_frame_timestamp; // Previous frame timestamp (milliseconds).
|
||||||
WebPIterator prev_iter_; // Iterator object for previous frame.
|
WebPIterator prev_iter; // Iterator object for previous frame.
|
||||||
int prev_frame_was_keyframe_; // True if previous frame was a keyframe.
|
int prev_frame_was_keyframe; // True if previous frame was a keyframe.
|
||||||
int next_frame_; // Index of the next frame to be decoded
|
int next_frame; // Index of the next frame to be decoded
|
||||||
// (starting from 1).
|
// (starting from 1).
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ WEBP_NODISCARD static int ApplyDecoderOptions(
|
|||||||
const WebPAnimDecoderOptions* const dec_options,
|
const WebPAnimDecoderOptions* const dec_options,
|
||||||
WebPAnimDecoder* const dec) {
|
WebPAnimDecoder* const dec) {
|
||||||
WEBP_CSP_MODE mode;
|
WEBP_CSP_MODE mode;
|
||||||
WebPDecoderConfig* config = &dec->config_;
|
WebPDecoderConfig* config = &dec->config;
|
||||||
assert(dec_options != NULL);
|
assert(dec_options != NULL);
|
||||||
|
|
||||||
mode = dec_options->color_mode;
|
mode = dec_options->color_mode;
|
||||||
@ -81,7 +81,7 @@ WEBP_NODISCARD static int ApplyDecoderOptions(
|
|||||||
mode != MODE_rgbA && mode != MODE_bgrA) {
|
mode != MODE_rgbA && mode != MODE_bgrA) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
dec->blend_func_ = (mode == MODE_RGBA || mode == MODE_BGRA)
|
dec->blend_func = (mode == MODE_RGBA || mode == MODE_BGRA)
|
||||||
? &BlendPixelRowNonPremult
|
? &BlendPixelRowNonPremult
|
||||||
: &BlendPixelRowPremult;
|
: &BlendPixelRowPremult;
|
||||||
if (!WebPInitDecoderConfig(config)) {
|
if (!WebPInitDecoderConfig(config)) {
|
||||||
@ -123,22 +123,22 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal(
|
|||||||
}
|
}
|
||||||
if (!ApplyDecoderOptions(&options, dec)) goto Error;
|
if (!ApplyDecoderOptions(&options, dec)) goto Error;
|
||||||
|
|
||||||
dec->demux_ = WebPDemux(webp_data);
|
dec->demux = WebPDemux(webp_data);
|
||||||
if (dec->demux_ == NULL) goto Error;
|
if (dec->demux == NULL) goto Error;
|
||||||
|
|
||||||
dec->info_.canvas_width = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_WIDTH);
|
dec->info.canvas_width = WebPDemuxGetI(dec->demux, WEBP_FF_CANVAS_WIDTH);
|
||||||
dec->info_.canvas_height = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_HEIGHT);
|
dec->info.canvas_height = WebPDemuxGetI(dec->demux, WEBP_FF_CANVAS_HEIGHT);
|
||||||
dec->info_.loop_count = WebPDemuxGetI(dec->demux_, WEBP_FF_LOOP_COUNT);
|
dec->info.loop_count = WebPDemuxGetI(dec->demux, WEBP_FF_LOOP_COUNT);
|
||||||
dec->info_.bgcolor = WebPDemuxGetI(dec->demux_, WEBP_FF_BACKGROUND_COLOR);
|
dec->info.bgcolor = WebPDemuxGetI(dec->demux, WEBP_FF_BACKGROUND_COLOR);
|
||||||
dec->info_.frame_count = WebPDemuxGetI(dec->demux_, WEBP_FF_FRAME_COUNT);
|
dec->info.frame_count = WebPDemuxGetI(dec->demux, WEBP_FF_FRAME_COUNT);
|
||||||
|
|
||||||
// Note: calloc() because we fill frame with zeroes as well.
|
// Note: calloc() because we fill frame with zeroes as well.
|
||||||
dec->curr_frame_ = (uint8_t*)WebPSafeCalloc(
|
dec->curr_frame = (uint8_t*)WebPSafeCalloc(
|
||||||
dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height);
|
dec->info.canvas_width * NUM_CHANNELS, dec->info.canvas_height);
|
||||||
if (dec->curr_frame_ == NULL) goto Error;
|
if (dec->curr_frame == NULL) goto Error;
|
||||||
dec->prev_frame_disposed_ = (uint8_t*)WebPSafeCalloc(
|
dec->prev_frame_disposed = (uint8_t*)WebPSafeCalloc(
|
||||||
dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height);
|
dec->info.canvas_width * NUM_CHANNELS, dec->info.canvas_height);
|
||||||
if (dec->prev_frame_disposed_ == NULL) goto Error;
|
if (dec->prev_frame_disposed == NULL) goto Error;
|
||||||
|
|
||||||
WebPAnimDecoderReset(dec);
|
WebPAnimDecoderReset(dec);
|
||||||
return dec;
|
return dec;
|
||||||
@ -150,7 +150,7 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal(
|
|||||||
|
|
||||||
int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec, WebPAnimInfo* info) {
|
int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec, WebPAnimInfo* info) {
|
||||||
if (dec == NULL || info == NULL) return 0;
|
if (dec == NULL || info == NULL) return 0;
|
||||||
*info = dec->info_;
|
*info = dec->info;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,25 +338,25 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
|
|||||||
if (dec == NULL || buf_ptr == NULL || timestamp_ptr == NULL) return 0;
|
if (dec == NULL || buf_ptr == NULL || timestamp_ptr == NULL) return 0;
|
||||||
if (!WebPAnimDecoderHasMoreFrames(dec)) return 0;
|
if (!WebPAnimDecoderHasMoreFrames(dec)) return 0;
|
||||||
|
|
||||||
width = dec->info_.canvas_width;
|
width = dec->info.canvas_width;
|
||||||
height = dec->info_.canvas_height;
|
height = dec->info.canvas_height;
|
||||||
blend_row = dec->blend_func_;
|
blend_row = dec->blend_func;
|
||||||
|
|
||||||
// Get compressed frame.
|
// Get compressed frame.
|
||||||
if (!WebPDemuxGetFrame(dec->demux_, dec->next_frame_, &iter)) {
|
if (!WebPDemuxGetFrame(dec->demux, dec->next_frame, &iter)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
timestamp = dec->prev_frame_timestamp_ + iter.duration;
|
timestamp = dec->prev_frame_timestamp + iter.duration;
|
||||||
|
|
||||||
// Initialize.
|
// Initialize.
|
||||||
is_key_frame = IsKeyFrame(&iter, &dec->prev_iter_,
|
is_key_frame = IsKeyFrame(&iter, &dec->prev_iter,
|
||||||
dec->prev_frame_was_keyframe_, width, height);
|
dec->prev_frame_was_keyframe, width, height);
|
||||||
if (is_key_frame) {
|
if (is_key_frame) {
|
||||||
if (!ZeroFillCanvas(dec->curr_frame_, width, height)) {
|
if (!ZeroFillCanvas(dec->curr_frame, width, height)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_,
|
if (!CopyCanvas(dec->prev_frame_disposed, dec->curr_frame,
|
||||||
width, height)) {
|
width, height)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
@ -370,12 +370,12 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
|
|||||||
const uint64_t out_offset = (uint64_t)iter.y_offset * stride +
|
const uint64_t out_offset = (uint64_t)iter.y_offset * stride +
|
||||||
(uint64_t)iter.x_offset * NUM_CHANNELS; // 53b
|
(uint64_t)iter.x_offset * NUM_CHANNELS; // 53b
|
||||||
const uint64_t size = (uint64_t)iter.height * stride; // at most 25 + 27b
|
const uint64_t size = (uint64_t)iter.height * stride; // at most 25 + 27b
|
||||||
WebPDecoderConfig* const config = &dec->config_;
|
WebPDecoderConfig* const config = &dec->config;
|
||||||
WebPRGBABuffer* const buf = &config->output.u.RGBA;
|
WebPRGBABuffer* const buf = &config->output.u.RGBA;
|
||||||
if ((size_t)size != size) goto Error;
|
if ((size_t)size != size) goto Error;
|
||||||
buf->stride = (int)stride;
|
buf->stride = (int)stride;
|
||||||
buf->size = (size_t)size;
|
buf->size = (size_t)size;
|
||||||
buf->rgba = dec->curr_frame_ + out_offset;
|
buf->rgba = dec->curr_frame + out_offset;
|
||||||
|
|
||||||
if (WebPDecode(in, in_size, config) != VP8_STATUS_OK) {
|
if (WebPDecode(in, in_size, config) != VP8_STATUS_OK) {
|
||||||
goto Error;
|
goto Error;
|
||||||
@ -388,18 +388,18 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
|
|||||||
// that pixel in the previous frame if blending method of is WEBP_MUX_BLEND.
|
// that pixel in the previous frame if blending method of is WEBP_MUX_BLEND.
|
||||||
if (iter.frame_num > 1 && iter.blend_method == WEBP_MUX_BLEND &&
|
if (iter.frame_num > 1 && iter.blend_method == WEBP_MUX_BLEND &&
|
||||||
!is_key_frame) {
|
!is_key_frame) {
|
||||||
if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_NONE) {
|
if (dec->prev_iter.dispose_method == WEBP_MUX_DISPOSE_NONE) {
|
||||||
int y;
|
int y;
|
||||||
// Blend transparent pixels with pixels in previous canvas.
|
// Blend transparent pixels with pixels in previous canvas.
|
||||||
for (y = 0; y < iter.height; ++y) {
|
for (y = 0; y < iter.height; ++y) {
|
||||||
const size_t offset =
|
const size_t offset =
|
||||||
(iter.y_offset + y) * width + iter.x_offset;
|
(iter.y_offset + y) * width + iter.x_offset;
|
||||||
blend_row((uint32_t*)dec->curr_frame_ + offset,
|
blend_row((uint32_t*)dec->curr_frame + offset,
|
||||||
(uint32_t*)dec->prev_frame_disposed_ + offset, iter.width);
|
(uint32_t*)dec->prev_frame_disposed + offset, iter.width);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int y;
|
int y;
|
||||||
assert(dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND);
|
assert(dec->prev_iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND);
|
||||||
// We need to blend a transparent pixel with its value just after
|
// We need to blend a transparent pixel with its value just after
|
||||||
// initialization. That is, blend it with:
|
// initialization. That is, blend it with:
|
||||||
// * Fully transparent pixel if it belongs to prevRect <-- No-op.
|
// * Fully transparent pixel if it belongs to prevRect <-- No-op.
|
||||||
@ -407,39 +407,39 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
|
|||||||
for (y = 0; y < iter.height; ++y) {
|
for (y = 0; y < iter.height; ++y) {
|
||||||
const int canvas_y = iter.y_offset + y;
|
const int canvas_y = iter.y_offset + y;
|
||||||
int left1, width1, left2, width2;
|
int left1, width1, left2, width2;
|
||||||
FindBlendRangeAtRow(&iter, &dec->prev_iter_, canvas_y, &left1, &width1,
|
FindBlendRangeAtRow(&iter, &dec->prev_iter, canvas_y, &left1, &width1,
|
||||||
&left2, &width2);
|
&left2, &width2);
|
||||||
if (width1 > 0) {
|
if (width1 > 0) {
|
||||||
const size_t offset1 = canvas_y * width + left1;
|
const size_t offset1 = canvas_y * width + left1;
|
||||||
blend_row((uint32_t*)dec->curr_frame_ + offset1,
|
blend_row((uint32_t*)dec->curr_frame + offset1,
|
||||||
(uint32_t*)dec->prev_frame_disposed_ + offset1, width1);
|
(uint32_t*)dec->prev_frame_disposed + offset1, width1);
|
||||||
}
|
}
|
||||||
if (width2 > 0) {
|
if (width2 > 0) {
|
||||||
const size_t offset2 = canvas_y * width + left2;
|
const size_t offset2 = canvas_y * width + left2;
|
||||||
blend_row((uint32_t*)dec->curr_frame_ + offset2,
|
blend_row((uint32_t*)dec->curr_frame + offset2,
|
||||||
(uint32_t*)dec->prev_frame_disposed_ + offset2, width2);
|
(uint32_t*)dec->prev_frame_disposed + offset2, width2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update info of the previous frame and dispose it for the next iteration.
|
// Update info of the previous frame and dispose it for the next iteration.
|
||||||
dec->prev_frame_timestamp_ = timestamp;
|
dec->prev_frame_timestamp = timestamp;
|
||||||
WebPDemuxReleaseIterator(&dec->prev_iter_);
|
WebPDemuxReleaseIterator(&dec->prev_iter);
|
||||||
dec->prev_iter_ = iter;
|
dec->prev_iter = iter;
|
||||||
dec->prev_frame_was_keyframe_ = is_key_frame;
|
dec->prev_frame_was_keyframe = is_key_frame;
|
||||||
if (!CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height)) {
|
if (!CopyCanvas(dec->curr_frame, dec->prev_frame_disposed, width, height)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
|
if (dec->prev_iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
|
||||||
ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS,
|
ZeroFillFrameRect(dec->prev_frame_disposed, width * NUM_CHANNELS,
|
||||||
dec->prev_iter_.x_offset, dec->prev_iter_.y_offset,
|
dec->prev_iter.x_offset, dec->prev_iter.y_offset,
|
||||||
dec->prev_iter_.width, dec->prev_iter_.height);
|
dec->prev_iter.width, dec->prev_iter.height);
|
||||||
}
|
}
|
||||||
++dec->next_frame_;
|
++dec->next_frame;
|
||||||
|
|
||||||
// All OK, fill in the values.
|
// All OK, fill in the values.
|
||||||
*buf_ptr = dec->curr_frame_;
|
*buf_ptr = dec->curr_frame;
|
||||||
*timestamp_ptr = timestamp;
|
*timestamp_ptr = timestamp;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@ -450,30 +450,30 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
|
|||||||
|
|
||||||
int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec) {
|
int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec) {
|
||||||
if (dec == NULL) return 0;
|
if (dec == NULL) return 0;
|
||||||
return (dec->next_frame_ <= (int)dec->info_.frame_count);
|
return (dec->next_frame <= (int)dec->info.frame_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPAnimDecoderReset(WebPAnimDecoder* dec) {
|
void WebPAnimDecoderReset(WebPAnimDecoder* dec) {
|
||||||
if (dec != NULL) {
|
if (dec != NULL) {
|
||||||
dec->prev_frame_timestamp_ = 0;
|
dec->prev_frame_timestamp = 0;
|
||||||
WebPDemuxReleaseIterator(&dec->prev_iter_);
|
WebPDemuxReleaseIterator(&dec->prev_iter);
|
||||||
memset(&dec->prev_iter_, 0, sizeof(dec->prev_iter_));
|
memset(&dec->prev_iter, 0, sizeof(dec->prev_iter));
|
||||||
dec->prev_frame_was_keyframe_ = 0;
|
dec->prev_frame_was_keyframe = 0;
|
||||||
dec->next_frame_ = 1;
|
dec->next_frame = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const WebPDemuxer* WebPAnimDecoderGetDemuxer(const WebPAnimDecoder* dec) {
|
const WebPDemuxer* WebPAnimDecoderGetDemuxer(const WebPAnimDecoder* dec) {
|
||||||
if (dec == NULL) return NULL;
|
if (dec == NULL) return NULL;
|
||||||
return dec->demux_;
|
return dec->demux;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPAnimDecoderDelete(WebPAnimDecoder* dec) {
|
void WebPAnimDecoderDelete(WebPAnimDecoder* dec) {
|
||||||
if (dec != NULL) {
|
if (dec != NULL) {
|
||||||
WebPDemuxReleaseIterator(&dec->prev_iter_);
|
WebPDemuxReleaseIterator(&dec->prev_iter);
|
||||||
WebPDemuxDelete(dec->demux_);
|
WebPDemuxDelete(dec->demux);
|
||||||
WebPSafeFree(dec->curr_frame_);
|
WebPSafeFree(dec->curr_frame);
|
||||||
WebPSafeFree(dec->prev_frame_disposed_);
|
WebPSafeFree(dec->prev_frame_disposed);
|
||||||
WebPSafeFree(dec);
|
WebPSafeFree(dec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,49 +28,49 @@
|
|||||||
#define DMUX_REV_VERSION 0
|
#define DMUX_REV_VERSION 0
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t start_; // start location of the data
|
size_t start; // start location of the data
|
||||||
size_t end_; // end location
|
size_t end; // end location
|
||||||
size_t riff_end_; // riff chunk end location, can be > end_.
|
size_t riff_end; // riff chunk end location, can be > end.
|
||||||
size_t buf_size_; // size of the buffer
|
size_t buf_size; // size of the buffer
|
||||||
const uint8_t* buf_;
|
const uint8_t* buf;
|
||||||
} MemBuffer;
|
} MemBuffer;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t offset_;
|
size_t offset;
|
||||||
size_t size_;
|
size_t size;
|
||||||
} ChunkData;
|
} ChunkData;
|
||||||
|
|
||||||
typedef struct Frame {
|
typedef struct Frame {
|
||||||
int x_offset_, y_offset_;
|
int x_offset, y_offset;
|
||||||
int width_, height_;
|
int width, height;
|
||||||
int has_alpha_;
|
int has_alpha;
|
||||||
int duration_;
|
int duration;
|
||||||
WebPMuxAnimDispose dispose_method_;
|
WebPMuxAnimDispose dispose_method;
|
||||||
WebPMuxAnimBlend blend_method_;
|
WebPMuxAnimBlend blend_method;
|
||||||
int frame_num_;
|
int frame_num;
|
||||||
int complete_; // img_components_ contains a full image.
|
int complete; // img_components contains a full image.
|
||||||
ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH
|
ChunkData img_components[2]; // 0=VP8{,L} 1=ALPH
|
||||||
struct Frame* next_;
|
struct Frame* next;
|
||||||
} Frame;
|
} Frame;
|
||||||
|
|
||||||
typedef struct Chunk {
|
typedef struct Chunk {
|
||||||
ChunkData data_;
|
ChunkData data;
|
||||||
struct Chunk* next_;
|
struct Chunk* next;
|
||||||
} Chunk;
|
} Chunk;
|
||||||
|
|
||||||
struct WebPDemuxer {
|
struct WebPDemuxer {
|
||||||
MemBuffer mem_;
|
MemBuffer mem;
|
||||||
WebPDemuxState state_;
|
WebPDemuxState state;
|
||||||
int is_ext_format_;
|
int is_ext_format;
|
||||||
uint32_t feature_flags_;
|
uint32_t feature_flags;
|
||||||
int canvas_width_, canvas_height_;
|
int canvas_width, canvas_height;
|
||||||
int loop_count_;
|
int loop_count;
|
||||||
uint32_t bgcolor_;
|
uint32_t bgcolor;
|
||||||
int num_frames_;
|
int num_frames;
|
||||||
Frame* frames_;
|
Frame* frames;
|
||||||
Frame** frames_tail_;
|
Frame** frames_tail;
|
||||||
Chunk* chunks_; // non-image chunks
|
Chunk* chunks; // non-image chunks
|
||||||
Chunk** chunks_tail_;
|
Chunk** chunks_tail;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -108,10 +108,10 @@ int WebPGetDemuxVersion(void) {
|
|||||||
|
|
||||||
static int RemapMemBuffer(MemBuffer* const mem,
|
static int RemapMemBuffer(MemBuffer* const mem,
|
||||||
const uint8_t* data, size_t size) {
|
const uint8_t* data, size_t size) {
|
||||||
if (size < mem->buf_size_) return 0; // can't remap to a shorter buffer!
|
if (size < mem->buf_size) return 0; // can't remap to a shorter buffer!
|
||||||
|
|
||||||
mem->buf_ = data;
|
mem->buf = data;
|
||||||
mem->end_ = mem->buf_size_ = size;
|
mem->end = mem->buf_size = size;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,49 +123,49 @@ static int InitMemBuffer(MemBuffer* const mem,
|
|||||||
|
|
||||||
// Return the remaining data size available in 'mem'.
|
// Return the remaining data size available in 'mem'.
|
||||||
static WEBP_INLINE size_t MemDataSize(const MemBuffer* const mem) {
|
static WEBP_INLINE size_t MemDataSize(const MemBuffer* const mem) {
|
||||||
return (mem->end_ - mem->start_);
|
return (mem->end - mem->start);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if 'size' exceeds the end of the RIFF chunk.
|
// Return true if 'size' exceeds the end of the RIFF chunk.
|
||||||
static WEBP_INLINE int SizeIsInvalid(const MemBuffer* const mem, size_t size) {
|
static WEBP_INLINE int SizeIsInvalid(const MemBuffer* const mem, size_t size) {
|
||||||
return (size > mem->riff_end_ - mem->start_);
|
return (size > mem->riff_end - mem->start);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void Skip(MemBuffer* const mem, size_t size) {
|
static WEBP_INLINE void Skip(MemBuffer* const mem, size_t size) {
|
||||||
mem->start_ += size;
|
mem->start += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void Rewind(MemBuffer* const mem, size_t size) {
|
static WEBP_INLINE void Rewind(MemBuffer* const mem, size_t size) {
|
||||||
mem->start_ -= size;
|
mem->start -= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE const uint8_t* GetBuffer(MemBuffer* const mem) {
|
static WEBP_INLINE const uint8_t* GetBuffer(MemBuffer* const mem) {
|
||||||
return mem->buf_ + mem->start_;
|
return mem->buf + mem->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read from 'mem' and skip the read bytes.
|
// Read from 'mem' and skip the read bytes.
|
||||||
static WEBP_INLINE uint8_t ReadByte(MemBuffer* const mem) {
|
static WEBP_INLINE uint8_t ReadByte(MemBuffer* const mem) {
|
||||||
const uint8_t byte = mem->buf_[mem->start_];
|
const uint8_t byte = mem->buf[mem->start];
|
||||||
Skip(mem, 1);
|
Skip(mem, 1);
|
||||||
return byte;
|
return byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE int ReadLE16s(MemBuffer* const mem) {
|
static WEBP_INLINE int ReadLE16s(MemBuffer* const mem) {
|
||||||
const uint8_t* const data = mem->buf_ + mem->start_;
|
const uint8_t* const data = mem->buf + mem->start;
|
||||||
const int val = GetLE16(data);
|
const int val = GetLE16(data);
|
||||||
Skip(mem, 2);
|
Skip(mem, 2);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE int ReadLE24s(MemBuffer* const mem) {
|
static WEBP_INLINE int ReadLE24s(MemBuffer* const mem) {
|
||||||
const uint8_t* const data = mem->buf_ + mem->start_;
|
const uint8_t* const data = mem->buf + mem->start;
|
||||||
const int val = GetLE24(data);
|
const int val = GetLE24(data);
|
||||||
Skip(mem, 3);
|
Skip(mem, 3);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t ReadLE32(MemBuffer* const mem) {
|
static WEBP_INLINE uint32_t ReadLE32(MemBuffer* const mem) {
|
||||||
const uint8_t* const data = mem->buf_ + mem->start_;
|
const uint8_t* const data = mem->buf + mem->start;
|
||||||
const uint32_t val = GetLE32(data);
|
const uint32_t val = GetLE32(data);
|
||||||
Skip(mem, 4);
|
Skip(mem, 4);
|
||||||
return val;
|
return val;
|
||||||
@ -175,20 +175,20 @@ static WEBP_INLINE uint32_t ReadLE32(MemBuffer* const mem) {
|
|||||||
// Secondary chunk parsing
|
// Secondary chunk parsing
|
||||||
|
|
||||||
static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) {
|
static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) {
|
||||||
*dmux->chunks_tail_ = chunk;
|
*dmux->chunks_tail = chunk;
|
||||||
chunk->next_ = NULL;
|
chunk->next = NULL;
|
||||||
dmux->chunks_tail_ = &chunk->next_;
|
dmux->chunks_tail = &chunk->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a frame to the end of the list, ensuring the last frame is complete.
|
// Add a frame to the end of the list, ensuring the last frame is complete.
|
||||||
// Returns true on success, false otherwise.
|
// Returns true on success, false otherwise.
|
||||||
static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) {
|
static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) {
|
||||||
const Frame* const last_frame = *dmux->frames_tail_;
|
const Frame* const last_frame = *dmux->frames_tail;
|
||||||
if (last_frame != NULL && !last_frame->complete_) return 0;
|
if (last_frame != NULL && !last_frame->complete) return 0;
|
||||||
|
|
||||||
*dmux->frames_tail_ = frame;
|
*dmux->frames_tail = frame;
|
||||||
frame->next_ = NULL;
|
frame->next = NULL;
|
||||||
dmux->frames_tail_ = &frame->next_;
|
dmux->frames_tail = &frame->next;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,13 +196,13 @@ static void SetFrameInfo(size_t start_offset, size_t size,
|
|||||||
int frame_num, int complete,
|
int frame_num, int complete,
|
||||||
const WebPBitstreamFeatures* const features,
|
const WebPBitstreamFeatures* const features,
|
||||||
Frame* const frame) {
|
Frame* const frame) {
|
||||||
frame->img_components_[0].offset_ = start_offset;
|
frame->img_components[0].offset = start_offset;
|
||||||
frame->img_components_[0].size_ = size;
|
frame->img_components[0].size = size;
|
||||||
frame->width_ = features->width;
|
frame->width = features->width;
|
||||||
frame->height_ = features->height;
|
frame->height = features->height;
|
||||||
frame->has_alpha_ |= features->has_alpha;
|
frame->has_alpha |= features->has_alpha;
|
||||||
frame->frame_num_ = frame_num;
|
frame->frame_num = frame_num;
|
||||||
frame->complete_ = complete;
|
frame->complete = complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store image bearing chunks to 'frame'. 'min_size' is an optional size
|
// Store image bearing chunks to 'frame'. 'min_size' is an optional size
|
||||||
@ -218,7 +218,7 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
|
|||||||
if (done) return PARSE_NEED_MORE_DATA;
|
if (done) return PARSE_NEED_MORE_DATA;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
const size_t chunk_start_offset = mem->start_;
|
const size_t chunk_start_offset = mem->start;
|
||||||
const uint32_t fourcc = ReadLE32(mem);
|
const uint32_t fourcc = ReadLE32(mem);
|
||||||
const uint32_t payload_size = ReadLE32(mem);
|
const uint32_t payload_size = ReadLE32(mem);
|
||||||
uint32_t payload_size_padded;
|
uint32_t payload_size_padded;
|
||||||
@ -238,10 +238,10 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
|
|||||||
case MKFOURCC('A', 'L', 'P', 'H'):
|
case MKFOURCC('A', 'L', 'P', 'H'):
|
||||||
if (alpha_chunks == 0) {
|
if (alpha_chunks == 0) {
|
||||||
++alpha_chunks;
|
++alpha_chunks;
|
||||||
frame->img_components_[1].offset_ = chunk_start_offset;
|
frame->img_components[1].offset = chunk_start_offset;
|
||||||
frame->img_components_[1].size_ = chunk_size;
|
frame->img_components[1].size = chunk_size;
|
||||||
frame->has_alpha_ = 1;
|
frame->has_alpha = 1;
|
||||||
frame->frame_num_ = frame_num;
|
frame->frame_num = frame_num;
|
||||||
Skip(mem, payload_available);
|
Skip(mem, payload_available);
|
||||||
} else {
|
} else {
|
||||||
goto Done;
|
goto Done;
|
||||||
@ -256,7 +256,7 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
|
|||||||
// is incomplete.
|
// is incomplete.
|
||||||
WebPBitstreamFeatures features;
|
WebPBitstreamFeatures features;
|
||||||
const VP8StatusCode vp8_status =
|
const VP8StatusCode vp8_status =
|
||||||
WebPGetFeatures(mem->buf_ + chunk_start_offset, chunk_size,
|
WebPGetFeatures(mem->buf + chunk_start_offset, chunk_size,
|
||||||
&features);
|
&features);
|
||||||
if (status == PARSE_NEED_MORE_DATA &&
|
if (status == PARSE_NEED_MORE_DATA &&
|
||||||
vp8_status == VP8_STATUS_NOT_ENOUGH_DATA) {
|
vp8_status == VP8_STATUS_NOT_ENOUGH_DATA) {
|
||||||
@ -281,7 +281,7 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mem->start_ == mem->riff_end_) {
|
if (mem->start == mem->riff_end) {
|
||||||
done = 1;
|
done = 1;
|
||||||
} else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) {
|
} else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) {
|
||||||
status = PARSE_NEED_MORE_DATA;
|
status = PARSE_NEED_MORE_DATA;
|
||||||
@ -310,42 +310,42 @@ static ParseStatus NewFrame(const MemBuffer* const mem,
|
|||||||
// 'frame_chunk_size' is the previously validated, padded chunk size.
|
// 'frame_chunk_size' is the previously validated, padded chunk size.
|
||||||
static ParseStatus ParseAnimationFrame(
|
static ParseStatus ParseAnimationFrame(
|
||||||
WebPDemuxer* const dmux, uint32_t frame_chunk_size) {
|
WebPDemuxer* const dmux, uint32_t frame_chunk_size) {
|
||||||
const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
|
const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG);
|
||||||
const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE;
|
const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE;
|
||||||
int added_frame = 0;
|
int added_frame = 0;
|
||||||
int bits;
|
int bits;
|
||||||
MemBuffer* const mem = &dmux->mem_;
|
MemBuffer* const mem = &dmux->mem;
|
||||||
Frame* frame;
|
Frame* frame;
|
||||||
size_t start_offset;
|
size_t start_offset;
|
||||||
ParseStatus status =
|
ParseStatus status =
|
||||||
NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame);
|
NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame);
|
||||||
if (status != PARSE_OK) return status;
|
if (status != PARSE_OK) return status;
|
||||||
|
|
||||||
frame->x_offset_ = 2 * ReadLE24s(mem);
|
frame->x_offset = 2 * ReadLE24s(mem);
|
||||||
frame->y_offset_ = 2 * ReadLE24s(mem);
|
frame->y_offset = 2 * ReadLE24s(mem);
|
||||||
frame->width_ = 1 + ReadLE24s(mem);
|
frame->width = 1 + ReadLE24s(mem);
|
||||||
frame->height_ = 1 + ReadLE24s(mem);
|
frame->height = 1 + ReadLE24s(mem);
|
||||||
frame->duration_ = ReadLE24s(mem);
|
frame->duration = ReadLE24s(mem);
|
||||||
bits = ReadByte(mem);
|
bits = ReadByte(mem);
|
||||||
frame->dispose_method_ =
|
frame->dispose_method =
|
||||||
(bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
|
(bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
|
||||||
frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
|
frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
|
||||||
if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) {
|
if (frame->width * (uint64_t)frame->height >= MAX_IMAGE_AREA) {
|
||||||
WebPSafeFree(frame);
|
WebPSafeFree(frame);
|
||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store a frame only if the animation flag is set there is some data for
|
// Store a frame only if the animation flag is set there is some data for
|
||||||
// this frame is available.
|
// this frame is available.
|
||||||
start_offset = mem->start_;
|
start_offset = mem->start;
|
||||||
status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame);
|
status = StoreFrame(dmux->num_frames + 1, anmf_payload_size, mem, frame);
|
||||||
if (status != PARSE_ERROR && mem->start_ - start_offset > anmf_payload_size) {
|
if (status != PARSE_ERROR && mem->start - start_offset > anmf_payload_size) {
|
||||||
status = PARSE_ERROR;
|
status = PARSE_ERROR;
|
||||||
}
|
}
|
||||||
if (status != PARSE_ERROR && is_animation && frame->frame_num_ > 0) {
|
if (status != PARSE_ERROR && is_animation && frame->frame_num > 0) {
|
||||||
added_frame = AddFrame(dmux, frame);
|
added_frame = AddFrame(dmux, frame);
|
||||||
if (added_frame) {
|
if (added_frame) {
|
||||||
++dmux->num_frames_;
|
++dmux->num_frames;
|
||||||
} else {
|
} else {
|
||||||
status = PARSE_ERROR;
|
status = PARSE_ERROR;
|
||||||
}
|
}
|
||||||
@ -364,8 +364,8 @@ static int StoreChunk(WebPDemuxer* const dmux,
|
|||||||
Chunk* const chunk = (Chunk*)WebPSafeCalloc(1ULL, sizeof(*chunk));
|
Chunk* const chunk = (Chunk*)WebPSafeCalloc(1ULL, sizeof(*chunk));
|
||||||
if (chunk == NULL) return 0;
|
if (chunk == NULL) return 0;
|
||||||
|
|
||||||
chunk->data_.offset_ = start_offset;
|
chunk->data.offset = start_offset;
|
||||||
chunk->data_.size_ = size;
|
chunk->data.size = size;
|
||||||
AddChunk(dmux, chunk);
|
AddChunk(dmux, chunk);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -389,9 +389,9 @@ static ParseStatus ReadHeader(MemBuffer* const mem) {
|
|||||||
if (riff_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
|
if (riff_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
|
||||||
|
|
||||||
// There's no point in reading past the end of the RIFF chunk
|
// There's no point in reading past the end of the RIFF chunk
|
||||||
mem->riff_end_ = riff_size + CHUNK_HEADER_SIZE;
|
mem->riff_end = riff_size + CHUNK_HEADER_SIZE;
|
||||||
if (mem->buf_size_ > mem->riff_end_) {
|
if (mem->buf_size > mem->riff_end) {
|
||||||
mem->buf_size_ = mem->end_ = mem->riff_end_;
|
mem->buf_size = mem->end = mem->riff_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
Skip(mem, RIFF_HEADER_SIZE);
|
Skip(mem, RIFF_HEADER_SIZE);
|
||||||
@ -400,12 +400,12 @@ static ParseStatus ReadHeader(MemBuffer* const mem) {
|
|||||||
|
|
||||||
static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
|
static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
|
||||||
const size_t min_size = CHUNK_HEADER_SIZE;
|
const size_t min_size = CHUNK_HEADER_SIZE;
|
||||||
MemBuffer* const mem = &dmux->mem_;
|
MemBuffer* const mem = &dmux->mem;
|
||||||
Frame* frame;
|
Frame* frame;
|
||||||
ParseStatus status;
|
ParseStatus status;
|
||||||
int image_added = 0;
|
int image_added = 0;
|
||||||
|
|
||||||
if (dmux->frames_ != NULL) return PARSE_ERROR;
|
if (dmux->frames != NULL) return PARSE_ERROR;
|
||||||
if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR;
|
if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR;
|
||||||
if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
|
if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
|
||||||
|
|
||||||
@ -414,29 +414,29 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
|
|||||||
|
|
||||||
// For the single image case we allow parsing of a partial frame, so no
|
// For the single image case we allow parsing of a partial frame, so no
|
||||||
// minimum size is imposed here.
|
// minimum size is imposed here.
|
||||||
status = StoreFrame(1, 0, &dmux->mem_, frame);
|
status = StoreFrame(1, 0, &dmux->mem, frame);
|
||||||
if (status != PARSE_ERROR) {
|
if (status != PARSE_ERROR) {
|
||||||
const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG);
|
const int has_alpha = !!(dmux->feature_flags & ALPHA_FLAG);
|
||||||
// Clear any alpha when the alpha flag is missing.
|
// Clear any alpha when the alpha flag is missing.
|
||||||
if (!has_alpha && frame->img_components_[1].size_ > 0) {
|
if (!has_alpha && frame->img_components[1].size > 0) {
|
||||||
frame->img_components_[1].offset_ = 0;
|
frame->img_components[1].offset = 0;
|
||||||
frame->img_components_[1].size_ = 0;
|
frame->img_components[1].size = 0;
|
||||||
frame->has_alpha_ = 0;
|
frame->has_alpha = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the frame width/height as the canvas values for non-vp8x files.
|
// Use the frame width/height as the canvas values for non-vp8x files.
|
||||||
// Also, set ALPHA_FLAG if this is a lossless image with alpha.
|
// Also, set ALPHA_FLAG if this is a lossless image with alpha.
|
||||||
if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) {
|
if (!dmux->is_ext_format && frame->width > 0 && frame->height > 0) {
|
||||||
dmux->state_ = WEBP_DEMUX_PARSED_HEADER;
|
dmux->state = WEBP_DEMUX_PARSED_HEADER;
|
||||||
dmux->canvas_width_ = frame->width_;
|
dmux->canvas_width = frame->width;
|
||||||
dmux->canvas_height_ = frame->height_;
|
dmux->canvas_height = frame->height;
|
||||||
dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0;
|
dmux->feature_flags |= frame->has_alpha ? ALPHA_FLAG : 0;
|
||||||
}
|
}
|
||||||
if (!AddFrame(dmux, frame)) {
|
if (!AddFrame(dmux, frame)) {
|
||||||
status = PARSE_ERROR; // last frame was left incomplete
|
status = PARSE_ERROR; // last frame was left incomplete
|
||||||
} else {
|
} else {
|
||||||
image_added = 1;
|
image_added = 1;
|
||||||
dmux->num_frames_ = 1;
|
dmux->num_frames = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,14 +445,14 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
|
static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
|
||||||
const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
|
const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG);
|
||||||
MemBuffer* const mem = &dmux->mem_;
|
MemBuffer* const mem = &dmux->mem;
|
||||||
int anim_chunks = 0;
|
int anim_chunks = 0;
|
||||||
ParseStatus status = PARSE_OK;
|
ParseStatus status = PARSE_OK;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int store_chunk = 1;
|
int store_chunk = 1;
|
||||||
const size_t chunk_start_offset = mem->start_;
|
const size_t chunk_start_offset = mem->start;
|
||||||
const uint32_t fourcc = ReadLE32(mem);
|
const uint32_t fourcc = ReadLE32(mem);
|
||||||
const uint32_t chunk_size = ReadLE32(mem);
|
const uint32_t chunk_size = ReadLE32(mem);
|
||||||
uint32_t chunk_size_padded;
|
uint32_t chunk_size_padded;
|
||||||
@ -483,8 +483,8 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
|
|||||||
status = PARSE_NEED_MORE_DATA;
|
status = PARSE_NEED_MORE_DATA;
|
||||||
} else if (anim_chunks == 0) {
|
} else if (anim_chunks == 0) {
|
||||||
++anim_chunks;
|
++anim_chunks;
|
||||||
dmux->bgcolor_ = ReadLE32(mem);
|
dmux->bgcolor = ReadLE32(mem);
|
||||||
dmux->loop_count_ = ReadLE16s(mem);
|
dmux->loop_count = ReadLE16s(mem);
|
||||||
Skip(mem, chunk_size_padded - ANIM_CHUNK_SIZE);
|
Skip(mem, chunk_size_padded - ANIM_CHUNK_SIZE);
|
||||||
} else {
|
} else {
|
||||||
store_chunk = 0;
|
store_chunk = 0;
|
||||||
@ -498,15 +498,15 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MKFOURCC('I', 'C', 'C', 'P'): {
|
case MKFOURCC('I', 'C', 'C', 'P'): {
|
||||||
store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG);
|
store_chunk = !!(dmux->feature_flags & ICCP_FLAG);
|
||||||
goto Skip;
|
goto Skip;
|
||||||
}
|
}
|
||||||
case MKFOURCC('E', 'X', 'I', 'F'): {
|
case MKFOURCC('E', 'X', 'I', 'F'): {
|
||||||
store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG);
|
store_chunk = !!(dmux->feature_flags & EXIF_FLAG);
|
||||||
goto Skip;
|
goto Skip;
|
||||||
}
|
}
|
||||||
case MKFOURCC('X', 'M', 'P', ' '): {
|
case MKFOURCC('X', 'M', 'P', ' '): {
|
||||||
store_chunk = !!(dmux->feature_flags_ & XMP_FLAG);
|
store_chunk = !!(dmux->feature_flags & XMP_FLAG);
|
||||||
goto Skip;
|
goto Skip;
|
||||||
}
|
}
|
||||||
Skip:
|
Skip:
|
||||||
@ -527,7 +527,7 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mem->start_ == mem->riff_end_) {
|
if (mem->start == mem->riff_end) {
|
||||||
break;
|
break;
|
||||||
} else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) {
|
} else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) {
|
||||||
status = PARSE_NEED_MORE_DATA;
|
status = PARSE_NEED_MORE_DATA;
|
||||||
@ -538,12 +538,12 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
|
static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
|
||||||
MemBuffer* const mem = &dmux->mem_;
|
MemBuffer* const mem = &dmux->mem;
|
||||||
uint32_t vp8x_size;
|
uint32_t vp8x_size;
|
||||||
|
|
||||||
if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
|
if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
|
||||||
|
|
||||||
dmux->is_ext_format_ = 1;
|
dmux->is_ext_format = 1;
|
||||||
Skip(mem, TAG_SIZE); // VP8X
|
Skip(mem, TAG_SIZE); // VP8X
|
||||||
vp8x_size = ReadLE32(mem);
|
vp8x_size = ReadLE32(mem);
|
||||||
if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
|
if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
|
||||||
@ -552,15 +552,15 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
|
|||||||
if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR;
|
if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR;
|
||||||
if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA;
|
if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA;
|
||||||
|
|
||||||
dmux->feature_flags_ = ReadByte(mem);
|
dmux->feature_flags = ReadByte(mem);
|
||||||
Skip(mem, 3); // Reserved.
|
Skip(mem, 3); // Reserved.
|
||||||
dmux->canvas_width_ = 1 + ReadLE24s(mem);
|
dmux->canvas_width = 1 + ReadLE24s(mem);
|
||||||
dmux->canvas_height_ = 1 + ReadLE24s(mem);
|
dmux->canvas_height = 1 + ReadLE24s(mem);
|
||||||
if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) {
|
if (dmux->canvas_width * (uint64_t)dmux->canvas_height >= MAX_IMAGE_AREA) {
|
||||||
return PARSE_ERROR; // image final dimension is too large
|
return PARSE_ERROR; // image final dimension is too large
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
|
||||||
if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR;
|
if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR;
|
||||||
if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
|
if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
|
||||||
@ -572,13 +572,13 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
|
|||||||
// Format validation
|
// Format validation
|
||||||
|
|
||||||
static int IsValidSimpleFormat(const WebPDemuxer* const dmux) {
|
static int IsValidSimpleFormat(const WebPDemuxer* const dmux) {
|
||||||
const Frame* const frame = dmux->frames_;
|
const Frame* const frame = dmux->frames;
|
||||||
if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
|
if (dmux->state == WEBP_DEMUX_PARSING_HEADER) return 1;
|
||||||
|
|
||||||
if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
|
if (dmux->canvas_width <= 0 || dmux->canvas_height <= 0) return 0;
|
||||||
if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0;
|
if (dmux->state == WEBP_DEMUX_DONE && frame == NULL) return 0;
|
||||||
|
|
||||||
if (frame->width_ <= 0 || frame->height_ <= 0) return 0;
|
if (frame->width <= 0 || frame->height <= 0) return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,65 +587,65 @@ static int IsValidSimpleFormat(const WebPDemuxer* const dmux) {
|
|||||||
static int CheckFrameBounds(const Frame* const frame, int exact,
|
static int CheckFrameBounds(const Frame* const frame, int exact,
|
||||||
int canvas_width, int canvas_height) {
|
int canvas_width, int canvas_height) {
|
||||||
if (exact) {
|
if (exact) {
|
||||||
if (frame->x_offset_ != 0 || frame->y_offset_ != 0) {
|
if (frame->x_offset != 0 || frame->y_offset != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (frame->width_ != canvas_width || frame->height_ != canvas_height) {
|
if (frame->width != canvas_width || frame->height != canvas_height) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (frame->x_offset_ < 0 || frame->y_offset_ < 0) return 0;
|
if (frame->x_offset < 0 || frame->y_offset < 0) return 0;
|
||||||
if (frame->width_ + frame->x_offset_ > canvas_width) return 0;
|
if (frame->width + frame->x_offset > canvas_width) return 0;
|
||||||
if (frame->height_ + frame->y_offset_ > canvas_height) return 0;
|
if (frame->height + frame->y_offset > canvas_height) return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
||||||
const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
|
const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG);
|
||||||
const Frame* f = dmux->frames_;
|
const Frame* f = dmux->frames;
|
||||||
|
|
||||||
if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
|
if (dmux->state == WEBP_DEMUX_PARSING_HEADER) return 1;
|
||||||
|
|
||||||
if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
|
if (dmux->canvas_width <= 0 || dmux->canvas_height <= 0) return 0;
|
||||||
if (dmux->loop_count_ < 0) return 0;
|
if (dmux->loop_count < 0) return 0;
|
||||||
if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
|
if (dmux->state == WEBP_DEMUX_DONE && dmux->frames == NULL) return 0;
|
||||||
if (dmux->feature_flags_ & ~ALL_VALID_FLAGS) return 0; // invalid bitstream
|
if (dmux->feature_flags & ~ALL_VALID_FLAGS) return 0; // invalid bitstream
|
||||||
|
|
||||||
while (f != NULL) {
|
while (f != NULL) {
|
||||||
const int cur_frame_set = f->frame_num_;
|
const int cur_frame_set = f->frame_num;
|
||||||
|
|
||||||
// Check frame properties.
|
// Check frame properties.
|
||||||
for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
|
for (; f != NULL && f->frame_num == cur_frame_set; f = f->next) {
|
||||||
const ChunkData* const image = f->img_components_;
|
const ChunkData* const image = f->img_components;
|
||||||
const ChunkData* const alpha = f->img_components_ + 1;
|
const ChunkData* const alpha = f->img_components + 1;
|
||||||
|
|
||||||
if (!is_animation && f->frame_num_ > 1) return 0;
|
if (!is_animation && f->frame_num > 1) return 0;
|
||||||
|
|
||||||
if (f->complete_) {
|
if (f->complete) {
|
||||||
if (alpha->size_ == 0 && image->size_ == 0) return 0;
|
if (alpha->size == 0 && image->size == 0) return 0;
|
||||||
// Ensure alpha precedes image bitstream.
|
// Ensure alpha precedes image bitstream.
|
||||||
if (alpha->size_ > 0 && alpha->offset_ > image->offset_) {
|
if (alpha->size > 0 && alpha->offset > image->offset) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->width_ <= 0 || f->height_ <= 0) return 0;
|
if (f->width <= 0 || f->height <= 0) return 0;
|
||||||
} else {
|
} else {
|
||||||
// There shouldn't be a partial frame in a complete file.
|
// There shouldn't be a partial frame in a complete file.
|
||||||
if (dmux->state_ == WEBP_DEMUX_DONE) return 0;
|
if (dmux->state == WEBP_DEMUX_DONE) return 0;
|
||||||
|
|
||||||
// Ensure alpha precedes image bitstream.
|
// Ensure alpha precedes image bitstream.
|
||||||
if (alpha->size_ > 0 && image->size_ > 0 &&
|
if (alpha->size > 0 && image->size > 0 &&
|
||||||
alpha->offset_ > image->offset_) {
|
alpha->offset > image->offset) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// There shouldn't be any frames after an incomplete one.
|
// There shouldn't be any frames after an incomplete one.
|
||||||
if (f->next_ != NULL) return 0;
|
if (f->next != NULL) return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->width_ > 0 && f->height_ > 0 &&
|
if (f->width > 0 && f->height > 0 &&
|
||||||
!CheckFrameBounds(f, !is_animation,
|
!CheckFrameBounds(f, !is_animation,
|
||||||
dmux->canvas_width_, dmux->canvas_height_)) {
|
dmux->canvas_width, dmux->canvas_height)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -657,21 +657,21 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
|||||||
// WebPDemuxer object
|
// WebPDemuxer object
|
||||||
|
|
||||||
static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) {
|
static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) {
|
||||||
dmux->state_ = WEBP_DEMUX_PARSING_HEADER;
|
dmux->state = WEBP_DEMUX_PARSING_HEADER;
|
||||||
dmux->loop_count_ = 1;
|
dmux->loop_count = 1;
|
||||||
dmux->bgcolor_ = 0xFFFFFFFF; // White background by default.
|
dmux->bgcolor = 0xFFFFFFFF; // White background by default.
|
||||||
dmux->canvas_width_ = -1;
|
dmux->canvas_width = -1;
|
||||||
dmux->canvas_height_ = -1;
|
dmux->canvas_height = -1;
|
||||||
dmux->frames_tail_ = &dmux->frames_;
|
dmux->frames_tail = &dmux->frames;
|
||||||
dmux->chunks_tail_ = &dmux->chunks_;
|
dmux->chunks_tail = &dmux->chunks;
|
||||||
dmux->mem_ = *mem;
|
dmux->mem = *mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ParseStatus CreateRawImageDemuxer(MemBuffer* const mem,
|
static ParseStatus CreateRawImageDemuxer(MemBuffer* const mem,
|
||||||
WebPDemuxer** demuxer) {
|
WebPDemuxer** demuxer) {
|
||||||
WebPBitstreamFeatures features;
|
WebPBitstreamFeatures features;
|
||||||
const VP8StatusCode status =
|
const VP8StatusCode status =
|
||||||
WebPGetFeatures(mem->buf_, mem->buf_size_, &features);
|
WebPGetFeatures(mem->buf, mem->buf_size, &features);
|
||||||
*demuxer = NULL;
|
*demuxer = NULL;
|
||||||
if (status != VP8_STATUS_OK) {
|
if (status != VP8_STATUS_OK) {
|
||||||
return (status == VP8_STATUS_NOT_ENOUGH_DATA) ? PARSE_NEED_MORE_DATA
|
return (status == VP8_STATUS_NOT_ENOUGH_DATA) ? PARSE_NEED_MORE_DATA
|
||||||
@ -683,14 +683,14 @@ static ParseStatus CreateRawImageDemuxer(MemBuffer* const mem,
|
|||||||
Frame* const frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame));
|
Frame* const frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame));
|
||||||
if (dmux == NULL || frame == NULL) goto Error;
|
if (dmux == NULL || frame == NULL) goto Error;
|
||||||
InitDemux(dmux, mem);
|
InitDemux(dmux, mem);
|
||||||
SetFrameInfo(0, mem->buf_size_, 1 /*frame_num*/, 1 /*complete*/, &features,
|
SetFrameInfo(0, mem->buf_size, 1 /*frame_num*/, 1 /*complete*/, &features,
|
||||||
frame);
|
frame);
|
||||||
if (!AddFrame(dmux, frame)) goto Error;
|
if (!AddFrame(dmux, frame)) goto Error;
|
||||||
dmux->state_ = WEBP_DEMUX_DONE;
|
dmux->state = WEBP_DEMUX_DONE;
|
||||||
dmux->canvas_width_ = frame->width_;
|
dmux->canvas_width = frame->width;
|
||||||
dmux->canvas_height_ = frame->height_;
|
dmux->canvas_height = frame->height;
|
||||||
dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0;
|
dmux->feature_flags |= frame->has_alpha ? ALPHA_FLAG : 0;
|
||||||
dmux->num_frames_ = 1;
|
dmux->num_frames = 1;
|
||||||
assert(IsValidSimpleFormat(dmux));
|
assert(IsValidSimpleFormat(dmux));
|
||||||
*demuxer = dmux;
|
*demuxer = dmux;
|
||||||
return PARSE_OK;
|
return PARSE_OK;
|
||||||
@ -734,7 +734,7 @@ WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial = (mem.buf_size_ < mem.riff_end_);
|
partial = (mem.buf_size < mem.riff_end);
|
||||||
if (!allow_partial && partial) return NULL;
|
if (!allow_partial && partial) return NULL;
|
||||||
|
|
||||||
dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux));
|
dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux));
|
||||||
@ -743,16 +743,16 @@ WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
|
|||||||
|
|
||||||
status = PARSE_ERROR;
|
status = PARSE_ERROR;
|
||||||
for (parser = kMasterChunks; parser->parse != NULL; ++parser) {
|
for (parser = kMasterChunks; parser->parse != NULL; ++parser) {
|
||||||
if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) {
|
if (!memcmp(parser->id, GetBuffer(&dmux->mem), TAG_SIZE)) {
|
||||||
status = parser->parse(dmux);
|
status = parser->parse(dmux);
|
||||||
if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE;
|
if (status == PARSE_OK) dmux->state = WEBP_DEMUX_DONE;
|
||||||
if (status == PARSE_NEED_MORE_DATA && !partial) status = PARSE_ERROR;
|
if (status == PARSE_NEED_MORE_DATA && !partial) status = PARSE_ERROR;
|
||||||
if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR;
|
if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR;
|
||||||
if (status == PARSE_ERROR) dmux->state_ = WEBP_DEMUX_PARSE_ERROR;
|
if (status == PARSE_ERROR) dmux->state = WEBP_DEMUX_PARSE_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state != NULL) *state = dmux->state_;
|
if (state != NULL) *state = dmux->state;
|
||||||
|
|
||||||
if (status == PARSE_ERROR) {
|
if (status == PARSE_ERROR) {
|
||||||
WebPDemuxDelete(dmux);
|
WebPDemuxDelete(dmux);
|
||||||
@ -766,14 +766,14 @@ void WebPDemuxDelete(WebPDemuxer* dmux) {
|
|||||||
Frame* f;
|
Frame* f;
|
||||||
if (dmux == NULL) return;
|
if (dmux == NULL) return;
|
||||||
|
|
||||||
for (f = dmux->frames_; f != NULL;) {
|
for (f = dmux->frames; f != NULL;) {
|
||||||
Frame* const cur_frame = f;
|
Frame* const cur_frame = f;
|
||||||
f = f->next_;
|
f = f->next;
|
||||||
WebPSafeFree(cur_frame);
|
WebPSafeFree(cur_frame);
|
||||||
}
|
}
|
||||||
for (c = dmux->chunks_; c != NULL;) {
|
for (c = dmux->chunks; c != NULL;) {
|
||||||
Chunk* const cur_chunk = c;
|
Chunk* const cur_chunk = c;
|
||||||
c = c->next_;
|
c = c->next;
|
||||||
WebPSafeFree(cur_chunk);
|
WebPSafeFree(cur_chunk);
|
||||||
}
|
}
|
||||||
WebPSafeFree(dmux);
|
WebPSafeFree(dmux);
|
||||||
@ -785,12 +785,12 @@ uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) {
|
|||||||
if (dmux == NULL) return 0;
|
if (dmux == NULL) return 0;
|
||||||
|
|
||||||
switch (feature) {
|
switch (feature) {
|
||||||
case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags_;
|
case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags;
|
||||||
case WEBP_FF_CANVAS_WIDTH: return (uint32_t)dmux->canvas_width_;
|
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_CANVAS_HEIGHT: return (uint32_t)dmux->canvas_height;
|
||||||
case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count_;
|
case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count;
|
||||||
case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor_;
|
case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor;
|
||||||
case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames_;
|
case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -800,8 +800,8 @@ uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) {
|
|||||||
|
|
||||||
static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) {
|
static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) {
|
||||||
const Frame* f;
|
const Frame* f;
|
||||||
for (f = dmux->frames_; f != NULL; f = f->next_) {
|
for (f = dmux->frames; f != NULL; f = f->next) {
|
||||||
if (frame_num == f->frame_num_) break;
|
if (frame_num == f->frame_num) break;
|
||||||
}
|
}
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
@ -811,19 +811,19 @@ static const uint8_t* GetFramePayload(const uint8_t* const mem_buf,
|
|||||||
size_t* const data_size) {
|
size_t* const data_size) {
|
||||||
*data_size = 0;
|
*data_size = 0;
|
||||||
if (frame != NULL) {
|
if (frame != NULL) {
|
||||||
const ChunkData* const image = frame->img_components_;
|
const ChunkData* const image = frame->img_components;
|
||||||
const ChunkData* const alpha = frame->img_components_ + 1;
|
const ChunkData* const alpha = frame->img_components + 1;
|
||||||
size_t start_offset = image->offset_;
|
size_t start_offset = image->offset;
|
||||||
*data_size = image->size_;
|
*data_size = image->size;
|
||||||
|
|
||||||
// if alpha exists it precedes image, update the size allowing for
|
// if alpha exists it precedes image, update the size allowing for
|
||||||
// intervening chunks.
|
// intervening chunks.
|
||||||
if (alpha->size_ > 0) {
|
if (alpha->size > 0) {
|
||||||
const size_t inter_size = (image->offset_ > 0)
|
const size_t inter_size = (image->offset > 0)
|
||||||
? image->offset_ - (alpha->offset_ + alpha->size_)
|
? image->offset - (alpha->offset + alpha->size)
|
||||||
: 0;
|
: 0;
|
||||||
start_offset = alpha->offset_;
|
start_offset = alpha->offset;
|
||||||
*data_size += alpha->size_ + inter_size;
|
*data_size += alpha->size + inter_size;
|
||||||
}
|
}
|
||||||
return mem_buf + start_offset;
|
return mem_buf + start_offset;
|
||||||
}
|
}
|
||||||
@ -834,23 +834,23 @@ static const uint8_t* GetFramePayload(const uint8_t* const mem_buf,
|
|||||||
static int SynthesizeFrame(const WebPDemuxer* const dmux,
|
static int SynthesizeFrame(const WebPDemuxer* const dmux,
|
||||||
const Frame* const frame,
|
const Frame* const frame,
|
||||||
WebPIterator* const iter) {
|
WebPIterator* const iter) {
|
||||||
const uint8_t* const mem_buf = dmux->mem_.buf_;
|
const uint8_t* const mem_buf = dmux->mem.buf;
|
||||||
size_t payload_size = 0;
|
size_t payload_size = 0;
|
||||||
const uint8_t* const payload = GetFramePayload(mem_buf, frame, &payload_size);
|
const uint8_t* const payload = GetFramePayload(mem_buf, frame, &payload_size);
|
||||||
if (payload == NULL) return 0;
|
if (payload == NULL) return 0;
|
||||||
assert(frame != NULL);
|
assert(frame != NULL);
|
||||||
|
|
||||||
iter->frame_num = frame->frame_num_;
|
iter->frame_num = frame->frame_num;
|
||||||
iter->num_frames = dmux->num_frames_;
|
iter->num_frames = dmux->num_frames;
|
||||||
iter->x_offset = frame->x_offset_;
|
iter->x_offset = frame->x_offset;
|
||||||
iter->y_offset = frame->y_offset_;
|
iter->y_offset = frame->y_offset;
|
||||||
iter->width = frame->width_;
|
iter->width = frame->width;
|
||||||
iter->height = frame->height_;
|
iter->height = frame->height;
|
||||||
iter->has_alpha = frame->has_alpha_;
|
iter->has_alpha = frame->has_alpha;
|
||||||
iter->duration = frame->duration_;
|
iter->duration = frame->duration;
|
||||||
iter->dispose_method = frame->dispose_method_;
|
iter->dispose_method = frame->dispose_method;
|
||||||
iter->blend_method = frame->blend_method_;
|
iter->blend_method = frame->blend_method;
|
||||||
iter->complete = frame->complete_;
|
iter->complete = frame->complete;
|
||||||
iter->fragment.bytes = payload;
|
iter->fragment.bytes = payload;
|
||||||
iter->fragment.size = payload_size;
|
iter->fragment.size = payload_size;
|
||||||
return 1;
|
return 1;
|
||||||
@ -860,8 +860,8 @@ static int SetFrame(int frame_num, WebPIterator* const iter) {
|
|||||||
const Frame* frame;
|
const Frame* frame;
|
||||||
const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_;
|
const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_;
|
||||||
if (dmux == NULL || frame_num < 0) return 0;
|
if (dmux == NULL || frame_num < 0) return 0;
|
||||||
if (frame_num > dmux->num_frames_) return 0;
|
if (frame_num > dmux->num_frames) return 0;
|
||||||
if (frame_num == 0) frame_num = dmux->num_frames_;
|
if (frame_num == 0) frame_num = dmux->num_frames;
|
||||||
|
|
||||||
frame = GetFrame(dmux, frame_num);
|
frame = GetFrame(dmux, frame_num);
|
||||||
if (frame == NULL) return 0;
|
if (frame == NULL) return 0;
|
||||||
@ -896,11 +896,11 @@ void WebPDemuxReleaseIterator(WebPIterator* iter) {
|
|||||||
// Chunk iteration
|
// Chunk iteration
|
||||||
|
|
||||||
static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) {
|
static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) {
|
||||||
const uint8_t* const mem_buf = dmux->mem_.buf_;
|
const uint8_t* const mem_buf = dmux->mem.buf;
|
||||||
const Chunk* c;
|
const Chunk* c;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (c = dmux->chunks_; c != NULL; c = c->next_) {
|
for (c = dmux->chunks; c != NULL; c = c->next) {
|
||||||
const uint8_t* const header = mem_buf + c->data_.offset_;
|
const uint8_t* const header = mem_buf + c->data.offset;
|
||||||
if (!memcmp(header, fourcc, TAG_SIZE)) ++count;
|
if (!memcmp(header, fourcc, TAG_SIZE)) ++count;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
@ -908,11 +908,11 @@ static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) {
|
|||||||
|
|
||||||
static const Chunk* GetChunk(const WebPDemuxer* const dmux,
|
static const Chunk* GetChunk(const WebPDemuxer* const dmux,
|
||||||
const char fourcc[4], int chunk_num) {
|
const char fourcc[4], int chunk_num) {
|
||||||
const uint8_t* const mem_buf = dmux->mem_.buf_;
|
const uint8_t* const mem_buf = dmux->mem.buf;
|
||||||
const Chunk* c;
|
const Chunk* c;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (c = dmux->chunks_; c != NULL; c = c->next_) {
|
for (c = dmux->chunks; c != NULL; c = c->next) {
|
||||||
const uint8_t* const header = mem_buf + c->data_.offset_;
|
const uint8_t* const header = mem_buf + c->data.offset;
|
||||||
if (!memcmp(header, fourcc, TAG_SIZE)) ++count;
|
if (!memcmp(header, fourcc, TAG_SIZE)) ++count;
|
||||||
if (count == chunk_num) break;
|
if (count == chunk_num) break;
|
||||||
}
|
}
|
||||||
@ -930,10 +930,10 @@ static int SetChunk(const char fourcc[4], int chunk_num,
|
|||||||
if (chunk_num == 0) chunk_num = count;
|
if (chunk_num == 0) chunk_num = count;
|
||||||
|
|
||||||
if (chunk_num <= count) {
|
if (chunk_num <= count) {
|
||||||
const uint8_t* const mem_buf = dmux->mem_.buf_;
|
const uint8_t* const mem_buf = dmux->mem.buf;
|
||||||
const Chunk* const chunk = GetChunk(dmux, fourcc, chunk_num);
|
const Chunk* const chunk = GetChunk(dmux, fourcc, chunk_num);
|
||||||
iter->chunk.bytes = mem_buf + chunk->data_.offset_ + CHUNK_HEADER_SIZE;
|
iter->chunk.bytes = mem_buf + chunk->data.offset + CHUNK_HEADER_SIZE;
|
||||||
iter->chunk.size = chunk->data_.size_ - CHUNK_HEADER_SIZE;
|
iter->chunk.size = chunk->data.size - CHUNK_HEADER_SIZE;
|
||||||
iter->num_chunks = count;
|
iter->num_chunks = count;
|
||||||
iter->chunk_num = chunk_num;
|
iter->chunk_num = chunk_num;
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user