[SCM] libav/experimental: use lzw compression in gif encoder

siretart at users.alioth.debian.org siretart at users.alioth.debian.org
Sun Jun 30 16:55:28 UTC 2013


The following commit has been merged in the experimental branch:
commit f38e450746ca52c7965146ebdbcdd4cc30ad1fd9
Author: Baptiste Coudurier <baptiste.coudurier at gmail.com>
Date:   Thu Dec 3 19:17:39 2009 +0000

    use lzw compression in gif encoder
    
    Originally committed as revision 20723 to svn://svn.ffmpeg.org/ffmpeg/trunk

diff --git a/libavcodec/gif.c b/libavcodec/gif.c
index fae1366..8c7f72b 100644
--- a/libavcodec/gif.c
+++ b/libavcodec/gif.c
@@ -43,6 +43,7 @@
 
 #include "avcodec.h"
 #include "bytestream.h"
+#include "lzw.h"
 
 /* The GIF format uses reversed order for bitstreams... */
 /* at least they don't use PDP_ENDIAN :) */
@@ -50,11 +51,10 @@
 
 #include "put_bits.h"
 
-/* bitstream minipacket size */
-#define GIF_CHUNKS 100
-
 typedef struct {
     AVFrame picture;
+    LZWState *lzw;
+    uint8_t *buf;
 } GIFContext;
 
 /* GIF header */
@@ -82,12 +82,12 @@ static int gif_image_write_header(AVCodecContext *avctx,
     return 0;
 }
 
-static int gif_image_write_image(AVCodecContext *avctx, uint8_t **bytestream,
+static int gif_image_write_image(AVCodecContext *avctx,
+                                 uint8_t **bytestream, uint8_t *end,
                                  const uint8_t *buf, int linesize)
 {
-    PutBitContext p;
-    uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */
-    int i, left, w;
+    GIFContext *s = avctx->priv_data;
+    int len, height;
     const uint8_t *ptr;
     /* image block */
 
@@ -101,39 +101,25 @@ static int gif_image_write_image(AVCodecContext *avctx, uint8_t **bytestream,
 
     bytestream_put_byte(bytestream, 0x08);
 
-    left= avctx->width * avctx->height;
-
-    init_put_bits(&p, buffer, 130);
+    ff_lzw_encode_init(s->lzw, s->buf, avctx->width*avctx->height,
+                       12, FF_LZW_GIF, put_bits);
 
-/*
- * the thing here is the bitstream is written as little packets, with a size byte before
- * but it's still the same bitstream between packets (no flush !)
- */
     ptr = buf;
-    w = avctx->width;
-    while(left>0) {
-
-        put_bits(&p, 9, 0x0100); /* clear code */
-
-        for(i=(left<GIF_CHUNKS)?left:GIF_CHUNKS;i;i--) {
-            put_bits(&p, 9, *ptr++);
-            if (--w == 0) {
-                w = avctx->width;
-                buf += linesize;
-                ptr = buf;
-            }
-        }
-
-        if(left<=GIF_CHUNKS) {
-            put_bits(&p, 9, 0x101); /* end of stream */
-            flush_put_bits(&p);
-        }
-        if(put_bits_ptr(&p) - p.buf > 0) {
-            bytestream_put_byte(bytestream, put_bits_ptr(&p) - p.buf); /* byte count of the packet */
-            bytestream_put_buffer(bytestream, p.buf, put_bits_ptr(&p) - p.buf); /* the actual buffer */
-            p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */
-        }
-        left-=GIF_CHUNKS;
+    for (height = avctx->height; height--;) {
+        len += ff_lzw_encode(s->lzw, ptr, avctx->width);
+        ptr += linesize;
+    }
+    len += ff_lzw_encode_flush(s->lzw, flush_put_bits);
+
+    ptr = s->buf;
+    while (len > 0) {
+        int size = FFMIN(255, len);
+        bytestream_put_byte(bytestream, size);
+        if (end - *bytestream < size)
+            return -1;
+        bytestream_put_buffer(bytestream, ptr, size);
+        ptr += size;
+        len -= size;
     }
     bytestream_put_byte(bytestream, 0x00); /* end of image block */
     bytestream_put_byte(bytestream, 0x3b);
@@ -145,6 +131,12 @@ static av_cold int gif_encode_init(AVCodecContext *avctx)
     GIFContext *s = avctx->priv_data;
 
     avctx->coded_frame = &s->picture;
+    s->lzw = av_mallocz(ff_lzw_encode_state_size);
+    if (!s->lzw)
+        return AVERROR_NOMEM;
+    s->buf = av_malloc(avctx->width*avctx->height*2);
+    if (!s->buf)
+         return AVERROR_NOMEM;
     return 0;
 }
 
@@ -155,15 +147,25 @@ static int gif_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int bu
     AVFrame *pict = data;
     AVFrame *const p = (AVFrame *)&s->picture;
     uint8_t *outbuf_ptr = outbuf;
+    uint8_t *end = outbuf + buf_size;
 
     *p = *pict;
     p->pict_type = FF_I_TYPE;
     p->key_frame = 1;
     gif_image_write_header(avctx, &outbuf_ptr, (uint32_t *)pict->data[1]);
-    gif_image_write_image(avctx, &outbuf_ptr, pict->data[0], pict->linesize[0]);
+    gif_image_write_image(avctx, &outbuf_ptr, end, pict->data[0], pict->linesize[0]);
     return outbuf_ptr - outbuf;
 }
 
+static int gif_encode_close(AVCodecContext *avctx)
+{
+    GIFContext *s = avctx->priv_data;
+
+    av_freep(&s->lzw);
+    av_freep(&s->buf);
+    return 0;
+}
+
 AVCodec gif_encoder = {
     "gif",
     CODEC_TYPE_VIDEO,
@@ -171,7 +173,7 @@ AVCodec gif_encoder = {
     sizeof(GIFContext),
     gif_encode_init,
     gif_encode_frame,
-    NULL, //encode_end,
+    gif_encode_close,
     .pix_fmts= (const enum PixelFormat[]){PIX_FMT_RGB8, PIX_FMT_BGR8, PIX_FMT_RGB4_BYTE, PIX_FMT_BGR4_BYTE, PIX_FMT_GRAY8, PIX_FMT_PAL8, PIX_FMT_NONE},
     .long_name= NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
 };
diff --git a/libavcodec/lzw.h b/libavcodec/lzw.h
index 601d01f..bebb335 100644
--- a/libavcodec/lzw.h
+++ b/libavcodec/lzw.h
@@ -32,6 +32,8 @@
 
 #include "get_bits.h"
 
+struct PutBitContext;
+
 enum FF_LZW_MODES{
     FF_LZW_GIF,
     FF_LZW_TIFF
@@ -52,8 +54,11 @@ void ff_lzw_decode_tail(LZWState *lzw);
 struct LZWEncodeState;
 extern const int ff_lzw_encode_state_size;
 
-void ff_lzw_encode_init(struct LZWEncodeState * s, uint8_t * outbuf, int outsize, int maxbits);
+void ff_lzw_encode_init(struct LZWEncodeState *s, uint8_t *outbuf, int outsize,
+                        int maxbits, enum FF_LZW_MODES mode,
+                        void (*lzw_put_bits)(struct PutBitContext *, int, unsigned int));
 int ff_lzw_encode(struct LZWEncodeState * s, const uint8_t * inbuf, int insize);
-int ff_lzw_encode_flush(struct LZWEncodeState * s);
+int ff_lzw_encode_flush(struct LZWEncodeState *s,
+                        void (*lzw_flush_put_bits)(struct PutBitContext *));
 
 #endif /* AVCODEC_LZW_H */
diff --git a/libavcodec/lzwenc.c b/libavcodec/lzwenc.c
index f3f6683..f8cf491 100644
--- a/libavcodec/lzwenc.c
+++ b/libavcodec/lzwenc.c
@@ -58,6 +58,8 @@ typedef struct LZWEncodeState {
     int maxcode;             ///< Max value of code
     int output_bytes;        ///< Number of written bytes
     int last_code;           ///< Value of last output code or LZW_PREFIX_EMPTY
+    enum FF_LZW_MODES mode;  ///< TIFF or GIF
+    void (*put_bits)(PutBitContext *, int, unsigned); ///< GIF is LE while TIFF is BE
 }LZWEncodeState;
 
 
@@ -110,7 +112,7 @@ static inline int hashOffset(const int head)
 static inline void writeCode(LZWEncodeState * s, int c)
 {
     assert(0 <= c && c < 1 << s->bits);
-    put_bits(&s->pb, s->bits, c);
+    s->put_bits(&s->pb, s->bits, c);
 }
 
 
@@ -151,7 +153,7 @@ static inline void addCode(LZWEncodeState * s, uint8_t c, int hash_prefix, int h
 
     s->tabsize++;
 
-    if (s->tabsize >= 1 << s->bits)
+    if (s->tabsize >= (1 << s->bits) + (s->mode == FF_LZW_GIF))
         s->bits++;
 }
 
@@ -196,7 +198,9 @@ static int writtenBytes(LZWEncodeState *s){
  * @param outsize Size of output buffer
  * @param maxbits Maximum length of code
  */
-void ff_lzw_encode_init(LZWEncodeState * s, uint8_t * outbuf, int outsize, int maxbits)
+void ff_lzw_encode_init(LZWEncodeState *s, uint8_t *outbuf, int outsize,
+                        int maxbits, enum FF_LZW_MODES mode,
+                        void (*lzw_put_bits)(PutBitContext *, int, unsigned))
 {
     s->clear_code = 256;
     s->end_code = 257;
@@ -208,6 +212,8 @@ void ff_lzw_encode_init(LZWEncodeState * s, uint8_t * outbuf, int outsize, int m
     s->output_bytes = 0;
     s->last_code = LZW_PREFIX_EMPTY;
     s->bits = 9;
+    s->mode = mode;
+    s->put_bits = lzw_put_bits;
 }
 
 /**
@@ -250,12 +256,13 @@ int ff_lzw_encode(LZWEncodeState * s, const uint8_t * inbuf, int insize)
  * @param s LZW state
  * @return Number of bytes written or -1 on error
  */
-int ff_lzw_encode_flush(LZWEncodeState * s)
+int ff_lzw_encode_flush(LZWEncodeState *s,
+                        void (*lzw_flush_put_bits)(PutBitContext *))
 {
     if (s->last_code != -1)
         writeCode(s, s->last_code);
     writeCode(s, s->end_code);
-    flush_put_bits(&s->pb);
+    lzw_flush_put_bits(&s->pb);
     s->last_code = -1;
 
     return writtenBytes(s);
diff --git a/libavcodec/tiffenc.c b/libavcodec/tiffenc.c
index 7af3914..1d6b5b0 100644
--- a/libavcodec/tiffenc.c
+++ b/libavcodec/tiffenc.c
@@ -32,6 +32,7 @@
 #include "tiff.h"
 #include "rle.h"
 #include "lzw.h"
+#include "put_bits.h"
 
 #define TIFF_MAX_ENTRY 32
 
@@ -352,7 +353,8 @@ static int encode_frame(AVCodecContext * avctx, unsigned char *buf,
         for (i = 0; i < s->height; i++) {
             if (strip_sizes[i / s->rps] == 0) {
                 if(s->compr == TIFF_LZW){
-                    ff_lzw_encode_init(s->lzws, ptr, s->buf_size - (*s->buf - s->buf_start), 12);
+                    ff_lzw_encode_init(s->lzws, ptr, s->buf_size - (*s->buf - s->buf_start),
+                                       12, FF_LZW_TIFF, put_bits);
                 }
                 strip_offsets[i / s->rps] = ptr - buf;
             }
@@ -372,7 +374,7 @@ static int encode_frame(AVCodecContext * avctx, unsigned char *buf,
             ptr += n;
             if(s->compr == TIFF_LZW && (i==s->height-1 || i%s->rps == s->rps-1)){
                 int ret;
-                ret = ff_lzw_encode_flush(s->lzws);
+                ret = ff_lzw_encode_flush(s->lzws, flush_put_bits);
                 strip_sizes[(i / s->rps )] += ret ;
                 ptr += ret;
             }

-- 
Libav/FFmpeg packaging



More information about the pkg-multimedia-commits mailing list