1/* 2 * Copyright (c) 2000 Fabrice Bellard 3 * Copyright (c) 2002 Francois Revol 4 * Copyright (c) 2006 Baptiste Coudurier 5 * 6 * first version by Francois Revol <revol@free.fr> 7 * 8 * This file is part of FFmpeg. 9 * 10 * FFmpeg is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * FFmpeg is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with FFmpeg; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23 */ 24 25/** 26 * @file 27 * GIF encoder 28 * @see http://www.w3.org/Graphics/GIF/spec-gif89a.txt 29 */ 30 31#define BITSTREAM_WRITER_LE 32#include "libavutil/opt.h" 33#include "libavutil/imgutils.h" 34#include "avcodec.h" 35#include "bytestream.h" 36#include "internal.h" 37#include "lzw.h" 38#include "gif.h" 39 40#include "put_bits.h" 41 42typedef struct { 43 const AVClass *class; 44 LZWState *lzw; 45 uint8_t *buf; 46 AVFrame *last_frame; 47 int flags; 48 uint32_t palette[AVPALETTE_COUNT]; ///< local reference palette for !pal8 49 uint8_t *tmpl; ///< temporary line buffer 50} GIFContext; 51 52enum { 53 GF_OFFSETTING = 1<<0, 54 GF_TRANSDIFF = 1<<1, 55}; 56 57static int pick_palette_entry(const uint8_t *buf, int linesize, int w, int h) 58{ 59 int histogram[AVPALETTE_COUNT] = {0}; 60 int x, y, i; 61 62 for (y = 0; y < h; y++) { 63 for (x = 0; x < w; x++) 64 histogram[buf[x]]++; 65 buf += linesize; 66 } 67 for (i = 0; i < FF_ARRAY_ELEMS(histogram); i++) 68 if (!histogram[i]) 69 return i; 70 return -1; 71} 72 73static int gif_image_write_image(AVCodecContext *avctx, 74 uint8_t **bytestream, uint8_t *end, 75 const uint32_t *palette, 76 const uint8_t *buf, const int linesize, 77 AVPacket *pkt) 78{ 79 GIFContext *s = avctx->priv_data; 80 int len = 0, height = avctx->height, width = avctx->width, x, y; 81 int x_start = 0, y_start = 0, trans = -1; 82 const uint8_t *ptr; 83 84 /* Crop image */ 85 // TODO support with palette change 86 if ((s->flags & GF_OFFSETTING) && s->last_frame && !palette) { 87 const uint8_t *ref = s->last_frame->data[0]; 88 const int ref_linesize = s->last_frame->linesize[0]; 89 int x_end = avctx->width - 1, 90 y_end = avctx->height - 1; 91 92 /* skip common lines */ 93 while (y_start < y_end) { 94 if (memcmp(ref + y_start*ref_linesize, buf + y_start*linesize, width)) 95 break; 96 y_start++; 97 } 98 while (y_end > y_start) { 99 if (memcmp(ref + y_end*ref_linesize, buf + y_end*linesize, width)) 100 break; 101 y_end--; 102 } 103 height = y_end + 1 - y_start; 104 105 /* skip common columns */ 106 while (x_start < x_end) { 107 int same_column = 1; 108 for (y = y_start; y < y_end; y++) { 109 if (ref[y*ref_linesize + x_start] != buf[y*linesize + x_start]) { 110 same_column = 0; 111 break; 112 } 113 } 114 if (!same_column) 115 break; 116 x_start++; 117 } 118 while (x_end > x_start) { 119 int same_column = 1; 120 for (y = y_start; y < y_end; y++) { 121 if (ref[y*ref_linesize + x_end] != buf[y*linesize + x_end]) { 122 same_column = 0; 123 break; 124 } 125 } 126 if (!same_column) 127 break; 128 x_end--; 129 } 130 width = x_end + 1 - x_start; 131 132 av_log(avctx, AV_LOG_DEBUG,"%dx%d image at pos (%d;%d) [area:%dx%d]\n", 133 width, height, x_start, y_start, avctx->width, avctx->height); 134 } 135 136 /* image block */ 137 bytestream_put_byte(bytestream, GIF_IMAGE_SEPARATOR); 138 bytestream_put_le16(bytestream, x_start); 139 bytestream_put_le16(bytestream, y_start); 140 bytestream_put_le16(bytestream, width); 141 bytestream_put_le16(bytestream, height); 142 143 if (!palette) { 144 bytestream_put_byte(bytestream, 0x00); /* flags */ 145 } else { 146 unsigned i; 147 bytestream_put_byte(bytestream, 1<<7 | 0x7); /* flags */ 148 for (i = 0; i < AVPALETTE_COUNT; i++) { 149 const uint32_t v = palette[i]; 150 bytestream_put_be24(bytestream, v); 151 } 152 } 153 154 /* TODO: support with palette change (pal8) */ 155 if ((s->flags & GF_TRANSDIFF) && s->last_frame && !palette) { 156 trans = pick_palette_entry(buf + y_start*linesize + x_start, 157 linesize, width, height); 158 if (trans < 0) { // TODO, patch welcome 159 av_log(avctx, AV_LOG_DEBUG, "No available color, can not use transparency\n"); 160 } else { 161 uint8_t *pal_exdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE); 162 if (!pal_exdata) 163 return AVERROR(ENOMEM); 164 memcpy(pal_exdata, s->palette, AVPALETTE_SIZE); 165 pal_exdata[trans*4 + 3*!HAVE_BIGENDIAN] = 0x00; 166 } 167 } 168 169 bytestream_put_byte(bytestream, 0x08); 170 171 ff_lzw_encode_init(s->lzw, s->buf, 2 * width * height, 172 12, FF_LZW_GIF, put_bits); 173 174 ptr = buf + y_start*linesize + x_start; 175 if (trans >= 0) { 176 const int ref_linesize = s->last_frame->linesize[0]; 177 const uint8_t *ref = s->last_frame->data[0] + y_start*ref_linesize + x_start; 178 179 for (y = 0; y < height; y++) { 180 memcpy(s->tmpl, ptr, width); 181 for (x = 0; x < width; x++) 182 if (ref[x] == ptr[x]) 183 s->tmpl[x] = trans; 184 len += ff_lzw_encode(s->lzw, s->tmpl, width); 185 ptr += linesize; 186 ref += ref_linesize; 187 } 188 } else { 189 for (y = 0; y < height; y++) { 190 len += ff_lzw_encode(s->lzw, ptr, width); 191 ptr += linesize; 192 } 193 } 194 len += ff_lzw_encode_flush(s->lzw, flush_put_bits); 195 196 ptr = s->buf; 197 while (len > 0) { 198 int size = FFMIN(255, len); 199 bytestream_put_byte(bytestream, size); 200 if (end - *bytestream < size) 201 return -1; 202 bytestream_put_buffer(bytestream, ptr, size); 203 ptr += size; 204 len -= size; 205 } 206 bytestream_put_byte(bytestream, 0x00); /* end of image block */ 207 return 0; 208} 209 210static av_cold int gif_encode_init(AVCodecContext *avctx) 211{ 212 GIFContext *s = avctx->priv_data; 213 214 if (avctx->width > 65535 || avctx->height > 65535) { 215 av_log(avctx, AV_LOG_ERROR, "GIF does not support resolutions above 65535x65535\n"); 216 return AVERROR(EINVAL); 217 } 218 219 avctx->coded_frame = av_frame_alloc(); 220 if (!avctx->coded_frame) 221 return AVERROR(ENOMEM); 222 223 avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I; 224 avctx->coded_frame->key_frame = 1; 225 226 s->lzw = av_mallocz(ff_lzw_encode_state_size); 227 s->buf = av_malloc(avctx->width*avctx->height*2); 228 s->tmpl = av_malloc(avctx->width); 229 if (!s->tmpl || !s->buf || !s->lzw) 230 return AVERROR(ENOMEM); 231 232 if (avpriv_set_systematic_pal2(s->palette, avctx->pix_fmt) < 0) 233 av_assert0(avctx->pix_fmt == AV_PIX_FMT_PAL8); 234 235 return 0; 236} 237 238static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt, 239 const AVFrame *pict, int *got_packet) 240{ 241 GIFContext *s = avctx->priv_data; 242 uint8_t *outbuf_ptr, *end; 243 const uint32_t *palette = NULL; 244 int ret; 245 246 if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width*avctx->height*7/5 + FF_MIN_BUFFER_SIZE)) < 0) 247 return ret; 248 outbuf_ptr = pkt->data; 249 end = pkt->data + pkt->size; 250 251 if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { 252 uint8_t *pal_exdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE); 253 if (!pal_exdata) 254 return AVERROR(ENOMEM); 255 memcpy(pal_exdata, pict->data[1], AVPALETTE_SIZE); 256 palette = (uint32_t*)pict->data[1]; 257 } 258 259 gif_image_write_image(avctx, &outbuf_ptr, end, palette, 260 pict->data[0], pict->linesize[0], pkt); 261 if (!s->last_frame) { 262 s->last_frame = av_frame_alloc(); 263 if (!s->last_frame) 264 return AVERROR(ENOMEM); 265 } 266 av_frame_unref(s->last_frame); 267 ret = av_frame_ref(s->last_frame, (AVFrame*)pict); 268 if (ret < 0) 269 return ret; 270 271 pkt->size = outbuf_ptr - pkt->data; 272 pkt->flags |= AV_PKT_FLAG_KEY; 273 *got_packet = 1; 274 275 return 0; 276} 277 278static int gif_encode_close(AVCodecContext *avctx) 279{ 280 GIFContext *s = avctx->priv_data; 281 282 av_frame_free(&avctx->coded_frame); 283 284 av_freep(&s->lzw); 285 av_freep(&s->buf); 286 av_frame_free(&s->last_frame); 287 av_freep(&s->tmpl); 288 return 0; 289} 290 291#define OFFSET(x) offsetof(GIFContext, x) 292#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM 293static const AVOption gif_options[] = { 294 { "gifflags", "set GIF flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = GF_OFFSETTING|GF_TRANSDIFF}, 0, INT_MAX, FLAGS, "flags" }, 295 { "offsetting", "enable picture offsetting", 0, AV_OPT_TYPE_CONST, {.i64=GF_OFFSETTING}, INT_MIN, INT_MAX, FLAGS, "flags" }, 296 { "transdiff", "enable transparency detection between frames", 0, AV_OPT_TYPE_CONST, {.i64=GF_TRANSDIFF}, INT_MIN, INT_MAX, FLAGS, "flags" }, 297 { NULL } 298}; 299 300static const AVClass gif_class = { 301 .class_name = "GIF encoder", 302 .item_name = av_default_item_name, 303 .option = gif_options, 304 .version = LIBAVUTIL_VERSION_INT, 305}; 306 307AVCodec ff_gif_encoder = { 308 .name = "gif", 309 .long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"), 310 .type = AVMEDIA_TYPE_VIDEO, 311 .id = AV_CODEC_ID_GIF, 312 .priv_data_size = sizeof(GIFContext), 313 .init = gif_encode_init, 314 .encode2 = gif_encode_frame, 315 .close = gif_encode_close, 316 .pix_fmts = (const enum AVPixelFormat[]){ 317 AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, 318 AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE 319 }, 320 .priv_class = &gif_class, 321}; 322