diff --git a/libavformat/gif.c b/libavformat/gif.c index 20ae2a239b..44f3edcc89 100644 --- a/libavformat/gif.c +++ b/libavformat/gif.c @@ -167,9 +167,11 @@ static void gif_flush_put_bits_rev(PutBitContext *s) /* !RevPutBitContext */ /* 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; + unsigned int v; put_tag(pb, "GIF"); 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 */ /* the global palette */ - - put_buffer(pb, (unsigned char *)gif_clut, 216*3); - for(i=0;i<((256-216)*3);i++) - put_byte(pb, 0); + if (!palette) { + put_buffer(pb, (unsigned char *)gif_clut, 216*3); + for(i=0;i<((256-216)*3);i++) + 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 */ /* 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 */ -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)); } @@ -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, int x1, int y1, int width, int height, - uint8_t *buf, int linesize) + uint8_t *buf, int linesize, int pix_fmt) { PutBitContext p; UINT8 buffer[200]; /* 100 * 9 / 8 = 113 */ - int i, left, w; + int i, left, w, v; uint8_t *ptr; /* image block */ @@ -243,8 +253,13 @@ static int gif_image_write_image(ByteIOContext *pb, gif_put_bits_rev(&p, 9, 0x0100); /* clear code */ for(i=0;ipix_fmt = PIX_FMT_RGB24; - gif_image_write_header(pb, width, height); + gif_image_write_header(pb, width, height, NULL); put_flush_packet(&s->pb); 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, AVCodecContext *enc, UINT8 *buf, int size) { @@ -354,7 +359,7 @@ static int gif_write_video(AVFormatContext *s, put_byte(pb, 0x00); 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); return 0; @@ -382,9 +387,11 @@ static int gif_write_trailer(AVFormatContext *s) /* better than nothing gif image writer */ 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, - info->pict.data[0], info->pict.linesize[0]); + info->pict.data[0], info->pict.linesize[0], + PIX_FMT_PAL8); put_byte(pb, 0x3b); put_flush_packet(pb); return 0; diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c index 181d42ab8e..b827845fe9 100644 --- a/libavformat/gifdec.c +++ b/libavformat/gifdec.c @@ -39,6 +39,9 @@ typedef struct GifState { int color_resolution; uint8_t *image_buf; int image_linesize; + uint32_t *image_palette; + int pix_fmt; + /* after the frame is displayed, the disposal method is used */ int gce_disposal; /* delay during which the frame is shown */ @@ -274,7 +277,7 @@ static int gif_read_image(GifState *s) { ByteIOContext *f = s->f; 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; left = get_le16(f); @@ -294,6 +297,7 @@ static int gif_read_image(GifState *s) palette = s->local_palette; } else { palette = s->global_palette; + bits_per_pixel = s->bits_per_pixel; } /* verify that all the image is inside the screen dimensions */ @@ -301,32 +305,51 @@ static int gif_read_image(GifState *s) top + height > s->screen_height) return -EINVAL; - line = av_malloc(width); - if (!line) - return -ENOMEM; + /* build the palette */ + if (s->pix_fmt == PIX_FMT_RGB24) { + line = av_malloc(width); + if (!line) + 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 */ s->f = f; code_size = get_byte(f); GLZWDecodeInit(s, code_size); - /* read all the image and transcode it to RGB24 (horrible) */ + /* read all the image */ linesize = s->image_linesize; ptr1 = s->image_buf + top * linesize + (left * 3); ptr = ptr1; pass = 0; y1 = 0; for (y = 0; y < height; y++) { - GLZWDecode(s, line, width); - d = ptr; - sptr = line; - for(x = 0; x < width; x++) { - spal = palette + sptr[0] * 3; - d[0] = spal[0]; - d[1] = spal[1]; - d[2] = spal[2]; - d += 3; - sptr++; + if (s->pix_fmt == PIX_FMT_RGB24) { + /* transcode to RGB24 */ + GLZWDecode(s, line, width); + d = ptr; + sptr = line; + for(x = 0; x < width; x++) { + spal = palette + sptr[0] * 3; + d[0] = spal[0]; + d[1] = spal[1]; + d[2] = spal[2]; + d += 3; + sptr++; + } + } else { + GLZWDecode(s, ptr, width); } if (is_interleaved) { switch(pass) { @@ -504,6 +527,7 @@ static int gif_read_header(AVFormatContext * s1, s->image_buf = av_malloc(s->screen_height * s->image_linesize); if (!s->image_buf) return -ENOMEM; + s->pix_fmt = PIX_FMT_RGB24; /* now we are ready: build format streams */ st = av_new_stream(s1, 0); if (!st) @@ -559,13 +583,14 @@ static int gif_read(ByteIOContext *f, return -1; info->width = s->screen_width; info->height = s->screen_height; - info->pix_fmt = PIX_FMT_RGB24; + info->pix_fmt = PIX_FMT_PAL8; ret = alloc_cb(opaque, info); if (ret) return ret; s->image_buf = info->pict.data[0]; s->image_linesize = info->pict.linesize[0]; - + s->image_palette = (uint32_t *)info->pict.data[1]; + if (gif_parse_next_image(s) < 0) return -1; return 0; @@ -587,6 +612,6 @@ AVImageFormat gif_image_format = { "gif", gif_image_probe, gif_read, - (1 << PIX_FMT_RGB24), + (1 << PIX_FMT_PAL8), gif_write, };