changeset 60:c89672a5f24e libavformat

added 8 bit palette support for non animated GIF
author bellard
date Sun, 09 Feb 2003 16:25:21 +0000
parents 05be5bf0025e
children 2aa6e12c82fc
files gif.c gifdec.c
diffstat 2 files changed, 74 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/gif.c	Sun Feb 09 16:22:06 2003 +0000
+++ b/gif.c	Sun Feb 09 16:25:21 2003 +0000
@@ -167,9 +167,11 @@
 /* !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 @@
     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 @@
 }
 
 /* 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 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 @@
         gif_put_bits_rev(&p, 9, 0x0100); /* clear code */
 
         for(i=0;i<GIF_CHUNKS;i++) {
-	    gif_put_bits_rev(&p, 9, gif_clut_index(NULL, ptr[0], ptr[1], ptr[2]));
-            ptr+=3;
+            if (pix_fmt == PIX_FMT_RGB24) {
+                v = gif_clut_index(ptr[0], ptr[1], ptr[2]);
+                ptr+=3;
+            } else {
+                v = *ptr++;
+            }
+            gif_put_bits_rev(&p, 9, v);
             if (--w == 0) {
                 w = width;
                 buf += linesize;
@@ -309,22 +324,12 @@
     /* XXX: is it allowed ? seems to work so far... */
     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);
     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 @@
     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 @@
 /* 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;
--- a/gifdec.c	Sun Feb 09 16:22:06 2003 +0000
+++ b/gifdec.c	Sun Feb 09 16:25:21 2003 +0000
@@ -39,6 +39,9 @@
     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 @@
 {
     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 @@
         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 @@
         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 @@
     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 @@
         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 @@
     "gif",
     gif_image_probe,
     gif_read,
-    (1 << PIX_FMT_RGB24),
+    (1 << PIX_FMT_PAL8),
     gif_write,
 };