1/* 2 * Animated GIF muxer 3 * Copyright (c) 2000 Fabrice Bellard 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/* 23 * First version by Francois Revol revol@free.fr 24 * 25 * Features and limitations: 26 * - currently no compression is performed, 27 * in fact the size of the data is 9/8 the size of the image in 8bpp 28 * - uses only a global standard palette 29 * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS). 30 * 31 * Reference documents: 32 * http://www.goice.co.jp/member/mo/formats/gif.html 33 * http://astronomy.swin.edu.au/pbourke/dataformats/gif/ 34 * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt 35 * 36 * this url claims to have an LZW algorithm not covered by Unisys patent: 37 * http://www.msg.net/utility/whirlgif/gifencod.html 38 * could help reduce the size of the files _a lot_... 39 * some sites mentions an RLE type compression also. 40 */ 41 42#include "avformat.h" 43 44/* The GIF format uses reversed order for bitstreams... */ 45/* at least they don't use PDP_ENDIAN :) */ 46#define BITSTREAM_WRITER_LE 47 48#include "libavcodec/bitstream.h" 49 50/* bitstream minipacket size */ 51#define GIF_CHUNKS 100 52 53/* slows down the decoding (and some browsers don't like it) */ 54/* update on the 'some browsers don't like it issue from above: this was probably due to missing 'Data Sub-block Terminator' (byte 19) in the app_header */ 55#define GIF_ADD_APP_HEADER // required to enable looping of animated gif 56 57typedef struct { 58 unsigned char r; 59 unsigned char g; 60 unsigned char b; 61} rgb_triplet; 62 63/* we use the standard 216 color palette */ 64 65/* this script was used to create the palette: 66 * for r in 00 33 66 99 cc ff; do for g in 00 33 66 99 cc ff; do echo -n " "; for b in 00 33 66 99 cc ff; do 67 * echo -n "{ 0x$r, 0x$g, 0x$b }, "; done; echo ""; done; done 68 */ 69 70static const rgb_triplet gif_clut[216] = { 71 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff }, 72 { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff }, 73 { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff }, 74 { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff }, 75 { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff }, 76 { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff }, 77 { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff }, 78 { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff }, 79 { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff }, 80 { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff }, 81 { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff }, 82 { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff }, 83 { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff }, 84 { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff }, 85 { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff }, 86 { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff }, 87 { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff }, 88 { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff }, 89 { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff }, 90 { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff }, 91 { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff }, 92 { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff }, 93 { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff }, 94 { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff }, 95 { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff }, 96 { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff }, 97 { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff }, 98 { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff }, 99 { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff }, 100 { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff }, 101 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff }, 102 { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff }, 103 { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff }, 104 { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff }, 105 { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff }, 106 { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff }, 107}; 108 109/* GIF header */ 110static int gif_image_write_header(ByteIOContext *pb, 111 int width, int height, int loop_count, 112 uint32_t *palette) 113{ 114 int i; 115 unsigned int v; 116 117 put_tag(pb, "GIF"); 118 put_tag(pb, "89a"); 119 put_le16(pb, width); 120 put_le16(pb, height); 121 122 put_byte(pb, 0xf7); /* flags: global clut, 256 entries */ 123 put_byte(pb, 0x1f); /* background color index */ 124 put_byte(pb, 0); /* aspect ratio */ 125 126 /* the global palette */ 127 if (!palette) { 128 put_buffer(pb, (const unsigned char *)gif_clut, 216*3); 129 for(i=0;i<((256-216)*3);i++) 130 put_byte(pb, 0); 131 } else { 132 for(i=0;i<256;i++) { 133 v = palette[i]; 134 put_byte(pb, (v >> 16) & 0xff); 135 put_byte(pb, (v >> 8) & 0xff); 136 put_byte(pb, (v) & 0xff); 137 } 138 } 139 140 /* update: this is the 'NETSCAPE EXTENSION' that allows for looped animated gif 141 see http://members.aol.com/royalef/gifabout.htm#net-extension 142 143 byte 1 : 33 (hex 0x21) GIF Extension code 144 byte 2 : 255 (hex 0xFF) Application Extension Label 145 byte 3 : 11 (hex (0x0B) Length of Application Block 146 (eleven bytes of data to follow) 147 bytes 4 to 11 : "NETSCAPE" 148 bytes 12 to 14 : "2.0" 149 byte 15 : 3 (hex 0x03) Length of Data Sub-Block 150 (three bytes of data to follow) 151 byte 16 : 1 (hex 0x01) 152 bytes 17 to 18 : 0 to 65535, an unsigned integer in 153 lo-hi byte format. This indicate the 154 number of iterations the loop should 155 be executed. 156 bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator 157 */ 158 159 /* application extension header */ 160#ifdef GIF_ADD_APP_HEADER 161 if (loop_count >= 0 && loop_count <= 65535) { 162 put_byte(pb, 0x21); 163 put_byte(pb, 0xff); 164 put_byte(pb, 0x0b); 165 put_tag(pb, "NETSCAPE2.0"); // bytes 4 to 14 166 put_byte(pb, 0x03); // byte 15 167 put_byte(pb, 0x01); // byte 16 168 put_le16(pb, (uint16_t)loop_count); 169 put_byte(pb, 0x00); // byte 19 170 } 171#endif 172 return 0; 173} 174 175/* this is maybe slow, but allows for extensions */ 176static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b) 177{ 178 return (((r) / 47) % 6) * 6 * 6 + (((g) / 47) % 6) * 6 + (((b) / 47) % 6); 179} 180 181 182static int gif_image_write_image(ByteIOContext *pb, 183 int x1, int y1, int width, int height, 184 const uint8_t *buf, int linesize, int pix_fmt) 185{ 186 PutBitContext p; 187 uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */ 188 int i, left, w, v; 189 const uint8_t *ptr; 190 /* image block */ 191 192 put_byte(pb, 0x2c); 193 put_le16(pb, x1); 194 put_le16(pb, y1); 195 put_le16(pb, width); 196 put_le16(pb, height); 197 put_byte(pb, 0x00); /* flags */ 198 /* no local clut */ 199 200 put_byte(pb, 0x08); 201 202 left= width * height; 203 204 init_put_bits(&p, buffer, 130); 205 206/* 207 * the thing here is the bitstream is written as little packets, with a size byte before 208 * but it's still the same bitstream between packets (no flush !) 209 */ 210 ptr = buf; 211 w = width; 212 while(left>0) { 213 214 put_bits(&p, 9, 0x0100); /* clear code */ 215 216 for(i=(left<GIF_CHUNKS)?left:GIF_CHUNKS;i;i--) { 217 if (pix_fmt == PIX_FMT_RGB24) { 218 v = gif_clut_index(ptr[0], ptr[1], ptr[2]); 219 ptr+=3; 220 } else { 221 v = *ptr++; 222 } 223 put_bits(&p, 9, v); 224 if (--w == 0) { 225 w = width; 226 buf += linesize; 227 ptr = buf; 228 } 229 } 230 231 if(left<=GIF_CHUNKS) { 232 put_bits(&p, 9, 0x101); /* end of stream */ 233 flush_put_bits(&p); 234 } 235 if(pbBufPtr(&p) - p.buf > 0) { 236 put_byte(pb, pbBufPtr(&p) - p.buf); /* byte count of the packet */ 237 put_buffer(pb, p.buf, pbBufPtr(&p) - p.buf); /* the actual buffer */ 238 p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */ 239 } 240 left-=GIF_CHUNKS; 241 } 242 put_byte(pb, 0x00); /* end of image block */ 243 244 return 0; 245} 246 247typedef struct { 248 int64_t time, file_time; 249 uint8_t buffer[100]; /* data chunks */ 250} GIFContext; 251 252static int gif_write_header(AVFormatContext *s) 253{ 254 GIFContext *gif = s->priv_data; 255 ByteIOContext *pb = s->pb; 256 AVCodecContext *enc, *video_enc; 257 int i, width, height, loop_count /*, rate*/; 258 259/* XXX: do we reject audio streams or just ignore them ? 260 if(s->nb_streams > 1) 261 return -1; 262*/ 263 gif->time = 0; 264 gif->file_time = 0; 265 266 video_enc = NULL; 267 for(i=0;i<s->nb_streams;i++) { 268 enc = s->streams[i]->codec; 269 if (enc->codec_type != CODEC_TYPE_AUDIO) 270 video_enc = enc; 271 } 272 273 if (!video_enc) { 274 av_free(gif); 275 return -1; 276 } else { 277 width = video_enc->width; 278 height = video_enc->height; 279 loop_count = s->loop_output; 280// rate = video_enc->time_base.den; 281 } 282 283 if (video_enc->pix_fmt != PIX_FMT_RGB24) { 284 av_log(s, AV_LOG_ERROR, "ERROR: gif only handles the rgb24 pixel format. Use -pix_fmt rgb24.\n"); 285 return AVERROR(EIO); 286 } 287 288 gif_image_write_header(pb, width, height, loop_count, NULL); 289 290 put_flush_packet(s->pb); 291 return 0; 292} 293 294static int gif_write_video(AVFormatContext *s, 295 AVCodecContext *enc, const uint8_t *buf, int size) 296{ 297 ByteIOContext *pb = s->pb; 298 GIFContext *gif = s->priv_data; 299 int jiffies; 300 int64_t delay; 301 302 /* graphic control extension block */ 303 put_byte(pb, 0x21); 304 put_byte(pb, 0xf9); 305 put_byte(pb, 0x04); /* block size */ 306 put_byte(pb, 0x04); /* flags */ 307 308 /* 1 jiffy is 1/70 s */ 309 /* the delay_time field indicates the number of jiffies - 1 */ 310 delay = gif->file_time - gif->time; 311 312 /* XXX: should use delay, in order to be more accurate */ 313 /* instead of using the same rounded value each time */ 314 /* XXX: don't even remember if I really use it for now */ 315 jiffies = (70*enc->time_base.num/enc->time_base.den) - 1; 316 317 put_le16(pb, jiffies); 318 319 put_byte(pb, 0x1f); /* transparent color index */ 320 put_byte(pb, 0x00); 321 322 gif_image_write_image(pb, 0, 0, enc->width, enc->height, 323 buf, enc->width * 3, PIX_FMT_RGB24); 324 325 put_flush_packet(s->pb); 326 return 0; 327} 328 329static int gif_write_packet(AVFormatContext *s, AVPacket *pkt) 330{ 331 AVCodecContext *codec = s->streams[pkt->stream_index]->codec; 332 if (codec->codec_type == CODEC_TYPE_AUDIO) 333 return 0; /* just ignore audio */ 334 else 335 return gif_write_video(s, codec, pkt->data, pkt->size); 336} 337 338static int gif_write_trailer(AVFormatContext *s) 339{ 340 ByteIOContext *pb = s->pb; 341 342 put_byte(pb, 0x3b); 343 put_flush_packet(s->pb); 344 return 0; 345} 346 347AVOutputFormat gif_muxer = { 348 "gif", 349 NULL_IF_CONFIG_SMALL("GIF Animation"), 350 "image/gif", 351 "gif", 352 sizeof(GIFContext), 353 CODEC_ID_NONE, 354 CODEC_ID_RAWVIDEO, 355 gif_write_header, 356 gif_write_packet, 357 gif_write_trailer, 358}; 359