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 #ifdef HAVE_GIF
|
|
13
|
|
14 #include "mp_msg.h"
|
|
15 #include "help_mp.h"
|
|
16
|
|
17 #include "stream.h"
|
|
18 #include "demuxer.h"
|
|
19 #include "stheader.h"
|
|
20
|
|
21 #include <gif_lib.h>
|
|
22 static int current_pts = 0;
|
|
23 static unsigned char *pallete = NULL;
|
|
24
|
|
25 #define GIF_SIGNATURE (('G' << 16) | ('I' << 8) | 'F')
|
|
26
|
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
diff
changeset
|
27 #ifndef HAVE_GIF_TVT_HACK
|
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
diff
changeset
|
28 // not supported by certain versions of the library
|
9344
|
29 int my_read_gif(GifFileType *gif, uint8_t *buf, int len) {
|
|
30 return stream_read(gif->UserData, buf, len);
|
|
31 }
|
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
diff
changeset
|
32 #endif
|
9344
|
33
|
16175
|
34 static int gif_check_file(demuxer_t *demuxer)
|
9133
|
35 {
|
|
36 if (stream_read_int24(demuxer->stream) == GIF_SIGNATURE)
|
16175
|
37 return DEMUXER_TYPE_GIF;
|
9133
|
38 return 0;
|
|
39 }
|
|
40
|
16175
|
41 static int demux_gif_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds)
|
9133
|
42 {
|
|
43 GifFileType *gif = (GifFileType *)demuxer->priv;
|
|
44 sh_video_t *sh_video = (sh_video_t *)demuxer->video->sh;
|
|
45 GifRecordType type = UNDEFINED_RECORD_TYPE;
|
|
46 int len = 0;
|
|
47 demux_packet_t *dp = NULL;
|
|
48 ColorMapObject *effective_map = NULL;
|
|
49 char *buf = NULL;
|
|
50
|
|
51 while (type != IMAGE_DESC_RECORD_TYPE) {
|
|
52 if (DGifGetRecordType(gif, &type) == GIF_ERROR) {
|
|
53 PrintGifError();
|
|
54 return 0; // oops
|
|
55 }
|
|
56 if (type == TERMINATE_RECORD_TYPE)
|
|
57 return 0; // eof
|
|
58 if (type == SCREEN_DESC_RECORD_TYPE) {
|
|
59 if (DGifGetScreenDesc(gif) == GIF_ERROR) {
|
|
60 PrintGifError();
|
|
61 return 0; // oops
|
|
62 }
|
|
63 }
|
|
64 if (type == EXTENSION_RECORD_TYPE) {
|
|
65 int code;
|
|
66 unsigned char *p = NULL;
|
|
67 if (DGifGetExtension(gif, &code, &p) == GIF_ERROR) {
|
|
68 PrintGifError();
|
|
69 return 0; // oops
|
|
70 }
|
|
71 if (code == 0xF9) {
|
|
72 int frametime = 0;
|
|
73 if (p[0] == 4) // is the length correct?
|
|
74 frametime = (p[1] << 8) | p[2]; // set the time, centiseconds
|
|
75 current_pts += frametime;
|
|
76 } else if ((code == 0xFE) && (verbose)) { // comment extension
|
|
77 // print iff verbose
|
|
78 printf("GIF comment: ");
|
|
79 while (p != NULL) {
|
|
80 int length = p[0];
|
|
81 char *comments = p + 1;
|
|
82 comments[length] = 0;
|
|
83 printf("%s", comments);
|
|
84 if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) {
|
|
85 PrintGifError();
|
|
86 return 0; // oops
|
|
87 }
|
|
88 }
|
|
89 printf("\n");
|
|
90 }
|
|
91 while (p != NULL) {
|
|
92 if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) {
|
|
93 PrintGifError();
|
|
94 return 0; // oops
|
|
95 }
|
|
96 }
|
|
97 }
|
|
98 }
|
|
99
|
|
100 if (DGifGetImageDesc(gif) == GIF_ERROR) {
|
|
101 PrintGifError();
|
|
102 return 0; // oops
|
|
103 }
|
|
104
|
|
105 len = gif->Image.Width * gif->Image.Height;
|
|
106 dp = new_demux_packet(len);
|
|
107 buf = malloc(len);
|
|
108 memset(buf, 0, len);
|
|
109 memset(dp->buffer, 0, len);
|
|
110
|
|
111 if (DGifGetLine(gif, buf, len) == GIF_ERROR) {
|
|
112 PrintGifError();
|
|
113 return 0; // oops
|
|
114 }
|
|
115
|
|
116 effective_map = gif->Image.ColorMap;
|
|
117 if (effective_map == NULL) effective_map = gif->SColorMap;
|
|
118
|
|
119 {
|
|
120 int y;
|
|
121
|
|
122 // copy the pallete
|
|
123 for (y = 0; y < 256; y++) {
|
|
124 pallete[(y * 4) + 0] = effective_map->Colors[y].Blue;
|
|
125 pallete[(y * 4) + 1] = effective_map->Colors[y].Green;
|
|
126 pallete[(y * 4) + 2] = effective_map->Colors[y].Red;
|
|
127 pallete[(y * 4) + 3] = 0;
|
|
128 }
|
|
129
|
|
130 for (y = 0; y < gif->Image.Height; y++) {
|
|
131 unsigned char *drow = dp->buffer;
|
9344
|
132 unsigned char *gbuf = buf + (y * gif->Image.Width);
|
9133
|
133
|
|
134 drow += gif->Image.Width * (y + gif->Image.Top);
|
|
135 drow += gif->Image.Left;
|
|
136
|
|
137 memcpy(drow, gbuf, gif->Image.Width);
|
|
138 }
|
|
139 }
|
|
140
|
|
141 free(buf);
|
|
142
|
|
143 demuxer->video->dpos++;
|
|
144 dp->pts = ((float)current_pts) / 100;
|
|
145 dp->pos = stream_tell(demuxer->stream);
|
|
146 ds_add_packet(demuxer->video, dp);
|
|
147
|
|
148 return 1;
|
|
149 }
|
|
150
|
16175
|
151 static demuxer_t* demux_open_gif(demuxer_t* demuxer)
|
9133
|
152 {
|
|
153 sh_video_t *sh_video = NULL;
|
|
154 GifFileType *gif = NULL;
|
|
155
|
|
156 current_pts = 0;
|
|
157 demuxer->seekable = 0; // FIXME
|
|
158
|
|
159 // go back to the beginning
|
9345
|
160 stream_seek(demuxer->stream,demuxer->stream->start_pos);
|
9133
|
161
|
9463
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
diff
changeset
|
162 #ifdef HAVE_GIF_TVT_HACK
|
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
diff
changeset
|
163 // 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
diff
changeset
|
164 // 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
diff
changeset
|
165 // 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
diff
changeset
|
166 // 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
diff
changeset
|
167 // 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
diff
changeset
|
168 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
diff
changeset
|
169 gif = DGifOpenFileHandle(demuxer->stream->fd);
|
93375ee56629
gif library incompatibility fixes and prefere libungif over libgif. Patch by Joey Parrish <joey@nicewarrior.org>
alex
diff
changeset
|
170 #else
|
9344
|
171 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
diff
changeset
|
172 #endif
|
9133
|
173 if (!gif) {
|
|
174 PrintGifError();
|
|
175 return NULL;
|
|
176 }
|
|
177
|
|
178 // create a new video stream header
|
|
179 sh_video = new_sh_video(demuxer, 0);
|
|
180
|
|
181 // make sure the demuxer knows about the new video stream header
|
|
182 // (even though new_sh_video() ought to take care of it)
|
|
183 demuxer->video->sh = sh_video;
|
|
184
|
|
185 // make sure that the video demuxer stream header knows about its
|
|
186 // parent video demuxer stream (this is getting wacky), or else
|
|
187 // video_read_properties() will choke
|
|
188 sh_video->ds = demuxer->video;
|
|
189
|
|
190 sh_video->disp_w = gif->SWidth;
|
|
191 sh_video->disp_h = gif->SHeight;
|
|
192
|
|
193 sh_video->format = mmioFOURCC(8, 'R', 'G', 'B');
|
|
194
|
|
195 sh_video->fps = 5.0f;
|
|
196 sh_video->frametime = 1.0f / sh_video->fps;
|
|
197
|
|
198 sh_video->bih = malloc(sizeof(BITMAPINFOHEADER) + (256 * 4));
|
|
199 sh_video->bih->biCompression = sh_video->format;
|
|
200 sh_video->bih->biBitCount = 8;
|
|
201 sh_video->bih->biPlanes = 2;
|
|
202 pallete = (unsigned char *)(sh_video->bih + 1);
|
|
203
|
|
204 demuxer->priv = gif;
|
|
205
|
|
206 return demuxer;
|
|
207 }
|
|
208
|
16175
|
209 static void demux_close_gif(demuxer_t* demuxer)
|
9133
|
210 {
|
|
211 GifFileType *gif = (GifFileType *)demuxer->priv;
|
|
212
|
|
213 if(!gif)
|
|
214 return;
|
|
215
|
|
216 if (DGifCloseFile(gif) == GIF_ERROR)
|
|
217 PrintGifError();
|
|
218
|
|
219 demuxer->stream->fd = 0;
|
|
220 demuxer->priv = NULL;
|
|
221 }
|
16175
|
222
|
|
223
|
|
224 demuxer_desc_t demuxer_desc_gif = {
|
|
225 "GIF demuxer",
|
|
226 "gif",
|
|
227 "GIF",
|
|
228 "Joey Parrish",
|
|
229 "",
|
|
230 DEMUXER_TYPE_GIF,
|
|
231 0, // unsafe autodetect
|
|
232 gif_check_file,
|
|
233 demux_gif_fill_buffer,
|
|
234 demux_open_gif,
|
|
235 demux_close_gif,
|
|
236 NULL,
|
|
237 NULL
|
|
238 };
|
|
239
|
9133
|
240 #endif /* HAVE_GIF */
|