Mercurial > libavformat.hg
annotate gif.c @ 5984:55c714a8fb00 libavformat
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
fields of common media header chunks (these can have different sizes depending
on the type of IFF file you read), better handle odd sizes (like RIFF, every
field is padded to word) and handle headerchunks after the BODY chunk.
Patch by Sebastian Vater <cdgs.basty googlemail com>.
author | rbultje |
---|---|
date | Tue, 27 Apr 2010 14:03:47 +0000 |
parents | 536e5527c1e0 |
children |
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 |
4251
77e0c7511d41
cosmetics: Remove pointless period after copyright statement non-sentences.
diego
parents:
4207
diff
changeset
|
3 * Copyright (c) 2000 Fabrice Bellard |
0 | 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" | |
4207 | 43 |
44 /* The GIF format uses reversed order for bitstreams... */ | |
45 /* at least they don't use PDP_ENDIAN :) */ | |
46 #define BITSTREAM_WRITER_LE | |
47 | |
4864
7aa7c5853bb6
Split bitstream.h, put the bitstream writer stuff in the new file
stefano
parents:
4251
diff
changeset
|
48 #include "libavcodec/put_bits.h" |
0 | 49 |
50 /* bitstream minipacket size */ | |
51 #define GIF_CHUNKS 100 | |
52 | |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
53 /* 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
|
54 /* 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
|
55 #define GIF_ADD_APP_HEADER // required to enable looping of animated gif |
0 | 56 |
57 typedef struct { | |
58 unsigned char r; | |
59 unsigned char g; | |
60 unsigned char b; | |
61 } rgb_triplet; | |
62 | |
63 /* we use the standard 216 color palette */ | |
64 | |
65 /* this script was used to create the palette: | |
885 | 66 * 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 | 67 * echo -n "{ 0x$r, 0x$g, 0x$b }, "; done; echo ""; done; done |
68 */ | |
69 | |
70 static const rgb_triplet gif_clut[216] = { | |
71 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff }, | |
72 { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff }, | |
73 { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff }, | |
74 { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff }, | |
75 { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff }, | |
76 { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff }, | |
77 { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff }, | |
78 { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff }, | |
79 { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff }, | |
80 { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff }, | |
81 { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff }, | |
82 { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff }, | |
83 { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff }, | |
84 { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff }, | |
85 { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff }, | |
86 { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff }, | |
87 { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff }, | |
88 { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff }, | |
89 { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff }, | |
90 { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff }, | |
91 { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff }, | |
92 { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff }, | |
93 { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff }, | |
94 { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff }, | |
95 { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff }, | |
96 { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff }, | |
97 { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff }, | |
98 { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff }, | |
99 { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff }, | |
100 { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff }, | |
101 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff }, | |
102 { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff }, | |
103 { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff }, | |
104 { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff }, | |
105 { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff }, | |
106 { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff }, | |
107 }; | |
108 | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
109 /* GIF header */ |
885 | 110 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
|
111 int width, int height, int loop_count, |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
112 uint32_t *palette) |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
113 { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
114 int i; |
60 | 115 unsigned int v; |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
116 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
117 put_tag(pb, "GIF"); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
118 put_tag(pb, "89a"); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
119 put_le16(pb, width); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
120 put_le16(pb, height); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
121 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
122 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
|
123 put_byte(pb, 0x1f); /* background color index */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
124 put_byte(pb, 0); /* aspect ratio */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
125 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
126 /* the global palette */ |
60 | 127 if (!palette) { |
1123
6992dd78ff68
Add (mostly) const to variable and parameter declaration, where a char* was
diego
parents:
896
diff
changeset
|
128 put_buffer(pb, (const unsigned char *)gif_clut, 216*3); |
60 | 129 for(i=0;i<((256-216)*3);i++) |
130 put_byte(pb, 0); | |
131 } else { | |
132 for(i=0;i<256;i++) { | |
133 v = palette[i]; | |
134 put_byte(pb, (v >> 16) & 0xff); | |
135 put_byte(pb, (v >> 8) & 0xff); | |
136 put_byte(pb, (v) & 0xff); | |
137 } | |
138 } | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
139 |
887 | 140 /* update: this is the 'NETSCAPE EXTENSION' that allows for looped animated gif |
141 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
|
142 |
887 | 143 byte 1 : 33 (hex 0x21) GIF Extension code |
144 byte 2 : 255 (hex 0xFF) Application Extension Label | |
145 byte 3 : 11 (hex (0x0B) Length of Application Block | |
146 (eleven bytes of data to follow) | |
147 bytes 4 to 11 : "NETSCAPE" | |
148 bytes 12 to 14 : "2.0" | |
149 byte 15 : 3 (hex 0x03) Length of Data Sub-Block | |
150 (three bytes of data to follow) | |
151 byte 16 : 1 (hex 0x01) | |
152 bytes 17 to 18 : 0 to 65535, an unsigned integer in | |
153 lo-hi byte format. This indicate the | |
154 number of iterations the loop should | |
155 be executed. | |
156 bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator | |
157 */ | |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
158 |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
159 /* application extension header */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
160 #ifdef GIF_ADD_APP_HEADER |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
161 if (loop_count >= 0 && loop_count <= 65535) { |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
162 put_byte(pb, 0x21); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
163 put_byte(pb, 0xff); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
164 put_byte(pb, 0x0b); |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
165 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
|
166 put_byte(pb, 0x03); // byte 15 |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
167 put_byte(pb, 0x01); // byte 16 |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
168 put_le16(pb, (uint16_t)loop_count); |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
169 put_byte(pb, 0x00); // byte 19 |
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
170 } |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
171 #endif |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
172 return 0; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
173 } |
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 /* this is maybe slow, but allows for extensions */ |
65 | 176 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
|
177 { |
3278 | 178 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
|
179 } |
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 |
885 | 182 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
|
183 int x1, int y1, int width, int height, |
241 | 184 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
|
185 { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
186 PutBitContext p; |
65 | 187 uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */ |
60 | 188 int i, left, w, v; |
241 | 189 const uint8_t *ptr; |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
190 /* image block */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
191 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
192 put_byte(pb, 0x2c); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
193 put_le16(pb, x1); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
194 put_le16(pb, y1); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
195 put_le16(pb, width); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
196 put_le16(pb, height); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
197 put_byte(pb, 0x00); /* flags */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
198 /* no local clut */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
199 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
200 put_byte(pb, 0x08); |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
201 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
202 left= width * height; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
203 |
276 | 204 init_put_bits(&p, buffer, 130); |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
205 |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
206 /* |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
207 * 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
|
208 * 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
|
209 */ |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
210 ptr = buf; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
211 w = width; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
212 while(left>0) { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
213 |
4207 | 214 put_bits(&p, 9, 0x0100); /* clear code */ |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
215 |
507 | 216 for(i=(left<GIF_CHUNKS)?left:GIF_CHUNKS;i;i--) { |
60 | 217 if (pix_fmt == PIX_FMT_RGB24) { |
218 v = gif_clut_index(ptr[0], ptr[1], ptr[2]); | |
219 ptr+=3; | |
220 } else { | |
221 v = *ptr++; | |
222 } | |
4207 | 223 put_bits(&p, 9, v); |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
224 if (--w == 0) { |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
225 w = width; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
226 buf += linesize; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
227 ptr = buf; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
228 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
229 } |
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 if(left<=GIF_CHUNKS) { |
4207 | 232 put_bits(&p, 9, 0x101); /* end of stream */ |
233 flush_put_bits(&p); | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
234 } |
4873 | 235 if(put_bits_ptr(&p) - p.buf > 0) { |
236 put_byte(pb, put_bits_ptr(&p) - p.buf); /* byte count of the packet */ | |
237 put_buffer(pb, p.buf, put_bits_ptr(&p) - p.buf); /* the actual buffer */ | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
238 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
|
239 } |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
240 left-=GIF_CHUNKS; |
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
241 } |
507 | 242 put_byte(pb, 0x00); /* end of image block */ |
885 | 243 |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
244 return 0; |
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 |
0 | 247 typedef struct { |
65 | 248 int64_t time, file_time; |
249 uint8_t buffer[100]; /* data chunks */ | |
0 | 250 } GIFContext; |
251 | |
252 static int gif_write_header(AVFormatContext *s) | |
253 { | |
254 GIFContext *gif = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
255 ByteIOContext *pb = s->pb; |
0 | 256 AVCodecContext *enc, *video_enc; |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
257 int i, width, height, loop_count /*, rate*/; |
0 | 258 |
259 /* XXX: do we reject audio streams or just ignore them ? | |
260 if(s->nb_streams > 1) | |
261 return -1; | |
262 */ | |
263 gif->time = 0; | |
264 gif->file_time = 0; | |
265 | |
266 video_enc = NULL; | |
267 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
|
268 enc = s->streams[i]->codec; |
5910
536e5527c1e0
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
4873
diff
changeset
|
269 if (enc->codec_type != AVMEDIA_TYPE_AUDIO) |
0 | 270 video_enc = enc; |
271 } | |
272 | |
273 if (!video_enc) { | |
274 av_free(gif); | |
275 return -1; | |
276 } else { | |
277 width = video_enc->width; | |
278 height = video_enc->height; | |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
279 loop_count = s->loop_output; |
743 | 280 // rate = video_enc->time_base.den; |
0 | 281 } |
282 | |
1220
ea469913fb68
Do not set the codec's pixel format in the format's write_header()
lucabe
parents:
1169
diff
changeset
|
283 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
|
284 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
|
285 return AVERROR(EIO); |
1220
ea469913fb68
Do not set the codec's pixel format in the format's write_header()
lucabe
parents:
1169
diff
changeset
|
286 } |
0 | 287 |
790
80aec794c2ed
Animated GIF looping patch by (Todd Kirby // ffmpeg.php gmail com)
michael
parents:
743
diff
changeset
|
288 gif_image_write_header(pb, width, height, loop_count, NULL); |
0 | 289 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
290 put_flush_packet(s->pb); |
0 | 291 return 0; |
292 } | |
293 | |
885 | 294 static int gif_write_video(AVFormatContext *s, |
241 | 295 AVCodecContext *enc, const uint8_t *buf, int size) |
0 | 296 { |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
297 ByteIOContext *pb = s->pb; |
0 | 298 GIFContext *gif = s->priv_data; |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
299 int jiffies; |
65 | 300 int64_t delay; |
0 | 301 |
302 /* graphic control extension block */ | |
303 put_byte(pb, 0x21); | |
304 put_byte(pb, 0xf9); | |
305 put_byte(pb, 0x04); /* block size */ | |
306 put_byte(pb, 0x04); /* flags */ | |
885 | 307 |
0 | 308 /* 1 jiffy is 1/70 s */ |
309 /* the delay_time field indicates the number of jiffies - 1 */ | |
310 delay = gif->file_time - gif->time; | |
311 | |
312 /* XXX: should use delay, in order to be more accurate */ | |
313 /* instead of using the same rounded value each time */ | |
314 /* XXX: don't even remember if I really use it for now */ | |
743 | 315 jiffies = (70*enc->time_base.num/enc->time_base.den) - 1; |
0 | 316 |
317 put_le16(pb, jiffies); | |
318 | |
319 put_byte(pb, 0x1f); /* transparent color index */ | |
320 put_byte(pb, 0x00); | |
321 | |
51
7c5d91c4ca14
added primitive image GIF encoder based on animated gif encoder
bellard
parents:
46
diff
changeset
|
322 gif_image_write_image(pb, 0, 0, enc->width, enc->height, |
60 | 323 buf, enc->width * 3, PIX_FMT_RGB24); |
0 | 324 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
325 put_flush_packet(s->pb); |
0 | 326 return 0; |
327 } | |
328 | |
468 | 329 static int gif_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 330 { |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
790
diff
changeset
|
331 AVCodecContext *codec = s->streams[pkt->stream_index]->codec; |
5910
536e5527c1e0
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
4873
diff
changeset
|
332 if (codec->codec_type == AVMEDIA_TYPE_AUDIO) |
0 | 333 return 0; /* just ignore audio */ |
334 else | |
468 | 335 return gif_write_video(s, codec, pkt->data, pkt->size); |
0 | 336 } |
337 | |
338 static int gif_write_trailer(AVFormatContext *s) | |
339 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
340 ByteIOContext *pb = s->pb; |
0 | 341 |
342 put_byte(pb, 0x3b); | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
343 put_flush_packet(s->pb); |
0 | 344 return 0; |
345 } | |
346 | |
1169 | 347 AVOutputFormat gif_muxer = { |
0 | 348 "gif", |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3286
diff
changeset
|
349 NULL_IF_CONFIG_SMALL("GIF Animation"), |
0 | 350 "image/gif", |
351 "gif", | |
352 sizeof(GIFContext), | |
353 CODEC_ID_NONE, | |
354 CODEC_ID_RAWVIDEO, | |
355 gif_write_header, | |
356 gif_write_packet, | |
357 gif_write_trailer, | |
358 }; |