comparison gif.c @ 10634:e15eb76d9e47 libavcodec

use lzw compression in gif encoder
author bcoudurier
date Thu, 03 Dec 2009 19:17:39 +0000
parents f164bb900d0b
children 8a4984c5cacc
comparison
equal deleted inserted replaced
10633:66242b8fbd32 10634:e15eb76d9e47
41 * some sites mentions an RLE type compression also. 41 * some sites mentions an RLE type compression also.
42 */ 42 */
43 43
44 #include "avcodec.h" 44 #include "avcodec.h"
45 #include "bytestream.h" 45 #include "bytestream.h"
46 #include "lzw.h"
46 47
47 /* The GIF format uses reversed order for bitstreams... */ 48 /* The GIF format uses reversed order for bitstreams... */
48 /* at least they don't use PDP_ENDIAN :) */ 49 /* at least they don't use PDP_ENDIAN :) */
49 #define BITSTREAM_WRITER_LE 50 #define BITSTREAM_WRITER_LE
50 51
51 #include "put_bits.h" 52 #include "put_bits.h"
52 53
53 /* bitstream minipacket size */
54 #define GIF_CHUNKS 100
55
56 typedef struct { 54 typedef struct {
57 AVFrame picture; 55 AVFrame picture;
56 LZWState *lzw;
57 uint8_t *buf;
58 } GIFContext; 58 } GIFContext;
59 59
60 /* GIF header */ 60 /* GIF header */
61 static int gif_image_write_header(AVCodecContext *avctx, 61 static int gif_image_write_header(AVCodecContext *avctx,
62 uint8_t **bytestream, uint32_t *palette) 62 uint8_t **bytestream, uint32_t *palette)
80 } 80 }
81 81
82 return 0; 82 return 0;
83 } 83 }
84 84
85 static int gif_image_write_image(AVCodecContext *avctx, uint8_t **bytestream, 85 static int gif_image_write_image(AVCodecContext *avctx,
86 uint8_t **bytestream, uint8_t *end,
86 const uint8_t *buf, int linesize) 87 const uint8_t *buf, int linesize)
87 { 88 {
88 PutBitContext p; 89 GIFContext *s = avctx->priv_data;
89 uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */ 90 int len, height;
90 int i, left, w;
91 const uint8_t *ptr; 91 const uint8_t *ptr;
92 /* image block */ 92 /* image block */
93 93
94 bytestream_put_byte(bytestream, 0x2c); 94 bytestream_put_byte(bytestream, 0x2c);
95 bytestream_put_le16(bytestream, 0); 95 bytestream_put_le16(bytestream, 0);
99 bytestream_put_byte(bytestream, 0x00); /* flags */ 99 bytestream_put_byte(bytestream, 0x00); /* flags */
100 /* no local clut */ 100 /* no local clut */
101 101
102 bytestream_put_byte(bytestream, 0x08); 102 bytestream_put_byte(bytestream, 0x08);
103 103
104 left= avctx->width * avctx->height; 104 ff_lzw_encode_init(s->lzw, s->buf, avctx->width*avctx->height,
105 12, FF_LZW_GIF, put_bits);
105 106
106 init_put_bits(&p, buffer, 130); 107 ptr = buf;
108 for (height = avctx->height; height--;) {
109 len += ff_lzw_encode(s->lzw, ptr, avctx->width);
110 ptr += linesize;
111 }
112 len += ff_lzw_encode_flush(s->lzw, flush_put_bits);
107 113
108 /* 114 ptr = s->buf;
109 * the thing here is the bitstream is written as little packets, with a size byte before 115 while (len > 0) {
110 * but it's still the same bitstream between packets (no flush !) 116 int size = FFMIN(255, len);
111 */ 117 bytestream_put_byte(bytestream, size);
112 ptr = buf; 118 if (end - *bytestream < size)
113 w = avctx->width; 119 return -1;
114 while(left>0) { 120 bytestream_put_buffer(bytestream, ptr, size);
115 121 ptr += size;
116 put_bits(&p, 9, 0x0100); /* clear code */ 122 len -= size;
117
118 for(i=(left<GIF_CHUNKS)?left:GIF_CHUNKS;i;i--) {
119 put_bits(&p, 9, *ptr++);
120 if (--w == 0) {
121 w = avctx->width;
122 buf += linesize;
123 ptr = buf;
124 }
125 }
126
127 if(left<=GIF_CHUNKS) {
128 put_bits(&p, 9, 0x101); /* end of stream */
129 flush_put_bits(&p);
130 }
131 if(put_bits_ptr(&p) - p.buf > 0) {
132 bytestream_put_byte(bytestream, put_bits_ptr(&p) - p.buf); /* byte count of the packet */
133 bytestream_put_buffer(bytestream, p.buf, put_bits_ptr(&p) - p.buf); /* the actual buffer */
134 p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */
135 }
136 left-=GIF_CHUNKS;
137 } 123 }
138 bytestream_put_byte(bytestream, 0x00); /* end of image block */ 124 bytestream_put_byte(bytestream, 0x00); /* end of image block */
139 bytestream_put_byte(bytestream, 0x3b); 125 bytestream_put_byte(bytestream, 0x3b);
140 return 0; 126 return 0;
141 } 127 }
143 static av_cold int gif_encode_init(AVCodecContext *avctx) 129 static av_cold int gif_encode_init(AVCodecContext *avctx)
144 { 130 {
145 GIFContext *s = avctx->priv_data; 131 GIFContext *s = avctx->priv_data;
146 132
147 avctx->coded_frame = &s->picture; 133 avctx->coded_frame = &s->picture;
134 s->lzw = av_mallocz(ff_lzw_encode_state_size);
135 if (!s->lzw)
136 return AVERROR_NOMEM;
137 s->buf = av_malloc(avctx->width*avctx->height*2);
138 if (!s->buf)
139 return AVERROR_NOMEM;
148 return 0; 140 return 0;
149 } 141 }
150 142
151 /* better than nothing gif encoder */ 143 /* better than nothing gif encoder */
152 static int gif_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data) 144 static int gif_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data)
153 { 145 {
154 GIFContext *s = avctx->priv_data; 146 GIFContext *s = avctx->priv_data;
155 AVFrame *pict = data; 147 AVFrame *pict = data;
156 AVFrame *const p = (AVFrame *)&s->picture; 148 AVFrame *const p = (AVFrame *)&s->picture;
157 uint8_t *outbuf_ptr = outbuf; 149 uint8_t *outbuf_ptr = outbuf;
150 uint8_t *end = outbuf + buf_size;
158 151
159 *p = *pict; 152 *p = *pict;
160 p->pict_type = FF_I_TYPE; 153 p->pict_type = FF_I_TYPE;
161 p->key_frame = 1; 154 p->key_frame = 1;
162 gif_image_write_header(avctx, &outbuf_ptr, (uint32_t *)pict->data[1]); 155 gif_image_write_header(avctx, &outbuf_ptr, (uint32_t *)pict->data[1]);
163 gif_image_write_image(avctx, &outbuf_ptr, pict->data[0], pict->linesize[0]); 156 gif_image_write_image(avctx, &outbuf_ptr, end, pict->data[0], pict->linesize[0]);
164 return outbuf_ptr - outbuf; 157 return outbuf_ptr - outbuf;
158 }
159
160 static int gif_encode_close(AVCodecContext *avctx)
161 {
162 GIFContext *s = avctx->priv_data;
163
164 av_freep(&s->lzw);
165 av_freep(&s->buf);
166 return 0;
165 } 167 }
166 168
167 AVCodec gif_encoder = { 169 AVCodec gif_encoder = {
168 "gif", 170 "gif",
169 CODEC_TYPE_VIDEO, 171 CODEC_TYPE_VIDEO,
170 CODEC_ID_GIF, 172 CODEC_ID_GIF,
171 sizeof(GIFContext), 173 sizeof(GIFContext),
172 gif_encode_init, 174 gif_encode_init,
173 gif_encode_frame, 175 gif_encode_frame,
174 NULL, //encode_end, 176 gif_encode_close,
175 .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}, 177 .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},
176 .long_name= NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"), 178 .long_name= NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
177 }; 179 };