2 GIF file parser for MPlayer
22 static int current_pts
= 0;
23 static unsigned char *pallete
= NULL
;
25 #define GIF_SIGNATURE (('G' << 16) | ('I' << 8) | 'F')
27 #ifndef HAVE_GIF_TVT_HACK
28 // not supported by certain versions of the library
29 int my_read_gif(GifFileType
*gif
, uint8_t *buf
, int len
) {
30 return stream_read(gif
->UserData
, buf
, len
);
34 static int gif_check_file(demuxer_t
*demuxer
)
36 if (stream_read_int24(demuxer
->stream
) == GIF_SIGNATURE
)
37 return DEMUXER_TYPE_GIF
;
41 static int demux_gif_fill_buffer(demuxer_t
*demuxer
, demux_stream_t
*ds
)
43 GifFileType
*gif
= (GifFileType
*)demuxer
->priv
;
44 sh_video_t
*sh_video
= (sh_video_t
*)demuxer
->video
->sh
;
45 GifRecordType type
= UNDEFINED_RECORD_TYPE
;
47 demux_packet_t
*dp
= NULL
;
48 ColorMapObject
*effective_map
= NULL
;
51 while (type
!= IMAGE_DESC_RECORD_TYPE
) {
52 if (DGifGetRecordType(gif
, &type
) == GIF_ERROR
) {
56 if (type
== TERMINATE_RECORD_TYPE
)
58 if (type
== SCREEN_DESC_RECORD_TYPE
) {
59 if (DGifGetScreenDesc(gif
) == GIF_ERROR
) {
64 if (type
== EXTENSION_RECORD_TYPE
) {
66 unsigned char *p
= NULL
;
67 if (DGifGetExtension(gif
, &code
, &p
) == GIF_ERROR
) {
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
78 printf("GIF comment: ");
81 char *comments
= p
+ 1;
83 printf("%s", comments
);
84 if (DGifGetExtensionNext(gif
, &p
) == GIF_ERROR
) {
92 if (DGifGetExtensionNext(gif
, &p
) == GIF_ERROR
) {
100 if (DGifGetImageDesc(gif
) == GIF_ERROR
) {
105 len
= gif
->Image
.Width
* gif
->Image
.Height
;
106 dp
= new_demux_packet(len
);
109 memset(dp
->buffer
, 0, len
);
111 if (DGifGetLine(gif
, buf
, len
) == GIF_ERROR
) {
116 effective_map
= gif
->Image
.ColorMap
;
117 if (effective_map
== NULL
) effective_map
= gif
->SColorMap
;
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;
130 for (y
= 0; y
< gif
->Image
.Height
; y
++) {
131 unsigned char *drow
= dp
->buffer
;
132 unsigned char *gbuf
= buf
+ (y
* gif
->Image
.Width
);
134 drow
+= gif
->Image
.Width
* (y
+ gif
->Image
.Top
);
135 drow
+= gif
->Image
.Left
;
137 memcpy(drow
, gbuf
, gif
->Image
.Width
);
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
);
151 static demuxer_t
* demux_open_gif(demuxer_t
* demuxer
)
153 sh_video_t
*sh_video
= NULL
;
154 GifFileType
*gif
= NULL
;
157 demuxer
->seekable
= 0; // FIXME
159 // go back to the beginning
160 stream_seek(demuxer
->stream
,demuxer
->stream
->start_pos
);
162 #ifdef HAVE_GIF_TVT_HACK
163 // without the TVT functionality of libungif, a hard seek must be
164 // done to the beginning of the file. this is because libgif is
165 // unable to use mplayer's cache, and without this lseek libgif will
166 // not read from the beginning of the file and the command will fail.
167 // with this hack enabled, you will lose the ability to stream a GIF.
168 lseek(demuxer
->stream
->fd
, 0, SEEK_SET
);
169 gif
= DGifOpenFileHandle(demuxer
->stream
->fd
);
171 gif
= DGifOpen(demuxer
->stream
, my_read_gif
);
178 // create a new video stream header
179 sh_video
= new_sh_video(demuxer
, 0);
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
;
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
;
190 sh_video
->disp_w
= gif
->SWidth
;
191 sh_video
->disp_h
= gif
->SHeight
;
193 sh_video
->format
= mmioFOURCC(8, 'R', 'G', 'B');
195 sh_video
->fps
= 5.0f
;
196 sh_video
->frametime
= 1.0f
/ sh_video
->fps
;
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);
209 static void demux_close_gif(demuxer_t
* demuxer
)
211 GifFileType
*gif
= (GifFileType
*)demuxer
->priv
;
216 if (DGifCloseFile(gif
) == GIF_ERROR
)
219 demuxer
->stream
->fd
= 0;
220 demuxer
->priv
= NULL
;
224 demuxer_desc_t demuxer_desc_gif
= {
231 0, // unsafe autodetect
233 demux_gif_fill_buffer
,
240 #endif /* HAVE_GIF */