|
|
@ -46,8 +46,7 @@ typedef struct GifState { |
|
|
|
int gce_delay; |
|
|
|
int gce_delay; |
|
|
|
|
|
|
|
|
|
|
|
/* LZW compatible decoder */ |
|
|
|
/* LZW compatible decoder */ |
|
|
|
const uint8_t *bytestream; |
|
|
|
GetByteContext gb; |
|
|
|
const uint8_t *bytestream_end; |
|
|
|
|
|
|
|
LZWState *lzw; |
|
|
|
LZWState *lzw; |
|
|
|
|
|
|
|
|
|
|
|
/* aux buffers */ |
|
|
|
/* aux buffers */ |
|
|
@ -66,11 +65,11 @@ static int gif_read_image(GifState *s, AVFrame *frame) |
|
|
|
int is_interleaved, has_local_palette, y, pass, y1, linesize, n, i; |
|
|
|
int is_interleaved, has_local_palette, y, pass, y1, linesize, n, i; |
|
|
|
uint8_t *ptr, *spal, *palette, *ptr1; |
|
|
|
uint8_t *ptr, *spal, *palette, *ptr1; |
|
|
|
|
|
|
|
|
|
|
|
left = bytestream_get_le16(&s->bytestream); |
|
|
|
left = bytestream2_get_le16(&s->gb); |
|
|
|
top = bytestream_get_le16(&s->bytestream); |
|
|
|
top = bytestream2_get_le16(&s->gb); |
|
|
|
width = bytestream_get_le16(&s->bytestream); |
|
|
|
width = bytestream2_get_le16(&s->gb); |
|
|
|
height = bytestream_get_le16(&s->bytestream); |
|
|
|
height = bytestream2_get_le16(&s->gb); |
|
|
|
flags = bytestream_get_byte(&s->bytestream); |
|
|
|
flags = bytestream2_get_byte(&s->gb); |
|
|
|
is_interleaved = flags & 0x40; |
|
|
|
is_interleaved = flags & 0x40; |
|
|
|
has_local_palette = flags & 0x80; |
|
|
|
has_local_palette = flags & 0x80; |
|
|
|
bits_per_pixel = (flags & 0x07) + 1; |
|
|
|
bits_per_pixel = (flags & 0x07) + 1; |
|
|
@ -78,7 +77,7 @@ static int gif_read_image(GifState *s, AVFrame *frame) |
|
|
|
av_dlog(s->avctx, "gif: image x=%d y=%d w=%d h=%d\n", left, top, width, height); |
|
|
|
av_dlog(s->avctx, "gif: image x=%d y=%d w=%d h=%d\n", left, top, width, height); |
|
|
|
|
|
|
|
|
|
|
|
if (has_local_palette) { |
|
|
|
if (has_local_palette) { |
|
|
|
bytestream_get_buffer(&s->bytestream, s->local_palette, 3 * (1 << bits_per_pixel)); |
|
|
|
bytestream2_get_buffer(&s->gb, s->local_palette, 3 * (1 << bits_per_pixel)); |
|
|
|
palette = s->local_palette; |
|
|
|
palette = s->local_palette; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
palette = s->global_palette; |
|
|
|
palette = s->global_palette; |
|
|
@ -107,9 +106,9 @@ static int gif_read_image(GifState *s, AVFrame *frame) |
|
|
|
s->image_palette[s->transparent_color_index] = 0; |
|
|
|
s->image_palette[s->transparent_color_index] = 0; |
|
|
|
|
|
|
|
|
|
|
|
/* now get the image data */ |
|
|
|
/* now get the image data */ |
|
|
|
code_size = bytestream_get_byte(&s->bytestream); |
|
|
|
code_size = bytestream2_get_byte(&s->gb); |
|
|
|
ff_lzw_decode_init(s->lzw, code_size, s->bytestream, |
|
|
|
ff_lzw_decode_init(s->lzw, code_size, s->gb.buffer, |
|
|
|
s->bytestream_end - s->bytestream, FF_LZW_GIF); |
|
|
|
bytestream2_get_bytes_left(&s->gb), FF_LZW_GIF); |
|
|
|
|
|
|
|
|
|
|
|
/* read all the image */ |
|
|
|
/* read all the image */ |
|
|
|
linesize = frame->linesize[0]; |
|
|
|
linesize = frame->linesize[0]; |
|
|
@ -152,7 +151,8 @@ static int gif_read_image(GifState *s, AVFrame *frame) |
|
|
|
} |
|
|
|
} |
|
|
|
/* read the garbage data until end marker is found */ |
|
|
|
/* read the garbage data until end marker is found */ |
|
|
|
ff_lzw_decode_tail(s->lzw); |
|
|
|
ff_lzw_decode_tail(s->lzw); |
|
|
|
s->bytestream = ff_lzw_cur_ptr(s->lzw); |
|
|
|
|
|
|
|
|
|
|
|
bytestream2_skip(&s->gb, ff_lzw_size_read(s->lzw)); |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -161,8 +161,8 @@ static int gif_read_extension(GifState *s) |
|
|
|
int ext_code, ext_len, i, gce_flags, gce_transparent_index; |
|
|
|
int ext_code, ext_len, i, gce_flags, gce_transparent_index; |
|
|
|
|
|
|
|
|
|
|
|
/* extension */ |
|
|
|
/* extension */ |
|
|
|
ext_code = bytestream_get_byte(&s->bytestream); |
|
|
|
ext_code = bytestream2_get_byte(&s->gb); |
|
|
|
ext_len = bytestream_get_byte(&s->bytestream); |
|
|
|
ext_len = bytestream2_get_byte(&s->gb); |
|
|
|
|
|
|
|
|
|
|
|
av_dlog(s->avctx, "gif: ext_code=0x%x len=%d\n", ext_code, ext_len); |
|
|
|
av_dlog(s->avctx, "gif: ext_code=0x%x len=%d\n", ext_code, ext_len); |
|
|
|
|
|
|
|
|
|
|
@ -171,9 +171,9 @@ static int gif_read_extension(GifState *s) |
|
|
|
if (ext_len != 4) |
|
|
|
if (ext_len != 4) |
|
|
|
goto discard_ext; |
|
|
|
goto discard_ext; |
|
|
|
s->transparent_color_index = -1; |
|
|
|
s->transparent_color_index = -1; |
|
|
|
gce_flags = bytestream_get_byte(&s->bytestream); |
|
|
|
gce_flags = bytestream2_get_byte(&s->gb); |
|
|
|
s->gce_delay = bytestream_get_le16(&s->bytestream); |
|
|
|
s->gce_delay = bytestream2_get_le16(&s->gb); |
|
|
|
gce_transparent_index = bytestream_get_byte(&s->bytestream); |
|
|
|
gce_transparent_index = bytestream2_get_byte(&s->gb); |
|
|
|
if (gce_flags & 0x01) |
|
|
|
if (gce_flags & 0x01) |
|
|
|
s->transparent_color_index = gce_transparent_index; |
|
|
|
s->transparent_color_index = gce_transparent_index; |
|
|
|
else |
|
|
|
else |
|
|
@ -184,7 +184,7 @@ static int gif_read_extension(GifState *s) |
|
|
|
gce_flags, s->gce_delay, |
|
|
|
gce_flags, s->gce_delay, |
|
|
|
s->transparent_color_index, s->gce_disposal); |
|
|
|
s->transparent_color_index, s->gce_disposal); |
|
|
|
|
|
|
|
|
|
|
|
ext_len = bytestream_get_byte(&s->bytestream); |
|
|
|
ext_len = bytestream2_get_byte(&s->gb); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -192,8 +192,8 @@ static int gif_read_extension(GifState *s) |
|
|
|
discard_ext: |
|
|
|
discard_ext: |
|
|
|
while (ext_len != 0) { |
|
|
|
while (ext_len != 0) { |
|
|
|
for (i = 0; i < ext_len; i++) |
|
|
|
for (i = 0; i < ext_len; i++) |
|
|
|
bytestream_get_byte(&s->bytestream); |
|
|
|
bytestream2_get_byte(&s->gb); |
|
|
|
ext_len = bytestream_get_byte(&s->bytestream); |
|
|
|
ext_len = bytestream2_get_byte(&s->gb); |
|
|
|
|
|
|
|
|
|
|
|
av_dlog(s->avctx, "gif: ext_len1=%d\n", ext_len); |
|
|
|
av_dlog(s->avctx, "gif: ext_len1=%d\n", ext_len); |
|
|
|
} |
|
|
|
} |
|
|
@ -206,31 +206,31 @@ static int gif_read_header1(GifState *s) |
|
|
|
int v, n; |
|
|
|
int v, n; |
|
|
|
int has_global_palette; |
|
|
|
int has_global_palette; |
|
|
|
|
|
|
|
|
|
|
|
if (s->bytestream_end < s->bytestream + 13) |
|
|
|
if (bytestream2_get_bytes_left(&s->gb) < 13) |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
|
|
|
|
/* read gif signature */ |
|
|
|
/* read gif signature */ |
|
|
|
bytestream_get_buffer(&s->bytestream, sig, 6); |
|
|
|
bytestream2_get_buffer(&s->gb, sig, 6); |
|
|
|
if (memcmp(sig, gif87a_sig, 6) != 0 && |
|
|
|
if (memcmp(sig, gif87a_sig, 6) != 0 && |
|
|
|
memcmp(sig, gif89a_sig, 6) != 0) |
|
|
|
memcmp(sig, gif89a_sig, 6) != 0) |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
|
|
|
|
/* read screen header */ |
|
|
|
/* read screen header */ |
|
|
|
s->transparent_color_index = -1; |
|
|
|
s->transparent_color_index = -1; |
|
|
|
s->screen_width = bytestream_get_le16(&s->bytestream); |
|
|
|
s->screen_width = bytestream2_get_le16(&s->gb); |
|
|
|
s->screen_height = bytestream_get_le16(&s->bytestream); |
|
|
|
s->screen_height = bytestream2_get_le16(&s->gb); |
|
|
|
if( (unsigned)s->screen_width > 32767 |
|
|
|
if( (unsigned)s->screen_width > 32767 |
|
|
|
|| (unsigned)s->screen_height > 32767){ |
|
|
|
|| (unsigned)s->screen_height > 32767){ |
|
|
|
av_log(NULL, AV_LOG_ERROR, "picture size too large\n"); |
|
|
|
av_log(NULL, AV_LOG_ERROR, "picture size too large\n"); |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
v = bytestream_get_byte(&s->bytestream); |
|
|
|
v = bytestream2_get_byte(&s->gb); |
|
|
|
s->color_resolution = ((v & 0x70) >> 4) + 1; |
|
|
|
s->color_resolution = ((v & 0x70) >> 4) + 1; |
|
|
|
has_global_palette = (v & 0x80); |
|
|
|
has_global_palette = (v & 0x80); |
|
|
|
s->bits_per_pixel = (v & 0x07) + 1; |
|
|
|
s->bits_per_pixel = (v & 0x07) + 1; |
|
|
|
s->background_color_index = bytestream_get_byte(&s->bytestream); |
|
|
|
s->background_color_index = bytestream2_get_byte(&s->gb); |
|
|
|
bytestream_get_byte(&s->bytestream); /* ignored */ |
|
|
|
bytestream2_get_byte(&s->gb); /* ignored */ |
|
|
|
|
|
|
|
|
|
|
|
av_dlog(s->avctx, "gif: screen_w=%d screen_h=%d bpp=%d global_palette=%d\n", |
|
|
|
av_dlog(s->avctx, "gif: screen_w=%d screen_h=%d bpp=%d global_palette=%d\n", |
|
|
|
s->screen_width, s->screen_height, s->bits_per_pixel, |
|
|
|
s->screen_width, s->screen_height, s->bits_per_pixel, |
|
|
@ -238,17 +238,17 @@ static int gif_read_header1(GifState *s) |
|
|
|
|
|
|
|
|
|
|
|
if (has_global_palette) { |
|
|
|
if (has_global_palette) { |
|
|
|
n = 1 << s->bits_per_pixel; |
|
|
|
n = 1 << s->bits_per_pixel; |
|
|
|
if (s->bytestream_end < s->bytestream + n * 3) |
|
|
|
if (bytestream2_get_bytes_left(&s->gb) < n * 3) |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
bytestream_get_buffer(&s->bytestream, s->global_palette, n * 3); |
|
|
|
bytestream2_get_buffer(&s->gb, s->global_palette, n * 3); |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int gif_parse_next_image(GifState *s, AVFrame *frame) |
|
|
|
static int gif_parse_next_image(GifState *s, AVFrame *frame) |
|
|
|
{ |
|
|
|
{ |
|
|
|
while (s->bytestream < s->bytestream_end) { |
|
|
|
while (bytestream2_get_bytes_left(&s->gb) > 0) { |
|
|
|
int code = bytestream_get_byte(&s->bytestream); |
|
|
|
int code = bytestream2_get_byte(&s->gb); |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
|
|
av_dlog(s->avctx, "gif: code=%02x '%c'\n", code, code); |
|
|
|
av_dlog(s->avctx, "gif: code=%02x '%c'\n", code, code); |
|
|
@ -289,8 +289,7 @@ static int gif_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, |
|
|
|
AVFrame *picture = data; |
|
|
|
AVFrame *picture = data; |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
|
|
s->bytestream = buf; |
|
|
|
bytestream2_init(&s->gb, buf, buf_size); |
|
|
|
s->bytestream_end = buf + buf_size; |
|
|
|
|
|
|
|
if ((ret = gif_read_header1(s)) < 0) |
|
|
|
if ((ret = gif_read_header1(s)) < 0) |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
|
|
|
|
|
|
|
@ -309,7 +308,7 @@ static int gif_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
|
|
|
|
|
|
|
|
*got_frame = 1; |
|
|
|
*got_frame = 1; |
|
|
|
return s->bytestream - buf; |
|
|
|
return bytestream2_tell(&s->gb); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static av_cold int gif_decode_close(AVCodecContext *avctx) |
|
|
|
static av_cold int gif_decode_close(AVCodecContext *avctx) |
|
|
|