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
00043
00044 #include "avcodec.h"
00045 #include "bytestream.h"
00046 #include "lzw.h"
00047
00048
00049
00050 #define BITSTREAM_WRITER_LE
00051
00052 #include "put_bits.h"
00053
00054 typedef struct {
00055 AVFrame picture;
00056 LZWState *lzw;
00057 uint8_t *buf;
00058 int buf_size;
00059 } GIFContext;
00060
00061
00062 static int gif_image_write_header(AVCodecContext *avctx,
00063 uint8_t **bytestream, uint32_t *palette)
00064 {
00065 int i;
00066 unsigned int v;
00067
00068 bytestream_put_buffer(bytestream, "GIF", 3);
00069 bytestream_put_buffer(bytestream, "89a", 3);
00070 bytestream_put_le16(bytestream, avctx->width);
00071 bytestream_put_le16(bytestream, avctx->height);
00072
00073 bytestream_put_byte(bytestream, 0xf7);
00074 bytestream_put_byte(bytestream, 0x1f);
00075 bytestream_put_byte(bytestream, 0);
00076
00077
00078 for(i=0;i<256;i++) {
00079 v = palette[i];
00080 bytestream_put_be24(bytestream, v);
00081 }
00082
00083 return 0;
00084 }
00085
00086 static int gif_image_write_image(AVCodecContext *avctx,
00087 uint8_t **bytestream, uint8_t *end,
00088 const uint8_t *buf, int linesize)
00089 {
00090 GIFContext *s = avctx->priv_data;
00091 int len = 0, height;
00092 const uint8_t *ptr;
00093
00094
00095 bytestream_put_byte(bytestream, 0x2c);
00096 bytestream_put_le16(bytestream, 0);
00097 bytestream_put_le16(bytestream, 0);
00098 bytestream_put_le16(bytestream, avctx->width);
00099 bytestream_put_le16(bytestream, avctx->height);
00100 bytestream_put_byte(bytestream, 0x00);
00101
00102
00103 bytestream_put_byte(bytestream, 0x08);
00104
00105 ff_lzw_encode_init(s->lzw, s->buf, s->buf_size,
00106 12, FF_LZW_GIF, put_bits);
00107
00108 ptr = buf;
00109 for (height = avctx->height; height--;) {
00110 len += ff_lzw_encode(s->lzw, ptr, avctx->width);
00111 ptr += linesize;
00112 }
00113 len += ff_lzw_encode_flush(s->lzw, flush_put_bits);
00114
00115 ptr = s->buf;
00116 while (len > 0) {
00117 int size = FFMIN(255, len);
00118 bytestream_put_byte(bytestream, size);
00119 if (end - *bytestream < size)
00120 return -1;
00121 bytestream_put_buffer(bytestream, ptr, size);
00122 ptr += size;
00123 len -= size;
00124 }
00125 bytestream_put_byte(bytestream, 0x00);
00126 bytestream_put_byte(bytestream, 0x3b);
00127 return 0;
00128 }
00129
00130 static av_cold int gif_encode_init(AVCodecContext *avctx)
00131 {
00132 GIFContext *s = avctx->priv_data;
00133
00134 avctx->coded_frame = &s->picture;
00135 s->lzw = av_mallocz(ff_lzw_encode_state_size);
00136 if (!s->lzw)
00137 return AVERROR(ENOMEM);
00138 s->buf_size = avctx->width*avctx->height*2 + 1000;
00139 s->buf = av_malloc(s->buf_size);
00140 if (!s->buf)
00141 return AVERROR(ENOMEM);
00142 return 0;
00143 }
00144
00145
00146 static int gif_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data)
00147 {
00148 GIFContext *s = avctx->priv_data;
00149 AVFrame *pict = data;
00150 AVFrame *const p = (AVFrame *)&s->picture;
00151 uint8_t *outbuf_ptr = outbuf;
00152 uint8_t *end = outbuf + buf_size;
00153
00154 *p = *pict;
00155 p->pict_type = AV_PICTURE_TYPE_I;
00156 p->key_frame = 1;
00157 gif_image_write_header(avctx, &outbuf_ptr, (uint32_t *)pict->data[1]);
00158 gif_image_write_image(avctx, &outbuf_ptr, end, pict->data[0], pict->linesize[0]);
00159 return outbuf_ptr - outbuf;
00160 }
00161
00162 static int gif_encode_close(AVCodecContext *avctx)
00163 {
00164 GIFContext *s = avctx->priv_data;
00165
00166 av_freep(&s->lzw);
00167 av_freep(&s->buf);
00168 s->buf_size = 0;
00169 return 0;
00170 }
00171
00172 AVCodec ff_gif_encoder = {
00173 .name = "gif",
00174 .type = AVMEDIA_TYPE_VIDEO,
00175 .id = CODEC_ID_GIF,
00176 .priv_data_size = sizeof(GIFContext),
00177 .init = gif_encode_init,
00178 .encode = gif_encode_frame,
00179 .close = gif_encode_close,
00180 .pix_fmts= (const enum PixelFormat[]){PIX_FMT_RGB8, PIX_FMT_BGR8, PIX_FMT_RGB4_BYTE, PIX_FMT_BGR4_BYTE, PIX_FMT_GRAY8, PIX_FMT_PAL8, PIX_FMT_NONE},
00181 .long_name= NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
00182 };