Mercurial > mplayer.hg
annotate libmpdemux/demux_gif.c @ 26602:d48e2d7191df
Make ao_pulse fall back to s16le format instead of just failing.
author | reimar |
---|---|
date | Thu, 01 May 2008 16:47:54 +0000 |
parents | d4fe6e23283e |
children | 2113bd9c6bd9 |
rev | line source |
---|---|
9133 | 1 /* |
2 GIF file parser for MPlayer | |
3 by Joey Parrish | |
4 */ | |
5 | |
6 #include <stdio.h> | |
7 #include <stdlib.h> | |
8 #include <unistd.h> | |
9 | |
10 #include "config.h" | |
11 | |
12 #include "mp_msg.h" | |
13 #include "help_mp.h" | |
14 | |
22605
4d81dbdf46b9
Add explicit location for headers from the stream/ directory.
diego
parents:
22377
diff
changeset
|
15 #include "stream/stream.h" |
9133 | 16 #include "demuxer.h" |
17 #include "stheader.h" | |
18 | |
19 #include <gif_lib.h> | |
21885 | 20 #include "libvo/fastmemcpy.h" |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
21 typedef struct { |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
22 int current_pts; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
23 unsigned char *palette; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
24 GifFileType *gif; |
21882
68ebac1f2b8d
Fix crash for gif images that have Top or Left set
reimar
parents:
21881
diff
changeset
|
25 int w, h; |
21891 | 26 int useref; |
21921 | 27 uint8_t *refimg; |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
28 } gif_priv_t; |
9133 | 29 |
30 #define GIF_SIGNATURE (('G' << 16) | ('I' << 8) | 'F') | |
31 | |
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
32 #ifndef HAVE_GIF_TVT_HACK |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
33 // not supported by certain versions of the library |
9344
bd7b5078475e
1) codecs.conf changed recently and demux_gif no longer needs to spit
arpi
parents:
9133
diff
changeset
|
34 int my_read_gif(GifFileType *gif, uint8_t *buf, int len) { |
bd7b5078475e
1) codecs.conf changed recently and demux_gif no longer needs to spit
arpi
parents:
9133
diff
changeset
|
35 return stream_read(gif->UserData, buf, len); |
bd7b5078475e
1) codecs.conf changed recently and demux_gif no longer needs to spit
arpi
parents:
9133
diff
changeset
|
36 } |
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
37 #endif |
9344
bd7b5078475e
1) codecs.conf changed recently and demux_gif no longer needs to spit
arpi
parents:
9133
diff
changeset
|
38 |
16175 | 39 static int gif_check_file(demuxer_t *demuxer) |
9133 | 40 { |
41 if (stream_read_int24(demuxer->stream) == GIF_SIGNATURE) | |
16175 | 42 return DEMUXER_TYPE_GIF; |
9133 | 43 return 0; |
44 } | |
45 | |
21920
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
46 static void memcpy_transp_pic(uint8_t *dst, uint8_t *src, int w, int h, |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
47 int dstride, int sstride, int transp, uint8_t trans_col) { |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
48 if (transp) { |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
49 dstride -= w; |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
50 sstride -= w; |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
51 while (h-- > 0) { |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
52 int wleft = w; |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
53 while (wleft-- > 0) { |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
54 if (*src != trans_col) |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
55 *dst = *src; |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
56 dst++; src++; |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
57 } |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
58 dst += dstride; |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
59 src += sstride; |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
60 } |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
61 } else |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
62 memcpy_pic(dst, src, w, h, dstride, sstride); |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
63 } |
65b2a9b3bd35
"Cosmetics" Introduce a memcpy function doing both transparent
reimar
parents:
21896
diff
changeset
|
64 |
16175 | 65 static int demux_gif_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds) |
9133 | 66 { |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
67 gif_priv_t *priv = demuxer->priv; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
68 GifFileType *gif = priv->gif; |
9133 | 69 GifRecordType type = UNDEFINED_RECORD_TYPE; |
70 int len = 0; | |
71 demux_packet_t *dp = NULL; | |
72 ColorMapObject *effective_map = NULL; | |
21921 | 73 uint8_t *buf = NULL; |
21891 | 74 int refmode = 0; |
21895 | 75 int transparency = 0; |
76 uint8_t transparent_col; | |
9133 | 77 |
78 while (type != IMAGE_DESC_RECORD_TYPE) { | |
79 if (DGifGetRecordType(gif, &type) == GIF_ERROR) { | |
80 PrintGifError(); | |
81 return 0; // oops | |
82 } | |
83 if (type == TERMINATE_RECORD_TYPE) | |
84 return 0; // eof | |
85 if (type == SCREEN_DESC_RECORD_TYPE) { | |
86 if (DGifGetScreenDesc(gif) == GIF_ERROR) { | |
87 PrintGifError(); | |
88 return 0; // oops | |
89 } | |
90 } | |
91 if (type == EXTENSION_RECORD_TYPE) { | |
92 int code; | |
93 unsigned char *p = NULL; | |
94 if (DGifGetExtension(gif, &code, &p) == GIF_ERROR) { | |
95 PrintGifError(); | |
96 return 0; // oops | |
97 } | |
98 if (code == 0xF9) { | |
99 int frametime = 0; | |
100 if (p[0] == 4) // is the length correct? | |
21891 | 101 { |
21895 | 102 transparency = p[1] & 1; |
21896 | 103 refmode = (p[1] >> 2) & 3; |
22020
a40f222a31df
Hack: use refmode == 1 instead of == 0, as browsers behave like this
reimar
parents:
22019
diff
changeset
|
104 // HACK: specification says |
a40f222a31df
Hack: use refmode == 1 instead of == 0, as browsers behave like this
reimar
parents:
22019
diff
changeset
|
105 // > 0 - No disposal specified. The decoder is not required to take any action. |
a40f222a31df
Hack: use refmode == 1 instead of == 0, as browsers behave like this
reimar
parents:
22019
diff
changeset
|
106 // but browsers treat it the same way as |
a40f222a31df
Hack: use refmode == 1 instead of == 0, as browsers behave like this
reimar
parents:
22019
diff
changeset
|
107 // > 1 - Do not dispose. The graphic is to be left in place. |
a40f222a31df
Hack: use refmode == 1 instead of == 0, as browsers behave like this
reimar
parents:
22019
diff
changeset
|
108 // Some broken files rely on this, e.g. |
a40f222a31df
Hack: use refmode == 1 instead of == 0, as browsers behave like this
reimar
parents:
22019
diff
changeset
|
109 // http://samples.mplayerhq.hu/GIF/broken-gif/CLAIRE.GIF |
a40f222a31df
Hack: use refmode == 1 instead of == 0, as browsers behave like this
reimar
parents:
22019
diff
changeset
|
110 if (refmode == 0) refmode = 1; |
21875
d81cf0be50f0
Frametime was being read from the wrong offset, compare
diego
parents:
18958
diff
changeset
|
111 frametime = (p[3] << 8) | p[2]; // set the time, centiseconds |
21895 | 112 transparent_col = p[4]; |
21891 | 113 } |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
114 priv->current_pts += frametime; |
9133 | 115 } else if ((code == 0xFE) && (verbose)) { // comment extension |
116 // print iff verbose | |
117 printf("GIF comment: "); | |
118 while (p != NULL) { | |
119 int length = p[0]; | |
120 char *comments = p + 1; | |
121 comments[length] = 0; | |
122 printf("%s", comments); | |
123 if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) { | |
124 PrintGifError(); | |
125 return 0; // oops | |
126 } | |
127 } | |
128 printf("\n"); | |
129 } | |
130 while (p != NULL) { | |
131 if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) { | |
132 PrintGifError(); | |
133 return 0; // oops | |
134 } | |
135 } | |
136 } | |
137 } | |
138 | |
139 if (DGifGetImageDesc(gif) == GIF_ERROR) { | |
140 PrintGifError(); | |
141 return 0; // oops | |
142 } | |
143 | |
144 len = gif->Image.Width * gif->Image.Height; | |
21882
68ebac1f2b8d
Fix crash for gif images that have Top or Left set
reimar
parents:
21881
diff
changeset
|
145 dp = new_demux_packet(priv->w * priv->h); |
21890 | 146 buf = calloc(gif->Image.Width, gif->Image.Height); |
21891 | 147 if (priv->useref) |
23457
a124f3abc1ec
Replace implicit use of fast_memcpy via macro by explicit use to allow
reimar
parents:
22605
diff
changeset
|
148 fast_memcpy(dp->buffer, priv->refimg, priv->w * priv->h); |
21891 | 149 else |
150 memset(dp->buffer, gif->SBackGroundColor, priv->w * priv->h); | |
9133 | 151 |
152 if (DGifGetLine(gif, buf, len) == GIF_ERROR) { | |
153 PrintGifError(); | |
154 return 0; // oops | |
155 } | |
156 | |
157 effective_map = gif->Image.ColorMap; | |
158 if (effective_map == NULL) effective_map = gif->SColorMap; | |
159 | |
160 { | |
161 int y; | |
21883 | 162 int cnt = FFMIN(effective_map->ColorCount, 256); |
22377
fd54975f9135
Use libavutil's av_clip* instead of unreadable MIN/MAX chaos.
reimar
parents:
22024
diff
changeset
|
163 int l = av_clip(gif->Image.Left, 0, priv->w); |
fd54975f9135
Use libavutil's av_clip* instead of unreadable MIN/MAX chaos.
reimar
parents:
22024
diff
changeset
|
164 int t = av_clip(gif->Image.Top, 0, priv->h); |
fd54975f9135
Use libavutil's av_clip* instead of unreadable MIN/MAX chaos.
reimar
parents:
22024
diff
changeset
|
165 int w = av_clip(gif->Image.Width, 0, priv->w - l); |
fd54975f9135
Use libavutil's av_clip* instead of unreadable MIN/MAX chaos.
reimar
parents:
22024
diff
changeset
|
166 int h = av_clip(gif->Image.Height, 0, priv->h - t); |
21885 | 167 unsigned char *dest = dp->buffer + priv->w * t + l; |
9133 | 168 |
21876 | 169 // copy the palette |
21881
a10888bc9758
Fix invalid read for gifs with a palette for less than 256 colors
reimar
parents:
21880
diff
changeset
|
170 for (y = 0; y < cnt; y++) { |
21893 | 171 priv->palette[(y * 4) + 0] = effective_map->Colors[y].Blue; |
172 priv->palette[(y * 4) + 1] = effective_map->Colors[y].Green; | |
173 priv->palette[(y * 4) + 2] = effective_map->Colors[y].Red; | |
174 priv->palette[(y * 4) + 3] = 0; | |
9133 | 175 } |
176 | |
21922 | 177 if (gif->Image.Interlace) { |
178 uint8_t *s = buf; | |
22024 | 179 int ih = (h - 0 + 7) >> 3; |
180 memcpy_transp_pic(dest, s, w, ih, | |
21922 | 181 priv->w << 3, gif->Image.Width, |
182 transparency, transparent_col); | |
22024 | 183 s += ih * w; |
184 ih = (h - 4 + 7) >> 3; | |
185 memcpy_transp_pic(dest + (priv->w << 2), s, w, ih, | |
21922 | 186 priv->w << 3, gif->Image.Width, |
187 transparency, transparent_col); | |
22024 | 188 s += ih * w; |
189 ih = (h - 2 + 3) >> 2; | |
190 memcpy_transp_pic(dest + (priv->w << 1), s, w, ih, | |
21922 | 191 priv->w << 2, gif->Image.Width, |
192 transparency, transparent_col); | |
22024 | 193 s += ih * w; |
194 ih = (h - 1 + 1) >> 1; | |
195 memcpy_transp_pic(dest + priv->w, s, w, ih, | |
21922 | 196 priv->w << 1, gif->Image.Width, |
197 transparency, transparent_col); | |
198 } else | |
199 memcpy_transp_pic(dest, buf, w, h, priv->w, gif->Image.Width, | |
200 transparency, transparent_col); | |
21892 | 201 |
23457
a124f3abc1ec
Replace implicit use of fast_memcpy via macro by explicit use to allow
reimar
parents:
22605
diff
changeset
|
202 if (refmode == 1) fast_memcpy(priv->refimg, dp->buffer, priv->w * priv->h); |
21892 | 203 if (refmode == 2 && priv->useref) { |
204 dest = priv->refimg + priv->w * t + l; | |
205 memset(buf, gif->SBackGroundColor, len); | |
206 memcpy_pic(dest, buf, w, h, priv->w, gif->Image.Width); | |
207 } | |
21894 | 208 if (!(refmode & 2)) priv->useref = refmode & 1; |
9133 | 209 } |
210 | |
211 free(buf); | |
212 | |
213 demuxer->video->dpos++; | |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
214 dp->pts = ((float)priv->current_pts) / 100; |
9133 | 215 dp->pos = stream_tell(demuxer->stream); |
216 ds_add_packet(demuxer->video, dp); | |
217 | |
218 return 1; | |
219 } | |
220 | |
16175 | 221 static demuxer_t* demux_open_gif(demuxer_t* demuxer) |
9133 | 222 { |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
223 gif_priv_t *priv = calloc(1, sizeof(gif_priv_t)); |
9133 | 224 sh_video_t *sh_video = NULL; |
225 GifFileType *gif = NULL; | |
226 | |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
227 priv->current_pts = 0; |
9133 | 228 demuxer->seekable = 0; // FIXME |
229 | |
230 // go back to the beginning | |
9345 | 231 stream_seek(demuxer->stream,demuxer->stream->start_pos); |
9133 | 232 |
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
233 #ifdef HAVE_GIF_TVT_HACK |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
234 // without the TVT functionality of libungif, a hard seek must be |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
235 // done to the beginning of the file. this is because libgif is |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
236 // unable to use mplayer's cache, and without this lseek libgif will |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
237 // not read from the beginning of the file and the command will fail. |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
238 // with this hack enabled, you will lose the ability to stream a GIF. |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
239 lseek(demuxer->stream->fd, 0, SEEK_SET); |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
240 gif = DGifOpenFileHandle(demuxer->stream->fd); |
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
241 #else |
9344
bd7b5078475e
1) codecs.conf changed recently and demux_gif no longer needs to spit
arpi
parents:
9133
diff
changeset
|
242 gif = DGifOpen(demuxer->stream, my_read_gif); |
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
parents:
9345
diff
changeset
|
243 #endif |
9133 | 244 if (!gif) { |
245 PrintGifError(); | |
246 return NULL; | |
247 } | |
248 | |
249 // create a new video stream header | |
250 sh_video = new_sh_video(demuxer, 0); | |
251 | |
252 // make sure the demuxer knows about the new video stream header | |
253 // (even though new_sh_video() ought to take care of it) | |
254 demuxer->video->sh = sh_video; | |
255 | |
256 // make sure that the video demuxer stream header knows about its | |
257 // parent video demuxer stream (this is getting wacky), or else | |
258 // video_read_properties() will choke | |
259 sh_video->ds = demuxer->video; | |
260 | |
261 sh_video->format = mmioFOURCC(8, 'R', 'G', 'B'); | |
262 | |
263 sh_video->fps = 5.0f; | |
264 sh_video->frametime = 1.0f / sh_video->fps; | |
265 | |
266 sh_video->bih = malloc(sizeof(BITMAPINFOHEADER) + (256 * 4)); | |
267 sh_video->bih->biCompression = sh_video->format; | |
22019
f43d02e9b58b
Set sh_video->bih->biWidth properly, fixes decoding after latest dec_video.c change
reimar
parents:
21922
diff
changeset
|
268 sh_video->bih->biWidth = priv->w = (uint16_t)gif->SWidth; |
f43d02e9b58b
Set sh_video->bih->biWidth properly, fixes decoding after latest dec_video.c change
reimar
parents:
21922
diff
changeset
|
269 sh_video->bih->biHeight = priv->h = (uint16_t)gif->SHeight; |
9133 | 270 sh_video->bih->biBitCount = 8; |
271 sh_video->bih->biPlanes = 2; | |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
272 priv->palette = (unsigned char *)(sh_video->bih + 1); |
21891 | 273 priv->refimg = malloc(priv->w * priv->h); |
9133 | 274 |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
275 priv->gif = gif; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
276 demuxer->priv = priv; |
9133 | 277 |
278 return demuxer; | |
279 } | |
280 | |
16175 | 281 static void demux_close_gif(demuxer_t* demuxer) |
9133 | 282 { |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
283 gif_priv_t *priv = demuxer->priv; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
284 if (!priv) return; |
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
285 if (priv->gif && DGifCloseFile(priv->gif) == GIF_ERROR) |
9133 | 286 PrintGifError(); |
21891 | 287 free(priv->refimg); |
21880
4e22e06485c6
Move global variables in gif demuxer into priv struct
reimar
parents:
21876
diff
changeset
|
288 free(priv); |
9133 | 289 } |
16175 | 290 |
291 | |
25707
d4fe6e23283e
Make all demuxer_desc_t const, thus moving them to .rodata
reimar
parents:
23457
diff
changeset
|
292 const demuxer_desc_t demuxer_desc_gif = { |
16175 | 293 "GIF demuxer", |
294 "gif", | |
295 "GIF", | |
296 "Joey Parrish", | |
297 "", | |
298 DEMUXER_TYPE_GIF, | |
299 0, // unsafe autodetect | |
300 gif_check_file, | |
301 demux_gif_fill_buffer, | |
302 demux_open_gif, | |
303 demux_close_gif, | |
304 NULL, | |
305 NULL | |
306 }; |