libavcodec/gif.c
Go to the documentation of this file.
00001 /*
00002  * GIF encoder.
00003  * Copyright (c) 2000 Fabrice Bellard
00004  * Copyright (c) 2002 Francois Revol
00005  * Copyright (c) 2006 Baptiste Coudurier
00006  *
00007  * This file is part of Libav.
00008  *
00009  * Libav is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * Libav is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with Libav; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00022  */
00023 
00024 /*
00025  * First version by Francois Revol revol@free.fr
00026  *
00027  * Features and limitations:
00028  * - currently no compression is performed,
00029  *   in fact the size of the data is 9/8 the size of the image in 8bpp
00030  * - uses only a global standard palette
00031  * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS).
00032  *
00033  * Reference documents:
00034  * http://www.goice.co.jp/member/mo/formats/gif.html
00035  * http://astronomy.swin.edu.au/pbourke/dataformats/gif/
00036  * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt
00037  *
00038  * this url claims to have an LZW algorithm not covered by Unisys patent:
00039  * http://www.msg.net/utility/whirlgif/gifencod.html
00040  * could help reduce the size of the files _a lot_...
00041  * some sites mentions an RLE type compression also.
00042  */
00043 
00044 #include "avcodec.h"
00045 #include "bytestream.h"
00046 #include "lzw.h"
00047 
00048 /* The GIF format uses reversed order for bitstreams... */
00049 /* at least they don't use PDP_ENDIAN :) */
00050 #define BITSTREAM_WRITER_LE
00051 
00052 #include "put_bits.h"
00053 
00054 typedef struct {
00055     AVFrame picture;
00056     LZWState *lzw;
00057     uint8_t *buf;
00058     int buf_size;
00059 } GIFContext;
00060 
00061 /* GIF header */
00062 static int gif_image_write_header(AVCodecContext *avctx,
00063                                   uint8_t **bytestream, uint32_t *palette)
00064 {
00065     int i;
00066     unsigned int v;
00067 
00068     bytestream_put_buffer(bytestream, "GIF", 3);
00069     bytestream_put_buffer(bytestream, "89a", 3);
00070     bytestream_put_le16(bytestream, avctx->width);
00071     bytestream_put_le16(bytestream, avctx->height);
00072 
00073     bytestream_put_byte(bytestream, 0xf7); /* flags: global clut, 256 entries */
00074     bytestream_put_byte(bytestream, 0x1f); /* background color index */
00075     bytestream_put_byte(bytestream, 0); /* aspect ratio */
00076 
00077     /* the global palette */
00078     for(i=0;i<256;i++) {
00079         v = palette[i];
00080         bytestream_put_be24(bytestream, v);
00081     }
00082 
00083     return 0;
00084 }
00085 
00086 static int gif_image_write_image(AVCodecContext *avctx,
00087                                  uint8_t **bytestream, uint8_t *end,
00088                                  const uint8_t *buf, int linesize)
00089 {
00090     GIFContext *s = avctx->priv_data;
00091     int len = 0, height;
00092     const uint8_t *ptr;
00093     /* image block */
00094 
00095     bytestream_put_byte(bytestream, 0x2c);
00096     bytestream_put_le16(bytestream, 0);
00097     bytestream_put_le16(bytestream, 0);
00098     bytestream_put_le16(bytestream, avctx->width);
00099     bytestream_put_le16(bytestream, avctx->height);
00100     bytestream_put_byte(bytestream, 0x00); /* flags */
00101     /* no local clut */
00102 
00103     bytestream_put_byte(bytestream, 0x08);
00104 
00105     ff_lzw_encode_init(s->lzw, s->buf, s->buf_size,
00106                        12, FF_LZW_GIF, put_bits);
00107 
00108     ptr = buf;
00109     for (height = avctx->height; height--;) {
00110         len += ff_lzw_encode(s->lzw, ptr, avctx->width);
00111         ptr += linesize;
00112     }
00113     len += ff_lzw_encode_flush(s->lzw, flush_put_bits);
00114 
00115     ptr = s->buf;
00116     while (len > 0) {
00117         int size = FFMIN(255, len);
00118         bytestream_put_byte(bytestream, size);
00119         if (end - *bytestream < size)
00120             return -1;
00121         bytestream_put_buffer(bytestream, ptr, size);
00122         ptr += size;
00123         len -= size;
00124     }
00125     bytestream_put_byte(bytestream, 0x00); /* end of image block */
00126     bytestream_put_byte(bytestream, 0x3b);
00127     return 0;
00128 }
00129 
00130 static av_cold int gif_encode_init(AVCodecContext *avctx)
00131 {
00132     GIFContext *s = avctx->priv_data;
00133 
00134     avctx->coded_frame = &s->picture;
00135     s->lzw = av_mallocz(ff_lzw_encode_state_size);
00136     if (!s->lzw)
00137         return AVERROR(ENOMEM);
00138     s->buf_size = avctx->width*avctx->height*2 + 1000;
00139     s->buf = av_malloc(s->buf_size);
00140     if (!s->buf)
00141          return AVERROR(ENOMEM);
00142     return 0;
00143 }
00144 
00145 /* better than nothing gif encoder */
00146 static int gif_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data)
00147 {
00148     GIFContext *s = avctx->priv_data;
00149     AVFrame *pict = data;
00150     AVFrame *const p = (AVFrame *)&s->picture;
00151     uint8_t *outbuf_ptr = outbuf;
00152     uint8_t *end = outbuf + buf_size;
00153 
00154     *p = *pict;
00155     p->pict_type = AV_PICTURE_TYPE_I;
00156     p->key_frame = 1;
00157     gif_image_write_header(avctx, &outbuf_ptr, (uint32_t *)pict->data[1]);
00158     gif_image_write_image(avctx, &outbuf_ptr, end, pict->data[0], pict->linesize[0]);
00159     return outbuf_ptr - outbuf;
00160 }
00161 
00162 static int gif_encode_close(AVCodecContext *avctx)
00163 {
00164     GIFContext *s = avctx->priv_data;
00165 
00166     av_freep(&s->lzw);
00167     av_freep(&s->buf);
00168     s->buf_size = 0;
00169     return 0;
00170 }
00171 
00172 AVCodec ff_gif_encoder = {
00173     .name           = "gif",
00174     .type           = AVMEDIA_TYPE_VIDEO,
00175     .id             = CODEC_ID_GIF,
00176     .priv_data_size = sizeof(GIFContext),
00177     .init           = gif_encode_init,
00178     .encode         = gif_encode_frame,
00179     .close          = gif_encode_close,
00180     .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},
00181     .long_name= NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
00182 };