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 "bitstream.h"
00044
00045
00046 #define GIF_CHUNKS 100
00047
00048
00049
00050 #define GIF_ADD_APP_HEADER // required to enable looping of animated gif
00051
00052 typedef struct {
00053 unsigned char r;
00054 unsigned char g;
00055 unsigned char b;
00056 } rgb_triplet;
00057
00058
00059
00060
00061
00062
00063
00064
00065 static const rgb_triplet gif_clut[216] = {
00066 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff },
00067 { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff },
00068 { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff },
00069 { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff },
00070 { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff },
00071 { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff },
00072 { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff },
00073 { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff },
00074 { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff },
00075 { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff },
00076 { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff },
00077 { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff },
00078 { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff },
00079 { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff },
00080 { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff },
00081 { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff },
00082 { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff },
00083 { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff },
00084 { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff },
00085 { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff },
00086 { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff },
00087 { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff },
00088 { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff },
00089 { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff },
00090 { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff },
00091 { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff },
00092 { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff },
00093 { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff },
00094 { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff },
00095 { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff },
00096 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff },
00097 { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff },
00098 { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff },
00099 { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff },
00100 { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff },
00101 { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff },
00102 };
00103
00104
00105
00106
00107
00108
00109 #ifdef ALT_BITSTREAM_WRITER
00110 # error no ALT_BITSTREAM_WRITER support for now
00111 #endif
00112
00113 static void gif_put_bits_rev(PutBitContext *s, int n, unsigned int value)
00114 {
00115 unsigned int bit_buf;
00116 int bit_cnt;
00117
00118
00119 assert(n == 32 || value < (1U << n));
00120
00121 bit_buf = s->bit_buf;
00122 bit_cnt = 32 - s->bit_left;
00123
00124
00125
00126 if (n < (32-bit_cnt)) {
00127 bit_buf |= value << (bit_cnt);
00128 bit_cnt+=n;
00129 } else {
00130 bit_buf |= value << (bit_cnt);
00131
00132 *s->buf_ptr = bit_buf & 0xff;
00133 s->buf_ptr[1] = (bit_buf >> 8) & 0xff;
00134 s->buf_ptr[2] = (bit_buf >> 16) & 0xff;
00135 s->buf_ptr[3] = (bit_buf >> 24) & 0xff;
00136
00137
00138 s->buf_ptr+=4;
00139 if (s->buf_ptr >= s->buf_end)
00140 abort();
00141
00142 bit_cnt=bit_cnt + n - 32;
00143 if (bit_cnt == 0) {
00144 bit_buf = 0;
00145 } else {
00146 bit_buf = value >> (n - bit_cnt);
00147 }
00148 }
00149
00150 s->bit_buf = bit_buf;
00151 s->bit_left = 32 - bit_cnt;
00152 }
00153
00154
00155 static void gif_flush_put_bits_rev(PutBitContext *s)
00156 {
00157 while (s->bit_left < 32) {
00158
00159 *s->buf_ptr++=s->bit_buf & 0xff;
00160 s->bit_buf>>=8;
00161 s->bit_left+=8;
00162 }
00163
00164 s->bit_left=32;
00165 s->bit_buf=0;
00166 }
00167
00168
00169
00170
00171 static int gif_image_write_header(ByteIOContext *pb,
00172 int width, int height, int loop_count,
00173 uint32_t *palette)
00174 {
00175 int i;
00176 unsigned int v;
00177
00178 put_tag(pb, "GIF");
00179 put_tag(pb, "89a");
00180 put_le16(pb, width);
00181 put_le16(pb, height);
00182
00183 put_byte(pb, 0xf7);
00184 put_byte(pb, 0x1f);
00185 put_byte(pb, 0);
00186
00187
00188 if (!palette) {
00189 put_buffer(pb, (const unsigned char *)gif_clut, 216*3);
00190 for(i=0;i<((256-216)*3);i++)
00191 put_byte(pb, 0);
00192 } else {
00193 for(i=0;i<256;i++) {
00194 v = palette[i];
00195 put_byte(pb, (v >> 16) & 0xff);
00196 put_byte(pb, (v >> 8) & 0xff);
00197 put_byte(pb, (v) & 0xff);
00198 }
00199 }
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 #ifdef GIF_ADD_APP_HEADER
00222 if (loop_count >= 0 && loop_count <= 65535) {
00223 put_byte(pb, 0x21);
00224 put_byte(pb, 0xff);
00225 put_byte(pb, 0x0b);
00226 put_tag(pb, "NETSCAPE2.0");
00227 put_byte(pb, 0x03);
00228 put_byte(pb, 0x01);
00229 put_le16(pb, (uint16_t)loop_count);
00230 put_byte(pb, 0x00);
00231 }
00232 #endif
00233 return 0;
00234 }
00235
00236
00237 static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b)
00238 {
00239 return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6));
00240 }
00241
00242
00243 static int gif_image_write_image(ByteIOContext *pb,
00244 int x1, int y1, int width, int height,
00245 const uint8_t *buf, int linesize, int pix_fmt)
00246 {
00247 PutBitContext p;
00248 uint8_t buffer[200];
00249 int i, left, w, v;
00250 const uint8_t *ptr;
00251
00252
00253 put_byte(pb, 0x2c);
00254 put_le16(pb, x1);
00255 put_le16(pb, y1);
00256 put_le16(pb, width);
00257 put_le16(pb, height);
00258 put_byte(pb, 0x00);
00259
00260
00261 put_byte(pb, 0x08);
00262
00263 left= width * height;
00264
00265 init_put_bits(&p, buffer, 130);
00266
00267
00268
00269
00270
00271 ptr = buf;
00272 w = width;
00273 while(left>0) {
00274
00275 gif_put_bits_rev(&p, 9, 0x0100);
00276
00277 for(i=(left<GIF_CHUNKS)?left:GIF_CHUNKS;i;i--) {
00278 if (pix_fmt == PIX_FMT_RGB24) {
00279 v = gif_clut_index(ptr[0], ptr[1], ptr[2]);
00280 ptr+=3;
00281 } else {
00282 v = *ptr++;
00283 }
00284 gif_put_bits_rev(&p, 9, v);
00285 if (--w == 0) {
00286 w = width;
00287 buf += linesize;
00288 ptr = buf;
00289 }
00290 }
00291
00292 if(left<=GIF_CHUNKS) {
00293 gif_put_bits_rev(&p, 9, 0x101);
00294 gif_flush_put_bits_rev(&p);
00295 }
00296 if(pbBufPtr(&p) - p.buf > 0) {
00297 put_byte(pb, pbBufPtr(&p) - p.buf);
00298 put_buffer(pb, p.buf, pbBufPtr(&p) - p.buf);
00299 p.buf_ptr = p.buf;
00300 }
00301 left-=GIF_CHUNKS;
00302 }
00303 put_byte(pb, 0x00);
00304
00305 return 0;
00306 }
00307
00308 typedef struct {
00309 int64_t time, file_time;
00310 uint8_t buffer[100];
00311 } GIFContext;
00312
00313 static int gif_write_header(AVFormatContext *s)
00314 {
00315 GIFContext *gif = s->priv_data;
00316 ByteIOContext *pb = s->pb;
00317 AVCodecContext *enc, *video_enc;
00318 int i, width, height, loop_count ;
00319
00320
00321
00322
00323
00324 gif->time = 0;
00325 gif->file_time = 0;
00326
00327 video_enc = NULL;
00328 for(i=0;i<s->nb_streams;i++) {
00329 enc = s->streams[i]->codec;
00330 if (enc->codec_type != CODEC_TYPE_AUDIO)
00331 video_enc = enc;
00332 }
00333
00334 if (!video_enc) {
00335 av_free(gif);
00336 return -1;
00337 } else {
00338 width = video_enc->width;
00339 height = video_enc->height;
00340 loop_count = s->loop_output;
00341
00342 }
00343
00344 if (video_enc->pix_fmt != PIX_FMT_RGB24) {
00345 av_log(s, AV_LOG_ERROR, "ERROR: gif only handles the rgb24 pixel format. Use -pix_fmt rgb24.\n");
00346 return AVERROR(EIO);
00347 }
00348
00349 gif_image_write_header(pb, width, height, loop_count, NULL);
00350
00351 put_flush_packet(s->pb);
00352 return 0;
00353 }
00354
00355 static int gif_write_video(AVFormatContext *s,
00356 AVCodecContext *enc, const uint8_t *buf, int size)
00357 {
00358 ByteIOContext *pb = s->pb;
00359 GIFContext *gif = s->priv_data;
00360 int jiffies;
00361 int64_t delay;
00362
00363
00364 put_byte(pb, 0x21);
00365 put_byte(pb, 0xf9);
00366 put_byte(pb, 0x04);
00367 put_byte(pb, 0x04);
00368
00369
00370
00371 delay = gif->file_time - gif->time;
00372
00373
00374
00375
00376 jiffies = (70*enc->time_base.num/enc->time_base.den) - 1;
00377
00378 put_le16(pb, jiffies);
00379
00380 put_byte(pb, 0x1f);
00381 put_byte(pb, 0x00);
00382
00383 gif_image_write_image(pb, 0, 0, enc->width, enc->height,
00384 buf, enc->width * 3, PIX_FMT_RGB24);
00385
00386 put_flush_packet(s->pb);
00387 return 0;
00388 }
00389
00390 static int gif_write_packet(AVFormatContext *s, AVPacket *pkt)
00391 {
00392 AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
00393 if (codec->codec_type == CODEC_TYPE_AUDIO)
00394 return 0;
00395 else
00396 return gif_write_video(s, codec, pkt->data, pkt->size);
00397 }
00398
00399 static int gif_write_trailer(AVFormatContext *s)
00400 {
00401 ByteIOContext *pb = s->pb;
00402
00403 put_byte(pb, 0x3b);
00404 put_flush_packet(s->pb);
00405 return 0;
00406 }
00407
00408 AVOutputFormat gif_muxer = {
00409 "gif",
00410 "GIF Animation",
00411 "image/gif",
00412 "gif",
00413 sizeof(GIFContext),
00414 CODEC_ID_NONE,
00415 CODEC_ID_RAWVIDEO,
00416 gif_write_header,
00417 gif_write_packet,
00418 gif_write_trailer,
00419 };