From ba19f84810d3393b4a00aacd3b61a2803d108849 Mon Sep 17 00:00:00 2001 From: Fabrice Bellard Date: Mon, 3 Feb 2003 22:52:38 +0000 Subject: added primitive image GIF encoder based on animated gif encoder Originally committed as revision 1540 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/gif.c | 206 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 121 insertions(+), 85 deletions(-) (limited to 'libavformat/gif.c') diff --git a/libavformat/gif.c b/libavformat/gif.c index 5791502fda..20ae2a239b 100644 --- a/libavformat/gif.c +++ b/libavformat/gif.c @@ -166,45 +166,10 @@ static void gif_flush_put_bits_rev(PutBitContext *s) /* !RevPutBitContext */ -typedef struct { - UINT8 buffer[100]; /* data chunks */ - INT64 time, file_time; -} GIFContext; - -static int gif_write_header(AVFormatContext *s) +/* GIF header */ +static int gif_image_write_header(ByteIOContext *pb, int width, int height) { - GIFContext *gif = s->priv_data; - ByteIOContext *pb = &s->pb; - AVCodecContext *enc, *video_enc; - int i, width, height, rate; - -/* XXX: do we reject audio streams or just ignore them ? - if(s->nb_streams > 1) - return -1; -*/ - gif->time = 0; - gif->file_time = 0; - - video_enc = NULL; - for(i=0;inb_streams;i++) { - enc = &s->streams[i]->codec; - if (enc->codec_type != CODEC_TYPE_AUDIO) - video_enc = enc; - } - - if (!video_enc) { - av_free(gif); - return -1; - } else { - width = video_enc->width; - height = video_enc->height; - rate = video_enc->frame_rate; - } - - /* XXX: is it allowed ? seems to work so far... */ - video_enc->pix_fmt = PIX_FMT_RGB24; - - /* GIF header */ + int i; put_tag(pb, "GIF"); put_tag(pb, "89a"); @@ -233,8 +198,6 @@ static int gif_write_header(AVFormatContext *s) put_byte(pb, 0x00); put_byte(pb, 0x00); #endif - - put_flush_packet(&s->pb); return 0; } @@ -244,60 +207,28 @@ static inline unsigned char gif_clut_index(rgb_triplet *clut, UINT8 r, UINT8 g, return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6)); } -/* chunk writer callback */ -/* !!! XXX:deprecated -static void gif_put_chunk(void *pbctx, UINT8 *buffer, int count) -{ - ByteIOContext *pb = (ByteIOContext *)pbctx; - put_byte(pb, (UINT8)count); - put_buffer(pb, buffer, count); -} -*/ -static int gif_write_video(AVFormatContext *s, - AVCodecContext *enc, UINT8 *buf, int size) +static int gif_image_write_image(ByteIOContext *pb, + int x1, int y1, int width, int height, + uint8_t *buf, int linesize) { - ByteIOContext *pb = &s->pb; - GIFContext *gif = s->priv_data; - int i, left, jiffies; - INT64 delay; PutBitContext p; UINT8 buffer[200]; /* 100 * 9 / 8 = 113 */ - - - /* graphic control extension block */ - put_byte(pb, 0x21); - put_byte(pb, 0xf9); - put_byte(pb, 0x04); /* block size */ - put_byte(pb, 0x04); /* flags */ - - /* 1 jiffy is 1/70 s */ - /* the delay_time field indicates the number of jiffies - 1 */ - delay = gif->file_time - gif->time; - - /* XXX: should use delay, in order to be more accurate */ - /* instead of using the same rounded value each time */ - /* XXX: don't even remember if I really use it for now */ - jiffies = (70*FRAME_RATE_BASE/enc->frame_rate) - 1; - - put_le16(pb, jiffies); - - put_byte(pb, 0x1f); /* transparent color index */ - put_byte(pb, 0x00); - + int i, left, w; + uint8_t *ptr; /* image block */ put_byte(pb, 0x2c); - put_le16(pb, 0); - put_le16(pb, 0); - put_le16(pb, enc->width); - put_le16(pb, enc->height); + put_le16(pb, x1); + put_le16(pb, y1); + put_le16(pb, width); + put_le16(pb, height); put_byte(pb, 0x00); /* flags */ /* no local clut */ put_byte(pb, 0x08); - left=size/3; + left= width * height; init_put_bits(&p, buffer, 130, NULL, NULL); @@ -305,14 +236,20 @@ static int gif_write_video(AVFormatContext *s, * the thing here is the bitstream is written as little packets, with a size byte before * but it's still the same bitstream between packets (no flush !) */ - + ptr = buf; + w = width; while(left>0) { gif_put_bits_rev(&p, 9, 0x0100); /* clear code */ for(i=0;ipriv_data; + ByteIOContext *pb = &s->pb; + AVCodecContext *enc, *video_enc; + int i, width, height, rate; + +/* XXX: do we reject audio streams or just ignore them ? + if(s->nb_streams > 1) + return -1; +*/ + gif->time = 0; + gif->file_time = 0; + + video_enc = NULL; + for(i=0;inb_streams;i++) { + enc = &s->streams[i]->codec; + if (enc->codec_type != CODEC_TYPE_AUDIO) + video_enc = enc; + } + + if (!video_enc) { + av_free(gif); + return -1; + } else { + width = video_enc->width; + height = video_enc->height; + rate = video_enc->frame_rate; + } + + /* XXX: is it allowed ? seems to work so far... */ + video_enc->pix_fmt = PIX_FMT_RGB24; + + gif_image_write_header(pb, width, height); + + put_flush_packet(&s->pb); + return 0; +} + +/* chunk writer callback */ +/* !!! XXX:deprecated +static void gif_put_chunk(void *pbctx, UINT8 *buffer, int count) +{ + ByteIOContext *pb = (ByteIOContext *)pbctx; + put_byte(pb, (UINT8)count); + put_buffer(pb, buffer, count); +} +*/ + +static int gif_write_video(AVFormatContext *s, + AVCodecContext *enc, UINT8 *buf, int size) +{ + ByteIOContext *pb = &s->pb; + GIFContext *gif = s->priv_data; + int jiffies; + INT64 delay; + + /* graphic control extension block */ + put_byte(pb, 0x21); + put_byte(pb, 0xf9); + put_byte(pb, 0x04); /* block size */ + put_byte(pb, 0x04); /* flags */ + + /* 1 jiffy is 1/70 s */ + /* the delay_time field indicates the number of jiffies - 1 */ + delay = gif->file_time - gif->time; + + /* XXX: should use delay, in order to be more accurate */ + /* instead of using the same rounded value each time */ + /* XXX: don't even remember if I really use it for now */ + jiffies = (70*FRAME_RATE_BASE/enc->frame_rate) - 1; + + put_le16(pb, jiffies); + + put_byte(pb, 0x1f); /* transparent color index */ + put_byte(pb, 0x00); + + gif_image_write_image(pb, 0, 0, enc->width, enc->height, + buf, enc->width * 3); put_flush_packet(&s->pb); return 0; @@ -355,6 +379,17 @@ static int gif_write_trailer(AVFormatContext *s) return 0; } +/* 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_image(pb, 0, 0, info->width, info->height, + info->pict.data[0], info->pict.linesize[0]); + put_byte(pb, 0x3b); + put_flush_packet(pb); + return 0; +} + static AVOutputFormat gif_oformat = { "gif", "GIF Animation", @@ -367,6 +402,7 @@ static AVOutputFormat gif_oformat = { gif_write_packet, gif_write_trailer, }; + extern AVInputFormat gif_iformat; int gif_init(void) -- cgit v1.2.3