[FFmpeg-devel] [PATCH 2/2] gif: use only one graphic control extension block per image.

Clément Bœsch ubitux at gmail.com
Thu Apr 18 19:05:33 CEST 2013


The encoder now doesn't produce any extra graphic control extension
block anymore. Only the image is encoded, and the muxer writing
its own GCE containing notably the timing information now includes the
optional palette transmitted through packet side data.

This commit avoid setting clashes between the two GCE, and reduce the
size of the generated file with pal8 output.
---
 libavcodec/gif.c  | 29 ++++++-----------------------
 libavformat/gif.c | 28 ++++++++++++++++++++++++++--
 2 files changed, 32 insertions(+), 25 deletions(-)

diff --git a/libavcodec/gif.c b/libavcodec/gif.c
index b35cfd1..0df302e 100644
--- a/libavcodec/gif.c
+++ b/libavcodec/gif.c
@@ -56,28 +56,6 @@ static int gif_image_write_image(AVCodecContext *avctx,
     int x_start = 0, y_start = 0;
     const uint8_t *ptr;
 
-    /* Mark one colour as transparent if the input palette contains at least
-     * one colour that is more than 50% transparent. */
-    if (palette) {
-        unsigned i, smallest_alpha = 0xFF, alpha_component = 0;
-        for (i = 0; i < AVPALETTE_COUNT; i++) {
-            const uint32_t v = palette[i];
-            if (v >> 24 < smallest_alpha) {
-                smallest_alpha = v >> 24;
-                alpha_component = i;
-            }
-        }
-        if (smallest_alpha < 128) {
-            bytestream_put_byte(bytestream, 0x21); /* Extension Introducer */
-            bytestream_put_byte(bytestream, 0xf9); /* Graphic Control Label */
-            bytestream_put_byte(bytestream, 0x04); /* block length */
-            bytestream_put_byte(bytestream, 0x01); /* Transparent Color Flag */
-            bytestream_put_le16(bytestream, 0x00); /* no delay */
-            bytestream_put_byte(bytestream, alpha_component);
-            bytestream_put_byte(bytestream, 0x00);
-        }
-    }
-
     /* Crop image */
     // TODO support with palette change
     if (s->last_frame && !palette) {
@@ -210,8 +188,13 @@ static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
     p->pict_type = AV_PICTURE_TYPE_I;
     p->key_frame = 1;
 
-    if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
+    if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
+        uint8_t *pal_exdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
+        if (!pal_exdata)
+            return AVERROR(ENOMEM);
+        memcpy(pal_exdata, p->data[1], AVPALETTE_SIZE);
         palette = (uint32_t*)p->data[1];
+    }
 
     gif_image_write_image(avctx, &outbuf_ptr, end, palette, pict->data[0], pict->linesize[0]);
     if (!s->last_frame) {
diff --git a/libavformat/gif.c b/libavformat/gif.c
index 3d86f23..f26d537 100644
--- a/libavformat/gif.c
+++ b/libavformat/gif.c
@@ -102,15 +102,39 @@ static int gif_write_header(AVFormatContext *s)
 
 static int gif_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
+    int size;
     AVCodecContext *enc = s->streams[pkt->stream_index]->codec;
     AVIOContext *pb = s->pb;
     int jiffies;
+    uint8_t flags = 0x4, transparent_color_index = 0x1f;
+    const uint32_t *palette;
+
+    /* Mark one colour as transparent if the input palette contains at least
+     * one colour that is more than 50% transparent. */
+    palette = (uint32_t*)av_packet_get_side_data(pkt, AV_PKT_DATA_PALETTE, &size);
+    if (palette && size != AVPALETTE_SIZE) {
+        av_log(s, AV_LOG_ERROR, "Invalid palette extradata\n");
+        return AVERROR_INVALIDDATA;
+    }
+    if (palette) {
+        unsigned i, smallest_alpha = 0xff;
+
+        for (i = 0; i < AVPALETTE_COUNT; i++) {
+            const uint32_t v = palette[i];
+            if (v >> 24 < smallest_alpha) {
+                smallest_alpha = v >> 24;
+                transparent_color_index = i;
+            }
+        }
+        if (smallest_alpha < 128)
+            flags |= 0x1; /* Transparent Color Flag */
+    }
 
     /* graphic control extension block */
     avio_w8(pb, 0x21);
     avio_w8(pb, 0xf9);
     avio_w8(pb, 0x04); /* block size */
-    avio_w8(pb, 0x04); /* flags */
+    avio_w8(pb, flags);
 
     /* 1 jiffy is 1/70 s */
     /* the delay_time field indicates the number of jiffies - 1 */
@@ -121,7 +145,7 @@ static int gif_write_packet(AVFormatContext *s, AVPacket *pkt)
 
     avio_wl16(pb, jiffies);
 
-    avio_w8(pb, 0x1f); /* transparent color index */
+    avio_w8(pb, transparent_color_index);
     avio_w8(pb, 0x00);
 
     avio_write(pb, pkt->data, pkt->size);
-- 
1.8.2.1



More information about the ffmpeg-devel mailing list