added 8 bit palette support for non animated GIF

Originally committed as revision 1562 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Fabrice Bellard 2003-02-09 16:25:21 +00:00
parent 3ce27f13b9
commit 84ab361f3e
2 changed files with 74 additions and 42 deletions

View File

@ -167,9 +167,11 @@ static void gif_flush_put_bits_rev(PutBitContext *s)
/* !RevPutBitContext */ /* !RevPutBitContext */
/* GIF header */ /* GIF header */
static int gif_image_write_header(ByteIOContext *pb, int width, int height) static int gif_image_write_header(ByteIOContext *pb,
int width, int height, uint32_t *palette)
{ {
int i; int i;
unsigned int v;
put_tag(pb, "GIF"); put_tag(pb, "GIF");
put_tag(pb, "89a"); put_tag(pb, "89a");
@ -181,10 +183,18 @@ static int gif_image_write_header(ByteIOContext *pb, int width, int height)
put_byte(pb, 0); /* aspect ratio */ put_byte(pb, 0); /* aspect ratio */
/* the global palette */ /* the global palette */
if (!palette) {
put_buffer(pb, (unsigned char *)gif_clut, 216*3); put_buffer(pb, (unsigned char *)gif_clut, 216*3);
for(i=0;i<((256-216)*3);i++) for(i=0;i<((256-216)*3);i++)
put_byte(pb, 0); put_byte(pb, 0);
} else {
for(i=0;i<256;i++) {
v = palette[i];
put_byte(pb, (v >> 16) & 0xff);
put_byte(pb, (v >> 8) & 0xff);
put_byte(pb, (v) & 0xff);
}
}
/* application extension header */ /* application extension header */
/* XXX: not really sure what to put in here... */ /* XXX: not really sure what to put in here... */
@ -202,7 +212,7 @@ static int gif_image_write_header(ByteIOContext *pb, int width, int height)
} }
/* this is maybe slow, but allows for extensions */ /* this is maybe slow, but allows for extensions */
static inline unsigned char gif_clut_index(rgb_triplet *clut, UINT8 r, UINT8 g, UINT8 b) static inline unsigned char gif_clut_index(UINT8 r, UINT8 g, UINT8 b)
{ {
return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6)); return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6));
} }
@ -210,11 +220,11 @@ static inline unsigned char gif_clut_index(rgb_triplet *clut, UINT8 r, UINT8 g,
static int gif_image_write_image(ByteIOContext *pb, static int gif_image_write_image(ByteIOContext *pb,
int x1, int y1, int width, int height, int x1, int y1, int width, int height,
uint8_t *buf, int linesize) uint8_t *buf, int linesize, int pix_fmt)
{ {
PutBitContext p; PutBitContext p;
UINT8 buffer[200]; /* 100 * 9 / 8 = 113 */ UINT8 buffer[200]; /* 100 * 9 / 8 = 113 */
int i, left, w; int i, left, w, v;
uint8_t *ptr; uint8_t *ptr;
/* image block */ /* image block */
@ -243,8 +253,13 @@ static int gif_image_write_image(ByteIOContext *pb,
gif_put_bits_rev(&p, 9, 0x0100); /* clear code */ gif_put_bits_rev(&p, 9, 0x0100); /* clear code */
for(i=0;i<GIF_CHUNKS;i++) { for(i=0;i<GIF_CHUNKS;i++) {
gif_put_bits_rev(&p, 9, gif_clut_index(NULL, ptr[0], ptr[1], ptr[2])); if (pix_fmt == PIX_FMT_RGB24) {
v = gif_clut_index(ptr[0], ptr[1], ptr[2]);
ptr+=3; ptr+=3;
} else {
v = *ptr++;
}
gif_put_bits_rev(&p, 9, v);
if (--w == 0) { if (--w == 0) {
w = width; w = width;
buf += linesize; buf += linesize;
@ -309,22 +324,12 @@ static int gif_write_header(AVFormatContext *s)
/* XXX: is it allowed ? seems to work so far... */ /* XXX: is it allowed ? seems to work so far... */
video_enc->pix_fmt = PIX_FMT_RGB24; video_enc->pix_fmt = PIX_FMT_RGB24;
gif_image_write_header(pb, width, height); gif_image_write_header(pb, width, height, NULL);
put_flush_packet(&s->pb); put_flush_packet(&s->pb);
return 0; return 0;
} }
/* chunk writer callback */
/* !!! XXX:deprecated
static void gif_put_chunk(void *pbctx, UINT8 *buffer, int count)
{
ByteIOContext *pb = (ByteIOContext *)pbctx;
put_byte(pb, (UINT8)count);
put_buffer(pb, buffer, count);
}
*/
static int gif_write_video(AVFormatContext *s, static int gif_write_video(AVFormatContext *s,
AVCodecContext *enc, UINT8 *buf, int size) AVCodecContext *enc, UINT8 *buf, int size)
{ {
@ -354,7 +359,7 @@ static int gif_write_video(AVFormatContext *s,
put_byte(pb, 0x00); put_byte(pb, 0x00);
gif_image_write_image(pb, 0, 0, enc->width, enc->height, gif_image_write_image(pb, 0, 0, enc->width, enc->height,
buf, enc->width * 3); buf, enc->width * 3, PIX_FMT_RGB24);
put_flush_packet(&s->pb); put_flush_packet(&s->pb);
return 0; return 0;
@ -382,9 +387,11 @@ static int gif_write_trailer(AVFormatContext *s)
/* better than nothing gif image writer */ /* better than nothing gif image writer */
int gif_write(ByteIOContext *pb, AVImageInfo *info) int gif_write(ByteIOContext *pb, AVImageInfo *info)
{ {
gif_image_write_header(pb, info->width, info->height); gif_image_write_header(pb, info->width, info->height,
(uint32_t *)info->pict.data[1]);
gif_image_write_image(pb, 0, 0, info->width, info->height, gif_image_write_image(pb, 0, 0, info->width, info->height,
info->pict.data[0], info->pict.linesize[0]); info->pict.data[0], info->pict.linesize[0],
PIX_FMT_PAL8);
put_byte(pb, 0x3b); put_byte(pb, 0x3b);
put_flush_packet(pb); put_flush_packet(pb);
return 0; return 0;

View File

@ -39,6 +39,9 @@ typedef struct GifState {
int color_resolution; int color_resolution;
uint8_t *image_buf; uint8_t *image_buf;
int image_linesize; int image_linesize;
uint32_t *image_palette;
int pix_fmt;
/* after the frame is displayed, the disposal method is used */ /* after the frame is displayed, the disposal method is used */
int gce_disposal; int gce_disposal;
/* delay during which the frame is shown */ /* delay during which the frame is shown */
@ -274,7 +277,7 @@ static int gif_read_image(GifState *s)
{ {
ByteIOContext *f = s->f; ByteIOContext *f = s->f;
int left, top, width, height, bits_per_pixel, code_size, flags; int left, top, width, height, bits_per_pixel, code_size, flags;
int is_interleaved, has_local_palette, y, x, pass, y1, linesize; int is_interleaved, has_local_palette, y, x, pass, y1, linesize, n, i;
uint8_t *ptr, *line, *d, *spal, *palette, *sptr, *ptr1; uint8_t *ptr, *line, *d, *spal, *palette, *sptr, *ptr1;
left = get_le16(f); left = get_le16(f);
@ -294,6 +297,7 @@ static int gif_read_image(GifState *s)
palette = s->local_palette; palette = s->local_palette;
} else { } else {
palette = s->global_palette; palette = s->global_palette;
bits_per_pixel = s->bits_per_pixel;
} }
/* verify that all the image is inside the screen dimensions */ /* verify that all the image is inside the screen dimensions */
@ -301,22 +305,38 @@ static int gif_read_image(GifState *s)
top + height > s->screen_height) top + height > s->screen_height)
return -EINVAL; return -EINVAL;
/* build the palette */
if (s->pix_fmt == PIX_FMT_RGB24) {
line = av_malloc(width); line = av_malloc(width);
if (!line) if (!line)
return -ENOMEM; return -ENOMEM;
} else {
n = (1 << bits_per_pixel);
spal = palette;
for(i = 0; i < n; i++) {
s->image_palette[i] = (0xff << 24) |
(spal[0] << 16) | (spal[1] << 8) | (spal[2]);
spal += 3;
}
for(; i < 256; i++)
s->image_palette[i] = (0xff << 24);
line = NULL;
}
/* now get the image data */ /* now get the image data */
s->f = f; s->f = f;
code_size = get_byte(f); code_size = get_byte(f);
GLZWDecodeInit(s, code_size); GLZWDecodeInit(s, code_size);
/* read all the image and transcode it to RGB24 (horrible) */ /* read all the image */
linesize = s->image_linesize; linesize = s->image_linesize;
ptr1 = s->image_buf + top * linesize + (left * 3); ptr1 = s->image_buf + top * linesize + (left * 3);
ptr = ptr1; ptr = ptr1;
pass = 0; pass = 0;
y1 = 0; y1 = 0;
for (y = 0; y < height; y++) { for (y = 0; y < height; y++) {
if (s->pix_fmt == PIX_FMT_RGB24) {
/* transcode to RGB24 */
GLZWDecode(s, line, width); GLZWDecode(s, line, width);
d = ptr; d = ptr;
sptr = line; sptr = line;
@ -328,6 +348,9 @@ static int gif_read_image(GifState *s)
d += 3; d += 3;
sptr++; sptr++;
} }
} else {
GLZWDecode(s, ptr, width);
}
if (is_interleaved) { if (is_interleaved) {
switch(pass) { switch(pass) {
default: default:
@ -504,6 +527,7 @@ static int gif_read_header(AVFormatContext * s1,
s->image_buf = av_malloc(s->screen_height * s->image_linesize); s->image_buf = av_malloc(s->screen_height * s->image_linesize);
if (!s->image_buf) if (!s->image_buf)
return -ENOMEM; return -ENOMEM;
s->pix_fmt = PIX_FMT_RGB24;
/* now we are ready: build format streams */ /* now we are ready: build format streams */
st = av_new_stream(s1, 0); st = av_new_stream(s1, 0);
if (!st) if (!st)
@ -559,12 +583,13 @@ static int gif_read(ByteIOContext *f,
return -1; return -1;
info->width = s->screen_width; info->width = s->screen_width;
info->height = s->screen_height; info->height = s->screen_height;
info->pix_fmt = PIX_FMT_RGB24; info->pix_fmt = PIX_FMT_PAL8;
ret = alloc_cb(opaque, info); ret = alloc_cb(opaque, info);
if (ret) if (ret)
return ret; return ret;
s->image_buf = info->pict.data[0]; s->image_buf = info->pict.data[0];
s->image_linesize = info->pict.linesize[0]; s->image_linesize = info->pict.linesize[0];
s->image_palette = (uint32_t *)info->pict.data[1];
if (gif_parse_next_image(s) < 0) if (gif_parse_next_image(s) < 0)
return -1; return -1;
@ -587,6 +612,6 @@ AVImageFormat gif_image_format = {
"gif", "gif",
gif_image_probe, gif_image_probe,
gif_read, gif_read,
(1 << PIX_FMT_RGB24), (1 << PIX_FMT_PAL8),
gif_write, gif_write,
}; };