Mercurial > libavformat.hg
annotate gif.c @ 3754:8d267b43eaba libavformat
Move malloc() down until after all initializations, so that the resource is
only allocated if initialization worked. This means that on failure, we
don't have to deallocate it.
author | rbultje |
---|---|
date | Sat, 23 Aug 2008 18:46:30 +0000 |
parents | 7a0230981402 |
children | 122c1576f705 |
rev | line source |
---|---|
0 | 1 /* |
1415
3b00fb8ef8e4
replace coder/decoder file description in libavformat by muxer/demuxer
aurel
parents:
1358
diff
changeset
|
2 * Animated GIF muxer |
0 | 3 * Copyright (c) 2000 Fabrice Bellard. |
4 * | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1220
diff
changeset
|
5 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1220
diff
changeset
|
6 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1220
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
0 | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1220
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
0 | 11 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1220
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
0 | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1220
diff
changeset
|
18 * License along with FFmpeg; if not, write to the Free Software |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
887
diff
changeset
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 20 */ |
21 | |
22 /* | |
23 * First version by Francois Revol revol@free.fr | |
24 * | |
25 * Features and limitations: | |
26 * - currently no compression is performed, | |
27 * in fact the size of the data is 9/8 the size of the image in 8bpp | |
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 * this url claims to have an LZW algorithm not covered by Unisys patent: | |
37 * http://www.msg.net/utility/whirlgif/gifencod.html | |
38 * could help reduce the size of the files _a lot_... | |
39 * some sites mentions an RLE type compression also. | |
40 */ | |
41 | |
42 #include "avformat.h" | |
3286 | 43 #include "libavcodec/bitstream.h" |
0 | 44 |
45 /* bitstream minipacket size */ | |
46 #define GIF_CHUNKS 100 | |
47 | |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
48 /* slows down the decoding (and some browsers don't like it) */ |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
49 /* update on the 'some browsers don't like it issue from above: this was probably due to missing 'Data Sub-block Terminator' (byte 19) in the app_header */ |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
50 #define GIF_ADD_APP_HEADER // required to enable looping of animated gif |
0 | 51 |
52 typedef struct { | |
53 unsigned char r; | |
54 unsigned char g; | |
55 unsigned char b; | |
56 } rgb_triplet; | |
57 | |
58 /* we use the standard 216 color palette */ | |
59 | |
60 /* this script was used to create the palette: | |
885 | 61 * for r in 00 33 66 99 cc ff; do for g in 00 33 66 99 cc ff; do echo -n " "; for b in 00 33 66 99 cc ff; do |
0 | 62 * echo -n "{ 0x$r, 0x$g, 0x$b }, "; done; echo ""; done; done |
63 */ | |
64 | |
65 static const rgb_triplet gif_clut[216] = { | |
66 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff }, | |
67 { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff }, | |
68 { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff }, | |
69 { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff }, | |
70 { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff }, | |
71 { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff }, | |
72 { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff }, | |
73 { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff }, | |
74 { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff }, | |
75 { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff }, | |
76 { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff }, | |
77 { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff }, | |
78 { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff }, | |
79 { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff }, | |
80 { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff }, | |
81 { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff }, | |
82 { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff }, | |
83 { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff }, | |
84 { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff }, | |
85 { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff }, | |
86 { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff }, | |
87 { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff }, | |
88 { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff }, | |
89 { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff }, | |
90 { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff }, | |
91 { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff }, | |
92 { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff }, | |
93 { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff }, | |
94 { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff }, | |
95 { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff }, | |
96 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff }, | |
97 { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff }, | |
98 { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff }, | |
99 { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff }, | |
100 { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff }, | |
101 { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff }, | |
102 }; | |
103 | |
104 /* The GIF format uses reversed order for bitstreams... */ | |
105 /* at least they don't use PDP_ENDIAN :) */ | |
106 /* so we 'extend' PutBitContext. hmmm, OOP :) */ | |
107 /* seems this thing changed slightly since I wrote it... */ | |
108 | |
109 #ifdef ALT_BITSTREAM_WRITER | |
110 # error no ALT_BITSTREAM_WRITER support for now | |
111 #endif | |
112 | |
113 static void gif_put_bits_rev(PutBitContext *s, int n, unsigned int value) | |
114 { | |
115 unsigned int bit_buf; | |
116 int bit_cnt; | |
117 | |
118 // printf("put_bits=%d %x\n", n, value); | |
119 assert(n == 32 || value < (1U << n)); | |
120 | |
121 bit_buf = s->bit_buf; | |
122 bit_cnt = 32 - s->bit_left; /* XXX:lazyness... was = s->bit_cnt; */ | |
123 | |
124 // printf("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); | |
125 /* XXX: optimize */ | |
126 if (n < (32-bit_cnt)) { | |
127 bit_buf |= value << (bit_cnt); | |
128 bit_cnt+=n; | |
129 } else { | |
130 bit_buf |= value << (bit_cnt); | |
885 | 131 |
0 | 132 *s->buf_ptr = bit_buf & 0xff; |
133 s->buf_ptr[1] = (bit_buf >> 8) & 0xff; | |
134 s->buf_ptr[2] = (bit_buf >> 16) & 0xff; | |
135 s->buf_ptr[3] = (bit_buf >> 24) & 0xff; | |
885 | 136 |
0 | 137 //printf("bitbuf = %08x\n", bit_buf); |
138 s->buf_ptr+=4; | |
139 if (s->buf_ptr >= s->buf_end) | |
2938
ae1f1ef873ef
Replace idiotic (what moron wrote that code?) "buffer overflow" message by
michael
parents:
2771
diff
changeset
|
140 abort(); |
0 | 141 // flush_buffer_rev(s); |
142 bit_cnt=bit_cnt + n - 32; | |
143 if (bit_cnt == 0) { | |
144 bit_buf = 0; | |
145 } else { | |
146 bit_buf = value >> (n - bit_cnt); | |
147 } | |
148 } | |
149 | |
150 s->bit_buf = bit_buf; | |
151 s->bit_left = 32 - bit_cnt; | |
152 } | |
153 | |
154 /* pad the end of the output stream with zeros */ | |
155 static void gif_flush_put_bits_rev(PutBitContext *s) | |
156 { | |
157 while (s->bit_left < 32) { | |
158 /* XXX: should test end of buffer */ | |
159 *s->buf_ptr++=s->bit_buf & 0xff; | |
160 s->bit_buf>>=8; | |
161 s->bit_left+=8; | |
162 } | |
163 // flush_buffer_rev(s); | |
164 s->bit_left=32; | |
165 s->bit_buf=0; | |
166 } | |
167 | |
168 /* !RevPutBitContext */ | |
169 | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
170 /* GIF header */ |
885 | 171 static int gif_image_write_header(ByteIOContext *pb, |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
172 int width, int height, int loop_count, |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
173 uint32_t *palette) |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
174 { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
175 int i; |
60 | 176 unsigned int v; |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
177 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
178 put_tag(pb, "GIF"); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
179 put_tag(pb, "89a"); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
180 put_le16(pb, width); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
181 put_le16(pb, height); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
182 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
183 put_byte(pb, 0xf7); /* flags: global clut, 256 entries */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
184 put_byte(pb, 0x1f); /* background color index */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
185 put_byte(pb, 0); /* aspect ratio */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
186 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
187 /* the global palette */ |
60 | 188 if (!palette) { |
1123
6992dd78ff68
Add (mostly) const to variable and parameter declaration, where a char* was
diego
parents:
896
diff
changeset
|
189 put_buffer(pb, (const unsigned char *)gif_clut, 216*3); |
60 | 190 for(i=0;i<((256-216)*3);i++) |
191 put_byte(pb, 0); | |
192 } else { | |
193 for(i=0;i<256;i++) { | |
194 v = palette[i]; | |
195 put_byte(pb, (v >> 16) & 0xff); | |
196 put_byte(pb, (v >> 8) & 0xff); | |
197 put_byte(pb, (v) & 0xff); | |
198 } | |
199 } | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
200 |
887 | 201 /* update: this is the 'NETSCAPE EXTENSION' that allows for looped animated gif |
202 see http://members.aol.com/royalef/gifabout.htm#net-extension | |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
203 |
887 | 204 byte 1 : 33 (hex 0x21) GIF Extension code |
205 byte 2 : 255 (hex 0xFF) Application Extension Label | |
206 byte 3 : 11 (hex (0x0B) Length of Application Block | |
207 (eleven bytes of data to follow) | |
208 bytes 4 to 11 : "NETSCAPE" | |
209 bytes 12 to 14 : "2.0" | |
210 byte 15 : 3 (hex 0x03) Length of Data Sub-Block | |
211 (three bytes of data to follow) | |
212 byte 16 : 1 (hex 0x01) | |
213 bytes 17 to 18 : 0 to 65535, an unsigned integer in | |
214 lo-hi byte format. This indicate the | |
215 number of iterations the loop should | |
216 be executed. | |
217 bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator | |
218 */ | |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
219 |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
220 /* application extension header */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
221 #ifdef GIF_ADD_APP_HEADER |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
222 if (loop_count >= 0 && loop_count <= 65535) { |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
223 put_byte(pb, 0x21); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
224 put_byte(pb, 0xff); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
225 put_byte(pb, 0x0b); |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
226 put_tag(pb, "NETSCAPE2.0"); // bytes 4 to 14 |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
227 put_byte(pb, 0x03); // byte 15 |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
228 put_byte(pb, 0x01); // byte 16 |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
229 put_le16(pb, (uint16_t)loop_count); |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
230 put_byte(pb, 0x00); // byte 19 |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
231 } |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
232 #endif |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
233 return 0; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
234 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
235 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
236 /* this is maybe slow, but allows for extensions */ |
65 | 237 static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b) |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
238 { |
3278 | 239 return (((r) / 47) % 6) * 6 * 6 + (((g) / 47) % 6) * 6 + (((b) / 47) % 6); |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
240 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
241 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
242 |
885 | 243 static int gif_image_write_image(ByteIOContext *pb, |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
244 int x1, int y1, int width, int height, |
241 | 245 const uint8_t *buf, int linesize, int pix_fmt) |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
246 { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
247 PutBitContext p; |
65 | 248 uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */ |
60 | 249 int i, left, w, v; |
241 | 250 const uint8_t *ptr; |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
251 /* image block */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
252 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
253 put_byte(pb, 0x2c); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
254 put_le16(pb, x1); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
255 put_le16(pb, y1); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
256 put_le16(pb, width); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
257 put_le16(pb, height); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
258 put_byte(pb, 0x00); /* flags */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
259 /* no local clut */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
260 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
261 put_byte(pb, 0x08); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
262 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
263 left= width * height; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
264 |
276 | 265 init_put_bits(&p, buffer, 130); |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
266 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
267 /* |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
268 * the thing here is the bitstream is written as little packets, with a size byte before |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
269 * but it's still the same bitstream between packets (no flush !) |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
270 */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
271 ptr = buf; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
272 w = width; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
273 while(left>0) { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
274 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
275 gif_put_bits_rev(&p, 9, 0x0100); /* clear code */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
276 |
507 | 277 for(i=(left<GIF_CHUNKS)?left:GIF_CHUNKS;i;i--) { |
60 | 278 if (pix_fmt == PIX_FMT_RGB24) { |
279 v = gif_clut_index(ptr[0], ptr[1], ptr[2]); | |
280 ptr+=3; | |
281 } else { | |
282 v = *ptr++; | |
283 } | |
284 gif_put_bits_rev(&p, 9, v); | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
285 if (--w == 0) { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
286 w = width; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
287 buf += linesize; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
288 ptr = buf; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
289 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
290 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
291 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
292 if(left<=GIF_CHUNKS) { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
293 gif_put_bits_rev(&p, 9, 0x101); /* end of stream */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
294 gif_flush_put_bits_rev(&p); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
295 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
296 if(pbBufPtr(&p) - p.buf > 0) { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
297 put_byte(pb, pbBufPtr(&p) - p.buf); /* byte count of the packet */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
298 put_buffer(pb, p.buf, pbBufPtr(&p) - p.buf); /* the actual buffer */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
299 p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
300 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
301 left-=GIF_CHUNKS; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
302 } |
507 | 303 put_byte(pb, 0x00); /* end of image block */ |
885 | 304 |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
305 return 0; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
306 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
307 |
0 | 308 typedef struct { |
65 | 309 int64_t time, file_time; |
310 uint8_t buffer[100]; /* data chunks */ | |
0 | 311 } GIFContext; |
312 | |
313 static int gif_write_header(AVFormatContext *s) | |
314 { | |
315 GIFContext *gif = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
316 ByteIOContext *pb = s->pb; |
0 | 317 AVCodecContext *enc, *video_enc; |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
318 int i, width, height, loop_count /*, rate*/; |
0 | 319 |
320 /* XXX: do we reject audio streams or just ignore them ? | |
321 if(s->nb_streams > 1) | |
322 return -1; | |
323 */ | |
324 gif->time = 0; | |
325 gif->file_time = 0; | |
326 | |
327 video_enc = NULL; | |
328 for(i=0;i<s->nb_streams;i++) { | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
790
diff
changeset
|
329 enc = s->streams[i]->codec; |
0 | 330 if (enc->codec_type != CODEC_TYPE_AUDIO) |
331 video_enc = enc; | |
332 } | |
333 | |
334 if (!video_enc) { | |
335 av_free(gif); | |
336 return -1; | |
337 } else { | |
338 width = video_enc->width; | |
339 height = video_enc->height; | |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
340 loop_count = s->loop_output; |
743 | 341 // rate = video_enc->time_base.den; |
0 | 342 } |
343 | |
1220
ea469913fb68
Do not set the codec's pixel format in the format's write_header()
lucabe
parents:
1169
diff
changeset
|
344 if (video_enc->pix_fmt != PIX_FMT_RGB24) { |
ea469913fb68
Do not set the codec's pixel format in the format's write_header()
lucabe
parents:
1169
diff
changeset
|
345 av_log(s, AV_LOG_ERROR, "ERROR: gif only handles the rgb24 pixel format. Use -pix_fmt rgb24.\n"); |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
1444
diff
changeset
|
346 return AVERROR(EIO); |
1220
ea469913fb68
Do not set the codec's pixel format in the format's write_header()
lucabe
parents:
1169
diff
changeset
|
347 } |
0 | 348 |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
349 gif_image_write_header(pb, width, height, loop_count, NULL); |
0 | 350 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
351 put_flush_packet(s->pb); |
0 | 352 return 0; |
353 } | |
354 | |
885 | 355 static int gif_write_video(AVFormatContext *s, |
241 | 356 AVCodecContext *enc, const uint8_t *buf, int size) |
0 | 357 { |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
358 ByteIOContext *pb = s->pb; |
0 | 359 GIFContext *gif = s->priv_data; |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
360 int jiffies; |
65 | 361 int64_t delay; |
0 | 362 |
363 /* graphic control extension block */ | |
364 put_byte(pb, 0x21); | |
365 put_byte(pb, 0xf9); | |
366 put_byte(pb, 0x04); /* block size */ | |
367 put_byte(pb, 0x04); /* flags */ | |
885 | 368 |
0 | 369 /* 1 jiffy is 1/70 s */ |
370 /* the delay_time field indicates the number of jiffies - 1 */ | |
371 delay = gif->file_time - gif->time; | |
372 | |
373 /* XXX: should use delay, in order to be more accurate */ | |
374 /* instead of using the same rounded value each time */ | |
375 /* XXX: don't even remember if I really use it for now */ | |
743 | 376 jiffies = (70*enc->time_base.num/enc->time_base.den) - 1; |
0 | 377 |
378 put_le16(pb, jiffies); | |
379 | |
380 put_byte(pb, 0x1f); /* transparent color index */ | |
381 put_byte(pb, 0x00); | |
382 | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
383 gif_image_write_image(pb, 0, 0, enc->width, enc->height, |
60 | 384 buf, enc->width * 3, PIX_FMT_RGB24); |
0 | 385 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
386 put_flush_packet(s->pb); |
0 | 387 return 0; |
388 } | |
389 | |
468 | 390 static int gif_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 391 { |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
790
diff
changeset
|
392 AVCodecContext *codec = s->streams[pkt->stream_index]->codec; |
0 | 393 if (codec->codec_type == CODEC_TYPE_AUDIO) |
394 return 0; /* just ignore audio */ | |
395 else | |
468 | 396 return gif_write_video(s, codec, pkt->data, pkt->size); |
0 | 397 } |
398 | |
399 static int gif_write_trailer(AVFormatContext *s) | |
400 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
401 ByteIOContext *pb = s->pb; |
0 | 402 |
403 put_byte(pb, 0x3b); | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
404 put_flush_packet(s->pb); |
0 | 405 return 0; |
406 } | |
407 | |
1169 | 408 AVOutputFormat gif_muxer = { |
0 | 409 "gif", |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3286
diff
changeset
|
410 NULL_IF_CONFIG_SMALL("GIF Animation"), |
0 | 411 "image/gif", |
412 "gif", | |
413 sizeof(GIFContext), | |
414 CODEC_ID_NONE, | |
415 CODEC_ID_RAWVIDEO, | |
416 gif_write_header, | |
417 gif_write_packet, | |
418 gif_write_trailer, | |
419 }; |