00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "avformat.h"
00043 #include "libavutil/log.h"
00044 #include "libavutil/opt.h"
00045
00046
00047
00048 #define BITSTREAM_WRITER_LE
00049
00050 #include "libavcodec/put_bits.h"
00051
00052
00053 #define GIF_CHUNKS 100
00054
00055
00056
00057 #define GIF_ADD_APP_HEADER // required to enable looping of animated gif
00058
00059 typedef struct {
00060 unsigned char r;
00061 unsigned char g;
00062 unsigned char b;
00063 } rgb_triplet;
00064
00065
00066
00067
00068
00069
00070
00071
00072 static const rgb_triplet gif_clut[216] = {
00073 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff },
00074 { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff },
00075 { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff },
00076 { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff },
00077 { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff },
00078 { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff },
00079 { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff },
00080 { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff },
00081 { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff },
00082 { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff },
00083 { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff },
00084 { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff },
00085 { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff },
00086 { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff },
00087 { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff },
00088 { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff },
00089 { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff },
00090 { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff },
00091 { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff },
00092 { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff },
00093 { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff },
00094 { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff },
00095 { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff },
00096 { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff },
00097 { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff },
00098 { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff },
00099 { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff },
00100 { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff },
00101 { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff },
00102 { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff },
00103 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff },
00104 { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff },
00105 { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff },
00106 { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff },
00107 { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff },
00108 { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff },
00109 };
00110
00111
00112 static int gif_image_write_header(AVIOContext *pb,
00113 int width, int height, int loop_count,
00114 uint32_t *palette)
00115 {
00116 int i;
00117 unsigned int v;
00118
00119 avio_write(pb, "GIF", 3);
00120 avio_write(pb, "89a", 3);
00121 avio_wl16(pb, width);
00122 avio_wl16(pb, height);
00123
00124 avio_w8(pb, 0xf7);
00125 avio_w8(pb, 0x1f);
00126 avio_w8(pb, 0);
00127
00128
00129 if (!palette) {
00130 avio_write(pb, (const unsigned char *)gif_clut, 216*3);
00131 for(i=0;i<((256-216)*3);i++)
00132 avio_w8(pb, 0);
00133 } else {
00134 for(i=0;i<256;i++) {
00135 v = palette[i];
00136 avio_w8(pb, (v >> 16) & 0xff);
00137 avio_w8(pb, (v >> 8) & 0xff);
00138 avio_w8(pb, (v) & 0xff);
00139 }
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 #ifdef GIF_ADD_APP_HEADER
00163 if (loop_count >= 0 && loop_count <= 65535) {
00164 avio_w8(pb, 0x21);
00165 avio_w8(pb, 0xff);
00166 avio_w8(pb, 0x0b);
00167 avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1);
00168 avio_w8(pb, 0x03);
00169 avio_w8(pb, 0x01);
00170 avio_wl16(pb, (uint16_t)loop_count);
00171 avio_w8(pb, 0x00);
00172 }
00173 #endif
00174 return 0;
00175 }
00176
00177
00178 static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b)
00179 {
00180 return (((r) / 47) % 6) * 6 * 6 + (((g) / 47) % 6) * 6 + (((b) / 47) % 6);
00181 }
00182
00183
00184 static int gif_image_write_image(AVIOContext *pb,
00185 int x1, int y1, int width, int height,
00186 const uint8_t *buf, int linesize, int pix_fmt)
00187 {
00188 PutBitContext p;
00189 uint8_t buffer[200];
00190 int i, left, w, v;
00191 const uint8_t *ptr;
00192
00193
00194 avio_w8(pb, 0x2c);
00195 avio_wl16(pb, x1);
00196 avio_wl16(pb, y1);
00197 avio_wl16(pb, width);
00198 avio_wl16(pb, height);
00199 avio_w8(pb, 0x00);
00200
00201
00202 avio_w8(pb, 0x08);
00203
00204 left= width * height;
00205
00206 init_put_bits(&p, buffer, 130);
00207
00208
00209
00210
00211
00212 ptr = buf;
00213 w = width;
00214 while(left>0) {
00215
00216 put_bits(&p, 9, 0x0100);
00217
00218 for(i=(left<GIF_CHUNKS)?left:GIF_CHUNKS;i;i--) {
00219 if (pix_fmt == PIX_FMT_RGB24) {
00220 v = gif_clut_index(ptr[0], ptr[1], ptr[2]);
00221 ptr+=3;
00222 } else {
00223 v = *ptr++;
00224 }
00225 put_bits(&p, 9, v);
00226 if (--w == 0) {
00227 w = width;
00228 buf += linesize;
00229 ptr = buf;
00230 }
00231 }
00232
00233 if(left<=GIF_CHUNKS) {
00234 put_bits(&p, 9, 0x101);
00235 flush_put_bits(&p);
00236 }
00237 if(put_bits_ptr(&p) - p.buf > 0) {
00238 avio_w8(pb, put_bits_ptr(&p) - p.buf);
00239 avio_write(pb, p.buf, put_bits_ptr(&p) - p.buf);
00240 p.buf_ptr = p.buf;
00241 }
00242 left-=GIF_CHUNKS;
00243 }
00244 avio_w8(pb, 0x00);
00245
00246 return 0;
00247 }
00248
00249 typedef struct {
00250 AVClass *class;
00251 int64_t time, file_time;
00252 uint8_t buffer[100];
00253 int loop;
00254 } GIFContext;
00255
00256 static int gif_write_header(AVFormatContext *s)
00257 {
00258 GIFContext *gif = s->priv_data;
00259 AVIOContext *pb = s->pb;
00260 AVCodecContext *enc, *video_enc;
00261 int i, width, height ;
00262
00263
00264
00265
00266
00267 gif->time = 0;
00268 gif->file_time = 0;
00269
00270 video_enc = NULL;
00271 for(i=0;i<s->nb_streams;i++) {
00272 enc = s->streams[i]->codec;
00273 if (enc->codec_type != AVMEDIA_TYPE_AUDIO)
00274 video_enc = enc;
00275 }
00276
00277 if (!video_enc) {
00278 av_free(gif);
00279 return -1;
00280 } else {
00281 width = video_enc->width;
00282 height = video_enc->height;
00283
00284 }
00285
00286 if (video_enc->pix_fmt != PIX_FMT_RGB24) {
00287 av_log(s, AV_LOG_ERROR, "ERROR: gif only handles the rgb24 pixel format. Use -pix_fmt rgb24.\n");
00288 return AVERROR(EIO);
00289 }
00290
00291 #if FF_API_LOOP_OUTPUT
00292 if (s->loop_output)
00293 gif->loop = s->loop_output;
00294 #endif
00295
00296 gif_image_write_header(pb, width, height, gif->loop, NULL);
00297
00298 avio_flush(s->pb);
00299 return 0;
00300 }
00301
00302 static int gif_write_video(AVFormatContext *s,
00303 AVCodecContext *enc, const uint8_t *buf, int size)
00304 {
00305 AVIOContext *pb = s->pb;
00306 int jiffies;
00307
00308
00309 avio_w8(pb, 0x21);
00310 avio_w8(pb, 0xf9);
00311 avio_w8(pb, 0x04);
00312 avio_w8(pb, 0x04);
00313
00314
00315
00316
00317
00318
00319 jiffies = (70*enc->time_base.num/enc->time_base.den) - 1;
00320
00321 avio_wl16(pb, jiffies);
00322
00323 avio_w8(pb, 0x1f);
00324 avio_w8(pb, 0x00);
00325
00326 gif_image_write_image(pb, 0, 0, enc->width, enc->height,
00327 buf, enc->width * 3, PIX_FMT_RGB24);
00328
00329 avio_flush(s->pb);
00330 return 0;
00331 }
00332
00333 static int gif_write_packet(AVFormatContext *s, AVPacket *pkt)
00334 {
00335 AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
00336 if (codec->codec_type == AVMEDIA_TYPE_AUDIO)
00337 return 0;
00338 else
00339 return gif_write_video(s, codec, pkt->data, pkt->size);
00340 }
00341
00342 static int gif_write_trailer(AVFormatContext *s)
00343 {
00344 AVIOContext *pb = s->pb;
00345
00346 avio_w8(pb, 0x3b);
00347 avio_flush(s->pb);
00348 return 0;
00349 }
00350
00351 #define OFFSET(x) offsetof(GIFContext, x)
00352 #define ENC AV_OPT_FLAG_ENCODING_PARAM
00353 static const AVOption options[] = {
00354 { "loop", "Number of times to loop the output.", OFFSET(loop), AV_OPT_TYPE_INT, {0}, 0, 65535, ENC },
00355 { NULL },
00356 };
00357
00358 static const AVClass gif_muxer_class = {
00359 .class_name = "GIF muxer",
00360 .item_name = av_default_item_name,
00361 .version = LIBAVUTIL_VERSION_INT,
00362 .option = options,
00363 };
00364
00365 AVOutputFormat ff_gif_muxer = {
00366 .name = "gif",
00367 .long_name = NULL_IF_CONFIG_SMALL("GIF Animation"),
00368 .mime_type = "image/gif",
00369 .extensions = "gif",
00370 .priv_data_size = sizeof(GIFContext),
00371 .audio_codec = CODEC_ID_NONE,
00372 .video_codec = CODEC_ID_RAWVIDEO,
00373 .write_header = gif_write_header,
00374 .write_packet = gif_write_packet,
00375 .write_trailer = gif_write_trailer,
00376 .priv_class = &gif_muxer_class,
00377 };