[MPlayer-dev-eng] GIF help needed

Joey Parrish joey at nicewarrior.org
Wed Jan 22 21:47:48 CET 2003


Hello,

I submitted a patch before to add GIF demux/decode support to MPlayer.
It was rejected because it made the decoder dependant on the demuxer
and it didn't really decode so much as colormap and blit.

On Arpi's suggestion, I made another patch where GIF demuxer colormaps
it all into RGB24 and outputs raw RGB.  (Instead of sending indexed
values to decoder and having decoder map them to RGB24.)

The problem is that so far, only the wrong way to do it actually works.
The version that needs no vd_gif displays garbled colors.  I have the
feeling that I'm doing something stupid, so I would really appreciate it
if someone could look at the patches and help me find my problem.

Attached below are three patches.
1) wrong_works.patch  --  the wrong way, but works right
2) right_broken.patch --  the right way, but garbles colors
3) cumulative.patch   --  the differences in the demuxer between the two

The third patch show very quickly that not much changed in the demuxer
between the two.  This is why I'm so confused about the second one being
broken.

Can anybody offer me any help?
--Joey
-------------- next part --------------
diff -Nur main.cvs/etc/codecs.conf main.wrong_works/etc/codecs.conf
--- main.cvs/etc/codecs.conf	Wed Jan 22 10:34:02 2003
+++ main.wrong_works/etc/codecs.conf	Wed Jan 22 14:15:46 2003
@@ -60,6 +60,13 @@
   driver mpng
   out BGR32,BGR24
 
+videocodec gif
+  info "GIF decoder"
+  status working
+  fourcc GIFV
+  driver gif
+  out RGB24
+
 videocodec mtga
   info "TGA images decoder"
   status working
diff -Nur main.cvs/libmpcodecs/Makefile main.wrong_works/libmpcodecs/Makefile
--- main.cvs/libmpcodecs/Makefile	Sun Dec 15 19:49:39 2002
+++ main.wrong_works/libmpcodecs/Makefile	Wed Jan 22 14:15:46 2003
@@ -9,7 +9,7 @@
 AUDIO_SRCS_OPT=ad_acm.c ad_dshow.c ad_dmo.c ad_qtaudio.c ad_ffmpeg.c ad_faad.c ad_libvorbis.c ad_libmad.c ad_realaud.c ad_libdv.c
 AUDIO_SRCS=dec_audio.c ad.c $(AUDIO_SRCS_LIB) $(AUDIO_SRCS_NAT) $(AUDIO_SRCS_OPT)
 
-VIDEO_SRCS_LIB=vd_libmpeg2.c vd_nuv.c vd_lzo.c
+VIDEO_SRCS_LIB=vd_libmpeg2.c vd_nuv.c vd_lzo.c vd_gif.c
 VIDEO_SRCS_NAT=vd_null.c vd_cinepak.c vd_qtrpza.c vd_raw.c vd_msvidc.c vd_fli.c vd_qtrle.c vd_qtsmc.c vd_roqvideo.c vd_cyuv.c vd_msrle.c vd_huffyuv.c vd_mpegpes.c vd_svq1.c vd_lcl.c vd_mtga.c
 VIDEO_SRCS_OPT=vd_realvid.c vd_ffmpeg.c vd_dshow.c vd_dmo.c vd_vfw.c vd_vfwex.c vd_odivx.c vd_divx4.c vd_xanim.c vd_xvid.c vd_libdv.c vd_qtvideo.c
 VIDEO_SRCS=dec_video.c vd.c $(VIDEO_SRCS_NAT) $(VIDEO_SRCS_LIB) $(VIDEO_SRCS_OPT)
diff -Nur main.cvs/libmpcodecs/vd.c main.wrong_works/libmpcodecs/vd.c
--- main.cvs/libmpcodecs/vd.c	Fri Dec 27 11:31:52 2002
+++ main.wrong_works/libmpcodecs/vd.c	Wed Jan 22 14:15:46 2003
@@ -58,6 +58,7 @@
 extern vd_functions_t mpcodecs_vd_lcl;
 extern vd_functions_t mpcodecs_vd_lzo;
 extern vd_functions_t mpcodecs_vd_qtvideo;
+extern vd_functions_t mpcodecs_vd_gif;
 
 vd_functions_t* mpcodecs_vd_drivers[] = {
         &mpcodecs_vd_null,
@@ -120,6 +121,9 @@
 	&mpcodecs_vd_lcl,
 #ifdef USE_QTX_CODECS
 	&mpcodecs_vd_qtvideo,
+#endif
+#ifdef HAVE_GIF
+	&mpcodecs_vd_gif,
 #endif
 	NULL
 };
diff -Nur main.cvs/libmpcodecs/vd_gif.c main.wrong_works/libmpcodecs/vd_gif.c
--- main.cvs/libmpcodecs/vd_gif.c	Wed Dec 31 18:00:00 1969
+++ main.wrong_works/libmpcodecs/vd_gif.c	Wed Jan 22 14:15:46 2003
@@ -0,0 +1,76 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "mp_msg.h"
+
+#ifdef HAVE_GIF
+
+#include <gif_lib.h>
+
+#include "vd_internal.h"
+
+static vd_info_t info = {
+	"GIF decoder",
+	"gif",
+	"Joey Parrish",
+	"http://www.w3.org/Graphics/GIF/spec-gif89a.txt",
+	"uses libungif and family"
+};
+
+LIBVD_EXTERN(gif)
+
+// to set/get/query special features/parameters
+static int control(sh_video_t *sh,int cmd,void* arg,...){
+    return CONTROL_UNKNOWN;
+}
+
+// init driver
+static int init(sh_video_t *sh){
+    return mpcodecs_config_vo(sh, sh->disp_w, sh->disp_h, IMGFMT_RGB24);
+}
+
+// uninit driver
+static void uninit(sh_video_t *sh){
+}
+
+// decode a frame
+static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
+    mp_image_t* mpi;
+    GifFileType *gif = (GifFileType *)sh->ds->demuxer->priv;
+    int x, y;
+    
+    if (!gif) return NULL; // no gif structure?
+    // this is bad, it makes the decoder demuxer-dependant.
+    
+    if (len <= 0) return NULL; // skipped frame
+
+    mpi = mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, sh->disp_w, sh->disp_h);
+    if(!mpi) return NULL;
+
+    for (y = 0; y < gif->Image.Height; y++) {
+      unsigned char *drow = mpi->planes[0];
+      unsigned char *buf = data + (y * gif->Image.Width);
+      ColorMapObject *cmap = gif->Image.ColorMap;
+
+      if (!cmap) cmap = gif->SColorMap; // default to a global map.
+
+      if (!cmap) { // no color map at all?
+        fprintf(stderr, "GIF color map failure.\n");
+        return NULL;
+      }
+      
+      drow += mpi->stride[0] * (y + gif->Image.Top);
+      drow += gif->Image.Left * 3;
+
+      for (x = 0; x < gif->Image.Width; x++) {
+        drow[(x * 3) + 0] = cmap->Colors[buf[x]].Red;
+        drow[(x * 3) + 1] = cmap->Colors[buf[x]].Green;
+        drow[(x * 3) + 2] = cmap->Colors[buf[x]].Blue;
+      }
+    }
+
+    return mpi;
+}
+
+#endif /* HAVE_GIF */
diff -Nur main.cvs/libmpdemux/Makefile main.wrong_works/libmpdemux/Makefile
--- main.cvs/libmpdemux/Makefile	Wed Jan 22 10:34:04 2003
+++ main.wrong_works/libmpdemux/Makefile	Wed Jan 22 14:15:46 2003
@@ -3,7 +3,7 @@
 
 include ../config.mak
 
-SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c
+SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c
 ifeq ($(XMMS_PLUGINS),yes)
 SRCS += demux_xmms.c
 endif 
diff -Nur main.cvs/libmpdemux/demux_gif.c main.wrong_works/libmpdemux/demux_gif.c
--- main.cvs/libmpdemux/demux_gif.c	Wed Dec 31 18:00:00 1969
+++ main.wrong_works/libmpdemux/demux_gif.c	Wed Jan 22 14:20:20 2003
@@ -0,0 +1,173 @@
+/*
+	GIF file parser for MPlayer
+	by Joey Parrish
+	based on demux_fli.c
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "stream.h"
+#include "demuxer.h"
+#include "stheader.h"
+
+#ifdef HAVE_GIF
+
+#include <gif_lib.h>
+
+static int current_pts = 0;
+
+#define GIF_SIGNATURE (('G' << 16) | ('I' << 8) | 'F')
+
+int gif_check_file(demuxer_t *demuxer)
+{
+  stream_reset(demuxer->stream);
+  stream_seek(demuxer->stream, 0);
+  if (stream_read_int24(demuxer->stream) == GIF_SIGNATURE)
+    return 1;
+  return 0;
+}
+
+int demux_gif_fill_buffer(demuxer_t *demuxer)
+{
+  GifFileType *gif = (GifFileType *)demuxer->priv;
+  GifRecordType type = UNDEFINED_RECORD_TYPE;
+  int len = 0;
+  demux_packet_t *dp = NULL;
+
+  while (type != IMAGE_DESC_RECORD_TYPE) {
+    if (DGifGetRecordType(gif, &type) == GIF_ERROR) {
+      PrintGifError();
+      return 0; // oops
+    }
+    if (type == TERMINATE_RECORD_TYPE)
+      return 0; // eof
+    if (type == SCREEN_DESC_RECORD_TYPE) {
+      if (DGifGetScreenDesc(gif) == GIF_ERROR) {
+        PrintGifError();
+        return 0; // oops
+      }
+    }
+    if (type == EXTENSION_RECORD_TYPE) {
+      int code;
+      unsigned char *p = NULL;
+      if (DGifGetExtension(gif, &code, &p) == GIF_ERROR) {
+        PrintGifError();
+        return 0; // oops
+      }
+      if (code == 0xF9) {
+        int frametime = 0;
+        if (p[0] == 4) // is the length correct?
+          frametime = (p[1] << 8) | p[2]; // set the time, centiseconds
+        current_pts += frametime;
+      } else if ((code == 0xFE) && (verbose)) { // comment extension
+	// print iff verbose
+	printf("GIF comment: ");
+        while (p != NULL) {
+          int length = p[0];
+	  char *comments = p + 1;
+	  comments[length] = 0;
+	  printf("%s", comments);
+          if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) {
+            PrintGifError();
+            return 0; // oops
+          }
+	}
+	printf("\n");
+      // FIXME  support these:
+      } else if (code == 0x01) { // plaintext extension
+      } else if (code == 0xFF) { // application extension
+      }
+      while (p != NULL) {
+        if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) {
+          PrintGifError();
+          return 0; // oops
+        }
+      }
+    }
+  }
+  
+  if (DGifGetImageDesc(gif) == GIF_ERROR) {
+    PrintGifError();
+    return 0; // oops
+  }
+
+  len = gif->Image.Width * gif->Image.Height;
+  dp = new_demux_packet(len);
+  
+  if (DGifGetLine(gif, dp->buffer, len) == GIF_ERROR) {
+    PrintGifError();
+    return 0; // oops
+  }
+
+  demuxer->video->dpos++;
+  dp->pts = ((float)current_pts) / 100;
+  dp->pos = stream_tell(demuxer->stream);
+  ds_add_packet(demuxer->video, dp);
+
+  return 1;
+}
+
+demuxer_t* demux_open_gif(demuxer_t* demuxer)
+{
+  sh_video_t *sh_video = NULL;
+  GifFileType *gif = NULL;
+
+  current_pts = 0;
+  demuxer->seekable = 0; // FIXME
+
+  // go back to the beginning
+  stream_reset(demuxer->stream);
+  stream_seek(demuxer->stream, 0);
+  lseek(demuxer->stream->fd, 0, SEEK_SET);
+
+  gif = DGifOpenFileHandle(demuxer->stream->fd);
+  if (!gif) {
+    PrintGifError();
+    return NULL;
+  }
+
+  // create a new video stream header
+  sh_video = new_sh_video(demuxer, 0);
+
+  // make sure the demuxer knows about the new video stream header
+  // (even though new_sh_video() ought to take care of it)
+  demuxer->video->sh = sh_video;
+
+  // make sure that the video demuxer stream header knows about its
+  // parent video demuxer stream (this is getting wacky), or else
+  // video_read_properties() will choke
+  sh_video->ds = demuxer->video;
+
+  sh_video->disp_w = gif->SWidth;
+  sh_video->disp_h = gif->SHeight;
+
+  sh_video->format = mmioFOURCC('G', 'I', 'F', 'V');
+  
+  sh_video->fps = 5.0f;
+  sh_video->frametime = 1.0f / sh_video->fps;
+  
+  demuxer->priv = gif;
+
+  return demuxer;
+}
+
+void demux_close_gif(demuxer_t* demuxer)
+{
+  GifFileType *gif = (GifFileType *)demuxer->priv;
+
+  if(!gif)
+    return;
+
+  if (DGifCloseFile(gif) == GIF_ERROR)
+    PrintGifError();
+  
+  demuxer->stream->fd = 0;
+  demuxer->priv = NULL;
+}
+#endif /* HAVE_GIF */
diff -Nur main.cvs/libmpdemux/demuxer.c main.wrong_works/libmpdemux/demuxer.c
--- main.cvs/libmpdemux/demuxer.c	Wed Jan 22 10:34:04 2003
+++ main.wrong_works/libmpdemux/demuxer.c	Wed Jan 22 14:15:46 2003
@@ -133,6 +133,7 @@
 extern void demux_close_pva(demuxer_t* demuxer);
 extern void demux_close_smjpeg(demuxer_t* demuxer);
 extern void demux_close_xmms(demuxer_t* demuxer);
+extern void demux_close_gif(demuxer_t* demuxer);
 
 #ifdef USE_TV
 #include "tv.h"
@@ -199,6 +200,10 @@
     case DEMUXER_TYPE_XMMS:
       demux_close_xmms(demuxer); break;
 #endif
+#ifdef HAVE_GIF
+    case DEMUXER_TYPE_GIF:
+      demux_close_gif(demuxer); break;
+#endif
 
     }
     // free streams:
@@ -276,6 +281,7 @@
 int demux_audio_fill_buffer(demux_stream_t *ds);
 int demux_pva_fill_buffer(demuxer_t *demux);
 int demux_xmms_fill_buffer(demuxer_t *demux,demux_stream_t *ds);
+int demux_gif_fill_buffer(demuxer_t *demux);
 
 extern int demux_demuxers_fill_buffer(demuxer_t *demux,demux_stream_t *ds);
 extern int demux_ogg_fill_buffer(demuxer_t *d);
@@ -322,6 +328,9 @@
     case DEMUXER_TYPE_RTP: return demux_rtp_fill_buffer(demux, ds);
 #endif
     case DEMUXER_TYPE_SMJPEG: return demux_smjpeg_fill_buffer(demux);
+#ifdef HAVE_GIF
+    case DEMUXER_TYPE_GIF: return demux_gif_fill_buffer(demux);
+#endif
   }
   return 0;
 }
@@ -544,6 +553,8 @@
 extern int demux_open_smjpeg(demuxer_t* demuxer);
 extern int bmp_check_file(demuxer_t *demuxer);
 extern int demux_xmms_open(demuxer_t* demuxer);
+extern int gif_check_file(demuxer_t *demuxer);
+extern int demux_open_gif(demuxer_t* demuxer);
 
 extern demuxer_t* init_avi_with_ogg(demuxer_t* demuxer);
 
@@ -748,6 +759,19 @@
       demuxer = NULL;
   }
 }
+#ifdef HAVE_GIF
+//=============== Try to open as GIF file: =================
+if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_GIF){
+  demuxer=new_demuxer(stream,DEMUXER_TYPE_GIF,audio_id,video_id,dvdsub_id);
+  if(gif_check_file(demuxer)){
+      mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_Detected_XXX_FileFormat,"GIF");
+      file_format=DEMUXER_TYPE_GIF;
+  } else {
+      free_demuxer(demuxer);
+      demuxer = NULL;
+  }
+}
+#endif
 //=============== Try to open as BMP file: =================
 if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_BMP){
   demuxer=new_demuxer(stream,DEMUXER_TYPE_BMP,audio_id,video_id,dvdsub_id);
@@ -932,6 +956,12 @@
   if (!demux_open_film(demuxer)) return NULL;
   break;
  }
+#ifdef HAVE_GIF
+ case DEMUXER_TYPE_GIF: {
+  if (!demux_open_gif(demuxer)) return NULL;
+  break;
+ }
+#endif
  case DEMUXER_TYPE_BMP: {
   if (!demux_open_bmp(demuxer)) return NULL;
   break;
diff -Nur main.cvs/libmpdemux/demuxer.h main.wrong_works/libmpdemux/demuxer.h
--- main.cvs/libmpdemux/demuxer.h	Wed Jan 22 10:34:04 2003
+++ main.wrong_works/libmpdemux/demuxer.h	Wed Jan 22 14:15:46 2003
@@ -34,6 +34,7 @@
 #define DEMUXER_TYPE_PVA 23
 #define DEMUXER_TYPE_SMJPEG 24
 #define DEMUXER_TYPE_XMMS 25
+#define DEMUXER_TYPE_GIF 26
 
 // This should always match the higest demuxer type number.
 // Unless you want to disallow users to force the demuxer to some types
diff -Nur main.cvs/libmpdemux/video.c main.wrong_works/libmpdemux/video.c
--- main.cvs/libmpdemux/video.c	Wed Jan 22 10:34:05 2003
+++ main.wrong_works/libmpdemux/video.c	Wed Jan 22 14:15:46 2003
@@ -362,6 +362,9 @@
           // frame_time = 1/25.0;
         }
       }
+      case DEMUXER_TYPE_GIF:
+	  frame_time=d_video->pts-pts1;
+        break;
     }
     
     if(demuxer->file_format==DEMUXER_TYPE_MPEG_PS ||
-------------- next part --------------
diff -Nur main.cvs/libmpdemux/Makefile main.right_broken/libmpdemux/Makefile
--- main.cvs/libmpdemux/Makefile	Wed Jan 22 10:34:04 2003
+++ main.right_broken/libmpdemux/Makefile	Wed Jan 22 14:15:55 2003
@@ -3,7 +3,7 @@
 
 include ../config.mak
 
-SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c
+SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c
 ifeq ($(XMMS_PLUGINS),yes)
 SRCS += demux_xmms.c
 endif 
diff -Nur main.cvs/libmpdemux/demux_gif.c main.right_broken/libmpdemux/demux_gif.c
--- main.cvs/libmpdemux/demux_gif.c	Wed Dec 31 18:00:00 1969
+++ main.right_broken/libmpdemux/demux_gif.c	Wed Jan 22 14:21:26 2003
@@ -0,0 +1,193 @@
+/*
+	GIF file parser for MPlayer
+	by Joey Parrish
+	based on demux_fli.c
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "stream.h"
+#include "demuxer.h"
+#include "stheader.h"
+
+#ifdef HAVE_GIF
+
+#include <gif_lib.h>
+
+static int current_pts = 0;
+
+#define GIF_SIGNATURE (('G' << 16) | ('I' << 8) | 'F')
+
+int gif_check_file(demuxer_t *demuxer)
+{
+  stream_reset(demuxer->stream);
+  stream_seek(demuxer->stream, 0);
+  if (stream_read_int24(demuxer->stream) == GIF_SIGNATURE)
+    return 1;
+  return 0;
+}
+
+int demux_gif_fill_buffer(demuxer_t *demuxer)
+{
+  GifFileType *gif = (GifFileType *)demuxer->priv;
+  sh_video_t *sh_video = (sh_video_t *)demuxer->video->sh;
+  GifRecordType type = UNDEFINED_RECORD_TYPE;
+  int len = 0;
+  demux_packet_t *dp = NULL;
+  ColorMapObject *effective_map = NULL;
+  char *buf = NULL;
+
+  while (type != IMAGE_DESC_RECORD_TYPE) {
+    if (DGifGetRecordType(gif, &type) == GIF_ERROR) {
+      PrintGifError();
+      return 0; // oops
+    }
+    if (type == TERMINATE_RECORD_TYPE)
+      return 0; // eof
+    if (type == SCREEN_DESC_RECORD_TYPE) {
+      if (DGifGetScreenDesc(gif) == GIF_ERROR) {
+        PrintGifError();
+        return 0; // oops
+      }
+    }
+    if (type == EXTENSION_RECORD_TYPE) {
+      int code;
+      unsigned char *p = NULL;
+      if (DGifGetExtension(gif, &code, &p) == GIF_ERROR) {
+        PrintGifError();
+        return 0; // oops
+      }
+      if (code == 0xF9) {
+        int frametime = 0;
+        if (p[0] == 4) // is the length correct?
+          frametime = (p[1] << 8) | p[2]; // set the time, centiseconds
+        current_pts += frametime;
+      } else if ((code == 0xFE) && (verbose)) { // comment extension
+	// print iff verbose
+	printf("GIF comment: ");
+        while (p != NULL) {
+          int length = p[0];
+	  char *comments = p + 1;
+	  comments[length] = 0;
+	  printf("%s", comments);
+          if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) {
+            PrintGifError();
+            return 0; // oops
+          }
+	}
+	printf("\n");
+      // FIXME  support these:
+      } else if (code == 0x01) { // plaintext extension
+      } else if (code == 0xFF) { // application extension
+      }
+      while (p != NULL) {
+        if (DGifGetExtensionNext(gif, &p) == GIF_ERROR) {
+          PrintGifError();
+          return 0; // oops
+        }
+      }
+    }
+  }
+  
+  if (DGifGetImageDesc(gif) == GIF_ERROR) {
+    PrintGifError();
+    return 0; // oops
+  }
+
+  len = gif->Image.Width * gif->Image.Height;
+  dp = new_demux_packet(len * 3);
+  buf = malloc(len);
+  memset(buf, 0, len);
+  memset(dp->buffer, 0, len * 3);
+  
+  if (DGifGetLine(gif, buf, len) == GIF_ERROR) {
+    PrintGifError();
+    return 0; // oops
+  }
+
+  effective_map = gif->Image.ColorMap;
+  if (effective_map == NULL) effective_map = gif->SColorMap;
+
+  {
+    int x;
+    for (x = 0; x < len; x++) {
+      dp->buffer[(x * 3) + 0] = effective_map->Colors[buf[x]].Red;
+      dp->buffer[(x * 3) + 1] = effective_map->Colors[buf[x]].Green;
+      dp->buffer[(x * 3) + 2] = effective_map->Colors[buf[x]].Blue;
+    }
+  }
+
+  free(buf);
+
+  demuxer->video->dpos++;
+  dp->pts = ((float)current_pts) / 100;
+  dp->pos = stream_tell(demuxer->stream);
+  ds_add_packet(demuxer->video, dp);
+
+  return 1;
+}
+
+demuxer_t* demux_open_gif(demuxer_t* demuxer)
+{
+  sh_video_t *sh_video = NULL;
+  GifFileType *gif = NULL;
+
+  current_pts = 0;
+  demuxer->seekable = 0; // FIXME
+
+  // go back to the beginning
+  stream_reset(demuxer->stream);
+  stream_seek(demuxer->stream, 0);
+  lseek(demuxer->stream->fd, 0, SEEK_SET);
+
+  gif = DGifOpenFileHandle(demuxer->stream->fd);
+  if (!gif) {
+    PrintGifError();
+    return NULL;
+  }
+
+  // create a new video stream header
+  sh_video = new_sh_video(demuxer, 0);
+
+  // make sure the demuxer knows about the new video stream header
+  // (even though new_sh_video() ought to take care of it)
+  demuxer->video->sh = sh_video;
+
+  // make sure that the video demuxer stream header knows about its
+  // parent video demuxer stream (this is getting wacky), or else
+  // video_read_properties() will choke
+  sh_video->ds = demuxer->video;
+
+  sh_video->disp_w = gif->SWidth;
+  sh_video->disp_h = gif->SHeight;
+
+  sh_video->format = mmioFOURCC(24, 'B', 'G', 'R');
+  
+  sh_video->fps = 5.0f;
+  sh_video->frametime = 1.0f / sh_video->fps;
+  
+  demuxer->priv = gif;
+
+  return demuxer;
+}
+
+void demux_close_gif(demuxer_t* demuxer)
+{
+  GifFileType *gif = (GifFileType *)demuxer->priv;
+
+  if(!gif)
+    return;
+
+  if (DGifCloseFile(gif) == GIF_ERROR)
+    PrintGifError();
+  
+  demuxer->stream->fd = 0;
+  demuxer->priv = NULL;
+}
+#endif /* HAVE_GIF */
diff -Nur main.cvs/libmpdemux/demuxer.c main.right_broken/libmpdemux/demuxer.c
--- main.cvs/libmpdemux/demuxer.c	Wed Jan 22 10:34:04 2003
+++ main.right_broken/libmpdemux/demuxer.c	Wed Jan 22 14:15:55 2003
@@ -133,6 +133,7 @@
 extern void demux_close_pva(demuxer_t* demuxer);
 extern void demux_close_smjpeg(demuxer_t* demuxer);
 extern void demux_close_xmms(demuxer_t* demuxer);
+extern void demux_close_gif(demuxer_t* demuxer);
 
 #ifdef USE_TV
 #include "tv.h"
@@ -199,6 +200,10 @@
     case DEMUXER_TYPE_XMMS:
       demux_close_xmms(demuxer); break;
 #endif
+#ifdef HAVE_GIF
+    case DEMUXER_TYPE_GIF:
+      demux_close_gif(demuxer); break;
+#endif
 
     }
     // free streams:
@@ -276,6 +281,7 @@
 int demux_audio_fill_buffer(demux_stream_t *ds);
 int demux_pva_fill_buffer(demuxer_t *demux);
 int demux_xmms_fill_buffer(demuxer_t *demux,demux_stream_t *ds);
+int demux_gif_fill_buffer(demuxer_t *demux);
 
 extern int demux_demuxers_fill_buffer(demuxer_t *demux,demux_stream_t *ds);
 extern int demux_ogg_fill_buffer(demuxer_t *d);
@@ -322,6 +328,9 @@
     case DEMUXER_TYPE_RTP: return demux_rtp_fill_buffer(demux, ds);
 #endif
     case DEMUXER_TYPE_SMJPEG: return demux_smjpeg_fill_buffer(demux);
+#ifdef HAVE_GIF
+    case DEMUXER_TYPE_GIF: return demux_gif_fill_buffer(demux);
+#endif
   }
   return 0;
 }
@@ -544,6 +553,8 @@
 extern int demux_open_smjpeg(demuxer_t* demuxer);
 extern int bmp_check_file(demuxer_t *demuxer);
 extern int demux_xmms_open(demuxer_t* demuxer);
+extern int gif_check_file(demuxer_t *demuxer);
+extern int demux_open_gif(demuxer_t* demuxer);
 
 extern demuxer_t* init_avi_with_ogg(demuxer_t* demuxer);
 
@@ -748,6 +759,19 @@
       demuxer = NULL;
   }
 }
+#ifdef HAVE_GIF
+//=============== Try to open as GIF file: =================
+if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_GIF){
+  demuxer=new_demuxer(stream,DEMUXER_TYPE_GIF,audio_id,video_id,dvdsub_id);
+  if(gif_check_file(demuxer)){
+      mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_Detected_XXX_FileFormat,"GIF");
+      file_format=DEMUXER_TYPE_GIF;
+  } else {
+      free_demuxer(demuxer);
+      demuxer = NULL;
+  }
+}
+#endif
 //=============== Try to open as BMP file: =================
 if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_BMP){
   demuxer=new_demuxer(stream,DEMUXER_TYPE_BMP,audio_id,video_id,dvdsub_id);
@@ -932,6 +956,12 @@
   if (!demux_open_film(demuxer)) return NULL;
   break;
  }
+#ifdef HAVE_GIF
+ case DEMUXER_TYPE_GIF: {
+  if (!demux_open_gif(demuxer)) return NULL;
+  break;
+ }
+#endif
  case DEMUXER_TYPE_BMP: {
   if (!demux_open_bmp(demuxer)) return NULL;
   break;
diff -Nur main.cvs/libmpdemux/demuxer.h main.right_broken/libmpdemux/demuxer.h
--- main.cvs/libmpdemux/demuxer.h	Wed Jan 22 10:34:04 2003
+++ main.right_broken/libmpdemux/demuxer.h	Wed Jan 22 14:15:55 2003
@@ -34,6 +34,7 @@
 #define DEMUXER_TYPE_PVA 23
 #define DEMUXER_TYPE_SMJPEG 24
 #define DEMUXER_TYPE_XMMS 25
+#define DEMUXER_TYPE_GIF 26
 
 // This should always match the higest demuxer type number.
 // Unless you want to disallow users to force the demuxer to some types
diff -Nur main.cvs/libmpdemux/video.c main.right_broken/libmpdemux/video.c
--- main.cvs/libmpdemux/video.c	Wed Jan 22 10:34:05 2003
+++ main.right_broken/libmpdemux/video.c	Wed Jan 22 14:15:55 2003
@@ -362,6 +362,9 @@
           // frame_time = 1/25.0;
         }
       }
+      case DEMUXER_TYPE_GIF:
+	  frame_time=d_video->pts-pts1;
+        break;
     }
     
     if(demuxer->file_format==DEMUXER_TYPE_MPEG_PS ||
-------------- next part --------------
diff -ur main.wrong_works/libmpdemux/demux_gif.c main.right_broken/libmpdemux/demux_gif.c
--- main.wrong_works/libmpdemux/demux_gif.c	Wed Jan 22 14:20:20 2003
+++ main.right_broken/libmpdemux/demux_gif.c	Wed Jan 22 14:21:26 2003
@@ -36,9 +36,12 @@
 int demux_gif_fill_buffer(demuxer_t *demuxer)
 {
   GifFileType *gif = (GifFileType *)demuxer->priv;
+  sh_video_t *sh_video = (sh_video_t *)demuxer->video->sh;
   GifRecordType type = UNDEFINED_RECORD_TYPE;
   int len = 0;
   demux_packet_t *dp = NULL;
+  ColorMapObject *effective_map = NULL;
+  char *buf = NULL;
 
   while (type != IMAGE_DESC_RECORD_TYPE) {
     if (DGifGetRecordType(gif, &type) == GIF_ERROR) {
@@ -98,13 +101,30 @@
   }
 
   len = gif->Image.Width * gif->Image.Height;
-  dp = new_demux_packet(len);
+  dp = new_demux_packet(len * 3);
+  buf = malloc(len);
+  memset(buf, 0, len);
+  memset(dp->buffer, 0, len * 3);
   
-  if (DGifGetLine(gif, dp->buffer, len) == GIF_ERROR) {
+  if (DGifGetLine(gif, buf, len) == GIF_ERROR) {
     PrintGifError();
     return 0; // oops
   }
 
+  effective_map = gif->Image.ColorMap;
+  if (effective_map == NULL) effective_map = gif->SColorMap;
+
+  {
+    int x;
+    for (x = 0; x < len; x++) {
+      dp->buffer[(x * 3) + 0] = effective_map->Colors[buf[x]].Red;
+      dp->buffer[(x * 3) + 1] = effective_map->Colors[buf[x]].Green;
+      dp->buffer[(x * 3) + 2] = effective_map->Colors[buf[x]].Blue;
+    }
+  }
+
+  free(buf);
+
   demuxer->video->dpos++;
   dp->pts = ((float)current_pts) / 100;
   dp->pos = stream_tell(demuxer->stream);
@@ -147,7 +167,7 @@
   sh_video->disp_w = gif->SWidth;
   sh_video->disp_h = gif->SHeight;
 
-  sh_video->format = mmioFOURCC('G', 'I', 'F', 'V');
+  sh_video->format = mmioFOURCC(24, 'B', 'G', 'R');
   
   sh_video->fps = 5.0f;
   sh_video->frametime = 1.0f / sh_video->fps;


More information about the MPlayer-dev-eng mailing list