Mercurial > mplayer.hg
annotate libmpdemux/demux_gif.c @ 24129:50e1e79056b6
Make terminal input work more like VO key input
The Unix version of getch2() could either return an internally buffered
key or do a second-level select() in addition to the input.c one and
then read more data. Change getch2() to always add all read keys with
mplayer_put_key() (like video output window keyboard input does) and
remove the internal select() from the Unix version. Make input.c call
mplayer_get_key() directly.
The primary motivation for this change is to make combining multiple
event sources under one select() easier. Now getch2() only needs to be
called when the corresponding fd is readable, and it will be possible to
handle events from X-based VOs with the same code.
author | uau |
---|---|
date | Sat, 25 Aug 2007 04:28:08 +0000 |
parents | a124f3abc1ec |
children | d4fe6e23283e |
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 | |
292 demuxer_desc_t demuxer_desc_gif = { | |
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 }; |