diff options
author | Todd Kirby <doubleshot@pacbell.net> | 2005-06-18 05:52:24 +0400 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2005-06-18 05:52:24 +0400 |
commit | 8108551a5c4c4c9696582c73d000f94b12cd95a5 (patch) | |
tree | 2ec75876931d8d935492d183fbcac69db2fbe64d /libavformat | |
parent | bb628dae442f85fc8814d7c60c744a409fa001ab (diff) |
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
Originally committed as revision 4383 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/avformat.h | 8 | ||||
-rw-r--r-- | libavformat/gif.c | 47 |
2 files changed, 42 insertions, 13 deletions
diff --git a/libavformat/avformat.h b/libavformat/avformat.h index f81a4f37fa..705ff008b9 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -5,7 +5,7 @@ extern "C" { #endif -#define LIBAVFORMAT_BUILD 4626 +#define LIBAVFORMAT_BUILD 4627 #define LIBAVFORMAT_VERSION_INT FFMPEG_VERSION_INT #define LIBAVFORMAT_VERSION FFMPEG_VERSION @@ -327,6 +327,12 @@ typedef struct AVFormatContext { int packet_size; int preload; int max_delay; + +#define AVFMT_NOOUTPUTLOOP -1 +#define AVFMT_INFINITEOUTPUTLOOP 0 + /* number of times to loop output in formats that support it */ + int loop_output; + } AVFormatContext; typedef struct AVPacketList { diff --git a/libavformat/gif.c b/libavformat/gif.c index 0cb9b9a1ee..1248139d79 100644 --- a/libavformat/gif.c +++ b/libavformat/gif.c @@ -43,8 +43,9 @@ /* bitstream minipacket size */ #define GIF_CHUNKS 100 -/* slows down the decoding (and some browsers doesn't like it) */ -/* #define GIF_ADD_APP_HEADER */ +/* slows down the decoding (and some browsers don't like it) */ +/* 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 */ +#define GIF_ADD_APP_HEADER // required to enable looping of animated gif typedef struct { unsigned char r; @@ -169,7 +170,8 @@ static void gif_flush_put_bits_rev(PutBitContext *s) /* GIF header */ static int gif_image_write_header(ByteIOContext *pb, - int width, int height, uint32_t *palette) + int width, int height, int loop_count, + uint32_t *palette) { int i; unsigned int v; @@ -197,17 +199,37 @@ static int gif_image_write_header(ByteIOContext *pb, } } + /* update: this is the 'NETSCAPE EXTENSION' that allows for looped animated gif + see http://members.aol.com/royalef/gifabout.htm#net-extension + + byte 1 : 33 (hex 0x21) GIF Extension code + byte 2 : 255 (hex 0xFF) Application Extension Label + byte 3 : 11 (hex (0x0B) Length of Application Block + (eleven bytes of data to follow) + bytes 4 to 11 : "NETSCAPE" + bytes 12 to 14 : "2.0" + byte 15 : 3 (hex 0x03) Length of Data Sub-Block + (three bytes of data to follow) + byte 16 : 1 (hex 0x01) + bytes 17 to 18 : 0 to 65535, an unsigned integer in + lo-hi byte format. This indicate the + number of iterations the loop should + be executed. + bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator + */ + /* application extension header */ - /* XXX: not really sure what to put in here... */ #ifdef GIF_ADD_APP_HEADER + if (loop_count >= 0 && loop_count <= 65535) { put_byte(pb, 0x21); put_byte(pb, 0xff); put_byte(pb, 0x0b); - put_tag(pb, "NETSCAPE2.0"); - put_byte(pb, 0x03); - put_byte(pb, 0x01); - put_byte(pb, 0x00); - put_byte(pb, 0x00); + put_tag(pb, "NETSCAPE2.0"); // bytes 4 to 14 + put_byte(pb, 0x03); // byte 15 + put_byte(pb, 0x01); // byte 16 + put_le16(pb, (uint16_t)loop_count); + put_byte(pb, 0x00); // byte 19 + } #endif return 0; } @@ -294,7 +316,7 @@ static int gif_write_header(AVFormatContext *s) GIFContext *gif = s->priv_data; ByteIOContext *pb = &s->pb; AVCodecContext *enc, *video_enc; - int i, width, height/*, rate*/; + int i, width, height, loop_count /*, rate*/; /* XXX: do we reject audio streams or just ignore them ? if(s->nb_streams > 1) @@ -316,13 +338,14 @@ static int gif_write_header(AVFormatContext *s) } else { width = video_enc->width; height = video_enc->height; + loop_count = s->loop_output; // rate = video_enc->time_base.den; } /* XXX: is it allowed ? seems to work so far... */ video_enc->pix_fmt = PIX_FMT_RGB24; - gif_image_write_header(pb, width, height, NULL); + gif_image_write_header(pb, width, height, loop_count, NULL); put_flush_packet(&s->pb); return 0; @@ -384,7 +407,7 @@ static int gif_write_trailer(AVFormatContext *s) /* better than nothing gif image writer */ int gif_write(ByteIOContext *pb, AVImageInfo *info) { - gif_image_write_header(pb, info->width, info->height, + gif_image_write_header(pb, info->width, info->height, AVFMT_NOOUTPUTLOOP, (uint32_t *)info->pict.data[1]); gif_image_write_image(pb, 0, 0, info->width, info->height, info->pict.data[0], info->pict.linesize[0], |