Libav 0.7.1
|
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 } GIFContext; 00059 00060 /* GIF header */ 00061 static int gif_image_write_header(AVCodecContext *avctx, 00062 uint8_t **bytestream, uint32_t *palette) 00063 { 00064 int i; 00065 unsigned int v; 00066 00067 bytestream_put_buffer(bytestream, "GIF", 3); 00068 bytestream_put_buffer(bytestream, "89a", 3); 00069 bytestream_put_le16(bytestream, avctx->width); 00070 bytestream_put_le16(bytestream, avctx->height); 00071 00072 bytestream_put_byte(bytestream, 0xf7); /* flags: global clut, 256 entries */ 00073 bytestream_put_byte(bytestream, 0x1f); /* background color index */ 00074 bytestream_put_byte(bytestream, 0); /* aspect ratio */ 00075 00076 /* the global palette */ 00077 for(i=0;i<256;i++) { 00078 v = palette[i]; 00079 bytestream_put_be24(bytestream, v); 00080 } 00081 00082 return 0; 00083 } 00084 00085 static int gif_image_write_image(AVCodecContext *avctx, 00086 uint8_t **bytestream, uint8_t *end, 00087 const uint8_t *buf, int linesize) 00088 { 00089 GIFContext *s = avctx->priv_data; 00090 int len = 0, height; 00091 const uint8_t *ptr; 00092 /* image block */ 00093 00094 bytestream_put_byte(bytestream, 0x2c); 00095 bytestream_put_le16(bytestream, 0); 00096 bytestream_put_le16(bytestream, 0); 00097 bytestream_put_le16(bytestream, avctx->width); 00098 bytestream_put_le16(bytestream, avctx->height); 00099 bytestream_put_byte(bytestream, 0x00); /* flags */ 00100 /* no local clut */ 00101 00102 bytestream_put_byte(bytestream, 0x08); 00103 00104 ff_lzw_encode_init(s->lzw, s->buf, avctx->width*avctx->height, 00105 12, FF_LZW_GIF, put_bits); 00106 00107 ptr = buf; 00108 for (height = avctx->height; height--;) { 00109 len += ff_lzw_encode(s->lzw, ptr, avctx->width); 00110 ptr += linesize; 00111 } 00112 len += ff_lzw_encode_flush(s->lzw, flush_put_bits); 00113 00114 ptr = s->buf; 00115 while (len > 0) { 00116 int size = FFMIN(255, len); 00117 bytestream_put_byte(bytestream, size); 00118 if (end - *bytestream < size) 00119 return -1; 00120 bytestream_put_buffer(bytestream, ptr, size); 00121 ptr += size; 00122 len -= size; 00123 } 00124 bytestream_put_byte(bytestream, 0x00); /* end of image block */ 00125 bytestream_put_byte(bytestream, 0x3b); 00126 return 0; 00127 } 00128 00129 static av_cold int gif_encode_init(AVCodecContext *avctx) 00130 { 00131 GIFContext *s = avctx->priv_data; 00132 00133 avctx->coded_frame = &s->picture; 00134 s->lzw = av_mallocz(ff_lzw_encode_state_size); 00135 if (!s->lzw) 00136 return AVERROR(ENOMEM); 00137 s->buf = av_malloc(avctx->width*avctx->height*2); 00138 if (!s->buf) 00139 return AVERROR(ENOMEM); 00140 return 0; 00141 } 00142 00143 /* better than nothing gif encoder */ 00144 static int gif_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data) 00145 { 00146 GIFContext *s = avctx->priv_data; 00147 AVFrame *pict = data; 00148 AVFrame *const p = (AVFrame *)&s->picture; 00149 uint8_t *outbuf_ptr = outbuf; 00150 uint8_t *end = outbuf + buf_size; 00151 00152 *p = *pict; 00153 p->pict_type = AV_PICTURE_TYPE_I; 00154 p->key_frame = 1; 00155 gif_image_write_header(avctx, &outbuf_ptr, (uint32_t *)pict->data[1]); 00156 gif_image_write_image(avctx, &outbuf_ptr, end, pict->data[0], pict->linesize[0]); 00157 return outbuf_ptr - outbuf; 00158 } 00159 00160 static int gif_encode_close(AVCodecContext *avctx) 00161 { 00162 GIFContext *s = avctx->priv_data; 00163 00164 av_freep(&s->lzw); 00165 av_freep(&s->buf); 00166 return 0; 00167 } 00168 00169 AVCodec ff_gif_encoder = { 00170 "gif", 00171 AVMEDIA_TYPE_VIDEO, 00172 CODEC_ID_GIF, 00173 sizeof(GIFContext), 00174 gif_encode_init, 00175 gif_encode_frame, 00176 gif_encode_close, 00177 .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}, 00178 .long_name= NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"), 00179 };