Mercurial > libavformat.hg
comparison gif.c @ 790:80aec794c2ed libavformat
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
author | michael |
---|---|
date | Sat, 18 Jun 2005 01:52:24 +0000 |
parents | af4e24d6310c |
children | feca73904e67 |
comparison
equal
deleted
inserted
replaced
789:411b75055a43 | 790:80aec794c2ed |
---|---|
41 #include "bitstream.h" | 41 #include "bitstream.h" |
42 | 42 |
43 /* bitstream minipacket size */ | 43 /* bitstream minipacket size */ |
44 #define GIF_CHUNKS 100 | 44 #define GIF_CHUNKS 100 |
45 | 45 |
46 /* slows down the decoding (and some browsers doesn't like it) */ | 46 /* slows down the decoding (and some browsers don't like it) */ |
47 /* #define GIF_ADD_APP_HEADER */ | 47 /* 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 */ |
48 #define GIF_ADD_APP_HEADER // required to enable looping of animated gif | |
48 | 49 |
49 typedef struct { | 50 typedef struct { |
50 unsigned char r; | 51 unsigned char r; |
51 unsigned char g; | 52 unsigned char g; |
52 unsigned char b; | 53 unsigned char b; |
167 | 168 |
168 /* !RevPutBitContext */ | 169 /* !RevPutBitContext */ |
169 | 170 |
170 /* GIF header */ | 171 /* GIF header */ |
171 static int gif_image_write_header(ByteIOContext *pb, | 172 static int gif_image_write_header(ByteIOContext *pb, |
172 int width, int height, uint32_t *palette) | 173 int width, int height, int loop_count, |
174 uint32_t *palette) | |
173 { | 175 { |
174 int i; | 176 int i; |
175 unsigned int v; | 177 unsigned int v; |
176 | 178 |
177 put_tag(pb, "GIF"); | 179 put_tag(pb, "GIF"); |
195 put_byte(pb, (v >> 8) & 0xff); | 197 put_byte(pb, (v >> 8) & 0xff); |
196 put_byte(pb, (v) & 0xff); | 198 put_byte(pb, (v) & 0xff); |
197 } | 199 } |
198 } | 200 } |
199 | 201 |
202 /* update: this is the 'NETSCAPE EXTENSION' that allows for looped animated gif | |
203 see http://members.aol.com/royalef/gifabout.htm#net-extension | |
204 | |
205 byte 1 : 33 (hex 0x21) GIF Extension code | |
206 byte 2 : 255 (hex 0xFF) Application Extension Label | |
207 byte 3 : 11 (hex (0x0B) Length of Application Block | |
208 (eleven bytes of data to follow) | |
209 bytes 4 to 11 : "NETSCAPE" | |
210 bytes 12 to 14 : "2.0" | |
211 byte 15 : 3 (hex 0x03) Length of Data Sub-Block | |
212 (three bytes of data to follow) | |
213 byte 16 : 1 (hex 0x01) | |
214 bytes 17 to 18 : 0 to 65535, an unsigned integer in | |
215 lo-hi byte format. This indicate the | |
216 number of iterations the loop should | |
217 be executed. | |
218 bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator | |
219 */ | |
220 | |
200 /* application extension header */ | 221 /* application extension header */ |
201 /* XXX: not really sure what to put in here... */ | |
202 #ifdef GIF_ADD_APP_HEADER | 222 #ifdef GIF_ADD_APP_HEADER |
223 if (loop_count >= 0 && loop_count <= 65535) { | |
203 put_byte(pb, 0x21); | 224 put_byte(pb, 0x21); |
204 put_byte(pb, 0xff); | 225 put_byte(pb, 0xff); |
205 put_byte(pb, 0x0b); | 226 put_byte(pb, 0x0b); |
206 put_tag(pb, "NETSCAPE2.0"); | 227 put_tag(pb, "NETSCAPE2.0"); // bytes 4 to 14 |
207 put_byte(pb, 0x03); | 228 put_byte(pb, 0x03); // byte 15 |
208 put_byte(pb, 0x01); | 229 put_byte(pb, 0x01); // byte 16 |
209 put_byte(pb, 0x00); | 230 put_le16(pb, (uint16_t)loop_count); |
210 put_byte(pb, 0x00); | 231 put_byte(pb, 0x00); // byte 19 |
232 } | |
211 #endif | 233 #endif |
212 return 0; | 234 return 0; |
213 } | 235 } |
214 | 236 |
215 /* this is maybe slow, but allows for extensions */ | 237 /* this is maybe slow, but allows for extensions */ |
292 static int gif_write_header(AVFormatContext *s) | 314 static int gif_write_header(AVFormatContext *s) |
293 { | 315 { |
294 GIFContext *gif = s->priv_data; | 316 GIFContext *gif = s->priv_data; |
295 ByteIOContext *pb = &s->pb; | 317 ByteIOContext *pb = &s->pb; |
296 AVCodecContext *enc, *video_enc; | 318 AVCodecContext *enc, *video_enc; |
297 int i, width, height/*, rate*/; | 319 int i, width, height, loop_count /*, rate*/; |
298 | 320 |
299 /* XXX: do we reject audio streams or just ignore them ? | 321 /* XXX: do we reject audio streams or just ignore them ? |
300 if(s->nb_streams > 1) | 322 if(s->nb_streams > 1) |
301 return -1; | 323 return -1; |
302 */ | 324 */ |
314 av_free(gif); | 336 av_free(gif); |
315 return -1; | 337 return -1; |
316 } else { | 338 } else { |
317 width = video_enc->width; | 339 width = video_enc->width; |
318 height = video_enc->height; | 340 height = video_enc->height; |
341 loop_count = s->loop_output; | |
319 // rate = video_enc->time_base.den; | 342 // rate = video_enc->time_base.den; |
320 } | 343 } |
321 | 344 |
322 /* XXX: is it allowed ? seems to work so far... */ | 345 /* XXX: is it allowed ? seems to work so far... */ |
323 video_enc->pix_fmt = PIX_FMT_RGB24; | 346 video_enc->pix_fmt = PIX_FMT_RGB24; |
324 | 347 |
325 gif_image_write_header(pb, width, height, NULL); | 348 gif_image_write_header(pb, width, height, loop_count, NULL); |
326 | 349 |
327 put_flush_packet(&s->pb); | 350 put_flush_packet(&s->pb); |
328 return 0; | 351 return 0; |
329 } | 352 } |
330 | 353 |
382 } | 405 } |
383 | 406 |
384 /* better than nothing gif image writer */ | 407 /* better than nothing gif image writer */ |
385 int gif_write(ByteIOContext *pb, AVImageInfo *info) | 408 int gif_write(ByteIOContext *pb, AVImageInfo *info) |
386 { | 409 { |
387 gif_image_write_header(pb, info->width, info->height, | 410 gif_image_write_header(pb, info->width, info->height, AVFMT_NOOUTPUTLOOP, |
388 (uint32_t *)info->pict.data[1]); | 411 (uint32_t *)info->pict.data[1]); |
389 gif_image_write_image(pb, 0, 0, info->width, info->height, | 412 gif_image_write_image(pb, 0, 0, info->width, info->height, |
390 info->pict.data[0], info->pict.linesize[0], | 413 info->pict.data[0], info->pict.linesize[0], |
391 PIX_FMT_PAL8); | 414 PIX_FMT_PAL8); |
392 put_byte(pb, 0x3b); | 415 put_byte(pb, 0x3b); |