]>
Piment Noir Git Repositories - deb_ffmpeg.git/blob - ffmpeg/libavcodec/gif.c
27d054e512e10a09d622469a32d6b14cc571eb44
2 * Copyright (c) 2000 Fabrice Bellard
3 * Copyright (c) 2002 Francois Revol
4 * Copyright (c) 2006 Baptiste Coudurier
6 * first version by Francois Revol <revol@free.fr>
8 * This file is part of FFmpeg.
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.
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.
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
28 * @see http://www.w3.org/Graphics/GIF/spec-gif89a.txt
31 #define BITSTREAM_WRITER_LE
32 #include "libavutil/opt.h"
33 #include "libavutil/imgutils.h"
35 #include "bytestream.h"
48 uint32_t palette
[AVPALETTE_COUNT
]; ///< local reference palette for !pal8
49 uint8_t *tmpl
; ///< temporary line buffer
57 static int pick_palette_entry(const uint8_t *buf
, int linesize
, int w
, int h
)
59 int histogram
[AVPALETTE_COUNT
] = {0};
62 for (y
= 0; y
< h
; y
++) {
63 for (x
= 0; x
< w
; x
++)
67 for (i
= 0; i
< FF_ARRAY_ELEMS(histogram
); i
++)
73 static 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
,
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;
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;
92 /* skip common lines */
93 while (y_start
< y_end
) {
94 if (memcmp(ref
+ y_start
*ref_linesize
, buf
+ y_start
*linesize
, width
))
98 while (y_end
> y_start
) {
99 if (memcmp(ref
+ y_end
*ref_linesize
, buf
+ y_end
*linesize
, width
))
103 height
= y_end
+ 1 - y_start
;
105 /* skip common columns */
106 while (x_start
< x_end
) {
108 for (y
= y_start
; y
< y_end
; y
++) {
109 if (ref
[y
*ref_linesize
+ x_start
] != buf
[y
*linesize
+ x_start
]) {
118 while (x_end
> x_start
) {
120 for (y
= y_start
; y
< y_end
; y
++) {
121 if (ref
[y
*ref_linesize
+ x_end
] != buf
[y
*linesize
+ x_end
]) {
130 width
= x_end
+ 1 - x_start
;
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
);
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
);
144 bytestream_put_byte(bytestream
, 0x00); /* flags */
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
);
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");
161 uint8_t *pal_exdata
= av_packet_new_side_data(pkt
, AV_PKT_DATA_PALETTE
, AVPALETTE_SIZE
);
163 return AVERROR(ENOMEM
);
164 memcpy(pal_exdata
, s
->palette
, AVPALETTE_SIZE
);
165 pal_exdata
[trans
*4 + 3*!HAVE_BIGENDIAN
] = 0x00;
169 bytestream_put_byte(bytestream
, 0x08);
171 ff_lzw_encode_init(s
->lzw
, s
->buf
, 2 * width
* height
,
172 12, FF_LZW_GIF
, put_bits
);
174 ptr
= buf
+ y_start
*linesize
+ x_start
;
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
;
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
])
184 len
+= ff_lzw_encode(s
->lzw
, s
->tmpl
, width
);
189 for (y
= 0; y
< height
; y
++) {
190 len
+= ff_lzw_encode(s
->lzw
, ptr
, width
);
194 len
+= ff_lzw_encode_flush(s
->lzw
, flush_put_bits
);
198 int size
= FFMIN(255, len
);
199 bytestream_put_byte(bytestream
, size
);
200 if (end
- *bytestream
< size
)
202 bytestream_put_buffer(bytestream
, ptr
, size
);
206 bytestream_put_byte(bytestream
, 0x00); /* end of image block */
210 static av_cold
int gif_encode_init(AVCodecContext
*avctx
)
212 GIFContext
*s
= avctx
->priv_data
;
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
);
219 avctx
->coded_frame
= av_frame_alloc();
220 if (!avctx
->coded_frame
)
221 return AVERROR(ENOMEM
);
223 avctx
->coded_frame
->pict_type
= AV_PICTURE_TYPE_I
;
224 avctx
->coded_frame
->key_frame
= 1;
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
);
232 if (avpriv_set_systematic_pal2(s
->palette
, avctx
->pix_fmt
) < 0)
233 av_assert0(avctx
->pix_fmt
== AV_PIX_FMT_PAL8
);
238 static int gif_encode_frame(AVCodecContext
*avctx
, AVPacket
*pkt
,
239 const AVFrame
*pict
, int *got_packet
)
241 GIFContext
*s
= avctx
->priv_data
;
242 uint8_t *outbuf_ptr
, *end
;
243 const uint32_t *palette
= NULL
;
246 if ((ret
= ff_alloc_packet2(avctx
, pkt
, avctx
->width
*avctx
->height
*7/5 + FF_MIN_BUFFER_SIZE
)) < 0)
248 outbuf_ptr
= pkt
->data
;
249 end
= pkt
->data
+ pkt
->size
;
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
);
254 return AVERROR(ENOMEM
);
255 memcpy(pal_exdata
, pict
->data
[1], AVPALETTE_SIZE
);
256 palette
= (uint32_t*)pict
->data
[1];
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();
264 return AVERROR(ENOMEM
);
266 av_frame_unref(s
->last_frame
);
267 ret
= av_frame_ref(s
->last_frame
, (AVFrame
*)pict
);
271 pkt
->size
= outbuf_ptr
- pkt
->data
;
272 pkt
->flags
|= AV_PKT_FLAG_KEY
;
278 static int gif_encode_close(AVCodecContext
*avctx
)
280 GIFContext
*s
= avctx
->priv_data
;
282 av_frame_free(&avctx
->coded_frame
);
286 av_frame_free(&s
->last_frame
);
291 #define OFFSET(x) offsetof(GIFContext, x)
292 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
293 static 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" },
300 static 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
,
307 AVCodec ff_gif_encoder
= {
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
320 .priv_class
= &gif_class
,