]> git.sesse.net Git - ffmpeg/blob - libavcodec/gif.c
lavc/gif: merge two allocation checks.
[ffmpeg] / libavcodec / gif.c
1 /*
2  * GIF encoder.
3  * Copyright (c) 2000 Fabrice Bellard
4  * Copyright (c) 2002 Francois Revol
5  * Copyright (c) 2006 Baptiste Coudurier
6  *
7  * first version by Francois Revol <revol@free.fr>
8  *
9  * This file is part of FFmpeg.
10  *
11  * FFmpeg is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * FFmpeg is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with FFmpeg; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24  */
25
26 /*
27  * Features and limitations:
28  * - uses only a global standard palette
29  * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS).
30  *
31  * Reference documents:
32  * http://www.goice.co.jp/member/mo/formats/gif.html
33  * http://astronomy.swin.edu.au/pbourke/dataformats/gif/
34  * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt
35  */
36
37 #include "avcodec.h"
38 #include "bytestream.h"
39 #include "internal.h"
40 #include "lzw.h"
41
42 /* The GIF format uses reversed order for bitstreams... */
43 /* at least they don't use PDP_ENDIAN :) */
44 #define BITSTREAM_WRITER_LE
45
46 #include "put_bits.h"
47
48 typedef struct {
49     AVFrame picture;
50     LZWState *lzw;
51     uint8_t *buf;
52     AVFrame *last_frame;
53 } GIFContext;
54
55 static int gif_image_write_image(AVCodecContext *avctx,
56                                  uint8_t **bytestream, uint8_t *end,
57                                  const uint32_t *palette,
58                                  const uint8_t *buf, int linesize)
59 {
60     GIFContext *s = avctx->priv_data;
61     int len = 0, height = avctx->height, width = avctx->width, y;
62     int x_start = 0, y_start = 0;
63     const uint8_t *ptr;
64
65     /* Mark one colour as transparent if the input palette contains at least
66      * one colour that is more than 50% transparent. */
67     if (palette) {
68         unsigned i, smallest_alpha = 0xFF, alpha_component = 0;
69         for (i = 0; i < AVPALETTE_COUNT; i++) {
70             const uint32_t v = palette[i];
71             if (v >> 24 < smallest_alpha) {
72                 smallest_alpha = v >> 24;
73                 alpha_component = i;
74             }
75         }
76         if (smallest_alpha < 128) {
77             bytestream_put_byte(bytestream, 0x21); /* Extension Introducer */
78             bytestream_put_byte(bytestream, 0xf9); /* Graphic Control Label */
79             bytestream_put_byte(bytestream, 0x04); /* block length */
80             bytestream_put_byte(bytestream, 0x01); /* Transparent Color Flag */
81             bytestream_put_le16(bytestream, 0x00); /* no delay */
82             bytestream_put_byte(bytestream, alpha_component);
83             bytestream_put_byte(bytestream, 0x00);
84         }
85     }
86
87     /* Crop image */
88     // TODO support with palette change
89     if (s->last_frame && !palette) {
90         const uint8_t *ref = s->last_frame->data[0];
91         const int ref_linesize = s->last_frame->linesize[0];
92         int x_end = avctx->width  - 1,
93             y_end = avctx->height - 1;
94
95         /* skip common lines */
96         while (y_start < height) {
97             if (memcmp(ref + y_start*ref_linesize, buf + y_start*linesize, width))
98                 break;
99             y_start++;
100         }
101         while (y_end > y_start) {
102             if (memcmp(ref + y_end*ref_linesize, buf + y_end*linesize, width))
103                 break;
104             y_end--;
105         }
106         height = y_end + 1 - y_start;
107
108         /* skip common columns */
109         while (x_start < width) {
110             int same_column = 1;
111             for (y = y_start; y < y_end; y++) {
112                 if (ref[y*ref_linesize + x_start] != buf[y*linesize + x_start]) {
113                     same_column = 0;
114                     break;
115                 }
116             }
117             if (!same_column)
118                 break;
119             x_start++;
120         }
121         while (x_end > x_start) {
122             int same_column = 1;
123             for (y = y_start; y < y_end; y++) {
124                 if (ref[y*ref_linesize + x_end] != buf[y*linesize + x_end]) {
125                     same_column = 0;
126                     break;
127                 }
128             }
129             if (!same_column)
130                 break;
131             x_end--;
132         }
133         width = x_end + 1 - x_start;
134
135         av_log(avctx, AV_LOG_DEBUG,"%dx%d image at pos (%d;%d) [area:%dx%d]\n",
136                width, height, x_start, y_start, avctx->width, avctx->height);
137     }
138
139     /* image block */
140     bytestream_put_byte(bytestream, 0x2c);
141     bytestream_put_le16(bytestream, x_start);
142     bytestream_put_le16(bytestream, y_start);
143     bytestream_put_le16(bytestream, width);
144     bytestream_put_le16(bytestream, height);
145
146     if (!palette) {
147         bytestream_put_byte(bytestream, 0x00); /* flags */
148     } else {
149         unsigned i;
150         bytestream_put_byte(bytestream, 1<<7 | 0x7); /* flags */
151         for (i = 0; i < AVPALETTE_COUNT; i++) {
152             const uint32_t v = palette[i];
153             bytestream_put_be24(bytestream, v);
154         }
155     }
156
157     bytestream_put_byte(bytestream, 0x08);
158
159     ff_lzw_encode_init(s->lzw, s->buf, width * height,
160                        12, FF_LZW_GIF, put_bits);
161
162     ptr = buf + y_start*linesize + x_start;
163     for (y = 0; y < height; y++) {
164         len += ff_lzw_encode(s->lzw, ptr, width);
165         ptr += linesize;
166     }
167     len += ff_lzw_encode_flush(s->lzw, flush_put_bits);
168
169     ptr = s->buf;
170     while (len > 0) {
171         int size = FFMIN(255, len);
172         bytestream_put_byte(bytestream, size);
173         if (end - *bytestream < size)
174             return -1;
175         bytestream_put_buffer(bytestream, ptr, size);
176         ptr += size;
177         len -= size;
178     }
179     bytestream_put_byte(bytestream, 0x00); /* end of image block */
180     return 0;
181 }
182
183 static av_cold int gif_encode_init(AVCodecContext *avctx)
184 {
185     GIFContext *s = avctx->priv_data;
186
187     if (avctx->width > 65535 || avctx->height > 65535) {
188         av_log(avctx, AV_LOG_ERROR, "GIF does not support resolutions above 65535x65535\n");
189         return -1;
190     }
191
192     avctx->coded_frame = &s->picture;
193     s->lzw = av_mallocz(ff_lzw_encode_state_size);
194     s->buf = av_malloc(avctx->width*avctx->height*2);
195     if (!s->buf || !s->lzw)
196         return AVERROR(ENOMEM);
197     return 0;
198 }
199
200 /* better than nothing gif encoder */
201 static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
202                             const AVFrame *pict, int *got_packet)
203 {
204     GIFContext *s = avctx->priv_data;
205     AVFrame *const p = &s->picture;
206     uint8_t *outbuf_ptr, *end;
207     const uint32_t *palette = NULL;
208     int ret;
209
210     if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width*avctx->height*7/5 + FF_MIN_BUFFER_SIZE)) < 0)
211         return ret;
212     outbuf_ptr = pkt->data;
213     end        = pkt->data + pkt->size;
214
215     *p = *pict;
216     p->pict_type = AV_PICTURE_TYPE_I;
217     p->key_frame = 1;
218
219     if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
220         palette = (uint32_t*)p->data[1];
221
222     gif_image_write_image(avctx, &outbuf_ptr, end, palette, pict->data[0], pict->linesize[0]);
223     if (!s->last_frame) {
224         s->last_frame = av_frame_alloc();
225         if (!s->last_frame)
226             return AVERROR(ENOMEM);
227     }
228     av_frame_unref(s->last_frame);
229     ret = av_frame_ref(s->last_frame, (AVFrame*)pict);
230     if (ret < 0)
231         return ret;
232
233     pkt->size   = outbuf_ptr - pkt->data;
234     pkt->flags |= AV_PKT_FLAG_KEY;
235     *got_packet = 1;
236
237     return 0;
238 }
239
240 static int gif_encode_close(AVCodecContext *avctx)
241 {
242     GIFContext *s = avctx->priv_data;
243
244     av_freep(&s->lzw);
245     av_freep(&s->buf);
246     av_frame_free(&s->last_frame);
247     return 0;
248 }
249
250 AVCodec ff_gif_encoder = {
251     .name           = "gif",
252     .type           = AVMEDIA_TYPE_VIDEO,
253     .id             = AV_CODEC_ID_GIF,
254     .priv_data_size = sizeof(GIFContext),
255     .init           = gif_encode_init,
256     .encode2        = gif_encode_frame,
257     .close          = gif_encode_close,
258     .pix_fmts       = (const enum AVPixelFormat[]){
259         AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE,
260         AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE
261     },
262     .long_name      = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
263 };