Mercurial > libavformat.hg
annotate gif.c @ 584:4e3bab6555ae libavformat
When playing
ftp://ftp.mplayerhq.hu/MPlayer/samples/V-codecs/QPEG/VWbig6.avi with my
decoder (should appear soon) it hadn't changed palette even there are
palette change chunks in that AVI.
Here is small patch to make it work (zero number of colors to change in
that chunk actually means to change ALL colors).
patch by (Kostya <cannonball>at<bw-team>dot<com>)
author | michael |
---|---|
date | Fri, 12 Nov 2004 01:32:35 +0000 |
parents | f998b32632d6 |
children | 8909a59c9461 |
rev | line source |
---|---|
0 | 1 /* |
2 * Animated GIF encoder | |
3 * Copyright (c) 2000 Fabrice Bellard. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 /* | |
21 * First version by Francois Revol revol@free.fr | |
22 * | |
23 * Features and limitations: | |
24 * - currently no compression is performed, | |
25 * in fact the size of the data is 9/8 the size of the image in 8bpp | |
26 * - uses only a global standard palette | |
27 * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS). | |
28 * | |
29 * Reference documents: | |
30 * http://www.goice.co.jp/member/mo/formats/gif.html | |
31 * http://astronomy.swin.edu.au/pbourke/dataformats/gif/ | |
32 * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt | |
33 * | |
34 * this url claims to have an LZW algorithm not covered by Unisys patent: | |
35 * http://www.msg.net/utility/whirlgif/gifencod.html | |
36 * could help reduce the size of the files _a lot_... | |
37 * some sites mentions an RLE type compression also. | |
38 */ | |
39 | |
40 #include "avformat.h" | |
41 | |
42 /* bitstream minipacket size */ | |
43 #define GIF_CHUNKS 100 | |
44 | |
45 /* slows down the decoding (and some browsers doesn't like it) */ | |
46 /* #define GIF_ADD_APP_HEADER */ | |
47 | |
48 typedef struct { | |
49 unsigned char r; | |
50 unsigned char g; | |
51 unsigned char b; | |
52 } rgb_triplet; | |
53 | |
54 /* we use the standard 216 color palette */ | |
55 | |
56 /* this script was used to create the palette: | |
57 * 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 | |
58 * echo -n "{ 0x$r, 0x$g, 0x$b }, "; done; echo ""; done; done | |
59 */ | |
60 | |
61 static const rgb_triplet gif_clut[216] = { | |
62 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff }, | |
63 { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff }, | |
64 { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff }, | |
65 { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff }, | |
66 { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff }, | |
67 { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff }, | |
68 { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff }, | |
69 { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff }, | |
70 { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff }, | |
71 { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff }, | |
72 { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff }, | |
73 { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff }, | |
74 { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff }, | |
75 { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff }, | |
76 { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff }, | |
77 { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff }, | |
78 { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff }, | |
79 { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff }, | |
80 { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff }, | |
81 { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff }, | |
82 { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff }, | |
83 { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff }, | |
84 { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff }, | |
85 { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff }, | |
86 { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff }, | |
87 { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff }, | |
88 { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff }, | |
89 { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff }, | |
90 { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff }, | |
91 { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff }, | |
92 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff }, | |
93 { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff }, | |
94 { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff }, | |
95 { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff }, | |
96 { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff }, | |
97 { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff }, | |
98 }; | |
99 | |
100 /* The GIF format uses reversed order for bitstreams... */ | |
101 /* at least they don't use PDP_ENDIAN :) */ | |
102 /* so we 'extend' PutBitContext. hmmm, OOP :) */ | |
103 /* seems this thing changed slightly since I wrote it... */ | |
104 | |
105 #ifdef ALT_BITSTREAM_WRITER | |
106 # error no ALT_BITSTREAM_WRITER support for now | |
107 #endif | |
108 | |
109 static void gif_put_bits_rev(PutBitContext *s, int n, unsigned int value) | |
110 { | |
111 unsigned int bit_buf; | |
112 int bit_cnt; | |
113 | |
114 #ifdef STATS | |
115 st_out_bit_counts[st_current_index] += n; | |
116 #endif | |
117 // printf("put_bits=%d %x\n", n, value); | |
118 assert(n == 32 || value < (1U << n)); | |
119 | |
120 bit_buf = s->bit_buf; | |
121 bit_cnt = 32 - s->bit_left; /* XXX:lazyness... was = s->bit_cnt; */ | |
122 | |
123 // printf("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); | |
124 /* XXX: optimize */ | |
125 if (n < (32-bit_cnt)) { | |
126 bit_buf |= value << (bit_cnt); | |
127 bit_cnt+=n; | |
128 } else { | |
129 bit_buf |= value << (bit_cnt); | |
130 | |
131 *s->buf_ptr = bit_buf & 0xff; | |
132 s->buf_ptr[1] = (bit_buf >> 8) & 0xff; | |
133 s->buf_ptr[2] = (bit_buf >> 16) & 0xff; | |
134 s->buf_ptr[3] = (bit_buf >> 24) & 0xff; | |
135 | |
136 //printf("bitbuf = %08x\n", bit_buf); | |
137 s->buf_ptr+=4; | |
138 if (s->buf_ptr >= s->buf_end) | |
139 puts("bit buffer overflow !!"); // should never happen ! who got rid of the callback ??? | |
140 // flush_buffer_rev(s); | |
141 bit_cnt=bit_cnt + n - 32; | |
142 if (bit_cnt == 0) { | |
143 bit_buf = 0; | |
144 } else { | |
145 bit_buf = value >> (n - bit_cnt); | |
146 } | |
147 } | |
148 | |
149 s->bit_buf = bit_buf; | |
150 s->bit_left = 32 - bit_cnt; | |
151 } | |
152 | |
153 /* pad the end of the output stream with zeros */ | |
154 static void gif_flush_put_bits_rev(PutBitContext *s) | |
155 { | |
156 while (s->bit_left < 32) { | |
157 /* XXX: should test end of buffer */ | |
158 *s->buf_ptr++=s->bit_buf & 0xff; | |
159 s->bit_buf>>=8; | |
160 s->bit_left+=8; | |
161 } | |
162 // flush_buffer_rev(s); | |
163 s->bit_left=32; | |
164 s->bit_buf=0; | |
165 } | |
166 | |
167 /* !RevPutBitContext */ | |
168 | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
169 /* GIF header */ |
60 | 170 static int gif_image_write_header(ByteIOContext *pb, |
171 int width, int height, uint32_t *palette) | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
172 { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
173 int i; |
60 | 174 unsigned int v; |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
175 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
176 put_tag(pb, "GIF"); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
177 put_tag(pb, "89a"); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
178 put_le16(pb, width); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
179 put_le16(pb, height); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
180 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
181 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
|
182 put_byte(pb, 0x1f); /* background color index */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
183 put_byte(pb, 0); /* aspect ratio */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
184 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
185 /* the global palette */ |
60 | 186 if (!palette) { |
187 put_buffer(pb, (unsigned char *)gif_clut, 216*3); | |
188 for(i=0;i<((256-216)*3);i++) | |
189 put_byte(pb, 0); | |
190 } else { | |
191 for(i=0;i<256;i++) { | |
192 v = palette[i]; | |
193 put_byte(pb, (v >> 16) & 0xff); | |
194 put_byte(pb, (v >> 8) & 0xff); | |
195 put_byte(pb, (v) & 0xff); | |
196 } | |
197 } | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
198 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
199 /* application extension header */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
200 /* XXX: not really sure what to put in here... */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
201 #ifdef GIF_ADD_APP_HEADER |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
202 put_byte(pb, 0x21); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
203 put_byte(pb, 0xff); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
204 put_byte(pb, 0x0b); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
205 put_tag(pb, "NETSCAPE2.0"); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
206 put_byte(pb, 0x03); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
207 put_byte(pb, 0x01); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
208 put_byte(pb, 0x00); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
209 put_byte(pb, 0x00); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
210 #endif |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
211 return 0; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
212 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
213 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
214 /* this is maybe slow, but allows for extensions */ |
65 | 215 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
|
216 { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
217 return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6)); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
218 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
219 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
220 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
221 static int gif_image_write_image(ByteIOContext *pb, |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
222 int x1, int y1, int width, int height, |
241 | 223 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
|
224 { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
225 PutBitContext p; |
65 | 226 uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */ |
60 | 227 int i, left, w, v; |
241 | 228 const uint8_t *ptr; |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
229 /* image block */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
230 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
231 put_byte(pb, 0x2c); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
232 put_le16(pb, x1); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
233 put_le16(pb, y1); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
234 put_le16(pb, width); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
235 put_le16(pb, height); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
236 put_byte(pb, 0x00); /* flags */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
237 /* no local clut */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
238 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
239 put_byte(pb, 0x08); |
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 left= width * height; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
242 |
276 | 243 init_put_bits(&p, buffer, 130); |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
244 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
245 /* |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
246 * 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
|
247 * 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
|
248 */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
249 ptr = buf; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
250 w = width; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
251 while(left>0) { |
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 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
|
254 |
507 | 255 for(i=(left<GIF_CHUNKS)?left:GIF_CHUNKS;i;i--) { |
60 | 256 if (pix_fmt == PIX_FMT_RGB24) { |
257 v = gif_clut_index(ptr[0], ptr[1], ptr[2]); | |
258 ptr+=3; | |
259 } else { | |
260 v = *ptr++; | |
261 } | |
262 gif_put_bits_rev(&p, 9, v); | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
263 if (--w == 0) { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
264 w = width; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
265 buf += linesize; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
266 ptr = buf; |
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 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
269 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
270 if(left<=GIF_CHUNKS) { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
271 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
|
272 gif_flush_put_bits_rev(&p); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
273 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
274 if(pbBufPtr(&p) - p.buf > 0) { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
275 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
|
276 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
|
277 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
|
278 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
279 left-=GIF_CHUNKS; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
280 } |
507 | 281 put_byte(pb, 0x00); /* end of image block */ |
282 | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
283 return 0; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
284 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
285 |
0 | 286 typedef struct { |
65 | 287 int64_t time, file_time; |
288 uint8_t buffer[100]; /* data chunks */ | |
0 | 289 } GIFContext; |
290 | |
291 static int gif_write_header(AVFormatContext *s) | |
292 { | |
293 GIFContext *gif = s->priv_data; | |
294 ByteIOContext *pb = &s->pb; | |
295 AVCodecContext *enc, *video_enc; | |
85
25062c9b1f86
per context frame_rate_base, this should finally fix frame_rate related av sync issues
michaelni
parents:
65
diff
changeset
|
296 int i, width, height/*, rate*/; |
0 | 297 |
298 /* XXX: do we reject audio streams or just ignore them ? | |
299 if(s->nb_streams > 1) | |
300 return -1; | |
301 */ | |
302 gif->time = 0; | |
303 gif->file_time = 0; | |
304 | |
305 video_enc = NULL; | |
306 for(i=0;i<s->nb_streams;i++) { | |
307 enc = &s->streams[i]->codec; | |
308 if (enc->codec_type != CODEC_TYPE_AUDIO) | |
309 video_enc = enc; | |
310 } | |
311 | |
312 if (!video_enc) { | |
313 av_free(gif); | |
314 return -1; | |
315 } else { | |
316 width = video_enc->width; | |
317 height = video_enc->height; | |
85
25062c9b1f86
per context frame_rate_base, this should finally fix frame_rate related av sync issues
michaelni
parents:
65
diff
changeset
|
318 // rate = video_enc->frame_rate; |
0 | 319 } |
320 | |
321 /* XXX: is it allowed ? seems to work so far... */ | |
322 video_enc->pix_fmt = PIX_FMT_RGB24; | |
323 | |
60 | 324 gif_image_write_header(pb, width, height, NULL); |
0 | 325 |
326 put_flush_packet(&s->pb); | |
327 return 0; | |
328 } | |
329 | |
330 static int gif_write_video(AVFormatContext *s, | |
241 | 331 AVCodecContext *enc, const uint8_t *buf, int size) |
0 | 332 { |
333 ByteIOContext *pb = &s->pb; | |
334 GIFContext *gif = s->priv_data; | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
335 int jiffies; |
65 | 336 int64_t delay; |
0 | 337 |
338 /* graphic control extension block */ | |
339 put_byte(pb, 0x21); | |
340 put_byte(pb, 0xf9); | |
341 put_byte(pb, 0x04); /* block size */ | |
342 put_byte(pb, 0x04); /* flags */ | |
343 | |
344 /* 1 jiffy is 1/70 s */ | |
345 /* the delay_time field indicates the number of jiffies - 1 */ | |
346 delay = gif->file_time - gif->time; | |
347 | |
348 /* XXX: should use delay, in order to be more accurate */ | |
349 /* instead of using the same rounded value each time */ | |
350 /* XXX: don't even remember if I really use it for now */ | |
85
25062c9b1f86
per context frame_rate_base, this should finally fix frame_rate related av sync issues
michaelni
parents:
65
diff
changeset
|
351 jiffies = (70*enc->frame_rate_base/enc->frame_rate) - 1; |
0 | 352 |
353 put_le16(pb, jiffies); | |
354 | |
355 put_byte(pb, 0x1f); /* transparent color index */ | |
356 put_byte(pb, 0x00); | |
357 | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
358 gif_image_write_image(pb, 0, 0, enc->width, enc->height, |
60 | 359 buf, enc->width * 3, PIX_FMT_RGB24); |
0 | 360 |
361 put_flush_packet(&s->pb); | |
362 return 0; | |
363 } | |
364 | |
468 | 365 static int gif_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 366 { |
468 | 367 AVCodecContext *codec = &s->streams[pkt->stream_index]->codec; |
0 | 368 if (codec->codec_type == CODEC_TYPE_AUDIO) |
369 return 0; /* just ignore audio */ | |
370 else | |
468 | 371 return gif_write_video(s, codec, pkt->data, pkt->size); |
0 | 372 } |
373 | |
374 static int gif_write_trailer(AVFormatContext *s) | |
375 { | |
376 ByteIOContext *pb = &s->pb; | |
377 | |
378 put_byte(pb, 0x3b); | |
379 put_flush_packet(&s->pb); | |
380 return 0; | |
381 } | |
382 | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
383 /* better than nothing gif image writer */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
384 int gif_write(ByteIOContext *pb, AVImageInfo *info) |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
385 { |
60 | 386 gif_image_write_header(pb, info->width, info->height, |
387 (uint32_t *)info->pict.data[1]); | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
388 gif_image_write_image(pb, 0, 0, info->width, info->height, |
60 | 389 info->pict.data[0], info->pict.linesize[0], |
390 PIX_FMT_PAL8); | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
391 put_byte(pb, 0x3b); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
392 put_flush_packet(pb); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
393 return 0; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
394 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
395 |
0 | 396 static AVOutputFormat gif_oformat = { |
397 "gif", | |
398 "GIF Animation", | |
399 "image/gif", | |
400 "gif", | |
401 sizeof(GIFContext), | |
402 CODEC_ID_NONE, | |
403 CODEC_ID_RAWVIDEO, | |
404 gif_write_header, | |
405 gif_write_packet, | |
406 gif_write_trailer, | |
407 }; | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
408 |
46
890e9121a54d
added animated GIF decoder (pts and various disposal handling are missing)
bellard
parents:
0
diff
changeset
|
409 extern AVInputFormat gif_iformat; |
0 | 410 |
411 int gif_init(void) | |
412 { | |
413 av_register_output_format(&gif_oformat); | |
46
890e9121a54d
added animated GIF decoder (pts and various disposal handling are missing)
bellard
parents:
0
diff
changeset
|
414 av_register_input_format(&gif_iformat); |
0 | 415 return 0; |
416 } |