1/* 2 * GIF encoder. 3 * Copyright (c) 2000 Fabrice Bellard 4 * Copyright (c) 2002 Francois Revol 5 * Copyright (c) 2006 Baptiste Coudurier 6 * 7 * This file is part of FFmpeg. 8 * 9 * FFmpeg is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * FFmpeg is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with FFmpeg; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24/* 25 * First version by Francois Revol revol@free.fr 26 * 27 * Features and limitations: 28 * - currently no compression is performed, 29 * in fact the size of the data is 9/8 the size of the image in 8bpp 30 * - uses only a global standard palette 31 * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS). 32 * 33 * Reference documents: 34 * http://www.goice.co.jp/member/mo/formats/gif.html 35 * http://astronomy.swin.edu.au/pbourke/dataformats/gif/ 36 * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt 37 * 38 * this url claims to have an LZW algorithm not covered by Unisys patent: 39 * http://www.msg.net/utility/whirlgif/gifencod.html 40 * could help reduce the size of the files _a lot_... 41 * some sites mentions an RLE type compression also. 42 */ 43 44#include "avcodec.h" 45#include "bytestream.h" 46#include "lzw.h" 47 48/* The GIF format uses reversed order for bitstreams... */ 49/* at least they don't use PDP_ENDIAN :) */ 50#define BITSTREAM_WRITER_LE 51 52#include "put_bits.h" 53 54typedef struct { 55 AVFrame picture; 56 LZWState *lzw; 57 uint8_t *buf; 58} GIFContext; 59 60/* GIF header */ 61static int gif_image_write_header(AVCodecContext *avctx, 62 uint8_t **bytestream, uint32_t *palette) 63{ 64 int i; 65 unsigned int v; 66 67 bytestream_put_buffer(bytestream, "GIF", 3); 68 bytestream_put_buffer(bytestream, "89a", 3); 69 bytestream_put_le16(bytestream, avctx->width); 70 bytestream_put_le16(bytestream, avctx->height); 71 72 bytestream_put_byte(bytestream, 0xf7); /* flags: global clut, 256 entries */ 73 bytestream_put_byte(bytestream, 0x1f); /* background color index */ 74 bytestream_put_byte(bytestream, 0); /* aspect ratio */ 75 76 /* the global palette */ 77 for(i=0;i<256;i++) { 78 v = palette[i]; 79 bytestream_put_be24(bytestream, v); 80 } 81 82 return 0; 83} 84 85static int gif_image_write_image(AVCodecContext *avctx, 86 uint8_t **bytestream, uint8_t *end, 87 const uint8_t *buf, int linesize) 88{ 89 GIFContext *s = avctx->priv_data; 90 int len, height; 91 const uint8_t *ptr; 92 /* image block */ 93 94 bytestream_put_byte(bytestream, 0x2c); 95 bytestream_put_le16(bytestream, 0); 96 bytestream_put_le16(bytestream, 0); 97 bytestream_put_le16(bytestream, avctx->width); 98 bytestream_put_le16(bytestream, avctx->height); 99 bytestream_put_byte(bytestream, 0x00); /* flags */ 100 /* no local clut */ 101 102 bytestream_put_byte(bytestream, 0x08); 103 104 ff_lzw_encode_init(s->lzw, s->buf, avctx->width*avctx->height, 105 12, FF_LZW_GIF, put_bits); 106 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); 113 114 ptr = s->buf; 115 while (len > 0) { 116 int size = FFMIN(255, len); 117 bytestream_put_byte(bytestream, size); 118 if (end - *bytestream < size) 119 return -1; 120 bytestream_put_buffer(bytestream, ptr, size); 121 ptr += size; 122 len -= size; 123 } 124 bytestream_put_byte(bytestream, 0x00); /* end of image block */ 125 bytestream_put_byte(bytestream, 0x3b); 126 return 0; 127} 128 129static av_cold int gif_encode_init(AVCodecContext *avctx) 130{ 131 GIFContext *s = avctx->priv_data; 132 133 avctx->coded_frame = &s->picture; 134 s->lzw = av_mallocz(ff_lzw_encode_state_size); 135 if (!s->lzw) 136 return AVERROR(ENOMEM); 137 s->buf = av_malloc(avctx->width*avctx->height*2); 138 if (!s->buf) 139 return AVERROR(ENOMEM); 140 return 0; 141} 142 143/* better than nothing gif encoder */ 144static int gif_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data) 145{ 146 GIFContext *s = avctx->priv_data; 147 AVFrame *pict = data; 148 AVFrame *const p = (AVFrame *)&s->picture; 149 uint8_t *outbuf_ptr = outbuf; 150 uint8_t *end = outbuf + buf_size; 151 152 *p = *pict; 153 p->pict_type = FF_I_TYPE; 154 p->key_frame = 1; 155 gif_image_write_header(avctx, &outbuf_ptr, (uint32_t *)pict->data[1]); 156 gif_image_write_image(avctx, &outbuf_ptr, end, pict->data[0], pict->linesize[0]); 157 return outbuf_ptr - outbuf; 158} 159 160static 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; 167} 168 169AVCodec gif_encoder = { 170 "gif", 171 AVMEDIA_TYPE_VIDEO, 172 CODEC_ID_GIF, 173 sizeof(GIFContext), 174 gif_encode_init, 175 gif_encode_frame, 176 gif_encode_close, 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}, 178 .long_name= NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"), 179}; 180