*************************************************************************
*** Applied ***
Date: Sun, 15 Apr 2001 13:30:30 -0700
From: Mo <mo@nospam.com>
Subject: Patch for core dump in MPEG.cpp

I just did an update and noticed a silly little core dump in
the case where a file cannot be found:

% smpeg NOTTHERE
(core)

Here is the fix.

Index: MPEG.cpp
===================================================================
RCS file: /cvs/smpeg/MPEG.cpp,v
retrieving revision 1.25
diff -u -r1.25 MPEG.cpp
--- MPEG.cpp    2001/04/05 20:27:48     1.25
+++ MPEG.cpp    2001/04/15 21:26:11
@@ -151,7 +151,7 @@
   if(audio) delete audio;
   if(system) delete system;
   
-  SDL_RWclose(source);
+  if(source) SDL_RWclose(source);
   if ( mpeg_mem )
     delete[] mpeg_mem;
 }

Mo DeJong
Red Hat Inc
*************************************************************************
*** Applied ***
Date: Fri, 13 Apr 2001 22:57:00 -0400
From: Joe Drew <hoserhead@woot.net>
Subject: Non-encrypted mail; patch for gtv


Basically, I found an unmerged patch for smpeg which stops a segfault in gtv
(when seeking without a file loaded, iirc).. I'll attach it.

Anyhow, ttyl.

--- smpeg-0.4.2.orig/gtv.c
+++ smpeg-0.4.2/gtv.c
@@ -794,9 +794,9 @@
       SMPEG_getinfo( mpeg, info );
       
       SMPEG_seek(mpeg, (int)((info->total_size*adjust->value)/100));
+      SMPEG_getinfo( mpeg, info );
+      gtv_set_frame( raw, info->current_frame );
     }
-    SMPEG_getinfo( mpeg, info );
-    gtv_set_frame( raw, info->current_frame );
 }
 
*************************************************************************
*** Applied ***
Date: Fri, 23 Feb 2001 13:52:45 +0100
From: Andreas Kloeckner <ak@ixion.net>
Subject: [patch] making smpeg use SDL_RWops file read abstraction

Hi,

I've whipped up a patch against current smpeg (0.4.2) to enable it to
use the SDL_RWops file read-write abstraction structure. The patch is 
built in such a way that the SDL_RWops access has now actually become
the way in which file access is handled by smpeg internally. All the
other interfaces like file descriptors and play-from-memory can be
reduced to the SDL_RWops access method, and thusly, have been reworked
to use it.

The binary interface in smpeg.h is unchanged except for the addition
of the function SMPEG_new_rwops(). The C++ interface has changed
slightly, in the following ways:

* only one Init() method in class MPEG remaining
* one constructor (the RWops one) has been added
* the mpeg_fd and autoclose members in MPEG are history
* MPEGsystem's only remaining constructor only takes one RWops.

Binary compatibility is maintained with pre-existing C applications, I
tested this by means of smpeg-xmms.  My patch worked with all the
streams that I tested it with.

Hope you like it,

Andy

Only in smpeg-0.4.2-hacked/: .libs
diff -ur smpeg-0.4.2/MPEG.cpp smpeg-0.4.2-hacked/MPEG.cpp
--- smpeg-0.4.2/MPEG.cpp	Sat Dec  2 00:58:20 2000
+++ smpeg-0.4.2-hacked/MPEG.cpp	Thu Feb 22 17:23:00 2001
@@ -18,58 +18,56 @@
 MPEG::MPEG(const char * name, bool Sdlaudio) :
   MPEGerror()
 {
-  int new_fd;
-
-  new_fd = open(name, O_RDONLY|O_BINARY);
-  close_fd = true;
-
-  if(new_fd == -1)
-  {
-    audio = NULL;
-    video = NULL;
-    system = NULL;
-    close_fd = false;
-    error = NULL;
-
-    audiostream = videostream = NULL;
-    audioaction = NULL;
-    videoaction = NULL;
-    audio = NULL;
-    video = NULL;
-    audioaction_enabled = videoaction_enabled = false;
-    loop = false;
-    pause = false;
-
-    SetError(strerror(errno));
-
+  SDL_RWops *source = SDL_RWFromFile(name,"r");
+  if (!source) {
+    InitErrorState();
+    SetError(SDL_GetError());
     return;
   }
-
-  Init(new_fd, Sdlaudio);
+  Init(source, Sdlaudio);
 }
 
 MPEG::MPEG(int Mpeg_FD, bool Sdlaudio) :
   MPEGerror()
 {
-  close_fd = false;
-  Init(Mpeg_FD, Sdlaudio);
+  // *** FIXME we're leaking a bit of memory for the FILE *
+  // best solution would be to have SDL_RWFromFD
+  FILE *file = fdopen(Mpeg_FD,"r");
+  if (!file) {
+    InitErrorState();
+    SetError(strerror(errno));
+    return;
+  }
+
+  SDL_RWops *source = SDL_RWFromFP(file,false);
+  if (!source) {
+    InitErrorState();
+    SetError(SDL_GetError());
+    return;
+  }
+  Init(source, Sdlaudio);
 }
 
 MPEG::MPEG(void *data, int size, bool Sdlaudio) :
   MPEGerror()
 {
-  close_fd = false;
-  Init(data, size, Sdlaudio);
+  SDL_RWops *temp_source = SDL_RWFromMem(data,size);
+  Init(temp_source, Sdlaudio);
 }
 
-void MPEG::Init(int Mpeg_FD, bool Sdlaudio)
+MPEG::MPEG(SDL_RWops *mpeg_source,bool sdlaudio = true) :
+  MPEGerror()
 {
-    mpeg_fd = Mpeg_FD;
+  Init(mpeg_source, sdlaudio);
+}
 
+void MPEG::Init(SDL_RWops *mpeg_source,bool Sdlaudio)
+{
+    source = mpeg_source;
     sdlaudio = Sdlaudio;
 
     /* Create the system that will parse the MPEG stream */
-    system = new MPEGsystem(Mpeg_FD);
+    system = new MPEGsystem(source);
 
     /* Initialize everything to invalid values for cleanup */
     error = NULL;
@@ -109,14 +107,10 @@
     }
 }
 
-void MPEG::Init(void *data, int size, bool Sdlaudio)
-{
-    sdlaudio = Sdlaudio;
-
-    /* Create the system that will parse the MPEG stream */
-    system = new MPEGsystem(data, size);
-
-    /* Initialize everything to invalid values for cleanup */
+void MPEG::InitErrorState() {
+    audio = NULL;
+    video = NULL;
+    system = NULL;
     error = NULL;
 
     audiostream = videostream = NULL;
@@ -127,31 +121,6 @@
     audioaction_enabled = videoaction_enabled = false;
     loop = false;
     pause = false;
-
-    parse_stream_list();
-
-    EnableAudio(audioaction_enabled);
-    EnableVideo(videoaction_enabled);
-
-    if ( ! audiostream && ! videostream ) {
-      SetError("No audio/video stream found in MPEG");
-    }
-
-    if ( system && system->WasError() ) {
-      SetError(system->TheError());
-    }
-
-    if ( audio && audio->WasError() ) {
-      SetError(audio->TheError());
-    }
-
-    if ( video && video->WasError() ) {
-      SetError(video->TheError());
-    }
-
-    if ( WasError() ) {
-      SetError(TheError());
-    }
 }
 
 MPEG::~MPEG()
@@ -160,10 +129,8 @@
   if(video) delete video;
   if(audio) delete audio;
   if(system) delete system;
-
-  if ( close_fd && mpeg_fd ) {
-    close(mpeg_fd);
-  }
+  
+  SDL_RWclose(source);
 }
 
 bool MPEG::AudioEnabled(void) {
Only in smpeg-0.4.2-hacked/: MPEG.cpp~
diff -ur smpeg-0.4.2/MPEG.h smpeg-0.4.2-hacked/MPEG.h
--- smpeg-0.4.2/MPEG.h	Wed Oct  4 19:29:25 2000
+++ smpeg-0.4.2-hacked/MPEG.h	Thu Feb 22 17:08:47 2001
@@ -53,11 +53,12 @@
     MPEG(const char * name, bool sdlaudio = true);
     MPEG(int Mpeg_FD, bool sdlaudio = true);
     MPEG(void *data, int size, bool sdlaudio = true);
+    MPEG(SDL_RWops *mpeg_source,bool sdlaudio = true);
     virtual ~MPEG();
 
     /* Initialize the MPEG */
-    void Init(int Mpeg_FD, bool Sdlaudio);
-    void Init(void *data, int size, bool Sdlaudio);
+    void Init(SDL_RWops *mpeg_source, bool Sdlaudio);
+    void InitErrorState();
 
     /* Enable/Disable audio and video */
     bool AudioEnabled(void);
@@ -102,9 +103,7 @@
     MPEGsystem * system;
 
 protected:
-    int mpeg_fd;
-    bool close_fd;
-
+    SDL_RWops *source;
     MPEGaudioaction *audioaction;
     MPEGvideoaction *videoaction;
 
Only in smpeg-0.4.2-hacked/: MPEG.h~
Only in smpeg-0.4.2-hacked/: MPEG.lo
Only in smpeg-0.4.2-hacked/: MPEG.o
Only in smpeg-0.4.2-hacked/: MPEGfilter.lo
Only in smpeg-0.4.2-hacked/: MPEGfilter.o
Only in smpeg-0.4.2-hacked/: MPEGlist.lo
Only in smpeg-0.4.2-hacked/: MPEGlist.o
Only in smpeg-0.4.2-hacked/: MPEGring.lo
Only in smpeg-0.4.2-hacked/: MPEGring.o
Only in smpeg-0.4.2-hacked/: MPEGstream.lo
Only in smpeg-0.4.2-hacked/: MPEGstream.o
diff -ur smpeg-0.4.2/MPEGsystem.cpp smpeg-0.4.2-hacked/MPEGsystem.cpp
--- smpeg-0.4.2/MPEGsystem.cpp	Mon Dec  4 21:25:36 2000
+++ smpeg-0.4.2-hacked/MPEGsystem.cpp	Thu Feb 22 17:52:41 2001
@@ -387,9 +387,9 @@
   return(header_size);
 }
 
-MPEGsystem::MPEGsystem(int Mpeg_FD)
+MPEGsystem::MPEGsystem(SDL_RWops *mpeg_source)
 {
-  mpeg_fd = Mpeg_FD;
+  source = mpeg_source;
 
   /* Create a new buffer for reading */
   read_buffer = new Uint8[MPEG_BUFFER_SIZE];
@@ -398,13 +398,6 @@
   system_mutex = SDL_CreateMutex();
   request_wait = SDL_CreateSemaphore(0);
 
-  /*
-     We are not being passed data, so we don't need to simulate
-     file access.  Might something like MikMod's abstraction of
-     read/seek/tell be appropriate?
-   */
-  data_reader.fromData = false;
-
   /* Invalidate the read buffer */
   pointer = read_buffer;
   read_size = 0;
@@ -460,82 +453,6 @@
 	!Eof());
 }
 
-MPEGsystem::MPEGsystem(void *data, int size)
-{
-  /* Create a new buffer for reading */
-  read_buffer = new Uint8[MPEG_BUFFER_SIZE];
-
-  /* Create a mutex to avoid concurrent access to the stream */
-  system_mutex = SDL_CreateMutex();
-  request_wait = SDL_CreateSemaphore(0);
-
-  /* 
-     Our argument list indicates that we are being passed data, 
-     so we copy it and setup the data_reader data structure.
-    */
-  data_reader.fromData = true;
-  data_reader.data = malloc(size);
-  data_reader.size = size;
-  data_reader.offset = 0;
-
-  memcpy(data_reader.data, data, size);
-
-  /* Invalidate the read buffer */
-  pointer = read_buffer;
-  read_size = 0;
-  read_total = 0;
-  packet_total = 0;
-  endofstream = errorstream = false;
-  looping = false;
-  frametime = 0.0;
-  stream_timestamp = 0.0;
-
-  /* Create an empty stream list */
-  stream_list = 
-    (MPEGstream **) malloc(sizeof(MPEGstream *));
-  stream_list[0] = 0;
-
-  /* Create the system stream and add it to the list */
-  if(!get_stream(SYSTEM_STREAMID))
-    add_stream(new MPEGstream(this, SYSTEM_STREAMID));
-
-  timestamp = 0.0;
-  timedrift = 0.0;
-  skip_timestamp = -1;
-  system_thread_running = false;
-  system_thread = 0;
-
-  /* Search the MPEG for the first header */
-  if(!seek_first_header())
-  {
-    errorstream = true;
-    SetError("Could not find the beginning of MPEG data\n");
-    return;
-  }
-
-#ifdef USE_SYSTEM_THREAD
-  /* Start the system thread */
-  system_thread = SDL_CreateThread(SystemThread, this);
-
-  /* Wait for the thread to start */
-  while(!system_thread_running && !Eof())
-    SDL_Delay(1);
-#else
-  system_thread_running = true;
-#endif
-
-  /* Look for streams */
-  do
-  {
-    RequestBuffer();
-    Wait();
-  }
-  while(!exist_stream(VIDEO_STREAMID, 0xF0) &&
-	!exist_stream(AUDIO_STREAMID, 0xF0) &&
-	!Eof());
-}
-
-
 MPEGsystem::~MPEGsystem()
 {
   MPEGstream ** list;
@@ -586,77 +503,47 @@
     /* Replace unread data at the beginning of the stream */
     memmove(read_buffer, pointer, remaining);
 
-    if(data_reader.fromData == true)
-    {
-      /*
-         We were initialized from a chunk of data, so we simulate
-	 the read call
-       */
-
-       int size = READ_ALIGN(MPEG_BUFFER_SIZE - remaining);
-       char *frombuf = (char *) data_reader.data;
-
-       if(data_reader.offset > data_reader.size)
-       {
-         read_size = 0;
-       }
-       else 
-       {
-         if(data_reader.offset + size > data_reader.size)
-         {
-           size = data_reader.size - data_reader.offset;
-         }
-
-         frombuf += data_reader.offset;
-
-         memcpy(read_buffer + remaining, frombuf, size);
-
-         data_reader.offset += size;
-         read_size = size;
-       }
-    } else {
 #ifdef NO_GRIFF_MODS
-        read_size = read(mpeg_fd,
-                        read_buffer + remaining, 
-                        READ_ALIGN(MPEG_BUFFER_SIZE - remaining));
-	if(read_size < 0)
-	{
-	  perror("Read");
-	  errorstream = true;
-	  SDL_mutexV(system_mutex);
-	  return;
-	}
+    read_size = SDL_RWread(source,
+                    read_buffer + remaining, 
+                    READ_ALIGN(MPEG_BUFFER_SIZE - remaining));
+    if(read_size < 0)
+    {
+      perror("Read");
+      errorstream = true;
+      SDL_mutexV(system_mutex);
+      return;
+    }
 #else
-	/* Read new data */
-	int bytes_read    = 0;
-	int buffer_offset = remaining;
-	int bytes_to_read = READ_ALIGN(MPEG_BUFFER_SIZE - remaining);
-	int read_at_once = 0;
+    /* Read new data */
+    int bytes_read    = 0;
+    int buffer_offset = remaining;
+    int bytes_to_read = READ_ALIGN(MPEG_BUFFER_SIZE - remaining);
+    int read_at_once = 0;
 
-	read_size = 0;
-	do
-	{
-	  read_at_once = 
-	    read(mpeg_fd, read_buffer + buffer_offset, bytes_to_read );
+    read_size = 0;
+    do
+    {
+      read_at_once = 
+        SDL_RWread(source, read_buffer + buffer_offset, 1, bytes_to_read );
 
-	  if(read_at_once < 0)
-	  {
-	    perror("Read");
-	    errorstream = true;
-	    SDL_mutexV(system_mutex);
-	    return;
-	  }
-	  else
-	  {
-	    bytes_read    += read_at_once;
-	    buffer_offset += read_at_once;
-	    read_size     += read_at_once;
-	    bytes_to_read -= read_at_once;
-	  }
-	}
-	while( read_at_once>0 && bytes_to_read>0 );
-#endif
+      if(read_at_once < 0)
+      {
+        perror("Read");
+        errorstream = true;
+        SDL_mutexV(system_mutex);
+        return;
+      }
+      else
+      {
+        bytes_read    += read_at_once;
+        buffer_offset += read_at_once;
+        read_size     += read_at_once;
+        bytes_to_read -= read_at_once;
+      }
     }
+    while( read_at_once>0 && bytes_to_read>0 );
+#endif
 
     read_total += read_size;
 
@@ -1001,21 +888,12 @@
   off_t size;
   off_t pos;
 
-  if(data_reader.fromData == true)
-  {
-    /*
-       we are using simulated data access routines, so we know in advance
-       what the size is.
-     */
-    return data_reader.size;
-  }
-
   /* Lock to avoid concurrent access to the stream */
   SDL_mutexP(system_mutex);
 
   /* I made it this way (instead of fstat) to avoid #ifdef WIN32 everywhere */
   /* in case 'in some weird perversion of nature' someone wants to port this to Win32 :-) */
-  if((pos = lseek(mpeg_fd, 0, SEEK_CUR)) < 0)
+  if((pos = SDL_RWtell(source)) < 0)
   {
     if(errno != ESPIPE)
     {
@@ -1026,7 +904,7 @@
     return(0);
   }
 
-  if((size = lseek(mpeg_fd, 0, SEEK_END)) < 0)
+  if((size = SDL_RWseek(source, 0, SEEK_END)) < 0)
   {
     if(errno != ESPIPE)
     {
@@ -1037,7 +915,7 @@
     return(0);
   }
   
-  if((pos = lseek(mpeg_fd, pos, SEEK_SET)) < 0)
+  if((pos = SDL_RWseek(source, pos, SEEK_SET)) < 0)
   {
     if(errno != ESPIPE)
     {
@@ -1063,21 +941,17 @@
   SDL_mutexP(system_mutex);
 
   /* Save current position */
-  if(data_reader.fromData == true) {
-	  /* from data, no lseek needed */
-	  pos = data_reader.offset;
-  } else {
-	  if((pos = lseek(mpeg_fd, 0, SEEK_CUR)) < 0)
-	  {
-	    if(errno != ESPIPE)
-	    {
-	      errorstream = true;
-	      SetError(strerror(errno));
-	    }
-	    SDL_mutexV(system_mutex);
-	    return(false);
-	  }
+  if((pos = SDL_RWtell(source)) < 0)
+  {
+    if(errno != ESPIPE)
+    {
+      errorstream = true;
+      SetError(strerror(errno));
+    }
+    SDL_mutexV(system_mutex);
+    return(false);
   }
+
   file_ptr = 0;
   buffer = new Uint8[MPEG_BUFFER_SIZE];
 
@@ -1087,43 +961,18 @@
   {
     do
     {
-      if(data_reader.fromData == true) {
-	      data_reader.offset += file_ptr;
-	      size = data_reader.offset;
-      }
-      else {
-	      if((size = lseek(mpeg_fd, file_ptr, SEEK_SET)) < 0)
-	      {
-		if(errno != ESPIPE)
-		{
-		  errorstream = true;
-		  SetError(strerror(errno));  
-		}
-		SDL_mutexV(system_mutex);
-		return(false);
-	      }
+      if((size = SDL_RWseek(source, file_ptr, SEEK_SET)) < 0)
+      {
+        if(errno != ESPIPE)
+        {
+          errorstream = true;
+          SetError(strerror(errno));  
+        }
+        SDL_mutexV(system_mutex);
+        return(false);
       }
     
-      if(data_reader.fromData == true) {
-	      char *dataptr = (char *) data_reader.data;
-	      int size = MPEG_BUFFER_SIZE;
-
-	      if(data_reader.offset + size > data_reader.size) {
-                  size = data_reader.size - data_reader.offset;
-	      }
-
-              if(size >= 0) {
-                  dataptr += size;
-      
-                  memcpy(buffer, dataptr, size);
-      
-                  data_reader.offset += size;
-             } else {
-		     break;
-	     }
-      } else {
-        if(read(mpeg_fd, buffer, MPEG_BUFFER_SIZE) < 0) break;
-      }
+      if(SDL_RWread(source, buffer, 1, MPEG_BUFFER_SIZE) < 0) break;
 
       /* Search for a valid audio header */
       for(p = buffer; p < buffer + MPEG_BUFFER_SIZE; p++)
@@ -1152,33 +1001,18 @@
     /* Otherwise search the stream backwards for a valid header */
       file_ptr -= MPEG_BUFFER_SIZE;
       
-      if(data_reader.fromData == true) {
-	      data_reader.offset = data_reader.size - file_ptr;
-	      size = data_reader.offset;
-      } else {
-	      if((size = lseek(mpeg_fd, file_ptr, SEEK_END)) < 0)
-	      {
-		if(errno != ESPIPE)
-		{
-		  errorstream = true;
-		  SetError(strerror(errno));  
-		}
-		SDL_mutexV(system_mutex);
-		return(false);
-	      }
+      if((size = SDL_RWseek(source, file_ptr, SEEK_END)) < 0)
+      {
+        if(errno != ESPIPE)
+        {
+          errorstream = true;
+          SetError(strerror(errno));  
+        }
+        SDL_mutexV(system_mutex);
+        return(false);
       }
       
-      if(data_reader.fromData == true) {
-        char *dataptr = (char *) data_reader.data;
-
-        dataptr += data_reader.offset;
-
-        memcpy(buffer, dataptr, MPEG_BUFFER_SIZE);
-
-        data_reader.offset += MPEG_BUFFER_SIZE;
-      } else {
-        if(read(mpeg_fd, buffer, MPEG_BUFFER_SIZE) < 0) break;
-      }
+      if(SDL_RWread(source, buffer, 1, MPEG_BUFFER_SIZE) < 0) break;
       
       if(stream_list[0]->streamid == SYSTEM_STREAMID)
 	for(p = buffer + MPEG_BUFFER_SIZE - 1; p >= buffer;)
@@ -1213,20 +1047,16 @@
 
   delete buffer;
 
-  if(data_reader.fromData == true) {
-      data_reader.offset = pos;
-  } else {
-      /* Get back to saved position */
-      if((pos = lseek(mpeg_fd, pos, SEEK_SET)) < 0)
-      {
-        if(errno != ESPIPE)
-        {
-          errorstream = true;
-          SetError(strerror(errno));  
-        }
-        SDL_mutexV(system_mutex);
-        return(0);
-      }
+  /* Get back to saved position */
+  if((pos = SDL_RWseek(source, pos, SEEK_SET)) < 0)
+  {
+    if(errno != ESPIPE)
+    {
+      errorstream = true;
+      SetError(strerror(errno));  
+    }
+    SDL_mutexV(system_mutex);
+    return(0);
   }
 
   SDL_mutexV(system_mutex);
@@ -1247,19 +1077,15 @@
   /* Lock to avoid concurrent access to the stream */
   SDL_mutexP(system_mutex);
   
-  if(data_reader.fromData == true) {
-    data_reader.offset = length;
-  } else {
-    /* Get into the stream */
-    if(lseek(mpeg_fd, length, SEEK_SET) < 0)
+  /* Get into the stream */
+  if(SDL_RWseek(source, length, SEEK_SET) < 0)
+  {
+    if(errno != ESPIPE)
     {
-      if(errno != ESPIPE)
-      {
-        errorstream = true;
-        SetError(strerror(errno));
-      }
-      return(false);
+      errorstream = true;
+      SetError(strerror(errno));
     }
+    return(false);
   }
 
   /* Reinitialize the read buffer */
@@ -1359,20 +1185,15 @@
     /* Set the eof mark on all streams */
     system->end_all_streams();
 
-    if(system->data_reader.fromData == true)
+    /* Get back to the beginning of the stream if possible */
+    if(SDL_RWseek(system->source, 0, SEEK_SET) < 0)
     {
-      system->data_reader.offset = 0;
-    } else {
-      /* Get back to the beginning of the stream if possible */
-      if(lseek(system->mpeg_fd, 0, SEEK_SET) < 0)
+      if(errno != ESPIPE)
       {
-	if(errno != ESPIPE)
-	{
-	  system->errorstream = true;
-	  system->SetError(strerror(errno));
-	}
-        return(false);
+        system->errorstream = true;
+        system->SetError(strerror(errno));
       }
+      return(false);
     }
 
     /* Reinitialize the read buffer */
Only in smpeg-0.4.2-hacked/: MPEGsystem.cpp~
diff -ur smpeg-0.4.2/MPEGsystem.h smpeg-0.4.2-hacked/MPEGsystem.h
--- smpeg-0.4.2/MPEGsystem.h	Mon Dec  4 20:41:58 2000
+++ smpeg-0.4.2-hacked/MPEGsystem.h	Thu Feb 22 17:07:50 2001
@@ -19,8 +19,7 @@
 class MPEGsystem : public MPEGerror
 {
 public:
-    MPEGsystem(int MPEG_Fd);
-    MPEGsystem(void *data, int size);
+    MPEGsystem(SDL_RWops *mpeg_source);
     virtual ~MPEGsystem();
 
     /* Buffered I/O functions */
@@ -79,16 +78,7 @@
     /* The system thread which fills the FIFO */
     static int SystemThread(void * udata);
 
-    struct {
-    	bool fromData;
-
-	int size;
-	int offset;
-
-	void *data;
-    } data_reader;
-
-    int mpeg_fd;
+    SDL_RWops *source;
 
     SDL_Thread * system_thread;
     bool system_thread_running;
Only in smpeg-0.4.2-hacked/: MPEGsystem.h~
Only in smpeg-0.4.2-hacked/: MPEGsystem.lo
Only in smpeg-0.4.2-hacked/: MPEGsystem.o
Only in smpeg-0.4.2-hacked/: Makefile
Only in smpeg-0.4.2-hacked/audio: .libs
Only in smpeg-0.4.2-hacked/audio: MPEGaudio.lo
Only in smpeg-0.4.2-hacked/audio: MPEGaudio.o
Only in smpeg-0.4.2-hacked/audio: Makefile
Only in smpeg-0.4.2-hacked/audio: bitwindow.lo
Only in smpeg-0.4.2-hacked/audio: bitwindow.o
Only in smpeg-0.4.2-hacked/audio: filter.lo
Only in smpeg-0.4.2-hacked/audio: filter.o
Only in smpeg-0.4.2-hacked/audio: filter_2.lo
Only in smpeg-0.4.2-hacked/audio: filter_2.o
Only in smpeg-0.4.2-hacked/audio: huffmantable.lo
Only in smpeg-0.4.2-hacked/audio: huffmantable.o
Only in smpeg-0.4.2-hacked/audio: libaudio.la
Only in smpeg-0.4.2-hacked/audio: mpeglayer1.lo
Only in smpeg-0.4.2-hacked/audio: mpeglayer1.o
Only in smpeg-0.4.2-hacked/audio: mpeglayer2.lo
Only in smpeg-0.4.2-hacked/audio: mpeglayer2.o
Only in smpeg-0.4.2-hacked/audio: mpeglayer3.lo
Only in smpeg-0.4.2-hacked/audio: mpeglayer3.o
Only in smpeg-0.4.2-hacked/audio: mpegtable.lo
Only in smpeg-0.4.2-hacked/audio: mpegtable.o
Only in smpeg-0.4.2-hacked/audio: mpegtoraw.lo
Only in smpeg-0.4.2-hacked/audio: mpegtoraw.o
Only in smpeg-0.4.2-hacked/: config.cache
Only in smpeg-0.4.2-hacked/: config.log
Only in smpeg-0.4.2-hacked/: config.status
Only in smpeg-0.4.2-hacked/: glmovie
Only in smpeg-0.4.2-hacked/: glmovie-tile.o
Only in smpeg-0.4.2-hacked/: glmovie.o
Only in smpeg-0.4.2-hacked/: gtv
Only in smpeg-0.4.2-hacked/: gtv.o
Only in smpeg-0.4.2-hacked/: libsmpeg.la
Only in smpeg-0.4.2-hacked/: libtool
Only in smpeg-0.4.2-hacked/: plaympeg
Only in smpeg-0.4.2-hacked/: plaympeg.o
Only in smpeg-0.4.2-hacked/: smpeg-config
diff -ur smpeg-0.4.2/smpeg.cpp smpeg-0.4.2-hacked/smpeg.cpp
--- smpeg-0.4.2/smpeg.cpp	Thu Oct  5 21:58:08 2000
+++ smpeg-0.4.2-hacked/smpeg.cpp	Thu Feb 22 17:01:20 2001
@@ -90,6 +90,21 @@
     return(mpeg);
 }
 
+SMPEG* SMPEG_new_rwops(SDL_RWops *src, SMPEG_Info* info, int sdl_audio)
+{
+    SMPEG *mpeg;
+
+    /* Create a new SMPEG object! */
+    mpeg = new SMPEG;
+    mpeg->obj = new MPEG(src, sdl_audio ? true : false);
+
+    /* Find out the details of the stream, if requested */
+    SMPEG_getinfo(mpeg, info);
+
+    /* We're done! */
+    return(mpeg);
+}
+
 /* Get current information about an SMPEG object */
 void SMPEG_getinfo( SMPEG* mpeg, SMPEG_Info* info )
 {
Only in smpeg-0.4.2-hacked/: smpeg.cpp~
diff -ur smpeg-0.4.2/smpeg.h smpeg-0.4.2-hacked/smpeg.h
--- smpeg-0.4.2/smpeg.h	Thu Oct  5 21:56:46 2000
+++ smpeg-0.4.2-hacked/smpeg.h	Thu Feb 22 16:40:55 2001
@@ -104,6 +104,9 @@
  */
 extern DECLSPEC SMPEG* SMPEG_new_data(void *data, int size, SMPEG_Info* info, int sdl_audio);
 
+/* The same for a generic SDL_RWops structure. */
+extern DECLSPEC SMPEG* SMPEG_new_rwops(SDL_RWops *src, SMPEG_Info* info, int sdl_audio);
+
 /* Get current information about an SMPEG object */
 extern DECLSPEC void SMPEG_getinfo( SMPEG* mpeg, SMPEG_Info* info );
 
Only in smpeg-0.4.2-hacked/: smpeg.h~
Only in smpeg-0.4.2-hacked/: smpeg.lo
Only in smpeg-0.4.2-hacked/: smpeg.o
Only in smpeg-0.4.2-hacked/: smpeg.spec
Only in smpeg-0.4.2-hacked/video: .libs
Only in smpeg-0.4.2-hacked/video: MPEGvideo.lo
Only in smpeg-0.4.2-hacked/video: MPEGvideo.o
Only in smpeg-0.4.2-hacked/video: Makefile
Only in smpeg-0.4.2-hacked/video: decoders.lo
Only in smpeg-0.4.2-hacked/video: decoders.o
Only in smpeg-0.4.2-hacked/video: floatdct.lo
Only in smpeg-0.4.2-hacked/video: floatdct.o
Only in smpeg-0.4.2-hacked/video: gdith.lo
Only in smpeg-0.4.2-hacked/video: gdith.o
Only in smpeg-0.4.2-hacked/video: jrevdct.lo
Only in smpeg-0.4.2-hacked/video: jrevdct.o
Only in smpeg-0.4.2-hacked/video: libvideo.la
Only in smpeg-0.4.2-hacked/video: mmxflags_asm.lo
Only in smpeg-0.4.2-hacked/video: mmxflags_asm.o
Only in smpeg-0.4.2-hacked/video: mmxidct_asm.lo
Only in smpeg-0.4.2-hacked/video: mmxidct_asm.o
Only in smpeg-0.4.2-hacked/video: motionvector.lo
Only in smpeg-0.4.2-hacked/video: motionvector.o
Only in smpeg-0.4.2-hacked/video: parseblock.lo
Only in smpeg-0.4.2-hacked/video: parseblock.o
Only in smpeg-0.4.2-hacked/video: readfile.lo
Only in smpeg-0.4.2-hacked/video: readfile.o
Only in smpeg-0.4.2-hacked/video: util.lo
Only in smpeg-0.4.2-hacked/video: util.o
Only in smpeg-0.4.2-hacked/video: vhar128.lo
Only in smpeg-0.4.2-hacked/video: vhar128.o
Only in smpeg-0.4.2-hacked/video: video.lo
Only in smpeg-0.4.2-hacked/video: video.o
*************************************************************************
*** Applied ***
Date: Fri, 2 Mar 2001 20:29:54 -0500
From: Joe Drew <hoserhead@woot.net>
Subject: Debian smpeg, smpeg-xmms packages, and the fix for audio not updating current time

After some playing around and thinking, I know now why this happens. 

TimeElapsed() is TotalTime modified for the audio case. However, for the 
video/system stream case, it is the same: it extracts the time information
from the MPEG header. The problem is, when playing MPEG video, the audio
case isn't used, so when we recalculate the time elapsed on the audio
stream, it actually returns the total time (that the video/system stream 
gives it). So, the current_time for audio is set to the total length
of the MPEG stream, and the system carries merrily on its little way.
Of course, SMPEG notices that the video and audio are horribly out of sync,
starts skipping frames, and now everything is out of whack.

I think, therefore, that it only makes sense to calculate TimeElapsed for
audio streams without video. That's what this patch does. I've tested
it with mpg321 and smpeg-xmms, and it seems to work. I don't know if it
will break on really odd MPEG streams; for the few MPEGs I have on my
computer (from Heretic 2, really) it seems to work fine, though.

Incidentally, TimeElapsed() was entirely worthless on video anyways; it
would ALWAYS return the total time, regardless of what it was.

As well, after looking through the code more, I found that setCurrentTime()
was completely useless - ResetSynchro does the same job. So that's gone too.

This patch is against current CVS.

Please test it!

...

I'm now the smpeg and smpeg-xmms maintainer for Debian, so I'll be handling
bugreports/etc for these packages. 

Thinking about my fix (attached again, just in case you haven't gotten it:
I haven't heard from either of you), it's pretty much a hack. I don't
understand all the MPEG parsing code, but it's quite obvious to me that
since mpeg video (apparently) keeps state information (ie, how far into
the stream you are) in the packet headers, the stream object gets its
timestamp set to that (correct) time. Everything is happy, then, because
the right time is in all the right places.

The bug is because either mpeg audio doesn't store state information, or
we don't calculate it. In either case, it's beyond me. The patch I attach
works, and smpeg-xmms works fine with it applied. Sam, if you feel comfortable
putting it in, I'd appreciate it. It is definitely not the Correct fix, but
for now the Correct fix is beyond my abilities. What's more, it does fix
the bug, and doesn't impact those not hurt by it. I'd say it's worth applying
just as a stop-gap measure. (It will be applied to the debian smpeg
packages, regardless.)

Thanks,
Joe

diff --recursive -u smpeg-0.4.2/MPEG.cpp smpeg-0.4.2.new/MPEG.cpp
--- smpeg-0.4.2/MPEG.cpp	Fri Dec  1 18:58:20 2000
+++ smpeg-0.4.2.new/MPEG.cpp	Sun Feb 18 15:04:14 2001
@@ -420,8 +420,14 @@
     while(videostream->time() == -1)
       videostream->next_packet();
 
+  /* Calculating current play time on audio only makes sense when there
+     is no video */  
+  if ( audioaction && !videoaction) {
+    audioaction->Rewind();
+    audioaction->ResetSynchro(system->TimeElapsedAudio(position));
+  }
   /* And forget what we previouly buffered */
-  if ( audioaction ) {
+  else if ( audioaction ) {
     audioaction->Rewind();
     audioaction->ResetSynchro(audiostream->time());
   }
diff --recursive -u smpeg-0.4.2/MPEGsystem.cpp smpeg-0.4.2.new/MPEGsystem.cpp
--- smpeg-0.4.2/MPEGsystem.cpp	Mon Dec  4 15:25:36 2000
+++ smpeg-0.4.2.new/MPEGsystem.cpp	Sun Feb 18 14:47:50 2001
@@ -1231,6 +1231,133 @@
 
   SDL_mutexV(system_mutex);
 
+  return(time);
+}
+
+double MPEGsystem::TimeElapsedAudio(int atByte)
+{
+  off_t size, pos;
+  off_t file_ptr;
+  Uint8 * buffer, * p;
+  double time;
+  
+  if (atByte < 0)
+  {
+      return -1;
+  }
+  
+  /* Lock to avoid concurrent access to the stream */
+  SDL_mutexP(system_mutex);
+
+  /* Save current position */
+  if(data_reader.fromData == true) {
+	  /* from data, no lseek needed */
+	  pos = data_reader.offset;
+  } else {
+	  if((pos = lseek(mpeg_fd, 0, SEEK_CUR)) < 0)
+	  {
+	    if(errno != ESPIPE)
+	    {
+	      errorstream = true;
+	      SetError(strerror(errno));
+	    }
+	    SDL_mutexV(system_mutex);
+	    return(false);
+	  }
+  }
+  file_ptr = 0;
+  buffer = new Uint8[MPEG_BUFFER_SIZE];
+
+  /* If audio, compute total time according to bitrate of the first header and total size */
+  /* Note: this doesn't work on variable bitrate streams */
+  if(stream_list[0]->streamid == AUDIO_STREAMID)
+  {
+    do
+    {
+      if(data_reader.fromData == true) {
+	      data_reader.offset += file_ptr;
+	      size = data_reader.offset;
+      }
+      else {
+	      if((size = lseek(mpeg_fd, file_ptr, SEEK_SET)) < 0)
+	      {
+		if(errno != ESPIPE)
+		{
+		  errorstream = true;
+		  SetError(strerror(errno));  
+		}
+		SDL_mutexV(system_mutex);
+		return(false);
+	      }
+      }
+    
+      if(data_reader.fromData == true) {
+	      char *dataptr = (char *) data_reader.data;
+	      int size = MPEG_BUFFER_SIZE;
+
+	      if(data_reader.offset + size > data_reader.size) {
+                  size = data_reader.size - data_reader.offset;
+	      }
+
+              if(size >= 0) {
+                  dataptr += size;
+      
+                  memcpy(buffer, dataptr, size);
+      
+                  data_reader.offset += size;
+             } else {
+		     break;
+	     }
+      } else {
+        if(read(mpeg_fd, buffer, MPEG_BUFFER_SIZE) < 0) break;
+      }
+
+      /* Search for a valid audio header */
+      for(p = buffer; p < buffer + MPEG_BUFFER_SIZE; p++)
+	if(audio_aligned(p, buffer + MPEG_BUFFER_SIZE - p)) break;
+    
+      file_ptr += MPEG_BUFFER_SIZE;
+    }
+    while(p >= MPEG_BUFFER_SIZE + buffer);
+
+    /* Extract time info from the first header */
+    Uint32 framesize;
+    double frametime;
+    Uint32 totalsize;
+
+    audio_header(p, &framesize, &frametime);
+    totalsize = TotalSize();
+    if(framesize)
+      //is there a better way to do this?
+      time = (frametime * (atByte ? atByte:totalsize)) / framesize;
+    else
+      time = 0;
+  }
+  else
+  //This is not a purely audio stream. This doesn't make sense!
+  {
+      time = -1;
+  }
+
+  delete buffer;
+
+  if(data_reader.fromData == true) {
+      data_reader.offset = pos;
+  } else {
+      /* Get back to saved position */
+      if((pos = lseek(mpeg_fd, pos, SEEK_SET)) < 0)
+      {
+        if(errno != ESPIPE)
+        {
+          errorstream = true;
+          SetError(strerror(errno));  
+        }
+        SDL_mutexV(system_mutex);
+        return(0);
+      }
+  }
+
+  SDL_mutexV(system_mutex);
   return(time);
 }
 
diff --recursive -u smpeg-0.4.2/MPEGsystem.h smpeg-0.4.2.new/MPEGsystem.h
--- smpeg-0.4.2/MPEGsystem.h	Mon Dec  4 14:41:58 2000
+++ smpeg-0.4.2.new/MPEGsystem.h	Sun Feb 18 14:23:59 2001
@@ -35,6 +35,7 @@
     bool Seek(int length);
     Uint32 TotalSize();
     double TotalTime();
+    double TimeElapsedAudio(int atByte);
 
     /* Skip "seconds" seconds */
     void Skip(double seconds);
*************************************************************************
*** Applied ***
Date: Wed, 14 Feb 2001 14:54:26 +0100
From: Michel Darricau <mdarricau@eprocess.fr>
Subject: Re: RTSP/MPEG1 Player

Hi,

I have created a patch for some files from the smpeg library for the
popcorn player...

Theses modifications have several goals :
        * declare some methods in the library for override.
        * create empty constructors for MPEG and MPEGsystem classes
        * change the Status method name for GetStatus to prevent some problem
with xmms pluggin sheme
        * I have force the #define USE_SYSTEM_THREAD in the MPEGsystem.cpp for
best results...

Thanks in advance to accept this patch. Comments are welcome!

To see the overrides methods, you can download the popcorn project and
see in the src directory... 

Michel Darricau
eProcess

David Olivari wrote:
> 
> eProcess, a french software company specialized in embedded multimedia
> solutions, announces the release of popCorn, an open source MPEG-1
> streaming player for Linux based on SMPEG and libwww.
> 
> popCorn is a desktop-oriented MPEG-1 audio (MP3) and video software
> capable of playing data streamed directly from the network.
> Compatibility with existing media servers is provided by the support of
> the industry standard RTSP protocol (Real Time Streaming Protocol).
> 
> http://opensource.eprocess.fr/popcorn

diff -urN smpeg-0.4.2.org/MPEG.cpp smpeg-0.4.2/MPEG.cpp
--- smpeg-0.4.2.org/MPEG.cpp	Sat Dec  2 00:58:20 2000
+++ smpeg-0.4.2/MPEG.cpp	Wed Feb  7 16:37:46 2001
@@ -244,12 +244,14 @@
   }
 }
 
-MPEGstatus MPEG::Status(void) {
+/* Michel Darricau from eProcess <mdarricau@eprocess.fr> conflict name with popcorn */
+MPEGstatus MPEG::GetStatus(void) {
   MPEGstatus status;
 
   status = MPEG_STOPPED;
   if ( VideoEnabled() ) {
-    switch (videoaction->Status()) {
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr> conflict name with popcorn */
+    switch (videoaction->GetStatus()) {
       case MPEG_PLAYING:
         status = MPEG_PLAYING;
       break;
@@ -258,7 +260,8 @@
     }
   }
   if ( AudioEnabled() ) {
-    switch (audioaction->Status()) {
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr> conflict name with popcorn */
+    switch (audioaction->GetStatus()) {
       case MPEG_PLAYING:
         status = MPEG_PLAYING;
       break;
@@ -274,7 +277,8 @@
     Play();
 
     if ( VideoEnabled() ) {
-      switch (videoaction->Status()) {
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr> conflict name with popcorn */
+      switch (videoaction->GetStatus()) {
       case MPEG_PLAYING:
         status = MPEG_PLAYING;
 	break;
@@ -283,7 +287,8 @@
       }
     }
     if ( AudioEnabled() ) {
-      switch (audioaction->Status()) {
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr> conflict name with popcorn */
+      switch (audioaction->GetStatus()) {
       case MPEG_PLAYING:
         status = MPEG_PLAYING;
 	break;
@@ -383,8 +388,9 @@
   /* Cannot seek past end of file */
   if((Uint32)position > system->TotalSize()) return;
   
+	/* Michel Darricau from eProcess <mdarricau@eprocess.fr> conflict name with popcorn */
   /* get info whrether we need to restart playing at the end */
-  if( Status() == MPEG_PLAYING )
+  if( GetStatus() == MPEG_PLAYING )
     was_playing = 1;
 
   if(!seekIntoStream(position)) return;
diff -urN smpeg-0.4.2.org/MPEG.h smpeg-0.4.2/MPEG.h
--- smpeg-0.4.2.org/MPEG.h	Wed Oct  4 19:29:25 2000
+++ smpeg-0.4.2/MPEG.h	Wed Feb  7 16:39:02 2001
@@ -1,6 +1,8 @@
 /*
     SMPEG - SDL MPEG Player Library
     Copyright (C) 1999  Loki Entertainment Software
+    
+    - Modified by Michel Darricau from eProcess <mdarricau@eprocess.fr>  for popcorn -
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -50,6 +52,10 @@
 class MPEG : public MPEGerror
 {
 public:
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  need for override in popcorn */
+    MPEG():MPEGerror(){}
+	MPEG(bool Sdlaudio, char *addresse,char *asset,long buffersize){}
+
     MPEG(const char * name, bool sdlaudio = true);
     MPEG(int Mpeg_FD, bool sdlaudio = true);
     MPEG(void *data, int size, bool sdlaudio = true);
@@ -67,13 +73,16 @@
 
     /* MPEG actions */
     void Loop(bool toggle);
-    void Play(void);
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  need for override in popcorn */
+    virtual void Play(void);
     void Stop(void);
     void Rewind(void);
-    void Pause(void);
-    void Seek(int bytes);
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  need for override in popcorn */
+    virtual void Pause(void);
+    virtual void Seek(int bytes);
     void Skip(float seconds);
-    MPEGstatus Status(void);
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  need for override in popcorn */
+    MPEGstatus GetStatus(void);
     void GetSystemInfo(MPEG_SystemInfo *info);
 
     /* MPEG audio actions */
diff -urN smpeg-0.4.2.org/MPEGaction.h smpeg-0.4.2/MPEGaction.h
--- smpeg-0.4.2.org/MPEGaction.h	Tue Sep  5 23:11:32 2000
+++ smpeg-0.4.2/MPEGaction.h	Wed Feb  7 16:40:33 2001
@@ -1,6 +1,8 @@
 /*
     SMPEG - SDL MPEG Player Library
     Copyright (C) 1999  Loki Entertainment Software
+    
+    - Modified by Michel Darricau from eProcess <mdarricau@eprocess.fr>  for popcorn -
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -59,7 +61,8 @@
             paused = true;
         }
     }
-    virtual MPEGstatus Status(void) = 0;
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  conflict name in popcorn */
+    virtual MPEGstatus GetStatus(void) = 0;
 
 protected:
     bool playing;
diff -urN smpeg-0.4.2.org/MPEGaudio.h smpeg-0.4.2/MPEGaudio.h
--- smpeg-0.4.2.org/MPEGaudio.h	Thu Oct  5 21:51:43 2000
+++ smpeg-0.4.2/MPEGaudio.h	Wed Feb  7 16:42:32 2001
@@ -1,6 +1,8 @@
 /*
     SMPEG - SDL MPEG Player Library
     Copyright (C) 1999  Loki Entertainment Software
+    
+    - Modified by Michel Darricau from eProcess <mdarricau@eprocess.fr>  for popcorn -
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -168,7 +170,8 @@
     void ResetSynchro(double time);
     void Skip(float seconds);
     void Volume(int vol);
-    MPEGstatus Status(void);
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr> conflict name in popcorn */
+    MPEGstatus GetStatus(void);
 
     /* Returns the desired SDL audio spec for this stream */
     bool WantedSpec(SDL_AudioSpec *wanted);
diff -urN smpeg-0.4.2.org/MPEGsystem.cpp smpeg-0.4.2/MPEGsystem.cpp
--- smpeg-0.4.2.org/MPEGsystem.cpp	Mon Dec  4 21:25:36 2000
+++ smpeg-0.4.2/MPEGsystem.cpp	Wed Feb  7 17:04:30 2001
@@ -17,7 +17,8 @@
 #include "MPEGstream.h"
 
 /* Define this if you want to use a separate thread for stream decoding */
-//#define USE_SYSTEM_THREAD
+/* Michel Darricau from eProcess <mdarricau@eprocess.fr> popcorn */
+#define USE_SYSTEM_THREAD
 
 Uint8 const PACKET_CODE[]       = { 0x00, 0x00, 0x01, 0xba };
 Uint8 const PACKET_MASK[]       = { 0xff, 0xff, 0xff, 0xff };
diff -urN smpeg-0.4.2.org/MPEGsystem.h smpeg-0.4.2/MPEGsystem.h
--- smpeg-0.4.2.org/MPEGsystem.h	Mon Dec  4 20:41:58 2000
+++ smpeg-0.4.2/MPEGsystem.h	Wed Feb  7 17:08:24 2001
@@ -1,4 +1,6 @@
 /* A class based on the MPEG stream class, used to parse the system stream */
+    
+/* - Modified by Michel Darricau from eProcess <mdarricau@eprocess.fr>  for popcorn - */
 
 #ifndef _MPEGSYSTEM_H_
 #define _MPEGSYSTEM_H_
@@ -19,6 +21,8 @@
 class MPEGsystem : public MPEGerror
 {
 public:
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  need for override in popcorn */
+	MPEGsystem(){}
     MPEGsystem(int MPEG_Fd);
     MPEGsystem(void *data, int size);
     virtual ~MPEGsystem();
@@ -29,12 +33,14 @@
     Uint32 Tell();
     void Rewind();
     void Loop(bool toggle);
-    void Start();
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  need for override in popcorn */
+    virtual void Start();
     void Stop();
     bool Eof() const;
-    bool Seek(int length);
-    Uint32 TotalSize();
-    double TotalTime();
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  need for override in popcorn */
+    virtual bool Seek(int length);
+    virtual Uint32 TotalSize();
+    virtual double TotalTime();
 
     /* Skip "seconds" seconds */
     void Skip(double seconds);
@@ -60,21 +66,24 @@
     /* Set looping for all streams */
     void loop_all_streams(bool toggle);
 
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  need for override in popcorn */
     /* Seek the first header */
-    bool seek_first_header();
+    virtual bool seek_first_header();
 
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  need for override in popcorn */
     /* Seek the next header */
-    bool seek_next_header();
+    virtual bool seek_next_header();
 
 protected:
     /* Run the loop to fill the stream buffers */
     static bool SystemLoop(MPEGsystem *system);
 
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  need for override in popcorn */
     /* Fill a buffer */
-    Uint8 FillBuffer();
+    virtual Uint8 FillBuffer();
 
     /* Read a new packet */
-    void Read();
+    virtual void Read();
 
     /* The system thread which fills the FIFO */
     static int SystemThread(void * udata);
diff -urN smpeg-0.4.2.org/MPEGvideo.h smpeg-0.4.2/MPEGvideo.h
--- smpeg-0.4.2.org/MPEGvideo.h	Tue Sep  5 23:11:32 2000
+++ smpeg-0.4.2/MPEGvideo.h	Wed Feb  7 17:09:39 2001
@@ -1,6 +1,8 @@
 /*
     SMPEG - SDL MPEG Player Library
     Copyright (C) 1999  Loki Entertainment Software
+    
+    - Modified by Michel Darricau from eProcess <mdarricau@eprocess.fr>  for popcorn -
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -56,7 +58,8 @@
     void Rewind(void);
     void ResetSynchro(double time);
      void Skip(float seconds);
-    MPEGstatus Status(void);
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr> conflict name in popcorn */
+    MPEGstatus GetStatus(void);
 
     /* MPEG video actions */
     bool GetVideoInfo(MPEG_VideoInfo *info);
diff -urN smpeg-0.4.2.org/audio/MPEGaudio.cpp smpeg-0.4.2/audio/MPEGaudio.cpp
--- smpeg-0.4.2.org/audio/MPEGaudio.cpp	Thu Oct  5 21:31:05 2000
+++ smpeg-0.4.2/audio/MPEGaudio.cpp	Thu Feb  8 16:06:10 2001
@@ -1,6 +1,8 @@
 /*
     SMPEG - SDL MPEG Player Library
     Copyright (C) 1999  Loki Entertainment Software
+    
+    - Modified by Michel Darricau from eProcess <mdarricau@eprocess.fr>  for popcorn -
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -247,8 +249,9 @@
         volume = (vol*SDL_MIX_MAXVOLUME)/100;
     }
 }
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  conflict name in popcorn */
 MPEGstatus
-MPEGaudio:: Status(void)
+MPEGaudio:: GetStatus(void)
 {
     if ( valid_stream ) {
         /* Has decoding stopped because of end of stream? */
diff -urN smpeg-0.4.2.org/audio/mpegtoraw.cpp smpeg-0.4.2/audio/mpegtoraw.cpp
--- smpeg-0.4.2.org/audio/mpegtoraw.cpp	Wed Oct 18 00:26:12 2000
+++ smpeg-0.4.2/audio/mpegtoraw.cpp	Thu Feb  8 16:09:59 2001
@@ -362,8 +362,9 @@
     long copylen;
     int mixed = 0;
 
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  conflict name in popcorn */
     /* Bail if audio isn&#039;t playing */
-    if ( audio->Status() != MPEG_PLAYING ) {
+    if ( audio->GetStatus() != MPEG_PLAYING ) {
         return(0);
     }
     volume = audio->volume;
diff -urN smpeg-0.4.2.org/smpeg.cpp smpeg-0.4.2/smpeg.cpp
--- smpeg-0.4.2.org/smpeg.cpp	Thu Oct  5 21:58:08 2000
+++ smpeg-0.4.2/smpeg.cpp	Wed Feb  7 17:20:35 2001
@@ -1,6 +1,8 @@
 /*
     SMPEG - SDL MPEG Player Library
     Copyright (C) 1999  Loki Entertainment Software
+    
+    - Modified by Michel Darricau from eProcess <mdarricau@eprocess.fr>  for popcorn -
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -162,7 +164,8 @@
     SMPEGstatus status;
 
     status = SMPEG_ERROR;
-    switch (mpeg->obj->Status()) {
+		/* Michel Darricau from eProcess <mdarricau@eprocess.fr>  conflict name in popcorn */
+    switch (mpeg->obj->GetStatus()) {
         case MPEG_STOPPED:
             if ( ! mpeg->obj->WasError() ) {
                 status = SMPEG_STOPPED;
diff -urN smpeg-0.4.2.org/video/MPEGvideo.cpp smpeg-0.4.2/video/MPEGvideo.cpp
--- smpeg-0.4.2.org/video/MPEGvideo.cpp	Sat Dec  2 03:33:11 2000
+++ smpeg-0.4.2/video/MPEGvideo.cpp	Wed Feb  7 17:23:44 2001
@@ -1,6 +1,8 @@
 /*
     SMPEG - SDL MPEG Player Library
     Copyright (C) 1999  Loki Entertainment Software
+    
+    - Modified by Michel Darricau from eProcess <mdarricau@eprocess.fr>  for popcorn -
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -204,6 +206,7 @@
     _image = 0;
     _filter = SMPEGfilter_null();
     _filter_mutex = SDL_CreateMutex();
+//	printf("[MPEGvideo::MPEGvideo]_filter_mutex[%lx] = SDL_CreateMutex()\n",_filter_mutex);
 }
 
 MPEGvideo:: ~MPEGvideo()
@@ -362,8 +365,9 @@
   }
 }
 
+	/* Michel Darricau from eProcess <mdarricau@eprocess.fr> conflict name in popcorn */
 MPEGstatus
-MPEGvideo:: Status(void)
+MPEGvideo:: GetStatus(void)
 {
     if ( _stream ) {
         if( !_thread || (_stream->film_has_ended ) ) {
*************************************************************************
*** Not Applied ***
Date: Mon, 5 Feb 2001 23:29:43 -0500
From: Joe Drew <hoserhead@woot.net>
Subject: Bug#84685: [PATCH] SMPEG does not update current time when seeking by byte offsets

retitle 84685 [PATCH] SMPEG does not update current time when seeking by byte offsets
thanks

I've taken the liberty of fixing this problem. Please update smpeg
soon - my mpg321 package is much less useful without this patch!

I think upstream will accept it; if not as it is, in the same vein of thought.

Thanks!

diff -ru smpeg-0.4.2.orig/MPEG.cpp smpeg-0.4.2/MPEG.cpp
--- smpeg-0.4.2.orig/MPEG.cpp	Fri Dec  1 18:58:20 2000
+++ smpeg-0.4.2/MPEG.cpp	Mon Feb  5 19:38:48 2001
@@ -421,13 +421,18 @@
       videostream->next_packet();
 
   /* And forget what we previouly buffered */
+  /* {video, audio}action is the same object as video, but under a different
+     interface (through polymorphism.) We need to use {video,audio} here
+     instead. -JD */
   if ( audioaction ) {
     audioaction->Rewind();
     audioaction->ResetSynchro(audiostream->time());
+    audio->setPlayTime(system->TimeElapsed(position));
   }
   if ( videoaction ) {
     videoaction->Rewind();
     videoaction->ResetSynchro(videostream->time());
+    video->setPlayTime(system->TimeElapsed(position));
   }
 
   return(true);
diff -ru smpeg-0.4.2.orig/MPEGaudio.h smpeg-0.4.2/MPEGaudio.h
--- smpeg-0.4.2.orig/MPEGaudio.h	Thu Oct  5 15:51:43 2000
+++ smpeg-0.4.2/MPEGaudio.h	Mon Feb  5 19:16:11 2001
@@ -148,7 +148,7 @@
 
 /* The actual MPEG audio class */
 class MPEGaudio : public MPEGerror, public MPEGaudioaction {
-
+    friend class MPEG;
     friend void Play_MPEGaudioSDL(void *udata, Uint8 *stream, int len);
     friend int Play_MPEGaudio(MPEGaudio *audio, Uint8 *stream, int len);
 #ifdef THREADED_AUDIO
@@ -359,6 +359,9 @@
   /********************/
   /* Timestamp sync   */
   /********************/
+
+  void setPlayTime (double time);
+
 public:
 #define N_TIMESTAMPS 5
 
diff -ru smpeg-0.4.2.orig/MPEGsystem.cpp smpeg-0.4.2/MPEGsystem.cpp
--- smpeg-0.4.2.orig/MPEGsystem.cpp	Mon Dec  4 15:25:36 2000
+++ smpeg-0.4.2/MPEGsystem.cpp	Mon Feb  5 19:33:03 2001
@@ -1054,11 +1054,24 @@
 
 double MPEGsystem::TotalTime()
 {
+    return TimeElapsed(0);
+}
+
+/* I don't think special calculation is needed for video,
+   but it's definitely needed for audio. This should work for
+   both. - JD */
+double MPEGsystem::TimeElapsed(int atByte)
+{
   off_t size, pos;
   off_t file_ptr;
   Uint8 * buffer, * p;
   double time;
 
+  if (atByte < 0)
+  {
+      return -1;
+  }
+  
   /* Lock to avoid concurrent access to the stream */
   SDL_mutexP(system_mutex);
 
@@ -1141,7 +1154,8 @@
     audio_header(p, &framesize, &frametime);
     totalsize = TotalSize();
     if(framesize)
-      time = frametime * totalsize / framesize;
+      //is there a better way to do this?
+      time = (frametime * (atByte ? atByte:totalsize)) / framesize;
     else
       time = 0;
   }
diff -ru smpeg-0.4.2.orig/MPEGsystem.h smpeg-0.4.2/MPEGsystem.h
--- smpeg-0.4.2.orig/MPEGsystem.h	Mon Dec  4 14:41:58 2000
+++ smpeg-0.4.2/MPEGsystem.h	Mon Feb  5 19:31:09 2001
@@ -35,6 +35,7 @@
     bool Seek(int length);
     Uint32 TotalSize();
     double TotalTime();
+    double TimeElapsed(int atByte);
 
     /* Skip "seconds" seconds */
     void Skip(double seconds);
diff -ru smpeg-0.4.2.orig/MPEGvideo.h smpeg-0.4.2/MPEGvideo.h
--- smpeg-0.4.2.orig/MPEGvideo.h	Tue Sep  5 17:11:32 2000
+++ smpeg-0.4.2/MPEGvideo.h	Mon Feb  5 19:35:39 2001
@@ -42,6 +42,11 @@
     /* Thread to play the video asynchronously */
     friend int Play_MPEGvideo(void *udata);
 
+    /* For when seek() is used - to update current "play time"
+       The same thing is in MPEGaudio. Ugly but I couldn't get
+       friend <functionname> to work! */
+    friend class MPEG;
+
     /* Various mpeg_play functions that need our data */
     friend VidStream* mpegVidRsrc( TimeStamp time_stamp, VidStream* vid_stream, int first );
     friend int get_more_data( VidStream* vid_stream );
@@ -101,6 +106,11 @@
     SDL_mutex* _filter_mutex; // make sure the filter is not changed while being used
 
     void RewindStream(void);
+private:
+    /* This is needed, I think, because of the way inheritance
+       and 'friend' works. play_time is in MPEGaction.h, and that's
+       two levels of inheritance above us */
+    void setPlayTime(double time);
 };
 
 #endif /* _MPEGVIDEO_H_ */
diff -ru smpeg-0.4.2.orig/audio/MPEGaudio.cpp smpeg-0.4.2/audio/MPEGaudio.cpp
--- smpeg-0.4.2.orig/audio/MPEGaudio.cpp	Thu Oct  5 15:31:05 2000
+++ smpeg-0.4.2/audio/MPEGaudio.cpp	Mon Feb  5 18:17:56 2001
@@ -183,6 +183,12 @@
     }
     return now;
 }
+
+void MPEGaudio:: setPlayTime(double time)
+{
+    play_time = time;
+}
+
 void
 MPEGaudio:: Play(void)
 {
diff -ru smpeg-0.4.2.orig/video/MPEGvideo.cpp smpeg-0.4.2/video/MPEGvideo.cpp
--- smpeg-0.4.2.orig/video/MPEGvideo.cpp	Fri Dec  1 21:33:11 2000
+++ smpeg-0.4.2/video/MPEGvideo.cpp	Mon Feb  5 18:18:12 2001
@@ -592,4 +592,10 @@
     MoveDisplay(saved_x, saved_y);
 }
 
+void 
+MPEGvideo:: setPlayTime(double time)
+{
+    play_time = time;
+}
+
 /* EOF */




*************************************************************************
*** Applied ***
Date: Thu, 21 Dec 2000 02:07:07 -0800 (PST)
From: Stephane Peter <megastep@lokigames.com>
Subject: plaympeg patch


The following patch prevents plaympeg to switch between fullscreen/windowed
modes for each file when several MPEG files are passed on the command line.
Trivial really...



diff -u -r1.39 plaympeg.c
--- plaympeg.c  2000/12/18 03:31:35     1.39
+++ plaympeg.c  2000/12/21 10:04:36
@@ -765,6 +765,7 @@
                          // toggle fullscreen
                          if ( event.key.keysym.mod & KMOD_ALT ) {
                             SDL_WM_ToggleFullScreen(screen);
+                           fullscreen = !fullscreen;
                           }
                         } else if ( event.key.keysym.sym == SDLK_UP ) {
                          // Volume up



*************************************************************************
*** Applied ***
Date: Wed, 13 Dec 2000 03:01:58 +0100 (CET)
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: [Fwd: v0.4.2 Re: SMPEG 0.4.1 system streams]

Fixed:
        - MPEGSystem::TotalTime() hanging on small files
        - system header decoding (caused misdetection of system streams)
and added few goodies of my own:
        - fixed padding stream (0xbe) and user stream (0xb2) not being
recognized by the system decoder
        - fixed plaympeg requiring a mouse (useful for console playback)
        - added bilinear filter toggling with the 'f' key in plaympeg

see ya,
Vivien.

diff -Naur smpeg/MPEGsystem.cpp smpeg.patched/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Tue Dec  5 11:19:44 2000
+++ smpeg.patched/MPEGsystem.cpp	Wed Dec 13 01:21:11 2000
@@ -25,22 +25,22 @@
 Uint8 const END_MASK[]          = { 0xff, 0xff, 0xff, 0xff };
 Uint8 const END2_CODE[]         = { 0x00, 0x00, 0x01, 0xb7 };
 Uint8 const END2_MASK[]         = { 0xff, 0xff, 0xff, 0xff };
-Uint8 const VIDEO_CODE[]        = { 0x00, 0x00, 0x01, 0xb3 };
-Uint8 const VIDEO_MASK[]        = { 0xff, 0xff, 0xff, 0xff };
-Uint8 const AUDIO_CODE[]        = { 0xff, 0xf0, 0x00, 0x00 };
-Uint8 const AUDIO_MASK[]        = { 0xff, 0xf0, 0x00, 0x00 };
 Uint8 const VIDEOSTREAM_CODE[]  = { 0x00, 0x00, 0x01, 0xe0 };
 Uint8 const VIDEOSTREAM_MASK[]  = { 0xff, 0xff, 0xff, 0xe0 };
 Uint8 const AUDIOSTREAM_CODE[]  = { 0x00, 0x00, 0x01, 0xc0 };
 Uint8 const AUDIOSTREAM_MASK[]  = { 0xff, 0xff, 0xff, 0xc0 };
-Uint8 const PAD_CODE[]          = { 0x00, 0x00, 0x01, 0xbe };
-Uint8 const PAD_MASK[]          = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const PADSTREAM_CODE[]    = { 0x00, 0x00, 0x01, 0xbe };
+Uint8 const PADSTREAM_MASK[]    = { 0xff, 0xff, 0xff, 0xff };
 Uint8 const SYSTEMSTREAM_CODE[] = { 0x00, 0x00, 0x01, 0xbb };
 Uint8 const SYSTEMSTREAM_MASK[] = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const USERSTREAM_CODE[]   = { 0x00, 0x00, 0x01, 0xb2 };
+Uint8 const USERSTREAM_MASK[]   = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const VIDEO_CODE[]        = { 0x00, 0x00, 0x01, 0xb3 };
+Uint8 const VIDEO_MASK[]        = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const AUDIO_CODE[]        = { 0xff, 0xf0, 0x00, 0x00 };
+Uint8 const AUDIO_MASK[]        = { 0xff, 0xf0, 0x00, 0x00 };
 Uint8 const GOP_CODE[]          = { 0x00, 0x00, 0x01, 0xb8 };
 Uint8 const GOP_MASK[]          = { 0xff, 0xff, 0xff, 0xff };
-Uint8 const USER_CODE[]         = { 0x00, 0x00, 0x01, 0xb2 };
-Uint8 const USER_MASK[]         = { 0xff, 0xff, 0xff, 0xff };
 Uint8 const PICTURE_CODE[]      = { 0x00, 0x00, 0x01, 0x00 };
 Uint8 const PICTURE_MASK[]      = { 0xff, 0xff, 0xff, 0xff };
 Uint8 const SLICE_CODE[]        = { 0x00, 0x00, 0x01, 0x01 };
@@ -296,8 +296,10 @@
   if((header_size += 4) >= size) return(0); 
 
   if(!Match4(pointer, SYSTEMSTREAM_CODE, SYSTEMSTREAM_MASK) &&
-     !Match4(pointer, AUDIOSTREAM_CODE, AUDIOSTREAM_MASK) &&
-     !Match4(pointer, VIDEOSTREAM_CODE, VIDEOSTREAM_MASK))
+     !Match4(pointer, AUDIOSTREAM_CODE, AUDIOSTREAM_MASK)   &&
+     !Match4(pointer, VIDEOSTREAM_CODE, VIDEOSTREAM_MASK)   &&
+     !Match4(pointer, PADSTREAM_CODE, PADSTREAM_MASK)       &&
+     !Match4(pointer, USERSTREAM_CODE, USERSTREAM_MASK))
     return(0); /* Unknown encapsulated stream */
 
   /* Parse the stream packet */
@@ -731,6 +734,9 @@
      Match4(pointer, END2_CODE, END2_MASK))
   {
     /* End codes belong to video stream */
+#ifdef DEBUG_SYSTEM
+    fprintf(stderr, "[%d] MPEG end code\n", read_total - read_size + (pointer - read_buffer));
+#endif
     stream_id = exist_stream(VIDEO_STREAMID, 0xF0);
     packet_size = 4;
   }
@@ -907,10 +913,10 @@
       while (pointer[0] & 0x80 )
       {
 	/* If the stream doesn't already exist */
-	if(!get_stream(pointer[1]))
+	if(!get_stream(pointer[0]))
 	{
 	  /* Create a new stream and add it to the list */
-	  add_stream(new MPEGstream(this, pointer[1]));
+	  add_stream(new MPEGstream(this, pointer[0]));
 	}
 	pointer += 3;
 	stream_list[0]->pos += 3;
@@ -1151,6 +1157,7 @@
     {
     /* Otherwise search the stream backwards for a valid header */
       file_ptr -= MPEG_BUFFER_SIZE;
+      if(file_ptr < -TotalSize()) file_ptr = -TotalSize();
       
       if(data_reader.fromData == true) {
 	      data_reader.offset = data_reader.size - file_ptr;
diff -Naur smpeg/plaympeg.c smpeg.patched/plaympeg.c
--- smpeg/plaympeg.c	Mon Oct  9 22:25:50 2000
+++ smpeg.patched/plaympeg.c	Tue Dec 12 22:11:43 2000
@@ -572,6 +572,9 @@
         exit(0);
     }
 
+    /* Plaympeg doesn't need a mouse */
+    setenv("SDL_NOMOUSE","1",0);
+
     /* Play the mpeg files! */
     for ( ; argv[i]; ++i ) {
 	/* Initialize SDL */
@@ -833,6 +836,19 @@
                         } else if ( event.key.keysym.sym == SDLK_KP_PLUS ) {
 			  // Scale plus
 			  scalesize++;
+			} else if ( event.key.keysym.sym == SDLK_f ) {
+			  // Toggle filtering on/off
+			  if ( bilinear_filtering ) {
+			    SMPEG_Filter *filter = SMPEGfilter_null();
+			    filter = SMPEG_filter( mpeg, filter );
+			    filter->destroy(filter);
+			    bilinear_filtering = 0;
+			  } else {
+			    SMPEG_Filter *filter = SMPEGfilter_bilinear();
+			    filter = SMPEG_filter( mpeg, filter );
+			    filter->destroy(filter);
+			    bilinear_filtering = 1;
+			  }
 			}
                         break;
                     case SDL_QUIT:
diff -Naur smpeg/video/video.cpp smpeg.patched/video/video.cpp
--- smpeg/video/video.cpp	Wed Oct  4 19:38:03 2000
+++ smpeg.patched/video/video.cpp	Wed Dec 13 00:20:20 2000
@@ -1264,7 +1264,7 @@
         }
 #ifdef VERBOSE_DEBUG
         else
-            printf("Unknown data - not slice start code!\n");
+            fprintf(stderr, "Unknown data [%x] - not slice start code!\n", data);
 #endif
         break;
     }
*************************************************************************
*** Applied ***
Date: Mon, 11 Dec 2000 16:33:18 +0200
From: Maxim Sobolev <sobomax@FreeBSD.org>
Subject: Re: Announcing SMPEG 04.2

Thanks! Unlike 0.4.1 this version works on FreeBSD almost OOB, so I just
updated its FreeBSD port. BTW, I found a minor issue with smpeg-config (it
assumes that sdl-config is called `sdl-config', while it may not be true - on
FreeBSD we have sdl11-config for SDL1.1.* and sdl-config for SDL1.0.*).
Attached patch should solve this minor problem.

Sincerely,

Maxim

--- smpeg-config.in.orig	Fri Aug  4 02:51:30 2000
+++ smpeg-config.in	Mon Dec 11 14:15:26 2000
@@ -42,7 +42,7 @@
       if test @includedir@ != /usr/include ; then
         includes=-I@includedir@
       fi
-      echo $includes -I@includedir@/smpeg `sdl-config --cflags`
+      echo $includes -I@includedir@/smpeg `@SDL_CONFIG@ --cflags`
       ;;
     --libs)
       if [ "`uname`" = "SunOS" ]; then
@@ -50,7 +50,7 @@
       else
         libdirs="-L@libdir@ @SMPEG_RLD_FLAGS@"
       fi
-      echo $libdirs -lsmpeg `sdl-config --libs`
+      echo $libdirs -lsmpeg `@SDL_CONFIG@ --libs`
       ;;
     *)
       echo "${usage}" 1>&2
*************************************************************************
*** Applied ***
Date: Thu, 16 Nov 2000 01:23:51 -0800
From: Mo <mo@nospam.com>
Subject: Re: SMPEG loops forever on bad input.

I finally figured out what was going wrong in the current CVS
code. It would blow up ran "plaympeg ... ... ..." on a file
of length zero. This patch fixes the core dump. You just
need to allocate the mutex earlier so that it will not core
dump when you free the mutex.


Index: MPEGsystem.cpp
===================================================================
RCS file: /cvs/smpeg/MPEGsystem.cpp,v
retrieving revision 1.20
diff -u -r1.20 MPEGsystem.cpp
--- MPEGsystem.cpp      2000/10/27 22:12:28     1.20
+++ MPEGsystem.cpp      2000/11/16 10:22:15
@@ -393,6 +393,7 @@
 
   /* Create a mutex to avoid concurrent access to the stream */
   system_mutex = SDL_CreateMutex();
+  request_wait = SDL_CreateSemaphore(0);
 
   /*
      We are not being passed data, so we don't need to simulate
@@ -433,8 +434,6 @@
     SetError("Could not find the beginning of MPEG data\n");
     return;
   }
-  
-  request_wait = SDL_CreateSemaphore(0);
 
   /* Start the system thread */
   system_thread = SDL_CreateThread(SystemThread, this);
@@ -461,6 +460,7 @@
 
   /* Create a mutex to avoid concurrent access to the stream */
   system_mutex = SDL_CreateMutex();
+  request_wait = SDL_CreateSemaphore(0);
 
   /* 
      Our argument list indicates that we are being passed data, 
@@ -505,8 +505,6 @@
     SetError("Could not find the beginning of MPEG data\n");
     return;
   }
-  
-  request_wait = SDL_CreateSemaphore(0);
 
   /* Start the system thread */
   system_thread = SDL_CreateThread(SystemThread, this);

*************************************************************************
*** Applied ***
Date: Tue, 14 Nov 2000 00:54:55 +0100 (CET)
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: [Fwd: smpeg ::Seek() function broken?]


Hi!

On Thu, 9 Nov 2000, Sam Lantinga wrote:

> Vivien Chappelier wrote:
> > 
> > On Thu, 9 Nov 2000, Sam Lantinga wrote:
> > >
> > > Can you fix this?  It is broken in the current CVS.
> Okay, no rush, I'd just like to get it fixed.

Done.
Here is a tiny patch that should fix this bug. Actually, the RenderFrame
function rewinded both audio and video streams in MPEG systems, which
caused the MPEG audio decoder to stop, thinking it had reached end of
file. Thus the clock was stalled (as it is based on audio decoding).. and
the video was slow with no sound ;)
I fixed the RenderFrame function to rewind only when wanted frame is
before *current* frame and not current total number of decoded frames.

see ya,
Vivien Chappelier.

diff -Naur smpeg/video/MPEGvideo.cpp smpeg.seekfix/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Sun Sep 24 02:48:44 2000
+++ smpeg.seekfix/video/MPEGvideo.cpp	Tue Nov 14 00:28:46 2000
@@ -516,7 +516,7 @@
 {
     _stream->need_frameadjust = true;
 
-    if( _stream->totNumFrames > frame ) {
+    if( _stream->current_frame > frame ) {
         mpeg->rewind_stream();
 	mpeg->next_packet();
         Rewind();
@@ -524,7 +524,7 @@
 
     _stream->_jumpFrame = frame;
 
-    while( (_stream->totNumFrames < frame) &&
+    while( (_stream->current_frame < frame) &&
            ! _stream->film_has_ended )
     {
         mpegVidRsrc( 0, _stream, 0 );
*************************************************************************
*** Applied ***
Date: Mon, 13 Nov 2000 13:53:51 -0800
From: "Joseph I . Valenzuela" <tsaotsao@lokigames.com>
Subject: smpeg redux


Sam;

Slightly updated patch.  Thanks again.

-- 
J. Valenzuela -- tsaotsao@lokigames.com

diff -Naur smpeg/MPEGsystem.cpp smpeg-new/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Fri Oct 27 15:12:28 2000
+++ smpeg-new/MPEGsystem.cpp	Mon Nov 13 13:33:07 2000
@@ -1100,14 +1100,18 @@
 	      int size = MPEG_BUFFER_SIZE;
 
 	      if(data_reader.offset + size > data_reader.size) {
-		      size = data_reader.size - data_reader.offset;
+                  size = data_reader.size - data_reader.offset;
 	      }
 
-	      dataptr += size;
-
-	      memcpy(buffer, dataptr, size);
-
-	      data_reader.offset += size;
+              if(size >= 0) {
+                  dataptr += size;
+      
+                  memcpy(buffer, dataptr, size);
+      
+                  data_reader.offset += size;
+             } else {
+		     break;
+	     }
       } else {
         if(read(mpeg_fd, buffer, MPEG_BUFFER_SIZE) < 0) break;
       }
*************************************************************************
*** Applied ***
Date: Sat, 14 Oct 2000 23:43:33 +0900
From: Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>
Subject: SDL-1.1 Patch For FreeBSD.

latest smpeg is audio output always Mono.
(smpeg041fix.diff)

Index: audio/mpegtoraw.cpp
===================================================================
RCS file: /home/ncvs/smpeg/audio/mpegtoraw.cpp,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 mpegtoraw.cpp
--- audio/mpegtoraw.cpp	2000/10/06 01:17:03	1.1.1.1
+++ audio/mpegtoraw.cpp	2000/10/06 01:21:24
@@ -84,6 +84,7 @@
   register REAL *s1,*s2;
   REAL *s3,*s4;
 
+  stereo = true;
   forcetomonoflag = false;
   forcetostereoflag = false;
   downfrequency = 0;
*************************************************************************
*** Applied ***
Date: Mon, 25 Sep 2000 20:37:43 +0200
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: [SMPEG] ati hardware acceleration

Hi!

        I've done a few test on ATI code performance and I've got some bad
news...
It seems that hardware decoding sample code provided by ATI is nearly
equivalent to SMPEG software decoding (with MMX) ...! From what I saw
dissasembling their code a few (I think this is legal in Europe), this
is not really surprising as there are many level of calls before
accessing the hardware, especially there is one function call for each
access to a register!!!
Moreover, reading from the ATI overlay seems really slow (not too
surprising, reading from video memory is rarely accelerated.. I noticed
this too with TV capture software for my ATI All-in-Wonder 128).
Conclusion:
        * we should probably implement ATI overlay in SDL too, now that there
is support for it, and render directly.
        * we should really contact ATI to see if they're still interested in
providing MPEG decoding acceleration under Linux, and maybe ask them to
involve more, and provide better software. Showing them that SMPEG is
now working with their SDK should help getting better relationship with
them :)

I attached the new patch, integrating latest CVS updates concerning
overlays, along with my performance tests.

I've been thinking of rewriting the aticce.o to be used with more
kernels, not only 2.2.10, as this probably won't break the NDA, since
the CCE is used for DRI and Xv projects, which are public (NDA, article
2, (i) : "is or becomes (through no improper action or inaction of the
receiving party or any affiliate, agent, consultant or employee)
generally known by the public").
I need to check if, firstly, I'm skilled enough for that :), secondly I
have the right to do that. But, first of all, I'd like your point of
view on this question.
Maybe I could work with ATI too if they are interrested :)

Now I'm waiting for you to test all this, tell me what you think of it,
and what you're planning for the future :)

see ya,
Vivien Chappelier.

diff -Naur smpeg/configure.in smpeg.patched/configure.in
--- smpeg/configure.in	Wed Sep  6 10:12:01 2000
+++ smpeg.patched/configure.in	Fri Sep 22 20:12:47 2000
@@ -142,6 +142,23 @@
     fi
 fi
 
+dnl Check for ATI vha support
+AC_ARG_ENABLE(ati,
+[  --enable-ati            enable ATI Rage128 hardware acceleration [default=no]],
+              , enable_ati=no)
+if test x$enable_ati = xyes; then
+    use_ati=yes
+    AC_CHECK_LIB(r128hap, ATIHAP_StartCCE, LIBS="$LIBS -lr128hap", use_ati=no)
+    AC_CHECK_LIB(r128vha, VHA_Init, LIBS="$LIBS -lr128vha", use_ati=no)
+    AC_CHECK_LIB(r128ov, CreateOVSurface, LIBS="$LIBS -lr128ov", use_ati=no)
+    AC_MSG_CHECKING(for ATI Rage128 hardware acceleration)
+    AC_MSG_RESULT($use_ati)
+
+    if test x$use_ati = xyes; then
+        CFLAGS="$CFLAGS -DUSE_ATI"
+    fi
+fi
+
 dnl Check for system timestamp sync
 AC_ARG_ENABLE(timestamp-sync,
 [  --enable-timestamp-sync  enable system timestamp sync [default=yes]],
diff -Naur smpeg/video/Makefile.am smpeg.patched/video/Makefile.am
--- smpeg/video/Makefile.am	Mon Apr 10 04:50:55 2000
+++ smpeg.patched/video/Makefile.am	Sun Sep 24 17:29:01 2000
@@ -17,6 +17,7 @@
 	util.h			\
 	video.cpp		\
 	video.h			\
+	vhar128.c		\
 	mmxflags_asm.S		\
 	mmxidct_asm.S
 
diff -Naur smpeg/video/gdith.cpp smpeg.patched/video/gdith.cpp
--- smpeg/video/gdith.cpp	Sun Sep 24 02:48:44 2000
+++ smpeg.patched/video/gdith.cpp	Mon Sep 25 20:04:55 2000
@@ -54,6 +54,10 @@
 #include "dither.h"
 #include "SDL_timer.h"
 
+#ifdef USE_ATI
+#include "vhar128.h"
+#endif
+
 #ifdef __STDC__
 #include <stdlib.h>
 #include <string.h>
@@ -318,6 +326,9 @@
     Uint8 *pixels[3];
 
     /* Fill in an SDL YV12 overlay structure for the source */
+#ifdef USE_ATI
+    vhar128_lockimage(vid_stream->ati_handle, vid_stream->current->image, &src);
+#else
     src.format = SDL_YV12_OVERLAY;
     src.w = _w;
     src.h = _h;
@@ -331,10 +342,15 @@
     pixels[2] = vid_stream->current->image + pitches[0] * _h +
                                              pitches[1] * _h / 2;
     src.pixels = pixels;
+#endif
 
     _filter->callback(_image, &src, &_srcrect, &info, _filter->data );
+
+#ifdef USE_ATI
+    vhar128_unlockimage(vid_stream->ati_handle, vid_stream->current->image, &src);
+#endif
   }
-  
+
   /* Now display the image */
   if ( _mutex )
     SDL_mutexP( _mutex );
diff -Naur smpeg/video/parseblock.cpp smpeg.patched/video/parseblock.cpp
--- smpeg/video/parseblock.cpp	Fri Apr 14 10:57:34 2000
+++ smpeg.patched/video/parseblock.cpp	Fri Sep 22 20:12:47 2000
@@ -197,10 +197,18 @@
 
     int diff;
     int size, level=0, i, run, pos, coeff;
+#ifdef USE_ATI
+    long int *reconptr;
+#else
     short int *reconptr;
+#endif
     unsigned char *iqmatrixptr, *niqmatrixptr;
     int qscale;
 
+#ifdef USE_ATI
+    reconptr = DCT_recon[n];
+    memset(reconptr, 0, 130*sizeof(reconptr[0]));
+#else
     reconptr = DCT_recon[0];
 
 #if 0
@@ -222,6 +230,7 @@
 #else
     memset(reconptr, 0, 64*sizeof(reconptr[0]));
 #endif
+#endif
 
     if (vid_stream->mblock.mb_intra) {
 
@@ -271,6 +280,16 @@
         }
         flush_bits(flushed);
 
+#ifdef USE_ATI
+	if ( (n == 0) && ((vid_stream->mblock.mb_address -
+                           vid_stream->mblock.past_intra_addr) > 1) ) {
+	  DCT_dc_y_past = diff;
+	  } else {
+	  DCT_dc_y_past += diff;
+        }
+	*reconptr++ = 0;
+	*reconptr++ = DCT_dc_y_past;
+#else
         if ( (n == 0) && ((vid_stream->mblock.mb_address -
                            vid_stream->mblock.past_intra_addr) > 1) ) {
           coeff = diff + 1024;
@@ -278,7 +297,7 @@
           coeff = diff + DCT_dc_y_past;
         }
         DCT_dc_y_past = coeff;
-
+#endif
       } else { /* n = 4 or 5 */
     
     /*
@@ -313,6 +332,28 @@
         }
         flush_bits(flushed);
     
+#ifdef USE_ATI
+	*reconptr++ = 0;
+
+	if(n == 5) {
+          if (vid_stream->mblock.mb_address -
+              vid_stream->mblock.past_intra_addr > 1) {
+	    DCT_dc_cr_past = diff;
+	  } else {
+	    DCT_dc_cr_past += diff;
+	  }
+	  *reconptr++ = DCT_dc_cr_past;
+	} else {
+          if (vid_stream->mblock.mb_address -
+              vid_stream->mblock.past_intra_addr > 1) {
+	    DCT_dc_cb_past = diff;
+	  } else {
+	    DCT_dc_cb_past += diff;
+	  }
+	  *reconptr++ = DCT_dc_cb_past;
+	}
+#else
+
       /* We test 5 first; a result of the mixup of Cr and Cb */
         coeff = diff;
         if (n == 5) {
@@ -332,20 +373,25 @@
           }
           DCT_dc_cb_past = coeff;
         }
+#endif
       }
       
+#ifndef USE_ATI
       *reconptr = coeff;
 #ifdef USE_MMX
       if ( mmx_available ) {
         *reconptr <<= 4;
       }
-#endif
-      i = 0; 
+#endif /* USE_MMX */
+#endif /* USE_ATI */
+
       pos = 0;
       coeffCount = (coeff != 0);
-    
+
+      i = 0; 
+
       if (vid_stream->picture.code_type != 4) {
-    
+
         qscale = vid_stream->slice.quant_scale;
         iqmatrixptr = vid_stream->intra_quant_matrix[0];
     
@@ -353,7 +399,7 @@
       
           DECODE_DCT_COEFF_NEXT(run, level);
 
-          if (run >= END_OF_BLOCK) break;
+	  if (run >= END_OF_BLOCK) break;
 
           i = i + run + 1;
 
@@ -369,23 +415,35 @@
                      ((int) (*(iqmatrixptr+pos)))) >> 4; 
             coeff -= (1 - (coeff & 1));
           }
+
+#ifdef USE_ATI
+	  *reconptr++ = run;
+	  *reconptr++ = coeff;
+#else
+
 #ifdef USE_MMX
           if ( mmx_available )
             coeff *= 16;
 #endif
+
 #ifdef QUANT_CHECK
           printf ("coeff: %d\n", coeff);
 #endif
 
           reconptr[pos] = coeff;
           coeffCount++;
-
+#endif /* USE_ATI */
         }
 
 #ifdef QUANT_CHECK
 	printf ("\n");
 #endif
 
+#ifdef USE_ATI
+	/* mark end of block */
+	*reconptr++ = 0xFFFFFFFF;
+#endif
+
 #ifdef ANALYSIS 
         {
           extern unsigned int *mbCoeffPtr;
@@ -397,11 +455,12 @@
 	goto end;
       }
     } else { /* non-intra-coded macroblock */
-      
+
       niqmatrixptr = vid_stream->non_intra_quant_matrix[0];
       qscale = vid_stream->slice.quant_scale;
-      
+
       DECODE_DCT_COEFF_FIRST(run, level);
+
       i = run;
 
       pos = zigzag_direct[i&0x3f];
@@ -416,6 +475,12 @@
                  ((int) (*(niqmatrixptr+pos)))) >> 4; 
 	coeff = (coeff-1) | 1; /* equivalent to: if ((coeff&1)==0) coeff = coeff - 1; */
       }
+
+#ifdef USE_ATI
+      *reconptr++ = run;
+      *reconptr++ = coeff;
+#else
+
 #ifdef USE_MMX
       if ( mmx_available )
         coeff *= 16;
@@ -425,6 +490,7 @@
       if (coeff) {
           coeffCount = 1;
       }
+#endif /* USE_ATI */
 
       if (vid_stream->picture.code_type != 4) {
     
@@ -449,14 +515,26 @@
                      ((int) (*(niqmatrixptr+pos)))) >> 4; 
             coeff = (coeff-1) | 1; /* equivalent to: if ((coeff&1)==0) coeff = coeff - 1; */
           }
+
+#ifdef USE_ATI
+	  *reconptr++ = run;
+	  *reconptr++ = coeff;
+#else
+
 #ifdef USE_MMX
           if ( mmx_available )
             coeff *= 16;
 #endif
           reconptr[pos] = coeff;
           coeffCount++;
+#endif /* USE_ATI */
         } /* end while */
 
+#ifdef USE_ATI
+	/* mark end of block */
+	*reconptr++ = 0xFFFFFFFF; 
+#endif
+
 #ifdef ANALYSIS
         {
           extern unsigned int *mbCoeffPtr;
@@ -472,6 +550,10 @@
     
   end:
 
+#ifdef USE_ATI
+    return;
+#else
+
     if( ! vid_stream->_skipFrame || (vid_stream->picture.code_type != B_TYPE) )
     {
         if( coeffCount == 1 )
@@ -508,6 +590,7 @@
     if ( mmx_available ) {
       __asm__ ("emms");
     }
+#endif
 #endif
 }
     
diff -Naur smpeg/video/proto.h smpeg.patched/video/proto.h
--- smpeg/video/proto.h	Wed Sep  6 10:12:01 2000
+++ smpeg.patched/video/proto.h	Fri Sep 22 20:12:47 2000
@@ -69,7 +69,7 @@
 void DestroyVidStream P((VidStream *astream ));
 PictImage *NewPictImage P(( VidStream *vid_stream ));
 bool InitPictImages P(( VidStream *vid_stream, int w, int h, SDL_Surface *dst ));
-void DestroyPictImage P((PictImage *apictimage ));
+void DestroyPictImage P(( VidStream *vid_stream, PictImage *apictimage ));
 VidStream *mpegVidRsrc P((TimeStamp time_stamp,VidStream *vid_stream, int first  ));
 void SetBFlag P((BOOLEAN val ));
 void SetPFlag P((BOOLEAN val ));
diff -Naur smpeg/video/vhar128.c smpeg.patched/video/vhar128.c
--- smpeg/video/vhar128.c	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/video/vhar128.c	Sun Sep 24 17:36:39 2000
@@ -0,0 +1,272 @@
+#ifdef USE_ATI
+#include <stdio.h>
+#include <vha.h>
+#include <r128hap.h>
+#include <ovly.h>
+#include "vhar128.h"
+
+/* #define  DEBUG_R128VHA */
+
+#define I_FRAME 1
+#define P_FRAME 2
+#define B_FRAME 3
+#define D_FRAME 4
+
+struct vhar128_image {
+  OVDESCRIPTION * overlay;
+};
+
+struct private_yuvhwdata {
+  OVSURFACE * surface;
+};
+
+/* Translate error code to something readable */
+static void vhar128_perror(char * string, int error_code)
+{
+  switch(error_code)
+  {
+    case VHAERR_INVALIDPARAMS:
+      fprintf(stderr, "%s: (ATI) Invalid parameters\n", string);
+      break; 
+    case VHAERR_UNSUPPORTED:
+      fprintf(stderr, "%s: (ATI) Unsupported feature\n", string);
+      break; 
+    case VHAERR_INVALIDHANDLE:
+      fprintf(stderr, "%s: (ATI) Invalid handle\n", string);
+      break; 
+    case VHAERR_OUTOFMEMORY:
+      fprintf(stderr, "%s: (ATI) Out of memory\n", string);
+      break; 
+    case VHA_OK:
+      fprintf(stderr, "%s: (ATI) Success\n", string);
+      break; 
+    default:
+      fprintf(stderr, "%s: (ATI) Undocumented error\n", string);
+      break;
+  }
+}
+
+/* Check and initialize hardware */
+unsigned int vhar128_new()
+{
+    VHA_HARDWAREQUERY vhaQuery;
+
+    /* Initialize hardware access */
+    ATIHAP_InitHWAccess();
+
+    /* Query hardware information */
+    memset(&vhaQuery, 0, sizeof(VHA_HARDWAREQUERY));
+    vhaQuery.uSize = sizeof(VHA_HARDWAREQUERY);
+    vhaQuery.uCards = 0;
+    vhaQuery.ulCodedWidth = 0;
+    vhaQuery.ulCodedHeight = 0;
+    VHA_HardwareQuery(&vhaQuery);
+
+#ifdef DEBUG_R128VHA
+    printf("VHA_HardwareQuery :\n");
+    printf("uHandle = %d\n", vhaQuery.uHandle);
+    if(vhaQuery.ulHWCaps & VHA_HWCAPS_IDCTMC)
+      printf("Hardware supports iScan, iDCT, and MC.\n");
+    if(vhaQuery.ulHWCaps & VHA_HWCAPS_SUBPIC)
+      printf("Hardware supports Sub-picture.\n");
+    printf("ulMinOvlyBuffer = %d\n", vhaQuery.ulMinOvlyBuffer);
+    printf("ulMaxOvlyBuffer = %d\n", vhaQuery.ulMaxOvlyBuffer);
+#endif
+
+    return(vhaQuery.uHandle);
+}
+
+/* Create a new overlay */
+struct vhar128_image * vhar128_newimage(unsigned int handle, unsigned long width, unsigned long height)
+{
+  struct vhar128_image * image;
+
+  image = (struct vhar128_image *) malloc(sizeof *image);
+  
+  image->overlay = (OVDESCRIPTION *) malloc(sizeof *image->overlay);
+  memset(image->overlay, 0, sizeof(OVDESCRIPTION));
+  image->overlay->uSize = sizeof(OVDESCRIPTION);
+  image->overlay->ulOVFormat = OV_FORMAT_YUV12;
+  image->overlay->uWidth = width;
+  image->overlay->uHeight = height;
+  CreateOVSurface(handle, image->overlay);
+
+  return(image);
+}
+
+/* Lock overlay */
+void vhar128_lockimage(unsigned int handle, struct vhar128_image * image, SDL_Overlay * ov)
+{
+    struct private_yuvhwdata * hwdata;
+
+#ifdef DEBUG_R128VHA
+    /* show locked overlay */
+    SetOVSurface(handle, image->overlay);
+#endif
+
+    hwdata = (struct private_yuvhwdata *) malloc(sizeof *hwdata);
+    hwdata->surface = (OVSURFACE *) malloc(sizeof *hwdata->surface);
+    hwdata->surface->uSize = sizeof(OVSURFACE);
+
+    LockOVSurface(handle, image->overlay, hwdata->surface);
+
+    /* create an SDL_Overlay from the information in the ATI overlay */
+    ov->format = SDL_YV12_OVERLAY;
+    ov->w = image->overlay->uWidth;
+    ov->h = image->overlay->uHeight;
+    ov->planes = 3;
+    ov->pitches = (Uint16 *) malloc(ov->planes * sizeof(Uint16));
+    ov->pitches[0] = hwdata->surface->uPitchPlane1;
+    ov->pitches[1] = hwdata->surface->uPitchPlane3;
+    ov->pitches[2] = hwdata->surface->uPitchPlane2;
+    ov->pixels = (Uint8 **) malloc(ov->planes * sizeof(void *));
+    ov->pixels[0] = (Uint8 *) hwdata->surface->pSurfPlane1;
+    ov->pixels[1] = (Uint8 *) hwdata->surface->pSurfPlane3;
+    ov->pixels[2] = (Uint8 *) hwdata->surface->pSurfPlane2;
+    ov->hwdata = hwdata;
+}
+
+/* Unlock the overlay */
+void vhar128_unlockimage(unsigned int handle, struct vhar128_image * image, SDL_Overlay * ov)
+{
+  UnlockOVSurface(handle, image->overlay, ov->hwdata->surface);
+  free(ov->pitches);
+  free(ov->pixels);
+  free(ov->hwdata->surface);
+  free(ov->hwdata);
+}
+
+/* Destroy the overlay */
+void vhar128_destroyimage(unsigned int handle, struct vhar128_image * image)
+{
+  DestroyOVSurface(handle, image->overlay);
+  free(image->overlay);
+  free(image);
+}
+
+/* Setup hardware decoding */
+int vhar128_init(unsigned int handle, unsigned long width, unsigned long height, struct vhar128_image *ring[], int ring_size)
+{
+    VHA_INIT vhaInit;
+    register int i;
+
+    memset(&vhaInit, 0, sizeof(VHA_INIT));
+
+    /* obtain yv12 offset and send it to vha */
+    for(i = 0; i < ring_size; i++)
+    {
+      vhaInit.yv12[i].ulOffsetY = ring[i]->overlay->OVOffset.ulOfsPlane1;
+      vhaInit.yv12[i].ulOffsetU = ring[i]->overlay->OVOffset.ulOfsPlane2;
+      vhaInit.yv12[i].ulOffsetV = ring[i]->overlay->OVOffset.ulOfsPlane3;
+      vhaInit.yv12[i].ulPitchY  = ring[i]->overlay->OVOffset.uPitchPlane1;
+      vhaInit.yv12[i].ulPitchUV = ring[i]->overlay->OVOffset.uPitchPlane2;
+    }
+    vhaInit.ulNumYV12Buffer = ring_size;
+    vhaInit.uSize = sizeof(VHA_INIT);
+    vhaInit.ulHWSupports = VHA_HWCAPS_IDCTMC;
+    vhaInit.ulCodedWidth = width;
+    vhaInit.ulCodedHeight = height;
+
+#ifdef DEBUG_R128VHA
+    /* set region for showing ATI overlay on the screen */
+    {
+      RCTL rSrc, rDst, rView;
+
+      rView.left = rView.top = 0;
+      rView.right = width;
+      rView.bottom = height;
+      rSrc.left = rSrc.top = 0;
+      rSrc.right = width;
+      rSrc.bottom = height;
+      rDst.left = 0;
+      rDst.top = 0;
+      rDst.right = width;
+      rDst.bottom = height;
+      
+      UpdateOVPosition(handle, &rSrc, &rDst, &rView, OV_SHOW);
+
+      SetOVSurface(handle, ring[0]->overlay);
+    }
+#endif
+
+    return(VHA_Init(handle, &vhaInit));
+}
+
+/* Setup decoding of a new picture */
+int vhar128_newdecode(unsigned int handle, int back, int forw, int current)
+{
+  VHA_NEWDECODE vhaND;
+  int retval;
+
+  memset(&vhaND, 0, sizeof(VHA_NEWDECODE));
+  vhaND.uSize = sizeof(VHA_NEWDECODE);
+  vhaND.BackwardRefFrame[0] = vhaND.BackwardRefFrame[1] = back;
+  vhaND.ForwardRefFrame[0] = vhaND.ForwardRefFrame[1] = forw;
+  vhaND.DecodeFrame = current;
+  vhaND.PictureStructure = VHA_PS_FRAME_PICTURE;
+
+  if((retval = VHA_NewDecode(handle, &vhaND)) != VHA_OK)
+    vhar128_perror("vhar128_newdecode", retval);
+
+  return(retval);
+}
+
+/* Send a macroblock to the hardware */
+int vhar128_macroblock(unsigned int handle, int mb_x, int mb_y, int intra, int back, int forw, int mv_back_x, int mv_back_y, int mv_forw_x, int mv_forw_y, long runlevel[6][130])
+{
+  VHA_MACROBLOCK vhaMB;
+  int retval;
+
+  memset(&vhaMB, 0, sizeof(VHA_MACROBLOCK));
+  vhaMB.ulSize = sizeof(VHA_MACROBLOCK);
+
+  memcpy(vhaMB.RunLevel, runlevel, 6*130*sizeof(long));
+
+  vhaMB.mb_x = mb_x;
+  vhaMB.mb_y = mb_y;
+  vhaMB.mbType = (intra)?VHA_MBT_INTRA:0;
+  if(forw) vhaMB.mbType |= VHA_MBT_MOTION_FORWARD;
+  if(back) vhaMB.mbType |= VHA_MBT_MOTION_BACKWARD;
+  vhaMB.PredictionType = VHA_PT_FRAME_BASED;
+  vhaMB.ScanType = SCAN_ZIG_ZAG;
+  vhaMB.dct_type = 0;
+  vhaMB.vector[0][0][0] = mv_forw_x;
+  vhaMB.vector[0][0][1] = mv_forw_y;
+  vhaMB.vector[0][1][0] = mv_back_x;
+  vhaMB.vector[0][1][1] = mv_back_y;
+
+  if((retval = VHA_Macroblock(handle, &vhaMB)) != VHA_OK)
+    vhar128_perror("vhar128_macroblock", retval);
+
+  return(retval);
+}
+
+/* Flush all macroblocks */
+int vhar128_flush(unsigned int handle)
+{
+  VHA_DECODECOMMAND vhaDC;
+  int retval;
+
+  memset(&vhaDC, 0, sizeof(VHA_DECODECOMMAND));
+  vhaDC.uSize = sizeof(VHA_DECODECOMMAND);
+  vhaDC.ulCommand = VHA_CMD_FLUSH;
+
+  if((retval = VHA_DecodeCommand(handle, &vhaDC)) != VHA_OK)
+    vhar128_perror("vhar128_flush", retval);
+
+  return(retval);
+}
+
+/* Close hardware decoding */
+void vhar128_close(unsigned int handle)
+{
+    VHA_Close(handle);
+}
+
+/* Close hardware access */
+void vhar128_delete()
+{
+    ATIHAP_CloseHWAccess();    
+}
+
+#endif
diff -Naur smpeg/video/vhar128.h smpeg.patched/video/vhar128.h
--- smpeg/video/vhar128.h	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/video/vhar128.h	Mon Sep 25 20:04:28 2000
@@ -0,0 +1,30 @@
+/* ATI Rage128 video hardware acceleration */
+#ifndef _VHAR128_H_
+#define _VHAR128_H_
+
+#include "SDL.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct vhar128_image;
+
+unsigned int vhar128_new();
+int vhar128_init(unsigned int handle, unsigned long width, unsigned long height, struct vhar128_image *ring[], int ring_size);
+int vhar128_newdecode(unsigned int handle, int back, int forw, int current);
+int vhar128_macroblock(unsigned int handle, int mb_x, int mb_y, int intra, int back, int forw, int mv_back_x, int mv_back_y, int mv_forw_x, int mv_forw_y, long runlevel[6][130]);
+
+int vhar128_flush(unsigned int handle);
+void vhar128_close(unsigned int handle);
+void vhar128_delete();
+
+struct vhar128_image * vhar128_newimage(unsigned int handle, unsigned long width, unsigned long height);
+void vhar128_lockimage(unsigned int handle, struct vhar128_image * image, SDL_Overlay * surface);
+void vhar128_unlockimage(unsigned int handle, struct vhar128_image * image, SDL_Overlay * surface);
+void vhar128_destroyimage(unsigned int handle, struct vhar128_image * image);
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* _VHAR128_H_ */
diff -Naur smpeg/video/video.cpp smpeg.patched/video/video.cpp
--- smpeg/video/video.cpp	Wed Sep  6 10:12:02 2000
+++ smpeg.patched/video/video.cpp	Sun Sep 24 02:18:17 2000
@@ -49,8 +49,17 @@
 
 /* We use FULL_COLOR_DITHER code for SMPEG */
 #define DISABLE_DITHER
+
+/* Correct bad motion information */
 #define LOOSE_MPEG
 
+/* If hardware accelerated, prevent use of dither code */
+#ifdef USE_ATI
+#ifndef DISABLE_DITHER
+#define DISABLE_DITHER
+#endif
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -61,8 +70,12 @@
 #include "util.h"
 #include "proto.h"
 
+#ifdef USE_ATI
+#include "vhar128.h"
+#endif
 
 /* Declarations of functions. */
+#ifndef USE_ATI
 static void ReconIMBlock( VidStream*, int bnum );
 static void ReconPMBlock( VidStream*, int bnum,
         int recon_right_for, int recon_down_for, int zflag );
@@ -74,6 +87,7 @@
 static void ReconSkippedBlock( unsigned char *source, unsigned char *dest,
       int row, int col, int row_size, int right, int down,
       int right_half, int down_half, int width );
+#endif /* USE_ATI */
 static void DoPictureDisplay( VidStream* );
 static int ParseSeqHead( VidStream* );
 static int ParseGOP( VidStream* );
@@ -750,6 +764,11 @@
     /* Reset everything for start of display */
     ResetVidStream(vs);
 
+#ifdef USE_ATI
+    /* Initialize Rage128 hardware */
+    vs->ati_handle = vhar128_new();
+#endif
+
     /* Return structure. */
 
     return vs;
@@ -868,7 +887,7 @@
     {
         if( astream->ring[i] != NULL )
         {
-            DestroyPictImage( astream->ring[i] );
+            DestroyPictImage( astream, astream->ring[i] );
             astream->ring[i] = NULL;
         }
     }
@@ -876,6 +895,14 @@
     if( astream->ditherFlags != NULL )
         free( astream->ditherFlags );
 
+#ifdef USE_ATI
+    vhar128_close(astream->ati_handle);
+#endif
+
+#ifdef USE_ATI
+    vhar128_delete();
+#endif
+
     free( (char*) astream );
 }
 
@@ -908,10 +935,14 @@
     pi = (PictImage *) malloc(sizeof(PictImage));
 
     /* Create a YV12 image (Y + V + U) */
+#ifdef USE_ATI
+    pi->image = vhar128_newimage(vid_stream->ati_handle, w, h);
+#else
     pi->image = (unsigned char *) malloc(w*h*12/8);
     pi->luminance = (unsigned char *)pi->image;
     pi->Cr = pi->luminance + (w*h);
     pi->Cb = pi->luminance + (w*h) + (w*h)/4;
+#endif
   
     /* Alloc space for filter info */
     pi->mb_qscale = (unsigned short int *) malloc(vid_stream->mb_width * vid_stream->mb_height * sizeof(unsigned int));
@@ -932,12 +963,23 @@
     vid_stream->current = vid_stream->past = vid_stream->future = NULL;
     for (i = 0; i < RING_BUF_SIZE; i++) {
         if ( vid_stream->ring[i] ) {
-            DestroyPictImage(vid_stream->ring[i]);
+            DestroyPictImage(vid_stream, vid_stream->ring[i]);
         }
         vid_stream->ring[i] = NewPictImage( vid_stream, w, h, dst );
         if ( ! vid_stream->ring[i] )
             return false;
     }
+
+#ifdef USE_ATI
+    struct vhar128_image * ring[RING_BUF_SIZE];
+
+    for (i = 0; i < RING_BUF_SIZE; i++) {
+      ring[i] = vid_stream->ring[i]->image;
+    }
+
+    vhar128_init(vid_stream->ati_handle, w, h, ring, RING_BUF_SIZE);
+#endif
+
     return true;
 }
 
@@ -956,9 +998,13 @@
  *
  *--------------------------------------------------------------
  */
-void DestroyPictImage( PictImage* apictimage )
+void DestroyPictImage( VidStream* vid_stream, PictImage* apictimage )
 {
+#ifdef USE_ATI
+  vhar128_destroyimage(vid_stream->ati_handle, apictimage->image);
+#else
   if (apictimage->image != NULL) free(apictimage->image);
+#endif
 
   free(apictimage->mb_qscale);
   free(apictimage);
@@ -1696,6 +1742,7 @@
     }
     vid_stream->picture.user_data = get_ext_data(vid_stream);
   }
+
   /* Find a pict image structure in ring buffer not currently locked. */
 
   i = 0;
@@ -1719,6 +1766,34 @@
 
   vid_stream->mblock.past_mb_addr = -1;
 
+#ifdef USE_ATI
+  int back, forw, current;
+
+  back = forw = -1;
+  current = i;
+
+  /* Look for indexes of future and past frames */
+  for(i = 0; i < RING_BUF_SIZE; i++)
+  {
+    if(vid_stream->future == vid_stream->ring[i]) forw = i;
+    if(vid_stream->past == vid_stream->ring[i]) back = i;
+  }
+
+  /* Start decoding a new frame */
+  switch(vid_stream->picture.code_type)
+  {
+    case B_TYPE:
+      vhar128_newdecode(vid_stream->ati_handle, forw, back, current);
+    break;
+    case P_TYPE:
+      vhar128_newdecode(vid_stream->ati_handle, -1, forw, current);
+    break;
+    case I_TYPE:
+      vhar128_newdecode(vid_stream->ati_handle, -1, -1, current);
+    break;
+  }
+#endif
+
   return PARSE_OK;
 }
 
@@ -1783,9 +1858,15 @@
 
   /* Reset past dct dc y, cr, and cb values. */
 
+#ifdef USE_ATI
+  vid_stream->block.dct_dc_y_past = 0;
+  vid_stream->block.dct_dc_cr_past = 0;
+  vid_stream->block.dct_dc_cb_past = 0;
+#else
   vid_stream->block.dct_dc_y_past = 1024 << 3;
   vid_stream->block.dct_dc_cr_past = 1024 << 3;
   vid_stream->block.dct_dc_cb_past = 1024 << 3;
+#endif
 
   return PARSE_OK;
 }
@@ -1829,6 +1910,16 @@
   mbSizeCount = bitCountRead();
 #endif
 
+#ifdef USE_ATI
+  /* Empty macroblock */
+  vid_stream->block.dct_recon[0][0] = 0xFFFFFFFF;
+  vid_stream->block.dct_recon[1][0] = 0xFFFFFFFF;
+  vid_stream->block.dct_recon[2][0] = 0xFFFFFFFF;
+  vid_stream->block.dct_recon[3][0] = 0xFFFFFFFF;
+  vid_stream->block.dct_recon[4][0] = 0xFFFFFFFF;
+  vid_stream->block.dct_recon[5][0] = 0xFFFFFFFF;
+#endif
+
   /*
    * Parse off macroblock address increment and add to macroblock address.
    */
@@ -2112,7 +2203,8 @@
         } else {
           zero_block_flag = 1;
         }
-        
+
+#ifndef USE_ATI
         /* If macroblock is intra coded... */
         if (vid_stream->mblock.mb_intra) {
           ReconIMBlock(vid_stream, i);
@@ -2126,7 +2218,20 @@
           ReconBMBlock(vid_stream, i, recon_right_back, recon_down_back,
                        zero_block_flag);
         }
+#endif
       }
+
+#ifdef USE_ATI
+      vhar128_macroblock(vid_stream->ati_handle,
+			 (vid_stream->mblock.mb_address % vid_stream->mb_width) << 4,
+			 (vid_stream->mblock.mb_address / vid_stream->mb_width) << 4,
+			 vid_stream->mblock.mb_intra,
+			 mb_motion_back, mb_motion_forw,
+			 recon_right_back, recon_down_back,
+			 recon_right_for, recon_down_for,
+			 vid_stream->block.dct_recon);
+#endif
+
 #ifndef DISABLE_DITHER
     }
   }
@@ -2171,7 +2276,8 @@
   return PARSE_OK;
 }
 
-
+/* software decoder follows */
+#ifndef USE_ATI
 /*
  *--------------------------------------------------------------
  *
@@ -2209,7 +2315,6 @@
   mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width;
   mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width;
 
-
   /* If block is luminance block... */
 
   if (bnum < 4) {
@@ -3301,6 +3406,7 @@
   unsigned char *index, *rindex1, *bindex1;
   short int *blockvals;
   int forw_row_start, back_row_start, forw_col_start, back_col_start;
+
 #ifdef LOOSE_MPEG
   int lmaxx = vid_stream->mb_width*16-1;
   int lmaxy = vid_stream->mb_height*16-1;
@@ -3693,6 +3799,7 @@
   }
 }
 
+#endif /* USE_ATI */
 
 /*
  *--------------------------------------------------------------
@@ -3742,6 +3849,16 @@
     row = mb_row << 4;
     col = mb_col << 4;
 
+#ifdef USE_ATI
+    vhar128_macroblock(vid_stream->ati_handle,
+		       col,
+		       row,
+		       0,    /* skipped block are empty non-intra blocks */
+		       1, 0, /* P frames are based on past picture       */
+		       0, 0, /* backward motion is null                  */
+		       0, 0, /* forward  motion is null                  */
+		       vid_stream->block.dct_recon);
+#else
 
     /* For each row in macroblock luminance plane... */
 
@@ -3818,6 +3935,7 @@
       vid_stream->ditherFlags[addr] = 0;
     }
 #endif
+#endif /* USE_ATI */
   }
 
   vid_stream->mblock.recon_right_for_prev = 0;
@@ -3876,6 +3994,7 @@
   int c_illegal_back = 0;
 #endif
 
+
   /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */
 
   row_size = vid_stream->mb_width << 4;
@@ -3901,6 +4020,24 @@
     recon_down_back = vid_stream->mblock.recon_down_back_prev;
   }
 
+#ifdef USE_ATI
+
+  /* For each skipped macroblock do ... */
+  for (addr = vid_stream->mblock.past_mb_addr + 1;
+       addr < vid_stream->mblock.mb_address; addr++) {
+    
+    vhar128_macroblock(vid_stream->ati_handle,
+		       (addr % vid_stream->mb_width) << 4,
+		       (addr / vid_stream->mb_width) << 4,
+		       0,                                  /* skipped blocks are empty non-intra blocks */
+		       vid_stream->mblock.bpict_past_back, 
+		       vid_stream->mblock.bpict_past_forw,
+		       recon_right_back, recon_down_back,  /* backward motion */
+		       recon_right_for, recon_down_for,    /* forward  motion */
+		       vid_stream->block.dct_recon);
+  }
+
+#else
 
   /* If only one motion vector, do display copy, else do full
      calculation. 
@@ -4135,7 +4272,7 @@
     }
 
 #endif
-    
+
     /* If forward predicted, calculate prediction values. */
     
     if (vid_stream->mblock.bpict_past_forw) {
@@ -4317,9 +4454,11 @@
     }
 #endif
   }
+#endif /* USE_ATI */
 }
 
 
+#ifndef USE_ATI
 
 /*
  *--------------------------------------------------------------
@@ -4484,7 +4623,7 @@
   }
 }
 
-
+#endif /* USE_ATI */
 
 /*
  *--------------------------------------------------------------
@@ -4514,6 +4653,11 @@
     PrintOneStat();
 #endif
     CollectStats();
+#endif
+
+#ifdef USE_ATI
+    /* Flush the macroblocks to the hardware decoder */
+    vhar128_flush( vid_stream->ati_handle );
 #endif
 
     /* Update past and future references if needed. */
diff -Naur smpeg/video/video.h smpeg.patched/video/video.h
--- smpeg/video/video.h	Wed Sep  6 10:12:02 2000
+++ smpeg.patched/video/video.h	Fri Sep 22 20:12:47 2000
@@ -83,8 +83,7 @@
 
 /* Set ring buffer size. */
 
-//#define RING_BUF_SIZE 5
-#define RING_BUF_SIZE 3
+#define RING_BUF_SIZE 5
 
 /* Macros for picture code type. */
 
@@ -152,10 +151,14 @@
 /* Structure with reconstructed pixel values. */
 
 typedef struct pict_image {
+#ifdef USE_ATI
+  struct vhar128_image *image;
+#else
   unsigned char *image;                  /* YV12 format image  */
   unsigned char *luminance;              /* Luminance plane.   */
   unsigned char *Cr;                     /* Cr plane.          */
   unsigned char *Cb;                     /* Cb plane.          */
+#endif
   unsigned short int *mb_qscale;         /* macroblock info    */
   int locked;                            /* Lock flag.         */
   TimeStamp show_time;                   /* Presentation time. */
@@ -230,7 +233,11 @@
 /* Block structure. */
 
 typedef struct block {
+#ifdef USE_ATI
+  long int dct_recon[6][130];            /* Reconstructed dct runs & levels */
+#else
   short int dct_recon[8][8];             /* Reconstructed dct coeff matrix. */
+#endif
   short int dct_dc_y_past;               /* Past lum. dc dct coefficient.   */
   short int dct_dc_cr_past;              /* Past cr dc dct coefficient.     */
   short int dct_dc_cb_past;              /* Past cb dc dct coefficient.     */
@@ -316,6 +323,11 @@
 /* begining of added variables */
   bool need_frameadjust;
   int  current_frame;
+
+#ifdef USE_ATI
+  unsigned int ati_handle;
+#endif
+
 } VidStream;   
 
 /* Declaration of global display pointer. */
*************************************************************************
*** Applied ***
Date: Sat, 19 Aug 2000 00:22:25 +0900
From: Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>
Subject: lseek problem latest smpeg on FreeBSD

Hi.

I have problem on latest smpeg & FreeBSD.
It's difference in the spec of lseek.

FreeBSD's lseek has 64bit off_t type.

patch attached(smpg0817.diff)

MPEGsystem.cpp Uint32 -> off_t.
and plaympeg.c gtv.c small change.

Thanks.
-----------------------------------------------
Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>

Index: MPEGsystem.cpp
===================================================================
RCS file: /home/ncvs/smpeg/MPEGsystem.cpp,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 MPEGsystem.cpp
--- MPEGsystem.cpp	2000/08/18 12:39:45	1.1.1.1
+++ MPEGsystem.cpp	2000/08/18 15:07:36
@@ -946,8 +946,8 @@
 
 Uint32 MPEGsystem::TotalSize()
 {
-  Uint32 size;
-  Uint32 pos;
+  off_t size;
+  off_t pos;
 
   if(data_reader.fromData == true)
   {
@@ -1002,8 +1002,8 @@
 
 double MPEGsystem::TotalTime()
 {
-  Uint32 size, pos;
-  Uint32 file_ptr;
+  off_t size, pos;
+  off_t file_ptr;
   Uint8 * buffer, * p;
   Uint8 c;
   double time;
@@ -1304,7 +1304,7 @@
         system->data_reader.offset = 0;
       } else {
 	      /* Get back to the beginning of the stream if possible */
-	      if(lseek(system->mpeg_fd, 0, SEEK_SET) == (long) -1)
+	      if(lseek(system->mpeg_fd, 0, SEEK_SET) == (off_t) -1)
 	      {
 		if(errno != ESPIPE)
 		{
Index: gtv.c
===================================================================
RCS file: /home/ncvs/smpeg/gtv.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 gtv.c
--- gtv.c	2000/08/18 12:39:45	1.1.1.1
+++ gtv.c	2000/08/18 12:43:27
@@ -382,6 +382,7 @@
     gint ignored = 0;
     GtkWidget* text = NULL;
     SMPEG_Info* info = NULL;
+    int hh,mm,ss;
 
     dialog = create_file_info_dialog( );
     ok = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( dialog ), "ok" ) );
@@ -392,14 +393,17 @@
 
     /* Actually stuff some data in there. */
     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
-    g_snprintf( buffer, 1024, "Filename: %s\nStream: %s\nVideo: %dx%d resolution\nAudio: %s\nSize: %d\n",
+    hh = info->total_time / 3600;
+    mm = (info->total_time - hh * 3600)/60;
+    ss = ((int)info->total_time % 60);
+    g_snprintf( buffer, 1024, "Filename: %s\nStream: %s\nVideo: %dx%d resolution\nAudio: %s\nSize: %d\nTime %d:%02d:%02d\n",
 		(gchar*) gtk_object_get_data( GTK_OBJECT( raw ), "filename_buffer" ),
 		( info->has_audio && info->has_video ) ? "system" :
 		( info->has_video ? "video" :
 		( info->has_audio ? "audio" : "not MPEG" ) ),
 		info->width, info->height,
 		( info->has_audio ? info->audio_string : "none" ),
-		info->total_size );
+		info->total_size , hh,mm,ss);
     text = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( dialog ), "text" ) );
     gtk_editable_insert_text( GTK_EDITABLE( text ), buffer, strlen( buffer ), &ignored );
 
Index: plaympeg.c
===================================================================
RCS file: /home/ncvs/smpeg/plaympeg.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 plaympeg.c
--- plaympeg.c	2000/08/18 12:39:45	1.1.1.1
+++ plaympeg.c	2000/08/18 12:46:45
@@ -33,7 +33,9 @@
 #define RAW_SUPPORT  /* Raw data transport support */
 #define HTTP_SUPPORT /* HTTP support */
 #define FTP_SUPPORT  /* FTP support */
+#ifdef __linux__
 #define VCD_SUPPORT  /* Video CD support */
+#endif
 #endif
 
 #ifdef NET_SUPPORT
*************************************************************************
*** Applied ***
Date: Tue, 19 Sep 2000 17:30:33 +0200
From: Tim Jansen <tim@tjansen.de>
Subject: SMPEG/splay bugfix

Hi...

The following bugfix should prevent buffer overflows in audio/mpeglayer3.cpp 
in some rare cases (I dont have a file that produces the bug directly, but 
I run into it in my libmedia splay plugin when I accidentally skipped some 
frames).

Basically, if i is set to sfBandIndex->l[22] in the block before, i is 576,
k is somewhere around 56 (or something similar, depends on the frequency) and 
the array dimension is 576, too. This results in 56 REAL values written
after the end of the array, corrupting the stack.

bye...


--- mpeglayer3.cpp.orig	Tue Sep 19 17:19:21 2000
+++ mpeglayer3.cpp	Tue Sep 19 17:19:04 2000
@@ -1192,7 +1192,7 @@
 	}
       }
 
-      {
+      if (i <= sfBandIndex->l[21]) {
 	int k,t,tt;
 
 	tt=sfBandIndex->l[20];
*************************************************************************
*** Applied ***
Date: Sat, 02 Sep 2000 17:21:49 +0200
From: Tim Jansen <ml@tjansen.de>
Subject: SMPEG/Splay bugfix


Hi...

I have found a small bug in smpeg/splay:
the MPEGaudio::loadheader() method  in audio/mpegtoraw.cpp does not
check for the reserved frequency (11). If it loads a header with the
invalid frequency this will create an out-of-bound condition when the
MPEGaudio::frequencies array is accessed a few lines below (and will
probably cause a devision-by-zero for MPEG2 streams, look at the value
following the frequencies array in mpegtables.cpp).
Bugfix attached.

bye...

--- mpegtoraw.cpp.original Sat Sep  2 16:59:59 2000
+++ mpegtoraw.cpp Sat Sep  2 17:04:25 2000
@@ -171,6 +171,8 @@
     padding = (c & 1);
     c >>= 1;
     frequency = (_frequency) (c&3);
+    if (frequency == 3)
+           return false;
     c >>= 2;
     bitrateindex = (int) c;
     if( bitrateindex == 15 )

*************************************************************************
*** Applied ***
Date: Tue, 05 Sep 2000 20:19:37 +0200
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: SMPEG Status?

Hi!

        Here it is finally, prepare for a long mail :)

First of all, the things I fixed that are not related to filtering:

you wrote:
> This is true of just about every big movie I know of (Metal Gear Solid,
> Halo intro, etc.)  After a certain consistent amount of time, the video
> stops and the sound keeps going.
> 
> Any ideas?

this should be fixed. It was insert_packet that inserted a 0 byte long packet
which was interpreted as EOF by the video decoder.
 
Chris Jensen <chris@sourcelight.com> wrote:
> I think I found a bug in smpeg... setting loop to true and then calling
> SMPEG_status causes a Seg fault... here is the gdb output and backtrace,
> and the code that caused it.  I'll see if I can track it down when I get
> time...
 
Olle Hllns <olle@xmms.org> wrote:
> 2. SMPEG_enablevideo(mpeg, FALSE); then try to seek some will result in
> nice baboom.. try: plaympeg --novideo --seek somdamnbytes /pr0n/xxx.mpeg :)
> 

fixed. just a missing 'if( _stream ) ...'.

Also,
* fixed incorrect size when not multiple of 16 (see SimWars: 
http://www-eleves.enst-bretagne.fr/~chappeli/simwars_extract.mpg)
Actually, this is a side effect of the filter code. More on this later.

* fixed To end -> Stop -> To end crash (from current frame adjustement code)

* fixed crash in crash2.mpg (see smpeg news message from 08/09/00 00:12)
I integrated lossresist patch from Carsten Griwodz (posted on the news on
07/17/00) which seems to correct this bug as long as making network streaming
much more stable. (see the #ifdef NO_GRIFF_MODS everywhere, define if you
wish to disable his code)

Finally, I added libs for network support under Solaris in configure.in, and
corrected VCD support to apply under linux only (not all unix).

Now for the filter code:
        Filters are applied just before displaying the picture, that is, you
get the image from the video decoder, and the region you must copy to the
screen (not always the full picture, in the case of MPEG not multiple of 16
for example) and you call the filter, which must copy the source rectangle to
the video overlay and do whatever computation it wants on the pixels while
doing this.
        As I needed to specify the source region, I also added a interface
(setdisplayregion) to change it on the fly, thus allowing to copy whatever
rectangle region of the movie you want.

+--------------------+                    +--------------------+
+--------------------+
|  decoded frame     |                    |filtered|           |
|      window        |
|                    |                    |  image |-------------------> SDL
strech code ----> |                    |
|     +----------+   |                    |--------+           |
|                    |
|     | src rect |------->   filter ----> |                    |
|       dest         |
|     |          |   |                    |                    |
|       rect         |
|     +----------+   |                    |       video        |
|                    |
|                    |                    |      overlay       |
|                    |
+--------------------+                    +--------------------+
+--------------------+

There is always an active filter. The default filter (called 'null') just
copies source rect to the video overlay.
Currently there are 3 builtin filters in SMPEG:
        * the null filter.
        * the bilinear filter: just a basic low pass (smoothing) filter.
        * the deblocking filter: inspired from the pseudo code from Carlo Daffara.
I optimized it to remove divides which are quite time consuming, but it's still
relatively slow.

There is also a C interface for using external filters (see SMPEG_filter
function) to allow user filters. To define a new filter, you need a callback
function that will be called anytime the src rect needs to be filtered and
copied to the overlay, and a destroy function for releasing the SMPEG_Filter
structure and optional private data. There is a flags field in the
SMPEG_Filter structure to ask the video decoder to provide extra information
(which may require extra time to compute), for example, this is needed by
the deblocking filter to ask for per-macroblock quantization error.
        A call to the SMPEG_filter function will return a pointer to the
previous filter used, to free it. Use the destroy function pointer for this.

Anyway, the best for understanding all this stuff is to take a look to gtv.c (I
added a toggle button to switch the deblocking filter on/off) and MPEGfilter.cpp
(implementation of the 3 filters)

There is a lot of things this patch will allow (such as correcting gamma,
contrast, luminance,etc on the fly, zooming on regions...) 

I know this is quite a huge patch, so if you have any questions about it, just
ask.
Also this makes me think one (maybe not me nor you, we're busy coding :)) should
start a documentation for SMPEG, just as the one for SDL. Maybe we should ask on
the news...

Hope this is ok for you, send comments, I need feedback :)

Now, let's take a look to that ATI stuff ;)

see ya,
Vivien.

...

Hi!

        here is the new filter patch.

Additionnaly to what I already told in my last mails about it, it fixes:
        * crashes in MPEGs when audio frames are not always stereo or mono
        * crashes in the video decoders due to invalid motion information
        * crashed when using software overlays. This will require SDL 1.1.5 or
more now.

I'm finishing writting the SDL patch right now so that you can test
(patch SDL1.1.4 while we haven't found what was wrong with SDL1.1.5
overlays) :)

see ya,
Vivien.

diff -Naur smpeg/MPEG.cpp smpeg.patched/MPEG.cpp
--- smpeg/MPEG.cpp	Wed Aug  9 22:05:28 2000
+++ smpeg.patched/MPEG.cpp	Mon Sep  4 18:07:20 2000
@@ -348,6 +348,11 @@
     videoaction->ScaleDisplayXY(w, h);
   }
 }
+void MPEG::SetDisplayRegion(int x, int y, int w, int h) {
+  if ( VideoEnabled() ) {
+    videoaction->SetDisplayRegion(x, y, w, h);
+  }
+}
 void MPEG::RenderFrame(int frame) {
   /* Prevent acces to the audio stream to avoid filling it */
   if( audiostream ) audiostream->enable(false);
@@ -367,6 +372,13 @@
   }
 
   if( audiostream ) audiostream->enable(true);
+}
+
+MPEG_Filter * MPEG::Filter(MPEG_Filter * filter)
+{
+  if ( VideoEnabled() ) {
+    return(videoaction->Filter(filter));
+  }
 }
 
 void MPEG::Seek(int position)
diff -Naur smpeg/MPEG.h smpeg.patched/MPEG.h
--- smpeg/MPEG.h	Wed Aug  9 22:05:28 2000
+++ smpeg.patched/MPEG.h	Mon Sep  4 18:07:20 2000
@@ -34,6 +34,7 @@
 #include "MPEGaudio.h"
 #include "MPEGvideo.h"
 #include "MPEGsystem.h"
+#include "MPEGfilter.h"
 
 #define LENGTH_TO_CHECK_FOR_SYSTEM 0x50000	// Added by HanishKVC
 
@@ -88,8 +89,10 @@
 		                 MPEG_DisplayCallback callback);
     void MoveDisplay(int x, int y);
     void ScaleDisplayXY(int w, int h);
+    void SetDisplayRegion(int x, int y, int w, int h);
     void RenderFrame(int frame);
     void RenderFinal(SDL_Surface *dst, int x, int y);
+    MPEG_Filter * Filter(MPEG_Filter * filter);
 
 public:
     /* We need to have separate audio and video streams */
diff -Naur smpeg/MPEGaction.h smpeg.patched/MPEGaction.h
--- smpeg/MPEGaction.h	Wed Aug  9 22:05:28 2000
+++ smpeg.patched/MPEGaction.h	Mon Sep  4 18:07:27 2000
@@ -94,6 +94,28 @@
 typedef void(*MPEG_DisplayCallback)(SDL_Surface* dst, int x, int y,
                                      unsigned int w, unsigned int h);
 
+/* Matches the declarations in smpeg.h */
+/* SMPEG filter info flags */
+#define SMPEG_FILTER_INFO_MB_ERROR    1
+#define SMPEG_FILTER_INFO_PIXEL_ERROR 2
+
+/* Filter info from SMPEG */
+typedef struct MPEG_FilterInfo {
+  Uint16* yuv_mb_square_error;
+  Uint16* yuv_pixel_square_error;
+} MPEG_FilterInfo;
+
+/* MPEG filter definition, matches SMPEG filter definition in smpeg.h */
+typedef void (* MPEG_FilterCallback)( SDL_Overlay * dest, SDL_Overlay * source, SDL_Rect * region, MPEG_FilterInfo * filter_info, void * data );
+typedef void (* MPEG_FilterDestroy)( struct MPEG_Filter * filter );
+
+typedef struct MPEG_Filter {
+  Uint32 flags;
+  void * data;
+  MPEG_FilterCallback callback;
+  MPEG_FilterDestroy destroy;
+} MPEG_Fitler;
+
 /* For getting info about the video portion of the stream */
 typedef struct MPEG_VideoInfo {
     int width;
@@ -115,8 +137,10 @@
                                 MPEG_DisplayCallback callback) = 0;
     virtual void MoveDisplay(int x, int y) = 0;
     virtual void ScaleDisplayXY(int w, int h) = 0;
+    virtual void SetDisplayRegion(int x, int y, int w, int h) = 0;
     virtual void RenderFrame(int frame) = 0;
     virtual void RenderFinal(SDL_Surface *dst, int x, int y) = 0;
+    virtual MPEG_Filter * Filter(MPEG_Filter * filter) = 0;
 protected:
     MPEGaudioaction *time_source;
 };
diff -Naur smpeg/MPEGaudio.h smpeg.patched/MPEGaudio.h
--- smpeg/MPEGaudio.h	Wed May 31 00:21:04 2000
+++ smpeg.patched/MPEGaudio.h	Mon Sep  4 18:07:27 2000
@@ -183,6 +183,7 @@
     bool sdl_audio;
     MPEGstream *mpeg;
     int valid_stream;
+    bool stereo;
     double rate_in_s;
     Uint32 frags_playing;
     Uint32 frag_time;
diff -Naur smpeg/MPEGfilter.cpp smpeg.patched/MPEGfilter.cpp
--- smpeg/MPEGfilter.cpp	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/MPEGfilter.cpp	Mon Sep  4 19:37:19 2000
@@ -0,0 +1,360 @@
+/*
+    SMPEG - SDL MPEG Player Library
+    Copyright (C) 1999  Loki Entertainment Software
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "MPEG.h"
+#include <stdlib.h>
+#include <string.h>
+
+/**************************************************/
+/* The null filter. Copies source rect to overlay */
+/**************************************************/
+
+MPEG_Filter_null::MPEG_Filter_null()
+{
+  /* the null filter requires no extra info */
+  flags = 0;
+  /* no private data */
+  data = 0;
+  /* set the function pointers to the callback and destroy functions */
+  callback = Callback;
+  destroy = Destroy;
+}
+
+void MPEG_Filter_null::Callback(SDL_Overlay * dest, SDL_Overlay * source, SDL_Rect * region, MPEG_FilterInfo * info, void * data)
+{
+  register Uint32 y;
+  register Uint8 * s, * d;
+
+  s = (Uint8 *) source->pixels;
+  d = (Uint8 *) dest->pixels;
+
+  /* Y component */
+  s += region->y * source->pitch + region->x; /* Go to the top left corner of the source rectangle */
+  for(y = 0; y < region->h; y++)
+  {
+    memcpy(d, s, region->w);   /* Copy lines */
+    s += source->pitch;
+    d += dest->pitch;
+  }
+  s += (source->h - region->h - region->y) * source->pitch - region->x;
+  d += (dest->h - region->h) * dest->pitch;              /* Go to end */
+
+  /* U component */
+  s += (region->y >> 1) * (source->pitch >> 1) + (region->x >> 1);
+  for(y = 0; y < region->h; y+=2)
+  {
+    memcpy(d, s, region->w >> 1);
+    s += source->pitch >> 1;
+    d += dest->pitch >> 1;
+  }
+  s += (((source->h - region->h - region->y) >> 1) * (source->pitch >> 1)) - (region->x >> 1);
+  d += ((dest->h - region->h) >> 1) * (dest->pitch >> 1);
+  
+  /* V component */
+  s += (region->y >> 1) * (source->pitch >> 1) + (region->x >> 1);
+  for(y = 0; y < region->h; y+=2)
+  {
+    memcpy(d, s, region->w >> 1);
+    s += source->pitch >> 1;
+    d += dest->pitch >> 1;
+  }
+}
+
+void MPEG_Filter_null::Destroy(MPEG_Filter * filter)
+{
+  delete (MPEG_Filter_null *) filter;
+}
+
+/************************************************************************************/
+/* The bilinear filter. A basic low-pass filter that will produce a smoother image. */
+/* It uses the following convolution matrix:         [0 1 0]                        */
+/*                                                   [1 4 1]                        */
+/*                                                   [0 1 0]                        */
+/************************************************************************************/
+
+MPEG_Filter_bilinear::MPEG_Filter_bilinear()
+{
+  flags = 0;
+  data = 0;
+  callback = Callback;
+  destroy = Destroy;
+}
+
+void MPEG_Filter_bilinear::Callback(SDL_Overlay * dest, SDL_Overlay * source, SDL_Rect * region, MPEG_FilterInfo * info, void * data)
+{
+  register Uint32 x, y;
+  register Uint8 * s, * d;
+
+  s = (Uint8 *) source->pixels;
+  d = (Uint8 *) dest->pixels;
+
+  s += region->y * source->pitch + region->x;
+
+  /* Skip first line */
+  memcpy(d, s, region->w);
+  d += dest->pitch;
+  s += source->pitch;
+
+  for(y = 1; y < region->h - 1; y++)
+  {
+    /* Skip first pixel */
+    *d++ = *s++;
+
+    for(x = 1; x < region->w - 1; x++)
+    {
+	*d++ = 
+	  (((*s) << 2)           +  // 4*(x,y)   +
+	   *(s - source->pitch)  +  //   (x,y-1) +
+	   *(s - 1)              +  //   (x-1,y) +
+	   *(s + 1)              +  //   (x+1,y) +
+	   *(s + source->pitch))    //   (x,y+1)
+	  >> 3;                     // / 8
+	s++;
+    }
+
+    /* Skip last pixel */
+    *d++ = *s++;
+
+    /* Go to next line */
+    d += dest->pitch - region->w;
+    s += source->pitch - region->w;
+  }
+
+  /* Skip last line */
+  memcpy(d, s, region->w);
+  d += dest->pitch;
+  s += source->pitch;
+
+  /* Go to end of Y plane */
+  s -= region->y * source->pitch + region->x;
+  s += (source->h - region->y - region->h) * source->pitch;
+  d += (dest->h - region->h) * dest->pitch;
+
+  /* U component (unfiltered) */
+  s += (region->y >> 1) * (source->pitch >> 1) + (region->x >> 1);
+  for(y = 0; y < region->h; y+=2)
+  {
+    memcpy(d, s, region->w >> 1);
+    s += source->pitch >> 1;
+    d += dest->pitch >> 1;
+  }
+  s += (((source->h - region->h - region->y) >> 1) * (source->pitch >> 1)) - (region->x >> 1);
+  d += ((dest->h - region->h) >> 1) * (dest->pitch >> 1);
+
+  /* V component (unfiltered) */
+  s += (region->y >> 1) * (source->pitch >> 1) + (region->x >> 1);
+  for(y = 0; y < region->h; y+=2)
+  {
+    memcpy(d, s, region->w >> 1);
+    s += source->pitch >> 1;
+    d += dest->pitch >> 1;
+  }
+}
+
+void MPEG_Filter_bilinear::Destroy(MPEG_Filter * filter)
+{
+  delete (MPEG_Filter_bilinear *) filter;
+}
+
+/***************************************************************************************************/
+/* The deblocking filter. It filters block borders and non-intra coded blocks to reduce blockiness */ 
+/***************************************************************************************************/
+
+MPEG_Filter_deblocking::MPEG_Filter_deblocking()
+{
+  Uint16 * coeffs, * c;
+  Uint32 pos, q, q1, q5, q9, d;
+
+  /* precalc table is 256Kb long */
+  c = new Uint16[8*32*512];
+  data = (void *) c;
+
+  /* precalc filter coefficients:                                     */
+  /*                           1                                      */
+  /* coeffs(Q,d,x,y) = _____________________                          */
+  /*                           d(x,y)*d(x,y)                          */
+  /*                   1  +    _____________                          */
+  /*                             Q*Q*k(x,y)                           */
+  /* where                                                            */
+  /* k(x,y) = [ 9 9 9 9 9 9 9 9 ]                                     */
+  /*          [ 9 5 5 5 5 5 5 9 ]                                     */
+  /*          [ 9 5 1 1 1 1 5 9 ]                                     */
+  /*          [ 9 5 1 1 1 1 5 9 ]                                     */
+  /*          [ 9 5 1 1 1 1 5 9 ]                                     */
+  /*          [ 9 5 1 1 1 1 5 9 ]                                     */
+  /*          [ 9 5 5 5 5 5 5 9 ]                                     */
+  /*          [ 9 9 9 9 9 9 9 9 ]                                     */
+  /* and Q is the quantization error for the block                    */
+  /* and d is the difference between current pixel and neighbor pixel */
+  /*                                                                  */
+  /* this is for the math :), now some additional tricks:             */
+  /*                                                                  */
+  /* all coeffs are multiplied by 65536 for precision (fixed point)   */
+  /* and d is translated from [-128,127] to [0,255] (array indexation)*/
+
+
+  for(d = 0; d < 512*8; d++)
+    *c++ = 0;
+
+  for(q = 1; q < 32; q++)
+  {
+    q1 = q*q;
+    q9 = (q1 << 3) + q1;
+    q5 = (q1 << 2) + q1;
+    
+    for(d = 0; d < 256; d++)
+    {
+      *c++ = (Uint16) ((q9 << 16) / ((256 - d)*(256 - d) + q9));
+      *c++ = (Uint16) ((q5 << 16) / ((256 - d)*(256 - d) + q5));
+      *c++ = (Uint16) ((q1 << 16) / ((256 - d)*(256 - d) + q1));
+      *c++ = (Uint16) ((q1 << 16) / ((256 - d)*(256 - d) + q1));
+      *c++ = (Uint16) ((q1 << 16) / ((256 - d)*(256 - d) + q1));
+      *c++ = (Uint16) ((q1 << 16) / ((256 - d)*(256 - d) + q1));
+      *c++ = (Uint16) ((q5 << 16) / ((256 - d)*(256 - d) + q5));
+      *c++ = (Uint16) ((q9 << 16) / ((256 - d)*(256 - d) + q9));
+    }
+    for(d = 0; d < 256; d++)
+    {
+      *c++ = (Uint16) ((q9 << 16) / (d*d + q9));
+      *c++ = (Uint16) ((q5 << 16) / (d*d + q5));
+      *c++ = (Uint16) ((q1 << 16) / (d*d + q1));
+      *c++ = (Uint16) ((q1 << 16) / (d*d + q1));
+      *c++ = (Uint16) ((q1 << 16) / (d*d + q1));
+      *c++ = (Uint16) ((q1 << 16) / (d*d + q1));
+      *c++ = (Uint16) ((q5 << 16) / (d*d + q5));
+      *c++ = (Uint16) ((q9 << 16) / (d*d + q9));
+    }
+  }
+
+  /* Ask the video decoder to provide per-block quantization error */
+  flags = SMPEG_FILTER_INFO_MB_ERROR;
+
+  callback = Callback;
+  destroy = Destroy;
+}
+
+MPEG_Filter_deblocking::~MPEG_Filter_deblocking()
+{
+  delete (Uint16 *) data;
+}
+
+void MPEG_Filter_deblocking::Callback(SDL_Overlay * dest, SDL_Overlay * source, SDL_Rect * region, MPEG_FilterInfo * info, void * data)
+{
+  Uint32 x, y;
+  Uint32 dL, dU, dR, dD;
+  Uint32 aL, aU, aR, aD;
+  Uint32 Q, Q9;
+  Uint16 * coeffs;
+  register Uint8 * s, * d;
+
+  /* retrieve the coeffs from private data */
+  coeffs = (Uint16 *) data;
+
+  /* Y component */
+  s = (Uint8 *) source->pixels;
+  d = (Uint8 *) dest->pixels;
+
+  s += region->y * source->pitch + region->x;
+
+  /* Skip first line */
+  memcpy(d, s, region->w);
+  d += dest->pitch;
+  s += source->pitch;
+
+  for(y = 1; y < region->h - 1; y++)
+  {
+    /* Skip first pixel */
+    *d++ = *s++;
+
+    for(x = 1; x < region->w - 1; x++)
+    {
+      /* get current block quantization error from the info structure provided by the video decoder */
+      Q = info->yuv_mb_square_error[((region->y + y) >> 4) * (source->w >> 4) + ((region->x + x) >> 4)];
+
+      if(!Q)
+	*d++ = *s++; /* block is intra coded, don't filter */
+      else
+      {
+	/* compute differences with up, left, right and down neighbors */
+	dL = *s - *(s - 1) + 256;
+	dR = *s - *(s + 1) + 256;
+	dU = *s - *(s - source->pitch) + 256;
+	dD = *s - *(s + source->pitch) + 256;
+
+	/* get the corresponding filter coefficients from the lookup table */
+	aU = coeffs[(y & 7) + (Q << 12) + (dU << 3)];
+	aD = coeffs[(y & 7) + (Q << 12) + (dD << 3)];
+	aL = coeffs[(x & 7) + (Q << 12) + (dL << 3)];
+	aR = coeffs[(x & 7) + (Q << 12) + (dR << 3)];
+
+	/* apply the filter on current pixel */
+	*d++ = 
+	  ((*s)*(4 * 65536 - aL - aR - aU - aD) + // (4-aL-aR-aU-aD)*(x,y) +
+	   (*(s - source->pitch))*aU +            // aU*(x,y-1) +
+	   (*(s - 1))*aL +                        // aL*(x-1,y) +
+	   (*(s + 1))*aR +                        // aR*(x+1,y) +
+	   (*(s + source->pitch))*aD)             // aU*(x,y+1)
+	     >> 18;                               // remove fixed point and / 4
+	s++;
+      }
+    }
+
+    /* Skip last pixel */
+    *d++ = *s++;
+
+    /* Go to next line */
+    d += dest->pitch - region->w;
+    s += source->pitch - region->w;
+  }
+
+  /* Skip last line */
+  memcpy(d, s, region->w);
+  d += dest->pitch;
+  s += source->pitch;
+
+  /* Go to end of Y plane */
+  s -= region->y * source->pitch + region->x;
+  s += (source->h - region->y - region->h) * source->pitch;
+  d += (dest->h - region->h) * dest->pitch;
+
+  /* U component (unfiltered) */
+  s += (region->y >> 1) * (source->pitch >> 1) + (region->x >> 1);
+  for(y = 0; y < region->h; y+=2)
+  {
+    memcpy(d, s, region->w >> 1);
+    s += source->pitch >> 1;
+    d += dest->pitch >> 1;
+  }
+  s += (((source->h - region->h - region->y) >> 1) * (source->pitch >> 1)) - (region->x >> 1);
+  d += ((dest->h - region->h) >> 1) * (dest->pitch >> 1);
+
+  /* V component (unfiltered) */
+  s += (region->y >> 1) * (source->pitch >> 1) + (region->x >> 1);
+  for(y = 0; y < region->h; y+=2)
+  {
+    memcpy(d, s, region->w >> 1);
+    s += source->pitch >> 1;
+    d += dest->pitch >> 1;
+  }
+}
+
+void MPEG_Filter_deblocking::Destroy(MPEG_Filter * filter)
+{
+  delete (MPEG_Filter_deblocking *) filter;
+}
diff -Naur smpeg/MPEGfilter.h smpeg.patched/MPEGfilter.h
--- smpeg/MPEGfilter.h	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/MPEGfilter.h	Mon Sep  4 18:07:27 2000
@@ -0,0 +1,52 @@
+/*
+    SMPEG - SDL MPEG Player Library
+    Copyright (C) 1999  Loki Entertainment Software
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* MPEG filters */
+
+#ifndef _MPEGFILTER_H_
+#define _MPEGFILTER_H_
+#include "MPEGaction.h"
+
+/* The null filter (default). It simply copies the source rectangle to the video overlay. */ 
+class MPEG_Filter_null : public MPEG_Filter {
+ public:
+  MPEG_Filter_null();
+  static void Callback( SDL_Overlay * dest, SDL_Overlay * source, SDL_Rect * region, MPEG_FilterInfo * filter_info, void * data );
+  static void Destroy(MPEG_Filter * filter);
+};
+
+/* The bilinear filter. A basic low-pass filter that will produce a smoother image. */ 
+class MPEG_Filter_bilinear : public MPEG_Filter {
+ public:
+  MPEG_Filter_bilinear();
+  static void Callback( SDL_Overlay * dest, SDL_Overlay * source, SDL_Rect * region, MPEG_FilterInfo * filter_info, void * data );
+  static void Destroy(MPEG_Filter * filter);
+};
+
+/* The deblocking filter. It filters block borders and non-intra coded blocks to reduce blockiness */ 
+class MPEG_Filter_deblocking : public MPEG_Filter {
+ public:
+  MPEG_Filter_deblocking();
+  ~MPEG_Filter_deblocking();
+  static void Callback( SDL_Overlay * dest, SDL_Overlay * source, SDL_Rect * region, MPEG_FilterInfo * filter_info, void * data );
+  static void Destroy(MPEG_Filter * filter);
+};
+
+#endif
+
diff -Naur smpeg/MPEGring.cpp smpeg.patched/MPEGring.cpp
--- smpeg/MPEGring.cpp	Wed May 31 00:21:04 2000
+++ smpeg.patched/MPEGring.cpp	Mon Sep  4 18:07:27 2000
@@ -155,7 +155,12 @@
 MPEG_ring:: WriteDone( Uint32 len, double timestamp)
 {
     if ( ring->active ) {
+#ifdef NO_GRIFF_MODS
         assert(len <= ring->bufSize);
+#else
+	if ( len > ring->bufSize )
+            len = ring->bufSize;
+#endif
         *((Uint32*) ring->write) = len;
 
         ring->write += ring->bufSize + sizeof(Uint32);
@@ -205,7 +210,9 @@
 double
 MPEG_ring:: ReadTimeStamp(void)
 {
+  if(ring->active)
     return *ring->timestamp_read;
+  return(0);
 }
 
 void
@@ -219,7 +226,7 @@
         data = ring->read + sizeof(Uint32);
         oldlen = *((Uint32*) ring->read);
         newlen = oldlen - used;
-        memcpy(data, data+used, newlen);
+        memmove(data, data+used, newlen);
         *((Uint32*) ring->read) = newlen;
 //printf("Reusing read buffer (%d+1 available)\n", SDL_SemValue(ring->readwait));
         SDL_SemPost(ring->readwait);
diff -Naur smpeg/MPEGring.cpp.orig smpeg.patched/MPEGring.cpp.orig
--- smpeg/MPEGring.cpp.orig	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/MPEGring.cpp.orig	Mon Sep  4 18:07:20 2000
@@ -0,0 +1,257 @@
+/*
+    SMPEG - SDL MPEG Player Library
+    Copyright (C) 1999  Loki Entertainment Software
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include "SDL_timer.h"
+
+#include "MPEGring.h"
+
+
+MPEG_ring:: MPEG_ring( Uint32 size, Uint32 count )
+{
+    Uint32 tSize;
+
+    /* Set up the 'ring' pointer for all the old C code */
+    ring = this;
+
+    tSize = (size + sizeof(Uint32)) * count;
+    if( tSize )
+    {
+        ring->begin = (Uint8 *) malloc( tSize );
+        ring->timestamps = (double *) malloc( sizeof(double)*count );
+    }
+    else
+        ring->begin = 0;
+
+    if( ring->begin && count )
+    {
+        ring->end   = ring->begin + tSize;
+        ring->read  = ring->begin;
+        ring->write = ring->begin;
+        ring->timestamp_read  = timestamps;
+        ring->timestamp_write = timestamps;
+        ring->bufSize  = size;
+        
+        ring->readwait = SDL_CreateSemaphore(0);
+        ring->writewait = SDL_CreateSemaphore(count);
+    }
+    else
+    {
+        ring->end   = 0;
+        ring->read  = 0;
+        ring->write = 0;
+        ring->bufSize  = 0;
+
+        ring->readwait = 0;
+    }
+
+    if ( ring->begin && ring->readwait && ring->writewait ) {
+        ring->active = 1;
+    }
+}
+
+/* Release any waiting threads on the ring so they can be cleaned up.
+   The ring isn't valid after this call, so when threads are done you
+   should call MPRing_sdelete() on the ring.
+ */
+void
+MPEG_ring:: ReleaseThreads( void )
+{
+    /* Let the threads know that the ring is now inactive */
+    ring->active = 0;
+
+    if ( ring->readwait ) {
+        while ( SDL_SemValue(ring->readwait) == 0 ) {
+            SDL_SemPost(ring->readwait);
+        }
+    }
+    if ( ring->writewait ) {
+        while ( SDL_SemValue(ring->writewait) == 0 ) {
+            SDL_SemPost(ring->writewait);
+        }
+    }
+}
+
+
+MPEG_ring:: ~MPEG_ring( void )
+{
+    if( ring )
+    {
+        /* Free up the semaphores */
+        ReleaseThreads();
+
+	/* Destroy the semaphores */
+	if( ring->readwait )
+	{
+	    SDL_DestroySemaphore( ring->readwait );
+	    ring->readwait = 0;
+	}
+	if( ring->writewait )
+	{
+	    SDL_DestroySemaphore( ring->writewait );
+	    ring->writewait = 0;
+	}
+
+        /* Free data buffer */
+        if ( ring->begin ) {
+            free( ring->begin );
+            free( ring->timestamps );
+            ring->begin = 0;
+            ring->timestamps = 0;
+        }
+    }
+}
+
+/*
+  Returns free buffer of ring->bufSize to be filled with data.
+  Zero is returned if there is no free buffer.
+*/
+
+Uint8 *
+MPEG_ring:: NextWriteBuffer( void )
+{
+    Uint8 *buffer;
+
+    buffer = 0;
+    if ( ring->active ) {
+	//printf("Waiting for write buffer (%d available)\n", SDL_SemValue(ring->writewait));
+        SDL_SemWait(ring->writewait);
+	//printf("Finished waiting for write buffer\n");
+	if ( ring->active ) {
+            buffer = ring->write + sizeof(Uint32);
+        }
+    }
+    return buffer;
+}
+
+
+/*
+  Call this when the buffer returned from MPRing_nextWriteBuffer() has
+  been filled.  The passed length must not be larger than ring->bufSize.
+*/
+
+void
+MPEG_ring:: WriteDone( Uint32 len, double timestamp)
+{
+    if ( ring->active ) {
+#ifdef NO_GRIFF_MODS
+        assert(len <= ring->bufSize);
+#else
+	if ( len > ring->bufSize )
+            len = ring->bufSize;
+#endif
+        *((Uint32*) ring->write) = len;
+
+        ring->write += ring->bufSize + sizeof(Uint32);
+        *(ring->timestamp_write++) = timestamp;
+        if( ring->write >= ring->end )
+        {
+            ring->write = ring->begin;
+            ring->timestamp_write = ring->timestamps;
+        }
+//printf("Finished write buffer, making available for reads (%d+1 available for reads)\n", SDL_SemValue(ring->readwait));
+        SDL_SemPost(ring->readwait);
+    }
+}
+
+
+/*
+  Returns the number of bytes in the next ring buffer and sets the buffer
+  pointer to this buffer.  If there is no buffer ready then the buffer
+  pointer is not changed and zero is returned.
+*/
+
+Uint32
+MPEG_ring:: NextReadBuffer( Uint8** buffer )
+{
+    Uint32 size;
+
+    size = 0;
+    if ( ring->active ) {
+        /* Wait for a buffer to become available */
+//printf("Waiting for read buffer (%d available)\n", SDL_SemValue(ring->readwait));
+        SDL_SemWait(ring->readwait);
+//printf("Finished waiting for read buffer\n");
+	if ( ring->active ) {
+            size = *((Uint32*) ring->read);
+            *buffer = ring->read + sizeof(Uint32);
+        }
+    }
+    return size;
+}
+
+/*
+  Call this when you have used some of the buffer previously returned by
+  MPRing_nextReadBuffer(), and want to update it so the rest of the data
+  is returned with the next call to MPRing_nextReadBuffer().
+*/
+
+double
+MPEG_ring:: ReadTimeStamp(void)
+{
+    return *ring->timestamp_read;
+}
+
+void
+MPEG_ring:: ReadSome( Uint32 used )
+{
+    Uint8 *data;
+    Uint32 oldlen;
+    Uint32 newlen;
+
+    if ( ring->active ) {
+        data = ring->read + sizeof(Uint32);
+        oldlen = *((Uint32*) ring->read);
+        newlen = oldlen - used;
+        memcpy(data, data+used, newlen);
+        *((Uint32*) ring->read) = newlen;
+//printf("Reusing read buffer (%d+1 available)\n", SDL_SemValue(ring->readwait));
+        SDL_SemPost(ring->readwait);
+    }
+}
+
+/*
+  Call this when the buffer returned from MPRing_nextReadBuffer() is no
+  longer needed.  This assumes there is only one read thread and one write
+  thread for a particular ring buffer.
+*/
+
+void
+MPEG_ring:: ReadDone( void )
+{
+    if ( ring->active ) {
+        ring->read += ring->bufSize + sizeof(Uint32);
+        ring->timestamp_read++;
+        if( ring->read >= ring->end )
+        {
+            ring->read = ring->begin;
+            ring->timestamp_read = ring->timestamps;
+        }
+//printf("Finished read buffer, making available for writes (%d+1 available for writes)\n", SDL_SemValue(ring->writewait));
+        SDL_SemPost(ring->writewait);
+    }
+}
+
+
+/* EOF */
diff -Naur smpeg/MPEGstream.cpp smpeg.patched/MPEGstream.cpp
--- smpeg/MPEGstream.cpp	Wed Aug  9 22:05:28 2000
+++ smpeg.patched/MPEGstream.cpp	Mon Sep  4 18:07:23 2000
@@ -119,7 +119,7 @@
   preread_size -= br->Size();
 
   /* Check for the end of stream mark */
-  if(eof())
+  while(eof())
   {
     if(looping)
     {
diff -Naur smpeg/MPEGsystem.cpp smpeg.patched/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Wed Aug  9 22:05:29 2000
+++ smpeg.patched/MPEGsystem.cpp	Mon Sep  4 18:07:20 2000
@@ -597,19 +597,49 @@
          read_size = size;
        }
     } else {
-       read_size = read(mpeg_fd,
+#ifdef NO_GRIFF_MODS
+        read_size = read(mpeg_fd,
                         read_buffer + remaining, 
                         READ_ALIGN(MPEG_BUFFER_SIZE - remaining));
-    }
+	if(read_size < 0)
+	{
+	  perror("Read");
+	  errorstream = true;
+	  SDL_mutexV(system_mutex);
+	  return;
+	}
+#else
+	/* Read new data */
+	int bytes_read    = 0;
+	int buffer_offset = remaining;
+	int bytes_to_read = READ_ALIGN(MPEG_BUFFER_SIZE - remaining);
+	int read_at_once = 0;
 
-    if(read_size < 0)
-    {
-      perror("Read");
-      errorstream = true;
-      SDL_mutexV(system_mutex);
-      return;
+	read_size = 0;
+	do
+	{
+	  read_at_once = 
+	    read(mpeg_fd, read_buffer + buffer_offset, bytes_to_read );
+
+	  if(read_at_once < 0)
+	  {
+	    perror("Read");
+	    errorstream = true;
+	    SDL_mutexV(system_mutex);
+	    return;
+	  }
+	  else
+	  {
+	    bytes_read    += read_at_once;
+	    buffer_offset += read_at_once;
+	    read_size     += read_at_once;
+	    bytes_to_read -= read_at_once;
+	  }
+	}
+	while( read_at_once>0 && bytes_to_read>0 );
+#endif
     }
-    
+
     read_total += read_size;
 
     packet_total ++;
@@ -909,7 +939,7 @@
       /* Insert the new data at the end of the stream */
       if(pointer + packet_size <= read_buffer + read_size)
       {
-	stream->insert_packet(pointer, packet_size, stream_timestamp);
+	if(packet_size) stream->insert_packet(pointer, packet_size, stream_timestamp);
 	pointer += packet_size;
       }
       else
diff -Naur smpeg/MPEGvideo.h smpeg.patched/MPEGvideo.h
--- smpeg/MPEGvideo.h	Fri May 26 19:54:37 2000
+++ smpeg.patched/MPEGvideo.h	Mon Sep  4 18:07:20 2000
@@ -44,9 +44,6 @@
 
     /* Various mpeg_play functions that need our data */
     friend VidStream* mpegVidRsrc( TimeStamp time_stamp, VidStream* vid_stream, int first );
-    friend void DoDitherImage( VidStream* vid_stream );
-    friend void DisplayCurrentFrame( VidStream* vid_stream );
-    friend int timeSync( VidStream* vid_stream );
     friend int get_more_data( VidStream* vid_stream );
 
 public:
@@ -67,8 +64,15 @@
                                             MPEG_DisplayCallback callback);
     void MoveDisplay(int x, int y);
     void ScaleDisplayXY(int w, int h);
+    void SetDisplayRegion(int x, int y, int w, int h);
     void RenderFrame(int frame);
     void RenderFinal(SDL_Surface *dst, int x, int y);
+    MPEG_Filter * Filter(MPEG_Filter * filter);
+
+    /* Display and sync functions */
+    void DisplayFrame( VidStream* vid_stream );
+    void ExecuteDisplay( VidStream* vid_stream );
+    int timeSync( VidStream* vid_stream );
 
     /* Yes, it's a hack.. */
     MPEGaudioaction *TimeSource(void ) {
@@ -85,10 +89,16 @@
 
     MPEG_DisplayCallback _callback;
 
-    int _w;             // width of movie
-    int _h;             // height of movie
-    SDL_Rect _rect;	// display area
+    int _ow;            // original width of the movie
+    int _oh;            // original height of the movie
+    int _w;             // mb aligned width of the movie
+    int _h;             // mb aligned height of the movie
+    SDL_Rect _srcrect;	// source area
+    SDL_Rect _dstrect;	// display area
+    SDL_Overlay *_image;// source image
     float _fps;         // frames per second
+    MPEG_Filter * _filter; // pointer to the current filter used
+    SDL_mutex* _filter_mutex; // make sure the filter is not changed while being used
 
     void RewindStream(void);
 };
diff -Naur smpeg/Makefile.am smpeg.patched/Makefile.am
--- smpeg/Makefile.am	Mon Aug  7 21:14:06 2000
+++ smpeg.patched/Makefile.am	Mon Sep  4 18:07:20 2000
@@ -15,6 +15,7 @@
 	MPEGlist.cpp		\
 	MPEGstream.cpp		\
 	MPEGsystem.cpp		\
+	MPEGfilter.cpp		\
 	smpeg.cpp
 
 libsmpegincludedir = $(includedir)/smpeg
diff -Naur smpeg/audio/MPEGaudio.cpp smpeg.patched/audio/MPEGaudio.cpp
--- smpeg/audio/MPEGaudio.cpp	Sun Jun  4 20:06:18 2000
+++ smpeg.patched/audio/MPEGaudio.cpp	Mon Sep  4 18:07:27 2000
@@ -138,6 +138,7 @@
         fprintf(stderr, "Warning: incorrect audio format\n");
     }
     rate_in_s=((double)((actual->format&0xFF)/8)*actual->channels*actual->freq);
+    stereo=(actual->channels-1);
 }
 
 #ifdef THREADED_AUDIO
diff -Naur smpeg/audio/mpegtoraw.cpp smpeg.patched/audio/mpegtoraw.cpp
--- smpeg/audio/mpegtoraw.cpp	Mon Aug  7 21:14:07 2000
+++ smpeg.patched/audio/mpegtoraw.cpp	Mon Sep  4 18:07:27 2000
@@ -184,6 +184,10 @@
     // Making information
 
     inputstereo = (mode == single) ? 0 : 1;
+
+    forcetomonoflag = (!stereo && inputstereo);
+    forcetostereoflag = (stereo && !inputstereo);
+
     if(forcetomonoflag)
         outputstereo=0;
     else
@@ -248,11 +252,7 @@
   }
 
 #ifdef DEBUG_AUDIO
-  static int printed = 0;
-  if ( ! printed ) {
-    printf("MPEG audio stream layer %d (%d kbps), at %d Hz %s\n", layer,  bitrate[version][layer-1][bitrateindex], frequencies[version][frequency], (mode == single) ? "mono" : "stereo");
-    printed = 1;
-  }
+  fprintf(stderr, "MPEG %d audio layer %d (%d kbps), at %d Hz %s [%d]\n", version+1, layer,  bitrate[version][layer-1][bitrateindex], frequencies[version][frequency], (mode == single) ? "mono" : "stereo", framesize);
 #endif
 
   /* Fill the buffer with new data */
@@ -330,7 +330,9 @@
         if ( audio->rawdata ) {
             audio->rawdatawriteoffset = 0;
             audio->run(1, &timestamp);
-            audio->ring->WriteDone(audio->rawdatawriteoffset*2, timestamp);
+
+	    if(audio->rawdatawriteoffset*2 <= audio->ring->BufferSize())
+	      audio->ring->WriteDone(audio->rawdatawriteoffset*2, timestamp);
         }
     }
 
diff -Naur smpeg/configure.in smpeg.patched/configure.in
--- smpeg/configure.in	Fri Aug 11 14:49:44 2000
+++ smpeg.patched/configure.in	Tue Sep  5 20:09:08 2000
@@ -60,6 +60,11 @@
             CFLAGS="$CFLAGS -mcpu=ev4 -Wa,-mall"
         fi
         ;;
+    sparc*-*-solaris*)
+	if test x$ac_cv_prog_gcc = xyes; then
+            LIBS="$LIBS -lsocket -lnsl"	
+        fi
+        ;;
     *-*-cygwin* | *-*-mingw32*)
         if test "$build" != "$target"; then # cross-compiling
             ac_default_prefix=/usr/local/cross-tools/i386-mingw32msvc
diff -Naur smpeg/gtv.c smpeg.patched/gtv.c
--- smpeg/gtv.c	Sun Jun 11 20:51:58 2000
+++ smpeg.patched/gtv.c	Tue Sep  5 20:07:59 2000
@@ -27,6 +27,7 @@
 static void gtv_double( GtkWidget*, gpointer );
 static void gtv_loop( GtkWidget*, gpointer );
 static void gtv_audio( GtkWidget*, gpointer );
+static void gtv_filter( GtkWidget*, gpointer );
 
 static void gtv_open( GtkWidget*, gpointer );
 static void gtv_open_file( gchar*, gpointer );
@@ -64,19 +65,23 @@
 	GtkWidget* twotimes = NULL;
 	GtkWidget* loop = NULL;
 	GtkWidget* audio = NULL;
+	GtkWidget* filter = NULL;
 
 	twotimes = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "twotimes" ) );
 	loop = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "loop" ) );
 	audio = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "audio" ) );
+	filter = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "filter" ) );
 
 #if 1 /* Sam 5/31/2000 - Default to doubled video and audio on */
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( twotimes ), FALSE );
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( loop ), FALSE );
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( audio ), TRUE );
+	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( filter ), FALSE );
 #else
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( twotimes ), FALSE );
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( loop ), FALSE );
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( audio ), FALSE );
+	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( filter ), FALSE );
 #endif
     }
 
@@ -111,6 +116,7 @@
     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
     gtv_set_sensitive( raw, "twotimes", sensitive && info->has_video );
     gtv_set_sensitive( raw, "audio", sensitive && info->has_audio );
+    gtv_set_sensitive( raw, "filter", sensitive && info->has_video );
 
     gtv_fix_toggle_state( raw );
 }
@@ -265,6 +271,7 @@
 
     gtv_loop( NULL, raw );
     gtv_audio( NULL, raw );
+    gtv_filter( NULL, raw );
     gtv_set_buttons_sensitive( raw, TRUE );
 }
 
@@ -600,6 +607,43 @@
 
 }
 
+static void gtv_filter( GtkWidget* item, gpointer raw )
+{
+    SMPEG* mpeg = NULL;
+
+    assert( raw );
+
+    mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
+
+    if( mpeg ) {
+	GtkWidget* filter = NULL;
+	gboolean active = FALSE;
+
+	filter = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "filter" ) );
+	active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( filter ) );
+
+	if(active)
+	{
+	  SMPEG_Filter * filter;
+
+	  /* Activate the deblocking filter */
+       	  filter = SMPEGfilter_deblocking();
+	  filter = SMPEG_filter( mpeg, filter );
+	  filter->destroy(filter);
+	}
+	else
+	{
+	  SMPEG_Filter * filter;
+
+	  /* Reset to default (null) filter */
+	  filter = SMPEGfilter_null();
+	  filter = SMPEG_filter( mpeg, filter );
+	  filter->destroy(filter);
+	}
+    }
+
+}
+
 static void gtv_play( GtkWidget* item, gpointer raw )
 {
     SMPEG* mpeg = NULL;
@@ -935,6 +979,8 @@
     gtv_connect( window, "twotimes", "toggled", GTK_SIGNAL_FUNC( gtv_double ) );
     gtv_connect( window, "loop", "toggled", GTK_SIGNAL_FUNC( gtv_loop ) );
     gtv_connect( window, "audio", "toggled", GTK_SIGNAL_FUNC( gtv_audio ) );
+    gtv_connect( window, "filter", "toggled", GTK_SIGNAL_FUNC( gtv_filter ) );
+
     gtv_connect( window, "seek", "value_changed", GTK_SIGNAL_FUNC( gtv_seek ) );
 
     gtv_connect( window, "scale", "button_press_event", GTK_SIGNAL_FUNC( gtv_trackbar_drag_on ) );
@@ -985,6 +1031,7 @@
   GtkWidget *twotimes;
   GtkWidget *loop;
   GtkWidget *audio;
+  GtkWidget *filter;
   GtkWidget *label3;
   GtkWidget *fps;
   GtkWidget *label2;
@@ -1200,6 +1247,15 @@
                             (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (audio);
   gtk_table_attach (GTK_TABLE (table1), audio, 2, 3, 2, 3,
+                    (GtkAttachOptions) (0),
+                    (GtkAttachOptions) (0), 0, 0);
+
+  filter = gtk_check_button_new_with_label ("Filter");
+  gtk_widget_ref (filter);
+  gtk_object_set_data_full (GTK_OBJECT (gtv_window), "filter", filter,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (filter);
+  gtk_table_attach (GTK_TABLE (table1), filter, 3, 4, 2, 3,
                     (GtkAttachOptions) (0),
                     (GtkAttachOptions) (0), 0, 0);
 
diff -Naur smpeg/plaympeg.c smpeg.patched/plaympeg.c
--- smpeg/plaympeg.c	Wed Aug  9 22:05:34 2000
+++ smpeg.patched/plaympeg.c	Mon Sep  4 18:07:20 2000
@@ -23,6 +23,7 @@
 
 #ifdef unix
 #include <unistd.h>
+
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -33,7 +34,9 @@
 #define RAW_SUPPORT  /* Raw data transport support */
 #define HTTP_SUPPORT /* HTTP support */
 #define FTP_SUPPORT  /* FTP support */
+#ifdef linux
 #define VCD_SUPPORT  /* Video CD support */
+#endif
 #endif
 
 #ifdef NET_SUPPORT
diff -Naur smpeg/smpeg.cpp smpeg.patched/smpeg.cpp
--- smpeg/smpeg.cpp	Wed Aug  9 22:05:34 2000
+++ smpeg.patched/smpeg.cpp	Mon Sep  4 18:07:20 2000
@@ -217,6 +217,12 @@
     mpeg->obj->MoveDisplay(x, y);
 }
 
+/* Set the region of the video to be shown */
+void SMPEG_setdisplayregion(SMPEG* mpeg, int x, int y, int w, int h)
+{
+    mpeg->obj->SetDisplayRegion(x, y, w, h);
+}
+
 /* Play an SMPEG object */
 void SMPEG_play( SMPEG* mpeg )
 {
@@ -265,6 +271,12 @@
     mpeg->obj->RenderFinal(dst, x, y);
 }
 
+/* Set video filter */
+SMPEG_Filter * SMPEG_filter( SMPEG* mpeg, SMPEG_Filter * filter )
+{
+    return((SMPEG_Filter *) mpeg->obj->Filter((MPEG_Filter *) filter));
+}
+
 /* Exported function for SDL audio playback */
 void SMPEG_playAudio(void *udata, Uint8 *stream, int len)
 {
@@ -298,6 +310,25 @@
     return(error);
 }
 
+/* SMPEG built-in filters */
+
+/* The null filter (default). It simply copies the source rectangle to the video overlay. */ 
+extern DECLSPEC SMPEG_Filter * SMPEGfilter_null()
+{
+  return (SMPEG_Filter *) new MPEG_Filter_null;
+}
+
+/* The bilinear filter. A basic low-pass filter that will produce a smoother image. */
+extern DECLSPEC SMPEG_Filter * SMPEGfilter_bilinear()
+{
+  return (SMPEG_Filter *) new MPEG_Filter_bilinear;
+}
+
+/* The deblocking filter. It filters block borders and non-intra coded blocks to reduce blockiness */
+extern DECLSPEC SMPEG_Filter * SMPEGfilter_deblocking()
+{
+  return (SMPEG_Filter *) new MPEG_Filter_deblocking;
+}
 
 /* Extern "C" */
 };
diff -Naur smpeg/smpeg.h smpeg.patched/smpeg.h
--- smpeg/smpeg.h	Wed Aug  9 22:05:34 2000
+++ smpeg.patched/smpeg.h	Mon Sep  4 18:07:27 2000
@@ -76,11 +76,28 @@
     SMPEG_PLAYING
 } SMPEGstatus;
 
+/* SMPEG filter flags */
+#define SMPEG_FILTER_INFO_MB_ERROR    1
+#define SMPEG_FILTER_INFO_PIXEL_ERROR 2
+
+/* Filter info from SMPEG */
+typedef struct __SMPEG_FilterInfo{
+  Uint16* yuv_mb_square_error;
+  Uint16* yuv_pixel_square_error;
+} SMPEG_FilterInfo;
+
+/* Filter declaration */
+typedef struct _SMPEG_Filter {
+  Uint32 flags;
+  void * data;
+  void (* callback)( SDL_Overlay * dest, SDL_Overlay * source, SDL_Rect * region, SMPEG_FilterInfo * filter_info, void * data );
+  void (* destroy)( struct _SMPEG_Filter * data );
+} SMPEG_Filter;
+
 /* Matches the declaration of SDL_UpdateRect() */
 typedef void(*SMPEG_DisplayCallback)(SDL_Surface* dst, int x, int y,
                                      unsigned int w, unsigned int h);
 
-
 /* Create a new SMPEG object from an MPEG file.
    On return, if 'info' is not NULL, it will be filled with information 
    about the MPEG object.
@@ -141,6 +158,9 @@
 /* Move the video display area within the destination surface */
 extern DECLSPEC void SMPEG_move( SMPEG* mpeg, int x, int y );
 
+/* Set the region of the video to be shown */
+extern DECLSPEC void SMPEG_setdisplayregion(SMPEG* mpeg, int x, int y, int w, int h);
+
 /* Play an SMPEG object */
 extern DECLSPEC void SMPEG_play( SMPEG* mpeg );
 
@@ -168,6 +188,9 @@
 /* Render the last frame of an MPEG video */
 extern DECLSPEC void SMPEG_renderFinal( SMPEG* mpeg, SDL_Surface* dst, int x, int y );
 
+/* Set video filter */
+extern DECLSPEC SMPEG_Filter * SMPEG_filter( SMPEG* mpeg, SMPEG_Filter * filter );
+
 /* Return NULL if there is no error in the MPEG stream, or an error message
    if there was a fatal error in the MPEG stream for the SMPEG object.
 */
@@ -183,6 +206,17 @@
 
 /* Inform SMPEG of the actual SDL audio spec used for sound playback */
 extern DECLSPEC void SMPEG_actualSpec( SMPEG *mpeg, SDL_AudioSpec *spec );
+
+/* SMPEG built-in filters. */
+
+/* The null filter (default). It simply copies the source rectangle to the video overlay. */ 
+extern DECLSPEC SMPEG_Filter * SMPEGfilter_null();
+
+/* The bilinear filter. A basic low-pass filter that will produce a smoother image. */ 
+extern DECLSPEC SMPEG_Filter * SMPEGfilter_bilinear();
+
+/* The deblocking filter. It filters block borders and non-intra coded blocks to reduce blockiness */ 
+extern DECLSPEC SMPEG_Filter * SMPEGfilter_deblocking();
 
 #ifdef __cplusplus
 };
diff -Naur smpeg/video/MPEGvideo.cpp smpeg.patched/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Wed Aug  9 22:05:34 2000
+++ smpeg.patched/video/MPEGvideo.cpp	Mon Sep  4 18:07:27 2000
@@ -78,7 +78,6 @@
 */
 
 
-
 #include <limits.h>
 #include <string.h>
 
@@ -88,7 +87,7 @@
 #include "util.h"
 
 #include "MPEGvideo.h"
-
+#include "MPEGfilter.h"
 
 /*--------------------------------------------------------------*/
 
@@ -155,8 +154,8 @@
 
         /* Get the width and height of the video */
         mpeg->copy_data(buf, 4);
-        _w = (((buf[0]<<4)|(buf[1]>>4)) + 15) & ~15;    /* 12 bits of width */
-        _h = ((((buf[1]&0xF)<<8)|buf[2]) + 15) & ~15;   /* 12 bits of height */
+        _w = (buf[0]<<4)|(buf[1]>>4);    /* 12 bits of width */
+        _h = ((buf[1]&0xF)<<8)|buf[2];   /* 12 bits of height */
 	switch(buf[3]&0xF)                /*  4 bits of fps */
 	{
 	  case 1: _fps = 23.97; break;
@@ -180,11 +179,31 @@
     mpeg->seek_marker(marker);
     mpeg->delete_marker(marker);
 
+    /* Keep original width and height in _ow and _oh */
+    _ow = _w;
+    _oh = _h;
+
+    /* Now round up width and height to a multiple   */
+    /* of a macroblock size (16 pixels) to keep the  */
+    /* video decoder happy */
+    _w = (_w + 15) & ~15;
+    _h = (_h + 15) & ~15;
+
     /* Set the default playback area */
-    _rect.x = 0;
-    _rect.y = 0;
-    _rect.w = _w;
-    _rect.h = _h;
+    _dstrect.x = 0;
+    _dstrect.y = 0;
+    _dstrect.w = 0;
+    _dstrect.h = 0;
+
+    /* Set the source area */
+    _srcrect.x = 0;
+    _srcrect.y = 0;
+    _srcrect.w = _ow;
+    _srcrect.h = _oh;
+
+    _image = 0;
+    _filter = new MPEG_Filter_null;
+    _filter_mutex = SDL_CreateMutex();
 }
 
 MPEGvideo:: ~MPEGvideo()
@@ -195,6 +214,13 @@
     /* Free actual video stream */
     if( _stream )
         DestroyVidStream( _stream );
+
+    /* Free overlay */
+    if(_image) SDL_FreeYUVOverlay(_image);
+
+    /* Release filter */
+    SDL_DestroyMutex(_filter_mutex);
+    _filter->destroy(_filter);
 }
 
 /* Simple thread play function */
@@ -300,10 +326,12 @@
 void
 MPEGvideo:: ResetSynchro(double time)
 {
-  _stream->_jumpFrame = -1;
-  _stream->realTimeStart = -time;
-  play_time = time;
-  if (time > 0) {
+  if( _stream )
+  {
+    _stream->_jumpFrame = -1;
+    _stream->realTimeStart = -time;
+    play_time = time;
+    if (time > 0) {
 	double oneframetime;
 	if (_stream->_oneFrameTime == 0)
 		oneframetime = 1.0 / _stream->_smpeg->_fps;	
@@ -316,6 +344,7 @@
 	/* Set Current Frame To 0 & Frame Adjust Frag Set */
 	_stream->current_frame = 0;
 	_stream->need_frameadjust=true;
+    }
   }
 }
 
@@ -359,8 +388,8 @@
 MPEGvideo:: GetVideoInfo(MPEG_VideoInfo *info)
 {
     if ( info ) {
-        info->width = _w;
-        info->height = _h;
+        info->width = _ow;
+        info->height = _oh;
         if ( _stream ) {
             info->current_frame = _stream->current_frame;
 #ifdef CALCULATE_FPS
@@ -410,6 +439,9 @@
     _mutex = lock;
     _dst = dst;
     _callback = callback;
+    _image = SDL_CreateYUVOverlay(_srcrect.w, _srcrect.h, SDL_YV12_OVERLAY, dst);
+    _dstrect.w = dst->w;
+    _dstrect.h = dst->h;
 
     if ( !_stream ) {
         decodeInitTables();
@@ -442,8 +474,8 @@
 MPEGvideo:: MoveDisplay( int x, int y )
 {
     SDL_mutexP( _mutex );
-    _rect.x = x;
-    _rect.y = y;
+    _dstrect.x = x;
+    _dstrect.y = y;
     SDL_mutexV( _mutex );
 }
 
@@ -451,11 +483,44 @@
 MPEGvideo:: ScaleDisplayXY( int w, int h )
 {
     SDL_mutexP( _mutex );
-    _rect.w = w;
-    _rect.h = h;
+    if(_image)
+    {
+      /* Adjust to hide offscreen part */
+      SDL_LockYUVOverlay( _image );
+      _dstrect.w = _image->pitch * w / _ow;
+      _dstrect.h = _image->h * h / _oh;
+      SDL_UnlockYUVOverlay( _image );
+    }
     SDL_mutexV( _mutex );
 }
 
+void
+MPEGvideo:: SetDisplayRegion(int x, int y, int w, int h)
+{
+    SDL_mutexP( _mutex );
+    _srcrect.x = x;
+    _srcrect.y = y;
+    _srcrect.w = w;
+    _srcrect.h = h;
+
+    if(_image)
+    {
+      SDL_LockYUVOverlay( _image );
+      w = _dstrect.w * _ow / _image->pitch;
+      h = _dstrect.h * _oh / _image->h;
+      SDL_UnlockYUVOverlay( _image );
+
+      SDL_FreeYUVOverlay(_image);
+      _image = SDL_CreateYUVOverlay(_srcrect.w, _srcrect.h, SDL_YV12_OVERLAY, _dst);
+
+      SDL_LockYUVOverlay( _image );
+      _dstrect.w = _image->pitch * w / _ow;
+      _dstrect.h = _image->h * h / _oh;
+      SDL_UnlockYUVOverlay( _image );
+    }
+
+    SDL_mutexV( _mutex );
+}
 
 /* API CHANGE: This function no longer takes a destination surface and x/y
    You must use SetDisplay() and MoveDisplay() to set those attributes.
@@ -463,18 +528,7 @@
 void
 MPEGvideo:: RenderFrame( int frame )
 {
-
-   if (_stream->need_frameadjust) {
-      _stream->_jumpFrame=0;
-      while(_stream->need_frameadjust) {
-        mpegVidRsrc(0, _stream, 0);
-#ifdef DEBUG
-        printf("Adjusting Frame %d Timecode %f\n",_stream->totNumFrames,_stream->timestamp);
-#endif
-      }
-      _stream->_jumpFrame=-1;
-      return;
-   }
+    _stream->need_frameadjust = true;
 
     if( _stream->totNumFrames > frame ) {
         mpeg->rewind_stream();
@@ -542,23 +596,8 @@
 	mpeg->garbage_collect();
     }
 
-    /* Create a temporary YUV surface and display the frame */
-    yuv = SDL_CreateYUVOverlay(_w, _h, SDL_YV12_OVERLAY, dst);
-    if ( yuv ) {
-        if ( SDL_LockYUVOverlay(yuv) == 0 ) {
-	  SDL_Rect dstrect;
-
-            memcpy(yuv->pixels, _stream->current->image->pixels, (_w*_h)+2*(_w*_h)/4);
-            SDL_UnlockYUVOverlay(yuv);
-            dstrect.x = _rect.x;
-            dstrect.y = _rect.y;
-            dstrect.w = _rect.w;
-            dstrect.h = _rect.h;
-            SDL_DisplayYUVOverlay(yuv, &dstrect);
-        }
-        SDL_FreeYUVOverlay(yuv);
-    }
+    /* Display the frame */
+    DisplayFrame(_stream);
 }
-
 
 /* EOF */
diff -Naur smpeg/video/decoders.cpp smpeg.patched/video/decoders.cpp
--- smpeg/video/decoders.cpp	Wed May 31 00:21:05 2000
+++ smpeg.patched/video/decoders.cpp	Mon Sep  4 18:07:20 2000
@@ -836,6 +836,12 @@
 	 if (next32bits >> (31-flushed)) *level = -*level;
 	 flushed++;
 	 /* next32bits &= bitMask[flushed];  last op before update */
+#ifdef NO_GRIFF_MODS
+#else
+	 /* CG: moved into if case 12jul2000 */
+         /* Update bitstream... */
+         flush_bits(flushed);
+#endif
        }
        else {    /* *run == ESCAPE */
          /* get_bits14(temp); */
@@ -849,21 +855,53 @@
 	    *level = next32bits >> (24-flushed);
 	    flushed += 8;
 	    /* next32bits &= bitMask[flushed];  last op before update */
+#ifdef NO_GRIFF_MODS
  	    assert(*level >= 128);
+#else
+	    /* CG: Try to overcome the assertion and incorrect decoding in
+	     * case of lost packets. 12jul2000 */
+ 	    if (*level >= 128) {
+              flush_bits(flushed);
+	    }
+	    else {
+              *run = END_OF_BLOCK;
+              *level = END_OF_BLOCK;
+	    }
+#endif
 	 } else if (temp != 128) {
 	    /* Grab sign bit */
 	    *level = ((int) (temp << 24)) >> 24;
+#ifdef NO_GRIFF_MODS
+#else
+	    /* CG: moved into else case 12jul2000 */
+            /* Update bitstream... */
+            flush_bits(flushed);
+#endif
 	 } else {
             /* get_bits8(*level); */
 	    *level = next32bits >> (24-flushed);
 	    flushed += 8;
 	    /* next32bits &= bitMask[flushed];  last op before update */
 	    *level = *level - 256;
+#ifdef NO_GRIFF_MODS
 	    assert(*level <= -128 && *level >= -255);
+#else
+	    /* CG: Try to overcome the assertion and incorrect decoding in
+	     * case of lost packets. 12jul2000 */
+	    if (*level <= -128 && *level >= -255) {
+              flush_bits(flushed);
+	    }
+	    else {
+              *run = END_OF_BLOCK;
+              *level = END_OF_BLOCK;
+	    }
+#endif
 	 }
        }
+#ifdef NO_GRIFF_MODS
        /* Update bitstream... */
        flush_bits(flushed);
+#endif
     }
   }
   else {
diff -Naur smpeg/video/decoders.h smpeg.patched/video/decoders.h
--- smpeg/video/decoders.h	Wed May 31 00:21:05 2000
+++ smpeg.patched/video/decoders.h	Mon Sep  4 18:07:20 2000
@@ -170,6 +170,7 @@
   }	\
 }
 
+#ifdef NO_GRIFF_MODS
 #define DecodeDCTCoeff(dct_coeff_tbl, run, level)			\
 {									\
   unsigned int temp, index;						\
@@ -290,6 +291,148 @@
     assert (flushed <= 32);						\
   }									\
 }
+#else /* NO_GRIFF_MODS */
+#define DecodeDCTCoeff(dct_coeff_tbl, run, level)			\
+{									\
+  unsigned int temp, index;						\
+  unsigned int value, next32bits, flushed;				\
+									\
+  /*									\
+   * Grab the next 32 bits and use it to improve performance of		\
+   * getting the bits to parse. Thus, calls are translated as:		\
+   *									\
+   *	show_bitsX  <-->   next32bits >> (32-X)				\
+   *	get_bitsX   <-->   val = next32bits >> (32-flushed-X);		\
+   *			   flushed += X;				\
+   *			   next32bits &= bitMask[flushed];		\
+   *	flush_bitsX <-->   flushed += X;				\
+   *			   next32bits &= bitMask[flushed];		\
+   *									\
+   * I've streamlined the code a lot, so that we don't have to mask	\
+   * out the low order bits and a few of the extra adds are removed.	\
+   */									\
+  show_bits32(next32bits);						\
+									\
+  /* show_bits8(index); */						\
+  index = next32bits >> 24;						\
+									\
+  if (index > 3) {							\
+    value = dct_coeff_tbl[index];					\
+    run = value >> RUN_SHIFT;						\
+    if (run != END_OF_BLOCK) {						\
+      /* num_bits = (value & NUM_MASK) + 1; */				\
+      /* flush_bits(num_bits); */					\
+      if (run != ESCAPE) {						\
+	 /* get_bits1(value); */					\
+	 /* if (value) level = -level; */				\
+	 flushed = (value & NUM_MASK) + 2;				\
+         level = (value & LEVEL_MASK) >> LEVEL_SHIFT;			\
+	 value = next32bits >> (32-flushed);				\
+	 value &= 0x1;							\
+	 if (value) level = -level;					\
+	 /* next32bits &= ((~0) >> flushed);  last op before update */	\
+									\
+         /* Update bitstream... */					\
+         flush_bits(flushed);						\
+         assert (flushed <= 32);					\
+       }								\
+       else {    /* run == ESCAPE */					\
+	 /* Get the next six into run, and next 8 into temp */		\
+         /* get_bits14(temp); */					\
+	 flushed = (value & NUM_MASK) + 1;				\
+	 temp = next32bits >> (18-flushed);				\
+	 /* Normally, we'd ad 14 to flushed, but I've saved a few	\
+	  * instr by moving the add below */				\
+	 temp &= 0x3fff;						\
+	 run = temp >> 8;						\
+	 temp &= 0xff;							\
+	 if (temp == 0) {						\
+            /* get_bits8(level); */					\
+	    level = next32bits >> (10-flushed);				\
+	    level &= 0xff;						\
+	    flushed += 22;						\
+ 	    /* CG: 12jul2000 - assert(level >= 128); */                 \
+ 	    if (level >= 128) {                                         \
+               /* Update bitstream... */				\
+               flush_bits(flushed);					\
+               assert (flushed <= 32);					\
+	    } else {                                                    \
+	      run = END_OF_BLOCK;                                       \
+	      level = END_OF_BLOCK;                                     \
+	    }                                                           \
+	 } else if (temp != 128) {					\
+	    /* Grab sign bit */						\
+	    flushed += 14;						\
+	    level = ((int) (temp << 24)) >> 24;				\
+            /* Update bitstream... */					\
+            flush_bits(flushed);					\
+            assert (flushed <= 32);					\
+	 } else {							\
+            /* get_bits8(level); */					\
+	    level = next32bits >> (10-flushed);				\
+	    level &= 0xff;						\
+	    flushed += 22;						\
+	    level = level - 256;					\
+	    /* CG: 12jul2000 - assert(level <= -128 && level >= -255); */ \
+	    if ( level <= -128 && level >= -255) {                      \
+              /* Update bitstream... */					\
+              flush_bits(flushed);					\
+              assert (flushed <= 32);					\
+	    } else {                                                    \
+	      run = END_OF_BLOCK;                                       \
+	      level = END_OF_BLOCK;                                     \
+	    }                                                           \
+	 }								\
+       }								\
+    }									\
+  }									\
+  else {								\
+    switch (index) {                                                    \
+    case 2: {   							\
+      /* show_bits10(index); */						\
+      index = next32bits >> 22;						\
+      value = dct_coeff_tbl_2[index & 3];				\
+      break;                                                            \
+    }									\
+    case 3: { 						                \
+      /* show_bits10(index); */						\
+      index = next32bits >> 22;						\
+      value = dct_coeff_tbl_3[index & 3];				\
+      break;                                                            \
+    }									\
+    case 1: {                                             		\
+      /* show_bits12(index); */						\
+      index = next32bits >> 20;						\
+      value = dct_coeff_tbl_1[index & 15];				\
+      break;                                                            \
+    }									\
+    default: { /* index == 0 */						\
+      /* show_bits16(index); */						\
+      index = next32bits >> 16;						\
+      value = dct_coeff_tbl_0[index & 255];				\
+    }}									\
+    run = value >> RUN_SHIFT;						\
+    level = (value & LEVEL_MASK) >> LEVEL_SHIFT;			\
+									\
+    /*									\
+     * Fold these operations together to make it fast...		\
+     */									\
+    /* num_bits = (value & NUM_MASK) + 1; */				\
+    /* flush_bits(num_bits); */						\
+    /* get_bits1(value); */						\
+    /* if (value) level = -level; */					\
+									\
+    flushed = (value & NUM_MASK) + 2;					\
+    value = next32bits >> (32-flushed);					\
+    value &= 0x1;							\
+    if (value) level = -level;						\
+									\
+    /* Update bitstream ... */						\
+    flush_bits(flushed);						\
+    assert (flushed <= 32);						\
+  }									\
+}
+#endif /* NO_GRIFF_MODS */
 
 #define DecodeDCTCoeffFirst(runval, levelval)         \
 {                                                     \
diff -Naur smpeg/video/gdith.cpp smpeg.patched/video/gdith.cpp
--- smpeg/video/gdith.cpp	Thu Jun  8 21:05:08 2000
+++ smpeg.patched/video/gdith.cpp	Mon Sep  4 18:07:27 2000
@@ -140,9 +140,8 @@
     return now;
 }
 
-int timeSync( VidStream* vid_stream )
+int MPEGvideo::timeSync( VidStream* vid_stream )
 {
-    MPEGvideo* mpeg = (MPEGvideo*) vid_stream->_smpeg;
     static double correction = -1;
 
     /* Update the number of frames displayed */
@@ -170,25 +169,25 @@
     }
 
     /* Update the current play time */
-    mpeg->play_time += vid_stream->_oneFrameTime;
+    play_time += vid_stream->_oneFrameTime;
 
     /* Synchronize using system timestamps */
     if(vid_stream->current && vid_stream->current->show_time > 0){
 #ifdef DEBUG_TIMESTAMP_SYNC
       fprintf(stderr, "video: time:%.3f  shift:%.3f\r",
-	      mpeg->play_time,
-	      mpeg->play_time - vid_stream->current->show_time);
+	      play_time,
+	      play_time - vid_stream->current->show_time);
 #endif
       if(correction == -1)
 #ifdef STRANGE_SYNC_TEST
        /* this forces us to maintain the offset we have at the begining
           all the time, and is only usefull for testing */
-        correction = mpeg->play_time - vid_stream->current->show_time;
+        correction = play_time - vid_stream->current->show_time;
 #else
        correction = 0;
 #endif
 #ifdef USE_TIMESTAMP_SYNC
-      mpeg->play_time = vid_stream->current->show_time + correction ;
+      play_time = vid_stream->current->show_time + correction ;
 #endif
       vid_stream->current->show_time = -1;
     }
@@ -216,10 +215,10 @@
         double time_behind;
 
         /* Calculate the frame time relative to real time */
-        time_behind = CurrentTime(vid_stream) - mpeg->Time();
+        time_behind = CurrentTime(vid_stream) - Time();
 
 #ifdef DEBUG_MPEG_SCHEDULING
-printf("Frame %d: frame time: %f, real time: %f, time behind: %f\n", vid_stream->totNumFrames, mpeg->Time(), CurrentTime(vid_stream), time_behind);
+printf("Frame %d: frame time: %f, real time: %f, time behind: %f\n", vid_stream->totNumFrames, Time(), CurrentTime(vid_stream), time_behind);
 #endif
 
         /* Allow up to MAX_FUDGE_TIME of delay in output */
@@ -255,7 +254,7 @@
 printf("Way too far behind, losing time sync...\n");
 #endif
 #if 0 // This results in smoother video, but sync's terribly on slow machines
-                mpeg->play_time = CurrentTime(vid_stream) - (MAX_FUDGE_TIME*2);
+                play_time = CurrentTime(vid_stream) - (MAX_FUDGE_TIME*2);
 #endif
             }
 #ifdef SLOW_START_SCHEDULING
@@ -278,26 +277,75 @@
 /* Do the hard work of copying from the video stream working buffer to the
    screen display and then calling the update callback.
 */
-void DisplayCurrentFrame( VidStream* vid_stream )
+void MPEGvideo::DisplayFrame( VidStream * vid_stream )
 {
-    SDL_Rect dstrect;
-    MPEGvideo* mpeg = (MPEGvideo*) vid_stream->_smpeg;
+  Uint8 * image;
+  MPEG_FilterInfo info;
 
-    SDL_UnlockYUVOverlay(vid_stream->current->image);
+  if ( _filter_mutex )
+    SDL_mutexP( _filter_mutex );
 
-    if ( mpeg->_mutex )
-        SDL_mutexP( mpeg->_mutex );
+  /* Get a pointer to _image pixels */
+  SDL_LockYUVOverlay( _image );
 
-    dstrect = mpeg->_rect;
-    SDL_DisplayYUVOverlay(vid_stream->current->image, &dstrect);
-
-    if ( mpeg->_callback )
-        mpeg->_callback(mpeg->_dst, dstrect.x, dstrect.y, dstrect.w, dstrect.h);
-
-    if ( mpeg->_mutex )
-        SDL_mutexV( mpeg->_mutex );
-
-    SDL_LockYUVOverlay(vid_stream->current->image);
+  /* Compute additionnal info for the filter */
+  if((_filter->flags & SMPEG_FILTER_INFO_PIXEL_ERROR) && vid_stream->current->mb_qscale)
+  {
+    register Uint32 x, y;
+    register Uint32 w, h;
+    register Uint16 * ptr;
+
+    /* Compute quantization error for each pixel */
+    info.yuv_pixel_square_error = (Uint16 *) malloc(_w*_h*12/8*sizeof(Uint16));
+
+    ptr =  info.yuv_pixel_square_error;
+    for(y = 0; y < _h; y++)
+      for(x = 0; x < _w; x++)
+	*ptr++ = (Uint16) (((Uint32) vid_stream->noise_base_matrix[x & 7][y & 7] * 
+			    vid_stream->current->mb_qscale[((y>>4) * (_w>>4)) + (x >> 4)]) >> 8);
+  }
+  
+  if((_filter->flags & SMPEG_FILTER_INFO_MB_ERROR) && vid_stream->current->mb_qscale)
+  {
+    /* Retreive macroblock quantization error info */
+    info.yuv_mb_square_error = vid_stream->current->mb_qscale;
+  }
+    
+  if( _filter )
+  {
+    SDL_Overlay src;
+
+    src.format = SDL_YV12_OVERLAY;
+    src.w = _w;
+    src.h = _h;
+    src.pitch = _w;
+    src.pixels = vid_stream->current->image;
+
+    _filter->callback(_image, &src, &_srcrect, &info, _filter->data );
+  }
+  
+  /* Now display the image */
+  if ( _mutex )
+    SDL_mutexP( _mutex );
+
+  SDL_DisplayYUVOverlay(_image, &_dstrect);
+
+  if ( _callback )
+    _callback(_dst, _dstrect.x, _dstrect.y, _dstrect.w, _dstrect.h);
+
+  SDL_UnlockYUVOverlay( _image );
+
+  if( _filter )
+  {
+    if( _filter->flags & SMPEG_FILTER_INFO_PIXEL_ERROR )
+      free(info.yuv_pixel_square_error);
+  }
+
+  if ( _filter_mutex )
+    SDL_mutexV( _filter_mutex );
+  
+  if ( _mutex )
+    SDL_mutexV( _mutex );
 }
 
 /*
@@ -317,17 +365,33 @@
  */
 
 
-void ExecuteDisplay( VidStream* vid_stream )
+void MPEGvideo::ExecuteDisplay( VidStream* vid_stream )
 {
     if( ! vid_stream->_skipFrame )
     {
-        DisplayCurrentFrame(vid_stream);
+      DisplayFrame(vid_stream);
+
 #ifdef CALCULATE_FPS
-        TimestampFPS(vid_stream);
+      TimestampFPS(vid_stream);
 #endif
     }
     timeSync( vid_stream );
 }
 
+
+MPEG_Filter *
+MPEGvideo:: Filter(MPEG_Filter * filter)
+{
+  MPEG_Filter * old_filter;
+
+  old_filter = _filter;
+  if ( _filter_mutex )
+    SDL_mutexP( _filter_mutex );
+  _filter = filter;
+  if ( _filter_mutex )
+    SDL_mutexV( _filter_mutex );
+
+  return(old_filter);
+}
 
 /* EOF */
diff -Naur smpeg/video/proto.h smpeg.patched/video/proto.h
--- smpeg/video/proto.h	Tue Apr 11 16:22:53 2000
+++ smpeg.patched/video/proto.h	Mon Sep  4 18:07:20 2000
@@ -91,9 +91,6 @@
 
 /* gdith.c */
 void InitColor P((void ));
-int timeSync P((VidStream* vid_stream ));
-void ExecuteDisplay P((VidStream *vid_stream ));
-void DisplayCurrentFrame P((VidStream *vid_stream ));
 
 /* fs2.c */
 void InitFS2Dither P((void ));
diff -Naur smpeg/video/util.cpp smpeg.patched/video/util.cpp
--- smpeg/video/util.cpp	Thu Aug 26 06:37:52 1999
+++ smpeg.patched/video/util.cpp	Mon Sep  4 18:07:20 2000
@@ -392,8 +392,26 @@
 #endif
       }
 
+#ifdef NO_GRIFF_MODS
       /* Return success. */
       return OK;
+#else /* NO_GRIFF_MODS */
+      show_bits32(data);
+      if ( data==SEQ_START_CODE ||
+	   data==GOP_START_CODE ||
+	   data==PICTURE_START_CODE ||
+	   (data>=SLICE_MIN_START_CODE && data<=SLICE_MAX_START_CODE) ||
+	   data==EXT_START_CODE ||
+	   data==USER_START_CODE )
+      {
+        /* Return success. */
+        return OK;
+      }
+      else
+      {
+	flush_bits32;
+      }
+#endif /* NO_GRIFF_MODS */
     }
   }
 
diff -Naur smpeg/video/video.cpp smpeg.patched/video/video.cpp
--- smpeg/video/video.cpp	Wed Aug  9 22:05:34 2000
+++ smpeg.patched/video/video.cpp	Mon Sep  4 18:07:27 2000
@@ -49,6 +49,7 @@
 
 /* We use FULL_COLOR_DITHER code for SMPEG */
 #define DISABLE_DITHER
+#define LOOSE_MPEG
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -711,6 +712,17 @@
             vs->non_intra_quant_matrix[i][j] = 16;
         }
     }
+    
+    /* Initialize noise base matrix */
+    for( i = 0; i < 8; i++ )
+        for( j = 0; j < 8; j++ )
+            vs->noise_base_matrix[i][j] = (short) vs->non_intra_quant_matrix[i][j];
+
+    j_rev_dct((short *) vs->noise_base_matrix);
+
+    for( i = 0; i < 8; i++ )
+        for( j = 0; j < 8; j++ )
+	  vs->noise_base_matrix[i][j] *= vs->noise_base_matrix[i][j];
 
     /* Initialize pointers to image spaces. */
 
@@ -896,18 +908,14 @@
     pi = (PictImage *) malloc(sizeof(PictImage));
 
     /* Create a YV12 image (Y + V + U) */
-    pi->image = SDL_CreateYUVOverlay(w, h, SDL_YV12_OVERLAY, dst);
-    if ( ! pi->image || (SDL_LockYUVOverlay(pi->image) < 0) ) {
-        if ( pi->image ) {
-            SDL_FreeYUVOverlay(pi->image);
-        }
-        free(pi);
-        return(NULL);
-    }
-    pi->luminance = (unsigned char *)pi->image->pixels;
+    pi->image = (unsigned char *) malloc(w*h*12/8);
+    pi->luminance = (unsigned char *)pi->image;
     pi->Cr = pi->luminance + (w*h);
     pi->Cb = pi->luminance + (w*h) + (w*h)/4;
   
+    /* Alloc space for filter info */
+    pi->mb_qscale = (unsigned short int *) malloc(vid_stream->mb_width * vid_stream->mb_height * sizeof(unsigned int));
+
     /* Reset locked flag. */
   
     pi->locked = 0;
@@ -950,10 +958,9 @@
  */
 void DestroyPictImage( PictImage* apictimage )
 {
-  if (apictimage->image != NULL) {
-    SDL_UnlockYUVOverlay(apictimage->image);
-    SDL_FreeYUVOverlay(apictimage->image);
-  }
+  if (apictimage->image != NULL) free(apictimage->image);
+
+  free(apictimage->mb_qscale);
   free(apictimage);
 }
 
@@ -1037,7 +1044,7 @@
 	  if( vid_stream->future != NULL )
 	  {
             vid_stream->current = vid_stream->future;
-            ExecuteDisplay( vid_stream );
+            vid_stream->_smpeg->ExecuteDisplay( vid_stream );
 	  }
 
 #ifdef ANALYSIS
@@ -1157,7 +1164,7 @@
                 next_start_code( vid_stream );
             }
 
-            timeSync( vid_stream );
+            vid_stream->_smpeg->timeSync( vid_stream );
             goto done;
         }
         else if( status != PARSE_OK )
@@ -1305,7 +1312,7 @@
 static int ParseSeqHead( VidStream* vid_stream )
 {
   unsigned int data;
-  int i;
+  int i, j;
 #ifndef DISABLE_DITHER
   int ditherType=vid_stream->ditherType;
 #endif
@@ -1412,6 +1419,18 @@
         (unsigned char) data;
     }
   }
+
+  /* Adjust noise base matrix according to non_intra matrix */
+  for( i = 0; i < 8; i++ )
+    for( j = 0; j < 8; j++ )
+      vid_stream->noise_base_matrix[i][j] = (short) vid_stream->non_intra_quant_matrix[i][j];
+  
+  j_rev_dct((short *) vid_stream->noise_base_matrix);
+  
+  for( i = 0; i < 8; i++ )
+    for( j = 0; j < 8; j++ )
+      vid_stream->noise_base_matrix[i][j] *= vid_stream->noise_base_matrix[i][j];
+
   /* Go to next start code. */
 
   next_start_code(vid_stream);
@@ -2140,6 +2159,12 @@
     vid_stream->mblock.past_intra_addr =
       vid_stream->mblock.mb_address;
 
+  /* Store macroblock error for filter info */
+  if (vid_stream->mblock.mb_intra)
+    vid_stream->current->mb_qscale[vid_stream->mblock.mb_address] = 0;
+  else
+    vid_stream->current->mb_qscale[vid_stream->mblock.mb_address] = vid_stream->slice.quant_scale;
+
 #ifdef ANALYSIS
   *mbSizePtr += bitCountRead() - mbSizeCount;
 #endif
@@ -2371,10 +2396,10 @@
     maxx = vid_stream->mb_width*16-1;
     maxy = vid_stream->mb_height*16-1;
 
-    if (row + vid_stream->down_for + 7 > maxy) illegalBlock |= 0x4;
+    if (row + vid_stream->down_for + vid_stream->down_half_for + 7 > maxy) illegalBlock |= 0x4;
     else if (row + vid_stream->down_for < 0)  illegalBlock |= 0x1;
     
-    if (col + vid_stream->right_for + 7 > maxx) illegalBlock |= 0x2;
+    if (col + vid_stream->right_for + vid_stream->right_half_for + 7 > maxx) illegalBlock |= 0x2;
     else if (col + vid_stream->right_for < 0) illegalBlock |= 0x8;
 
 #endif
@@ -2404,13 +2429,13 @@
 #ifdef LOOSE_MPEG
     /* Check for block illegality. */
 
-    maxx = vid_stream->mb_width*16-1;
-    maxy = vid_stream->mb_height*16-1;
+    maxx = vid_stream->mb_width*8-1;
+    maxy = vid_stream->mb_height*8-1;
 
-    if (row + vid_stream->down_for  + 7 > maxy) illegalBlock |= 0x4;
+    if (row + vid_stream->down_for  + vid_stream->down_half_for  + 7 > maxy) illegalBlock |= 0x4;
     else if (row + vid_stream->down_for < 0) illegalBlock |= 0x1;
 
-    if (col + vid_stream->right_for  + 7 > maxx) illegalBlock  |= 0x2;
+    if (col + vid_stream->right_for + vid_stream->right_half_for + 7 > maxx) illegalBlock  |= 0x2;
     else if (col + vid_stream->right_for < 0) illegalBlock |= 0x8;
 
 #endif
@@ -2855,10 +2880,10 @@
     maxx = vid_stream->mb_width*16-1;
     maxy = vid_stream->mb_height*16-1;
 
-    if (row + down_back + 7 > maxy) illegalBlock |= 0x4;
+    if (row + down_back + down_half_back + 7 > maxy) illegalBlock |= 0x4;
     else if (row + down_back < 0)  illegalBlock |= 0x1;
     
-    if (col + right_back + 7 > maxx) illegalBlock |= 0x2;
+    if (col + right_back + right_half_back + 7 > maxx) illegalBlock |= 0x2;
     else if (col + right_back < 0) illegalBlock |= 0x8;
 
 #endif
@@ -2893,10 +2918,10 @@
     maxx = vid_stream->mb_width*8-1;
     maxy = vid_stream->mb_height*8-1;
 
-    if (row + down_back + 7 > maxy) illegalBlock |= 0x4;
+    if (row + down_back + down_half_back + 7 > maxy) illegalBlock |= 0x4;
     else if (row + down_back < 0) illegalBlock |= 0x1;
 
-    if (col + right_back + 7 > maxx) illegalBlock  |= 0x2;
+    if (col + right_back + right_half_back + 7 > maxx) illegalBlock  |= 0x2;
     else if (col + right_back < 0) illegalBlock |= 0x8;
 
 #endif
@@ -3342,31 +3367,92 @@
     if (bnum & 0x01)
       col += 8;
 
-    forw_col_start = col + right_for;
-    forw_row_start = row + down_for;
-
-    back_col_start = col + right_back;
-    back_row_start = row + down_back;
-
 #ifdef LOOSE_MPEG
 
     /* Check for illegal pred. blocks. */
 
 
-    if (forw_col_start+7 > lmaxx) illegal_forw = 1;
-    else if (forw_col_start < 0) illegal_forw = 1;
+    /* Illegal forward Y block, right component */
+    if (col + right_for + right_half_for + 7 > lmaxx)
+    {
+      if(col > lmaxx)                                  // fix mb column 
+	col = lmaxx & ~15; 
+      if(col + right_for + 7 > lmaxx)                  // fix full component
+	right_for = lmaxx - col - 7;
+      if(col + right_for + right_half_for + 7 > lmaxx) // fix half component
+	right_half_for = 0;
+    }
+    else if (col + right_for < 0)
+    {
+      if(col < 0)                                      // fix mb column
+	col = 0;
+      if(col + right_for < 0)                          // fix full component
+	right_for = 0;
+    }
+
+    /* Illegal forward Y block, down component */
+    if (row + down_for + down_half_for + 7 > lmaxy)
+    {
+      if(row > lmaxy)                                  // fix mb row
+	row = lmaxy & ~15; 
+      if(row + down_for + 7 > lmaxy)                   // fix full component
+	down_for = lmaxy - row - 7;
+      if(row + down_for + down_half_for + 7 > lmaxy)   // fix half component
+	down_half_for = 0;
+    }
+    else if (row + down_for < 0)
+    {
+      if(row < 0)                                      // fix mb row
+	row = 0;
+      if(row + down_for < 0)                           // fix full component
+	down_for = 0;
+    }
 
-    if (forw_row_start+7 > lmaxy) illegal_forw = 1;
-    else if (forw_row_start < 0) illegal_forw = 1;
 
-    if (back_col_start+7 > lmaxx) illegal_back = 1;
-    else if (back_col_start < 0) illegal_back = 1;
+    /* Illegal backward Y block, right component */
+    if (col + right_back + right_half_back + 7 > lmaxx)
+    {
+      if(col > lmaxx)                                    // fix mb column 
+	col = lmaxx & ~15; 
+      if(col + right_back + 7 > lmaxx)                   // fix full component
+	right_back = lmaxx - col - 7;
+      if(col + right_back + right_half_back + 7 > lmaxx) // fix half component
+	right_half_back = 0;
+    }
+    else if (col + right_back < 0)
+    {
+      if(col < 0)                                        // fix mb column
+	col = 0;
+      if(col + right_back < 0)                           // fix full component
+	right_back = 0;
+    }
 
-    if (back_row_start+7 > lmaxy) illegal_back = 1;
-    else if (back_row_start < 0) illegal_back = 1;
+    /* Illegal backward Y block, down component */
+    if (row + down_back + down_half_back + 7 > lmaxy)
+    {
+      if(row > lmaxy)                                    // fix mb row
+	row = lmaxy & ~15; 
+      if(row + down_back + 7 > lmaxy)                    // fix full component
+	down_back = lmaxy - row - 7;
+      if(row + down_back + down_half_back + 7 > lmaxy)   // fix half component
+	down_half_back = 0;
+    }
+    else if (row + down_back < 0)
+    {
+      if(row < 0)                                        // fix mb row
+	row = 0;
+      if(row + down_back < 0)                            // fix full component
+	down_back = 0;
+    }
 
 #endif
 
+    forw_col_start = col + right_for;
+    forw_row_start = row + down_for;
+
+    back_col_start = col + right_back;
+    back_row_start = row + down_back;
+
   }
   /* Otherwise, block is NOT luminance block, ... */
 
@@ -3397,29 +3483,91 @@
     row = (mb_row << 3);
     col = (mb_col << 3);
 
-    forw_col_start = col + right_for;
-    forw_row_start = row + down_for;
-
-    back_col_start = col + right_back;
-    back_row_start = row + down_back;
-
 #ifdef LOOSE_MPEG
 
     /* Check for illegal pred. blocks. */
 
-    if (forw_col_start+7 > cmaxx) illegal_forw = 1;
-    else if (forw_col_start < 0) illegal_forw = 1;
 
-    if (forw_row_start+7 > cmaxy) illegal_forw = 1;
-    else if (forw_row_start < 0) illegal_forw = 1;
+    /* Illegal forward C block, right component */
+    if (col + right_for + right_half_for + 7 > cmaxx)
+    {
+      if(col > cmaxx)                                  // fix mb column 
+	col = cmaxx & ~15; 
+      if(col + right_for + 7 > cmaxx)                  // fix full component
+	right_for = cmaxx - col - 7;
+      if(col + right_for + right_half_for + 7 > cmaxx) // fix half component
+	right_half_for = 0;
+    }
+    else if (col + right_for < 0)
+    {
+      if(col < 0)                                      // fix mb column
+	col = 0;
+      if(col + right_for < 0)                          // fix full component
+	right_for = 0;
+    }
+
+    /* Illegal forward C block, down component */
+    if (row + down_for + down_half_for + 7 > cmaxy)
+    {
+      if(row > cmaxy)                                  // fix mb row
+	row = cmaxy & ~15; 
+      if(row + down_for + 7 > cmaxy)                   // fix full component
+	down_for = cmaxy - row - 7;
+      if(row + down_for + down_half_for + 7 > cmaxy)   // fix half component
+	down_half_for = 0;
+    }
+    else if (row + down_for < 0)
+    {
+      if(row < 0)                                      // fix mb row
+	row = 0;
+      if(row + down_for < 0)                           // fix full component
+	down_for = 0;
+    }
 
-    if (back_col_start+7 > cmaxx) illegal_back = 1;
-    else if (back_col_start < 0) illegal_back = 1;
-    
-    if (back_row_start+7 > cmaxy) illegal_back = 1;
-    else if (back_row_start < 0) illegal_back = 1;
+
+    /* Illegal backward C block, right component */
+    if (col + right_back + right_half_back + 7 > cmaxx)
+    {
+      if(col > cmaxx)                                    // fix mb column 
+	col = cmaxx & ~15; 
+      if(col + right_back + 7 > cmaxx)                   // fix full component
+	right_back = cmaxx - col - 7;
+      if(col + right_back + right_half_back + 7 > cmaxx) // fix half component
+	right_half_back = 0;
+    }
+    else if (col + right_back < 0)
+    {
+      if(col < 0)                                        // fix mb column
+	col = 0;
+      if(col + right_back < 0)                           // fix full component
+	right_back = 0;
+    }
+
+    /* Illegal backward C block, down component */
+    if (row + down_back + down_half_back + 7 > cmaxy)
+    {
+      if(row > cmaxy)                                    // fix mb row
+	row = cmaxy & ~15; 
+      if(row + down_back + 7 > cmaxy)                    // fix full component
+	down_back = cmaxy - row - 7;
+      if(row + down_back + down_half_back + 7 > cmaxy)   // fix half component
+	down_half_back = 0;
+    }
+    else if (row + down_back < 0)
+    {
+      if(row < 0)                                        // fix mb row
+	row = 0;
+      if(row + down_back < 0)                            // fix full component
+	down_back = 0;
+    }
 
 #endif
+
+    forw_col_start = col + right_for;
+    forw_row_start = row + down_for;
+
+    back_col_start = col + right_back;
+    back_row_start = row + down_back;
     
     /* If block is Cr block... */
         /* Switched earlier, so we test Cr first - eyhung */
@@ -3715,6 +3863,18 @@
 #ifndef DISABLE_DITHER
   int ditherType=vid_stream->ditherType;
 #endif
+#ifdef LOOSE_MPEG
+  int lmaxx = vid_stream->mb_width*16-1;
+  int lmaxy = vid_stream->mb_height*16-1;
+  int cmaxx = vid_stream->mb_width*8-1;
+  int cmaxy = vid_stream->mb_height*8-1;
+#endif
+#ifdef LOOSE_MPEG
+  int illegal_forw = 0;
+  int illegal_back = 0;
+  int c_illegal_forw = 0;
+  int c_illegal_back = 0;
+#endif
 
   /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */
 
@@ -3823,6 +3983,158 @@
     col = mb_col << 4;
     crow = row / 2;
     ccol = col / 2;
+
+#ifdef LOOSE_MPEG
+
+    /* Check for illegal blocks. */
+
+    /* Illegal forward Y block, right component */
+    if (col + right_for + right_half_for + 7 > lmaxx)
+    {
+      if(col > lmaxx)                                  // fix mb column 
+	col = lmaxx & ~15; 
+      if(col + right_for + 7 > lmaxx)                  // fix full component
+	right_for = lmaxx - col - 7;
+      if(col + right_for + right_half_for + 7 > lmaxx) // fix half component
+	right_half_for = 0;
+    }
+    else if (col + right_for < 0)
+    {
+      if(col < 0)                                      // fix mb column
+	col = 0;
+      if(col + right_for < 0)                          // fix full component
+	right_for = 0;
+    }
+
+    /* Illegal forward Y block, down component */
+    if (row + down_for + down_half_for + 7 > lmaxy)
+    {
+      if(row > lmaxy)                                  // fix mb row
+	row = lmaxy & ~15; 
+      if(row + down_for + 7 > lmaxy)                   // fix full component
+	down_for = lmaxy - row - 7;
+      if(row + down_for + down_half_for + 7 > lmaxy)   // fix half component
+	down_half_for = 0;
+    }
+    else if (row + down_for < 0)
+    {
+      if(row < 0)                                      // fix mb row
+	row = 0;
+      if(row + down_for < 0)                           // fix full component
+	down_for = 0;
+    }
+
+
+    /* Illegal backward Y block, right component */
+    if (col + right_back + right_half_back + 7 > lmaxx)
+    {
+      if(col > lmaxx)                                    // fix mb column 
+	col = lmaxx & ~15; 
+      if(col + right_back + 7 > lmaxx)                   // fix full component
+	right_back = lmaxx - col - 7;
+      if(col + right_back + right_half_back + 7 > lmaxx) // fix half component
+	right_half_back = 0;
+    }
+    else if (col + right_back < 0)
+    {
+      if(col < 0)                                        // fix mb column
+	col = 0;
+      if(col + right_back < 0)                           // fix full component
+	right_back = 0;
+    }
+
+    /* Illegal backward Y block, down component */
+    if (row + down_back + down_half_back + 7 > lmaxy)
+    {
+      if(row > lmaxy)                                    // fix mb row
+	row = lmaxy & ~15; 
+      if(row + down_back + 7 > lmaxy)                    // fix full component
+	down_back = lmaxy - row - 7;
+      if(row + down_back + down_half_back + 7 > lmaxy)   // fix half component
+	down_half_back = 0;
+    }
+    else if (row + down_back < 0)
+    {
+      if(row < 0)                                        // fix mb row
+	row = 0;
+      if(row + down_back < 0)                            // fix full component
+	down_back = 0;
+    }
+
+
+    /* Illegal forward C block, right component */
+    if (ccol + c_right_for + c_right_half_for + 7 > cmaxx)
+    {
+      if(ccol > cmaxx)                                      // fix mb column 
+	ccol = cmaxx & ~15; 
+      if(ccol + c_right_for + 7 > cmaxx)                    // fix full component
+	c_right_for = cmaxx - ccol - 7;
+      if(ccol + c_right_for + c_right_half_for + 7 > cmaxx) // fix half component
+	c_right_half_for = 0;
+    }
+    else if (ccol + c_right_for < 0)
+    {
+      if(ccol < 0)                                          // fix mb column
+	ccol = 0;
+      if(ccol + c_right_for < 0)                            // fix full component
+	c_right_for = 0;
+    }
+
+    /* Illegal forward C block, down component */
+    if (crow + c_down_for + c_down_half_for + 7 > cmaxy)
+    {
+      if(crow > cmaxy)                                      // fix mb row
+	crow = cmaxy & ~15; 
+      if(crow + c_down_for + 7 > cmaxy)                     // fix full component
+	c_down_for = cmaxy - crow - 7;
+      if(crow + c_down_for + c_down_half_for + 7 > cmaxy)   // fix half component
+	c_down_half_for = 0;
+    }
+    else if (crow + c_down_for < 0)
+    {
+      if(crow < 0)                                           // fix mb row
+	crow = 0;
+      if(crow + c_down_for < 0)                              // fix full component
+	c_down_for = 0;
+    }
+
+    /* Illegal backward C block, right component */
+    if (ccol + c_right_back + c_right_half_back + 7 > cmaxx)
+    {
+      if(ccol > cmaxx)                                        // fix mb column 
+	ccol = cmaxx & ~15; 
+      if(ccol + c_right_back + 7 > cmaxx)                     // fix full component
+	c_right_back = cmaxx - ccol - 7;
+      if(ccol + c_right_back + c_right_half_back + 7 > cmaxx) // fix half component
+	c_right_half_back = 0;
+    }
+    else if (ccol + c_right_back < 0)
+    {
+      if(ccol < 0)                                            // fix mb column
+	ccol = 0;
+      if(ccol + c_right_back < 0)                             // fix full component
+	c_right_back = 0;
+    }
+
+    /* Illegal backward C block, down component */
+    if (crow + c_down_back + c_down_half_back + 7 > cmaxy)
+    {
+      if(crow > cmaxy)                                        // fix mb row
+	crow = cmaxy & ~15; 
+      if(crow + c_down_back + 7 > cmaxy)                      // fix full component
+	c_down_back = cmaxy - crow - 7;
+      if(crow + c_down_back + c_down_half_back + 7 > cmaxy)   // fix half component
+	c_down_half_back = 0;
+    }
+    else if (crow + c_down_back < 0)
+    {
+      if(crow < 0)                                            // fix mb row
+	crow = 0;
+      if(crow + c_down_back < 0)                              // fix full component
+	c_down_back = 0;
+    }
+
+#endif
     
     /* If forward predicted, calculate prediction values. */
     
@@ -4227,12 +4539,12 @@
             vid_stream->future->locked |= FUTURE_LOCK;
             vid_stream->current = vid_stream->past;
 
-            ExecuteDisplay( vid_stream );
+            vid_stream->_smpeg->ExecuteDisplay( vid_stream );
         }
     }
     else
     {
-        ExecuteDisplay( vid_stream );
+        vid_stream->_smpeg->ExecuteDisplay( vid_stream );
     }
 }
 
diff -Naur smpeg/video/video.h smpeg.patched/video/video.h
--- smpeg/video/video.h	Tue Jun 13 23:35:10 2000
+++ smpeg.patched/video/video.h	Mon Sep  4 18:07:20 2000
@@ -152,10 +152,11 @@
 /* Structure with reconstructed pixel values. */
 
 typedef struct pict_image {
-  SDL_Overlay *image;                    /* YV12 format image  */
+  unsigned char *image;                  /* YV12 format image  */
   unsigned char *luminance;              /* Luminance plane.   */
   unsigned char *Cr;                     /* Cr plane.          */
   unsigned char *Cb;                     /* Cb plane.          */
+  unsigned short int *mb_qscale;         /* macroblock info    */
   int locked;                            /* Lock flag.         */
   TimeStamp show_time;                   /* Presentation time. */
 } PictImage;
@@ -264,6 +265,10 @@
 						  buffer.                    */
   int buf_length;                              /* Length of remaining buffer.*/
   unsigned int *buf_start;                     /* Pointer to buffer start.   */
+
+/* VC - beginning of added variables for noise computation */
+  short noise_base_matrix[8][8];               /* Square quantization error  */
+/* VC - end of added variables */
 
 /* Brown - beginning of added variables that used to be static or global */
   int max_buf_length;                          /* Max length of buffer.      */
*************************************************************************
*** Applied ***
From: J. Valenzuela <tsaotsao@lokigames.com>

Added small patch to allow construction of SMPEG objects from raw data.
This additional interface looks like:

	SMPEG_new_data(void *data, int size, SMPEG_Info *info, int sdl_audio);

--------------
diff -Naur smpeg/MPEG.cpp smpeg-new/MPEG.cpp
--- smpeg/MPEG.cpp	Wed Aug  9 09:48:35 2000
+++ smpeg-new/MPEG.cpp	Wed Aug  9 08:17:33 2000
@@ -55,6 +55,13 @@
   Init(Mpeg_FD, Sdlaudio);
 }
 
+MPEG::MPEG(void *data, int size, bool Sdlaudio) :
+  MPEGerror()
+{
+  close_fd = false;
+  Init(data, size, Sdlaudio);
+}
+
 void MPEG::Init(int Mpeg_FD, bool Sdlaudio)
 {
     mpeg_fd = Mpeg_FD;
@@ -63,6 +70,51 @@
 
     /* Create the system that will parse the MPEG stream */
     system = new MPEGsystem(Mpeg_FD);
+
+    /* Initialize everything to invalid values for cleanup */
+    error = NULL;
+
+    audiostream = videostream = NULL;
+    audioaction = NULL;
+    videoaction = NULL;
+    audio = NULL;
+    video = NULL;
+    audioaction_enabled = videoaction_enabled = false;
+    loop = false;
+    pause = false;
+
+    parse_stream_list();
+
+    EnableAudio(audioaction_enabled);
+    EnableVideo(videoaction_enabled);
+
+    if ( ! audiostream && ! videostream ) {
+      SetError("No audio/video stream found in MPEG");
+    }
+
+    if ( system && system->WasError() ) {
+      SetError(system->TheError());
+    }
+
+    if ( audio && audio->WasError() ) {
+      SetError(audio->TheError());
+    }
+
+    if ( video && video->WasError() ) {
+      SetError(video->TheError());
+    }
+
+    if ( WasError() ) {
+      SetError(TheError());
+    }
+}
+
+void MPEG::Init(void *data, int size, bool Sdlaudio)
+{
+    sdlaudio = Sdlaudio;
+
+    /* Create the system that will parse the MPEG stream */
+    system = new MPEGsystem(data, size);
 
     /* Initialize everything to invalid values for cleanup */
     error = NULL;
diff -Naur smpeg/MPEG.h smpeg-new/MPEG.h
--- smpeg/MPEG.h	Wed Aug  9 09:48:35 2000
+++ smpeg-new/MPEG.h	Wed Aug  9 08:17:33 2000
@@ -51,10 +51,12 @@
 public:
     MPEG(const char * name, bool sdlaudio = true);
     MPEG(int Mpeg_FD, bool sdlaudio = true);
+    MPEG(void *data, int size, bool sdlaudio = true);
     virtual ~MPEG();
 
     /* Initialize the MPEG */
     void MPEG::Init(int Mpeg_FD, bool Sdlaudio);
+    void MPEG::Init(void *data, int size, bool Sdlaudio);
 
     /* Enable/Disable audio and video */
     bool AudioEnabled(void);
diff -Naur smpeg/MPEGsystem.cpp smpeg-new/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Wed Aug  9 09:48:35 2000
+++ smpeg-new/MPEGsystem.cpp	Wed Aug  9 09:09:29 2000
@@ -391,6 +391,82 @@
   /* Create a mutex to avoid concurrent access to the stream */
   system_mutex = SDL_CreateMutex();
 
+  /*
+     We are not being passed data, so we don't need to simulate
+     file access.  Might something like MikMod's abstraction of
+     read/seek/tell be appropriate?
+   */
+  data_reader.fromData = false;
+
+  /* Invalidate the read buffer */
+  pointer = read_buffer;
+  read_size = 0;
+  read_total = 0;
+  packet_total = 0;
+  endofstream = errorstream = false;
+  looping = false;
+  frametime = 0.0;
+  stream_timestamp = 0.0;
+
+  /* Create an empty stream list */
+  stream_list = 
+    (MPEGstream **) malloc(sizeof(MPEGstream *));
+  stream_list[0] = 0;
+
+  /* Create the system stream and add it to the list */
+  if(!get_stream(SYSTEM_STREAMID))
+    add_stream(new MPEGstream(this, SYSTEM_STREAMID));
+
+  timestamp = 0.0;
+  timedrift = 0.0;
+  skip_timestamp = -1;
+  system_thread_running = false;
+  system_thread = 0;
+
+  /* Search the MPEG for the first header */
+  if(!seek_first_header())
+  {
+    errorstream = true;
+    SetError("Could not find the beginning of MPEG data\n");
+    return;
+  }
+  
+  request_wait = SDL_CreateSemaphore(0);
+
+  /* Start the system thread */
+  system_thread = SDL_CreateThread(SystemThread, this);
+
+  /* Wait for the thread to start */
+  while(!system_thread_running && !Eof())
+    SDL_Delay(1);
+
+  /* Look for streams */
+  do
+  {
+    RequestBuffer();
+    Wait();
+  }
+  while(!exist_stream(VIDEO_STREAMID, 0xF0) &&
+	!exist_stream(AUDIO_STREAMID, 0xF0) &&
+	!Eof());
+}
+
+MPEGsystem::MPEGsystem(void *data, int size)
+{
+  /* Create a new buffer for reading */
+  read_buffer = new Uint8[MPEG_BUFFER_SIZE];
+
+  /* 
+     Our argument list indicates that we are being passed data, 
+     so we copy it and setup the data_reader data structure.
+    */
+  data_reader.fromData = true;
+  data_reader.data = malloc(size);
+  data_reader.size = size;
+  data_reader.offset = 0;
+
+  memcpy(data_reader.data, data, size);
+
   /* Invalidate the read buffer */
   pointer = read_buffer;
   read_size = 0;
@@ -444,6 +520,7 @@
 	!Eof());
 }
 
+
 MPEGsystem::~MPEGsystem()
 {
   MPEGstream ** list;
@@ -491,19 +568,39 @@
     /* Replace unread data at the beginning of the stream */
     memmove(read_buffer, pointer, remaining);
 
-#ifdef unix
-    /* Wait for new data */
-    fd_set fdset;
-    do {
-       FD_ZERO(&fdset);
-       FD_SET(mpeg_fd, &fdset);
-    } while ( select(mpeg_fd+1, &fdset, NULL, NULL, NULL) < 0 );
-#endif
-
-    /* Read new data */
-    read_size = 
-      read(mpeg_fd, read_buffer + remaining, 
-	   READ_ALIGN(MPEG_BUFFER_SIZE - remaining));
+    if(data_reader.fromData == true)
+    {
+      /*
+         We were initialized from a chunk of data, so we simulate
+	 the read call
+       */
+
+       int size = READ_ALIGN(MPEG_BUFFER_SIZE - remaining);
+       char *frombuf = (char *) data_reader.data;
+
+       if(data_reader.offset > data_reader.size)
+       {
+         read_size = 0;
+       }
+       else 
+       {
+         if(data_reader.offset + size > data_reader.size)
+         {
+           size = data_reader.size - data_reader.offset;
+         }
+
+         frombuf += data_reader.offset;
+
+         memcpy(read_buffer + remaining, frombuf, size);
+
+         data_reader.offset += size;
+         read_size = size;
+       }
+    } else {
+       read_size = read(mpeg_fd,
+                        read_buffer + remaining, 
+                        READ_ALIGN(MPEG_BUFFER_SIZE - remaining));
+    }
 
     if(read_size < 0)
     {
@@ -852,6 +949,15 @@
   Uint32 size;
   Uint32 pos;
 
+  if(data_reader.fromData == true)
+  {
+    /*
+       we are using simulated data access routines, so we know in advance
+       what the size is.
+     */
+    return data_reader.size;
+  }
+
   /* Lock to avoid concurrent access to the stream */
   SDL_mutexP(system_mutex);
 
@@ -906,17 +1012,21 @@
   SDL_mutexP(system_mutex);
 
   /* Save current position */
-  if((pos = lseek(mpeg_fd, 0, SEEK_CUR)) == (off_t) -1)
-  {
-    if(errno != ESPIPE)
-    {
-      errorstream = true;
-      SetError(strerror(errno));
-    }
-    SDL_mutexV(system_mutex);
-    return(false);
+  if(data_reader.fromData == true) {
+	  /* from data, no lseek needed */
+	  pos = data_reader.offset;
+  } else {
+	  if((pos = lseek(mpeg_fd, 0, SEEK_CUR)) == (off_t) -1)
+	  {
+	    if(errno != ESPIPE)
+	    {
+	      errorstream = true;
+	      SetError(strerror(errno));
+	    }
+	    SDL_mutexV(system_mutex);
+	    return(false);
+	  }
   }
-
   file_ptr = 0;
   buffer = new Uint8[MPEG_BUFFER_SIZE];
 
@@ -926,19 +1036,35 @@
   {
     do
     {
-      if((size = lseek(mpeg_fd, file_ptr, SEEK_SET)) == (off_t) -1)
-      {
-	if(errno != ESPIPE)
-	{
-	  errorstream = true;
-	  SetError(strerror(errno));  
-	}
-	SDL_mutexV(system_mutex);
-	return(false);
+      if(data_reader.fromData == true) {
+	      data_reader.offset += file_ptr;
+	      size = data_reader.offset;
+      }
+      else {
+	      if((size = lseek(mpeg_fd, file_ptr, SEEK_SET)) == (off_t) -1)
+	      {
+		if(errno != ESPIPE)
+		{
+		  errorstream = true;
+		  SetError(strerror(errno));  
+		}
+		SDL_mutexV(system_mutex);
+		return(false);
+	      }
       }
-      
-      if(read(mpeg_fd, buffer, MPEG_BUFFER_SIZE) < 0) break;
-      
+    
+      if(data_reader.fromData == true) {
+             char *dataptr = (char *) data_reader.data;
+             int size = MPEG_BUFFER_SIZE;
+
+             if(data_reader.offset + size > data_reader.size) {
+       	      size = data_reader.size - data_reader.offset;
+             }
+
+             dataptr += size;
+
+             memcpy(buffer, dataptr, size);
+
+             data_reader.offset += size;
+      } else {
+        if(read(mpeg_fd, buffer, MPEG_BUFFER_SIZE) < 0) break;
+      }
+
       /* Search for a valid audio header */
       for(p = buffer; p < buffer + MPEG_BUFFER_SIZE; p++)
 	if(audio_aligned(p, buffer + MPEG_BUFFER_SIZE - p)) break;
@@ -965,18 +1091,34 @@
     {
     /* Otherwise search the stream backwards for a valid header */
       file_ptr -= MPEG_BUFFER_SIZE;
-      if((size = lseek(mpeg_fd, file_ptr, SEEK_END)) == (off_t) -1)
-      {
-	if(errno != ESPIPE)
-        {
-	  errorstream = true;
-	  SetError(strerror(errno));  
-	}
-	SDL_mutexV(system_mutex);
-	return(false);
+      
+      if(data_reader.fromData == true) {
+	      data_reader.offset = data_reader.size - file_ptr;
+	      size = data_reader.offset;
+      } else {
+	      if((size = lseek(mpeg_fd, file_ptr, SEEK_END)) == (off_t) -1)
+	      {
+		if(errno != ESPIPE)
+		{
+		  errorstream = true;
+		  SetError(strerror(errno));  
+		}
+		SDL_mutexV(system_mutex);
+		return(false);
+	      }
       }
       
-      if(read(mpeg_fd, buffer, MPEG_BUFFER_SIZE) < 0) break;
+      if(data_reader.fromData == true) {
+        char *dataptr = (char *) data_reader.data;
+
+        dataptr += data_reader.offset;
+
+        memcpy(buffer, dataptr, MPEG_BUFFER_SIZE);
+
+        data_reader.offset += MPEG_BUFFER_SIZE;
+      } else {
+        if(read(mpeg_fd, buffer, MPEG_BUFFER_SIZE) < 0) break;
+      }
       
       if(stream_list[0]->streamid == SYSTEM_STREAMID)
 	for(p = buffer + MPEG_BUFFER_SIZE - 1; p >= buffer;)
@@ -1011,16 +1153,20 @@
 
   delete buffer;
 
-  /* Get back to saved position */
-  if((pos = lseek(mpeg_fd, pos, SEEK_SET)) == (off_t) -1)
-  {
-    if(errno != ESPIPE)
-    {
-      errorstream = true;
-      SetError(strerror(errno));  
-    }
-    SDL_mutexV(system_mutex);
-    return(0);
+  if(data_reader.fromData == true) {
+      data_reader.offset = pos;
+  } else {
+      /* Get back to saved position */
+      if((pos = lseek(mpeg_fd, pos, SEEK_SET)) == (off_t) -1)
+      {
+        if(errno != ESPIPE)
+        {
+          errorstream = true;
+          SetError(strerror(errno));  
+        }
+        SDL_mutexV(system_mutex);
+        return(0);
+      }
   }
 
   SDL_mutexV(system_mutex);
@@ -1041,15 +1187,19 @@
   /* Lock to avoid concurrent access to the stream */
   SDL_mutexP(system_mutex);
   
-  /* Get into the stream */
-  if(lseek(mpeg_fd, length, SEEK_SET) == (off_t) -1)
-  {
-    if(errno != ESPIPE)
+  if(data_reader.fromData == true) {
+    data_reader.offset = length;
+  } else {
+    /* Get into the stream */
+    if(lseek(mpeg_fd, length, SEEK_SET) == (off_t) -1)
     {
-      errorstream = true;
-      SetError(strerror(errno));
+      if(errno != ESPIPE)
+      {
+        errorstream = true;
+        SetError(strerror(errno));
+      }
+      return(false);
     }
-    return(false);
   }
 
   /* Reinitialize the read buffer */
@@ -1144,15 +1294,20 @@
       /* Set the eof mark on all streams */
       system->end_all_streams();
 
-      /* Get back to the beginning of the stream if possible */
-      if(lseek(system->mpeg_fd, 0, SEEK_SET) == (long) -1)
+      if(system->data_reader.fromData == true)
       {
-	if(errno != ESPIPE)
-	{
-	  system->errorstream = true;
-	  system->SetError(strerror(errno));
-	}
-	break;
+        system->data_reader.offset = 0;
+      } else {
+	      /* Get back to the beginning of the stream if possible */
+	      if(lseek(system->mpeg_fd, 0, SEEK_SET) == (long) -1)
+	      {
+		if(errno != ESPIPE)
+		{
+		  system->errorstream = true;
+		  system->SetError(strerror(errno));
+		}
+		break;
+	      }
       }
 
       /* Reinitialize the read buffer */
diff -Naur smpeg/MPEGsystem.h smpeg-new/MPEGsystem.h
--- smpeg/MPEGsystem.h	Wed Aug  9 09:48:35 2000
+++ smpeg-new/MPEGsystem.h	Wed Aug  9 08:17:33 2000
@@ -20,6 +20,7 @@
 {
 public:
     MPEGsystem(int MPEG_Fd);
+    MPEGsystem(void *data, int size);
     virtual ~MPEGsystem();
 
     /* Buffered I/O functions */
@@ -74,6 +75,15 @@
 
     /* The system thread which fills the FIFO */
     static int SystemThread(void * udata);
+
+    struct {
+    	bool fromData;
+
+	int size;
+	int offset;
+
+	void *data;
+    } data_reader;
 
     int mpeg_fd;
 
diff -Naur smpeg/smpeg.cpp smpeg-new/smpeg.cpp
--- smpeg/smpeg.cpp	Wed Aug  9 09:48:35 2000
+++ smpeg-new/smpeg.cpp	Wed Aug  9 08:17:53 2000
@@ -69,6 +69,26 @@
     return(mpeg);
 }
 
+/*
+   The same as above but for a raw chunk of data.  SMPEG makes a copy of the
+   data, so the application is free to delete after a successful call to this
+   function.
+ */
+SMPEG* SMPEG_new_data(void *data, int size, SMPEG_Info* info, int sdl_audio)
+{
+    SMPEG *mpeg;
+
+    /* Create a new SMPEG object! */
+    mpeg = new SMPEG;
+    mpeg->obj = new MPEG(data, size, sdl_audio ? true : false);
+
+    /* Find out the details of the stream, if requested */
+    SMPEG_getinfo(mpeg, info);
+
+    /* We're done! */
+    return(mpeg);
+}
+
 /* Get current information about an SMPEG object */
 void SMPEG_getinfo( SMPEG* mpeg, SMPEG_Info* info )
 {
diff -Naur smpeg/smpeg.h smpeg-new/smpeg.h
--- smpeg/smpeg.h	Wed Aug  9 09:48:35 2000
+++ smpeg-new/smpeg.h	Wed Aug  9 08:17:53 2000
@@ -95,6 +95,13 @@
 /* The same as above for a file descriptor */
 extern DECLSPEC SMPEG* SMPEG_new_descr(int file, SMPEG_Info* info, int sdl_audio);
 
+/*
+   The same as above but for a raw chunk of data.  SMPEG makes a copy of the
+   data, so the application is free to delete after a successful call to this
+   function.
+ */
+extern DECLSPEC SMPEG* SMPEG_new_data(void *data, int size, SMPEG_Info* info, int sdl_audio);
+
 /* Get current information about an SMPEG object */
 extern DECLSPEC void SMPEG_getinfo( SMPEG* mpeg, SMPEG_Info* info );
 

*************************************************************************
*** Applied ***
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>

Hi, 

 I've added current play time reporting in my patched throu and tested
them a lot. I'm waiting for your feedback and if everythings ok, I'll
send them to Sam to integrate in the CVS version.

Olle Hllns wrote:
> but going
> doublesize makes it go baboom Xlib async error.. maybe you know what todo?
> :)

Yes, this is the Xv bug... and that's why it took me so much time to
finish my patches :) I wanted to be sure it doesn't come from SMPEG...
it doesn't... I've just recompiled SDL with the latest Xv (what I've
forgot to do last time with libXv from Sam... forgot that libXv is in
static version) and it runs ok. Do the same and tell me if you see
anything else wrong.
I've tried your MPEG (Nena) and it plays well.

> including the plugin that uses patched smpeg also included linking
> staticly.. best way for us I guess :)

Huh? why do you statically link your module, and include the smpeg
sources to it? Sam will most probably include the patches to smpeg once
we make sure everything's stable, you don't need to keep a separate
branch for your plug-in :)

BTW, for Sam: the filter patch is nearly finished too, but I'm waiting
we finish with this time stuff.

see ya,
Vivien.
--------------
diff -Naur smpeg/MPEG.cpp smpeg.time/MPEG.cpp
--- smpeg/MPEG.cpp	Sun Jun 11 20:51:57 2000
+++ smpeg.time/MPEG.cpp	Sun Jul 23 13:48:33 2000
@@ -322,7 +322,7 @@
   int was_playing = 0;
 
   /* Cannot seek past end of file */
-  if(position > TotalSize()) return;
+  if(position > system->TotalSize()) return;
   
   /* get info whrether we need to restart playing at the end */
   if( Status() == MPEG_PLAYING )
@@ -376,16 +376,6 @@
   return(true);
 }
 
-Uint32 MPEG::Tell()
-{
-  return(system->Tell());
-}
-
-Uint32 MPEG::TotalSize()
-{
-  return(system->TotalSize());
-}
-
 void MPEG::Skip(float seconds)
 {
   if(system->get_stream(SYSTEM_STREAMID))
@@ -398,6 +388,21 @@
     if( VideoEnabled() ) videoaction->Skip(seconds);
     if( AudioEnabled() ) audioaction->Skip(seconds);
   }
+}
+
+void MPEG::GetSystemInfo(MPEG_SystemInfo * sinfo)
+{
+  sinfo->total_size = system->TotalSize();
+  sinfo->current_offset = system->Tell();
+  sinfo->total_time = system->TotalTime();
+
+  /* Get current time from audio or video decoder */
+  /* TODO: move timing reference in MPEGsystem    */
+  sinfo->current_time = 0;
+  if( videoaction ) 
+    sinfo->current_time = videoaction->Time();
+  if( audioaction )
+    sinfo->current_time = audioaction->Time();
 }
 
 void MPEG::parse_stream_list()
diff -Naur smpeg/MPEG.h smpeg.time/MPEG.h
--- smpeg/MPEG.h	Fri May 26 19:54:37 2000
+++ smpeg.time/MPEG.h	Sun Jul 23 12:37:31 2000
@@ -70,9 +70,8 @@
     void Pause(void);
     void Seek(int bytes);
     void Skip(float seconds);
-    Uint32 Tell();
-    Uint32 TotalSize();
     MPEGstatus Status(void);
+    void GetSystemInfo(MPEG_SystemInfo *info);
 
     /* MPEG audio actions */
     bool GetAudioInfo(MPEG_AudioInfo *info);
diff -Naur smpeg/MPEGaction.h smpeg.time/MPEGaction.h
--- smpeg/MPEGaction.h	Thu May 18 02:45:45 2000
+++ smpeg.time/MPEGaction.h	Sun Jul 23 13:47:16 2000
@@ -121,4 +121,13 @@
     MPEGaudioaction *time_source;
 };
 
+
+/* For getting info about the system portion of the stream */
+typedef struct MPEG_SystemInfo {
+    int total_size;
+    int current_offset;
+    double total_time;
+    double current_time;
+} MPEG_SystemInfo;
+
 #endif /* _MPEGACTION_H_ */
diff -Naur smpeg/MPEGsystem.cpp smpeg.time/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Sun Jul 23 14:58:13 2000
+++ smpeg.time/MPEGsystem.cpp	Sun Jul 23 13:25:04 2000
@@ -104,6 +104,23 @@
 	  ((code1[3] & mask[3]) == (code2[3] & mask[3])) );
 }
 
+static inline double read_time_code(Uint8 *pointer)
+{ 
+  double timestamp;
+  Uint8 hibit; Uint32 lowbytes;
+
+  hibit = (pointer[0]>>3)&0x01;
+  lowbytes = (((Uint32)pointer[0] >> 1) & 0x03) << 30;
+  lowbytes |= (Uint32)pointer[1] << 22;
+  lowbytes |= ((Uint32)pointer[2] >> 1) << 15;
+  lowbytes |= (Uint32)pointer[3] << 7;
+  lowbytes |= ((Uint32)pointer[4]) >> 1;
+  timestamp = (double)hibit*FLOAT_0x10000*FLOAT_0x10000+(double)lowbytes;
+  timestamp /= STD_SYSTEM_CLOCK_FREQ;
+
+  return timestamp;
+}
+
 /* Return true if there is a valid audio header at the beginning of pointer */
 static inline Uint32 audio_header(Uint8 * pointer, Uint32 * framesize, double * frametime)
 {
@@ -188,9 +205,10 @@
 }
 
 /* Return true if there is a valid gop header at the beginning of pointer */
-static inline Uint32 gop_header(Uint8 * pointer, Uint32 size)
+static inline Uint32 gop_header(Uint8 * pointer, Uint32 size, double * timestamp)
 {
   Uint32 header_size;
+  Uint32 hour, min, sec, frame;
 
   header_size = 0;
   if((header_size+=4) >= size) return(0);
@@ -198,7 +216,13 @@
     return(0); /* Not a gop start code */
   
   /* Parse the gop header information */
+  hour = (pointer[4] >> 2) & 31;
+  min = ((pointer[4] & 3) << 4) | ((pointer[5] >> 4) & 15);
+  sec = ((pointer[5] & 7) << 3) | ((pointer[6] >> 5) & 7);
+  frame = ((pointer[6] & 31) << 1) | ((pointer[7] >> 7) & 1);
   if((header_size+=4) >= size) return(0);
+
+  if(timestamp) *timestamp = sec + 60.*min + 3600.*hour;
   
   return(header_size); /* gop header size */
 }
@@ -234,23 +258,6 @@
   return(header_size); /* slice header size */
 }
 
-static inline double read_time_code(Uint8 *pointer)
-{ 
-  double timestamp;
-  Uint8 hibit; Uint32 lowbytes;
-
-  hibit = (pointer[0]>>3)&0x01;
-  lowbytes = (((Uint32)pointer[0] >> 1) & 0x03) << 30;
-  lowbytes |= (Uint32)pointer[1] << 22;
-  lowbytes |= ((Uint32)pointer[2] >> 1) << 15;
-  lowbytes |= (Uint32)pointer[3] << 7;
-  lowbytes |= ((Uint32)pointer[4]) >> 1;
-  timestamp = (double)hibit*FLOAT_0x10000*FLOAT_0x10000+(double)lowbytes;
-  timestamp /= STD_SYSTEM_CLOCK_FREQ;
-
-  return timestamp;
-}
-
 /* Return true if there is a valid packet header at the beginning of pointer */
 static inline Uint32 packet_header(Uint8 * pointer, Uint32 size, double * _timestamp)
 {
@@ -608,7 +615,7 @@
       }
 
       /* GOP header */
-      while((header_size = gop_header(pointer+packet_size, read_buffer + read_size - pointer - packet_size)) != 0)
+      while((header_size = gop_header(pointer+packet_size, read_buffer + read_size - pointer - packet_size, 0)) != 0)
       {
 	packet_size += header_size; 
 #ifdef DEBUG_SYSTEM
@@ -884,6 +891,140 @@
 
   SDL_mutexV(system_mutex);
   return(size);
+}
+
+double MPEGsystem::TotalTime()
+{
+  Uint32 size, pos;
+  Uint32 file_ptr;
+  Uint8 * buffer, * p;
+  Uint8 c;
+  double time;
+
+  /* Lock to avoid concurrent access to the stream */
+  SDL_mutexP(system_mutex);
+
+  /* Save current position */
+  if((pos = lseek(mpeg_fd, 0, SEEK_CUR)) == (off_t) -1)
+  {
+    if(errno != ESPIPE)
+    {
+      errorstream = true;
+      SetError(strerror(errno));
+    }
+    SDL_mutexV(system_mutex);
+    return(false);
+  }
+
+  file_ptr = 0;
+  buffer = new Uint8[MPEG_BUFFER_SIZE];
+
+  /* If audio, compute total time according to bitrate of the first header and total size */
+  /* Note: this doesn't work on variable bitrate streams */
+  if(stream_list[0]->streamid == AUDIO_STREAMID)
+  {
+    do
+    {
+      if((size = lseek(mpeg_fd, file_ptr, SEEK_SET)) == (off_t) -1)
+      {
+	if(errno != ESPIPE)
+	{
+	  errorstream = true;
+	  SetError(strerror(errno));  
+	}
+	SDL_mutexV(system_mutex);
+	return(false);
+      }
+      
+      if(read(mpeg_fd, buffer, MPEG_BUFFER_SIZE) < 0) break;
+      
+      /* Search for a valid audio header */
+      for(p = buffer; p < buffer + MPEG_BUFFER_SIZE; p++)
+	if(audio_aligned(p, buffer + MPEG_BUFFER_SIZE - p)) break;
+    
+      file_ptr += MPEG_BUFFER_SIZE;
+    }
+    while(p >= MPEG_BUFFER_SIZE + buffer);
+
+    /* Extract time info from the first header */
+    Uint32 framesize;
+    double frametime;
+    Uint32 totalsize;
+
+    audio_header(p, &framesize, &frametime);
+    totalsize = TotalSize();
+    if(framesize)
+      time = frametime * totalsize / framesize;
+    else
+      time = 0;
+  }
+  else
+  {
+    do
+    {
+    /* Otherwise search the stream backwards for a valid header */
+      file_ptr -= MPEG_BUFFER_SIZE;
+      if((size = lseek(mpeg_fd, file_ptr, SEEK_END)) == (off_t) -1)
+      {
+	if(errno != ESPIPE)
+        {
+	  errorstream = true;
+	  SetError(strerror(errno));  
+	}
+	SDL_mutexV(system_mutex);
+	return(false);
+      }
+      
+      if(read(mpeg_fd, buffer, MPEG_BUFFER_SIZE) < 0) break;
+      
+      if(stream_list[0]->streamid == SYSTEM_STREAMID)
+	for(p = buffer + MPEG_BUFFER_SIZE - 1; p >= buffer;)
+	{
+	  if(*p-- != 0xba) continue; // Packet header
+	  if(*p-- != 1) continue;
+	  if(*p-- != 0) continue;
+	  if(*p-- != 0) continue;
+	  break;
+	}
+      if(stream_list[0]->streamid == VIDEO_STREAMID)
+	for(p = buffer + MPEG_BUFFER_SIZE - 1; p >= buffer;)
+	{
+	  if(*p-- != 0xb8) continue; // GOP header
+	  if(*p-- != 1) continue;
+	  if(*p-- != 0) continue;
+	  if(*p-- != 0) continue;
+	  break;
+	}
+    }
+    while(p < buffer);
+
+    p++;
+
+    /* Extract time info from the last header */
+    if(stream_list[0]->streamid == SYSTEM_STREAMID)
+      packet_header(p, buffer + MPEG_BUFFER_SIZE - p, &time);
+    
+    if(stream_list[0]->streamid == VIDEO_STREAMID)
+      gop_header(p, buffer + MPEG_BUFFER_SIZE - p, &time);
+  }
+
+  delete buffer;
+
+  /* Get back to saved position */
+  if((pos = lseek(mpeg_fd, pos, SEEK_SET)) == (off_t) -1)
+  {
+    if(errno != ESPIPE)
+    {
+      errorstream = true;
+      SetError(strerror(errno));  
+    }
+    SDL_mutexV(system_mutex);
+    return(0);
+  }
+
+  SDL_mutexV(system_mutex);
+
+  return(time);
 }
 
 void MPEGsystem::Rewind()
diff -Naur smpeg/MPEGsystem.h smpeg.time/MPEGsystem.h
--- smpeg/MPEGsystem.h	Sun Jul 23 14:58:13 2000
+++ smpeg.time/MPEGsystem.h	Sun Jul 23 12:37:31 2000
@@ -33,6 +33,7 @@
     bool Eof() const;
     bool Seek(int length);
     Uint32 TotalSize();
+    double TotalTime();
 
     /* Skip "seconds" seconds */
     void Skip(double seconds);
diff -Naur smpeg/plaympeg.c smpeg.time/plaympeg.c
--- smpeg/plaympeg.c	Thu Jun 15 10:41:04 2000
+++ smpeg.time/plaympeg.c	Sun Jul 23 12:37:31 2000
@@ -652,6 +652,9 @@
         if ( info.total_size ) {
 	    printf("\tSize: %d\n", info.total_size);
         }
+        if ( info.total_size ) {
+	    printf("\tTotal time: %f\n", info.total_time);
+        }
 
         /* Set up video display if needed */
         if ( info.has_video && use_video ) {
diff -Naur smpeg/smpeg.cpp smpeg.time/smpeg.cpp
--- smpeg/smpeg.cpp	Wed May 31 00:21:04 2000
+++ smpeg.time/smpeg.cpp	Sun Jul 23 13:46:41 2000
@@ -75,6 +75,7 @@
     if ( info ) {
         MPEG_AudioInfo ainfo;
         MPEG_VideoInfo vinfo;
+        MPEG_SystemInfo sinfo;
 
         memset(info, 0, (sizeof *info));
         if ( mpeg->obj ) {
@@ -100,8 +101,11 @@
             }
 	    if(mpeg->obj->system != NULL)
 	    {
-		info->total_size = mpeg->obj->TotalSize();
-		info->current_offset = mpeg->obj->Tell();
+	        mpeg->obj->GetSystemInfo(&sinfo);
+		info->total_size = sinfo.total_size;
+		info->current_offset = sinfo.current_offset;
+		info->total_time = sinfo.total_time;
+		info->current_time = sinfo.current_time;
 	    }
 	    else
 	    {
diff -Naur smpeg/smpeg.h smpeg.time/smpeg.h
--- smpeg/smpeg.h	Tue Jun 27 06:34:43 2000
+++ smpeg.time/smpeg.h	Sun Jul 23 13:46:14 2000
@@ -65,6 +65,8 @@
     int  audio_current_frame;
     Uint32 current_offset;
     Uint32 total_size;
+    double current_time;
+    double total_time;
 } SMPEG_Info;
 
 /* Possible MPEG status codes */

--------------

diff -Naur smpeg/MPEGstream.cpp smpeg.system-cond/MPEGstream.cpp
--- smpeg/MPEGstream.cpp	Tue Jun  6 03:51:43 2000
+++ smpeg.system-cond/MPEGstream.cpp	Sat Jul 22 14:20:11 2000
@@ -107,16 +107,11 @@
   br->Unlock();
 
   /* No more buffer ? */
-  if(!br->Next())
+  while(!br->Next())
   {
-    int timeout = 3000;
-
-    /* Then ask the system to read a new buffer */
     SDL_mutexV(mutex);
     system->RequestBuffer();
-    while(!br->Next() && timeout--)
-      SDL_Delay(1);
-    if(timeout<=0) return(false);
+    system->Wait();
     SDL_mutexP(mutex);
   }
 
@@ -134,6 +129,7 @@
 	/* Then ask the system to read a new buffer */
 	SDL_mutexV(mutex);
 	system->RequestBuffer();
+	system->Wait();
 	SDL_mutexP(mutex);
       }
 
diff -Naur smpeg/MPEGsystem.cpp smpeg.system-cond/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Tue Jun 13 23:34:56 2000
+++ smpeg.system-cond/MPEGsystem.cpp	Sat Jul 22 14:25:38 2000
@@ -56,10 +56,10 @@
 #define LG2_GRANULARITY 12
 #define READ_ALIGN(x) (((x) >> LG2_GRANULARITY) << LG2_GRANULARITY)
 
-/* This defines the maximum data that can be preread */
+/* This defines the maximum number of buffers that can be preread */
 /* It is to prevent filling the whole memory with buffers on systems */
 /* where read is immediate such as in the case of files */
-#define PRE_BUFFERED_MAX (256 * 1024)
+#define MPEG_BUFFER_MAX 16
 
 /* Timeout before read fails */
 #define READ_TIME_OUT 1000000
@@ -162,12 +162,12 @@
   Uint32 header_size;
 
   header_size = 0;
-  if((header_size+=4) >= size) return(header_size);
+  if((header_size+=4) >= size) return(0);
   if(!Match4(pointer, VIDEO_CODE, VIDEO_MASK)) 
     return(0); /* Not a sequence start code */
   
   /* Parse the sequence header information */
-  if((header_size+=8) >= size) return(header_size);
+  if((header_size+=8) >= size) return(0);
   switch(pointer[7]&0xF)                /*  4 bits of fps */
   {
     case 1: frametime = 1/23.97; break;
@@ -193,12 +193,12 @@
   Uint32 header_size;
 
   header_size = 0;
-  if((header_size+=4) >= size) return(header_size);
+  if((header_size+=4) >= size) return(0);
   if(!Match4(pointer, GOP_CODE, GOP_MASK)) 
     return(0); /* Not a gop start code */
   
   /* Parse the gop header information */
-  if((header_size+=4) >= size) return(header_size);
+  if((header_size+=4) >= size) return(0);
   
   return(header_size); /* gop header size */
 }
@@ -209,13 +209,13 @@
   Uint32 header_size;
 
   header_size = 0;
-  if((header_size+=4) >= size) return(header_size);
+  if((header_size+=4) >= size) return(0);
 
   if(!Match4(pointer, PICTURE_CODE, PICTURE_MASK)) 
     return(0); /* Not a picture start code */
   
   /* Parse the picture header information */
-  if((header_size+=4) >= size) return(header_size);
+  if((header_size+=4) >= size) return(0);
   
   return(header_size); /* picture header size */
 }
@@ -226,7 +226,7 @@
   Uint32 header_size;
 
   header_size = 0;
-  if((header_size+=4) >= size) return(header_size);
+  if((header_size+=4) >= size) return(0);
   if(!(Match4(pointer, SLICE_CODE, SLICE_MASK) && 
        pointer[3] >= 0x01 && pointer[3] <= 0xaf)) 
     return(0); /* Not a slice start code */
@@ -258,12 +258,12 @@
   Uint32 header_size;
 
   header_size = 0;
-  if((header_size+=4) >= size) return(header_size);
+  if((header_size+=4) >= size) return(0);
   if(!Match4(pointer, PACKET_CODE, PACKET_MASK)) 
     return(0); /* Not a packet start code */
 
   /* Parse the packet information */
-  if((header_size+=8) >= size) return(header_size);
+  if((header_size+=8) >= size) return(0);
   timestamp = read_time_code(pointer+4);
 
   if(_timestamp) *_timestamp = timestamp;
@@ -279,7 +279,7 @@
   double stream_timestamp;
 
   header_size = 0;
-  if((header_size += 4) >= size) return(header_size); 
+  if((header_size += 4) >= size) return(0); 
 
   if(!Match4(pointer, SYSTEMSTREAM_CODE, SYSTEMSTREAM_MASK) &&
      !Match4(pointer, AUDIOSTREAM_CODE, AUDIOSTREAM_MASK) &&
@@ -291,19 +291,19 @@
   stream_id = pointer[3];
 
   pointer += 4;
-  if((header_size += 2) >= size) return(header_size); 
+  if((header_size += 2) >= size) return(0); 
   packet_size = (((unsigned short) pointer[0] << 8) | pointer[1]);
   pointer += 2;
 
   /* Skip stuffing bytes */
   while ( pointer[0] == 0xff ) {
       ++pointer;
-      if((++header_size) >= size) return(header_size); 
+      if((++header_size) >= size) return(0); 
       --packet_size;
   }
   if ( (pointer[0] & 0x40) == 0x40 ) {
       pointer += 2;
-      if((header_size += 2) >= size) return(header_size); 
+      if((header_size += 2) >= size) return(0); 
       packet_size -= 2;
   }
   if ( (pointer[0] & 0x20) == 0x20 ) {
@@ -312,11 +312,11 @@
       /* we don't care about DTS */
       if ( (pointer[0] & 0x30) == 0x30 ){
 	pointer += 5;
-	if((header_size += 5) >= size) return(header_size); 
+	if((header_size += 5) >= size) return(0); 
 	packet_size -= 5;
       }
       pointer += 4;
-      if((header_size += 4) >= size) return(header_size); 
+      if((header_size += 4) >= size) return(0); 
       packet_size -= 4;
   }
   else if ( pointer[0] != 0x0f && pointer[0] != 0x80)
@@ -324,7 +324,7 @@
   else
       stream_timestamp = -1;
     
-  if((++header_size) >= size) return(header_size); 
+  if((++header_size) >= size) return(0); 
   --packet_size;
 
   if(_packet_size) *_packet_size = packet_size;
@@ -356,16 +356,18 @@
   Uint32 header_size;
   Uint8 const one[4]  = {0x00,0x00,0x00,0x01};
 
+  if(!size) return(0);
+
   header_size = 0;
   while(Match4(pointer, ZERO_CODE, FULL_MASK))
   {
     pointer++;
-    if((++header_size) >= size - 4) return(header_size); 
+    if((++header_size) >= size - 4) return(0); 
 
     if(Match4(pointer, one, FULL_MASK))
     {
       pointer++;
-      if((++header_size) >= size - 4) return(header_size); 
+      if((++header_size) >= size - 4) return(0); 
     }
   }
   return(header_size);
@@ -378,6 +380,9 @@
   /* Create a new buffer for reading */
   read_buffer = new Uint8[MPEG_BUFFER_SIZE];
 
+  /* Create a mutex to avoid concurrent access to the stream */
+  system_mutex = SDL_CreateMutex();
+
   /* Invalidate the read buffer */
   pointer = read_buffer;
   read_size = 0;
@@ -410,8 +415,8 @@
     SetError("Could not find the beginning of MPEG data\n");
     return;
   }
-
-  request = PRE_BUFFERED_MAX;
+  
+  request_wait = SDL_CreateSemaphore(0);
 
   /* Start the system thread */
   system_thread = SDL_CreateThread(SystemThread, this);
@@ -420,20 +425,15 @@
   while(!system_thread_running && !Eof())
     SDL_Delay(1);
 
-  /* Wait for prebuffering */
-  while(request > 0 && !Eof())
-    SDL_Delay(1);
-
   /* Look for streams */
   do
+  {
     RequestBuffer();
+    Wait();
+  }
   while(!exist_stream(VIDEO_STREAMID, 0xF0) &&
 	!exist_stream(AUDIO_STREAMID, 0xF0) &&
 	!Eof());
-
-  /* Wait for prebuffering */
-  while(request > 0 && !Eof())
-    SDL_Delay(1);
 }
 
 MPEGsystem::~MPEGsystem()
@@ -441,11 +441,10 @@
   MPEGstream ** list;
 
   /* Kill the system thread */
-  if(system_thread)
-  {
-    system_thread_running = false;
-    SDL_WaitThread(system_thread, NULL);
-  }
+  Stop();
+
+  SDL_DestroySemaphore(request_wait);
+  SDL_DestroyMutex(system_mutex);
 
   /* Delete the streams */
   for(list = stream_list; *list; list ++)
@@ -464,6 +463,9 @@
   int remaining;
   int timeout;
 
+  /* Lock to prevent concurrent access to the stream */
+  SDL_mutexP(system_mutex);
+
   timeout = READ_TIME_OUT;
   remaining = read_buffer + read_size - pointer;
 
@@ -474,6 +476,7 @@
     {
       /* Hum.. we'd better stop if we have already read past the buffer size */
       errorstream = true;
+      SDL_mutexV(system_mutex);
       return;
     }
 
@@ -498,11 +501,11 @@
     {
       perror("Read");
       errorstream = true;
+      SDL_mutexV(system_mutex);
       return;
     }
     
     read_total += read_size;
-    request -= read_size;
 
     packet_total ++;
 
@@ -511,23 +514,26 @@
       if(read_size != 0)
       {
 	errorstream = true;
+	SDL_mutexV(system_mutex);
 	return;
       }
     }
 
     read_size += remaining;
 
+    /* Move the pointer */
+    pointer = read_buffer;  
+
     if(read_size == 0)
     {
       /* There is no more data */
       endofstream = true;
+      SDL_mutexV(system_mutex);
       return;
     }
-
-    /* Move the pointer */
-    pointer = read_buffer;  
   }
 
+  SDL_mutexV(system_mutex);
 }
 
 /* ASSUME: stream_list[0] = system stream */
@@ -541,8 +547,11 @@
   /* - Read a new packet - */
   Read();
 
-  if(Eof()) 
+  if(Eof())
+  {
+    RequestBuffer();
     return(0);
+  }
 
   pointer += skip_zeros(pointer, read_buffer + read_size - pointer); 
 
@@ -691,12 +700,16 @@
 	pointer++;
 	stream_list[0]->pos++;
 	seek_next_header();
+	RequestBuffer();
 	return(0);
     }
   }
 
   if(Eof())
+  {
+    RequestBuffer();
     return(0);
+  }
 
   assert(packet_size <= MPEG_BUFFER_SIZE);
 
@@ -712,7 +725,7 @@
     stream_list[0]->pos += packet_size;
     /* since we skip data, request more */
     RequestBuffer();
-    return (1);
+    return (0);
   }
 
   switch(stream_id)
@@ -721,7 +734,8 @@
       /* Unknown stream, just get another packet */
       pointer += packet_size;
       stream_list[0]->pos += packet_size;
-    return(stream_id);
+      RequestBuffer();
+    return(0);
 
     case SYSTEM_STREAMID:
       /* System header */
@@ -750,6 +764,7 @@
 	  add_stream(new MPEGstream(this, VIDEO_STREAMID));
 	}
       }
+      RequestBuffer();
     return(stream_id);
 
     default:
@@ -781,6 +796,7 @@
 	  /* No stream found for packet, skip it */
 	  pointer += packet_size;
 	  stream_list[0]->pos += packet_size;
+	  RequestBuffer();
 	  return(stream_id);
 	}
       }
@@ -828,6 +844,9 @@
   Uint32 size;
   Uint32 pos;
 
+  /* Lock to avoid concurrent access to the stream */
+  SDL_mutexP(system_mutex);
+
   /* I made it this way (instead of fstat) to avoid #ifdef WIN32 everywhere */
   /* in case 'in some weird perversion of nature' someone wants to port this to Win32 :-) */
   if((pos = lseek(mpeg_fd, 0, SEEK_CUR)) == (off_t) -1)
@@ -837,6 +856,7 @@
       errorstream = true;
       SetError(strerror(errno));
     }
+    SDL_mutexV(system_mutex);
     return(0);
   }
 
@@ -847,6 +867,7 @@
       errorstream = true;
       SetError(strerror(errno));  
     }
+    SDL_mutexV(system_mutex);
     return(0);
   }
   
@@ -857,9 +878,11 @@
       errorstream = true;
       SetError(strerror(errno));  
     }
+    SDL_mutexV(system_mutex);
     return(0);
   }
 
+  SDL_mutexV(system_mutex);
   return(size);
 }
 
@@ -870,15 +893,12 @@
 
 bool MPEGsystem::Seek(int length)
 {
-  request = 0;
-
-  /* Force the system thread to die */
-  system_thread_running = false;
-  SDL_WaitThread(system_thread, NULL);
-
-  /* Reset the streams */
-  reset_all_streams();
+  /* Stop the system thread */
+  Stop();
 
+  /* Lock to avoid concurrent access to the stream */
+  SDL_mutexP(system_mutex);
+  
   /* Get into the stream */
   if(lseek(mpeg_fd, length, SEEK_SET) == (off_t) -1)
   {
@@ -901,6 +921,29 @@
   timestamp = 0.0;
   skip_timestamp = -1;
 
+  SDL_mutexV(system_mutex);
+
+  /* Restart the system thread */
+  Start();
+
+  return(true);
+}
+
+void MPEGsystem::Loop(bool toggle)
+{
+    looping = toggle;
+    loop_all_streams(looping);
+}
+
+void MPEGsystem::RequestBuffer()
+{
+  SDL_SemPost(request_wait);
+}
+
+void MPEGsystem::Start()
+{
+  if(system_thread_running) return;
+
   /* Get the next header */
   if(!seek_next_header())
   {
@@ -910,32 +953,32 @@
       SetError("Could not find the beginning of MPEG data\n");
     }
   }
-  request = PRE_BUFFERED_MAX;
-
+  
   /* Start the system thread */
   system_thread = SDL_CreateThread(SystemThread, this);
 
   /* Wait for the thread to start */
   while(!system_thread_running && !Eof())
     SDL_Delay(1);
-
-  /* Wait for prebuffering */
-  while(request > 0 && !Eof())
-    SDL_Delay(1);
-
-  return(true);
 }
 
-void MPEGsystem::Loop(bool toggle)
+void MPEGsystem::Stop()
 {
-    looping = toggle;
-    loop_all_streams(looping);
+  if(!system_thread_running) return;
+
+  /* Force the system thread to die */
+  system_thread_running = false;
+  SDL_SemPost(request_wait);
+  SDL_WaitThread(system_thread, NULL);
+
+  /* Reset the streams */
+  reset_all_streams();
 }
 
-void MPEGsystem::RequestBuffer()
+void MPEGsystem::Wait()
 {
-  if(request < PRE_BUFFERED_MAX)
-    request += MPEG_BUFFER_SIZE;
+  while(SDL_SemValue(request_wait) != 0)
+    SDL_Delay(1);
 }
 
 bool MPEGsystem::Eof() const
@@ -947,11 +990,6 @@
 {
   MPEGsystem * system = (MPEGsystem *) udata;
 
-#ifdef unix
-  /* Set low priority */
-  nice(1);
-#endif
-
   system->system_thread_running = true;
 
   while(system->system_thread_running)
@@ -992,20 +1030,11 @@
       }
     }
 
-    /* Is a buffer needed? */
-    if(system->request > 0)
-    {
-      /* Read the buffer */
-      while (system->FillBuffer()==1);
-      delay >>= 1;
-    }
-    else
-    {
-      /* Wait more and more time to avoid take too much cpu time when */
-      /* there are no packets requested */
-      if(delay >= 100) delay = 100;
-      SDL_Delay(delay++);
-    }
+    /* Wait for a buffer request */
+    SDL_SemWait(system->request_wait);
+
+    /* Read the buffer */
+    system->FillBuffer();
   }
   system->system_thread_running = false;
 
diff -Naur smpeg/MPEGsystem.h smpeg.system-cond/MPEGsystem.h
--- smpeg/MPEGsystem.h	Tue Jun  6 03:51:43 2000
+++ smpeg.system-cond/MPEGsystem.h	Sat Jul 22 14:20:11 2000
@@ -24,9 +24,12 @@
 
     /* Buffered I/O functions */
     void RequestBuffer();
+    void Wait();
     Uint32 Tell();
     void Rewind();
     void Loop(bool toggle);
+    void Start();
+    void Stop();
     bool Eof() const;
     bool Seek(int length);
     Uint32 TotalSize();
@@ -84,6 +87,8 @@
     Uint32 read_total;
     Uint32 packet_total;
     int request;
+    SDL_semaphore * request_wait;
+    SDL_mutex * system_mutex;
 
     bool endofstream;
     bool errorstream;
diff -Naur smpeg/video/MPEGvideo.cpp smpeg.system-cond/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Sun Jun 11 20:51:58 2000
+++ smpeg.system-cond/video/MPEGvideo.cpp	Sat Jul 22 14:20:11 2000
@@ -507,13 +507,12 @@
 	MPEGstream_marker * marker, * oldmarker;
 
 	marker = 0;
-        mpeg->rewind_stream();
-	mpeg->next_packet();
         start_code = mpeg->copy_byte();
         start_code <<= 8;
         start_code |= mpeg->copy_byte();
         start_code <<= 8;
         start_code |= mpeg->copy_byte();
+
         while ( ! mpeg->eof() ) {
             start_code <<= 8;
             start_code |= mpeg->copy_byte();
@@ -524,6 +523,7 @@
        		  mpeg->garbage_collect();
             }
         }
+
         /* Set the stream to the last spot marked */
         if ( ! mpeg->seek_marker( marker ) ) {
             mpeg->rewind_stream();
@@ -536,7 +536,9 @@
 
         /* Process all frames without displaying any */
         _stream->_skipFrame = 1;
+
         RenderFrame( INT_MAX );
+
 	mpeg->garbage_collect();
     }
 
diff -Naur smpeg/video/video.cpp smpeg.system-cond/video/video.cpp
--- smpeg/video/video.cpp	Tue Jun 13 23:35:10 2000
+++ smpeg.system-cond/video/video.cpp	Sat Jul 22 14:24:16 2000
@@ -1022,20 +1022,9 @@
 
     show_bits32(data);
 
-    /*
-    * Process according to start code (or parse macroblock if not a start code
-    * at all).
-    */
-
-    switch( data )
+    /* Check for end of file */
+    if(vid_stream->EOF_flag)
     {
-    case SEQ_END_CODE:
-    case 0x000001b9:   /*  handle ISO_11172_END_CODE too */
-
-#ifdef VERBOSE_DEBUG
-        printf("SEQ_END_CODE\n");
-#endif
-        flush_bits32;
         /* Display last frame if not looping */
 
 	if(!vid_stream->_smpeg->mpeg->is_looping())
@@ -1054,10 +1043,28 @@
 #ifdef ANALYSIS
 	  PrintAllStats(vid_stream);
 #endif
+	  goto done;
 	}
+	else
+	  vid_stream->EOF_flag = 0;
+    }
+
+    /*
+    * Process according to start code (or parse macroblock if not a start code
+    * at all).
+    */
+
+    switch( data )
+    {
+    case SEQ_END_CODE:
+    case 0x000001b9:   /*  handle ISO_11172_END_CODE too */
+
+#ifdef VERBOSE_DEBUG
+        printf("SEQ_END_CODE\n");
+#endif
+        flush_bits32;
         goto done;
         break;
-
 
     case SEQ_START_CODE:
 

*************************************************************************
*** Applied ***
Date: Fri, 28 Jul 2000 16:38:43 +0900
From: "Kevin Squire" <k-squire@uiuc.edu>
Subject: audio bug patch...

Hi there,

   I was playing with the original splay source, trying to compile it
on Windows, and I found a small bug in the audio mpeg layer 2 code which
does not seem to be fixed in smpeg 0.4.0.  In many cases, the decode still
works acceptably, but I found cases under Windows/Visual C++ where it
doesn't.
Anyway, the patch is below.  I've already forwarded it to the orignal
author and the maintainer of splay.sourceforge.net, although I'm not sure if
either one is doing much with splay right now.

Kevin

----
Kevin Squire      k-squire@uiuc.edu
Ph.D. Student
Department of Electrical and Computer Engineering
University of Illinois at Urbana-Champaign

-------------------------
--- audio/mpeglayer2.orig.cpp   Fri Jul 28 16:31:41 2000
+++ audio/mpeglayer2.cpp        Fri Jul 28 16:33:05 2000
@@ -727,9 +727,9 @@
          {
            if(!group[RS][i])
            {
-
fraction[RS][0][i]=(fraction[RS][0][i]+d[RS][i])*c[LS][i];
-
fraction[RS][1][i]=(fraction[RS][1][i]+d[RS][i])*c[LS][i];
-
fraction[RS][2][i]=(fraction[RS][2][i]+d[RS][i])*c[LS][i];
+
fraction[RS][0][i]=(fraction[RS][0][i]+d[RS][i])*c[RS][i];
+
fraction[RS][1][i]=(fraction[RS][1][i]+d[RS][i])*c[RS][i];
+
fraction[RS][2][i]=(fraction[RS][2][i]+d[RS][i])*c[RS][i];
            }

            register REAL t=scalefactor[RS][l>>2][i];


*************************************************************************
*** Applied ***
Date: 30 Jun 2000 15:40:51 -0700
From: David Hedbor <david@hedbor.org>
To: Sam Lantinga <slouken@devolution.com>
Subject: more patches

Firstly, this one adds -Wl,-rpath,... on Linux/fbsd to smpeg-config
--libs. Second patch fixes some typos in plaympeg --help (it had
spaces instead of tab in the help).


Index: smpeg-config.in
===================================================================
RCS file: /cvs/smpeg/smpeg-config.in,v
retrieving revision 1.2
diff -c -r1.2 smpeg-config.in
*** smpeg-config.in	2000/06/28 03:38:38	1.2
--- smpeg-config.in	2000/06/30 22:39:09
***************
*** 48,54 ****
        if [ "`uname`" = "SunOS" ]; then
          libdirs="-L@libdir@ -R@libdir@"
        else
!         libdirs="-L@libdir@"
        fi
        echo $libdirs -lsmpeg
        ;;
--- 48,54 ----
        if [ "`uname`" = "SunOS" ]; then
          libdirs="-L@libdir@ -R@libdir@"
        else
!         libdirs="-L@libdir@ @SMPEG_RLD_FLAGS@"
        fi
        echo $libdirs -lsmpeg
        ;;
Index: configure.in
===================================================================
RCS file: /cvs/smpeg/configure.in,v
retrieving revision 1.35
diff -c -r1.35 configure.in
*** configure.in	2000/06/21 21:59:27	1.35
--- configure.in	2000/06/30 22:39:09
***************
*** 61,66 ****
--- 61,82 ----
          ;;
  esac
  
+ # Set runtime shared library paths as needed 
+ 
+ case "$target" in
+     *-*-linux*)
+ 	SMPEG_RLD_FLAGS="-Wl,-rpath,\${exec_prefix}/lib"
+ 	;;
+     *-*-freebsd*)
+ 	SMPEG_RLD_FLAGS="-Wl,-rpath,\${exec_prefix}/lib"
+ 	;;
+     *-*-solaris*)
+ 	SMPEG_RLD_FLAGS="-R\${exec_prefix}/lib"
+ 	;;
+ esac
+ 
+ AC_SUBST(SMPEG_RLD_FLAGS)
+ 
  dnl Add compiler-specific optimization flags
  
  AC_ARG_ENABLE(debug,
***************
*** 187,192 ****
--- 203,209 ----
      CC="$save_CC"
      CFLAGS="$save_CFLAGS"
  fi
+ 
  
  # Finally create all the generated files
  AC_OUTPUT([
Index: plaympeg.c
===================================================================
RCS file: /cvs/smpeg/plaympeg.c,v
retrieving revision 1.29
diff -c -r1.29 plaympeg.c
*** plaympeg.c	2000/06/15 08:41:04	1.29
--- plaympeg.c	2000/06/30 22:39:09
***************
*** 64,72 ****
  "	--loop or -l	     Play MPEG over and over\n"
  "	--volume N or -v N   Set audio volume to N (0-100)\n"
  "	--scale wxh or -s wxh  Play MPEG at given resolution\n"
! "       --seek N or -S N     Skip N bytes\n"
  #ifdef USE_SYSTEM_TIMESTAMP
! "       --skip N or -k N     Skip N seconds\n"
  #endif
  "	--help or -h\n"
  "	--version or -V\n"
--- 64,72 ----
  "	--loop or -l	     Play MPEG over and over\n"
  "	--volume N or -v N   Set audio volume to N (0-100)\n"
  "	--scale wxh or -s wxh  Play MPEG at given resolution\n"
! "	--seek N or -S N     Skip N bytes\n"
  #ifdef USE_SYSTEM_TIMESTAMP
! "	--skip N or -k N     Skip N seconds\n"
  #endif
  "	--help or -h\n"
  "	--version or -V\n"

*************************************************************************
*** Applied ***
Date: Wed, 14 Jun 2000 21:36:33 +0200
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: Bug in SMPEG CVS audio stop


Sam Lantinga wrote:

> > Sorry, I was watching a movie with friends :)
> 
> No problem. :)

Hehe, it was called "Silicon Valley" and was about Bill Gates and Steve
Jobs :) ...and Bill looks really stupid :)

> Awesome, go ahead and send it, SMPEG 0.4.0 is now out. :)

Yep.
try these ones:
plaympeg /dev/cdrom
plaympeg http://my.favorite.address/my_favorite_mpeg.mpg
plaympeg ftp://my.favorite.address/my_favorite_mpeg.mpg

352x288 MPEGI streams need about 1.5Mbits/sec and you rarely have this
on the Web, so rather test in a LAN.

--- smpeg/plaympeg.c	Fri May 26 20:05:05 2000
+++ smpeg.patched/plaympeg.c	Wed Jun 14 16:46:21 2000
@@ -17,26 +17,38 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#ifdef unix
-#define NET_SUPPORT
-#endif
-
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#ifdef NET_SUPPORT
+
+#ifdef unix
+#include <unistd.h>
+#include <errno.h>
 #include <sys/types.h>
-#include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/ioctl.h>
+#include <sys/time.h>
+
+#define NET_SUPPORT  /* General network support */
+#define RAW_SUPPORT  /* Raw data transport support */
+#define HTTP_SUPPORT /* HTTP support */
+#define FTP_SUPPORT  /* FTP support */
+#define VCD_SUPPORT  /* Video CD support */
+#endif
+
+#ifdef NET_SUPPORT
 #include <netinet/in.h>
-#include <arpa/inet.h>
 #include <netdb.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
 #endif
+
+#ifdef VCD_SUPPORT
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <linux/cdrom.h>
+#endif
+
 #include "smpeg.h"
 
 
@@ -67,6 +79,351 @@
   if((address & 255) >= 224 && (address & 255) <= 239) return(1);
   return(0);
 }
+
+int tcp_open(char * address, int port)
+{
+  struct sockaddr_in stAddr;
+  struct hostent * host;
+  int sock;
+  struct linger l;
+
+  memset(&stAddr,0,sizeof(stAddr));
+  stAddr.sin_family = AF_INET ;
+  stAddr.sin_port = htons(port);
+
+  if((host = gethostbyname(address)) == NULL) return(0);
+
+  stAddr.sin_addr = *((struct in_addr *) host->h_addr_list[0]) ;
+
+  if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) return(0);
+
+  l.l_onoff = 1; l.l_linger = 5;
+  if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (char*) &l, sizeof(l)) < 0) return(0);
+
+  if(connect(sock, (struct sockaddr *) &stAddr, sizeof(stAddr)) < 0) return(0);
+
+  return(sock);
+}
+
+int udp_open(char * address, int port)
+{
+  int enable = 1L;
+  struct sockaddr_in stAddr;
+  struct sockaddr_in stLclAddr;
+  struct ip_mreq stMreq;
+  struct hostent * host;
+  int sock;
+
+  stAddr.sin_family = AF_INET; 
+  stAddr.sin_port = htons(port);
+
+  if((host = gethostbyname(address)) == NULL) return(0);
+
+  stAddr.sin_addr = *((struct in_addr *) host->h_addr_list[0]) ;
+
+  /* Create a UDP socket */
+  if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return(0);
+	    
+  /* Allow multiple instance of the client to share the same address and port */
+  if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(unsigned long int)) < 0) return(0);
+  
+  /* If the address is multicast, register to the multicast group */
+  if(is_address_multicast(stAddr.sin_addr.s_addr))
+  {
+    /* Bind the socket to port */
+    stLclAddr.sin_family      = AF_INET;
+    stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    stLclAddr.sin_port        = stAddr.sin_port;
+    if(bind(sock, (struct sockaddr*) & stLclAddr, sizeof(stLclAddr)) < 0) return(0);
+      
+    /* Register to a multicast address */
+    stMreq.imr_multiaddr.s_addr = stAddr.sin_addr.s_addr;
+    stMreq.imr_interface.s_addr = INADDR_ANY;
+    if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) & stMreq, sizeof(stMreq)) < 0) return(0);
+  }
+  else
+  {
+    /* Bind the socket to port */
+    if(bind(sock, (struct sockaddr *) & stAddr, sizeof(stAddr)) < 0) return(0);
+  }
+  
+  return(sock);
+}
+
+#ifdef RAW_SUPPORT
+int raw_open(char * arg)
+{
+  char * host;
+  int port;
+  int sock;
+
+  /* Check for URL syntax */
+  if(strncmp(arg, "raw://", strlen("raw://"))) return(0);
+
+  /* Parse URL */
+  port = 0;
+  host = arg + strlen("raw://");
+  if(strchr(host, ':') != NULL) /* port is specified */
+  {
+    port = atoi(strchr(host, ':') + 1);
+    *strchr(host, ':') = 0;
+  }
+
+  /* Open a UDP socket */
+  if(!(sock = udp_open(host, port)))
+    perror("raw_open");
+  
+  return(sock);
+}
+#endif
+
+#ifdef HTTP_SUPPORT
+int http_open(char * arg)
+{
+  char * host;
+  int port;
+  char * request;
+  int tcp_sock;
+  char http_request[1024];
+  int i;
+  char c;
+
+  /* Check for URL syntax */
+  if(strncmp(arg, "http://", strlen("http://"))) return(0);
+
+  /* Parse URL */
+  port = 80;
+  host = arg + strlen("http://");
+  if((request = strchr(host, '/')) == NULL) return(0);
+  *request++ = 0;
+  if(strchr(host, ':') != NULL) /* port is specified */
+  {
+    port = atoi(strchr(host, ':') + 1);
+    *strchr(host, ':') = 0;
+  } 
+
+  /* Open a TCP socket */
+  if(!(tcp_sock = tcp_open(host, port)))
+  {
+    perror("http_open");
+    return(0);
+  }
+
+  /* Send HTTP GET request */
+  sprintf(http_request, 
+	  "GET /%s HTTP/1.0\r\n"
+	  "User-Agent: Mozilla/2.0 (Win95; I)\r\n"
+	  "Pragma: no-cache\r\n"
+	  "Host: %s\r\n"
+	  "Accept: */*\r\n"
+	  "\r\n",
+	  request, host);
+  send(tcp_sock, http_request, strlen(http_request), 0);
+  
+  /* Parse server reply */
+  do read(tcp_sock, &c, sizeof(char)); while(c != ' ');
+  read(tcp_sock, http_request, 4*sizeof(char));
+  http_request[4] = 0;
+  if(strcmp(http_request, "200 "))
+  {
+    fprintf(stderr, "http_open: ");
+    do { 
+      read(tcp_sock, &c, sizeof(char));
+      fprintf(stderr, "%c", c); 
+    }
+    while(c != '\r');
+    fprintf(stderr, "\n");
+    return(0);
+  }
+  
+  return(tcp_sock);
+}
+#endif
+#ifdef FTP_SUPPORT
+int ftp_get_reply(int tcp_sock)
+{
+  int i;
+  char c;
+  char answer[1024];
+
+  do {
+    /* Read a line */
+    for(i = 0, c = 0; i < 1024 && c != '\n'; i++)
+    {
+      read(tcp_sock, &c, sizeof(char));
+      answer[i] = c;
+    }
+    answer[i] = 0;
+    fprintf(stderr, answer + 4);
+  }
+  while(answer[3] == '-');
+
+  answer[3] = 0;
+
+  return(atoi(answer));
+}
+
+int ftp_open(char * arg)
+{
+  char * host;
+  int port;
+  char * dir;
+  char * file;
+  int tcp_sock;
+  int data_sock;
+  int read_size;
+  char ftp_request[1024];
+  struct sockaddr_in stLclAddr;
+  int i;
+  char c;
+
+  /* Check for URL syntax */
+  if(strncmp(arg, "ftp://", strlen("ftp://"))) return(0);
+
+  /* Parse URL */
+  port = 21;
+  host = arg + strlen("ftp://");
+  if((dir = strchr(host, '/')) == NULL) return(0);
+  *dir++ = 0;
+  if((file = strrchr(dir, '/')) == NULL) {
+    file = dir;
+    dir = NULL;
+  } else
+    *file++ = 0;
+
+  if(strchr(host, ':') != NULL) /* port is specified */
+  {
+    port = atoi(strchr(host, ':') + 1);
+    *strchr(host, ':') = 0;
+  }
+
+  /* Open a TCP socket */
+  if(!(tcp_sock = tcp_open(host, port)))
+  {
+    perror("ftp_open");
+    return(0);
+  }
+
+  /* Send FTP USER and PASS request */
+  ftp_get_reply(tcp_sock);
+  sprintf(ftp_request, "USER anonymous\r\n");
+  send(tcp_sock, ftp_request, strlen(ftp_request), 0);
+  if(ftp_get_reply(tcp_sock) != 331) return(0);
+  sprintf(ftp_request, "PASS smpeguser@\r\n");
+  send(tcp_sock, ftp_request, strlen(ftp_request), 0);
+  if(ftp_get_reply(tcp_sock) != 230) return(0);
+  sprintf(ftp_request, "TYPE I\r\n");
+  send(tcp_sock, ftp_request, strlen(ftp_request), 0);
+  if(ftp_get_reply(tcp_sock) != 200) return(0);
+  if(dir != NULL)
+  {
+    sprintf(ftp_request, "CWD %s\r\n", dir);
+    send(tcp_sock, ftp_request, strlen(ftp_request), 0);
+    if(ftp_get_reply(tcp_sock) != 250) return(0);
+  }
+    
+  /* Get interface address */
+  i = sizeof(stLclAddr);
+  if(getsockname(tcp_sock, (struct sockaddr *) &stLclAddr, &i) < 0) return(0);
+
+  /* Open data socket */
+  if ((data_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) return(0);
+
+  stLclAddr.sin_family = AF_INET;
+
+  /* Get the first free port */
+  for(i = 0; i < 0xC000; i++) {
+    stLclAddr.sin_port = htons(0x4000 + i);
+    if(bind(data_sock, (struct sockaddr *) &stLclAddr, sizeof(stLclAddr)) >= 0) break;
+  }
+  port = 0x4000 + i;
+
+  if(listen(data_sock, 1) < 0) return(0);
+
+  i = ntohl(stLclAddr.sin_addr.s_addr);
+  sprintf(ftp_request, "PORT %d,%d,%d,%d,%d,%d\r\n",
+	    (i >> 24) & 0xFF, (i >> 16) & 0xFF,
+	    (i >> 8) & 0xFF, i & 0xFF,
+	    (port >> 8) & 0xFF, port & 0xFF);
+  send(tcp_sock, ftp_request, strlen(ftp_request), 0);
+  if(ftp_get_reply(tcp_sock) != 200) return(0);
+
+  sprintf(ftp_request, "RETR %s\r\n", file);
+  send(tcp_sock, ftp_request, strlen(ftp_request), 0);
+  if(ftp_get_reply(tcp_sock) != 150) return(0);
+
+  return(accept(data_sock, NULL, NULL));
+}
+#endif
+#endif
+
+#ifdef VCD_SUPPORT
+int vcd_read(int fd, int lba, unsigned char *buf)
+{
+    struct cdrom_msf *msf;
+    int    rc;
+
+    msf = (struct cdrom_msf*) buf;
+    msf->cdmsf_min0   = (lba + CD_MSF_OFFSET) / CD_FRAMES / CD_SECS; 
+    msf->cdmsf_sec0   = (lba + CD_MSF_OFFSET) / CD_FRAMES % CD_SECS;
+    msf->cdmsf_frame0 = (lba + CD_MSF_OFFSET) % CD_FRAMES;
+    return(ioctl(fd, CDROMREADMODE2, buf));
+}
+
+int vcd_open(char * arg)
+{
+  struct stat buf;
+  struct cdrom_tocentry toc;
+  int pipe_fd[2];
+  int fd;
+  int pid, parent;
+  unsigned char * buffer;
+  
+
+  if(stat(arg, &buf)) return(0);
+  if(!S_ISBLK(buf.st_mode)) return(0);
+
+  if((fd = open(arg,O_RDONLY)) < 0) return(0);
+
+  /* Track 02 contains MPEG data */
+  toc.cdte_track  = 2; 
+  toc.cdte_format = CDROM_LBA;
+  if(ioctl(fd, CDROMREADTOCENTRY, &toc) < 0) return(0);
+
+  if(pipe(pipe_fd) < 0) return(0);
+
+  parent = getpid();
+  pid = fork();
+
+  if(pid < 0) return(0);
+
+  if(!pid)
+  {
+    /* Child process fills the pipe */
+    int pos;
+    struct timeval timeout;
+    fd_set fdset;
+
+    buffer = (unsigned char *) malloc(CD_FRAMESIZE_RAW0);
+
+    for(pos = toc.cdte_addr.lba; vcd_read(fd, pos, buffer) >= 0; pos ++)
+    {
+      if(kill(parent, 0) < 0) break;
+
+      FD_ZERO(&fdset);
+      FD_SET(pipe_fd[1], &fdset);
+      timeout.tv_sec = 10;
+      timeout.tv_usec = 0;
+      if(select(pipe_fd[1]+1, NULL, &fdset, NULL, &timeout) <= 0) break;
+      if(write(pipe_fd[1], buffer, CD_FRAMESIZE_RAW0) < 0) break;
+    }
+
+    free(buffer);
+    exit(0);
+  }
+  
+  return(pipe_fd[0]);
+}
 #endif
 
 void update(SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
@@ -94,6 +451,7 @@
     char *basefile;
     SDL_version sdlver;
     SMPEG_version smpegver;
+    int fd;
 
     /* Get the command line options */
     use_audio = 1;
@@ -106,6 +464,7 @@
     volume = 100;
     seek = 0;
     skip = 0;
+    fd = 0;
     for ( i=1; argv[i] && (argv[i][0] == '-') && (argv[i][1] != 0); ++i ) {
         if ( (strcmp(argv[i], "--noaudio") == 0) ||
              (strcmp(argv[i], "--nosound") == 0) ) {
@@ -206,71 +565,29 @@
 	
         /* Create the MPEG stream */
 #ifdef NET_SUPPORT
-        /* Check if source is a file or an ip address */
-        if((access(argv[i], F_OK) < 0) && (strchr(argv[i], ':') != NULL))
-	{
-	  char * address;
-	  int port;
-	  int enable = 1L;
-	  struct sockaddr_in stAddr;
-	  struct sockaddr_in stLclAddr;
-	  struct ip_mreq stMreq;
-	  int sock;
-
-	  /* Source is an ip adress */
-	  port = atoi(strchr(argv[i], ':') + sizeof(char));
-	  *strchr(argv[i], ':') = '\0';
-	  address = argv[i];
-	  
-	  printf("Connecting to %s port %d...\n", address, port);
-	  
-          stAddr.sin_family = AF_INET; 
-	  stAddr.sin_addr.s_addr = inet_addr(address); 
-	  stAddr.sin_port = htons(port);
-
-	  /* Open socket */
-	  sock = socket(AF_INET, SOCK_DGRAM, 0);
-	  if (sock <= 0)
-	    fprintf(stderr, "socket() failed\n");
-	    
-	  /* Allow multiple instance of the client to share */
-	  /* the same address and port */
- 	  if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-		        (char *) &enable, sizeof(unsigned long int)) < 0)
-	    fprintf(stderr, "setsockopt() SO_REUSEADDR failed, %s\n",
-		    strerror(errno));
-
-	  /* Do protocol specific initialization */
-	  /* If the address is multicast, register to the multicast group */
-	  if(is_address_multicast(stAddr.sin_addr.s_addr))
-	  {
-	    /* Bind the socket to port */
-	    stLclAddr.sin_family      = AF_INET;
-	    stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
-	    stLclAddr.sin_port        = stAddr.sin_port;
-      
-	    if(bind(sock, (struct sockaddr*) & stLclAddr,
-		    sizeof(stLclAddr)) < 0)
-	    fprintf(stderr, "bind() failed, %s\n", strerror(errno));
-      
-	    /* Register to a multicast address */
-	    stMreq.imr_multiaddr.s_addr = stAddr.sin_addr.s_addr;
-	    stMreq.imr_interface.s_addr = INADDR_ANY;
-      
-	    if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
-		 	  (char *) & stMreq, sizeof(stMreq)) < 0)
-	      fprintf(stderr, "setsockopt() IP_ADD_MEMBERSHIP failed\n");
-	  }
-	  else
-	  {
-	    /* Bind the socket to port */
-	    if(bind(sock, (struct sockaddr *) & stAddr, sizeof(stAddr)) < 0)
-	      fprintf(stderr, "bind() failed, %s\n", strerror(errno));
-	  }
-
-	  /* Connected, now the socket is just like a regular file */
-	  mpeg = SMPEG_new_descr(sock, &info, use_audio);
-	}
+#ifdef RAW_SUPPORT
+        /* Check if source is an IP address and port*/
+        if((fd = raw_open(argv[i])) != 0)
+	  mpeg = SMPEG_new_descr(fd, &info, use_audio);
+	else
+#endif
+#ifdef HTTP_SUPPORT
+        /* Check if source is an http URL */
+        if((fd = http_open(argv[i])) != 0)
+	  mpeg = SMPEG_new_descr(fd, &info, use_audio);
+	else
+#endif
+#ifdef FTP_SUPPORT
+        /* Check if source is an http URL */
+        if((fd = ftp_open(argv[i])) != 0)
+	  mpeg = SMPEG_new_descr(fd, &info, use_audio);
+	else
+#endif
+#endif
+#ifdef VCD_SUPPORT
+	/* Check if source is a CDROM device */
+	if((fd = vcd_open(argv[i])) != 0)
+	  mpeg = SMPEG_new_descr(fd, &info, use_audio);
 	else
 #endif
 	{
@@ -486,6 +803,8 @@
         SMPEG_delete(mpeg);
     }
     SDL_Quit();
+
+    if(fd) close(fd);
 
     exit(0);
 }

*************************************************************************
*** Applied ***
Date: Mon, 12 Jun 2000 03:39:24 +0900
From: Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>
Subject: Re: smpeg patch (frame count fix after seeking)


Oops. I found bug in my patch.

in gtv 
  Play -> Pause -> Seek -> Step -> Hang...(Oh My God !!!)

fix patch attached. 

thanks & sorry.
-----------------------------------------------
Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>

Index: MPEG.cpp
===================================================================
RCS file: /home/ncvs/smpeg/MPEG.cpp,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 MPEG.cpp
--- MPEG.cpp	2000/06/06 06:53:35	1.1.1.3
+++ MPEG.cpp	2000/06/11 17:37:32
@@ -334,6 +334,9 @@
   if (was_playing)
     Play();
 
+  if (VideoEnabled() && !was_playing) 
+    videoaction->RenderFrame(0);
+
   if ( pause && VideoEnabled() ) {
     videoaction->Pause();
   }
Index: gtv.c
===================================================================
RCS file: /home/ncvs/smpeg/gtv.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 gtv.c
--- gtv.c	2000/06/10 09:04:50	1.1.1.4
+++ gtv.c	2000/06/11 17:48:04
@@ -744,6 +744,8 @@
       
       SMPEG_seek(mpeg, (int)((info->total_size*adjust->value)/100));
     }
+    SMPEG_getinfo( mpeg, info );
+    gtv_set_frame( raw, info->current_frame );
 }
 
 static void gtv_trackbar_drag_on(GtkWidget *widget, gpointer raw)
Index: video/MPEGvideo.cpp
===================================================================
RCS file: /home/ncvs/smpeg/video/MPEGvideo.cpp,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 MPEGvideo.cpp
--- video/MPEGvideo.cpp	2000/06/10 09:04:51	1.1.1.3
+++ video/MPEGvideo.cpp	2000/06/11 17:59:54
@@ -463,6 +463,19 @@
 void
 MPEGvideo:: RenderFrame( int frame )
 {
+
+   if (_stream->need_frameadjust) {
+      _stream->_jumpFrame=0;
+      while(_stream->need_frameadjust) {
+        mpegVidRsrc(0, _stream, 0);
+#ifdef DEBUG
+        printf("Adjusting Frame %d Timecode %f\n",_stream->totNumFrames,_stream->timestamp);
+#endif
+      }
+      _stream->_jumpFrame=-1;
+      return;
+   }
+
     if( _stream->totNumFrames > frame ) {
         mpeg->rewind_stream();
 	mpeg->next_packet();
Index: video/video.cpp
===================================================================
RCS file: /home/ncvs/smpeg/video/video.cpp,v
retrieving revision 1.1.1.4
retrieving revision 1.1.1.4.4.1
diff -u -r1.1.1.4 -r1.1.1.4.4.1
--- video/video.cpp	2000/06/10 09:04:53	1.1.1.4
+++ video/video.cpp	2000/06/11 17:35:06	1.1.1.4.4.1
@@ -1093,6 +1093,7 @@
 		vid_stream->group.tc_seconds * vid_stream->rate_deal +
 		vid_stream->group.tc_pictures);
 		vid_stream->need_frameadjust=false;
+		vid_stream->totNumFrames=vid_stream->current_frame;
 #if 0
 	printf("Adjusted Frame %d -> %d\n",prev,vid_stream->current_frame);
 #endif

*************************************************************************
*** Applied ***
Date: Fri, 09 Jun 2000 22:46:21 +0200
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: Buffering problems

Hi

I've fixed the To End bug, and send you this before you go on weekend
too :)
Maybe I'll take a look if we can make it faster with seeking this
week-end but I also have a few things to code for my encoder ;)

this time the patch will be really small! :)

see ya,
Vivien.

diff -Naur smpeg/video/MPEGvideo.cpp smpeg.patched/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Fri Jun  9 22:20:47 2000
+++ smpeg.patched/video/MPEGvideo.cpp	Fri Jun  9 22:33:02 2000
@@ -533,7 +533,7 @@
         if ( SDL_LockYUVOverlay(yuv) == 0 ) {
 	  SDL_Rect dstrect;
 
-            memcpy(yuv->pixels, _stream->current->image, (_w*_h)+2*(_w*_h)/4);
+            memcpy(yuv->pixels, _stream->current->image->pixels, (_w*_h)+2*(_w*_h)/4);
             SDL_UnlockYUVOverlay(yuv);
             dstrect.x = _rect.x;
             dstrect.y = _rect.y;
*************************************************************************
*** Applied ***
Date: Fri, 09 Jun 2000 00:30:56 +0900
From: Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>
Subject: smpeg patch (frame count fix after seeking)

Hello.

I'm looked latest cvs version of smpeg.

gtv's movie seek function is very great&cool!!

I'm tried to add a little change.

patch attached.(gtvfix.diff)

Window size change.(Double <-> Normal)
SMPEG_info's frame counter adjust after seeking.

thanks.
-----------------------------------------------
Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>

Index: gtv.c
===================================================================
RCS file: /home/ncvs/smpeg/gtv.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 gtv.c
--- gtv.c	2000/06/06 06:53:36	1.1.1.3
+++ gtv.c	2000/06/07 17:21:36
@@ -70,7 +70,7 @@
 	audio = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "audio" ) );
 
 #if 1 /* Sam 5/31/2000 - Default to doubled video and audio on */
-	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( twotimes ), TRUE );
+	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( twotimes ), FALSE );
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( loop ), FALSE );
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( audio ), TRUE );
 #else
@@ -255,7 +255,7 @@
 #ifdef linux
 	putenv("SDL_VIDEO_CENTERED=1");
 #endif
-	sdl_screen = SDL_SetVideoMode( info->width * 2, info->height * 2, video_bpp, SDL_ASYNCBLIT );
+	sdl_screen = SDL_SetVideoMode( info->width , info->height , video_bpp, SDL_ASYNCBLIT);
         SDL_WM_SetCaption(name, "gtv movie");
         gtv_center_window(sdl_screen);
 	SMPEG_setdisplay( mpeg, sdl_screen, NULL, NULL );
@@ -519,8 +519,10 @@
 static void gtv_double( GtkWidget* item, gpointer raw )
 {
     SMPEG* mpeg = NULL;
-    SDL_Surface* sdl_screen = NULL;
-    int scale = 1;
+    SDL_Surface* sdl_screen = NULL,*newscreen;
+    SMPEG_Info* info = NULL;
+    int stopped=0;
+    int width,height;
 
     assert( raw );
 
@@ -534,22 +536,26 @@
 	twotimes = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "twotimes" ) );
 	active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( twotimes ) );
 
+	info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
+	assert( info );
+        if (SMPEG_status(mpeg)==SMPEG_PLAYING) {
+		SMPEG_pause(mpeg);
+		stopped=1;
+	}
 	if( active ) {
-	    SMPEG_move( mpeg, 0, 0 );
-	    scale = 2;
+	    width = info->width * 2;
+	    height = info->height * 2;
 	} else {
-	    SMPEG_Info* info = NULL;
-
-	    info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
-	    assert( info );
-	    SMPEG_move( mpeg,
-			( sdl_screen->w - info->width ) / 2,
-			( sdl_screen->h - info->height ) / 2 );
-	    scale = 1;
+	    width = info->width;
+	    height = info->height;
 	}
-
-	SMPEG_scale( mpeg, scale );
-	gtv_clear_screen( raw );
+	newscreen = SDL_SetVideoMode(width, height,
+		sdl_screen->format->BitsPerPixel,sdl_screen->flags);
+	
+	gtk_object_set_data( GTK_OBJECT( raw ), "sdl_screen", newscreen );
+	SMPEG_scaleXY( mpeg, newscreen->w,newscreen->h );
+        gtv_center_window(sdl_screen);
+        if (stopped) SMPEG_pause(mpeg);
     }
 
 }
Index: video/MPEGvideo.cpp
===================================================================
RCS file: /home/ncvs/smpeg/video/MPEGvideo.cpp,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 MPEGvideo.cpp
--- video/MPEGvideo.cpp	2000/06/05 09:53:00	1.1.1.2
+++ video/MPEGvideo.cpp	2000/06/07 17:19:41
@@ -303,6 +303,20 @@
   _stream->_jumpFrame = -1;
   _stream->realTimeStart = -time;
   play_time = time;
+  if (time > 0) {
+	double oneframetime;
+	if (_stream->_oneFrameTime == 0)
+		oneframetime = 1.0 / _stream->_smpeg->_fps;	
+	else
+		oneframetime = _stream->_oneFrameTime;
+
+	/* time -> frame */
+	_stream->totNumFrames = (int)(time / oneframetime);
+
+	/* Set Current Frame To 0 & Frame Adjust Frag Set */
+	_stream->current_frame = 0;
+	_stream->need_frameadjust=true;
+  }
 }
 
 
@@ -348,7 +362,7 @@
         info->width = _w;
         info->height = _h;
         if ( _stream ) {
-            info->current_frame = _stream->totNumFrames;
+            info->current_frame = _stream->current_frame;
 #ifdef CALCULATE_FPS
 
             /* Get the appropriate indices for the timestamps */
Index: video/gdith.cpp
===================================================================
RCS file: /home/ncvs/smpeg/video/gdith.cpp,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 gdith.cpp
--- video/gdith.cpp	2000/06/01 12:01:43	1.1.1.1
+++ video/gdith.cpp	2000/06/06 15:23:29
@@ -147,6 +147,7 @@
 
     /* Update the number of frames displayed */
     vid_stream->totNumFrames++;
+    vid_stream->current_frame++;
 
     /* Do we need to initialize framerate? */
     if ( vid_stream->rate_deal < 0 ) {
Index: video/video.cpp
===================================================================
RCS file: /home/ncvs/smpeg/video/video.cpp,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 video.cpp
--- video/video.cpp	2000/06/06 06:53:37	1.1.1.3
+++ video/video.cpp	2000/06/07 17:20:25
@@ -799,6 +799,9 @@
 
   /* Reset EOF_flag to 0 */
   vid->EOF_flag = FALSE;
+
+  vid->current_frame=0;
+  vid->need_frameadjust=false;
 }
 
 
@@ -1079,6 +1082,19 @@
             fprintf( stderr, "mpegVidRsrc ParseGOP\n" );
             goto error;
         }
+	/* need adjust current_frame (after Seek) */
+	if (vid_stream->need_frameadjust) {
+		int prev;
+		prev = vid_stream->totNumFrames;
+		vid_stream->current_frame = (int)
+		(
+		vid_stream->group.tc_hours * 3600 * vid_stream->rate_deal +
+		vid_stream->group.tc_minutes * 60 * vid_stream->rate_deal +
+		vid_stream->group.tc_seconds * vid_stream->rate_deal +
+		vid_stream->group.tc_pictures);
+		vid_stream->need_frameadjust=false;
+	printf("Adjusted Frame %d -> %d\n",prev,vid_stream->current_frame);
+	}
         goto done;
 
 
Index: video/video.h
===================================================================
RCS file: /home/ncvs/smpeg/video/video.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 video.h
--- video/video.h	2000/06/01 12:01:43	1.1.1.1
+++ video/video.h	2000/06/06 15:23:29
@@ -309,6 +309,8 @@
   unsigned int *timestamp_mark;
   bool timestamp_used;
 /* begining of added variables */
+  bool need_frameadjust;
+  int  current_frame;
 } VidStream;   
 
 /* Declaration of global display pointer. */
*************************************************************************
*** Applied ***
Date: Tue, 06 Jun 2000 03:13:46 +0200
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: Buffering problems


Sam Lantinga wrote:
> Sweet!  I think we're ready to release SMPEG 0.4.0 just as soon as the
> sync on skip is fixed.

Hi!

I've managed to find some time today to fix this bug :-)
I reinitialized times according to the scr instead of pts...

for the Patches file :
        - changed seeking in MPEG.cpp to set video and audio decoder
times according to the first presentation timestamp in their respective stream
                * fixes slight delay between audio&video after a seek
        - removed call to gtv_step in gtv_seek
        that was meant in first place to see where we are in the stream
while seeking, but isn't needed, and actually didn't work :-)

What are you planning to do after 0.4.0?
I would be eager to help developping the ATI acceleration as I own an
ATI Rage128 myself :-)

see ya,
Vivien.

diff -Naur smpeg/MPEG.cpp smpeg.patched/MPEG.cpp
--- smpeg/MPEG.cpp	Sun Jun  4 21:16:54 2000
+++ smpeg.patched/MPEG.cpp	Tue Jun  6 02:36:25 2000
@@ -350,22 +350,24 @@
   Stop();
 
   /* Go to the desired position into file */
-  if((time = system->Seek(position)) < 0) return(false);
+  if(!system->Seek(position)) return(false);
 
-  /* Skip the first empty buffer made when creating a mpegstream */
-  /* which would otherwise be interpreted as end of file */
-
-  if(audiostream) audiostream->next_packet();
-  if(videostream) videostream->next_packet();
+  /* Seek first aligned data */
+  if(audiostream)
+    while(audiostream->time() == -1)
+      audiostream->next_packet();
+  if(videostream)
+    while(videostream->time() == -1)
+      videostream->next_packet();
 
   /* And forget what we previouly buffered */
   if ( audioaction ) {
     audioaction->Rewind();
-    audioaction->ResetSynchro(time);
+    audioaction->ResetSynchro(audiostream->time());
   }
   if ( videoaction ) {
     videoaction->Rewind();
-    videoaction->ResetSynchro(time);
+    videoaction->ResetSynchro(videostream->time());
   }
 
   return(true);
diff -Naur smpeg/MPEGlist.cpp smpeg.patched/MPEGlist.cpp
--- smpeg/MPEGlist.cpp	Thu May 11 06:49:13 2000
+++ smpeg.patched/MPEGlist.cpp	Tue Jun  6 02:17:42 2000
@@ -7,6 +7,7 @@
   lock = 0;
   next = 0;
   prev = 0;
+  TimeStamp = -1;
 }
 
 MPEGlist::~MPEGlist()
diff -Naur smpeg/MPEGstream.cpp smpeg.patched/MPEGstream.cpp
--- smpeg/MPEGstream.cpp	Fri Jun  2 14:18:56 2000
+++ smpeg.patched/MPEGstream.cpp	Mon Jun  5 18:33:34 2000
@@ -361,3 +361,8 @@
 {
   enabled = toggle;
 }
+
+double MPEGstream::time()
+{
+  return(br->TimeStamp);
+}
diff -Naur smpeg/MPEGstream.h smpeg.patched/MPEGstream.h
--- smpeg/MPEGstream.h	Fri May 26 20:04:53 2000
+++ smpeg.patched/MPEGstream.h	Mon Jun  5 18:28:02 2000
@@ -88,6 +88,9 @@
     /* Enable or disable the stream */
     void enable(bool toggle);
 
+    /* Get stream time */
+    double time();
+
     Uint32 pos;
 
     Uint8 streamid;
diff -Naur smpeg/MPEGsystem.cpp smpeg.patched/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Sun Jun  4 21:16:54 2000
+++ smpeg.patched/MPEGsystem.cpp	Tue Jun  6 02:29:12 2000
@@ -400,7 +400,6 @@
   timestamp = 0.0;
   timedrift = 0.0;
   skip_timestamp = -1;
-  start_timestamp = -1;
   system_thread_running = false;
   system_thread = 0;
 
@@ -551,7 +550,6 @@
   {
       pointer += header_size;
       stream_list[0]->pos += header_size;
-      if(start_timestamp == -1) start_timestamp = timestamp;
 #ifdef DEBUG_SYSTEM
       fprintf(stderr, "MPEG packet header time: %lf\n", timestamp);
 #endif
@@ -870,7 +868,7 @@
   Seek(0);
 }
 
-double MPEGsystem::Seek(int length)
+bool MPEGsystem::Seek(int length)
 {
   request = 0;
 
@@ -889,7 +887,7 @@
       errorstream = true;
       SetError(strerror(errno));
     }
-    return(-1);
+    return(false);
   }
 
   /* Reinitialize the read buffer */
@@ -901,7 +899,6 @@
   endofstream = false;
   errorstream = false;
   timestamp = 0.0;
-  start_timestamp = -1;
   skip_timestamp = -1;
 
   /* Get the next header */
@@ -924,16 +921,9 @@
 
   /* Wait for prebuffering */
   while(request > 0 && !Eof())
-  {
-    if(timestamp > 0 && start_timestamp < 0)
-      start_timestamp = timestamp;
-
     SDL_Delay(1);
-  }
-
-  if(start_timestamp < 0) start_timestamp = 0.0;
 
-  return(start_timestamp);
+  return(true);
 }
 
 void MPEGsystem::Loop(bool toggle)
diff -Naur smpeg/MPEGsystem.h smpeg.patched/MPEGsystem.h
--- smpeg/MPEGsystem.h	Fri May 26 20:04:54 2000
+++ smpeg.patched/MPEGsystem.h	Tue Jun  6 02:30:57 2000
@@ -28,7 +28,7 @@
     void Rewind();
     void Loop(bool toggle);
     bool Eof() const;
-    double Seek(int length);
+    bool Seek(int length);
     Uint32 TotalSize();
 
     /* Skip "seconds" seconds */
@@ -94,7 +94,6 @@
 
 #ifdef USE_SYSTEM_TIMESTAMP
     /* Current timestamp for this stream */
-    double start_timestamp;
     double timestamp;
     double timedrift;
     double skip_timestamp;
diff -Naur smpeg/gtv.c smpeg.patched/gtv.c
--- smpeg/gtv.c	Sun Jun  4 21:16:56 2000
+++ smpeg.patched/gtv.c	Mon Jun  5 18:20:56 2000
@@ -737,8 +737,6 @@
       SMPEG_getinfo( mpeg, info );
       
       SMPEG_seek(mpeg, (int)((info->total_size*adjust->value)/100));
-
-      gtv_step( NULL, raw );
     }
 }
 
diff -Naur smpeg/video/video.cpp smpeg.patched/video/video.cpp
--- smpeg/video/video.cpp	Sun Jun  4 21:16:57 2000
+++ smpeg.patched/video/video.cpp	Tue Jun  6 02:37:08 2000
@@ -1098,6 +1098,9 @@
         {
             status = SKIP_PICTURE;
         }
+	
+	if( !vid_stream->current )
+	    status = SKIP_PICTURE;
 
         if( status == SKIP_PICTURE )
         {
*************************************************************************
*** Applied ***
Date: Sun, 04 Jun 2000 16:42:54 +0200
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: Buffering problems


Daniel Vogel wrote:
> starts playing a movie. Here the sound starts playing but the first few
> frames of the movie get skipped... As this happens only in special
cases
> I guess we can live with that as long as it fixes the bug on Mike's box
> upstairs.
thanks for your debug log Daniel.

Sam Lantinga wrote:
> This is a bug, and I'm CC'ing the guys who implemented the buffering,
so
[...]
> It looks like the buffering state isn't reset when you stop and then
> start a movie.  To see this, try loading ab.mpg in gtv and then let it
> play all the way through twice.
>
> It stops before showing the final frames of the boy sitting on the
moon.

The bug hunting was good this week-end :-)

This patch fixes your bug and should fix Daniel's (Daniel: feedback
please :-))
It also includes the patch I sent to you on 28/05/2000 (fixed a crash
when playing empty files, added current directory persistence in gtv).

Here is the detail of what I did:
        - check for the existence of the system thread before waiting for
it to
end, in ~MPEGsystem
                * fixes crash when playing empty files
        - kept the last visited directory in gtv

        - wrote a much faster video-only frame splitter in
MPEGsystem::FillBuffer()
        - fixed TotalSize to report 0 on a pipe (and not to generate an
error)
        - forced MPEGsystem::Tell() to return current position <
TotalSize
                * fixes end skipping bug
        This fix might sound weird, but actually there is no way of
knowing
*exactly* where we are, as the system layer is read in advance. Current
position is defined as the sum of all the MPEGstream positions for
now... if someone has a better idea, let me know.
        - fixed seek_next_header/seek_first_header mess that caused hangs
on
video-only MPEGs (and maybe other)
        - added initialization of the audio time in
MPEGaudio::initialized()
                * should fix start skipping bug
        - reverted back to theorical audio play time instead of
experimental in
Play_MPEGaudio
                * fixes synchro
        I find synchro much better this way (actually ..perfect..), but
you
should test and tell me what you think of this compared to the
experimental way. With streams I used to test, sound was slightly before
video with the experimental way.
        - fixed realTimeStart value setting in MPEGvideo::Play and
MPEGvideo::Stop that caused smpeg to hang sometimes
(video thought it was in advance and slept for a long long time :-( )

> Great, thanks! :)

You're welcome :-)
 
> BTW, you, Daniel, and Manuel are going to get a big thank-you in the
> release README. :)

Hehe. And don't forget to also thank Metallica (especially Lars Ulrich)
for their great help in fixing the synchro (drums are very nice for
this) :-)

see ya,
Vivien

diff -Naur smpeg/MPEG.cpp smpeg.patched/MPEG.cpp
--- smpeg/MPEG.cpp	Fri May 26 20:04:52 2000
+++ smpeg.patched/MPEG.cpp	Sun Jun  4 13:09:05 2000
@@ -158,11 +158,11 @@
   system->Loop(toggle);
 }
 void MPEG::Play(void) {
-  if ( VideoEnabled() ) {
-    videoaction->Play();
-  }
   if ( AudioEnabled() ) {
     audioaction->Play();
+  }
+  if ( VideoEnabled() ) {
+    videoaction->Play();
   }
 }
 void MPEG::Stop(void) {
diff -Naur smpeg/MPEGsystem.cpp smpeg.patched/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Fri Jun  2 14:18:57 2000
+++ smpeg.patched/MPEGsystem.cpp	Sat Jun  3 14:44:14 2000
@@ -401,8 +401,10 @@
   timedrift = 0.0;
   skip_timestamp = -1;
   start_timestamp = -1;
+  system_thread_running = false;
+  system_thread = 0;
 
-  /* Search the MPEG for the next header */
+  /* Search the MPEG for the first header */
   if(!seek_first_header())
   {
     errorstream = true;
@@ -413,7 +415,6 @@
   request = PRE_BUFFERED_MAX;
 
   /* Start the system thread */
-  system_thread_running = false;
   system_thread = SDL_CreateThread(SystemThread, this);
 
   /* Wait for the thread to start */
@@ -441,8 +442,11 @@
   MPEGstream ** list;
 
   /* Kill the system thread */
-  system_thread_running = false;
-  SDL_WaitThread(system_thread, NULL);
+  if(system_thread)
+  {
+    system_thread_running = false;
+    SDL_WaitThread(system_thread, NULL);
+  }
 
   /* Delete the streams */
   for(list = stream_list; *list; list ++)
@@ -638,18 +642,38 @@
       else
       {
 	/* Check for next slice, picture, gop or sequence header */
-	for(; (packet_size <= read_buffer + read_size - pointer - 4) && 
-	      !(sequence_header(pointer+packet_size, read_buffer - pointer + read_size - packet_size, &frametime) ||
-		gop_header(pointer+packet_size, read_buffer - pointer + read_size - packet_size) ||
-		picture_header(pointer+packet_size, read_buffer - pointer + read_size - packet_size) ||
-		slice_header(pointer+packet_size, read_buffer - pointer + read_size - packet_size))
-	      ; packet_size++);
-	if(packet_size > read_buffer - pointer + read_size - 4)
-	{
-	  SetError("Could not find next video header\n");
-	  errorstream = true;
-	  return(0);
-	}
+	register Uint8 * p;
+	register Uint8 c;
+	
+	p = pointer + packet_size;
+      state0:
+	c = *p;
+	p++;
+	if(p >= read_buffer + read_size) goto end;
+	if(c != 0) goto state0;
+      state1:
+	c = *p;
+	p++;
+	if(p >= read_buffer + read_size) goto end;
+	if(c != 0) goto state0;
+      state2:
+	c = *p;
+	p++;
+	if(p >= read_buffer + read_size) goto end;
+	if(c == 0) goto state2;
+	if(c != 1) goto state0;
+      state3:
+	c = *p;
+	p++;
+	if(p >= read_buffer + read_size) goto end;
+	if(c <= 0xaf) goto end;
+	if(c == 0xb8) goto end;
+	if(c == 0xb3) goto end;
+	goto state0;
+      end:
+
+	if(p >= read_buffer + read_size) packet_size = read_size;
+	else packet_size = p - pointer - 4;
       }
 
       if(stream_id == SYSTEM_STREAMID)
@@ -795,7 +819,10 @@
   for(i = 0, t = 0; stream_list[i]; i++)
     t += stream_list[i]->pos;
 
-  return(t);
+  if(t > TotalSize())
+    return(TotalSize());
+  else
+    return(t);
 }
 
 Uint32 MPEGsystem::TotalSize()
@@ -805,24 +832,33 @@
 
   /* I made it this way (instead of fstat) to avoid #ifdef WIN32 everywhere */
   /* in case 'in some weird perversion of nature' someone wants to port this to Win32 :-) */
- if((pos = lseek(mpeg_fd, 0, SEEK_CUR)) == (off_t) -1)
+  if((pos = lseek(mpeg_fd, 0, SEEK_CUR)) == (off_t) -1)
   {
-    errorstream = true;
-    SetError(strerror(errno));
+    if(errno != ESPIPE)
+    {
+      errorstream = true;
+      SetError(strerror(errno));
+    }
     return(0);
   }
 
- if((size = lseek(mpeg_fd, 0, SEEK_END)) == (off_t) -1)
+  if((size = lseek(mpeg_fd, 0, SEEK_END)) == (off_t) -1)
   {
-    errorstream = true;
-    SetError(strerror(errno));  
+    if(errno != ESPIPE)
+    {
+      errorstream = true;
+      SetError(strerror(errno));  
+    }
     return(0);
   }
   
- if((pos = lseek(mpeg_fd, pos, SEEK_SET)) == (off_t) -1)
+  if((pos = lseek(mpeg_fd, pos, SEEK_SET)) == (off_t) -1)
   {
-    errorstream = true;
-    SetError(strerror(errno));  
+    if(errno != ESPIPE)
+    {
+      errorstream = true;
+      SetError(strerror(errno));  
+    }
     return(0);
   }
 
@@ -868,8 +904,8 @@
   start_timestamp = -1;
   skip_timestamp = -1;
 
-  /* Get the first header */
-  if(!seek_first_header())
+  /* Get the next header */
+  if(!seek_next_header())
   {
     if(!Eof())
     {
@@ -1086,14 +1122,10 @@
   if(Eof())
     return(false);
 
-  while(!( ((stream_list[0]->streamid == AUDIO_STREAMID) && audio_aligned(pointer, read_buffer + read_size - pointer)) ||
-	   ((stream_list[0]->streamid == SYSTEM_STREAMID) && system_aligned(pointer, read_buffer + read_size - pointer)) ||
-	   ((stream_list[0]->streamid == VIDEO_STREAMID) && (
-							     Match4(pointer, VIDEO_CODE, VIDEO_MASK) ||
-							     Match4(pointer, END_CODE, END_MASK) ||
-							     Match4(pointer, GOP_CODE, GOP_MASK) ||
-							     Match4(pointer, PICTURE_CODE, PICTURE_MASK)))
-	) )
+  while(!( (stream_list[0]->streamid == AUDIO_STREAMID && audio_aligned(pointer, read_buffer + read_size - pointer)) ||
+	   (stream_list[0]->streamid == SYSTEM_STREAMID && system_aligned(pointer, read_buffer + read_size - pointer)) ||
+	   (stream_list[0]->streamid == VIDEO_STREAMID && Match4(pointer, GOP_CODE, GOP_MASK))
+	 ) )
   {
        ++pointer;
        stream_list[0]->pos++;
diff -Naur smpeg/audio/mpegtoraw.cpp smpeg.patched/audio/mpegtoraw.cpp
--- smpeg/audio/mpegtoraw.cpp	Fri Jun  2 14:18:59 2000
+++ smpeg.patched/audio/mpegtoraw.cpp	Sun Jun  4 14:13:34 2000
@@ -119,6 +119,7 @@
   ring = NULL;
 #endif
   Rewind();
+  ResetSynchro(0);
 };
 
 
@@ -354,7 +355,8 @@
 
     /* Increment the current play time (assuming fixed frag size) */
     switch (audio->frags_playing++) {
-#if 0 /* This is how it theoretically should work */
+      // Vivien: Well... the theorical way seems good to me :-)
+#if 1 /* This is how it theoretically should work */
         case 0:        /* The first audio buffer is being filled */
             break;
         case 1:        /* The first audio buffer is starting playback */
diff -Naur smpeg/gtv.c smpeg.patched/gtv.c
--- smpeg/gtv.c	Fri Jun  2 14:18:59 2000
+++ smpeg.patched/gtv.c	Sat Jun  3 17:27:10 2000
@@ -49,6 +49,7 @@
 
 
 static int gtv_trackbar_dragging;
+static gchar * gtv_default_directory = 0;
 
 static void gtv_fix_toggle_state( gpointer raw )
 {
@@ -140,6 +141,13 @@
 
     if( filename ) {
 	gtv_open_file( filename, raw );
+	if( strrchr( filename, '/') )
+	{
+	  if( gtv_default_directory ) free( gtv_default_directory );
+	  gtv_default_directory = (gchar *) malloc( (strlen(filename) + 1) * sizeof(gchar) );
+	  strcpy( gtv_default_directory, filename);
+	  *(strrchr( gtv_default_directory, '/' ) + 1) = 0;
+	}
     }
 
     gtv_dialog_cleanup( raw );
@@ -154,6 +162,8 @@
 			GTK_SIGNAL_FUNC( gtv_open_ok ), raw );
     gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( file_sel )->cancel_button ), "clicked",
 			GTK_SIGNAL_FUNC( gtv_dialog_cancel ), raw );
+    if( gtv_default_directory )
+      gtk_file_selection_complete( GTK_FILE_SELECTION( file_sel ), gtv_default_directory );
     gtk_file_selection_hide_fileop_buttons( GTK_FILE_SELECTION( file_sel ) );
 
     /* HACK HACK HACK */
diff -Naur smpeg/video/MPEGvideo.cpp smpeg.patched/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Fri May 26 20:05:05 2000
+++ smpeg.patched/video/MPEGvideo.cpp	Sun Jun  4 15:17:26 2000
@@ -229,6 +229,8 @@
 	  mpeg->playing = false;
         }
     }
+    /* Get the time the playback stopped */
+    mpeg->_stream->realTimeStart -= ReadSysClock();
 #ifdef TIME_MPEG
     stop_time = SDL_GetTicks();
     stop_frames = mpeg->_stream->totNumFrames;
@@ -271,9 +273,6 @@
         _thread = NULL;
     }
     ResetPause();
-    if ( _stream ) {
-        _stream->realTimeStart -= ReadSysClock();
-    }
 }
 
 void
@@ -287,12 +286,14 @@
       init_stats();
 #endif
       /* Process start codes */
+      /* Vivien: seems unnecessary */
+#if 0
       if( mpegVidRsrc( 0, _stream, 1 ) == NULL )
       {
 	SetError("Not an MPEG video stream");
 	return;
       }
-      _stream->realTimeStart = 0.0;
+#endif
     }
 }
 
diff -Naur smpeg/video/video.cpp smpeg.patched/video/video.cpp
--- smpeg/video/video.cpp	Fri May 26 20:05:05 2000
+++ smpeg.patched/video/video.cpp	Sun Jun  4 14:44:41 2000
@@ -795,6 +795,7 @@
   vid->_skipFrame = 0;
   vid->_skipCount = 0;
   vid->_jumpFrame = -1;
+  vid->realTimeStart = 0;
 
   /* Reset EOF_flag to 0 */
   vid->EOF_flag = FALSE;
*************************************************************************
*** Applied ***
Date: Sat, 27 May 2000 15:43:08 -0700
From: Mo <mo@nospam.com>
Subject: A bug, a patch, and a question.

First off, I would like to say thanks to everyone working on
smpeg. It is really making some good progress. At the same
time, there also seem to be some regressions. The CVS version
of smpeg does not work for a number of mpeg files that it worked
on a couple of weeks ago. I am not just complaining here, I want
to help find out what went wrong and fix it. Problem is, I do not
know where to start. There is no ChangeLog in the smpeg CVS. What's
up with that? Every project needs a ChangeLog, otherwise it is
very difficult to figure out where and when something broke.

I also noticed that the autogen.sh script actually runs ./configure.
This is not correct. The autogen.sh script should do everything needed
to regen files but it should not run ./configure. I also found that
smpeg would sometimes deadlock inside the destructor for an audio file.
The following patch fixes the deadlock and the autogen.sh script, I have
also included the first entry for a ChangeLog that is so badly needed.


2000-05-27  Mo DeJong  <mdejong@cygnus.com>

        * ChangeLog: Added ChangeLog to project.
        * autogen.sh: Don't run ./configure
        * audio/MPEGaudio.cpp (~MPEGaudio): Shutdown
        the audio decoding thread before stopping to
        avoid deadlock.



Index: autogen.sh
===================================================================
RCS file: /cvs/smpeg/autogen.sh,v
retrieving revision 1.1
diff -u -r1.1 autogen.sh
--- autogen.sh	1999/10/25 14:38:47	1.1
+++ autogen.sh	2000/05/27 22:20:51
@@ -3,5 +3,3 @@
 aclocal
 automake --foreign
 autoconf
-
-./configure $*
Index: audio/MPEGaudio.cpp
===================================================================
RCS file: /cvs/smpeg/audio/MPEGaudio.cpp,v
retrieving revision 1.19
diff -u -r1.19 MPEGaudio.cpp
--- audio/MPEGaudio.cpp	2000/05/26 17:54:37	1.19
+++ audio/MPEGaudio.cpp	2000/05/27 22:20:51
@@ -74,12 +74,13 @@
 
 MPEGaudio:: ~MPEGaudio()
 {
-    /* Remove ourselves from the mixer hooks */
-    Stop();
 #ifdef THREADED_AUDIO
     /* Stop the decode thread */
     StopDecoding();
 #endif
+
+    /* Remove ourselves from the mixer hooks */
+    Stop();
     if ( sdl_audio ) {
         /* Close up the audio so others may play */
         SDL_CloseAudio();


Mo DeJong
Red Hat Inc
*************************************************************************
*** Applied ***
Date: Tue, 30 May 2000 03:57:33 +0200 (CEST)
From: "Markus F.X.J. Oberhumer" <markus.oberhumer@jk.uni-linz.ac.at>
To: Sam Lantinga <slouken@devolution.com>
Subject: smpeg win32 patches

Hello Sam,

below you will find some smpeg win32 patches. They are
against yesterday's CVS version, and I've also used
the lastest SDL-CVS version for testing.

Main changes:
  - allow compilation with VC++ 6
  - avoid some warnings
  - make some tables const
  - increase decoder thread priority (just like the SDL audio thread)

I've tested this successfully with my pysolsoundserver. Still,
some problems remain:

 - there are noticaable distortions (thread/semaphore problem ???)
 - SMPEG_stop() seems to cause a deadlock, at least from SDL_mixer
 - the version not using THREADED_AUDIO immediately crashes
Cheers,
Markus

----   Markus F.X.J. Oberhumer  @  http://oberhumer.tsx.org   ----
----     5E CB 5C 85 DE AF 9E BF  E9 DA 7E 6A 39 F8 CC 67     ----

                      3 WARPS TO URANUS

diff -ur smpeg/MPEGaudio.h smpeg-20000529/MPEGaudio.h
--- smpeg/MPEGaudio.h	Fri May 26 19:57:09 2000
+++ smpeg-20000529/MPEGaudio.h	Tue May 30 03:02:02 2000
@@ -343,9 +343,10 @@
   int     samplesperframe;
   int     rawdatareadoffset, rawdatawriteoffset;
   Sint16 *rawdata;
-  Sint16  spillover[ RAWDATASIZE ];
 #ifdef THREADED_AUDIO
   MPEG_ring *ring;
+#else
+  Sint16  spillover[ RAWDATASIZE ];
 #endif
   int volume;
 
diff -ur smpeg/MPEGring.cpp smpeg-20000529/MPEGring.cpp
--- smpeg/MPEGring.cpp	Fri May 26 19:57:09 2000
+++ smpeg-20000529/MPEGring.cpp	Tue May 30 01:48:36 2000
@@ -152,7 +152,7 @@
 */
 
 void
-MPEG_ring:: WriteDone( Uint32 len, double timestamp=-1 )
+MPEG_ring:: WriteDone( Uint32 len, double timestamp)
 {
     if ( ring->active ) {
         assert(len <= ring->bufSize);
diff -ur smpeg/MPEGstream.cpp smpeg-20000529/MPEGstream.cpp
--- smpeg/MPEGstream.cpp	Fri May 26 19:57:09 2000
+++ smpeg-20000529/MPEGstream.cpp	Tue May 30 01:48:36 2000
@@ -298,7 +298,7 @@
   return(!br->Size());
 }
 
-void MPEGstream::insert_packet(Uint8 * Data, Uint32 Size, double timestamp=-1)
+void MPEGstream::insert_packet(Uint8 * Data, Uint32 Size, double timestamp)
 {
   MPEGlist * newbr;
 
diff -ur smpeg/MPEGsystem.cpp smpeg-20000529/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Fri May 26 19:57:09 2000
+++ smpeg-20000529/MPEGsystem.cpp	Tue May 30 01:50:34 2000
@@ -3,6 +3,7 @@
 #include <errno.h>
 #include <assert.h>
 #ifdef WIN32
+#include <sys/types.h>
 #include <io.h>
 #include <winsock.h>
 #else
@@ -575,7 +576,7 @@
 
     if(!stream_list[1])
     { 
-      Uint8 * packet_end;
+      //Uint8 * packet_end;
 
       packet_size = 0;
 
diff -ur smpeg/audio/MPEGaudio.cpp smpeg-20000529/audio/MPEGaudio.cpp
--- smpeg/audio/MPEGaudio.cpp	Fri May 26 19:57:11 2000
+++ smpeg-20000529/audio/MPEGaudio.cpp	Tue May 30 01:50:34 2000
@@ -290,7 +290,7 @@
 bool
 MPEGaudio:: issync(void)
 {
-  return (bitindex&7);
+  return (bitindex&7) != 0;
 }
   
 int 
diff -ur smpeg/audio/mpeglayer1.cpp smpeg-20000529/audio/mpeglayer1.cpp
--- smpeg/audio/mpeglayer1.cpp	Thu Aug 26 06:37:52 1999
+++ smpeg-20000529/audio/mpeglayer1.cpp	Tue May 30 02:22:22 2000
@@ -10,6 +10,10 @@
 #endif
 
 #include "MPEGaudio.h"
+#if defined(_WIN32) && defined(_MSC_VER)
+// disable warnings about double to float conversions
+#pragma warning(disable: 4244 4305)
+#endif
 
 // Tables for layer 1
 static const REAL factortable[15] = 
diff -ur smpeg/audio/mpeglayer2.cpp smpeg-20000529/audio/mpeglayer2.cpp
--- smpeg/audio/mpeglayer2.cpp	Fri May  5 09:38:21 2000
+++ smpeg-20000529/audio/mpeglayer2.cpp	Tue May 30 02:22:24 2000
@@ -8,8 +8,9 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
-#ifdef _MSC_VER
-#pragma warning(disable:4305) 
+#if defined(_WIN32) && defined(_MSC_VER)
+// disable warnings about double to float conversions
+#pragma warning(disable: 4244 4305)
 #endif
 
 #include "MPEGaudio.h"
diff -ur smpeg/audio/mpeglayer3.cpp smpeg-20000529/audio/mpeglayer3.cpp
--- smpeg/audio/mpeglayer3.cpp	Tue Apr 11 16:22:53 2000
+++ smpeg-20000529/audio/mpeglayer3.cpp	Tue May 30 02:22:24 2000
@@ -19,6 +19,10 @@
 #include <stdlib.h>
 
 #include "MPEGaudio.h"
+#if defined(_WIN32) && defined(_MSC_VER)
+// disable warnings about double to float conversions
+#pragma warning(disable: 4244 4305)
+#endif
 
 inline void Mpegbitwindow::wrap(void)
 {
diff -ur smpeg/audio/mpegtoraw.cpp smpeg-20000529/audio/mpegtoraw.cpp
--- smpeg/audio/mpegtoraw.cpp	Fri May 26 19:57:11 2000
+++ smpeg-20000529/audio/mpegtoraw.cpp	Tue May 30 03:16:28 2000
@@ -16,6 +16,9 @@
 
 #include "MPEGaudio.h"
 #include "MPEGstream.h"
+#if defined(_WIN32)
+#include <windows.h>
+#endif
 
 #define MY_PI 3.14159265358979323846
 
@@ -264,7 +267,7 @@
 }
 
 
-bool MPEGaudio::run( int frames, double *timestamp = NULL)
+bool MPEGaudio::run( int frames, double *timestamp)
 {
     double last_timestamp = -1;
     int totFrames = frames;
@@ -316,6 +319,10 @@
     MPEGaudio *audio = (MPEGaudio *)udata;
     double timestamp;
 
+#if defined(_WIN32)
+    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+#endif
+
     while ( audio->decoding && ! audio->mpeg->eof() ) {
         audio->rawdata = (Sint16 *)audio->ring->NextWriteBuffer();
 
@@ -425,12 +432,12 @@
         copylen = (audio->rawdatawriteoffset-audio->rawdatareadoffset);
         assert(copylen >= 0);
         if ( copylen >= len ) {
-            SDL_MixAudio(stream, &audio->spillover[audio->rawdatareadoffset],
+            SDL_MixAudio(stream, (Uint8 *)&audio->spillover[audio->rawdatareadoffset],
                                                        len*2, volume);
             audio->rawdatareadoffset += len;
             return;
         }
-        SDL_MixAudio(stream, &audio->spillover[audio->rawdatareadoffset],
+        SDL_MixAudio(stream, (Uint8 *)&audio->spillover[audio->rawdatareadoffset],
                                                        copylen*2, volume);
         len -= copylen;
         stream += copylen*2;
@@ -448,7 +455,7 @@
     audio->rawdatawriteoffset = 0;
     if ( audio->run(1) ) {
         assert(audio->rawdatawriteoffset > len);
-        SDL_MixAudio(stream, audio->spillover, len*2, volume);
+        SDL_MixAudio(stream, (Uint8 *) audio->spillover, len*2, volume);
         audio->rawdatareadoffset = len;
     } else {
         audio->rawdatareadoffset = 0;
diff -ur smpeg/smpeg.cpp smpeg-20000529/smpeg.cpp
--- smpeg/smpeg.cpp	Fri May 26 19:57:11 2000
+++ smpeg-20000529/smpeg.cpp	Tue May 30 01:48:16 2000
@@ -226,7 +226,7 @@
 /* Skip 'seconds' seconds of the MPEG */
 void SMPEG_skip( SMPEG* mpeg, float seconds )
 {
-  return(mpeg->obj->Skip(seconds));
+    mpeg->obj->Skip(seconds);
 }
 
 /* Render a particular frame in the MPEG video */
diff -ur smpeg/video/decoders.cpp smpeg-20000529/video/decoders.cpp
--- smpeg/video/decoders.cpp	Thu Aug 26 06:37:52 1999
+++ smpeg-20000529/video/decoders.cpp	Tue May 30 02:21:18 2000
@@ -78,7 +78,7 @@
 
 /* Decoding table for coded_block_pattern */
 
-coded_block_pattern_entry coded_block_pattern[512] = 
+const coded_block_pattern_entry coded_block_pattern[512] = 
 { {(unsigned int)ERROR, 0}, {(unsigned int)ERROR, 0}, {39, 9}, {27, 9}, {59, 9}, {55, 9}, {47, 9}, {31, 9},
     {58, 8}, {58, 8}, {54, 8}, {54, 8}, {46, 8}, {46, 8}, {30, 8}, {30, 8},
     {57, 8}, {57, 8}, {53, 8}, {53, 8}, {45, 8}, {45, 8}, {29, 8}, {29, 8},
@@ -146,27 +146,27 @@
 };
 
 /* Decoding tables for dct_dc_size_luminance */
-dct_dc_size_entry dct_dc_size_luminance[32] =
+const dct_dc_size_entry dct_dc_size_luminance[32] =
 {   {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
     {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
     {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, 
     {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5}, {(unsigned int)ERROR, 0}
 };
 
-dct_dc_size_entry dct_dc_size_luminance1[16] =
+const dct_dc_size_entry dct_dc_size_luminance1[16] =
 {   {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6},
     {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9}
 };
 
 /* Decoding table for dct_dc_size_chrominance */
-dct_dc_size_entry dct_dc_size_chrominance[32] =
+const dct_dc_size_entry dct_dc_size_chrominance[32] =
 {   {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, 
     {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
     {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
     {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5}, {(unsigned int)ERROR, 0}
 };
 
-dct_dc_size_entry dct_dc_size_chrominance1[32] =
+const dct_dc_size_entry dct_dc_size_chrominance1[32] =
 {   {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, 
     {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, 
     {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, 
@@ -175,7 +175,7 @@
 
 /* DCT coeff tables. */
 
-unsigned short int dct_coeff_tbl_0[256] =
+const unsigned short int dct_coeff_tbl_0[256] =
 {
 0xffff, 0xffff, 0xffff, 0xffff, 
 0xffff, 0xffff, 0xffff, 0xffff, 
@@ -243,7 +243,7 @@
 0x581c, 0x581c, 0x581c, 0x581c, 
 };
 
-unsigned short int dct_coeff_tbl_1[16] = 
+const unsigned short int dct_coeff_tbl_1[16] = 
 {
 0x00bb, 0x202b, 0x103b, 0x00ab, 
 0x084b, 0x1c2b, 0x541b, 0x501b, 
@@ -251,17 +251,17 @@
 0x0c3b, 0x008b, 0x182b, 0x441b, 
 };
 
-unsigned short int dct_coeff_tbl_2[4] =
+const unsigned short int dct_coeff_tbl_2[4] =
 {
 0x4019, 0x1429, 0x0079, 0x0839, 
 };
 
-unsigned short int dct_coeff_tbl_3[4] = 
+const unsigned short int dct_coeff_tbl_3[4] = 
 {
 0x0449, 0x3c19, 0x3819, 0x1029, 
 };
 
-unsigned short int dct_coeff_next[256] = 
+const unsigned short int dct_coeff_next[256] = 
 {
 0xffff, 0xffff, 0xffff, 0xffff, 
 0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, 
@@ -329,7 +329,7 @@
 0x0011, 0x0011, 0x0011, 0x0011, 
 };
 
-unsigned short int dct_coeff_first[256] = 
+const unsigned short int dct_coeff_first[256] = 
 {
 0xffff, 0xffff, 0xffff, 0xffff, 
 0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, 
diff -ur smpeg/video/decoders.h smpeg-20000529/video/decoders.h
--- smpeg/video/decoders.h	Thu Aug 26 06:37:52 1999
+++ smpeg-20000529/video/decoders.h	Tue May 30 02:20:54 2000
@@ -81,7 +81,7 @@
 
 /* External declaration of coded block pattern table. */
 
-extern coded_block_pattern_entry coded_block_pattern[512];
+extern const coded_block_pattern_entry coded_block_pattern[512];
 
 
 
@@ -108,13 +108,13 @@
 
 /* External declaration of dct dc size lumiance table. */
 
-extern dct_dc_size_entry dct_dc_size_luminance[32];
-extern dct_dc_size_entry dct_dc_size_luminance1[16];
+extern const dct_dc_size_entry dct_dc_size_luminance[32];
+extern const dct_dc_size_entry dct_dc_size_luminance1[16];
 
 /* External declaration of dct dc size chrom table. */
 
-extern dct_dc_size_entry dct_dc_size_chrominance[32];
-extern dct_dc_size_entry dct_dc_size_chrominance1[32];
+extern const dct_dc_size_entry dct_dc_size_chrominance[32];
+extern const dct_dc_size_entry dct_dc_size_chrominance1[32];
 
 
 /* DCT coeff tables. */
@@ -127,12 +127,12 @@
 
 /* External declaration of dct coeff tables. */
 
-extern unsigned short int dct_coeff_tbl_0[256];
-extern unsigned short int dct_coeff_tbl_1[16];
-extern unsigned short int dct_coeff_tbl_2[4];
-extern unsigned short int dct_coeff_tbl_3[4];
-extern unsigned short int dct_coeff_next[256];
-extern unsigned short int dct_coeff_first[256];
+extern const unsigned short int dct_coeff_tbl_0[256];
+extern const unsigned short int dct_coeff_tbl_1[16];
+extern const unsigned short int dct_coeff_tbl_2[4];
+extern const unsigned short int dct_coeff_tbl_3[4];
+extern const unsigned short int dct_coeff_next[256];
+extern const unsigned short int dct_coeff_first[256];
 
 #define DecodeDCTDCSizeLum(macro_val)                    \
 {                                                    \
*************************************************************************
*** Applied ***
Subject: Re: Audio synchronisation with new timestamp sync code
Date: Thu, 25 May 2000 16:53:03 +0200
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>

diff -Naur smpeg/MPEG.cpp smpeg.patched/MPEG.cpp
--- smpeg/MPEG.cpp	Thu May 18 02:45:45 2000
+++ smpeg.patched/MPEG.cpp	Thu May 25 14:45:34 2000
@@ -316,23 +316,30 @@
 
 void MPEG::Seek(int position)
 {
-  int were_playing = 0;
+  int was_playing = 0;
 
   /* Cannot seek past end of file */
   if(position > TotalSize()) return;
   
   /* get info whrether we need to restart playing at the end */
   if( Status() == MPEG_PLAYING )
-    were_playing = 1;
+    was_playing = 1;
 
-  seekIntoStream(position);
+  if(!seekIntoStream(position)) return;
 
   /* If we were playing and not rewind then play again */
-  if (were_playing)
+  if (was_playing)
     Play();
+
+  if ( pause && VideoEnabled() ) {
+    videoaction->Pause();
+  }
+  if ( pause && AudioEnabled() ) {
+    audioaction->Pause();
+  }
 }
 
-void MPEG::seekIntoStream(int position)
+bool MPEG::seekIntoStream(int position)
 {
   double time;
 
@@ -340,7 +347,7 @@
   Stop();
 
   /* Go to the desired position into file */
-  time = system->Seek(position);
+  if((time = system->Seek(position)) < 0) return(false);
 
   /* Skip the first empty buffer made when creating a mpegstream */
   /* which would otherwise be interpreted as end of file */
@@ -349,16 +356,16 @@
   if(videostream) videostream->next_packet();
 
   /* And forget what we previouly buffered */
-
-  if ( AudioEnabled() ) {
+  if ( audioaction ) {
     audioaction->Rewind();
     audioaction->ResetSynchro(time);
   }
-
-  if ( VideoEnabled() ) {
+  if ( videoaction ) {
     videoaction->Rewind();
     videoaction->ResetSynchro(time);
   }
+
+  return(true);
 }
 
 Uint32 MPEG::Tell()
diff -Naur smpeg/MPEG.h smpeg.patched/MPEG.h
--- smpeg/MPEG.h	Thu May 18 02:45:45 2000
+++ smpeg.patched/MPEG.h	Thu May 25 14:45:34 2000
@@ -116,7 +116,7 @@
     bool pause;
 
     void parse_stream_list();
-    void seekIntoStream(int position);
+    bool seekIntoStream(int position);
 };
 
 #endif /* _MPEG_H_ */
diff -Naur smpeg/MPEGaudio.h smpeg.patched/MPEGaudio.h
--- smpeg/MPEGaudio.h	Thu May 18 02:45:45 2000
+++ smpeg.patched/MPEGaudio.h	Thu May 25 14:45:34 2000
@@ -355,6 +355,14 @@
         rawdata=NULL;
   }
   void putraw(short int pcm) {rawdata[rawdatawriteoffset++]=pcm;}
+
+  /********************/
+  /* Timestamp sync   */
+  /********************/
+public:
+#define N_TIMESTAMPS 5
+
+  double timestamp[N_TIMESTAMPS];
 };
 
 #endif /* _MPEGAUDIO_H_ */
diff -Naur smpeg/MPEGring.cpp smpeg.patched/MPEGring.cpp
--- smpeg/MPEGring.cpp	Thu May 18 02:45:45 2000
+++ smpeg.patched/MPEGring.cpp	Thu May 25 14:45:34 2000
@@ -85,15 +85,11 @@
         while ( SDL_SemValue(ring->readwait) == 0 ) {
             SDL_SemPost(ring->readwait);
         }
-        SDL_DestroySemaphore( ring->readwait );
-        ring->readwait = 0;
     }
     if ( ring->writewait ) {
         while ( SDL_SemValue(ring->writewait) == 0 ) {
             SDL_SemPost(ring->writewait);
         }
-        SDL_DestroySemaphore( ring->writewait );
-        ring->writewait = 0;
     }
 }
 
@@ -105,6 +101,18 @@
         /* Free up the semaphores */
         ReleaseThreads();
 
+	/* Destroy the semaphores */
+	if( ring->readwait )
+	{
+	    SDL_DestroySemaphore( ring->readwait );
+	    ring->readwait = 0;
+	}
+	if( ring->writewait )
+	{
+	    SDL_DestroySemaphore( ring->writewait );
+	    ring->writewait = 0;
+	}
+
         /* Free data buffer */
         if ( ring->begin ) {
             free( ring->begin );
@@ -127,9 +135,9 @@
 
     buffer = 0;
     if ( ring->active ) {
-//printf("Waiting for write buffer (%d available)\n", SDL_SemValue(ring->writewait));
+	//printf("Waiting for write buffer (%d available)\n", SDL_SemValue(ring->writewait));
         SDL_SemWait(ring->writewait);
-//printf("Finished waiting for write buffer\n");
+	//printf("Finished waiting for write buffer\n");
 	if ( ring->active ) {
             buffer = ring->write + sizeof(Uint32);
         }
diff -Naur smpeg/MPEGstream.cpp smpeg.patched/MPEGstream.cpp
--- smpeg/MPEGstream.cpp	Thu May 18 02:45:45 2000
+++ smpeg.patched/MPEGstream.cpp	Thu May 25 14:45:34 2000
@@ -79,6 +79,7 @@
   br = new MPEGlist();
   data = 0;
   stop = 0;
+  pos = 0;
   looping = false;
   preread_size = 0;
   SDL_mutexV(mutex);
@@ -226,8 +227,11 @@
 void
 MPEGstream:: delete_marker(MPEGstream_marker *marker)
 {
-    marker->marked_buffer->Unlock();
-    delete marker;
+    if( marker && marker->marked_buffer)
+    {
+      marker->marked_buffer->Unlock();
+      delete marker;
+    }
 }
 
 Uint32
diff -Naur smpeg/MPEGstream.h smpeg.patched/MPEGstream.h
--- smpeg/MPEGstream.h	Thu May 18 02:45:45 2000
+++ smpeg.patched/MPEGstream.h	Thu May 25 14:45:34 2000
@@ -88,6 +88,8 @@
     /* Enable or disable the stream */
     void enable(bool toggle);
 
+    Uint32 pos;
+
     Uint8 streamid;
 
 protected:
@@ -103,9 +105,6 @@
 
     SDL_mutex * mutex;
 public:
-    /* total of bytes read by our client, it doesn't realy have to be
-       too meaningful, it only serves as a reference for timestamp_pos */
-    Uint32 pos;
     /* "pos" where "timestamp" belongs */
     Uint32 timestamp_pos;
     double timestamp;
diff -Naur smpeg/MPEGsystem.cpp smpeg.patched/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Thu May 18 02:45:45 2000
+++ smpeg.patched/MPEGsystem.cpp	Thu May 25 14:45:34 2000
@@ -28,8 +28,8 @@
 Uint8 const VIDEOSTREAM_MASK[]  = { 0xff, 0xff, 0xff, 0xe0 };
 Uint8 const AUDIOSTREAM_CODE[]  = { 0x00, 0x00, 0x01, 0xc0 };
 Uint8 const AUDIOSTREAM_MASK[]  = { 0xff, 0xff, 0xff, 0xc0 };
-Uint8 const PADSTREAM_CODE[]    = { 0x00, 0x00, 0x01, 0xbe };
-Uint8 const PADSTREAM_MASK[]    = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const PAD_CODE[]          = { 0x00, 0x00, 0x01, 0xbe };
+Uint8 const PAD_MASK[]          = { 0xff, 0xff, 0xff, 0xff };
 Uint8 const SYSTEMSTREAM_CODE[] = { 0x00, 0x00, 0x01, 0xbb };
 Uint8 const SYSTEMSTREAM_MASK[] = { 0xff, 0xff, 0xff, 0xff };
 Uint8 const GOP_CODE[]          = { 0x00, 0x00, 0x01, 0xb8 };
@@ -37,7 +37,11 @@
 Uint8 const USER_CODE[]         = { 0x00, 0x00, 0x01, 0xb2 };
 Uint8 const USER_MASK[]         = { 0xff, 0xff, 0xff, 0xff };
 Uint8 const PICTURE_CODE[]      = { 0x00, 0x00, 0x01, 0x00 };
-Uint8 const PICTURE_MASK[]      = { 0xff, 0xff, 0xff, 0x00 };
+Uint8 const PICTURE_MASK[]      = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const SLICE_CODE[]        = { 0x00, 0x00, 0x01, 0x01 };
+Uint8 const SLICE_MASK[]        = { 0xff, 0xff, 0xff, 0x00 };
+Uint8 const ZERO_CODE[]         = { 0x00, 0x00, 0x00, 0x00 };
+Uint8 const FULL_MASK[]         = { 0xff, 0xff, 0xff, 0xff };
 
 /* The size is arbitrary but should be sufficient to contain */
 /* two MPEG packets and reduce disk (or network) access.     */
@@ -71,6 +75,24 @@
                 (((x)&0xFF000000)>>24))
 #define MATCH4(x, y, m) (((x) & REV(m)) == REV(y))
 */
+const int audio_frequencies[2][3]=
+{
+  {44100,48000,32000}, // MPEG 1
+  {22050,24000,16000}  // MPEG 2
+};
+
+const int audio_bitrate[2][3][15]=
+{
+  // MPEG 1
+  {{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448},
+   {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384},
+   {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320}},
+
+  // MPEG 2
+  {{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256},
+   {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},
+   {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}}
+};
 
 /* Match two 4-byte codes */
 static inline bool Match4(Uint8 const code1[4], Uint8 const code2[4], Uint8 const mask[4])
@@ -80,6 +102,137 @@
 	  ((code1[2] & mask[2]) == (code2[2] & mask[2])) &&
 	  ((code1[3] & mask[3]) == (code2[3] & mask[3])) );
 }
+
+/* Return true if there is a valid audio header at the beginning of pointer */
+static inline Uint32 audio_header(Uint8 * pointer, Uint32 * framesize, double * frametime)
+{
+  Uint32 layer, version, frequency, bitrate, mode, padding, size;
+
+  if(((pointer[0] & 0xff) != 0xff) || // No sync bits
+     ((pointer[1] & 0xf0) != 0xf0) || //
+     ((pointer[2] & 0xf0) == 0x00) || // Bitrate is 0
+     ((pointer[2] & 0xf0) == 0xf0) || // Bitrate is 15
+     ((pointer[2] & 0x0c) == 0x0c) || // Frequency is 3
+     ((pointer[1] & 0x06) == 0x00))   // Layer is 4
+     return(0);
+
+  layer = 4 - (((pointer)[1] >> 1) & 3);
+  version = (((pointer)[1] >> 3) & 1) ^ 1;
+  padding = ((pointer)[2] >> 1) & 1;
+  frequency = audio_frequencies[version][(((pointer)[2] >> 2) & 3)];
+  bitrate = audio_bitrate[version][layer-1][(((pointer)[2] >> 4) & 15)];
+  mode = ((pointer)[3] >> 6) & 3;
+
+  if(layer==1)
+  {
+      size = 12000 * bitrate / frequency;
+      if(frequency==0 && padding) size++;
+      size <<= 2;
+  }
+  else
+  {
+      size = 144000 * bitrate / (frequency<<version);
+      if(padding) size++;
+  }
+  if(framesize) *framesize = size;
+  if(frametime) *frametime = 8.0 * size / (1000. * bitrate);
+  
+  return(4); /* Audio header size */
+}
+
+/* Search the next valid audio header */
+static inline bool audio_aligned(Uint8 *pointer, Uint32 size)
+{
+    Uint32 i, s;
+
+    /* Check on all data available that next headers are aligned too */
+    for(i = 0; i + 3 < size && audio_header(pointer+i, &s, 0); i+=s);
+
+    if(i + 3 < size)
+	return(false);
+    else
+	return(true);
+}
+
+/* Return true if there is a valid sequence header at the beginning of pointer */
+static inline Uint32 sequence_header(Uint8 * pointer, Uint32 size, double * _frametime)
+{
+  double frametime;
+  Uint32 header_size;
+
+  header_size = 0;
+  if((header_size+=4) >= size) return(header_size);
+  if(!Match4(pointer, VIDEO_CODE, VIDEO_MASK)) 
+    return(0); /* Not a sequence start code */
+  
+  /* Parse the sequence header information */
+  if((header_size+=8) >= size) return(header_size);
+  switch(pointer[7]&0xF)                /*  4 bits of fps */
+  {
+    case 1: frametime = 1/23.97; break;
+    case 2: frametime = 1/24.00; break;
+    case 3: frametime = 1/25.00; break;
+    case 4: frametime = 1/29.97; break;
+    case 5: frametime = 1/30.00; break;
+    case 6: frametime = 1/50.00; break;
+    case 7: frametime = 1/59.94; break;
+    case 8: frametime = 1/60.00; break;
+    case 9: frametime = 1/15.00; break;
+    default: frametime = 1/30.00; break;
+  }
+
+  if(_frametime) *_frametime = frametime;
+  
+  return(header_size); /* sequence header size */
+}
+
+/* Return true if there is a valid gop header at the beginning of pointer */
+static inline Uint32 gop_header(Uint8 * pointer, Uint32 size)
+{
+  Uint32 header_size;
+
+  header_size = 0;
+  if((header_size+=4) >= size) return(header_size);
+  if(!Match4(pointer, GOP_CODE, GOP_MASK)) 
+    return(0); /* Not a gop start code */
+  
+  /* Parse the gop header information */
+  if((header_size+=4) >= size) return(header_size);
+  
+  return(header_size); /* gop header size */
+}
+
+/* Return true if there is a valid picture header at the beginning of pointer */
+static inline Uint32 picture_header(Uint8 * pointer, Uint32 size)
+{
+  Uint32 header_size;
+
+  header_size = 0;
+  if((header_size+=4) >= size) return(header_size);
+
+  if(!Match4(pointer, PICTURE_CODE, PICTURE_MASK)) 
+    return(0); /* Not a picture start code */
+  
+  /* Parse the picture header information */
+  if((header_size+=4) >= size) return(header_size);
+  
+  return(header_size); /* picture header size */
+}
+
+/* Return true if there is a valid slice header at the beginning of pointer */
+static inline Uint32 slice_header(Uint8 * pointer, Uint32 size)
+{
+  Uint32 header_size;
+
+  header_size = 0;
+  if((header_size+=4) >= size) return(header_size);
+  if(!(Match4(pointer, SLICE_CODE, SLICE_MASK) && 
+       pointer[3] >= 0x01 && pointer[3] <= 0xaf)) 
+    return(0); /* Not a slice start code */
+  
+  return(header_size); /* slice header size */
+}
+
 static inline double read_time_code(Uint8 *pointer)
 { 
   double timestamp;
@@ -97,6 +250,126 @@
   return timestamp;
 }
 
+/* Return true if there is a valid packet header at the beginning of pointer */
+static inline Uint32 packet_header(Uint8 * pointer, Uint32 size, double * _timestamp)
+{
+  double timestamp;
+  Uint32 header_size;
+
+  header_size = 0;
+  if((header_size+=4) >= size) return(header_size);
+  if(!Match4(pointer, PACKET_CODE, PACKET_MASK)) 
+    return(0); /* Not a packet start code */
+
+  /* Parse the packet information */
+  if((header_size+=8) >= size) return(header_size);
+  timestamp = read_time_code(pointer+4);
+
+  if(_timestamp) *_timestamp = timestamp;
+  
+  return(header_size); /* packet header size */
+}
+
+/* Return true if there is a valid stream header at the beginning of pointer */
+static inline Uint32 stream_header(Uint8 * pointer, Uint32 size, Uint32 * _packet_size, Uint8 * _stream_id, double * _stream_timestamp)
+{
+  Uint32 header_size, packet_size;
+  Uint8 stream_id;
+  double stream_timestamp;
+
+  header_size = 0;
+  if((header_size += 4) >= size) return(header_size); 
+
+  if(!Match4(pointer, SYSTEMSTREAM_CODE, SYSTEMSTREAM_MASK) &&
+     !Match4(pointer, AUDIOSTREAM_CODE, AUDIOSTREAM_MASK) &&
+     !Match4(pointer, VIDEOSTREAM_CODE, VIDEOSTREAM_MASK))
+    return(0); /* Unknown encapsulated stream */
+
+  /* Parse the stream packet */
+  /* Get the stream id, and packet length */
+  stream_id = pointer[3];
+
+  pointer += 4;
+  if((header_size += 2) >= size) return(header_size); 
+  packet_size = (((unsigned short) pointer[0] << 8) | pointer[1]);
+  pointer += 2;
+
+  /* Skip stuffing bytes */
+  while ( pointer[0] == 0xff ) {
+      ++pointer;
+      if((++header_size) >= size) return(header_size); 
+      --packet_size;
+  }
+  if ( (pointer[0] & 0x40) == 0x40 ) {
+      pointer += 2;
+      if((header_size += 2) >= size) return(header_size); 
+      packet_size -= 2;
+  }
+  if ( (pointer[0] & 0x20) == 0x20 ) {
+      /* get the PTS */
+      stream_timestamp = read_time_code(pointer);
+      /* we don't care about DTS */
+      if ( (pointer[0] & 0x30) == 0x30 ){
+	pointer += 5;
+	if((header_size += 5) >= size) return(header_size); 
+	packet_size -= 5;
+      }
+      pointer += 4;
+      if((header_size += 4) >= size) return(header_size); 
+      packet_size -= 4;
+  }
+  else if ( pointer[0] != 0x0f && pointer[0] != 0x80)
+      return(0);      /* not a valid header */
+  else
+      stream_timestamp = -1;
+    
+  if((++header_size) >= size) return(header_size); 
+  --packet_size;
+
+  if(_packet_size) *_packet_size = packet_size;
+  if(_stream_id) *_stream_id = stream_id;
+  if(_stream_timestamp) *_stream_timestamp = stream_timestamp;
+  
+  return(header_size);
+}
+
+/* Search the next valid audio header */
+static inline bool system_aligned(Uint8 *pointer, Uint32 size)
+{
+    Uint32 i, s;
+
+    /* Check that packet contains at least one stream */
+    i = 0;
+    while((s = packet_header(pointer+i, size-i, 0)) != 0)
+      if((i+=s) >= size) return(true);
+
+    if((s = stream_header(pointer+i, size-i, 0, 0, 0)) != 0)
+      return(true);
+    else
+      return(false);
+}
+
+/* Skip possible zeros at the beggining of the packet */
+Uint32 skip_zeros(Uint8 * pointer, Uint32 size)
+{
+  Uint32 header_size;
+  Uint8 const one[4]  = {0x00,0x00,0x00,0x01};
+
+  header_size = 0;
+  while(Match4(pointer, ZERO_CODE, FULL_MASK))
+  {
+    pointer++;
+    if((++header_size) >= size - 4) return(header_size); 
+
+    if(Match4(pointer, one, FULL_MASK))
+    {
+      pointer++;
+      if((++header_size) >= size - 4) return(header_size); 
+    }
+  }
+  return(header_size);
+}
+
 MPEGsystem::MPEGsystem(int Mpeg_FD)
 {
   mpeg_fd = Mpeg_FD;
@@ -111,6 +384,8 @@
   packet_total = 0;
   endofstream = errorstream = false;
   looping = false;
+  frametime = 0.0;
+  stream_timestamp = 0.0;
 
   /* Create an empty stream list */
   stream_list = 
@@ -121,14 +396,13 @@
   if(!get_stream(SYSTEM_STREAMID))
     add_stream(new MPEGstream(this, SYSTEM_STREAMID));
 
-#ifdef USE_SYSTEM_TIMESTAMP
   timestamp = 0.0;
   timedrift = 0.0;
   skip_timestamp = -1;
-#endif
+  start_timestamp = -1;
 
-  /* Search the MPEG for the first header */
-  if(!seek_next_header())
+  /* Search the MPEG for the next header */
+  if(!seek_first_header())
   {
     errorstream = true;
     SetError("Could not find the beginning of MPEG data\n");
@@ -258,10 +532,7 @@
 {
   Uint8 stream_id;
   Uint32 packet_size;
-  Uint8 const zero[4] = {0x00,0x00,0x00,0x00};
-  Uint8 const one[4]  = {0x00,0x00,0x00,0x01};
-  Uint8 const mask[4] = {0xff,0xff,0xff,0xff};
-  double stream_timestamp;
+  Uint32 header_size;
 
   /* - Read a new packet - */
   Read();
@@ -269,88 +540,26 @@
   if(Eof()) 
     return(0);
 
-  /* If there is only audio or video information give the packet */
-  /* without parsing it */
-  if(((stream_list[0]->streamid & 0xc0) == 0xc0) || /* audio only stream */
-     ((stream_list[0]->streamid & 0xe0) == 0xe0))   /* video only stream */
-  {
-    packet_size = read_buffer + read_size - pointer;
-
-    /* Insert the new data at the end of the stream */
-    stream_list[0]->insert_packet(pointer, packet_size);
-    pointer += packet_size;
-    return(stream_list[0]->streamid);
-  }
+  pointer += skip_zeros(pointer, read_buffer + read_size - pointer); 
 
-  /* Skip possible zeros at the beggining of the packet */
-  while(Match4(pointer, zero, mask))
+  if((header_size = packet_header(pointer, read_buffer + read_size - pointer, &timestamp)) != 0)
   {
-    pointer++;
-    Read();
-    if(Eof())
-      return(0);
-
-    if(Match4(pointer, one, mask))
-      pointer++;
+      pointer += header_size;
+      stream_list[0]->pos += header_size;
+      if(start_timestamp == -1) start_timestamp = timestamp;
+#ifdef DEBUG_SYSTEM
+      fprintf(stderr, "MPEG packet header time: %lf\n", timestamp);
+#endif
   }
 
-  /* Parse the packet header */
-  if(Match4(pointer, PACKET_CODE, PACKET_MASK))
+  if((header_size = stream_header(pointer, read_buffer + read_size - pointer, &packet_size, &stream_id, &stream_timestamp)) != 0)
   {
-    /* Parse the packet information */
-    pointer += 4;
-    timestamp = read_time_code(pointer);
-    pointer += 8;
-  }
-
-  /* Parse the stream packet */
-  if(Match4(pointer, SYSTEMSTREAM_CODE, SYSTEMSTREAM_MASK) ||
-     Match4(pointer, PADSTREAM_CODE, PADSTREAM_MASK) ||
-     Match4(pointer, AUDIOSTREAM_CODE, AUDIOSTREAM_MASK) ||
-     Match4(pointer, VIDEOSTREAM_CODE, VIDEOSTREAM_MASK))
-  {
-    /* Get the stream id, and packet length */
-    stream_id = pointer[3];
-    pointer += 4;
-    packet_size = (((unsigned short) pointer[0] << 8) | pointer[1]);
-    pointer += 2;
-
-    /* Skip stuffing bytes */
-    while ( pointer[0] == 0xff ) {
-      ++pointer;
-      --packet_size;
-    }
-    if ( (pointer[0] & 0x40) == 0x40 ) {
-      pointer += 2;
-      packet_size -= 2;
-    }
-    if ( (pointer[0] & 0x20) == 0x20 ) {
-      /* get the PTS */
-      stream_timestamp = read_time_code(pointer);
-      /* we don't care about DTS */
-      if ( (pointer[0] & 0x30) == 0x30 ){
-	pointer += 5;
-	packet_size -= 5;
-      }
-      pointer += 4;
-      packet_size -= 4;
-    } else if ( pointer[0] != 0x0f && pointer[0] != 0x80) {
-      /* Huh? there is something wrong, try to catch next header */
-      pointer++;
-      if(!seek_next_header())
-      	errorstream = true;
-      return(0);
-    } else
-      stream_timestamp = -1;
-    
-    ++pointer;
-    --packet_size;
-
-    if(read_buffer + read_size - pointer < 0)
-    {
-      errorstream = true;
-      return(0);
-    }
+      pointer += header_size;
+      stream_list[0]->pos += header_size;
+#ifdef DEBUG_SYSTEM
+      fprintf(stderr, "[%d] MPEG stream header [%d|%d] id: %d streamtime: %lf\n", read_total - read_size + (pointer - read_buffer),
+header_size, packet_size, stream_id, stream_timestamp);
+#endif
   }
   else
   if(Match4(pointer, END_CODE, END_MASK) ||
@@ -365,29 +574,85 @@
     stream_id = stream_list[0]->streamid;
 
     if(!stream_list[1])
-    {
+    { 
+      Uint8 * packet_end;
+
+      packet_size = 0;
+
       /* There is no system info in the stream */
 
       /* If we're still a system stream, morph to an audio */
       /* or video stream */
 
-      if(Match4(pointer, AUDIO_CODE, AUDIO_MASK) &&
-	 (pointer[2] & 0xf0) != 0xf0 &&
-	 (pointer[2] & 0xf0) != 0x00) /* Check for a valid mpeg audio header : bitrate != 0 */
+      /* Sequence header -> gives framerate */
+      while((header_size = sequence_header(pointer+packet_size, read_buffer + read_size - pointer - packet_size, &frametime)) != 0)
       {
-	stream_id = AUDIO_STREAMID;
+	stream_id = VIDEO_STREAMID;
 	stream_list[0]->streamid = stream_id;
+	packet_size += header_size;
+#ifdef DEBUG_SYSTEM
+	fprintf(stderr, "MPEG sequence header  frametime: %lf\n", frametime);
+#endif
       }
-      if(Match4(pointer, VIDEO_CODE, VIDEO_MASK))
+
+      /* GOP header */
+      while((header_size = gop_header(pointer+packet_size, read_buffer + read_size - pointer - packet_size)) != 0)
       {
-	stream_id = VIDEO_STREAMID;
-	stream_list[0]->streamid = stream_id;
+	packet_size += header_size; 
+#ifdef DEBUG_SYSTEM
+	fprintf(stderr, "MPEG gop header\n");
+#endif
+      }
+
+      /* Picture header */
+      while((header_size = picture_header(pointer+packet_size, read_buffer + read_size - pointer - packet_size)) != 0)
+      {
+	packet_size += header_size;    // Warning: header size not quite correct (can be not byte aligned)
+	stream_timestamp += frametime; // but this is compensated by skipping a little more, as we don't need to be header aligned	
+	packet_size += 4;              // after this, since we then check for the next header to know the slice size.
+#ifdef DEBUG_SYSTEM
+	fprintf(stderr, "MPEG picture header\n");
+#endif
+      }
+
+      /* Slice header */
+      while((header_size = slice_header(pointer+packet_size, read_buffer + read_size - pointer - packet_size)) != 0)
+      {
+	packet_size += header_size;    
+#ifdef DEBUG_SYSTEM
+	fprintf(stderr, "MPEG slice header\n");
+#endif
+      }
+
+      /* Audio frame */
+      if(audio_header(pointer+packet_size, &packet_size, &frametime))
+      {
+	  stream_id = AUDIO_STREAMID;
+	  stream_list[0]->streamid = stream_id;
+	  stream_timestamp += frametime;
+#ifdef DEBUG_SYSTEM
+	  fprintf(stderr, "MPEG audio header [%d] time: %lf @ %lf\n", packet_size, frametime, stream_timestamp);
+#endif
+      }
+      else
+      {
+	/* Check for next slice, picture, gop or sequence header */
+	for(; (packet_size <= read_buffer + read_size - pointer - 4) && 
+	      !(sequence_header(pointer+packet_size, read_buffer - pointer + read_size - packet_size, &frametime) ||
+		gop_header(pointer+packet_size, read_buffer - pointer + read_size - packet_size) ||
+		picture_header(pointer+packet_size, read_buffer - pointer + read_size - packet_size) ||
+		slice_header(pointer+packet_size, read_buffer - pointer + read_size - packet_size))
+	      ; packet_size++);
+	if(packet_size > read_buffer - pointer + read_size - 4)
+	{
+	  SetError("Could not find next video header\n");
+	  errorstream = true;
+	  return(0);
+	}
       }
 
       if(stream_id == SYSTEM_STREAMID)
 	stream_id = 0;
-
-      packet_size = read_buffer + read_size - pointer;
     }
     else
     {
@@ -398,9 +663,10 @@
 		pointer[1],
 		pointer[2],
 		pointer[3],
-		Tell() - read_size + (pointer - read_buffer));
+		read_total - read_size + (pointer - read_buffer));
 #endif
 	pointer++;
+	stream_list[0]->pos++;
 	seek_next_header();
 	return(0);
     }
@@ -420,6 +686,7 @@
               int(timestamp)/60, cur_seconds);
     }
     pointer += packet_size;
+    stream_list[0]->pos += packet_size;
     /* since we skip data, request more */
     RequestBuffer();
     return (1);
@@ -430,6 +697,7 @@
     case 0:
       /* Unknown stream, just get another packet */
       pointer += packet_size;
+      stream_list[0]->pos += packet_size;
     return(stream_id);
 
     case SYSTEM_STREAMID:
@@ -440,6 +708,7 @@
     
       /* Read the stream table */
       pointer += 5;
+      stream_list[0]->pos += 5;
 
       while (pointer[0] & 0x80 )
       {
@@ -450,6 +719,7 @@
 	  add_stream(new MPEGstream(this, pointer[1]));
 	}
 	pointer += 3;
+	stream_list[0]->pos += 3;
       }          
       /* Hack to detect video streams that are not advertised */
       if ( ! exist_stream(VIDEO_STREAMID, 0xF0) ) {
@@ -487,14 +757,24 @@
 	{
 	  /* No stream found for packet, skip it */
 	  pointer += packet_size;
+	  stream_list[0]->pos += packet_size;
 	  return(stream_id);
 	}
       }
 
       /* Insert the new data at the end of the stream */
-      stream->insert_packet(pointer, packet_size, stream_timestamp);
-      pointer += packet_size;
-    return(stream_id);
+      if(pointer + packet_size < read_buffer + read_size)
+      {
+	stream->insert_packet(pointer, packet_size, stream_timestamp);
+	pointer += packet_size;
+      }
+      else
+      {
+	stream->insert_packet(pointer, 0, stream_timestamp);
+	errorstream = true;
+	pointer = read_buffer + read_size;
+      }
+      return(stream_id);
   }
 }
 
@@ -507,23 +787,45 @@
  
 Uint32 MPEGsystem::Tell()
 {
-  /* Warning: 32 bits means that files > 4Go might return bad values */
-  return(read_total);
+  register int t;
+  register int i;
+
+  /* Sum all stream positions */
+  for(i = 0, t = 0; stream_list[i]; i++)
+    t += stream_list[i]->pos;
+
+  return(t);
 }
 
 Uint32 MPEGsystem::TotalSize()
 {
-#ifndef WIN32
-    struct stat st;
-    Uint32 size;
+  Uint32 size;
+  Uint32 pos;
 
-    if(!fstat(mpeg_fd, &st))
-      return(st.st_size);
-    else
-      return(0);
-#else
-#error "Not implemented"
-#endif
+  /* I made it this way (instead of fstat) to avoid #ifdef WIN32 everywhere */
+  /* in case 'in some weird perversion of nature' someone wants to port this to Win32 :-) */
+ if((pos = lseek(mpeg_fd, 0, SEEK_CUR)) == (off_t) -1)
+  {
+    errorstream = true;
+    SetError(strerror(errno));
+    return(0);
+  }
+
+ if((size = lseek(mpeg_fd, 0, SEEK_END)) == (off_t) -1)
+  {
+    errorstream = true;
+    SetError(strerror(errno));  
+    return(0);
+  }
+  
+ if((pos = lseek(mpeg_fd, pos, SEEK_SET)) == (off_t) -1)
+  {
+    errorstream = true;
+    SetError(strerror(errno));  
+    return(0);
+  }
+
+  return(size);
 }
 
 void MPEGsystem::Rewind()
@@ -556,19 +858,24 @@
   /* Reinitialize the read buffer */
   pointer = read_buffer;
   read_size = 0;
-  read_total = 0;
+  read_total = length;
+  stream_list[0]->pos += length;
   packet_total = 0;
   endofstream = false;
   errorstream = false;
+  timestamp = 0.0;
+  start_timestamp = -1;
+  skip_timestamp = -1;
 
   /* Get the first header */
-  if(!seek_next_header())
+  if(!seek_first_header())
   {
-    errorstream = true;
-    SetError("Could not find the beginning of MPEG data\n");
-    return (-1);
+    if(!Eof())
+    {
+      errorstream = true;
+      SetError("Could not find the beginning of MPEG data\n");
+    }
   }
-
   request = PRE_BUFFERED_MAX;
 
   /* Start the system thread */
@@ -580,12 +887,16 @@
 
   /* Wait for prebuffering */
   while(request > 0 && !Eof())
+  {
+    if(timestamp > 0 && start_timestamp < 0)
+      start_timestamp = timestamp;
+
     SDL_Delay(1);
+  }
 
-  /* Get current play time */
-  FillBuffer();
+  if(start_timestamp < 0) start_timestamp = 0.0;
 
-  return(timestamp);
+  return(start_timestamp);
 }
 
 void MPEGsystem::Loop(bool toggle)
@@ -646,7 +957,7 @@
       system->errorstream = false;
 
       /* Get the first header */
-      if(!system->seek_next_header())
+      if(!system->seek_first_header())
       {
 	system->errorstream = true;
 	system->SetError("Could not find the beginning of MPEG data\n");
@@ -745,32 +1056,52 @@
     stream_list[i]->loop(toggle);
 }
 
-bool MPEGsystem::seek_next_header()
+bool MPEGsystem::seek_first_header()
 {
   Read();
 
   if(Eof())
     return(false);
 
-  while(!(Match4(pointer, PACKET_CODE, PACKET_MASK) ||
-	  Match4(pointer, VIDEO_CODE, VIDEO_MASK) ||
-	  (Match4(pointer, AUDIO_CODE, AUDIO_MASK) &&
-	   /* Check for a valid mpeg audio header : bitrate != 0 */ 
-	   ((pointer[2] & 0xf0) != 0xf0) && ((pointer[2] & 0xf0) != 0)) ||
-	  Match4(pointer, END_CODE, END_MASK) ||
-	  Match4(pointer, VIDEOSTREAM_CODE, VIDEOSTREAM_MASK) ||
-	  Match4(pointer, AUDIOSTREAM_CODE, AUDIOSTREAM_MASK) ||
-	  Match4(pointer, GOP_CODE, GOP_MASK) ||
-	  Match4(pointer, USER_CODE, USER_MASK) ||
-	  Match4(pointer, PICTURE_CODE, PICTURE_MASK)))
+  while(!(audio_aligned(pointer, read_buffer + read_size - pointer) ||
+	  system_aligned(pointer, read_buffer + read_size - pointer) ||
+ 	  Match4(pointer, VIDEO_CODE, VIDEO_MASK)))
   {
        ++pointer;
+       stream_list[0]->pos++;
+      /* Make sure buffer is always full */
+      Read();
 
+      if(Eof())
+	return(false);
+  }
+  return(true);
+}
+
+bool MPEGsystem::seek_next_header()
+{
+  Read();
+
+  if(Eof())
+    return(false);
+
+  while(!( ((stream_list[0]->streamid == AUDIO_STREAMID) && audio_aligned(pointer, read_buffer + read_size - pointer)) ||
+	   ((stream_list[0]->streamid == SYSTEM_STREAMID) && system_aligned(pointer, read_buffer + read_size - pointer)) ||
+	   ((stream_list[0]->streamid == VIDEO_STREAMID) && (
+							     Match4(pointer, VIDEO_CODE, VIDEO_MASK) ||
+							     Match4(pointer, END_CODE, END_MASK) ||
+							     Match4(pointer, GOP_CODE, GOP_MASK) ||
+							     Match4(pointer, PICTURE_CODE, PICTURE_MASK)))
+	) )
+  {
+       ++pointer;
+       stream_list[0]->pos++;
       /* Make sure buffer is always full */
       Read();
 
       if(Eof())
 	return(false);
   }
+
   return(true);
 }
diff -Naur smpeg/MPEGsystem.h smpeg.patched/MPEGsystem.h
--- smpeg/MPEGsystem.h	Thu May 18 02:45:45 2000
+++ smpeg.patched/MPEGsystem.h	Thu May 25 14:45:34 2000
@@ -55,6 +55,9 @@
     /* Set looping for all streams */
     void loop_all_streams(bool toggle);
 
+    /* Seek the first header */
+    bool seek_first_header();
+
     /* Seek the next header */
     bool seek_next_header();
 
@@ -86,8 +89,12 @@
     bool errorstream;
     bool looping;
 
+    double frametime;
+    double stream_timestamp;
+
 #ifdef USE_SYSTEM_TIMESTAMP
     /* Current timestamp for this stream */
+    double start_timestamp;
     double timestamp;
     double timedrift;
     double skip_timestamp;
diff -Naur smpeg/MPEGvideo.h smpeg.patched/MPEGvideo.h
--- smpeg/MPEGvideo.h	Thu May 18 02:45:45 2000
+++ smpeg.patched/MPEGvideo.h	Thu May 25 15:52:15 2000
@@ -85,7 +85,6 @@
 
     MPEG_DisplayCallback _callback;
 
-    int _scale;         // play back at '_scale' size
     int _w;             // width of movie
     int _h;             // height of movie
     SDL_Rect _rect;	// display area
diff -Naur smpeg/audio/MPEGaudio.cpp smpeg.patched/audio/MPEGaudio.cpp
--- smpeg/audio/MPEGaudio.cpp	Thu May 18 02:45:45 2000
+++ smpeg.patched/audio/MPEGaudio.cpp	Thu May 25 14:45:34 2000
@@ -66,6 +66,10 @@
         }
         Volume(100);
     }
+
+    /* For using system timestamp */
+    for (int i=0; i<N_TIMESTAMPS; i++)
+      timestamp[i] = -1;
 }
 
 MPEGaudio:: ~MPEGaudio()
@@ -198,6 +202,7 @@
 MPEGaudio:: Rewind(void)
 {
     Stop();
+
 #ifdef THREADED_AUDIO
     /* Stop the decode thread */
     StopDecoding();
@@ -207,12 +212,16 @@
     decodedframe = 0;
     currentframe = 0;
     frags_playing = 0;
-    frag_time = 0;
 }
 void
 MPEGaudio:: ResetSynchro(double time)
 {
     play_time = time;
+    frag_time = 0;
+
+    /* Reinit the timestamp FIFO */
+    for (int i=0; i<N_TIMESTAMPS; i++)
+      timestamp[i] = -1;
 }
 void
 MPEGaudio:: Skip(float seconds)
diff -Naur smpeg/audio/mpegtoraw.cpp smpeg.patched/audio/mpegtoraw.cpp
--- smpeg/audio/mpegtoraw.cpp	Thu May 18 02:45:45 2000
+++ smpeg.patched/audio/mpegtoraw.cpp	Thu May 25 14:45:34 2000
@@ -19,7 +19,6 @@
 
 #define MY_PI 3.14159265358979323846
 
-
 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
 #define _KEY 0
 #else
@@ -319,12 +318,14 @@
 
     while ( audio->decoding && ! audio->mpeg->eof() ) {
         audio->rawdata = (Sint16 *)audio->ring->NextWriteBuffer();
+
         if ( audio->rawdata ) {
             audio->rawdatawriteoffset = 0;
             audio->run(1, &timestamp);
             audio->ring->WriteDone(audio->rawdatawriteoffset*2, timestamp);
         }
     }
+
     audio->decoding = false;
     audio->decode_thread = NULL;
     return(0);
@@ -378,19 +379,14 @@
 	   the timestamps refer to the time when the frame starts
 	   playing or then the frame ends playing, but as is works
 	   quite right */
-#define N_TIMESTAMPS 5
-	static double timestamp[N_TIMESTAMPS] = {0};
-	if(timestamp[0] == 0)
-	    for (int i=0; i<N_TIMESTAMPS; i++)
-		timestamp[i] = -1;
         copylen = audio->ring->NextReadBuffer(&rbuf);
         if ( copylen > len ) {
             SDL_MixAudio(stream, rbuf, len, volume);
             audio->ring->ReadSome(len);
             len = 0;
 	    for (int i=0; i < N_TIMESTAMPS -1; i++)
-		timestamp[i] = timestamp[i+1];
-	    timestamp[N_TIMESTAMPS-1] = audio->ring->ReadTimeStamp();
+		audio->timestamp[i] = audio->timestamp[i+1];
+	    audio->timestamp[N_TIMESTAMPS-1] = audio->ring->ReadTimeStamp();
         } else {
             SDL_MixAudio(stream, rbuf, copylen, volume);
             ++audio->currentframe;
@@ -399,10 +395,10 @@
             len -= copylen;
             stream += copylen;
         }
-	if (timestamp[0] != -1){
-	    double timeshift = audio->Time() - timestamp[0];
+	if (audio->timestamp[0] != -1){
+	    double timeshift = audio->Time() - audio->timestamp[0];
 	    double correction = 0;
-	    assert(timestamp >= 0);
+	    assert(audio->timestamp >= 0);
 	    if (fabs(timeshift) > 1.0){
 	        correction = -timeshift;
 #ifdef DEBUG_TIMESTAMP_SYNC
@@ -417,7 +413,7 @@
 	    fprintf(stderr, "\raudio: time:%8.3f shift:%8.4f",
                     audio->Time(), timeshift);
 #endif
-	    timestamp[0] = -1;
+	    audio->timestamp[0] = -1;
 	}
     } while ( copylen && (len > 0) && ((audio->currentframe < audio->decodedframe) || audio->decoding));
 #else
diff -Naur smpeg/configure.in smpeg.patched/configure.in
--- smpeg/configure.in	Thu May 18 02:45:45 2000
+++ smpeg.patched/configure.in	Thu May 25 14:45:34 2000
@@ -98,7 +98,7 @@
 dnl Check for system timestamp sync
 AC_ARG_ENABLE(timestamp-sync,
 [  --enable-timestamp-sync  enable system timestamp sync [default=yes]],
-              , enable_timestamp_sync=yes)
+              , enable_timestamp_sync=no)
 if test x$enable_timestamp_sync = xyes; then
 	CFLAGS="$CFLAGS -DUSE_TIMESTAMP_SYNC"
 fi
diff -Naur smpeg/gtv.c smpeg.patched/gtv.c
--- smpeg/gtv.c	Tue May 16 23:04:03 2000
+++ smpeg.patched/gtv.c	Thu May 25 14:45:34 2000
@@ -12,10 +12,13 @@
 
 #include "gtv.h"
 
+#define TIMER_TIMEOUT 100
+
 static GtkWidget* create_gtv_window( void );
 static void gtv_connect( gpointer, gchar*, gchar*, GtkSignalFunc );
 static void gtv_set_frame( gpointer, int );
 static void gtv_set_fps( gpointer, float );
+static void gtv_set_trackbar( gpointer, int );
 static void gtv_set_sensitive( gpointer, gchar*, gboolean );
 static void gtv_clear_screen( gpointer );
 static void gtv_fix_toggle_state( gpointer );
@@ -38,6 +41,8 @@
 static void gtv_to_end( GtkWidget*, gpointer );
 static void gtv_seek( GtkAdjustment*, gpointer );
 
+static int gtv_trackbar_dragging;
+
 static void gtv_fix_toggle_state( gpointer raw )
 {
     SMPEG* mpeg = NULL;
@@ -145,8 +150,6 @@
     gtk_widget_show( file_sel );
 }
 
-static float mpeg_size; /* FIXME: put this somewhere else */
-
 static void gtv_open_file( gchar* name, gpointer raw )
 {
     SMPEG_Info* info = NULL;
@@ -174,8 +177,6 @@
 	gtk_object_set_data( GTK_OBJECT( raw ), "mpeg", NULL );
 	return;
     }
-    /* Get the file size */
-    mpeg_size = (float)SMPEG_total_size(mpeg);
 
     gtk_object_set_data( GTK_OBJECT( raw ), "mpeg", mpeg );
     strncpy( (char*) gtk_object_get_data( GTK_OBJECT( raw ), "filename_buffer" ),
@@ -337,12 +338,14 @@
 
     /* Actually stuff some data in there. */
     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
-    g_snprintf( buffer, 1024, "Filename: %s\nStream: %s\nSize: %dx%d\n",
+    g_snprintf( buffer, 1024, "Filename: %s\nStream: %s\nVideo: %dx%d resolution\nAudio: %s\nSize: %d\n",
 		(gchar*) gtk_object_get_data( GTK_OBJECT( raw ), "filename_buffer" ),
 		( info->has_audio && info->has_video ) ? "system" :
 		( info->has_video ? "video" :
 		( info->has_audio ? "audio" : "not MPEG" ) ),
-		info->width, info->height );
+		info->width, info->height,
+		( info->has_audio ? info->audio_string : "none" ),
+		info->total_size );
     text = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( dialog ), "text" ) );
     gtk_editable_insert_text( GTK_EDITABLE( text ), buffer, strlen( buffer ), &ignored );
 
@@ -546,7 +549,7 @@
     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
 
     if( mpeg ) {
-	gtv_rewind( raw );
+      //	gtv_rewind( raw );
 	SMPEG_play( mpeg );
     }
 
@@ -569,14 +572,18 @@
 static void gtv_stop( GtkWidget* item, gpointer raw )
 {
     SMPEG* mpeg = NULL;
+    SMPEG_Info* info = NULL;
 
     assert( raw );
 
     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
+    info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
 
     if( mpeg ) {
 	SMPEG_stop( mpeg );
 	gtv_rewind( raw );
+	SMPEG_getinfo( mpeg, info );
+	gtv_set_trackbar( raw, info->current_offset );
     }
 
 }
@@ -655,16 +662,35 @@
 static void gtv_seek( GtkAdjustment* adjust, gpointer raw )
 {
     SMPEG* mpeg = NULL;
+    SMPEG_Info* info = NULL;
 
     assert( raw );
+    if(gtv_trackbar_dragging) return;
 
     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
+    info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
+
+    if( mpeg && info && info->total_size ) {
 
-    if( mpeg && mpeg_size ) {
-        SMPEG_seek(mpeg, (int)((mpeg_size*adjust->value)/100));
+      /* In case file is growing while we're playing */
+      SMPEG_getinfo( mpeg, info );
+      
+      SMPEG_seek(mpeg, (int)((info->total_size*adjust->value)/100));
+
+      gtv_step( NULL, raw );
     }
 }
 
+static void gtv_trackbar_drag_on(GtkWidget *widget, gpointer raw)
+{
+    gtv_trackbar_dragging = 1;
+}
+
+static void gtv_trackbar_drag_off(GtkWidget *widget, gpointer raw)
+{
+    gtv_trackbar_dragging = 0;
+}
+
 static void gtv_set_frame( gpointer raw, int value )
 {
     GtkWidget* frame = NULL;
@@ -691,6 +717,31 @@
     gtk_label_set_text( GTK_LABEL( fps ), buffer );
 }
 
+static void gtv_set_trackbar( gpointer raw, int value )
+{
+    SMPEG* mpeg = NULL;
+    SMPEG_Info* info = NULL;
+    GtkWidget* scale = NULL;
+    GtkAdjustment* seek = NULL;
+
+    assert( raw );
+    assert( value >= 0 );
+    if(gtv_trackbar_dragging) return;
+
+    mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
+    info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
+
+    if( mpeg && info && info->total_size ) {
+            scale = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "scale" ) );
+      seek  = gtk_range_get_adjustment ( GTK_RANGE( scale ) );
+      seek->value = 100. * value / info->total_size;
+      gtk_range_set_adjustment ( GTK_RANGE( scale ), seek );
+      gtk_range_slider_update ( GTK_RANGE( scale ) );
+      gtk_range_clear_background ( GTK_RANGE( scale ) );
+      gtk_range_draw_background ( GTK_RANGE( scale ) );
+    }
+}
+
 static gint gtv_timer( gpointer raw )
 {
     SMPEG* mpeg = NULL;
@@ -705,6 +756,7 @@
 	    SMPEG_getinfo( mpeg, info );
 	    gtv_set_frame( raw, info->current_frame );
 	    gtv_set_fps( raw, info->current_fps );
+	    gtv_set_trackbar( raw, info->current_offset );
 	}
 
     }
@@ -781,8 +833,11 @@
     gtv_connect( window, "audio", "toggled", GTK_SIGNAL_FUNC( gtv_audio ) );
     gtv_connect( window, "seek", "value_changed", GTK_SIGNAL_FUNC( gtv_seek ) );
 
+    gtv_connect( window, "scale", "button_press_event", GTK_SIGNAL_FUNC( gtv_trackbar_drag_on ) );
+    gtv_connect( window, "scale", "button_release_event", GTK_SIGNAL_FUNC( gtv_trackbar_drag_off ) );
+
     /*    gtk_idle_add_priority( G_PRIORITY_LOW, gtv_timer, window );*/
-    gtk_timeout_add( 1000, gtv_timer, window );
+    gtk_timeout_add( TIMER_TIMEOUT, gtv_timer, window );
 
     gtv_set_frame( window, 0 );
     gtv_set_fps( window, 0.0 );
@@ -962,6 +1017,10 @@
   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "seek", seek,
                             (GtkDestroyNotify) (0));
   scale = gtk_hscale_new(GTK_ADJUSTMENT(seek));
+  gtv_trackbar_dragging = 0;
+  gtk_widget_ref (scale);
+  gtk_object_set_data_full (GTK_OBJECT (gtv_window), "scale", scale,
+                            (GtkDestroyNotify) gtk_widget_unref);
   gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
   gtk_widget_show (scale);
   gtk_table_attach (GTK_TABLE (table1), scale, 0, 5, 3, 4,
diff -Naur smpeg/plaympeg.c smpeg.patched/plaympeg.c
--- smpeg/plaympeg.c	Thu May 18 02:45:45 2000
+++ smpeg.patched/plaympeg.c	Thu May 25 14:45:34 2000
@@ -309,9 +309,9 @@
         if ( info.has_audio ) {
 	    printf("\tAudio %s\n", info.audio_string);
         }
-
-	/* Print info on the stream */
-	printf("\t Total size: %d\n", SMPEG_total_size(mpeg));
+        if ( info.total_size ) {
+	    printf("\tSize: %d\n", info.total_size);
+        }
 
         /* Set up video display if needed */
         if ( info.has_video && use_video ) {
diff -Naur smpeg/smpeg.cpp smpeg.patched/smpeg.cpp
--- smpeg/smpeg.cpp	Thu May 18 02:45:45 2000
+++ smpeg.patched/smpeg.cpp	Thu May 25 14:45:34 2000
@@ -98,6 +98,16 @@
                 info->current_frame = vinfo.current_frame;
                 info->current_fps = vinfo.current_fps;
             }
+	    if(mpeg->obj->system != NULL)
+	    {
+		info->total_size = mpeg->obj->TotalSize();
+		info->current_offset = mpeg->obj->Tell();
+	    }
+	    else
+	    {
+		info->total_size = 0;
+		info->current_offset = 0;
+	    }
         }
     }
 }
@@ -211,20 +221,6 @@
 void SMPEG_seek( SMPEG* mpeg, int bytes )
 {
   mpeg->obj->Seek(bytes);
-}
-
-/* Tell the current position in the stream in bytes */
-/* Warning: this is 32 bit values so streams > 4Go will return bad values */
-Uint32 SMPEG_tell( SMPEG* mpeg )
-{
-  return(mpeg->obj->Tell());
-}
-
-/* Return the total size of the stream in bytes (O if unapplicable) */
-/* Warning: this is 32 bit values so streams > 4Go will return bad values */
-Uint32 SMPEG_total_size( SMPEG* mpeg )
-{
-  return(mpeg->obj->TotalSize());
 }
 
 /* Skip 'seconds' seconds of the MPEG */
diff -Naur smpeg/smpeg.h smpeg.patched/smpeg.h
--- smpeg/smpeg.h	Thu May 18 02:45:45 2000
+++ smpeg.patched/smpeg.h	Thu May 25 14:45:34 2000
@@ -63,6 +63,8 @@
     double current_fps;
     char audio_string[80];
     int  audio_current_frame;
+    Uint32 current_offset;
+    Uint32 total_size;
 } SMPEG_Info;
 
 /* Possible MPEG status codes */
@@ -144,14 +146,6 @@
 
 /* Seek 'bytes' bytes in the MPEG stream */
 void SMPEG_seek( SMPEG* mpeg, int bytes);
-
-/* Tell the current position in the stream in bytes */
-/* Warning: this is 32 bit values so streams > 4Go will return bad values */
-Uint32 SMPEG_tell( SMPEG* mpeg );
-
-/* Return the total size of the stream in bytes (O if unapplicable) */
-/* Warning: this is 32 bit values so streams > 4Go will return bad values */
-Uint32 SMPEG_total_size( SMPEG* mpeg );
 
 /* Skip 'seconds' seconds in the MPEG stream */
 void SMPEG_skip( SMPEG* mpeg, float seconds );
diff -Naur smpeg/video/MPEGvideo.cpp smpeg.patched/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Thu May 18 02:45:45 2000
+++ smpeg.patched/video/MPEGvideo.cpp	Thu May 25 15:55:12 2000
@@ -294,14 +294,13 @@
       }
       _stream->realTimeStart = 0.0;
     }
-    play_time = 0.0;
 }
 
 void
 MPEGvideo:: ResetSynchro(double time)
 {
   _stream->_jumpFrame = -1;
-  _stream->realTimeStart = 0.0;
+  _stream->realTimeStart = -time;
   play_time = time;
 }
 
@@ -516,14 +515,15 @@
     /* Create a temporary YUV surface and display the frame */
     yuv = SDL_CreateYUVOverlay(_w, _h, SDL_YV12_OVERLAY, dst);
     if ( yuv ) {
-        SDL_Rect dstrect;
         if ( SDL_LockYUVOverlay(yuv) == 0 ) {
+	  SDL_Rect dstrect;
+
             memcpy(yuv->pixels, _stream->current->image, (_w*_h)+2*(_w*_h)/4);
             SDL_UnlockYUVOverlay(yuv);
-            dstrect.x = x;
-            dstrect.y = x;
-            dstrect.w = _w*_scale;
-            dstrect.h = _h*_scale;
+            dstrect.x = _rect.x;
+            dstrect.y = _rect.y;
+            dstrect.w = _rect.w;
+            dstrect.h = _rect.h;
             SDL_DisplayYUVOverlay(yuv, &dstrect);
         }
         SDL_FreeYUVOverlay(yuv);
diff -Naur smpeg/video/gdith.cpp smpeg.patched/video/gdith.cpp
--- smpeg/video/gdith.cpp	Thu May 18 02:45:45 2000
+++ smpeg.patched/video/gdith.cpp	Thu May 25 14:45:34 2000
@@ -48,8 +48,6 @@
  * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
-
-
 #include <math.h>
 #include "video.h"
 #include "proto.h"
@@ -181,7 +179,13 @@
 	      mpeg->play_time - vid_stream->current->show_time);
 #endif
       if(correction == -1)
-	correction = mpeg->play_time - vid_stream->current->show_time;
+#ifdef STRANGE_SYNC_TEST
+       /* this forces us to maintain the offset we have at the begining
+          all the time, and is only usefull for testing */
+        correction = mpeg->play_time - vid_stream->current->show_time;
+#else
+       correction = 0;
+#endif
 #ifdef USE_TIMESTAMP_SYNC
       mpeg->play_time = vid_stream->current->show_time + correction ;
 #endif
diff -Naur smpeg/video/video.cpp smpeg.patched/video/video.cpp
--- smpeg/video/video.cpp	Thu May 18 02:45:45 2000
+++ smpeg.patched/video/video.cpp	Thu May 25 14:45:34 2000
@@ -1141,12 +1141,19 @@
 
 
     default:
+	/* No base picture for decoding */
+	if( !vid_stream->current )
+	{
+	    flush_bits32;
+	    next_start_code(vid_stream);
+	    goto done;
+	}
+
         /* Check for slice start code. */
 
         if( (data >= SLICE_MIN_START_CODE) && (data <= SLICE_MAX_START_CODE) )
         {
             /* Slice start code. Parse slice header. */
-
             if( ParseSlice(vid_stream) != PARSE_OK )
             {
                 fprintf( stderr, "mpegVidRsrc ParseSlice\n" );
*************************************************************************
*** Applied ***
Date: Thu, 18 May 2000 00:33:02 +0200
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
CC: Manuel Estrada <ranty@atdot.org>,
    Damien Chavarria <damien.chavarria@enst-bretagne.fr>,
    Scott Draeker <highlander@lokigames.com>
Subject: Re: Sim Wars MPEG not playing correctly


Sam Lantinga wrote:

> 2. Patch to provide the packet timesync.  If you could test this with
> various MPEG files, that would be great.  If it doesn't always work in
> its current form, can you make it an optional feature via conditional
> compile?

        I've just finished integrating Manuel's patch according to latest
CVS,
and made a configure option ('--enable-timestamp-sync') to
enable/disable sync correction using timestamps. This option does *not*
remove all the timestamping but only the synchronization correction.
This means that Skip(float seconds) is still compiled and will still
work.
        I've also moved all sync debugging information between #ifdef
DEBUG_TIMESTAMP_SYNC #endif statements.
Don't forget to autogen, as configure.in has been modified.

BTW, I spent some time searching why SMPEG was so slow after I did the
configure and make again, and it was the -O2 option missing... didn't
think that could change speed that much!
Why isn't it in the CFLAGS by default?

see ya,
Vivien.

diff -Naur smpeg/MPEG.cpp smpeg-all/MPEG.cpp
--- smpeg/MPEG.cpp	Tue May 16 23:26:06 2000
+++ smpeg-all/MPEG.cpp	Tue May 16 22:28:32 2000
@@ -101,9 +101,9 @@
 
 MPEG::~MPEG()
 {
-  if(audio) delete audio;
+  Stop();
   if(video) delete video;
-
+  if(audio) delete audio;
   if(system) delete system;
 
   if ( close_fd && mpeg_fd ) {
@@ -334,11 +334,13 @@
 
 void MPEG::seekIntoStream(int position)
 {
+  double time;
+
   /* First we stop everything */
   Stop();
 
   /* Go to the desired position into file */
-  system->Seek(position);
+  time = system->Seek(position);
 
   /* Skip the first empty buffer made when creating a mpegstream */
   /* which would otherwise be interpreted as end of file */
@@ -350,14 +352,13 @@
 
   if ( AudioEnabled() ) {
     audioaction->Rewind();
-    audioaction->ResetSynchro();
+    audioaction->ResetSynchro(time);
   }
 
   if ( VideoEnabled() ) {
     videoaction->Rewind();
-    videoaction->ResetSynchro();
+    videoaction->ResetSynchro(time);
   }
-
 }
 
 Uint32 MPEG::Tell()
@@ -368,6 +369,20 @@
 Uint32 MPEG::TotalSize()
 {
   return(system->TotalSize());
+}
+
+void MPEG::Skip(float seconds)
+{
+  if(system->get_stream(SYSTEM_STREAMID))
+  {
+    system->Skip(seconds);
+  }
+  else
+  {
+    /* No system information in MPEG */
+    if( VideoEnabled() ) videoaction->Skip(seconds);
+    if( AudioEnabled() ) audioaction->Skip(seconds);
+  }
 }
 
 void MPEG::parse_stream_list()
diff -Naur smpeg/MPEG.h smpeg-all/MPEG.h
--- smpeg/MPEG.h	Tue May 16 23:26:06 2000
+++ smpeg-all/MPEG.h	Tue May 16 22:31:11 2000
@@ -69,6 +69,7 @@
     void Rewind(void);
     void Pause(void);
     void Seek(int bytes);
+    void Skip(float seconds);
     Uint32 Tell();
     Uint32 TotalSize();
     MPEGstatus Status(void);
diff -Naur smpeg/MPEGaction.h smpeg-all/MPEGaction.h
--- smpeg/MPEGaction.h	Tue May 16 23:26:06 2000
+++ smpeg-all/MPEGaction.h	Wed May 17 00:04:29 2000
@@ -47,7 +47,8 @@
     virtual void Play(void) = 0;
     virtual void Stop(void) = 0;
     virtual void Rewind(void) = 0;
-    virtual void ResetSynchro(void) = 0;
+    virtual void ResetSynchro(double) = 0;
+    virtual void Skip(float seconds) = 0;
     virtual void Pause(void) {  /* A toggle action */
         if ( paused ) {
             paused = false;
diff -Naur smpeg/MPEGaudio.h smpeg-all/MPEGaudio.h
--- smpeg/MPEGaudio.h	Tue May 16 23:26:06 2000
+++ smpeg-all/MPEGaudio.h	Wed May 17 00:00:56 2000
@@ -167,7 +167,8 @@
     void Play(void);
     void Stop(void);
     void Rewind(void);
-    void ResetSynchro(void);
+    void ResetSynchro(double time);
+    void Skip(float seconds);
     void Volume(int vol);
     MPEGstatus Status(void);
 
@@ -246,7 +247,7 @@
   /*******************/
 public:
   void initialize();
-  bool run(int frames);
+  bool run(int frames, double *timestamp = NULL);
   void clearbuffer(void);
 
   /*****************************/
@@ -254,6 +255,7 @@
   /*****************************/
 private:
   Uint8 _buffer[4096];
+  Uint32 _buffer_pos;
   int  bitindex;
   bool fillbuffer(int size);
   void sync(void);
diff -Naur smpeg/MPEGlist.h smpeg-all/MPEGlist.h
--- smpeg/MPEGlist.h	Mon May 15 18:21:20 2000
+++ smpeg-all/MPEGlist.h	Tue May 16 22:35:27 2000
@@ -33,6 +33,8 @@
 
   inline Uint32 IsLocked() { return(lock); };
 
+  double TimeStamp;
+
 private:
   class MPEGlist * next;
   class MPEGlist * prev;
diff -Naur smpeg/MPEGring.cpp smpeg-all/MPEGring.cpp
--- smpeg/MPEGring.cpp	Mon May 15 18:21:20 2000
+++ smpeg-all/MPEGring.cpp	Tue May 16 22:42:21 2000
@@ -37,7 +37,10 @@
 
     tSize = (size + sizeof(Uint32)) * count;
     if( tSize )
+    {
         ring->begin = (Uint8 *) malloc( tSize );
+        ring->timestamps = (double *) malloc( sizeof(double)*count );
+    }
     else
         ring->begin = 0;
 
@@ -46,6 +49,8 @@
         ring->end   = ring->begin + tSize;
         ring->read  = ring->begin;
         ring->write = ring->begin;
+        ring->timestamp_read  = timestamps;
+        ring->timestamp_write = timestamps;
         ring->bufSize  = size;
         
         ring->readwait = SDL_CreateSemaphore(0);
@@ -103,7 +108,9 @@
         /* Free data buffer */
         if ( ring->begin ) {
             free( ring->begin );
+            free( ring->timestamps );
             ring->begin = 0;
+            ring->timestamps = 0;
         }
     }
 }
@@ -137,16 +144,18 @@
 */
 
 void
-MPEG_ring:: WriteDone( Uint32 len )
+MPEG_ring:: WriteDone( Uint32 len, double timestamp=-1 )
 {
     if ( ring->active ) {
         assert(len <= ring->bufSize);
         *((Uint32*) ring->write) = len;
 
         ring->write += ring->bufSize + sizeof(Uint32);
+        *(ring->timestamp_write++) = timestamp;
         if( ring->write >= ring->end )
         {
             ring->write = ring->begin;
+            ring->timestamp_write = ring->timestamps;
         }
 //printf("Finished write buffer, making available for reads (%d+1 available for reads)\n", SDL_SemValue(ring->readwait));
         SDL_SemPost(ring->readwait);
@@ -185,6 +194,12 @@
   is returned with the next call to MPRing_nextReadBuffer().
 */
 
+double
+MPEG_ring:: ReadTimeStamp(void)
+{
+    return *ring->timestamp_read;
+}
+
 void
 MPEG_ring:: ReadSome( Uint32 used )
 {
@@ -214,9 +229,11 @@
 {
     if ( ring->active ) {
         ring->read += ring->bufSize + sizeof(Uint32);
+        ring->timestamp_read++;
         if( ring->read >= ring->end )
         {
             ring->read = ring->begin;
+            ring->timestamp_read = ring->timestamps;
         }
 //printf("Finished read buffer, making available for writes (%d+1 available for writes)\n", SDL_SemValue(ring->writewait));
         SDL_SemPost(ring->writewait);
diff -Naur smpeg/MPEGring.h smpeg-all/MPEGring.h
--- smpeg/MPEGring.h	Mon May 15 18:21:20 2000
+++ smpeg-all/MPEGring.h	Tue May 16 22:43:43 2000
@@ -54,11 +54,14 @@
     Uint8 *NextWriteBuffer( void );
 
     /* Release a buffer, written to in the ring */
-    void WriteDone( Uint32 len );
+    void WriteDone( Uint32 len, double timestamp=-1 );
 
     /* Reserve a buffer for reading in the ring */
     Uint32 NextReadBuffer( Uint8** buffer );
 
+    /* Read the timestamp of the current buffer */
+    double ReadTimeStamp(void);
+
     /* Release a buffer having read some of it */
     void ReadSome( Uint32 used );
 
@@ -75,6 +78,10 @@
     Uint8 *begin;
     Uint8 *end;
 
+    double *timestamps;
+    double *timestamp_read;
+    double *timestamp_write;
+ 
     Uint8 *read;
     Uint8 *write;
 
diff -Naur smpeg/MPEGstream.cpp smpeg-all/MPEGstream.cpp
--- smpeg/MPEGstream.cpp	Mon May 15 18:21:20 2000
+++ smpeg-all/MPEGstream.cpp	Tue May 16 22:50:34 2000
@@ -34,6 +34,7 @@
   
   data = 0;
   stop = 0;
+  pos = 0;
   
   preread_size = 0;
   looping = false;
@@ -97,7 +98,7 @@
 }
 
 bool
-MPEGstream:: next_packet(bool recurse)
+MPEGstream:: next_packet(bool recurse, bool update_timestamp)
 {
   SDL_mutexP(mutex);
 
@@ -114,7 +115,7 @@
     system->RequestBuffer();
     while(!br->Next() && timeout--)
       SDL_Delay(1);
-    if(!timeout) return(false);
+    if(timeout<=0) return(false);
     SDL_mutexP(mutex);
   }
 
@@ -157,7 +158,10 @@
   /* Update stream datas */
   data = (Uint8 *) br->Buffer();
   stop = data + br->Size();
-
+  if(update_timestamp){
+    timestamp = br->TimeStamp;
+    timestamp_pos = pos;
+  }
   SDL_mutexV(mutex);
 
   return(true);
@@ -230,15 +234,18 @@
 MPEGstream:: copy_data(Uint8 *area, Sint32 size, bool short_read)
 {
     Uint32 copied = 0;
+    bool timestamped = false;
 
     while ( (size > 0) && !eof()) {
         Uint32 len;
 
         /* Get new data if necessary */
         if ( data == stop ) {
-            if ( ! next_packet() ) {
+            /* try to use the timestamp of the first packet */
+            if ( ! next_packet(true, (timestamp == -1) || !timestamped) ) {
                 break;
             }
+	    timestamped = true;
         }
 
 	SDL_mutexP(mutex);
@@ -256,6 +263,7 @@
         data += len;
         size -= len;
         copied += len;
+	pos += len;
 
         /* Allow 32-bit aligned short reads? */
         if ( ((copied%4) == 0) && short_read ) {
@@ -277,7 +285,7 @@
       return (-1);
     }
   }
-
+  pos ++;
   return(*data++);
 }
 
@@ -286,7 +294,7 @@
   return(!br->Size());
 }
 
-void MPEGstream::insert_packet(Uint8 * Data, Uint32 Size)
+void MPEGstream::insert_packet(Uint8 * Data, Uint32 Size, double timestamp=-1)
 {
   MPEGlist * newbr;
 
@@ -305,6 +313,7 @@
   if ( Size ) {
     memcpy(newbr->Buffer(), Data, Size);
   }
+  newbr->TimeStamp = timestamp;
 
   SDL_mutexV(mutex);
   garbage_collect();
diff -Naur smpeg/MPEGstream.h smpeg-all/MPEGstream.h
--- smpeg/MPEGstream.h	Mon May 15 18:21:20 2000
+++ smpeg-all/MPEGstream.h	Tue May 16 22:52:40 2000
@@ -53,8 +53,8 @@
     void rewind_stream(void);
 
     /* Go to the next packet in the stream */
-    bool next_packet(bool recurse = true);
-
+    bool next_packet(bool recurse = true, bool update_timestamp = true);
+ 
     /* Mark a position in the data stream */
     MPEGstream_marker *new_marker(int offset);
 
@@ -74,7 +74,7 @@
     bool eof(void) const;
 
     /* Insert a new packet at the end of the stream */
-    void insert_packet(Uint8 * data, Uint32 size);
+    void insert_packet(Uint8 * data, Uint32 size, double timestamp=-1);
 
     /* Check for unused buffers and free them */
     void garbage_collect(void);
@@ -102,6 +102,13 @@
     bool looping;
 
     SDL_mutex * mutex;
+public:
+    /* total of bytes read by our client, it doesn't realy have to be
+       too meaningful, it only serves as a reference for timestamp_pos */
+    Uint32 pos;
+    /* "pos" where "timestamp" belongs */
+    Uint32 timestamp_pos;
+    double timestamp;
 };
 
 #endif /* _MPEGSTREAM_H_ */
diff -Naur smpeg/MPEGsystem.cpp smpeg-all/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Tue May 16 23:26:06 2000
+++ smpeg-all/MPEGsystem.cpp	Tue May 16 23:07:14 2000
@@ -41,11 +41,8 @@
 
 /* The size is arbitrary but should be sufficient to contain */
 /* two MPEG packets and reduce disk (or network) access.     */
-#if 0 // Hiroshi Yamashita notes that the original size was too large
-#define MPEG_BUFFER_SIZE (64 * 1024)
-#else
+// Hiroshi Yamashita notes that the original size was too large
 #define MPEG_BUFFER_SIZE (16 * 1024)
-#endif
 
 /* The granularity (2^LG2_GRANULARITY) determine what length of read data */
 /* will be a multiple of, e.g. setting LG2_GRANULARITY to 12 will make    */
@@ -62,6 +59,10 @@
 /* Timeout before read fails */
 #define READ_TIME_OUT 1000000
 
+/* timestamping */
+#define FLOAT_0x10000 (double)((Uint32)1 << 16)
+#define STD_SYSTEM_CLOCK_FREQ 90000L
+
 /* This work only on little endian systems */
 /*
 #define REV(x) ((((x)&0x000000FF)<<24)| \
@@ -79,6 +80,22 @@
 	  ((code1[2] & mask[2]) == (code2[2] & mask[2])) &&
 	  ((code1[3] & mask[3]) == (code2[3] & mask[3])) );
 }
+static inline double read_time_code(Uint8 *pointer)
+{ 
+  double timestamp;
+  Uint8 hibit; Uint32 lowbytes;
+
+  hibit = (pointer[0]>>3)&0x01;
+  lowbytes = (((Uint32)pointer[0] >> 1) & 0x03) << 30;
+  lowbytes |= (Uint32)pointer[1] << 22;
+  lowbytes |= ((Uint32)pointer[2] >> 1) << 15;
+  lowbytes |= (Uint32)pointer[3] << 7;
+  lowbytes |= ((Uint32)pointer[4]) >> 1;
+  timestamp = (double)hibit*FLOAT_0x10000*FLOAT_0x10000+(double)lowbytes;
+  timestamp /= STD_SYSTEM_CLOCK_FREQ;
+
+  return timestamp;
+}
 
 MPEGsystem::MPEGsystem(int Mpeg_FD)
 {
@@ -107,6 +124,7 @@
 #ifdef USE_SYSTEM_TIMESTAMP
   timestamp = 0.0;
   timedrift = 0.0;
+  skip_timestamp = -1;
 #endif
 
   /* Search the MPEG for the first header */
@@ -243,6 +261,7 @@
   Uint8 const zero[4] = {0x00,0x00,0x00,0x00};
   Uint8 const one[4]  = {0x00,0x00,0x00,0x01};
   Uint8 const mask[4] = {0xff,0xff,0xff,0xff};
+  double stream_timestamp;
 
   /* - Read a new packet - */
   Read();
@@ -280,29 +299,7 @@
   {
     /* Parse the packet information */
     pointer += 4;
-
-    /* The system stream timestamp is not very useful to us since we
-       don't coordinate the audio and video threads very tightly, and
-       we read in large amounts of data at once in the video stream.
-       BUT... if you need it, here it is.
-    */
-
-#ifdef USE_SYSTEM_TIMESTAMP
-#define FLOAT_0x10000 (double)((Uint32)1 << 16)
-#define STD_SYSTEM_CLOCK_FREQ 90000L
-    { 
-      Uint8 hibit; Uint32 lowbytes;
-
-      hibit = (pointer[0]>>3)&0x01;
-      lowbytes = (((Uint32)pointer[0] >> 1) & 0x03) << 30;
-      lowbytes |= (Uint32)pointer[1] << 22;
-      lowbytes |= ((Uint32)pointer[2] >> 1) << 15;
-      lowbytes |= (Uint32)pointer[3] << 7;
-      lowbytes |= ((Uint32)pointer[4]) >> 1;
-      timestamp = (double)hibit*FLOAT_0x10000*FLOAT_0x10000+(double)lowbytes;
-      timestamp /= STD_SYSTEM_CLOCK_FREQ;
-    }
-#endif
+    timestamp = read_time_code(pointer);
     pointer += 8;
   }
 
@@ -327,10 +324,14 @@
       pointer += 2;
       packet_size -= 2;
     }
-    if ( (pointer[0] & 0x30) == 0x30 ) {
-      pointer += 9;
-      packet_size -= 9;
-    } else if ( (pointer[0] & 0x20) == 0x20 ) {
+    if ( (pointer[0] & 0x20) == 0x20 ) {
+      /* get the PTS */
+      stream_timestamp = read_time_code(pointer);
+      /* we don't care about DTS */
+      if ( (pointer[0] & 0x30) == 0x30 ){
+	pointer += 5;
+	packet_size -= 5;
+      }
       pointer += 4;
       packet_size -= 4;
     } else if ( pointer[0] != 0x0f && pointer[0] != 0x80) {
@@ -339,7 +340,9 @@
       if(!seek_next_header())
       	errorstream = true;
       return(0);
-    }
+    } else
+      stream_timestamp = -1;
+    
     ++pointer;
     --packet_size;
 
@@ -408,6 +411,20 @@
 
   assert(packet_size <= MPEG_BUFFER_SIZE);
 
+  if(skip_timestamp > timestamp){
+    int cur_seconds=int(timestamp)%60;
+
+    if (cur_seconds%5==0){
+      fprintf(stderr, "Skiping to %02d:%02d (%02d:%02d)\r",
+              int(skip_timestamp)/60, int(skip_timestamp)%60,
+              int(timestamp)/60, cur_seconds);
+    }
+    pointer += packet_size;
+    /* since we skip data, request more */
+    RequestBuffer();
+    return (1);
+  }
+
   switch(stream_id)
   {
     case 0:
@@ -475,12 +492,19 @@
       }
 
       /* Insert the new data at the end of the stream */
-      stream->insert_packet(pointer, packet_size);
+      stream->insert_packet(pointer, packet_size, stream_timestamp);
       pointer += packet_size;
     return(stream_id);
   }
 }
 
+void MPEGsystem::Skip(double time)
+{
+  if (skip_timestamp < timestamp)
+    skip_timestamp = timestamp;
+  skip_timestamp += time;
+}
+ 
 Uint32 MPEGsystem::Tell()
 {
   /* Warning: 32 bits means that files > 4Go might return bad values */
@@ -507,7 +531,7 @@
   Seek(0);
 }
 
-void MPEGsystem::Seek(int length)
+double MPEGsystem::Seek(int length)
 {
   request = 0;
 
@@ -526,7 +550,7 @@
       errorstream = true;
       SetError(strerror(errno));
     }
-    return;
+    return(-1);
   }
 
   /* Reinitialize the read buffer */
@@ -542,7 +566,7 @@
   {
     errorstream = true;
     SetError("Could not find the beginning of MPEG data\n");
-    return;
+    return (-1);
   }
 
   request = PRE_BUFFERED_MAX;
@@ -558,6 +582,10 @@
   while(request > 0 && !Eof())
     SDL_Delay(1);
 
+  /* Get current play time */
+  FillBuffer();
+
+  return(timestamp);
 }
 
 void MPEGsystem::Loop(bool toggle)
@@ -630,7 +658,7 @@
     if(system->request > 0)
     {
       /* Read the buffer */
-      system->FillBuffer();
+      while (system->FillBuffer()==1);
       delay >>= 1;
     }
     else
diff -Naur smpeg/MPEGsystem.h smpeg-all/MPEGsystem.h
--- smpeg/MPEGsystem.h	Tue May 16 23:26:06 2000
+++ smpeg-all/MPEGsystem.h	Wed May 17 00:03:54 2000
@@ -2,6 +2,7 @@
 
 #ifndef _MPEGSYSTEM_H_
 #define _MPEGSYSTEM_H_
+#define USE_SYSTEM_TIMESTAMP
 
 #include "SDL.h"
 #include "SDL_thread.h"
@@ -27,22 +28,15 @@
     void Rewind();
     void Loop(bool toggle);
     bool Eof() const;
-    void Seek(int length);
+    double Seek(int length);
     Uint32 TotalSize();
 
+    /* Skip "seconds" seconds */
+    void Skip(double seconds);
+
     /* Create all the streams present in the MPEG */
     MPEGstream ** GetStreamList();
 
-protected:
-    /* Fill a buffer */
-    Uint8 FillBuffer();
-
-    /* Read a new packet */
-    void Read();
-
-    /* The system thread which fills the FIFO */
-    static int SystemThread(void * udata);
-
     /* Insert a stream in the list */
     void add_stream(MPEGstream * stream);
 
@@ -64,6 +58,16 @@
     /* Seek the next header */
     bool seek_next_header();
 
+protected:
+    /* Fill a buffer */
+    Uint8 FillBuffer();
+
+    /* Read a new packet */
+    void Read();
+
+    /* The system thread which fills the FIFO */
+    static int SystemThread(void * udata);
+
     int mpeg_fd;
 
     SDL_Thread * system_thread;
@@ -86,6 +90,7 @@
     /* Current timestamp for this stream */
     double timestamp;
     double timedrift;
+    double skip_timestamp;
 #endif
 };
 #endif
diff -Naur smpeg/MPEGvideo.h smpeg-all/MPEGvideo.h
--- smpeg/MPEGvideo.h	Tue May 16 23:26:07 2000
+++ smpeg-all/MPEGvideo.h	Wed May 17 00:01:13 2000
@@ -35,7 +35,7 @@
 
 /* Temporary definition of time stamp structure. */
 
-typedef int TimeStamp;
+typedef double TimeStamp;
 
 class MPEGvideo : public MPEGerror, public MPEGvideoaction {
 
@@ -57,7 +57,8 @@
     void Play(void);
     void Stop(void);
     void Rewind(void);
-    void ResetSynchro(void);
+    void ResetSynchro(double time);
+     void Skip(float seconds);
     MPEGstatus Status(void);
 
     /* MPEG video actions */
diff -Naur smpeg/audio/MPEGaudio.cpp smpeg-all/audio/MPEGaudio.cpp
--- smpeg/audio/MPEGaudio.cpp	Tue May 16 23:26:07 2000
+++ smpeg-all/audio/MPEGaudio.cpp	Tue May 16 23:30:34 2000
@@ -169,7 +169,7 @@
     if ( frag_time ) {
         now = (play_time + (double)(SDL_GetTicks() - frag_time)/1000.0);
     } else {
-        now = 0.0;
+        now = play_time;
     }
     return now;
 }
@@ -207,14 +207,25 @@
     decodedframe = 0;
     currentframe = 0;
     frags_playing = 0;
+    frag_time = 0;
 }
 void
-MPEGaudio:: ResetSynchro(void)
+MPEGaudio:: ResetSynchro(double time)
 {
-    frag_time = 0;
-    play_time = 0.0;
+    play_time = time;
 }
 void
+MPEGaudio:: Skip(float seconds)
+{
+   /* Called only when there is no timestamp info in the MPEG */
+   printf("Audio: Skipping %f seconds...\n", seconds);
+   while(seconds > 0)
+   {
+     seconds -= (double) samplesperframe / ((double) frequencies[version][frequency]*(1+inputstereo));
+     if(!loadheader()) break;
+   }
+ }
+void
 MPEGaudio:: Volume(int vol)
 {
     if ( (vol >= 0) && (vol <= 100) ) {
@@ -257,6 +268,7 @@
 MPEGaudio:: fillbuffer(int size)
   {
       bitindex=0;
+      _buffer_pos = mpeg->pos;
       return(mpeg->copy_data(_buffer, size) > 0);
   };
   
diff -Naur smpeg/audio/mpegtoraw.cpp smpeg-all/audio/mpegtoraw.cpp
--- smpeg/audio/mpegtoraw.cpp	Mon May 15 18:21:20 2000
+++ smpeg-all/audio/mpegtoraw.cpp	Wed May 17 23:57:08 2000
@@ -265,14 +265,25 @@
 }
 
 
-bool MPEGaudio::run( int frames )
+bool MPEGaudio::run( int frames, double *timestamp = NULL)
 {
+    double last_timestamp = -1;
+    int totFrames = frames;
+
     for( ; frames; frames-- )
     {
         if( loadheader() == false ) {
 	  return false;	  
         }
 
+        if (frames == totFrames  && timestamp != NULL)
+            if (last_timestamp != mpeg->timestamp){
+		if (mpeg->timestamp_pos <= _buffer_pos)
+		    last_timestamp = *timestamp = mpeg->timestamp;
+	    }
+            else
+                *timestamp = -1;
+
         if     ( layer == 3 ) extractlayer3();
         else if( layer == 2 ) extractlayer2();
         else if( layer == 1 ) extractlayer1();
@@ -304,13 +315,14 @@
 int Decode_MPEGaudio(void *udata)
 {
     MPEGaudio *audio = (MPEGaudio *)udata;
+    double timestamp;
 
     while ( audio->decoding && ! audio->mpeg->eof() ) {
         audio->rawdata = (Sint16 *)audio->ring->NextWriteBuffer();
         if ( audio->rawdata ) {
             audio->rawdatawriteoffset = 0;
-            audio->run(1);
-            audio->ring->WriteDone(audio->rawdatawriteoffset*2);
+            audio->run(1, &timestamp);
+            audio->ring->WriteDone(audio->rawdatawriteoffset*2, timestamp);
         }
     }
     audio->decoding = false;
@@ -361,11 +373,24 @@
     assert(audio);
     assert(audio->ring);
     do {
+	/* this is empirical, I don't realy know how to find out when
+	   a certain piece of audio has finished playing or even if
+	   the timestamps refer to the time when the frame starts
+	   playing or then the frame ends playing, but as is works
+	   quite right */
+#define N_TIMESTAMPS 5
+	static double timestamp[N_TIMESTAMPS] = {0};
+	if(timestamp[0] == 0)
+	    for (int i=0; i<N_TIMESTAMPS; i++)
+		timestamp[i] = -1;
         copylen = audio->ring->NextReadBuffer(&rbuf);
         if ( copylen > len ) {
             SDL_MixAudio(stream, rbuf, len, volume);
             audio->ring->ReadSome(len);
             len = 0;
+	    for (int i=0; i < N_TIMESTAMPS -1; i++)
+		timestamp[i] = timestamp[i+1];
+	    timestamp[N_TIMESTAMPS-1] = audio->ring->ReadTimeStamp();
         } else {
             SDL_MixAudio(stream, rbuf, copylen, volume);
             ++audio->currentframe;
@@ -374,6 +399,26 @@
             len -= copylen;
             stream += copylen;
         }
+	if (timestamp[0] != -1){
+	    double timeshift = audio->Time() - timestamp[0];
+	    double correction = 0;
+	    assert(timestamp >= 0);
+	    if (fabs(timeshift) > 1.0){
+	        correction = -timeshift;
+#ifdef DEBUG_TIMESTAMP_SYNC
+                fprintf(stderr, "audio jump %f\n", timeshift);
+#endif
+            } else
+	        correction = -timeshift/100;
+#ifdef USE_TIMESTAMP_SYNC
+	    audio->play_time += correction;
+#endif
+#ifdef DEBUG_TIMESTAMP_SYNC
+	    fprintf(stderr, "\raudio: time:%8.3f shift:%8.4f",
+                    audio->Time(), timeshift);
+#endif
+	    timestamp[0] = -1;
+	}
     } while ( copylen && (len > 0) && ((audio->currentframe < audio->decodedframe) || audio->decoding));
 #else
     /* The length is interpreted as being in samples */
diff -Naur smpeg/configure.in smpeg-all/configure.in
--- smpeg/configure.in	Wed May 17 21:28:31 2000
+++ smpeg-all/configure.in	Wed May 17 23:59:08 2000
@@ -95,6 +95,14 @@
     esac
 fi
 
+dnl Check for system timestamp sync
+AC_ARG_ENABLE(timestamp-sync,
+[  --enable-timestamp-sync  enable system timestamp sync [default=yes]],
+              , enable_timestamp_sync=yes)
+if test x$enable_timestamp_sync = xyes; then
+	CFLAGS="$CFLAGS -DUSE_TIMESTAMP_SYNC"
+fi
+
 dnl See if we can build the GTk player
 AC_ARG_ENABLE(gtk_player,
 [  --enable-gtk-player     build a GTk sample SMPEG player [default=yes]],
diff -Naur smpeg/plaympeg.c smpeg-all/plaympeg.c
--- smpeg/plaympeg.c	Tue May 16 23:26:07 2000
+++ smpeg-all/plaympeg.c	Wed May 17 00:05:05 2000
@@ -53,6 +53,9 @@
 "	--volume N or -v N   Set audio volume to N (0-100)\n"
 "	--scale wxh or -s wxh  Play MPEG at given resolution\n"
 "       --seek N or -S N     Skip N bytes\n"
+#ifdef USE_SYSTEM_TIMESTAMP
+"       --skip N or -k N     Skip N seconds\n"
+#endif
 "	--help or -h\n"
 "	--version or -V\n"
 "Specifying - as filename will use stdin for input\n", argv0);
@@ -83,7 +86,8 @@
     int loop_play;
     int i, done, pause;
     int volume;
-    float seek;
+    Uint32 seek;
+    float skip;
     SDL_Surface *screen;
     SMPEG *mpeg;
     SMPEG_Info info;
@@ -101,6 +105,7 @@
     loop_play = 0;
     volume = 100;
     seek = 0;
+    skip = 0;
     for ( i=1; argv[i] && (argv[i][0] == '-') && (argv[i][1] != 0); ++i ) {
         if ( (strcmp(argv[i], "--noaudio") == 0) ||
              (strcmp(argv[i], "--nosound") == 0) ) {
@@ -121,7 +126,13 @@
         if ((strcmp(argv[i], "--seek") == 0)||(strcmp(argv[i], "-S") == 0)) {
             ++i;
             if ( argv[i] ) {
-                seek = (float)atof(argv[i]);
+                seek = atol(argv[i]);
+            }
+        } else
+        if ((strcmp(argv[i], "--skip") == 0)||(strcmp(argv[i], "-k") == 0)) {
+            ++i;
+            if ( argv[i] ) {
+                skip = (float)atof(argv[i]);
             }
         } else
         if ((strcmp(argv[i], "--volume") == 0)||(strcmp(argv[i], "-v") == 0)) {
@@ -356,8 +367,11 @@
             SMPEG_loop(mpeg, 1);
         }
 
-	/* Skip to starting position */
+	/* Seek starting position */
 	if(seek) SMPEG_seek(mpeg, seek);
+
+	/* Skip seconds to starting position */
+	if(skip) SMPEG_skip(mpeg, skip);
 	
         /* Play it, and wait for playback to complete */
         SMPEG_play(mpeg);
@@ -435,11 +449,11 @@
 			} else if ( event.key.keysym.sym == SDLK_RIGHT ) {
 			  // Forward
 			  if ( event.key.keysym.mod & KMOD_SHIFT ) {
-
+			    SMPEG_skip(mpeg, 100);
 			  } else if ( event.key.keysym.mod & KMOD_CTRL ) {
-
+			    SMPEG_skip(mpeg, 50);
 			  } else {
-			    
+			    SMPEG_skip(mpeg, 5);
 			  }
                         } else if ( event.key.keysym.sym == SDLK_LEFT ) {
 			  // Reverse
diff -Naur smpeg/smpeg.cpp smpeg-all/smpeg.cpp
--- smpeg/smpeg.cpp	Tue May 16 23:26:07 2000
+++ smpeg-all/smpeg.cpp	Tue May 16 23:46:10 2000
@@ -227,6 +227,12 @@
   return(mpeg->obj->TotalSize());
 }
 
+/* Skip 'seconds' seconds of the MPEG */
+void SMPEG_skip( SMPEG* mpeg, float seconds )
+{
+  return(mpeg->obj->Skip(seconds));
+}
+
 /* Render a particular frame in the MPEG video */
 void SMPEG_renderFrame( SMPEG* mpeg, int framenum )
 {
diff -Naur smpeg/smpeg.h smpeg-all/smpeg.h
--- smpeg/smpeg.h	Tue May 16 23:26:07 2000
+++ smpeg-all/smpeg.h	Tue May 16 23:47:21 2000
@@ -153,6 +153,9 @@
 /* Warning: this is 32 bit values so streams > 4Go will return bad values */
 Uint32 SMPEG_total_size( SMPEG* mpeg );
 
+/* Skip 'seconds' seconds in the MPEG stream */
+void SMPEG_skip( SMPEG* mpeg, float seconds );
+
 /* Render a particular frame in the MPEG video
    API CHANGE: This function no longer takes a target surface and position.
                Use SMPEG_setdisplay() and SMPEG_move() to set this information.
diff -Naur smpeg/video/MPEGvideo.cpp smpeg-all/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Tue May 16 23:26:07 2000
+++ smpeg-all/video/MPEGvideo.cpp	Tue May 16 23:51:16 2000
@@ -298,11 +298,34 @@
 }
 
 void
-MPEGvideo:: ResetSynchro(void)
+MPEGvideo:: ResetSynchro(double time)
 {
   _stream->_jumpFrame = -1;
   _stream->realTimeStart = 0.0;
-  play_time = 0.0;
+  play_time = time;
+}
+
+
+void
+MPEGvideo::Skip(float seconds)
+{
+  int frame;
+
+  /* Called only when there is no timestamp info in the MPEG */
+  /* This is quite slow however */
+  printf("Video: Skipping %f seconds...\n", seconds);  
+  frame = (int) (_fps * seconds);
+
+  if( _stream )
+  {
+    _stream->_jumpFrame = frame;
+    while( (_stream->totNumFrames < frame) &&
+	   ! _stream->film_has_ended )
+    {
+      mpegVidRsrc( 0, _stream, 0 );
+    }
+    ResetSynchro(0);
+  }
 }
 
 MPEGstatus
diff -Naur smpeg/video/gdith.cpp smpeg-all/video/gdith.cpp
--- smpeg/video/gdith.cpp	Mon May 15 18:21:20 2000
+++ smpeg-all/video/gdith.cpp	Wed May 17 23:56:42 2000
@@ -145,6 +145,7 @@
 int timeSync( VidStream* vid_stream )
 {
     MPEGvideo* mpeg = (MPEGvideo*) vid_stream->_smpeg;
+    static double correction = -1;
 
     /* Update the number of frames displayed */
     vid_stream->totNumFrames++;
@@ -172,6 +173,21 @@
     /* Update the current play time */
     mpeg->play_time += vid_stream->_oneFrameTime;
 
+    /* Synchronize using system timestamps */
+    if(vid_stream->current && vid_stream->current->show_time > 0){
+#ifdef DEBUG_TIMESTAMP_SYNC
+      fprintf(stderr, "video: time:%.3f  shift:%.3f\r",
+	      mpeg->play_time,
+	      mpeg->play_time - vid_stream->current->show_time);
+#endif
+      if(correction == -1)
+	correction = mpeg->play_time - vid_stream->current->show_time;
+#ifdef USE_TIMESTAMP_SYNC
+      mpeg->play_time = vid_stream->current->show_time + correction ;
+#endif
+      vid_stream->current->show_time = -1;
+    }
+
     /* If we are looking for a particular frame... */
     if( vid_stream->_jumpFrame > -1 )
     {
@@ -198,7 +214,7 @@
         time_behind = CurrentTime(vid_stream) - mpeg->Time();
 
 #ifdef DEBUG_MPEG_SCHEDULING
-//printf("Frame %d: frame time: %f, real time: %f, time behind: %f\n", vid_stream->totNumFrames, mpeg->Time(), CurrentTime(vid_stream), time_behind);
+printf("Frame %d: frame time: %f, real time: %f, time behind: %f\n", vid_stream->totNumFrames, mpeg->Time(), CurrentTime(vid_stream), time_behind);
 #endif
 
         /* Allow up to MAX_FUDGE_TIME of delay in output */
diff -Naur smpeg/video/readfile.cpp smpeg-all/video/readfile.cpp
--- smpeg/video/readfile.cpp	Mon May 15 18:21:20 2000
+++ smpeg-all/video/readfile.cpp	Tue May 16 23:55:53 2000
@@ -100,7 +100,9 @@
   unsigned int request;
   unsigned char *buffer, *mark;
   unsigned int *lmark;
-  
+  Sint32 timestamp_offset;
+  Uint32 data_pos;
+     
   if (vid_stream->EOF_flag) return 0;
   
   buf_start = vid_stream->buf_start;
@@ -118,8 +120,13 @@
   
   request = (vid_stream->max_buf_length-length)*4;
   
-  
+  data_pos = vid_stream->_smpeg->mpeg->pos;  
   num_read = vid_stream->_smpeg->mpeg->copy_data(mark, request);
+
+  vid_stream->timestamp = vid_stream->_smpeg->mpeg->timestamp;
+  timestamp_offset = vid_stream->_smpeg->mpeg->timestamp_pos - data_pos;
+  vid_stream->timestamp_mark = (unsigned int *)(mark+timestamp_offset);
+  vid_stream->timestamp_used = false;
 
   /* Paulo Villegas - 26/1/1993: Correction for 4-byte alignment */
   {
diff -Naur smpeg/video/video.cpp smpeg-all/video/video.cpp
--- smpeg/video/video.cpp	Sat Apr 29 00:58:33 2000
+++ smpeg-all/video/video.cpp	Tue May 16 23:57:02 2000
@@ -1085,7 +1085,12 @@
 
         /* Picture start code. Parse picture header and first slice header. */
 
-        status = ParsePicture( vid_stream, time_stamp );
+	if (vid_stream->timestamp_mark < vid_stream->buffer
+	    && !vid_stream->timestamp_used){
+	  vid_stream->timestamp_used = true;
+	  status = ParsePicture( vid_stream, vid_stream->timestamp );
+	} else
+	  status = ParsePicture( vid_stream, -1);
 
         if((vid_stream->picture.code_type == B_TYPE) &&
             vid_stream->_skipFrame && (vid_stream->_jumpFrame < 0))
diff -Naur smpeg/video/video.h smpeg-all/video/video.h
--- smpeg/video/video.h	Mon May 15 18:21:20 2000
+++ smpeg-all/video/video.h	Tue May 16 23:58:14 2000
@@ -304,7 +304,11 @@
   int timestamp_index;
 #endif
 /* SL - end of added variables */
-
+/* begining of added variables for system stream based sync */
+  double timestamp;
+  unsigned int *timestamp_mark;
+  bool timestamp_used;
+/* begining of added variables */
 } VidStream;   
 
 /* Declaration of global display pointer. */
*************************************************************************
*** Applied ***
Date: Tue, 16 May 2000 20:55:10 +0200
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: Sim Wars MPEG not playing correctly



Sam Lantinga wrote:

> 1. Patch to provide the seeking

        Here it is, featuring:
                - seeking code through the SMPEG_seek function
                - bugfix that made SMPEG stop when quitting
                - total size, current position in stream through
SMPEG_total_size and
SMPEG_tell

        I tested it with all my MPEGs (not so many though) and it worked
fine.

        I think you should apply this patch, then we would wait for feedback
and ensure the latest CVS is stable so that you can do a release. There
have been many enhancements since the 0.3.5 that are awaited by many
people. Then we could apply the timestamp patch on CVS, as an optionnal
feature to start with (I mean doing a --enable-timestamp configure
option), enhance it and finally make the option being enabled by
default. What do you think of it?

see ya,
Vivien.

diff -Naur smpeg/MPEG.cpp smpeg-seek/MPEG.cpp
--- smpeg/MPEG.cpp	Tue May 16 17:46:18 2000
+++ smpeg-seek/MPEG.cpp	Tue May 16 20:31:53 2000
@@ -175,23 +175,7 @@
 }
 
 void MPEG::Rewind(void) {
-  Stop();
-
-  /* Go to the beginning of the file */
-  system->Rewind();
-
-  /* Skip the first empty buffer made when creating a mpegstream */
-  /* which would otherwise be interpreted as end of file */
-  if(audiostream) audiostream->next_packet();
-  if(videostream) videostream->next_packet();
-
-  if ( AudioEnabled() ) {
-    audioaction->Rewind();
-  }
-
-  if ( VideoEnabled() ) {
-    videoaction->Rewind();
-  }
+  seekIntoStream(0);
 }
 
 void MPEG::Pause(void) {
@@ -257,6 +241,7 @@
   return(status);
 }
 
+
 /* MPEG audio actions */
 bool MPEG::GetAudioInfo(MPEG_AudioInfo *info) {
   if ( AudioEnabled() ) {
@@ -329,15 +314,60 @@
   if( audiostream ) audiostream->enable(true);
 }
 
-void MPEG::Skip(float seconds)
+void MPEG::Seek(int position)
+{
+  int were_playing = 0;
+
+  /* Cannot seek past end of file */
+  if(position > TotalSize()) return;
+  
+  /* get info whrether we need to restart playing at the end */
+  if( Status() == MPEG_PLAYING )
+    were_playing = 1;
+
+  seekIntoStream(position);
+
+  /* If we were playing and not rewind then play again */
+  if (were_playing)
+    Play();
+}
+
+void MPEG::seekIntoStream(int position)
 {
+  /* First we stop everything */
+  Stop();
+
+  /* Go to the desired position into file */
+  system->Seek(position);
+
+  /* Skip the first empty buffer made when creating a mpegstream */
+  /* which would otherwise be interpreted as end of file */
+
+  if(audiostream) audiostream->next_packet();
+  if(videostream) videostream->next_packet();
+
+  /* And forget what we previouly buffered */
+
   if ( AudioEnabled() ) {
-    audioaction->Skip(seconds);
+    audioaction->Rewind();
+    audioaction->ResetSynchro();
   }
 
   if ( VideoEnabled() ) {
-    videoaction->Skip(seconds);
+    videoaction->Rewind();
+    videoaction->ResetSynchro();
   }
+
+}
+
+Uint32 MPEG::Tell()
+{
+  return(system->Tell());
+}
+
+Uint32 MPEG::TotalSize()
+{
+  return(system->TotalSize());
 }
 
 void MPEG::parse_stream_list()
diff -Naur smpeg/MPEG.h smpeg-seek/MPEG.h
--- smpeg/MPEG.h	Tue May 16 17:46:18 2000
+++ smpeg-seek/MPEG.h	Sat May 13 00:48:26 2000
@@ -68,7 +68,9 @@
     void Stop(void);
     void Rewind(void);
     void Pause(void);
-    void Skip(float seconds);
+    void Seek(int bytes);
+    Uint32 Tell();
+    Uint32 TotalSize();
     MPEGstatus Status(void);
 
     /* MPEG audio actions */
@@ -113,6 +115,7 @@
     bool pause;
 
     void parse_stream_list();
+    void seekIntoStream(int position);
 };
 
 #endif /* _MPEG_H_ */
diff -Naur smpeg/MPEGaction.h smpeg-seek/MPEGaction.h
--- smpeg/MPEGaction.h	Tue May 16 17:46:18 2000
+++ smpeg-seek/MPEGaction.h	Tue May 16 20:30:47 2000
@@ -47,7 +47,7 @@
     virtual void Play(void) = 0;
     virtual void Stop(void) = 0;
     virtual void Rewind(void) = 0;
-    virtual void Skip(float seconds) = 0;
+    virtual void ResetSynchro(void) = 0;
     virtual void Pause(void) {  /* A toggle action */
         if ( paused ) {
             paused = false;
diff -Naur smpeg/MPEGaudio.h smpeg-seek/MPEGaudio.h
--- smpeg/MPEGaudio.h	Tue May 16 17:46:19 2000
+++ smpeg-seek/MPEGaudio.h	Tue May 16 20:30:56 2000
@@ -167,7 +167,7 @@
     void Play(void);
     void Stop(void);
     void Rewind(void);
-    void Skip(float seconds);
+    void ResetSynchro(void);
     void Volume(int vol);
     MPEGstatus Status(void);
 
diff -Naur smpeg/MPEGsystem.cpp smpeg-seek/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Tue May 16 17:46:19 2000
+++ smpeg-seek/MPEGsystem.cpp	Tue May 16 19:59:32 2000
@@ -7,6 +7,8 @@
 #include <winsock.h>
 #else
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #endif
 
 #include "MPEGsystem.h"
@@ -485,8 +487,28 @@
   return(read_total);
 }
 
+Uint32 MPEGsystem::TotalSize()
+{
+#ifndef WIN32
+    struct stat st;
+    Uint32 size;
+
+    if(!fstat(mpeg_fd, &st))
+      return(st.st_size);
+    else
+      return(0);
+#else
+#error "Not implemented"
+#endif
+}
+
 void MPEGsystem::Rewind()
 {
+  Seek(0);
+}
+
+void MPEGsystem::Seek(int length)
+{
   request = 0;
 
   /* Force the system thread to die */
@@ -496,8 +518,8 @@
   /* Reset the streams */
   reset_all_streams();
 
-  /* Get back to the beginning of the stream */
-  if(lseek(mpeg_fd, 0, SEEK_SET) == (long) -1)
+  /* Get into the stream */
+  if(lseek(mpeg_fd, length, SEEK_SET) == (off_t) -1)
   {
     if(errno != ESPIPE)
     {
diff -Naur smpeg/MPEGsystem.h smpeg-seek/MPEGsystem.h
--- smpeg/MPEGsystem.h	Tue May 16 17:46:19 2000
+++ smpeg-seek/MPEGsystem.h	Sat May 13 00:48:12 2000
@@ -27,6 +27,8 @@
     void Rewind();
     void Loop(bool toggle);
     bool Eof() const;
+    void Seek(int length);
+    Uint32 TotalSize();
 
     /* Create all the streams present in the MPEG */
     MPEGstream ** GetStreamList();
diff -Naur smpeg/MPEGvideo.h smpeg-seek/MPEGvideo.h
--- smpeg/MPEGvideo.h	Tue May 16 17:46:19 2000
+++ smpeg-seek/MPEGvideo.h	Tue May 16 20:31:01 2000
@@ -57,7 +57,7 @@
     void Play(void);
     void Stop(void);
     void Rewind(void);
-    void Skip(float seconds);
+    void ResetSynchro(void);
     MPEGstatus Status(void);
 
     /* MPEG video actions */
diff -Naur smpeg/audio/MPEGaudio.cpp smpeg-seek/audio/MPEGaudio.cpp
--- smpeg/audio/MPEGaudio.cpp	Tue May 16 17:46:20 2000
+++ smpeg-seek/audio/MPEGaudio.cpp	Tue May 16 20:32:10 2000
@@ -149,6 +149,7 @@
 {
     decoding = false;
     if ( decode_thread ) {
+        if( ring ) ring->ReleaseThreads();
         SDL_WaitThread(decode_thread, NULL);
         decode_thread = NULL;
     }
@@ -206,19 +207,12 @@
     decodedframe = 0;
     currentframe = 0;
     frags_playing = 0;
-    frag_time = 0;
-    play_time = 0.0;
 }
 void
-MPEGaudio:: Skip(float seconds)
+MPEGaudio:: ResetSynchro(void)
 {
-  printf("Audio: Skipping %f seconds...\n", seconds);  
-  while(seconds > 0)
-  {
-    seconds -= (double) samplesperframe / ((double) frequencies[version][frequency]*(1+inputstereo));
-
-    if(!loadheader()) break;
-  }
+    frag_time = 0;
+    play_time = 0.0;
 }
 void
 MPEGaudio:: Volume(int vol)
diff -Naur smpeg/gtv.c smpeg-seek/gtv.c
--- smpeg/gtv.c	Tue May 16 17:46:20 2000
+++ smpeg-seek/gtv.c	Thu May 11 13:37:25 2000
@@ -665,13 +665,9 @@
 
     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
 
-#if 1
-#warning Seeking is not implemented yet
-#else
     if( mpeg && mpeg_size ) {
         SMPEG_seek(mpeg, (int)((mpeg_size*adjust->value)/100));
     }
-#endif
 }
 
 static void gtv_set_frame( gpointer raw, int value )
diff -Naur smpeg/plaympeg.c smpeg-seek/plaympeg.c
--- smpeg/plaympeg.c	Tue May 16 17:46:20 2000
+++ smpeg-seek/plaympeg.c	Sat May 13 00:52:42 2000
@@ -52,7 +52,7 @@
 "	--loop or -l	     Play MPEG over and over\n"
 "	--volume N or -v N   Set audio volume to N (0-100)\n"
 "	--scale wxh or -s wxh  Play MPEG at given resolution\n"
-"       --skip N or -S N     Skip N seconds\n"
+"       --seek N or -S N     Skip N bytes\n"
 "	--help or -h\n"
 "	--version or -V\n"
 "Specifying - as filename will use stdin for input\n", argv0);
@@ -83,7 +83,7 @@
     int loop_play;
     int i, done, pause;
     int volume;
-    float skip;
+    float seek;
     SDL_Surface *screen;
     SMPEG *mpeg;
     SMPEG_Info info;
@@ -100,7 +100,7 @@
     scale_height = 0;
     loop_play = 0;
     volume = 100;
-    skip = 0;
+    seek = 0;
     for ( i=1; argv[i] && (argv[i][0] == '-') && (argv[i][1] != 0); ++i ) {
         if ( (strcmp(argv[i], "--noaudio") == 0) ||
              (strcmp(argv[i], "--nosound") == 0) ) {
@@ -118,10 +118,10 @@
         if ((strcmp(argv[i], "--loop") == 0) || (strcmp(argv[i], "-l") == 0)) {
             loop_play = 1;
         } else
-        if ((strcmp(argv[i], "--skip") == 0)||(strcmp(argv[i], "-S") == 0)) {
+        if ((strcmp(argv[i], "--seek") == 0)||(strcmp(argv[i], "-S") == 0)) {
             ++i;
             if ( argv[i] ) {
-                skip = (float)atof(argv[i]);
+                seek = (float)atof(argv[i]);
             }
         } else
         if ((strcmp(argv[i], "--volume") == 0)||(strcmp(argv[i], "-v") == 0)) {
@@ -299,6 +299,9 @@
 	    printf("\tAudio %s\n", info.audio_string);
         }
 
+	/* Print info on the stream */
+	printf("\t Total size: %d\n", SMPEG_total_size(mpeg));
+
         /* Set up video display if needed */
         if ( info.has_video && use_video ) {
             const SDL_VideoInfo *video_info;
@@ -352,10 +355,10 @@
         if ( loop_play ) {
             SMPEG_loop(mpeg, 1);
         }
-	
-	/* Skip to starting position */
-	if(skip) SMPEG_skip(mpeg, skip);
 
+	/* Skip to starting position */
+	if(seek) SMPEG_seek(mpeg, seek);
+	
         /* Play it, and wait for playback to complete */
         SMPEG_play(mpeg);
         done = 0;
diff -Naur smpeg/smpeg.cpp smpeg-seek/smpeg.cpp
--- smpeg/smpeg.cpp	Tue May 16 17:46:20 2000
+++ smpeg-seek/smpeg.cpp	Sat May 13 00:49:39 2000
@@ -207,10 +207,24 @@
     mpeg->obj->Rewind();
 }
 
-/* Skip 'seconds' seconds of the MPEG */
-void SMPEG_skip( SMPEG* mpeg, float seconds )
+/* Seek 'bytes' bytes of the MPEG */
+void SMPEG_seek( SMPEG* mpeg, int bytes )
 {
-    mpeg->obj->Skip(seconds);
+  mpeg->obj->Seek(bytes);
+}
+
+/* Tell the current position in the stream in bytes */
+/* Warning: this is 32 bit values so streams > 4Go will return bad values */
+Uint32 SMPEG_tell( SMPEG* mpeg )
+{
+  return(mpeg->obj->Tell());
+}
+
+/* Return the total size of the stream in bytes (O if unapplicable) */
+/* Warning: this is 32 bit values so streams > 4Go will return bad values */
+Uint32 SMPEG_total_size( SMPEG* mpeg )
+{
+  return(mpeg->obj->TotalSize());
 }
 
 /* Render a particular frame in the MPEG video */
diff -Naur smpeg/smpeg.h smpeg-seek/smpeg.h
--- smpeg/smpeg.h	Tue May 16 17:46:20 2000
+++ smpeg-seek/smpeg.h	Sat May 13 00:50:19 2000
@@ -142,8 +142,16 @@
 /* Rewind the play position of an SMPEG object to the beginning of the MPEG */
 extern DECLSPEC void SMPEG_rewind( SMPEG* mpeg );
 
-/* Skip 'seconds' seconds of the MPEG stream */
-void DECLSPEC SMPEG_skip( SMPEG* mpeg, float seconds );
+/* Seek 'bytes' bytes in the MPEG stream */
+void SMPEG_seek( SMPEG* mpeg, int bytes);
+
+/* Tell the current position in the stream in bytes */
+/* Warning: this is 32 bit values so streams > 4Go will return bad values */
+Uint32 SMPEG_tell( SMPEG* mpeg );
+
+/* Return the total size of the stream in bytes (O if unapplicable) */
+/* Warning: this is 32 bit values so streams > 4Go will return bad values */
+Uint32 SMPEG_total_size( SMPEG* mpeg );
 
 /* Render a particular frame in the MPEG video
    API CHANGE: This function no longer takes a target surface and position.
diff -Naur smpeg/video/MPEGvideo.cpp smpeg-seek/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Tue May 16 17:46:59 2000
+++ smpeg-seek/video/MPEGvideo.cpp	Tue May 16 20:32:29 2000
@@ -296,27 +296,15 @@
     }
     play_time = 0.0;
 }
+
 void
-MPEGvideo::Skip(float seconds)
+MPEGvideo:: ResetSynchro(void)
 {
-  int frame;
-
-  printf("Video: Skipping %f seconds... please wait\n", seconds);  
-  frame = (int) (_fps * seconds);
-
-  if( _stream )
-  {
-    _stream->_jumpFrame = frame;
-    while( (_stream->totNumFrames < frame) &&
-	   ! _stream->film_has_ended )
-    {
-      mpegVidRsrc( 0, _stream, 0 );
-    }
-    _stream->_jumpFrame = -1;
-    _stream->realTimeStart = 0.0;
-    play_time = 0.0;
-  }
+  _stream->_jumpFrame = -1;
+  _stream->realTimeStart = 0.0;
+  play_time = 0.0;
 }
+
 MPEGstatus
 MPEGvideo:: Status(void)
 {
*************************************************************************
*** NOT Applied ***
Date: Sun, 07 May 2000 21:51:14 +0200
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
To: Sam Lantinga <hercules@lokigames.com>
CC: Manuel Estrada <ranty@soon.com>,
    Damien Chavarria <damien.chavarria@enst-bretagne.fr>
Subject: SMPEG skipping, synchronization timestamps, and more

Hi

        I've just finished integrating the synchronization patch from Manuel
and the skipping patch of Damien into one, and corrected a few things.
Manuel's patch didn't work for audio or video only streams so I fixed
it. I also fixed the problem with quitting that Rene H. Larsen raised. 
        It is a patch against the latest CVS version.

see ya,
Vivien.


diff -Naur smpeg/MPEG.cpp smpeg-seek-timestamp/MPEG.cpp
--- smpeg/MPEG.cpp	Tue May  2 09:11:18 2000
+++ smpeg-seek-timestamp/MPEG.cpp	Sun May  7 19:50:30 2000
@@ -101,8 +101,10 @@
 
 MPEG::~MPEG()
 {
-  if(audio) delete audio;
+  Stop();
+
   if(video) delete video;
+  if(audio) delete audio;
 
   if(system) delete system;
 
@@ -175,23 +177,7 @@
 }
 
 void MPEG::Rewind(void) {
-  Stop();
-
-  /* Go to the beginning of the file */
-  system->Rewind();
-
-  /* Skip the first empty buffer made when creating a mpegstream */
-  /* which would otherwise be interpreted as end of file */
-  if(audiostream) audiostream->next_packet();
-  if(videostream) videostream->next_packet();
-
-  if ( AudioEnabled() ) {
-    audioaction->Rewind();
-  }
-
-  if ( VideoEnabled() ) {
-    videoaction->Rewind();
-  }
+  seekIntoStream(0);
 }
 
 void MPEG::Pause(void) {
@@ -257,6 +243,7 @@
   return(status);
 }
 
+
 /* MPEG audio actions */
 bool MPEG::GetAudioInfo(MPEG_AudioInfo *info) {
   if ( AudioEnabled() ) {
@@ -328,16 +315,64 @@
 
   if( audiostream ) audiostream->enable(true);
 }
-
+  
 void MPEG::Skip(float seconds)
 {
+  if(system->get_stream(SYSTEM_STREAMID))
+  {
+    system->Skip(seconds);
+  }
+  else
+  {
+    /* No system information in MPEG */
+    if( VideoEnabled() ) videoaction->Skip(seconds);
+    if( AudioEnabled() ) audioaction->Skip(seconds);
+  }
+}
+
+void MPEG::Seek(int position)
+{
+  int were_playing = 0;
+  
+  /* get info wether we need to restart playing at the end */
+  if( Status() == MPEG_PLAYING )
+    were_playing = 1;
+
+  seekIntoStream(position);
+
+  /* If we were playing and not rewind then play again */
+  if (were_playing)
+    Play();
+}
+
+void MPEG::seekIntoStream(int position)
+{
+  double time;
+
+  /* First we stop everything */
+  Stop();
+
+  /* Go to the desired position into file */
+  time = system->Seek(position);
+
+  /* Skip the first empty buffer made when creating a mpegstream */
+  /* which would otherwise be interpreted as end of file */
+
+  if(audiostream) audiostream->next_packet();
+  if(videostream) videostream->next_packet();
+
+  /* And forget what we previouly buffered */
+
   if ( AudioEnabled() ) {
-    audioaction->Skip(seconds);
+    audioaction->Rewind();
+    audioaction->ResetSynchro(time);
   }
 
   if ( VideoEnabled() ) {
-    videoaction->Skip(seconds);
+    videoaction->Rewind();
+    videoaction->ResetSynchro(time);
   }
+
 }
 
 void MPEG::parse_stream_list()
diff -Naur smpeg/MPEG.h smpeg-seek-timestamp/MPEG.h
--- smpeg/MPEG.h	Tue May  2 09:11:18 2000
+++ smpeg-seek-timestamp/MPEG.h	Sun May  7 15:49:10 2000
@@ -68,6 +68,7 @@
     void Stop(void);
     void Rewind(void);
     void Pause(void);
+    void Seek(int bytes);
     void Skip(float seconds);
     MPEGstatus Status(void);
 
@@ -113,6 +114,7 @@
     bool pause;
 
     void parse_stream_list();
+    void seekIntoStream(int position);
 };
 
 #endif /* _MPEG_H_ */
diff -Naur smpeg/MPEGaction.h smpeg-seek-timestamp/MPEGaction.h
--- smpeg/MPEGaction.h	Tue May  2 09:11:18 2000
+++ smpeg-seek-timestamp/MPEGaction.h	Sun May  7 16:30:45 2000
@@ -47,6 +47,7 @@
     virtual void Play(void) = 0;
     virtual void Stop(void) = 0;
     virtual void Rewind(void) = 0;
+    virtual void ResetSynchro(double time) = 0;
     virtual void Skip(float seconds) = 0;
     virtual void Pause(void) {  /* A toggle action */
         if ( paused ) {
diff -Naur smpeg/MPEGaudio.h smpeg-seek-timestamp/MPEGaudio.h
--- smpeg/MPEGaudio.h	Thu Apr  6 01:53:17 2000
+++ smpeg-seek-timestamp/MPEGaudio.h	Sun May  7 16:31:27 2000
@@ -167,6 +167,7 @@
     void Play(void);
     void Stop(void);
     void Rewind(void);
+    void ResetSynchro(double time);
     void Skip(float seconds);
     void Volume(int vol);
     MPEGstatus Status(void);
@@ -246,7 +247,7 @@
   /*******************/
 public:
   void initialize();
-  bool run(int frames);
+  bool run(int frames, double *timestamp = NULL);
   void clearbuffer(void);
 
   /*****************************/
diff -Naur smpeg/MPEGlist.h smpeg-seek-timestamp/MPEGlist.h
--- smpeg/MPEGlist.h	Thu Apr  6 01:53:17 2000
+++ smpeg-seek-timestamp/MPEGlist.h	Sun May  7 14:56:53 2000
@@ -33,6 +33,8 @@
 
   inline Uint32 IsLocked() { return(lock); };
 
+  double TimeStamp;
+
 private:
   class MPEGlist * next;
   class MPEGlist * prev;
diff -Naur smpeg/MPEGring.cpp smpeg-seek-timestamp/MPEGring.cpp
--- smpeg/MPEGring.cpp	Tue May  2 09:11:18 2000
+++ smpeg-seek-timestamp/MPEGring.cpp	Sun May  7 14:56:53 2000
@@ -36,9 +36,10 @@
     ring = this;
 
     tSize = (size + sizeof(Uint32)) * count;
-    if( tSize )
+    if( tSize ){
         ring->begin = (Uint8 *) malloc( tSize );
-    else
+        ring->timestamps = (double *) malloc( sizeof(double)*count);
+    }else
         ring->begin = 0;
 
     if( ring->begin && count )
@@ -46,6 +47,8 @@
         ring->end   = ring->begin + tSize;
         ring->read  = ring->begin;
         ring->write = ring->begin;
+        ring->timestamp_read  = timestamps;
+        ring->timestamp_write = timestamps;
         ring->bufSize  = size;
         
         ring->readwait = SDL_CreateSemaphore(0);
@@ -103,7 +106,9 @@
         /* Free data buffer */
         if ( ring->begin ) {
             free( ring->begin );
+            free( ring->timestamps );
             ring->begin = 0;
+            ring->timestamps = 0;
         }
     }
 }
@@ -137,16 +142,18 @@
 */
 
 void
-MPEG_ring:: WriteDone( Uint32 len )
+MPEG_ring:: WriteDone( Uint32 len, double timestamp=-1 )
 {
     if ( ring->active ) {
         assert(len <= ring->bufSize);
         *((Uint32*) ring->write) = len;
 
         ring->write += ring->bufSize + sizeof(Uint32);
+        *(ring->timestamp_write++) = timestamp;
         if( ring->write >= ring->end )
         {
             ring->write = ring->begin;
+            ring->timestamp_write = ring->timestamps;
         }
 //printf("Finished write buffer, making available for reads (%d+1 available for reads)\n", SDL_SemValue(ring->readwait));
         SDL_SemPost(ring->readwait);
@@ -184,7 +191,11 @@
   MPRing_nextReadBuffer(), and want to update it so the rest of the data
   is returned with the next call to MPRing_nextReadBuffer().
 */
-
+double
+MPEG_ring:: ReadTimeStamp(void)
+{
+    return *ring->timestamp_read;
+}
 void
 MPEG_ring:: ReadSome( Uint32 used )
 {
@@ -199,6 +210,7 @@
         memcpy(data, data+used, newlen);
         *((Uint32*) ring->read) = newlen;
 //printf("Reusing read buffer (%d+1 available)\n", SDL_SemValue(ring->readwait));
+        *ring->timestamp_read = -1;
         SDL_SemPost(ring->readwait);
     }
 }
@@ -214,9 +226,11 @@
 {
     if ( ring->active ) {
         ring->read += ring->bufSize + sizeof(Uint32);
+        ring->timestamp_read++;
         if( ring->read >= ring->end )
         {
             ring->read = ring->begin;
+            ring->timestamp_read = ring->timestamps;
         }
 //printf("Finished read buffer, making available for writes (%d+1 available for writes)\n", SDL_SemValue(ring->writewait));
         SDL_SemPost(ring->writewait);
diff -Naur smpeg/MPEGring.h smpeg-seek-timestamp/MPEGring.h
--- smpeg/MPEGring.h	Tue May  2 09:11:18 2000
+++ smpeg-seek-timestamp/MPEGring.h	Sun May  7 14:56:53 2000
@@ -54,11 +54,14 @@
     Uint8 *NextWriteBuffer( void );
 
     /* Release a buffer, written to in the ring */
-    void WriteDone( Uint32 len );
+    void WriteDone( Uint32 len, double timestamp=-1 );
 
     /* Reserve a buffer for reading in the ring */
     Uint32 NextReadBuffer( Uint8** buffer );
 
+    /* Read the timestamp of the current buffer */
+    double ReadTimeStamp(void);
+
     /* Release a buffer having read some of it */
     void ReadSome( Uint32 used );
 
@@ -74,6 +77,10 @@
     /* private */
     Uint8 *begin;
     Uint8 *end;
+
+    double *timestamps;
+    double *timestamp_read;
+    double *timestamp_write;
 
     Uint8 *read;
     Uint8 *write;
diff -Naur smpeg/MPEGstream.cpp smpeg-seek-timestamp/MPEGstream.cpp
--- smpeg/MPEGstream.cpp	Tue Apr 11 19:27:19 2000
+++ smpeg-seek-timestamp/MPEGstream.cpp	Sun May  7 14:56:53 2000
@@ -114,7 +114,7 @@
     system->RequestBuffer();
     while(!br->Next() && timeout--)
       SDL_Delay(1);
-    if(!timeout) return(false);
+    if(timeout<=0) return(false);
     SDL_mutexP(mutex);
   }
 
@@ -157,6 +157,7 @@
   /* Update stream datas */
   data = (Uint8 *) br->Buffer();
   stop = data + br->Size();
+  timestamp = br->TimeStamp;
 
   SDL_mutexV(mutex);
 
@@ -286,7 +287,7 @@
   return(!br->Size());
 }
 
-void MPEGstream::insert_packet(Uint8 * Data, Uint32 Size)
+void MPEGstream::insert_packet(Uint8 * Data, Uint32 Size, double timestamp=-1)
 {
   MPEGlist * newbr;
 
@@ -304,6 +305,7 @@
   newbr = newbr->Alloc(Size);
 
   memcpy(newbr->Buffer(), Data, Size);
+  newbr->TimeStamp = timestamp;
 
   SDL_mutexV(mutex);
   garbage_collect();
diff -Naur smpeg/MPEGstream.h smpeg-seek-timestamp/MPEGstream.h
--- smpeg/MPEGstream.h	Tue Apr 11 19:27:19 2000
+++ smpeg-seek-timestamp/MPEGstream.h	Sun May  7 14:56:53 2000
@@ -74,7 +74,7 @@
     bool eof(void) const;
 
     /* Insert a new packet at the end of the stream */
-    void insert_packet(Uint8 * data, Uint32 size);
+    void insert_packet(Uint8 * data, Uint32 size, double timestamp=-1);
 
     /* Check for unused buffers and free them */
     void garbage_collect(void);
@@ -102,6 +102,8 @@
     bool looping;
 
     SDL_mutex * mutex;
+public:
+    double timestamp;
 };
 
 #endif /* _MPEGSTREAM_H_ */
diff -Naur smpeg/MPEGsystem.cpp smpeg-seek-timestamp/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Tue May  2 09:11:18 2000
+++ smpeg-seek-timestamp/MPEGsystem.cpp	Sun May  7 18:23:21 2000
@@ -39,11 +39,8 @@
 
 /* The size is arbitrary but should be sufficient to contain */
 /* two MPEG packets and reduce disk (or network) access.     */
-#if 0 // Hiroshi Yamashita notes that the original size was too large
-#define MPEG_BUFFER_SIZE (64 * 1024)
-#else
-#define MPEG_BUFFER_SIZE (16 * 1024)
-#endif
+// Hiroshi Yamashita notes that the original size was too large
+#define MPEG_BUFFER_SIZE (16 * 1024) 
 
 /* The granularity (2^LG2_GRANULARITY) determine what length of read data */
 /* will be a multiple of, e.g. setting LG2_GRANULARITY to 12 will make    */
@@ -105,6 +102,7 @@
 #ifdef USE_SYSTEM_TIMESTAMP
   timestamp = 0.0;
   timedrift = 0.0;
+  skip_timestamp = 0.0;
 #endif
 
   /* Search the MPEG for the first header */
@@ -406,6 +404,19 @@
 
   assert(packet_size <= MPEG_BUFFER_SIZE);
 
+  if(skip_timestamp > timestamp){
+    int cur_seconds=int(timestamp)%60;
+
+    if (cur_seconds%5==0){
+      fprintf(stderr, "Skiping to %02d:%02d (%02d:%02d)\r",
+              int(skip_timestamp)/60, int(skip_timestamp)%60,
+              int(timestamp)/60, cur_seconds);
+    }
+    pointer += packet_size;
+    /* since we skip data, request more */
+    RequestBuffer();
+    return (1);
+  }
   switch(stream_id)
   {
     case 0:
@@ -473,11 +484,17 @@
       }
 
       /* Insert the new data at the end of the stream */
-      stream->insert_packet(pointer, packet_size);
+      stream->insert_packet(pointer, packet_size, timestamp);
       pointer += packet_size;
     return(stream_id);
   }
 }
+void MPEGsystem::Skip(double time)
+{
+  if (skip_timestamp < timestamp)
+    skip_timestamp = timestamp;
+  skip_timestamp += time;
+}
 
 Uint32 MPEGsystem::Tell()
 {
@@ -487,6 +504,11 @@
 
 void MPEGsystem::Rewind()
 {
+  Seek(0);
+}
+
+double MPEGsystem::Seek(int length)
+{
   request = 0;
 
   /* Force the system thread to die */
@@ -496,15 +518,15 @@
   /* Reset the streams */
   reset_all_streams();
 
-  /* Get back to the beginning of the stream */
-  if(lseek(mpeg_fd, 0, SEEK_SET) == (long) -1)
+  /* Get into the stream */
+  if(lseek(mpeg_fd, length, SEEK_SET) == (off_t) -1)
   {
     if(errno != ESPIPE)
     {
       errorstream = true;
       SetError(strerror(errno));
     }
-    return;
+    return (0);
   }
 
   /* Reinitialize the read buffer */
@@ -520,7 +542,7 @@
   {
     errorstream = true;
     SetError("Could not find the beginning of MPEG data\n");
-    return;
+    return (0);
   }
 
   request = PRE_BUFFERED_MAX;
@@ -536,6 +558,10 @@
   while(request > 0 && !Eof())
     SDL_Delay(1);
 
+  /* Get current play time */
+  FillBuffer();
+
+  return(timestamp);
 }
 
 void MPEGsystem::Loop(bool toggle)
@@ -608,7 +634,7 @@
     if(system->request > 0)
     {
       /* Read the buffer */
-      system->FillBuffer();
+      while (system->FillBuffer()==1) {};
       delay >>= 1;
     }
     else
diff -Naur smpeg/MPEGsystem.h smpeg-seek-timestamp/MPEGsystem.h
--- smpeg/MPEGsystem.h	Tue Apr 11 19:27:19 2000
+++ smpeg-seek-timestamp/MPEGsystem.h	Sun May  7 18:29:21 2000
@@ -2,6 +2,7 @@
 
 #ifndef _MPEGSYSTEM_H_
 #define _MPEGSYSTEM_H_
+#define USE_SYSTEM_TIMESTAMP
 
 #include "SDL.h"
 #include "SDL_thread.h"
@@ -27,20 +28,13 @@
     void Rewind();
     void Loop(bool toggle);
     bool Eof() const;
+    double Seek(int length);
+    /* Skip "seconds" seconds */
+    void Skip(double seconds);
 
     /* Create all the streams present in the MPEG */
     MPEGstream ** GetStreamList();
 
-protected:
-    /* Fill a buffer */
-    Uint8 FillBuffer();
-
-    /* Read a new packet */
-    void Read();
-
-    /* The system thread which fills the FIFO */
-    static int SystemThread(void * udata);
-
     /* Insert a stream in the list */
     void add_stream(MPEGstream * stream);
 
@@ -62,6 +56,16 @@
     /* Seek the next header */
     bool seek_next_header();
 
+protected:
+    /* Fill a buffer */
+    Uint8 FillBuffer();
+
+    /* Read a new packet */
+    void Read();
+
+    /* The system thread which fills the FIFO */
+    static int SystemThread(void * udata);
+
     int mpeg_fd;
 
     SDL_Thread * system_thread;
@@ -84,6 +88,7 @@
     /* Current timestamp for this stream */
     double timestamp;
     double timedrift;
+    double skip_timestamp;
 #endif
 };
 #endif
diff -Naur smpeg/MPEGvideo.h smpeg-seek-timestamp/MPEGvideo.h
--- smpeg/MPEGvideo.h	Tue May  2 09:11:18 2000
+++ smpeg-seek-timestamp/MPEGvideo.h	Sun May  7 16:31:01 2000
@@ -57,6 +57,7 @@
     void Play(void);
     void Stop(void);
     void Rewind(void);
+    void ResetSynchro(double time);
     void Skip(float seconds);
     MPEGstatus Status(void);
 
diff -Naur smpeg/audio/MPEGaudio.cpp smpeg-seek-timestamp/audio/MPEGaudio.cpp
--- smpeg/audio/MPEGaudio.cpp	Tue May  2 09:11:19 2000
+++ smpeg-seek-timestamp/audio/MPEGaudio.cpp	Sun May  7 19:51:00 2000
@@ -72,6 +72,7 @@
 {
     /* Remove ourselves from the mixer hooks */
     Stop();
+
 #ifdef THREADED_AUDIO
     /* Stop the decode thread */
     StopDecoding();
@@ -147,6 +148,9 @@
 MPEGaudio:: StopDecoding(void)
 {
     decoding = false;
+    if ( ring ) {
+      ring->ReleaseThreads();
+    }
     if ( decode_thread ) {
         SDL_WaitThread(decode_thread, NULL);
         decode_thread = NULL;
@@ -167,7 +171,7 @@
     if ( frag_time ) {
         now = (play_time + (double)(SDL_GetTicks() - frag_time)/1000.0);
     } else {
-        now = 0.0;
+        now = play_time;
     }
     return now;
 }
@@ -206,12 +210,18 @@
     currentframe = 0;
     frags_playing = 0;
     frag_time = 0;
-    play_time = 0.0;
 }
 void
+MPEGaudio:: ResetSynchro(double time)
+{
+    play_time = time;
+}
+
+void
 MPEGaudio:: Skip(float seconds)
 {
-  printf("Audio: Skipping %f seconds...\n", seconds);  
+  /* Called only when there is no timestamp info in the MPEG */
+  printf("Audio: Skipping %f seconds...\n", seconds);
   while(seconds > 0)
   {
     seconds -= (double) samplesperframe / ((double) frequencies[version][frequency]*(1+inputstereo));
@@ -219,6 +229,7 @@
     if(!loadheader()) break;
   }
 }
+
 void
 MPEGaudio:: Volume(int vol)
 {
diff -Naur smpeg/audio/mpegtoraw.cpp smpeg-seek-timestamp/audio/mpegtoraw.cpp
--- smpeg/audio/mpegtoraw.cpp	Tue May  2 09:11:19 2000
+++ smpeg-seek-timestamp/audio/mpegtoraw.cpp	Sun May  7 19:49:42 2000
@@ -265,14 +265,22 @@
 }
 
 
-bool MPEGaudio::run( int frames )
+bool MPEGaudio::run( int frames, double *timestamp = NULL)
 {
+    double last_timestamp = -1;
+    int totFrames = frames;
     for( ; frames; frames-- )
     {
         if( loadheader() == false ) {
 	  return false;	  
         }
 
+        if (frames == totFrames  && timestamp != NULL)
+            if (last_timestamp != mpeg->timestamp)
+                last_timestamp = *timestamp = mpeg->timestamp;
+            else
+                *timestamp = -1;
+
         if     ( layer == 3 ) extractlayer3();
         else if( layer == 2 ) extractlayer2();
         else if( layer == 1 ) extractlayer1();
@@ -304,13 +312,14 @@
 int Decode_MPEGaudio(void *udata)
 {
     MPEGaudio *audio = (MPEGaudio *)udata;
+    double timestamp;
 
     while ( audio->decoding && ! audio->mpeg->eof() ) {
         audio->rawdata = (Sint16 *)audio->ring->NextWriteBuffer();
         if ( audio->rawdata ) {
             audio->rawdatawriteoffset = 0;
-            audio->run(1);
-            audio->ring->WriteDone(audio->rawdatawriteoffset*2);
+            audio->run(1, &timestamp);
+            audio->ring->WriteDone(audio->rawdatawriteoffset*2, timestamp);
         }
     }
     audio->decoding = false;
@@ -362,6 +371,26 @@
     assert(audio->ring);
     do {
         copylen = audio->ring->NextReadBuffer(&rbuf);
+        double timestamp = audio->ring->ReadTimeStamp();
+	if (timestamp >= 0){
+	    double timeshift = fabs(audio->play_time - timestamp);
+	    double correction = 0;
+
+	    if (timeshift > 0.3)
+	        correction = timeshift;
+            else
+	        correction = timeshift/1000;
+
+	    if (audio->play_time < timestamp)
+                audio->play_time += correction;
+            else
+                audio->play_time -= correction;
+#if 0
+	    fprintf(stderr, "%.3f\t%.4f\r",
+	                     audio->play_time - timestamp,
+	                     correction);
+#endif
+	}
         if ( copylen > len ) {
             SDL_MixAudio(stream, rbuf, len, volume);
             audio->ring->ReadSome(len);
diff -Naur smpeg/plaympeg.c smpeg-seek-timestamp/plaympeg.c
--- smpeg/plaympeg.c	Tue May  2 09:11:19 2000
+++ smpeg-seek-timestamp/plaympeg.c	Sun May  7 19:50:45 2000
@@ -52,7 +52,8 @@
 "	--loop or -l	     Play MPEG over and over\n"
 "	--volume N or -v N   Set audio volume to N (0-100)\n"
 "	--scale wxh or -s wxh  Play MPEG at given resolution\n"
-"       --skip N or -S N     Skip N seconds\n"
+"       --seek N             Skip N bytes\n"
+"       --skip N             Skip N seconds\n"
 "	--help or -h\n"
 "	--version or -V\n"
 "Specifying - as filename will use stdin for input\n", argv0);
@@ -83,6 +84,7 @@
     int loop_play;
     int i, done, pause;
     int volume;
+    int seek;
     float skip;
     SDL_Surface *screen;
     SMPEG *mpeg;
@@ -100,7 +102,8 @@
     scale_height = 0;
     loop_play = 0;
     volume = 100;
-    skip = 0;
+    seek = 0;
+    skip = 0.0;
     for ( i=1; argv[i] && (argv[i][0] == '-') && (argv[i][1] != 0); ++i ) {
         if ( (strcmp(argv[i], "--noaudio") == 0) ||
              (strcmp(argv[i], "--nosound") == 0) ) {
@@ -118,10 +121,16 @@
         if ((strcmp(argv[i], "--loop") == 0) || (strcmp(argv[i], "-l") == 0)) {
             loop_play = 1;
         } else
-        if ((strcmp(argv[i], "--skip") == 0)||(strcmp(argv[i], "-S") == 0)) {
+	if ((strcmp(argv[i], "--seek") == 0)) {
             ++i;
             if ( argv[i] ) {
-                skip = (float)atof(argv[i]);
+                seek = atoi(argv[i]);
+            }
+        } else
+	if ((strcmp(argv[i], "--skip") == 0)) {
+            ++i;
+            if ( argv[i] ) {
+                skip = (float) atof(argv[i]);
             }
         } else
         if ((strcmp(argv[i], "--volume") == 0)||(strcmp(argv[i], "-v") == 0)) {
@@ -352,10 +361,12 @@
         if ( loop_play ) {
             SMPEG_loop(mpeg, 1);
         }
-	
-	/* Skip to starting position */
-	if(skip) SMPEG_skip(mpeg, skip);
 
+	/* Seek starting position */
+	if(seek) SMPEG_seek(mpeg, seek);
+	/* Skip seconds to starting position */
+	if(skip) SMPEG_skip(mpeg, skip);
+	
         /* Play it, and wait for playback to complete */
         SMPEG_play(mpeg);
         done = 0;
@@ -432,11 +443,11 @@
 			} else if ( event.key.keysym.sym == SDLK_RIGHT ) {
 			  // Forward
 			  if ( event.key.keysym.mod & KMOD_SHIFT ) {
-
+			    SMPEG_skip(mpeg, 100);
 			  } else if ( event.key.keysym.mod & KMOD_CTRL ) {
-
+			    SMPEG_skip(mpeg, 50);
 			  } else {
-			    
+			    SMPEG_skip(mpeg, 5);
 			  }
                         } else if ( event.key.keysym.sym == SDLK_LEFT ) {
 			  // Reverse
@@ -466,6 +477,7 @@
             }
             SDL_Delay(1000/2);
         }
+
         SMPEG_delete(mpeg);
     }
     SDL_Quit();
diff -Naur smpeg/smpeg.cpp smpeg-seek-timestamp/smpeg.cpp
--- smpeg/smpeg.cpp	Tue May  2 09:11:19 2000
+++ smpeg-seek-timestamp/smpeg.cpp	Sun May  7 15:33:15 2000
@@ -210,7 +210,13 @@
 /* Skip 'seconds' seconds of the MPEG */
 void SMPEG_skip( SMPEG* mpeg, float seconds )
 {
-    mpeg->obj->Skip(seconds);
+  mpeg->obj->Skip(seconds);
+}
+
+/* Seek 'bytes' bytes of the MPEG */
+void SMPEG_seek( SMPEG* mpeg, int bytes )
+{
+  mpeg->obj->Seek(bytes);
 }
 
 /* Render a particular frame in the MPEG video */
diff -Naur smpeg/smpeg.h smpeg-seek-timestamp/smpeg.h
--- smpeg/smpeg.h	Tue May  2 09:11:19 2000
+++ smpeg-seek-timestamp/smpeg.h	Sun May  7 15:34:18 2000
@@ -142,8 +142,11 @@
 /* Rewind the play position of an SMPEG object to the beginning of the MPEG */
 extern DECLSPEC void SMPEG_rewind( SMPEG* mpeg );
 
-/* Skip 'seconds' seconds of the MPEG stream */
-void DECLSPEC SMPEG_skip( SMPEG* mpeg, float seconds );
+/* Skip 'seconds' seconds of the MPEG */
+void SMPEG_skip( SMPEG* mpeg, float seconds );
+
+/* Seek 'bytes' bytes in the MPEG stream */
+void SMPEG_seek( SMPEG* mpeg, int bytes );
 
 /* Render a particular frame in the MPEG video
    API CHANGE: This function no longer takes a target surface and position.
diff -Naur smpeg/video/MPEGvideo.cpp smpeg-seek-timestamp/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Tue May  2 09:11:19 2000
+++ smpeg-seek-timestamp/video/MPEGvideo.cpp	Sun May  7 19:04:09 2000
@@ -296,12 +296,23 @@
     }
     play_time = 0.0;
 }
+
+void
+MPEGvideo:: ResetSynchro(double time)
+{
+  _stream->_jumpFrame = -1;
+  _stream->realTimeStart = 0.0;
+  play_time = time;
+}
+
 void
 MPEGvideo::Skip(float seconds)
 {
   int frame;
 
-  printf("Video: Skipping %f seconds... please wait\n", seconds);  
+  /* Called only when there is no timestamp info in the MPEG */
+  /* This is quite slow however */
+  printf("Video: Skipping %f seconds...\n", seconds);  
   frame = (int) (_fps * seconds);
 
   if( _stream )
@@ -312,11 +323,10 @@
     {
       mpegVidRsrc( 0, _stream, 0 );
     }
-    _stream->_jumpFrame = -1;
-    _stream->realTimeStart = 0.0;
-    play_time = 0.0;
+    ResetSynchro(0);
   }
 }
+
 MPEGstatus
 MPEGvideo:: Status(void)
 {
diff -Naur smpeg/video/gdith.cpp smpeg-seek-timestamp/video/gdith.cpp
--- smpeg/video/gdith.cpp	Tue May  2 09:11:19 2000
+++ smpeg-seek-timestamp/video/gdith.cpp	Sun May  7 19:24:06 2000
@@ -139,6 +139,7 @@
     } else {
         now = ReadSysClock() - vid_stream->realTimeStart;
     }
+
     return now;
 }
 
@@ -170,7 +171,13 @@
     }
 
     /* Update the current play time */
-    mpeg->play_time += vid_stream->_oneFrameTime;
+    if(vid_stream->timestamp == -1) vid_stream->timestamp_used = true;
+    if(vid_stream->timestamp_mark < vid_stream->buffer 
+       && !vid_stream->timestamp_used){
+       mpeg->play_time = vid_stream->timestamp;
+       vid_stream->timestamp_used = true;
+    } else
+       mpeg->play_time += vid_stream->_oneFrameTime;
 
     /* If we are looking for a particular frame... */
     if( vid_stream->_jumpFrame > -1 )
@@ -196,9 +203,8 @@
 
         /* Calculate the frame time relative to real time */
         time_behind = CurrentTime(vid_stream) - mpeg->Time();
-
 #ifdef DEBUG_MPEG_SCHEDULING
-//printf("Frame %d: frame time: %f, real time: %f, time behind: %f\n", vid_stream->totNumFrames, mpeg->Time(), CurrentTime(vid_stream), time_behind);
+printf("Frame %d: frame time: %f, real time: %f, time behind: %f\n", vid_stream->totNumFrames, mpeg->Time(), CurrentTime(vid_stream), time_behind);
 #endif
 
         /* Allow up to MAX_FUDGE_TIME of delay in output */
diff -Naur smpeg/video/readfile.cpp smpeg-seek-timestamp/video/readfile.cpp
--- smpeg/video/readfile.cpp	Tue Dec 21 18:17:35 1999
+++ smpeg-seek-timestamp/video/readfile.cpp	Sun May  7 19:21:35 2000
@@ -121,6 +121,10 @@
   
   num_read = vid_stream->_smpeg->mpeg->copy_data(mark, request);
 
+  vid_stream->timestamp = vid_stream->_smpeg->mpeg->timestamp;
+  vid_stream->timestamp_mark = (unsigned int *)mark;
+  vid_stream->timestamp_used = false;
+
   /* Paulo Villegas - 26/1/1993: Correction for 4-byte alignment */
   {
     int num_read_rounded;
diff -Naur smpeg/video/video.h smpeg-seek-timestamp/video/video.h
--- smpeg/video/video.h	Tue May  2 09:11:20 2000
+++ smpeg-seek-timestamp/video/video.h	Sun May  7 14:56:53 2000
@@ -304,6 +304,12 @@
   int timestamp_index;
 #endif
 /* SL - end of added variables */
+/* begining of added variables for system stream based sync */
+  double timestamp;
+  unsigned int *timestamp_mark;
+  bool timestamp_used;
+/* begining of added variables */
+
 
 } VidStream;   
 
*************************************************************************
*** Applied ***
Date: Tue, 18 Apr 2000 22:27:25 +0900
From: Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>
Subject: Re: layer2audio fix.

[...]

It is the modification of the problem about the synchronism 
of the video and audio. 
Video is a little delayed in about three minitues.
29.97 fps video has problem.
30.00 fps video not problem.

As for the details, see a patch(rate.diff).

#I am sorry in poor English. 

extra. plaympeg.diff
#plaympeg --printfps N videofile.mpg
printing fps every N seconds.
an average is output when a program is finished.

Thanks.

-----------------------------------------------
Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>

diff -Nru smpeg.old/video/MPEGvideo.cpp smpeg/video/MPEGvideo.cpp
--- smpeg.old/video/MPEGvideo.cpp	Sat Apr 15 05:31:15 2000
+++ smpeg/video/MPEGvideo.cpp	Tue Apr 18 21:20:20 2000
@@ -165,9 +165,13 @@
 	  case 1: _fps = 23.97; break;
 	  case 2: _fps = 24.00; break;
 	  case 3: _fps = 25.00; break;
-	  case 4: _fps = 29.90; break;
+	  case 4: _fps = 29.97; break;
 	  case 5: _fps = 30.00; break;
-	  default: _fps = 0.00; break;
+	  case 6: _fps = 50.00; break;
+	  case 7: _fps = 59.94; break;
+	  case 8: _fps = 60.00; break;
+	  case 9: _fps = 15.00; break;
+	  default: _fps = 30.00; break;
 	}
     } else {
         _w = 0;
diff -Nru smpeg.old/video/gdith.cpp smpeg/video/gdith.cpp
--- smpeg.old/video/gdith.cpp	Tue Apr 11 23:22:53 2000
+++ smpeg/video/gdith.cpp	Tue Apr 18 21:18:25 2000
@@ -85,7 +85,7 @@
 /* Cheat on Vid rates, round to 30, and use 30 if illegal value 
    Except for 9, where Xing means 15, and given their popularity, we'll
    be nice and do it */
-static int VidRateNum[16]={ 30, 24, 24, 25, 30, 30, 50, 60, 
+static double VidRateNum[16]={ 30, 23.97, 24, 25, 29.97, 30, 50, 59.94, 
                             60, 15, 30, 30, 30, 30, 30, 30 };
 
 #ifdef CALCULATE_FPS
diff -Nru smpeg.old/video/video.h smpeg/video/video.h
--- smpeg.old/video/video.h	Tue Apr 11 23:22:53 2000
+++ smpeg/video/video.h	Tue Apr 18 21:18:37 2000
@@ -288,7 +288,7 @@
   PictImage *ring[RING_BUF_SIZE];              /* Ring buffer of frames.     */
 
 /* KR - beginning of added variables */
-  int rate_deal;
+  double rate_deal;
   int _skipFrame;
   double _skipCount;
   int _jumpFrame;
*************************************************************************
*** Applied ***
Date: Thu, 06 Apr 2000 10:51:41 +0900
From: Atsushi Yamagata <yamagata@plathome.co.jp>
Subject: tiny patch for smpeg



This is a tiny patch for the locale in smpeg.
--- Atsushi Yamagata

--- gtv.c.locale	Thu Mar  2 00:22:45 2000
+++ gtv.c	Thu Apr  6 10:43:07 2000
@@ -728,6 +728,7 @@
 
     memset( &info, 0, sizeof( info ) );
     memset( &filename_buffer, 0, sizeof( gchar ) * FILENAME_BUFFER_SIZE );
+    gtk_set_locale();
     gtk_init( &argc, &argv );
 
     window = create_gtv_window( );
*************************************************************************
*** Applied ***
Date: Sun, 12 Mar 2000 03:18:09 +0900
From: Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>
Subject: layer2audio fix.


[Note: This fixes the Futurama videos!]

Hi.

  some movie is get SIGFPE exceptions on plaympeg.
  (Linux is No Exception. May Be Getting Noise.)

  add checking group10bits max size.
  (Possibly, better checking other tables,too group5bits,group3bits)

patch attached.(layer2.diff)

-----------------------------------------------
Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>

--- smpeg-0.3.3/audio/mpeglayer2.cpp	Thu Aug 26 13:37:52 1999
+++ smpeg-0.3.4/audio/mpeglayer2.cpp	Sun Mar 12 02:36:07 2000
@@ -615,6 +615,7 @@
 	    int code=getbits(codelength[LS][i]);
 
 	    code+=code<<1;
+if(code > 2184) {/*printf("fraction LS OverFlow code %d -> 2184 \n",code);*/code=2184;}
 	    s=group[LS][i]+code;
 
 	    fraction[LS][0][i]=s[0];
@@ -641,6 +642,7 @@
 	    int code=getbits(codelength[RS][i]);
 
 	    code+=code<<1;
+if(code > 2184) {/*printf("fraction RS OverFlow code %d -> 2184 \n",code);*/code=2184;}
 	    s=group[RS][i]+code;
 
 	    fraction[RS][0][i]=s[0];
*************************************************************************
*** Applied ***
Date: Wed, 29 Mar 2000 19:47:06 +0000
From: Vivien Chapplier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: Media Player


Sam Lantinga wrote:

> Could you send me an actual patch for the VCD stream detection code?

        No problem. It does also include the patch I sent (well, actually it
was a post) in the newsgroup today for playing video with width not
multiple of 16 (problems with horizontal synchronization). If you don't
want that code (actually this could be done better I think), just remove
it from the patch.

> Also, in this case, will the info structure properly have information
> about the unadvertised streams?  Much of our code looks at whether or
> not audio or video streams are available in the info struct before
> deciding whether or not to initialize audio and video.
        
        Hmm... well, it depends.
        If the unadvertised stream packet is within the range of the
prebuffered data, this will be ok, as the system will report that the
stream is here, as if it was declared in the system header. You might
then get any info you want of it, as the stream will be filled in
normally. However, if the packet is too far, the stream won't be
detected, as it would imply to parse the whole MPEG (not cool with
pipes). Anyway, most of the time, the stream starts a short time after
the system header so this will work (prebuffering is set to 256k
currently, you can change it in MPEGsystem.cpp and MPEGstream.cpp).
        New streams will be sent data, even if they were not detected during
initialization (e.g. there is a new stream at the middle of a long
movie). This means you can start playing them anyway afterwards.


> 
> Thanks!

You're welcome ;-)

Vivien.

diff -Naur smpeg/MPEGsystem.cpp smpeg.patched.20000329/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Wed Mar 29 21:11:35 2000
+++ smpeg.patched.20000329/MPEGsystem.cpp	Wed Mar 29 21:28:22 2000
@@ -447,10 +447,29 @@
       stream = get_stream(stream_id);
 
       if(!stream)
-      {
-	/* No stream found for packet, skip it */
-	pointer += packet_size;
-	return(stream_id);
+      {	
+	/* Hack to detect video or audio streams that are not declared in system header */
+	if ( ((stream_id & 0xF0) == VIDEO_STREAMID) && !exist_stream(stream_id, 0xFF) ) {
+#ifdef DEBUG_SYSTEM
+	  fprintf(stderr, "Undeclared video packet, creating a new video stream\n");
+#endif
+	    stream = new MPEGstream(this, stream_id);
+	    add_stream(stream);
+	}
+	else
+	if ( ((stream_id & 0xF0) == AUDIO_STREAMID) && !exist_stream(stream_id, 0xFF) ) {
+#ifdef DEBUG_SYSTEM
+	  fprintf(stderr, "Undeclared audio packet, creating a new audio stream\n");
+#endif
+	    stream = new MPEGstream(this, stream_id);
+	    add_stream(stream);
+	}
+	else
+	{
+	  /* No stream found for packet, skip it */
+	  pointer += packet_size;
+	  return(stream_id);
+	}
       }
 
       /* Insert the new data at the end of the stream */
diff -Naur smpeg/video/MPEGvideo.cpp smpeg.patched.20000329/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Wed Mar 29 21:11:35 2000
+++ smpeg.patched.20000329/video/MPEGvideo.cpp	Wed Mar 29 17:29:24 2000
@@ -162,8 +162,8 @@
 
         /* Get the width and height of the video */
         mpeg->copy_data(buf, 4);
-        _w = (buf[0]<<4)|(buf[1]>>4);     /* 12 bits of width */
-        _h = ((buf[1]&0xF)<<8)|buf[2];    /* 12 bits of height */
+        _w = (((buf[0]<<4)|(buf[1]>>4)) + 15) & ~15;    /* 12 bits of width */
+        _h = ((((buf[1]&0xF)<<8)|buf[2]) + 15) & ~15;   /* 12 bits of height */
 	switch(buf[3]&0xF)                /*  4 bits of fps */
 	{
 	  case 1: _fps = 23.97; break;
diff -Naur smpeg/video/video.cpp smpeg.patched.20000329/video/video.cpp
--- smpeg/video/video.cpp	Wed Mar 29 21:11:35 2000
+++ smpeg.patched.20000329/video/video.cpp	Wed Mar 29 17:21:21 2000
@@ -1242,12 +1242,12 @@
   /* Get horizontal size of image space. */
 
   get_bits12(data);
-  vid_stream->h_size = data;
+  vid_stream->h_size = (data + 15) & ~15;
 
   /* Get vertical size of image space. */
 
   get_bits12(data);
-  vid_stream->v_size = data;
+  vid_stream->v_size = (data + 15) & ~15;
 
   /* Calculate macroblock width and height of image space. */
 
*************************************************************************
*** Applied ***
Date: Mon, 20 Mar 2000 16:05:26 +0100
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: smpeg & streaming

Hi Sam!

        I've just finished correcting a few remaining bugs and memory
leaks in
my patch and I've been testing it during the week-end with Damien. I'm
sending you a patch to apply on the archive I've sent you on Thursday.
This corrects the Rewind function and the RenderFinal function.
        Damien is working on the skipping part, but we'll be waiting until
this patch is integrated and fully tested, so, what is the status on this
patch on your side? Did you successfully play all your mpegs? Is
performance ok?

regards,
Vivien.

diff -Naur smpeg/MPEG.cpp smpeg.patched/MPEG.cpp
--- smpeg/MPEG.cpp	Wed Mar 15 18:03:38 2000
+++ smpeg.patched/MPEG.cpp	Mon Mar 20 15:04:48 2000
@@ -175,6 +175,11 @@
   /* Go to the beginning of the file */
   system->Rewind();
 
+  /* Skip the first empty buffer made when creating a mpegstream */
+  /* which would otherwise be interpreted as end of file */
+  if(audiostream) audiostream->next_packet();
+  if(videostream) videostream->next_packet();
+
   if ( AudioEnabled() ) {
     audioaction->Rewind();
   }
@@ -291,14 +296,24 @@
   }
 }
 void MPEG::RenderFrame(int frame, SDL_Surface *dst, int x, int y) {
+  /* Prevent acces to the audio stream to avoid filling it */
+  if( audiostream ) audiostream->enable(false);
+
   if ( VideoEnabled() ) {
     videoaction->RenderFrame(frame, dst, x, y);
   }
+
+  if( audiostream ) audiostream->enable(true);
 }
 void MPEG::RenderFinal(SDL_Surface *dst, int x, int y) {
+  /* Prevent acces to the audio stream to avoid filling it */
+  if( audiostream ) audiostream->enable(false);
+
   if ( VideoEnabled() ) {
     videoaction->RenderFinal(dst, x, y);
   }
+
+  if( audiostream ) audiostream->enable(true);
 }
 
 void MPEG::Skip(float seconds)
diff -Naur smpeg/MPEGstream.cpp smpeg.patched/MPEGstream.cpp
--- smpeg/MPEGstream.cpp	Wed Mar 15 23:25:23 2000
+++ smpeg.patched/MPEGstream.cpp	Mon Mar 20 15:46:57 2000
@@ -37,13 +37,25 @@
   
   preread_size = 0;
   looping = false;
+  enabled = true;
   mutex = SDL_CreateMutex();
 }
 
 MPEGstream::~MPEGstream()
 {
+  MPEGlist * newbr;
+
   SDL_DestroyMutex(mutex);
-  delete br;
+
+  /* Free the list */
+  for(newbr = br; newbr->Prev(); newbr = newbr->Prev());
+
+  while(newbr->Next())
+  {
+    newbr = newbr->Next();
+    delete newbr->Prev();
+  }
+  delete newbr;
 }
 
 void
@@ -93,11 +105,16 @@
   br->Unlock();
 
   /* No more buffer ? */
-  while(!br->Next())
+  if(!br->Next())
   {
+    int timeout = 3000;
+
     /* Then ask the system to read a new buffer */
     SDL_mutexV(mutex);
     system->RequestBuffer();
+    while(!br->Next() && timeout--)
+      SDL_Delay(1);
+    if(!timeout) return(false);
     SDL_mutexP(mutex);
   }
 
@@ -135,10 +152,7 @@
 
   /* Make sure that we have read buffers in advance if possible */
   if(preread_size < MAX_QUEUE)
-  {
-    //printf("[%d] preread: %d\n", streamid, preread_size);
     system->RequestBuffer();
-  }
   
   /* Update stream datas */
   data = (Uint8 *) br->Buffer();
@@ -170,11 +184,11 @@
     /* Set up the mark */
     marker = new MPEGstream_marker;
     marker->marked_buffer = br;
-    marker->marked_data = data;
+    marker->marked_data = data+offset;
     marker->marked_stop = stop;
 
-    /* Lock the current buffer */
-    br->Lock();
+    /* Lock the new buffer */
+    marker->marked_buffer->Lock();
 
     SDL_mutexV(mutex);
 
@@ -187,13 +201,17 @@
     SDL_mutexP(mutex);
 
     if ( marker ) {
+        /* Release current buffer */
+        if(br->IsLocked())
+	{
+	  br->Unlock();
+       	  marker->marked_buffer->Lock();
+	}
+
         /* Reset the data positions */
 	br = marker->marked_buffer;
         data = marker->marked_data;
         stop = marker->marked_stop;
-
-        /* Release current buffer */
-	br->Unlock();
     }
 
     SDL_mutexV(mutex);
@@ -204,6 +222,7 @@
 void
 MPEGstream:: delete_marker(MPEGstream_marker const * marker)
 {
+    marker->marked_buffer->Unlock();
     delete marker;
 }
 
@@ -271,12 +290,13 @@
 {
   MPEGlist * newbr;
 
+  /* Discard all packets if not enabled */
+  if(!enabled) return;
+
   SDL_mutexP(mutex);
 
   preread_size += Size;
 
-  /* - Fill in a new buffer - */
-
   /* Seek the last buffer */
   for(newbr = br; newbr->Next(); newbr = newbr->Next());
 
@@ -285,22 +305,31 @@
 
   memcpy(newbr->Buffer(), Data, Size);
 
-  /* - Check for unused buffers and free them - */
+  SDL_mutexV(mutex);
+  garbage_collect();
+}
+
+/* - Check for unused buffers and free them - */
+void MPEGstream::garbage_collect(void)
+{
+  MPEGlist * newbr;
+
+  SDL_mutexP(mutex);  
+
+  br->Lock();
 
   /* First of all seek the first buffer */
   for(newbr = br; newbr->Prev(); newbr = newbr->Prev());
 
   /* Now free buffers until we find a locked buffer */
-  while(newbr->Next())
+  while(newbr->Next() && !newbr->IsLocked())
   {
     newbr = newbr->Next();
+    delete newbr->Prev();
+  }
 
-    if(newbr->Prev() == br) break;
+  br->Unlock();
 
-    /* Delete all unlocked buffers */
-    if(!newbr->Prev()->IsLocked())
-      delete newbr->Prev();
-  }
   SDL_mutexV(mutex);
 }
 
@@ -312,4 +341,9 @@
 bool MPEGstream::is_looping() const
 {
   return(looping);
+}
+
+void MPEGstream::enable(bool toggle)
+{
+  enabled = toggle;
 }
diff -Naur smpeg/MPEGstream.h smpeg.patched/MPEGstream.h
--- smpeg/MPEGstream.h	Wed Mar 15 19:17:06 2000
+++ smpeg.patched/MPEGstream.h	Mon Mar 20 15:04:48 2000
@@ -76,11 +76,17 @@
     /* Insert a new packet at the end of the stream */
     void insert_packet(Uint8 * data, Uint32 size);
 
+    /* Check for unused buffers and free them */
+    void garbage_collect(void);
+
     /* Set the looping flag */
     void loop(bool toggle);
 
     /* Check if the stream is looping */
     bool is_looping() const;
+
+    /* Enable or disable the stream */
+    void enable(bool toggle);
 
     Uint8 streamid;
 
diff -Naur smpeg/MPEGsystem.cpp smpeg.patched/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Thu Mar 16 02:50:59 2000
+++ smpeg.patched/MPEGsystem.cpp	Mon Mar 20 15:04:48 2000
@@ -517,12 +517,6 @@
   while(request > 0 && !Eof())
     SDL_Delay(1);
 
-  register int i;
-
-  /* Skip the first empty buffer made when creating a mpegstream */
-  /* which would otherwise be interpreted as end of file */
-  for(i = 0; stream_list[i]; i++)
-    stream_list[i]->next_packet();
 }
 
 void MPEGsystem::Loop(bool toggle)
@@ -533,7 +527,8 @@
 
 void MPEGsystem::RequestBuffer()
 {
-  request += MPEG_BUFFER_SIZE;
+  if(request < PRE_BUFFERED_MAX)
+    request += MPEG_BUFFER_SIZE;
 }
 
 bool MPEGsystem::Eof() const
@@ -571,7 +566,7 @@
       system->end_all_streams();
 
       /* Get back to the beginning of the stream if possible */
-      if(lseek(system->mpeg_fd, 0, SEEK_SET) == (off_t) -1);
+      if(lseek(system->mpeg_fd, 0, SEEK_SET) == (off_t) -1)
       {
 	if(errno != ESPIPE)
 	{
@@ -613,7 +608,6 @@
       usleep(delay++);
     }
   }
-  
   system->system_thread_running = false;
 
   return(true);
diff -Naur smpeg/video/MPEGvideo.cpp smpeg.patched/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Wed Mar 15 17:31:22 2000
+++ smpeg.patched/video/MPEGvideo.cpp	Mon Mar 20 15:04:48 2000
@@ -447,6 +447,7 @@
 
     if( _stream->totNumFrames > frame ) {
         mpeg->rewind_stream();
+	mpeg->next_packet();
         Rewind();
     }
 
@@ -478,10 +479,11 @@
     {
         /* Search for the last "group of pictures" start code */
         Uint32 start_code;
-	MPEGstream_marker const * marker;
-	
+	MPEGstream_marker const * marker, * oldmarker;
+
 	marker = 0;
         mpeg->rewind_stream();
+	mpeg->next_packet();
         start_code = mpeg->copy_byte();
         start_code <<= 8;
         start_code |= mpeg->copy_byte();
@@ -491,15 +493,18 @@
             start_code <<= 8;
             start_code |= mpeg->copy_byte();
             if ( start_code == GOP_START_CODE ) {
-	        if( marker ) mpeg->delete_marker( marker );
-                mpeg->new_marker(-4);
+	          oldmarker = marker;
+		  marker = mpeg->new_marker(-4);
+		  if( oldmarker ) mpeg->delete_marker( oldmarker );
+       		  mpeg->garbage_collect();
             }
         }
-
         /* Set the stream to the last spot marked */
         if ( ! mpeg->seek_marker( marker ) ) {
             mpeg->rewind_stream();
-        }
+	    mpeg->next_packet();
+	}
+
 	mpeg->delete_marker( marker );
         _stream->buf_length = 0;
         _stream->bit_offset = 0;
@@ -507,6 +512,7 @@
         /* Process all frames without displaying any */
         _stream->_skipFrame = 1;
         RenderFrame( INT_MAX, dst, x, y );
+	mpeg->garbage_collect();
     }
 
     /* Save original mpeg stream parameters */
*************************************************************************
*** Applied ***
Date: Thu, 16 Mar 2000 02:28:23 +0000
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: smpeg & streaming

Sam Lantinga wrote:

> > > We need it to loop exactly frame-to-frame.

        This is fixed.

> > That might even be better than what was in the original
> > version where I can notice a very small delay when the MPEG is being
> > rewinded.

        Well this is not better, but the same ;-)

> Sounds great.

        Works well, too.
 
> Sounds good to me.  I'm looking forward to your implementation. :)

        Here it is, I did what I said in the last mail, except for the
END_SEQUENCE codes, which are still passed to the decoder, but this is
ok.
        I also made some bugfixes:
                - When searching the first header, things such as
0xfff0ff... will no
more be interpreted as a MPEG audio header, I check the bitrate to see
if it is coherent. Thus it plays some MPEGs that my old version didn't
play (but the original did, I noticed it just this afternoon when
playing a clip).
                - I also changed the seek_next_header consequently and put
seek_next_header in the case the code for skipping stuffing bytes was
returning errorstream. Thus, it will not abort, but try to continue
playing.
                
        Consequently, smpeg now play more files than before (I have an
example
that I can send to you if you wish), and play some of them better (I've
an example too: the clip). In fact the clip that didn't play seems to be
encapsulated.
        I also tried to put random data after the end of the file and it
is
skipped correctly.

        Moreover, I added an option to plaympeg: when stating - as a file
to
play, it will use stdin as input (nicer for using pipes than having to
use mkfifo)

        I don't quite understand what you meant by 'integrating' so I sent
you
the my whole tar archive (don't know what you what that I use as the
original for making a patch). It is still based on the CVS version from
last Thursday. If you need something else tell me.

        Also, if you find some mpeg that you played that don't play
anymore
(unlikely), tell me, as it seems you have a lot more MPEGs than I have.

        Finally, I wanted to say that my code for connecting to a network
in
plaympeg is really ugly, and more or less a hack so that I can play the
network stream I encode, you should remove it in the final version and
wait until someone (why not me, but I have the first version of my
encoder to finish so that I can release it) does something better (with
ftp and http support for example). My skip function is not quite good
either, as it fills the mpegstreams and thus will eat all your memory if
skipping long times. As for playing VideoCDs, if someone knows the
ioctls to do, it is fairly easy to code I think.


        I'm sorry, there is a nasty ; that appeared line 574 in
MPEGsystem.h at
the end of the if. Please remove it (I didn't take care during my code
clean-up :-( )

      if(lseek(system->mpeg_fd, 0, SEEK_SET) == (off_t) -1);

                        ||
                        \/

      if(lseek(system->mpeg_fd, 0, SEEK_SET) == (off_t) -1)


regards,
Vivien.

diff -ruN -x CVS smpeg/MPEG.cpp smpeg.patched/MPEG.cpp
--- smpeg/MPEG.cpp	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/MPEG.cpp	Wed Mar 15 09:03:38 2000
@@ -127,9 +127,10 @@
       videoaction->SetTimeSource(NULL);
     }
   }
-
+/*
   if(audiostream)
     audiostream->enable(enabled);
+*/
 }
 bool MPEG::VideoEnabled(void) {
   return(videoaction_enabled);
@@ -144,14 +145,12 @@
   if ( videoaction && ! videoaction_enabled ) {
     videoaction->Stop();
   } 
-
-  if(videostream)
-    videostream->enable(enabled);
 }
 
 /* MPEG actions */
 void MPEG::Loop(bool toggle) {
   loop = toggle;
+  system->Loop(toggle);
 }
 void MPEG::Play(void) {
   if ( VideoEnabled() ) {
@@ -236,9 +235,6 @@
       }
     }
   }
-
-  // TEMP
-  //  printf("status : audio %d video %d\n", audioaction->Status()==MPEG_PLAYING, videoaction->Status()==MPEG_PLAYING);
 
   return(status);
 }
diff -ruN -x CVS smpeg/MPEGstream.cpp smpeg.patched/MPEGstream.cpp
--- smpeg/MPEGstream.cpp	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/MPEGstream.cpp	Wed Mar 15 14:25:23 2000
@@ -36,7 +36,7 @@
   stop = 0;
   
   preread_size = 0;
-  enabled = true;
+  looping = false;
   mutex = SDL_CreateMutex();
 }
 
@@ -66,7 +66,7 @@
   br = new MPEGlist();
   data = 0;
   stop = 0;
-
+  looping = false;
   preread_size = 0;
   SDL_mutexV(mutex);
 }
@@ -89,14 +89,11 @@
 {
   SDL_mutexP(mutex);
 
-  /* Return end of file if the stream is not enabled */
-  if(!enabled) return(false);
-
   /* Unlock current buffer */
   br->Unlock();
 
   /* No more buffer ? */
-  while(!br->Next() && !system->Eof())
+  while(!br->Next())
   {
     /* Then ask the system to read a new buffer */
     SDL_mutexV(mutex);
@@ -104,15 +101,36 @@
     SDL_mutexP(mutex);
   }
 
-  /* Couln't get a new buffer, then this is the end of the stream */
+  br = br->Next();
+  preread_size -= br->Size();
+
+  /* Check for the end of stream mark */
   if(eof())
   {
-    SDL_mutexV(mutex);
-    return(false);
+    if(looping)
+    {
+      /* No more buffer ? */
+      while(!br->Next())
+      {
+	/* Then ask the system to read a new buffer */
+	SDL_mutexV(mutex);
+	system->RequestBuffer();
+	SDL_mutexP(mutex);
+      }
+
+      /* Skip the eof mark */
+      br = br->Next();
+      preread_size -= br->Size();
+    }
+    else
+    {
+      /* Report eof */
+      SDL_mutexV(mutex);
+      return(false);
+    }
   }
 
-  br = br->Next();
-  preread_size -= br->Size();
+  /* Lock the buffer */
   br->Lock();
 
   /* Make sure that we have read buffers in advance if possible */
@@ -190,7 +208,7 @@
 }
 
 Uint32
-MPEGstream:: copy_data(Uint8 *area, Uint32 size, bool short_read)
+MPEGstream:: copy_data(Uint8 *area, Sint32 size, bool short_read)
 {
     Uint32 copied = 0;
 
@@ -246,16 +264,13 @@
 
 bool MPEGstream::eof() const
 {
-  return(!br->Next() && system->Eof());
+  return(!br->Size());
 }
 
 void MPEGstream::insert_packet(Uint8 * Data, Uint32 Size)
 {
   MPEGlist * newbr;
 
-  /* Discard the data if stream is not enabled */
-  if(!enabled) return;
-
   SDL_mutexP(mutex);
 
   preread_size += Size;
@@ -289,16 +304,12 @@
   SDL_mutexV(mutex);
 }
 
-void MPEGstream::enable(bool state)
+void MPEGstream::loop(bool toggle)
 {
-  if(enabled != state)
-  {
-    reset_stream();
-    enabled = state;
-  }
+  looping = toggle;
 }
 
-bool MPEGstream::is_enabled()
+bool MPEGstream::is_looping() const
 {
-  return(enabled);
+  return(looping);
 }
diff -ruN -x CVS smpeg/MPEGstream.h smpeg.patched/MPEGstream.h
--- smpeg/MPEGstream.h	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/MPEGstream.h	Wed Mar 15 10:17:06 2000
@@ -65,7 +65,7 @@
     void delete_marker(MPEGstream_marker const * marker);
 
     /* Copy data from the stream to a local buffer */
-    Uint32 copy_data(Uint8 *area, Uint32 size, bool short_read = false);
+    Uint32 copy_data(Uint8 *area, Sint32 size, bool short_read = false);
 
     /* Copy a byte from the stream */
     int copy_byte(void);
@@ -76,18 +76,16 @@
     /* Insert a new packet at the end of the stream */
     void insert_packet(Uint8 * data, Uint32 size);
 
-    /* Enable or disable the stream to receive data */
-    void enable(bool state);
+    /* Set the looping flag */
+    void loop(bool toggle);
 
-    /* Check if the stream is enabled */
-    bool is_enabled();
-public:
-    Uint8 streamid;
+    /* Check if the stream is looping */
+    bool is_looping() const;
 
-    // TODO: That shouldn't be public
-    Uint8 *data;
+    Uint8 streamid;
 
 protected:
+    Uint8 *data;
     Uint8 *stop;
 
     Uint32 preread_size;
@@ -95,10 +93,9 @@
     class MPEGsystem * system;
     MPEGlist * br;
     bool enabled;
+    bool looping;
 
     SDL_mutex * mutex;
-
-    bool next_buffer();
 };
 
 #endif /* _MPEGSTREAM_H_ */
diff -ruN -x CVS smpeg/MPEGsystem.cpp smpeg.patched/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/MPEGsystem.cpp	Wed Mar 15 17:50:59 2000
@@ -80,7 +80,15 @@
 
   /* Create a new buffer for reading */
   read_buffer = new Uint8[MPEG_BUFFER_SIZE];
-  
+
+  /* Invalidate the read buffer */
+  pointer = read_buffer;
+  read_size = 0;
+  read_total = 0;
+  packet_total = 0;
+  endofstream = errorstream = false;
+  looping = false;
+
   /* Create an empty stream list */
   stream_list = 
     (MPEGstream **) malloc(sizeof(MPEGstream *));
@@ -90,12 +98,6 @@
   if(!get_stream(SYSTEM_STREAMID))
     add_stream(new MPEGstream(this, SYSTEM_STREAMID));
 
-  /* Invalidate the read buffer */
-  pointer = read_buffer;
-  read_size = 0;
-  read_total = 0;
-  packet_total = 0;
-  endofstream = errorstream = false;
 #ifdef USE_SYSTEM_TIMESTAMP
   timestamp = 0.0;
   timedrift = 0.0;
@@ -116,11 +118,11 @@
   system_thread = SDL_CreateThread(SystemThread, this);
 
   /* Wait for the thread to start */
-  while(!system_thread_running)
+  while(!system_thread_running && !Eof())
     SDL_Delay(1);
 
   /* Wait for prebuffering */
-  while(request > 0)
+  while(request > 0 && !Eof())
     SDL_Delay(1);
 
   /* Look for streams */
@@ -131,7 +133,7 @@
 	!Eof());
 
   /* Wait for prebuffering */
-  while(request > 0)
+  while(request > 0 && !Eof())
     SDL_Delay(1);
 }
 
@@ -244,6 +246,19 @@
   if(Eof()) 
     return(0);
 
+  /* If there is only audio or video information give the packet */
+  /* without parsing it */
+  if(((stream_list[0]->streamid & 0xc0) == 0xc0) || /* audio only stream */
+     ((stream_list[0]->streamid & 0xe0) == 0xe0))   /* video only stream */
+  {
+    packet_size = read_buffer + read_size - pointer;
+
+    /* Insert the new data at the end of the stream */
+    stream_list[0]->insert_packet(pointer, packet_size);
+    pointer += packet_size;
+    return(stream_list[0]->streamid);
+  }
+
   /* Skip possible zeros at the beggining of the packet */
   while(Match4(pointer, zero, mask))
   {
@@ -317,9 +332,12 @@
       pointer += 4;
       packet_size -= 4;
     } else if ( pointer[0] != 0x0f && pointer[0] != 0x80) {
+      /* Huh? there is something wrong, try to catch next header */
+      pointer++;
+      if(!seek_next_header())
       	errorstream = true;
-	return(0);
-      }
+      return(0);
+    }
     ++pointer;
     --packet_size;
 
@@ -335,7 +353,7 @@
   {
     /* End codes belong to video stream */
     stream_id = exist_stream(VIDEO_STREAMID, 0xF0);
-    packet_size = read_buffer + read_size - pointer;
+    packet_size = 4;
   }
   else
   {
@@ -348,7 +366,9 @@
       /* If we're still a system stream, morph to an audio */
       /* or video stream */
 
-      if(Match4(pointer, AUDIO_CODE, AUDIO_MASK))
+      if(Match4(pointer, AUDIO_CODE, AUDIO_MASK) &&
+	 (pointer[2] & 0xf0) != 0xf0 &&
+	 (pointer[2] & 0xf0) != 0x00) /* Check for a valid mpeg audio header : bitrate != 0 */
       {
 	stream_id = AUDIO_STREAMID;
 	stream_list[0]->streamid = stream_id;
@@ -366,6 +386,7 @@
     }
     else
     {
+#ifdef DEBUG_SYSTEM
 	fprintf(stderr,
 		"Warning: unexpected header %02x%02x%02x%02x at offset %d\n",
 		pointer[0],
@@ -373,6 +394,7 @@
 		pointer[2],
 		pointer[3],
 		Tell() - read_size + (pointer - read_buffer));
+#endif
 	pointer++;
 	seek_next_header();
 	return(0);
@@ -412,8 +434,6 @@
       }          
       /* Hack to detect video streams that are not advertised */
       if ( ! exist_stream(VIDEO_STREAMID, 0xF0) ) {
-	// TEMP
-	printf("HACK operationnal\n");
 	if ( pointer[3] == 0xb3 ) {
 	  add_stream(new MPEGstream(this, VIDEO_STREAMID));
 	}
@@ -464,12 +484,8 @@
     {
       errorstream = true;
       SetError(strerror(errno));
-      return;
-    }
-    else
-    {
-      return;
     }
+    return;
   }
 
   /* Reinitialize the read buffer */
@@ -491,17 +507,33 @@
   request = PRE_BUFFERED_MAX;
 
   /* Start the system thread */
-  system_thread_running = false;
   system_thread = SDL_CreateThread(SystemThread, this);
 
+  /* Wait for the thread to start */
+  while(!system_thread_running && !Eof())
+    SDL_Delay(1);
+
   /* Wait for prebuffering */
-  while(request > 0)
+  while(request > 0 && !Eof())
     SDL_Delay(1);
+
+  register int i;
+
+  /* Skip the first empty buffer made when creating a mpegstream */
+  /* which would otherwise be interpreted as end of file */
+  for(i = 0; stream_list[i]; i++)
+    stream_list[i]->next_packet();
+}
+
+void MPEGsystem::Loop(bool toggle)
+{
+    looping = toggle;
+    loop_all_streams(looping);
 }
 
 void MPEGsystem::RequestBuffer()
 {
-  if(request < PRE_BUFFERED_MAX) request += MPEG_BUFFER_SIZE;
+  request += MPEG_BUFFER_SIZE;
 }
 
 bool MPEGsystem::Eof() const
@@ -528,10 +560,44 @@
 
   system->system_thread_running = true;
 
-  while(!system->Eof() && system->system_thread_running)
+  while(system->system_thread_running)
   {
     int delay = 1;
 
+    /* Check for end of file */
+    if(system->Eof())
+    {
+      /* Set the eof mark on all streams */
+      system->end_all_streams();
+
+      /* Get back to the beginning of the stream if possible */
+      if(lseek(system->mpeg_fd, 0, SEEK_SET) == (off_t) -1);
+      {
+	if(errno != ESPIPE)
+	{
+	  system->errorstream = true;
+	  system->SetError(strerror(errno));
+	}
+	break;
+      }
+
+      /* Reinitialize the read buffer */
+      system->pointer = system->read_buffer;
+      system->read_size = 0;
+      system->read_total = 0;
+      system->packet_total = 0;
+      system->endofstream = false;
+      system->errorstream = false;
+
+      /* Get the first header */
+      if(!system->seek_next_header())
+      {
+	system->errorstream = true;
+	system->SetError("Could not find the beginning of MPEG data\n");
+	break;
+      }
+    }
+
     /* Is a buffer needed? */
     if(system->request > 0)
     {
@@ -543,10 +609,11 @@
     {
       /* Wait more and more time to avoid take too much cpu time when */
       /* there are no packets requested */
+      if(delay >= 100) delay = 100;
       usleep(delay++);
     }
   }
-
+  
   system->system_thread_running = false;
 
   return(true);
@@ -578,6 +645,9 @@
 
   /* Write the stream */
   stream_list[i] = stream;
+
+  /* Set the looping flag for that stream */
+  stream->loop(looping);
   
   /* Put the end marker (null) */
   stream_list[i+1] = 0;
@@ -614,6 +684,25 @@
     stream_list[i]->reset_stream();
 }
 
+void MPEGsystem::end_all_streams()
+{
+  register int i;
+
+  /* End the streams */
+  /* We use a null buffer as the end of stream marker */
+  for(i = 0; stream_list[i]; i++)
+    stream_list[i]->insert_packet(0, 0);
+}
+
+void MPEGsystem::loop_all_streams(bool toggle)
+{
+  register int i;
+
+  /* Set loop flag on all streams */
+  for(i = 0; stream_list[i]; i++)
+    stream_list[i]->loop(toggle);
+}
+
 bool MPEGsystem::seek_next_header()
 {
   Read();
@@ -623,7 +712,9 @@
 
   while(!(Match4(pointer, PACKET_CODE, PACKET_MASK) ||
 	  Match4(pointer, VIDEO_CODE, VIDEO_MASK) ||
-	  Match4(pointer, AUDIO_CODE, AUDIO_MASK) ||
+	  (Match4(pointer, AUDIO_CODE, AUDIO_MASK) &&
+	   /* Check for a valid mpeg audio header : bitrate != 0 */ 
+	   ((pointer[2] & 0xf0) != 0xf0) && ((pointer[2] & 0xf0) != 0)) ||
 	  Match4(pointer, END_CODE, END_MASK) ||
 	  Match4(pointer, VIDEOSTREAM_CODE, VIDEOSTREAM_MASK) ||
 	  Match4(pointer, AUDIOSTREAM_CODE, AUDIOSTREAM_MASK) ||
@@ -639,6 +730,5 @@
       if(Eof())
 	return(false);
   }
-
   return(true);
 }
diff -ruN -x CVS smpeg/MPEGsystem.h smpeg.patched/MPEGsystem.h
--- smpeg/MPEGsystem.h	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/MPEGsystem.h	Tue Mar 14 13:30:00 2000
@@ -25,6 +25,7 @@
     void RequestBuffer();
     Uint32 Tell();
     void Rewind();
+    void Loop(bool toggle);
     bool Eof() const;
 
     /* Create all the streams present in the MPEG */
@@ -54,6 +55,12 @@
 
     /* Reset all the system streams */
     void reset_all_streams();
+    
+    /* Set eof for all streams */
+    void end_all_streams();
+    
+    /* Set looping for all streams */
+    void loop_all_streams(bool toggle);
 
     /* Seek the next header */
     bool seek_next_header();
@@ -74,6 +81,7 @@
 
     bool endofstream;
     bool errorstream;
+    bool looping;
 
 #ifdef USE_SYSTEM_TIMESTAMP
     /* Current timestamp for this stream */
diff -ruN -x CVS smpeg/MPEGvideo.h smpeg.patched/MPEGvideo.h
--- smpeg/MPEGvideo.h	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/MPEGvideo.h	Tue Mar 14 15:24:30 2000
@@ -33,12 +33,17 @@
 struct vid_stream;
 typedef struct vid_stream VidStream;
 
+/* Temporary definition of time stamp structure. */
+
+typedef int TimeStamp;
+
 class MPEGvideo : public MPEGerror, public MPEGvideoaction {
 
     /* Thread to play the video asynchronously */
     friend int Play_MPEGvideo(void *udata);
 
     /* Various mpeg_play functions that need our data */
+    friend VidStream* mpegVidRsrc( TimeStamp time_stamp, VidStream* vid_stream, int first );
     friend void DoDitherImage( VidStream* vid_stream );
     friend void DisplayCurrentFrame( VidStream* vid_stream );
     friend int timeSync( VidStream* vid_stream );
diff -ruN -x CVS smpeg/Makefile.in smpeg.patched/Makefile.in
--- smpeg/Makefile.in	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/Makefile.in	Wed Mar 15 17:58:02 2000
@@ -191,7 +191,7 @@
 .SUFFIXES:
 .SUFFIXES: .S .c .cpp .lo .o .s
 $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
-	cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile
+	cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile
 
 Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
 	cd $(top_builddir) \
@@ -514,7 +514,7 @@
 	top_distdir=`cd $(distdir) && pwd`; \
 	distdir=`cd $(distdir) && pwd`; \
 	cd $(top_srcdir) \
-	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu Makefile
+	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign Makefile
 	@for file in $(DISTFILES); do \
 	  d=$(srcdir); \
 	  if test -d $$d/$$file; then \
diff -ruN -x CVS smpeg/audio/Makefile.in smpeg.patched/audio/Makefile.in
--- smpeg/audio/Makefile.in	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/audio/Makefile.in	Wed Mar 15 17:58:02 2000
@@ -132,7 +132,7 @@
 .SUFFIXES:
 .SUFFIXES: .S .c .cpp .lo .o .s
 $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
-	cd $(top_srcdir) && $(AUTOMAKE) --gnu audio/Makefile
+	cd $(top_srcdir) && $(AUTOMAKE) --foreign audio/Makefile
 
 Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
 	cd $(top_builddir) \
@@ -225,7 +225,7 @@
 	top_distdir=`cd $(top_distdir) && pwd`; \
 	distdir=`cd $(distdir) && pwd`; \
 	cd $(top_srcdir) \
-	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu audio/Makefile
+	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign audio/Makefile
 	@for file in $(DISTFILES); do \
 	  d=$(srcdir); \
 	  if test -d $$d/$$file; then \
diff -ruN -x CVS smpeg/audio/mpegtoraw.cpp smpeg.patched/audio/mpegtoraw.cpp
--- smpeg/audio/mpegtoraw.cpp	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/audio/mpegtoraw.cpp	Wed Mar 15 07:50:14 2000
@@ -248,7 +248,7 @@
 #ifdef DEBUG_AUDIO
   static int printed = 0;
   if ( ! printed ) {
-    printf("MPEG audio stream layer %d, at %d Hz %s\n", layer, frequencies[version][frequency], (mode == single) ? "mono" : "stereo");
+    printf("MPEG audio stream layer %d (%d kbps), at %d Hz %s\n", layer,  bitrate[version][layer-1][bitrateindex], frequencies[version][frequency], (mode == single) ? "mono" : "stereo");
     printed = 1;
   }
 #endif
@@ -367,7 +367,7 @@
             len -= copylen;
             stream += copylen;
         }
-    } while ( (audio->Status() == MPEG_PLAYING) && (len > 0) );
+    } while ( copylen && (len > 0) && ((audio->currentframe < audio->decodedframe) || audio->decoding));
 #else
     /* The length is interpreted as being in samples */
     len /= 2;
diff -ruN -x CVS smpeg/configure.in smpeg.patched/configure.in
--- smpeg/configure.in	Thu Mar  9 19:53:29 2000
+++ smpeg.patched/configure.in	Wed Mar  8 15:53:01 2000
@@ -91,8 +91,8 @@
 
 dnl Check for MMX support
 AC_ARG_ENABLE(mmx,
-[  --enable-mmx            enable MMX IDCT decoding routines [default=no]],
-              , enable_mmx=no)
+[  --enable-mmx            enable MMX IDCT decoding routines [default=yes]],
+              , enable_mmx=yes)
 if test x$enable_mmx = xyes; then
     case "$target" in
         i?86*)
diff -ruN -x CVS smpeg/plaympeg.c smpeg.patched/plaympeg.c
--- smpeg/plaympeg.c	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/plaympeg.c	Wed Mar 15 17:26:47 2000
@@ -52,7 +52,8 @@
 "	--scale S or -s S    Play MPEG at size S (1-)\n"
 "       --skip N or -S N     Skip N seconds\n"
 "	--help or -h\n"
-"	--version or -V\n", argv0);
+"	--version or -V\n"
+"Specifying - as filename will use stdin for input\n", argv0);
 }
 
 #ifdef NET_SUPPORT
@@ -96,7 +97,7 @@
     loop_play = 0;
     volume = 100;
     skip = 0;
-    for ( i=1; argv[i] && (argv[i][0] == '-'); ++i ) {
+    for ( i=1; argv[i] && (argv[i][0] == '-') && (argv[i][1] != 0); ++i ) {
         if ( (strcmp(argv[i], "--noaudio") == 0) ||
              (strcmp(argv[i], "--nosound") == 0) ) {
             use_audio = 0;
@@ -261,16 +262,16 @@
 
 	  /* Connected, now the socket is just like a regular file */
 	  mpeg = SMPEG_new_descr(sock, &info, use_audio);
-
-	  if ( SMPEG_error(mpeg) ) {
-            fprintf(stderr, "%s: %s\n", argv[i], SMPEG_error(mpeg));
-            SMPEG_delete(mpeg);
-            continue;
-	  }
 	}
 	else
 #endif
-        mpeg = SMPEG_new(argv[i], &info, use_audio);
+	{
+	  if(strcmp(argv[i], "-") == 0) /* Use stdin for input */
+	    mpeg = SMPEG_new_descr(0, &info, use_audio);
+	  else
+	    mpeg = SMPEG_new(argv[i], &info, use_audio);
+	}
+
         if ( SMPEG_error(mpeg) ) {
             fprintf(stderr, "%s: %s\n", argv[i], SMPEG_error(mpeg));
             SMPEG_delete(mpeg);
diff -ruN -x CVS smpeg/smpeg.cpp smpeg.patched/smpeg.cpp
--- smpeg/smpeg.cpp	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/smpeg.cpp	Wed Mar 15 17:56:56 2000
@@ -198,8 +198,6 @@
 /* Skip 'seconds' seconds of the MPEG */
 void SMPEG_skip( SMPEG* mpeg, float seconds )
 {
-  // TEMP
-  printf("smpeg skip %f\n", seconds);
     mpeg->obj->Skip(seconds);
 }
 
diff -ruN -x CVS smpeg/video/Makefile.in smpeg.patched/video/Makefile.in
--- smpeg/video/Makefile.in	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/video/Makefile.in	Wed Mar 15 17:58:03 2000
@@ -139,7 +139,7 @@
 .SUFFIXES:
 .SUFFIXES: .S .c .cpp .lo .o .s
 $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
-	cd $(top_srcdir) && $(AUTOMAKE) --gnu video/Makefile
+	cd $(top_srcdir) && $(AUTOMAKE) --foreign video/Makefile
 
 Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
 	cd $(top_builddir) \
@@ -232,7 +232,7 @@
 	top_distdir=`cd $(top_distdir) && pwd`; \
 	distdir=`cd $(distdir) && pwd`; \
 	cd $(top_srcdir) \
-	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu video/Makefile
+	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign video/Makefile
 	@for file in $(DISTFILES); do \
 	  d=$(srcdir); \
 	  if test -d $$d/$$file; then \
diff -ruN -x CVS smpeg/video/video.cpp smpeg.patched/video/video.cpp
--- smpeg/video/video.cpp	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/video/video.cpp	Tue Mar 14 15:17:10 2000
@@ -1022,20 +1022,25 @@
     case 0x000001b9:   /*  handle ISO_11172_END_CODE too */
 
         flush_bits32;
-        /* Display last frame. */
+        /* Display last frame if not looping */
 
-        /* Set ended flag first so that ExecuteDisplay may check it. */
-        vid_stream->film_has_ended = TRUE;
+	if(!vid_stream->_smpeg->mpeg->is_looping())
+	{
 
-        if( vid_stream->future != NULL )
-        {
+	  /* Set ended flag first so that ExecuteDisplay may check it. */
+
+	  vid_stream->film_has_ended = TRUE;
+
+	  if( vid_stream->future != NULL )
+	  {
             vid_stream->current = vid_stream->future;
             ExecuteDisplay( vid_stream );
-        }
+	  }
 
 #ifdef ANALYSIS
-        PrintAllStats(vid_stream);
+	  PrintAllStats(vid_stream);
 #endif
+	}
         goto done;
         break;
 
diff -ruN -x CVS smpeg/video/video.h smpeg.patched/video/video.h
--- smpeg/video/video.h	Mon Mar 20 12:56:51 2000
+++ smpeg.patched/video/video.h	Tue Mar 14 15:23:55 2000
@@ -149,10 +149,6 @@
 /* Brown - changed to const int because it is a help variable */
 extern const int scan[][8];
 
-/* Temporary definition of time stamp structure. */
-
-typedef int TimeStamp;
-
 /* Structure with reconstructed pixel values. */
 
 typedef struct pict_image {
*************************************************************************
*** Applied ***
Date: Fri, 10 Mar 2000 00:12:32 +0000
From: Vivien Chappelier <vivien.chappelier@enst-bretagne.fr>
Subject: Re: smpeg & streaming


Let's start with the classes and inheritance scheme which changed a
little:

                ========= MPEGaction ==========
                [ generic class for handling  ]
                [ common operations performed ]
                [ on audio an video decoders  ]
                ===============================
                             |
                +------------+--------------------------------+
                |                                             |
                v                                             v
======= MPEGaudioaction ======                  ====== MPEGvideoaction =======
[ operations specific to the ]                  [ operations specific to the ]
[ audio decoder              ]                  [ video decoder              ]
==============================                  ==============================
                |                                            |
                v                                            v
========== MPEGaudio =========                  ======= MPEGvideo ============
[ the audio decoder          ]                  [ the video decoder          ]
==============================                  ==============================
                ^                                            ^
                |                                            |
                +---------------+----------------------------+
                                |               
                                |
                ========== MPEGerror =========
                [ generic class for handling ]
                [ common errors              ]
                ==============================
                             |
        +--------------------+--------------------------------+
        |                                                     |
        v                                                     v
=========== MPEG =============                  ========= MPEGsystem =======
[ handles operations on the  ]                  [ read the file descriptor ]
[ whole MPEG such as playing ]                  [ cut the stream into      ]
[ stopping, ...              ]                  [ packets and send them to ]
==============================                  [ the right stream         ]
                                                ============================



                ========== MPEGlist  =========
                [ the class used to manage   ]
                [ buffering                  ]
                ==============================



                ========== MPEGstream ========
                [ class representing an      ]
                [ elementary stream          ]
                ==============================
                


        Everything else is left unchanged.



Now the architecture (which class contains another):

        [*] means 'any number of'.
        [1] means 'only one'

                                MPEG
        +------------------------+-------------------------+
        |                        |                         |
        |                        |                         |
    [1] MPEGvideo       [1] MPEGsystem              [1] MPEGaudio
                                 |
                                 |
                                 |
                        [*] MPEGstream
                                 |
                                 |
                                 |
                        [*] MPEGlist


I'm now going to explain how the data flows between each class:

  

        First some data is read from the file_descriptor by the system
(MPEGsystem), cut into packets, and parsed to determine if they need to
be interpreted (system layer) or sent to the audio/video decoder. When
there is no system information, the packet size is the same as the read
buffer size. They are then routed to the the stream (MPEGstream) they
belong to by calling MPEGstream::insert_packet(). A thread is
responsible for taking care that the streams are always filled.
        When a decoder requires a packet it reads it from the stream with
MPEGstream::next_packet() and the MPEGstream class notifies the
MPEGsystem class about that with MPEGsystem::RequestBuffer() so that
MPEGsystem can refill the stream next time it checks for requested
buffers.

Now let's take a look to the files:

+++ smpeg.patched/MPEG.cpp      Thu Mar  9 16:20:51 2000

        Almost everything changed.
        Moved code from MPEG.h there.
        Removed mmap :-)

+++ smpeg.patched/MPEG.h        Thu Mar  9 15:53:30 2000

        Moved code to MPEG.cpp
        MPEG doesn't inherit from MPEGstream anymore (is an MPEG a stream?, i
don't think so)

+++ smpeg.patched/MPEGaction.h  Thu Mar  9 15:32:15 2000

        Added Skip()

+++ smpeg.patched/MPEGlist.h    Thu Mar  9 01:19:07 2000
+++ smpeg.patched/MPEGlist.cpp  Thu Mar  9 01:19:03 2000

        Code to manage the list where the stream data is stored. It is a list
of buffers, that can be filled, read and where buffers can be locked to
avoid they are freed. Now I think that I might have used MPEGring, but
at the time I wrote this one down I had no idea of how I would handle
buffering actually.


+++ smpeg.patched/MPEGstream.cpp        Thu Mar  9 01:19:30 2000

        Greatly modified version of your MPEGstream class. Used to fill or
read
the buffer list (MPEGlist).

+++ smpeg.patched/MPEGstream.h  Thu Mar  9 01:19:32 2000

+++ smpeg.patched/MPEGsystem.h  Thu Mar  9 19:09:08 2000
+++ smpeg.patched/MPEGsystem.cpp        Thu Mar  9 21:29:50 2000

        Data is read from the file descriptor by the Read() function which
stores it into a read buffer (64k). This data is then parsed by
FillBuffer() and sent to the streams. There is a small amount of data
(max 50 mpeg packets) read before playing starts to ensure that the
streams are filled and prevent that reading a large amount of data (as
the video decoder does) will block because the streams are empty.


+++ smpeg.patched/Makefile.am   Thu Mar  9 01:20:58 2000

        Added MPEGsystem.cpp, MPEGlist.cpp, MPEGsystem.h, MPEGlist.h

+++ smpeg.patched/plaympeg.c    Thu Mar  9 21:35:48 2000

        Added network support.
        Added skipping function.

+++ smpeg.patched/smpeg.h       Thu Mar  9 16:53:13 2000
+++ smpeg.patched/smpeg.cpp     Thu Mar  9 16:04:41 2000

        Added smpeg_new_descr to create a new MPEG from a file descriptor and
not only a filename.
        Added smpeg_skip to skip some of the MPEG.

+++ smpeg.patched/MPEGaudio.h   Thu Mar  9 15:32:34 2000
+++ smpeg.patched/audio/MPEGaudio.cpp   Thu Mar  9 16:20:28 2000

        Removed reset_stream everywhere.
        added Skip()

+++ smpeg.patched/audio/mpegtoraw.cpp   Thu Mar  9 02:20:45 2000

        removed looping.
        It is now handled by the MPEG class when Status is called

+++ smpeg.patched/MPEGvideo.h   Thu Mar  9 15:32:59 2000
+++ smpeg.patched/video/MPEGvideo.cpp   Thu Mar  9 16:21:02 2000

        Added Skip()
        removed reset_stream.
        Changed RenderFrame and RenderFinal (rewinding)

+++ smpeg.patched/video/video.h Thu Mar  9 01:17:42 2000

        Remove _loopFlag, the decoder already inherits looping from
MPEGaction)

+++ smpeg.patched/video/video.cpp       Thu Mar  9 02:44:49 2000

        Added flushing for the end sequence code (0x1b7 or 0x1b9)


That's all. Hope it wasn't too boring :-)

If you have any question (i'm sure you have), send a mail.

regards,
Vivien.

diff -Naur smpeg/MPEG.cpp smpeg.patched/MPEG.cpp
--- smpeg/MPEG.cpp	Mon Mar  6 17:27:07 2000
+++ smpeg.patched/MPEG.cpp	Thu Mar  9 16:20:51 2000
@@ -1,102 +1,359 @@
+#include "SDL.h"
 
 #include "MPEG.h"
 
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
 
-MPEG::MPEG(Uint8 *Mpeg, Uint32 Size, Uint8 StreamID, bool sdlaudio) :
-                                   MPEGstream(Mpeg, Size, StreamID)
+MPEG::MPEG(const char * name, bool Sdlaudio) :
+  MPEGerror()
 {
-    audiostream = NULL; audio = NULL; audioaction = NULL;
-    audioaction_enabled = false;
-    videostream = NULL; video = NULL; videoaction = NULL;
-    videoaction_enabled = false;
-    if ( streamid == SYSTEM_STREAMID ) {
-        /* Do special parsing to find out which MPEG streams to create */
-        while ( next_packet(false) ) {
-            data += 6;
-            while ( data[0] & 0x80 ) {
-#ifndef PROFILE_VIDEO
-                if ( (data[1] == AUDIO_STREAMID) && !audiostream ) {
-                    audiostream = new MPEG(mpeg, size, data[1], sdlaudio);
-                    if ( audiostream->WasError() ) {
-                        SetError(audiostream->TheError());
-                    }
-                    audioaction = audiostream;
-                    audioaction_enabled = true;
-                } else
-#endif
-                if ( ((data[1] & 0xF0) == VIDEO_STREAMID)  && !videostream ) {
-                    videostream = new MPEG(mpeg, size, data[1]&0xF0, sdlaudio);
-                    if ( videostream->WasError() ) {
-                        SetError(videostream->TheError());
-                    }
-                    videoaction = videostream;
-                    videoaction_enabled = true;
-                }
-                data += 3;
-            }
-            /* Hack to detect video streams that are not advertised */
-            if ( ! videostream ) {
-                if ( data[3] == 0xb3 ) {
-                    videostream = new MPEG(mpeg,size, VIDEO_STREAMID, sdlaudio);
-                    if ( videostream->WasError() ) {
-                        SetError(videostream->TheError());
-                    }
-                    videoaction = videostream;
-                    videoaction_enabled = true;
-                }
-            }
-        }
-        EnableAudio(audioaction_enabled);
-        EnableVideo(videoaction_enabled);
-        reset_stream();
-    }
-    /* Determine if we are reading a system layer, and get first packet */
-    if ( mpeg[3] == 0xba ) {
-        next_packet();
+  int new_fd;
+
+  new_fd = open(name, O_RDONLY);
+  close_fd = true;
+
+  if(new_fd == -1)
+  {
+    audio = NULL;
+    video = NULL;
+    system = NULL;
+    close_fd = false;
+    error = NULL;
+
+    audiostream = videostream = NULL;
+    audioaction = NULL;
+    videoaction = NULL;
+    audio = NULL;
+    video = NULL;
+    audioaction_enabled = videoaction_enabled = false;
+    loop = false;
+    pause = false;
+
+    SetError(strerror(errno));
+
+    return;
+  }
+
+  Init(new_fd, Sdlaudio);
+}
+
+MPEG::MPEG(int Mpeg_FD, bool Sdlaudio) :
+  MPEGerror()
+{
+  close_fd = false;
+  Init(Mpeg_FD, Sdlaudio);
+}
+
+void MPEG::Init(int Mpeg_FD, bool Sdlaudio)
+{
+    mpeg_fd = Mpeg_FD;
+
+    sdlaudio = Sdlaudio;
+
+    /* Create the system that will parse the MPEG stream */
+    system = new MPEGsystem(Mpeg_FD);
+
+    /* Initialize everything to invalid values for cleanup */
+    error = NULL;
+
+    audiostream = videostream = NULL;
+    audioaction = NULL;
+    videoaction = NULL;
+    audio = NULL;
+    video = NULL;
+    audioaction_enabled = videoaction_enabled = false;
+    loop = false;
+    pause = false;
+
+    parse_stream_list();
+
+    EnableAudio(audioaction_enabled);
+    EnableVideo(videoaction_enabled);
+
+    if ( ! audiostream && ! videostream ) {
+      SetError("No audio/video stream found in MPEG");
+    }
+
+    if ( system && system->WasError() ) {
+      SetError(system->TheError());
+    }
+
+    if ( audio && audio->WasError() ) {
+      SetError(audio->TheError());
+    }
+
+    if ( video && video->WasError() ) {
+      SetError(video->TheError());
+    }
+
+    if ( WasError() ) {
+      SetError(TheError());
+    }
+}
+
+MPEG::~MPEG()
+{
+  if(audio) delete audio;
+  if(video) delete video;
+
+  if(system) delete system;
+
+  if ( close_fd && mpeg_fd ) {
+    close(mpeg_fd);
+  }
+}
+
+bool MPEG::AudioEnabled(void) {
+  return(audioaction_enabled);
+}
+void MPEG::EnableAudio(bool enabled) {
+  if ( enabled && ! audioaction ) {
+    enabled = false;
+  }
+  audioaction_enabled = enabled;
+
+  /* Stop currently playing stream, if necessary */
+  if ( audioaction && ! audioaction_enabled ) {
+    audioaction->Stop();
+  } 
+  /* Set the video time source */
+  if ( videoaction ) {
+    if ( audioaction_enabled ) {
+      videoaction->SetTimeSource(audioaction);
     } else {
-        packet = mpeg;
-        packetlen = size;
-        data = packet;
-        stop = data + packetlen;
-    }
-    if ( streamid == AUDIO_STREAMID ) {
-        audiostream = this;
-        audio = new MPEGaudio(audiostream, sdlaudio);
-        if ( audio->WasError() ) {
-            SetError(audio->TheError());
-        } else {
-            audioaction = audio;
-            audioaction_enabled = true;
-        }
-    } else
-    if ( streamid == VIDEO_STREAMID ) {
-        videostream = this;
-        video = new MPEGvideo(videostream);
-        if ( video->WasError() ) {
-            SetError(video->TheError());
-        } else {
-            videoaction = video;
-            videoaction_enabled = true;
-        }
+      videoaction->SetTimeSource(NULL);
     }
-    if ( ! audiostream && ! videostream ) {
-        SetError("No audio/video stream found in MPEG");
+  }
+
+  if(audiostream)
+    audiostream->enable(enabled);
+}
+bool MPEG::VideoEnabled(void) {
+  return(videoaction_enabled);
+}
+void MPEG::EnableVideo(bool enabled) {
+  if ( enabled && ! videoaction ) {
+    enabled = false;
+  }
+  videoaction_enabled = enabled;
+
+  /* Stop currently playing stream, if necessary */
+  if ( videoaction && ! videoaction_enabled ) {
+    videoaction->Stop();
+  } 
+
+  if(videostream)
+    videostream->enable(enabled);
+}
+
+/* MPEG actions */
+void MPEG::Loop(bool toggle) {
+  loop = toggle;
+}
+void MPEG::Play(void) {
+  if ( VideoEnabled() ) {
+    videoaction->Play();
+  }
+  if ( AudioEnabled() ) {
+    audioaction->Play();
+  }
+}
+void MPEG::Stop(void) {
+  if ( VideoEnabled() ) {
+    videoaction->Stop();
+  }
+  if ( AudioEnabled() ) {
+    audioaction->Stop();
+  }
+}
+
+void MPEG::Rewind(void) {
+  Stop();
+
+  /* Go to the beginning of the file */
+  system->Rewind();
+
+  if ( AudioEnabled() ) {
+    audioaction->Rewind();
+  }
+
+  if ( VideoEnabled() ) {
+    videoaction->Rewind();
+  }
+}
+
+void MPEG::Pause(void) {
+  pause = !pause;
+
+  if ( VideoEnabled() ) {
+    videoaction->Pause();
+  }
+  if ( AudioEnabled() ) {
+    audioaction->Pause();
+  }
+}
+
+MPEGstatus MPEG::Status(void) {
+  MPEGstatus status;
+
+  status = MPEG_STOPPED;
+  if ( VideoEnabled() ) {
+    switch (videoaction->Status()) {
+      case MPEG_PLAYING:
+        status = MPEG_PLAYING;
+      break;
     }
+  }
+  if ( AudioEnabled() ) {
+    switch (audioaction->Status()) {
+      case MPEG_PLAYING:
+        status = MPEG_PLAYING;
+      break;
+    }
+  }
+
+  if(status == MPEG_STOPPED && loop && !pause)
+  {
+    /* Here we go again */
+    Rewind();
+    Play();
+
+    if ( VideoEnabled() ) {
+      switch (videoaction->Status()) {
+      case MPEG_PLAYING:
+        status = MPEG_PLAYING;
+	break;
+      }
+    }
+    if ( AudioEnabled() ) {
+      switch (audioaction->Status()) {
+      case MPEG_PLAYING:
+        status = MPEG_PLAYING;
+	break;
+      }
+    }
+  }
+
+  // TEMP
+  //  printf("status : audio %d video %d\n", audioaction->Status()==MPEG_PLAYING, videoaction->Status()==MPEG_PLAYING);
+
+  return(status);
+}
+
+/* MPEG audio actions */
+bool MPEG::GetAudioInfo(MPEG_AudioInfo *info) {
+  if ( AudioEnabled() ) {
+    return(audioaction->GetAudioInfo(info));
+  }
+  return(false);
+}
+void MPEG::Volume(int vol) {
+  if ( AudioEnabled() ) {
+    return(audioaction->Volume(vol));
+  }
+}
+bool MPEG::WantedSpec(SDL_AudioSpec *wanted) {
+  if( audiostream ) {
+    return(GetAudio()->WantedSpec(wanted));
+  }
+  return(false);
+}
+void MPEG::ActualSpec(const SDL_AudioSpec *actual) {
+  if( audiostream ) {
+    GetAudio()->ActualSpec(actual);
+  }
+}
+MPEGaudio *MPEG::GetAudio(void) { // Simple accessor used in the C interface
+  return audio;
+}
+
+/* MPEG video actions */
+bool MPEG::GetVideoInfo(MPEG_VideoInfo *info) {
+  if ( VideoEnabled() ) {
+    return(videoaction->GetVideoInfo(info));
+  }
+  return(false);
+}
+bool MPEG::SetDisplay(SDL_Surface *dst, SDL_mutex *lock,
+		MPEG_DisplayCallback callback) {
+  if ( VideoEnabled() ) {
+    return(videoaction->SetDisplay(dst, lock, callback));
+  }
+  return(false);
+}
+void MPEG::MoveDisplay(int x, int y) {
+  if ( VideoEnabled() ) {
+    videoaction->MoveDisplay(x, y);
+  }
+}
+void MPEG::ScaleDisplay(int scale) {
+  if ( VideoEnabled() ) {
+    videoaction->ScaleDisplay(scale);
+  }
+}
+void MPEG::RenderFrame(int frame, SDL_Surface *dst, int x, int y) {
+  if ( VideoEnabled() ) {
+    videoaction->RenderFrame(frame, dst, x, y);
+  }
 }
+void MPEG::RenderFinal(SDL_Surface *dst, int x, int y) {
+  if ( VideoEnabled() ) {
+    videoaction->RenderFinal(dst, x, y);
+  }
+}
+
+void MPEG::Skip(float seconds)
+{
+  if ( AudioEnabled() ) {
+    audioaction->Skip(seconds);
+  }
 
-MPEG::~MPEG() {
-    if ( audiostream ) {
-        if ( audiostream == this ) {
-            delete audio;
-        } else {
-            delete audiostream;
-        }
-    }
-    if ( videostream ) {
-        if ( videostream == this ) {
-            delete video;
-        } else {
-            delete videostream;
-        }
+  if ( VideoEnabled() ) {
+    videoaction->Skip(seconds);
+  }
+}
+
+void MPEG::parse_stream_list()
+{
+  MPEGstream ** stream_list;
+  register int i;
+
+  /* A new thread is created for each video and audio */
+  /* stream                                           */ 
+  /* TODO: support MPEG systems containing more than  */
+  /*       one audio or video stream                  */
+  i = 0;
+  do
+  {
+    /* Retreive the list of streams */
+    stream_list = system->GetStreamList();
+
+    switch(stream_list[i]->streamid)
+    {
+      case SYSTEM_STREAMID:
+      break;
+
+      case AUDIO_STREAMID:
+	audiostream = stream_list[i];
+	audioaction_enabled = true;
+	audiostream->next_packet();
+	audio = new MPEGaudio(audiostream, sdlaudio);
+	audioaction = audio;
+      break;
+
+      case VIDEO_STREAMID:
+	videostream = stream_list[i];
+	videoaction_enabled = true;
+	videostream->next_packet();
+	video = new MPEGvideo(videostream);
+	videoaction = video;
+      break;
     }
+
+    i++;
+  }
+  while(stream_list[i]);
 }
diff -Naur smpeg/MPEG.h smpeg.patched/MPEG.h
--- smpeg/MPEG.h	Wed Mar  1 09:26:35 2000
+++ smpeg.patched/MPEG.h	Thu Mar  9 15:53:30 2000
@@ -33,6 +33,9 @@
 #include "MPEGaction.h"
 #include "MPEGaudio.h"
 #include "MPEGvideo.h"
+#include "MPEGsystem.h"
+
+#define LENGTH_TO_CHECK_FOR_SYSTEM 0x50000	// Added by HanishKVC
 
 /* The main MPEG class - parses system streams and creates other streams
  A few design notes:
@@ -43,415 +46,73 @@
    do all the data parsing for that stream type.  It's a little odd,
    but seemed like the best way do implement stream parsing.
  */
-class MPEG : public MPEGstream, public MPEGaudioaction,public MPEGvideoaction {
+class MPEG : public MPEGerror
+{
 public:
-    MPEG(Uint8 *Mpeg, Uint32 Size, Uint8 StreamID = 0, bool sdlaudio = true);
+    MPEG(const char * name, bool sdlaudio = true);
+    MPEG(int Mpeg_FD, bool sdlaudio = true);
     virtual ~MPEG();
 
+    /* Initialize the MPEG */
+    void MPEG::Init(int Mpeg_FD, bool Sdlaudio);
+
     /* Enable/Disable audio and video */
-    bool AudioEnabled(void) {
-        return(audioaction_enabled);
-    }
-    void EnableAudio(bool enabled) {
-        if ( enabled && ! audioaction ) {
-            enabled = false;
-        }
-        audioaction_enabled = enabled;
-
-        /* Stop currently playing stream, if necessary */
-        if ( audioaction && ! audioaction_enabled ) {
-            audioaction->Stop();
-        } 
-        /* Set the video time source */
-        if ( videoaction ) {
-            if ( audioaction_enabled ) {
-                videostream->videoaction->SetTimeSource(audiostream->audioaction);
-            } else {
-                videostream->videoaction->SetTimeSource(NULL);
-            }
-        }
-    }
-    bool VideoEnabled(void) {
-        return(videoaction_enabled);
-    }
-    void EnableVideo(bool enabled) {
-        if ( enabled && ! videoaction ) {
-            enabled = false;
-        }
-        videoaction_enabled = enabled;
-
-        /* Stop currently playing stream, if necessary */
-        if ( videoaction && ! videoaction_enabled ) {
-            videoaction->Stop();
-        } 
-    }
+    bool AudioEnabled(void);
+    void EnableAudio(bool enabled);
+    bool VideoEnabled(void);
+    void EnableVideo(bool enabled);
 
     /* MPEG actions */
-    void Loop(bool toggle) {
-        if ( videoaction ) {
-            videoaction->Loop(toggle);
-        }
-        if ( audioaction ) {
-            audioaction->Loop(toggle);
-        }
-    }
-    void Play(void) {
-        if ( VideoEnabled() ) {
-            videoaction->Play();
-        }
-        if ( AudioEnabled() ) {
-            audioaction->Play();
-        }
-    }
-    void Stop(void) {
-        if ( VideoEnabled() ) {
-            videoaction->Stop();
-        }
-        if ( AudioEnabled() ) {
-            audioaction->Stop();
-        }
-    }
-    void Rewind(void) {
-        if ( VideoEnabled() ) {
-            videoaction->Rewind();
-        }
-        if ( AudioEnabled() ) {
-            audioaction->Rewind();
-        }
-    }
-    void Pause(void) {
-        if ( VideoEnabled() ) {
-            videoaction->Pause();
-        }
-        if ( AudioEnabled() ) {
-            audioaction->Pause();
-        }
-    }
-    MPEGstatus Status(void) {
-        MPEGstatus status;
-
-        status = MPEG_STOPPED;
-        if ( VideoEnabled() ) {
-            switch (videoaction->Status()) {
-                case MPEG_PLAYING:
-                    status = MPEG_PLAYING;
-                    break;
-            }
-        }
-        if ( AudioEnabled() ) {
-            switch (audioaction->Status()) {
-                case MPEG_PLAYING:
-                    status = MPEG_PLAYING;
-                    break;
-            }
-        }
-        return(status);
-    }
+    void Loop(bool toggle);
+    void Play(void);
+    void Stop(void);
+    void Rewind(void);
+    void Pause(void);
+    void Skip(float seconds);
+    MPEGstatus Status(void);
 
     /* MPEG audio actions */
-    bool GetAudioInfo(MPEG_AudioInfo *info) {
-        if ( AudioEnabled() ) {
-            return(audioaction->GetAudioInfo(info));
-        }
-        return(false);
-    }
-    void Volume(int vol) {
-        if ( AudioEnabled() ) {
-            return(audioaction->Volume(vol));
-        }
-    }
-    bool WantedSpec(SDL_AudioSpec *wanted) {
-        if( audiostream ) {
-            return(GetAudio()->WantedSpec(wanted));
-        }
-        return(false);
-    }
-    void ActualSpec(const SDL_AudioSpec *actual) {
-        if( audiostream ) {
-            GetAudio()->ActualSpec(actual);
-        }
-    }
-    MPEGaudio *GetAudio(void) { // Simple accessor used in the C interface
-        if ( audiostream == this ) {
-            return audio;
-        } else {
-            return(audiostream->GetAudio());
-        }
-    }
+    bool GetAudioInfo(MPEG_AudioInfo *info);
+    void Volume(int vol);
+    bool WantedSpec(SDL_AudioSpec *wanted);
+    void ActualSpec(const SDL_AudioSpec *actual);
+    MPEGaudio *GetAudio(void);
 
     /* MPEG video actions */
-    bool GetVideoInfo(MPEG_VideoInfo *info) {
-        if ( VideoEnabled() ) {
-            return(videoaction->GetVideoInfo(info));
-        }
-        return(false);
-    }
+    bool GetVideoInfo(MPEG_VideoInfo *info);
     bool SetDisplay(SDL_Surface *dst, SDL_mutex *lock,
-                                MPEG_DisplayCallback callback) {
-        if ( VideoEnabled() ) {
-            return(videoaction->SetDisplay(dst, lock, callback));
-        }
-        return(false);
-    }
-    void MoveDisplay(int x, int y) {
-        if ( VideoEnabled() ) {
-            videoaction->MoveDisplay(x, y);
-        }
-    }
-    void ScaleDisplay(int scale) {
-        if ( VideoEnabled() ) {
-            videoaction->ScaleDisplay(scale);
-        }
-    }
-    void RenderFrame(int frame, SDL_Surface *dst, int x, int y) {
-        if ( VideoEnabled() ) {
-            videoaction->RenderFrame(frame, dst, x, y);
-        }
-    }
-    void RenderFinal(SDL_Surface *dst, int x, int y) {
-        if ( VideoEnabled() ) {
-            videoaction->RenderFinal(dst, x, y);
-        }
-    }
+		                 MPEG_DisplayCallback callback);
+    void MoveDisplay(int x, int y);
+    void ScaleDisplay(int scale);
+    void RenderFrame(int frame, SDL_Surface *dst, int x, int y);
+    void RenderFinal(SDL_Surface *dst, int x, int y);
 
-protected:
-    /* We need to have separate audio and video streams */
 public:
-    MPEG *audiostream;
-    MPEG *videostream;
+    /* We need to have separate audio and video streams */
+    MPEGstream * audiostream;
+    MPEGstream * videostream;
+
+    MPEGsystem * system;
 
 protected:
-    MPEGaudio *audio;
-    MPEGvideo *video;
+    int mpeg_fd;
+    bool close_fd;
+
     MPEGaudioaction *audioaction;
-    bool audioaction_enabled;
     MPEGvideoaction *videoaction;
-    bool videoaction_enabled;
-};
-
-/* This class is system dependent in the way it uses memory mapping */
-#ifdef unix
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <fcntl.h>
 
-#define LENGTH_TO_CHECK_FOR_SYSTEM 0x50000	// Added by HanishKVC
-
-class MPEGfile : public MPEGerror,
-                 public MPEGaudioaction, public MPEGvideoaction {
-public:
-    MPEGfile(const char *file, bool sdlaudio = true) {
-        FILE *newfp;
-        newfp = fopen(file, "rb");
-        Init(newfp, true, sdlaudio);
-    }
-    MPEGfile(FILE *MPEG_fp, bool autoclose = false) {
-        Init(MPEG_fp, autoclose);
-    }
-    void Init(FILE *MPEG_fp, bool autoclose, bool sdlaudio = true) {
-	// Added by HanishKVC
-	Uint8 *mpeg_start;
-	int mpeg_offset;
-        const Uint8 PACKET_START_CODE[] = { 0x00, 0x00, 0x01, 0xba };
-	// End of HanishKVC 
-        /* Initialize everything to invalid values for cleanup */
-        mpeg_fp = MPEG_fp;
-        mpeg_area = (caddr_t)-1;
-        mpeg = NULL;
-        error = NULL;
-
-        /* Memory map the file and create an MPEG object */
-        if ( MPEG_fp ) {
-            struct stat statb;
-
-            mpeg_fp = MPEG_fp;
-            if ( fstat(fileno(mpeg_fp), &statb) == 0 ) {
-                mpeg_size = statb.st_size;
-                mpeg_area = mmap(NULL, mpeg_size, PROT_READ, MAP_SHARED,
-                                                     fileno(mpeg_fp), 0);
-		// Added by HanishKVC
-                mpeg_start = (Uint8 *)mpeg_area;
-		mpeg_offset = 0;
-		if ( (memcmp(mpeg_start, PACKET_START_CODE, 3) != 0) &&
-                     (mpeg_start[0] != 0xFF /* MP3 audio */) ) {
-		  //printf("DebugKVC: A Not so normal mpeg file\n");
-		  while((mpeg_start = 
-			(Uint8*)memchr((Uint8 *)mpeg_area+mpeg_offset,0xba,
-			mpeg_size-mpeg_offset)) != NULL)
-		  {
-		    mpeg_start = mpeg_start-3;
-		    mpeg_offset = mpeg_start-(Uint8 *)mpeg_area;
-		    //printf("DebugKVC: Possible Location %x\n",mpeg_offset);
-		    if ( memcmp(mpeg_start, PACKET_START_CODE, 3) == 0 ) {
-		      //printf("DebugKVC: System stream found\n");
-		      break;
-		    } else {
-		      //printf("DebugKVC: Sorry spurious match\n");
-		      mpeg_offset = mpeg_offset+4; 
-		      // Actually I can skip 3 more chars as 0xba is not there 
-		      // anywhere else in the PACKET_START_CODE. I may be able
-		      // to do more optimizations to search, but as this search
-		      // occurs only once at the begining and that to in a small
-		      // data space, I think this dumb way should be sufficient.
-		    }
-		  } // of while
-		}
-		// End of HanishKVC
-                if ( mpeg_area != (caddr_t)-1 ) {
-		    if ( mpeg_start ) {
-                        mpeg = new MPEG(mpeg_start,
-                                        mpeg_size-mpeg_offset, 0, sdlaudio);
-                        if ( mpeg->WasError() ) {
-                            SetError(mpeg->TheError());
-                            delete mpeg;
-                            mpeg = NULL;
-                        }
-                    } else {
-                        SetError("Unable to find MPEG start code");
-                    }
-                } else {
-                    SetError("Memory map of MPEG failed");
-                }
-            } else {
-                SetError("Unable to stat() MPEG file");
-            }
-        } else {
-            SetError("Unable to open MPEG file");
-        }
-        close_fp = autoclose;
-    }
-    virtual ~MPEGfile() {
-        if ( mpeg ) {
-            delete mpeg;
-        }
-        if ( mpeg_area != (caddr_t)-1 ) {
-            munmap((caddr_t)mpeg_area, mpeg_size);
-        }
-        if ( close_fp && mpeg_fp ) {
-            fclose(mpeg_fp);
-        }
-    }
-
-    /* Enable/Disable audio and video */
-    bool AudioEnabled(void) {
-        if ( mpeg ) {
-            return(mpeg->AudioEnabled());
-        }
-        return(false);
-    }
-    void EnableAudio(bool enabled) {
-        if ( mpeg ) mpeg->EnableAudio(enabled);
-    }
-    bool VideoEnabled(void) {
-        if ( mpeg ) {
-            return(mpeg->VideoEnabled());
-        }
-        return(false);
-    }
-    void EnableVideo(bool enabled) {
-        if ( mpeg ) mpeg->EnableVideo(enabled);
-    }
+    MPEGaudio *audio;
+    MPEGvideo *video;
 
-    /* MPEG actions */
-    void Loop(bool toggle) {
-        if ( mpeg ) mpeg->Loop(toggle);
-    }
-    void Play(void) {
-        if ( mpeg ) mpeg->Play();
-    }
-    void Stop(void) {
-        if ( mpeg ) mpeg->Stop();
-    }
-    void Rewind(void) {
-        if ( mpeg ) mpeg->Rewind();
-    }
-    void Pause(void) {
-        if ( mpeg ) mpeg->Pause();
-    }
-    MPEGstatus Status(void) {
-        MPEGstatus status;
-
-        status = MPEG_ERROR;
-        if ( mpeg ) {
-            status = mpeg->Status();
-        }
-        return(status);
-    }
+    bool audioaction_enabled;
+    bool videoaction_enabled;
 
-    /* MPEG audio actions */
-    bool GetAudioInfo(MPEG_AudioInfo *info) {
-        if ( mpeg ) {
-            return(mpeg->GetAudioInfo(info));
-        }
-        return(false);
-    }
-    void Volume(int vol) {
-        if ( mpeg ) {
-            return(mpeg->Volume(vol));
-        }
-    }
-    bool WantedSpec(SDL_AudioSpec *wanted) {
-        if( mpeg ) {
-            return(mpeg->WantedSpec(wanted));
-        }
-    }
-    void ActualSpec(const SDL_AudioSpec *actual) {
-        if( mpeg ) {
-            mpeg->ActualSpec(actual);
-        }
-    }
-    MPEGaudio *GetAudio(void) {
-        if( mpeg ) {
-            return mpeg->GetAudio();
-        }
-    }
+    bool sdlaudio;
 
-    /* MPEG video actions */
-    bool GetVideoInfo(MPEG_VideoInfo *info) {
-        if ( mpeg ) {
-            return(mpeg->GetVideoInfo(info));
-        }
-        return(false);
-    }
-    bool SetDisplay(SDL_Surface *dst, SDL_mutex *lock,
-                                MPEG_DisplayCallback callback) {
-        if ( mpeg ) {
-            return(mpeg->SetDisplay(dst, lock, callback));
-        }
-        return(false);
-    }
-    void MoveDisplay(int x, int y) {
-        if ( mpeg ) {
-            mpeg->MoveDisplay(x, y);
-        }
-    }
-    void ScaleDisplay(int scale) {
-        if ( mpeg ) {
-            mpeg->ScaleDisplay(scale);
-        }
-    }
-    void RenderFrame(int frame, SDL_Surface *dst, int x, int y) {
-        if ( mpeg ) {
-            mpeg->RenderFrame(frame, dst, x, y);
-        }
-    }
-    void RenderFinal(SDL_Surface *dst, int x, int y) {
-        if ( mpeg ) {
-            mpeg->RenderFinal(dst, x, y);
-        }
-    }
+    bool loop;
+    bool pause;
 
-protected:
-    FILE *mpeg_fp;
-    bool close_fp;
-    void  *mpeg_area;
-    size_t mpeg_size;
-public:
-    MPEG *mpeg;
+    void parse_stream_list();
 };
-#else
-#error Non-mmap implementation not completed
-#endif /* unix */
 
 #endif /* _MPEG_H_ */
diff -Naur smpeg/MPEGaction.h smpeg.patched/MPEGaction.h
--- smpeg/MPEGaction.h	Mon Mar  6 17:27:07 2000
+++ smpeg.patched/MPEGaction.h	Thu Mar  9 15:32:15 2000
@@ -47,6 +47,7 @@
     virtual void Play(void) = 0;
     virtual void Stop(void) = 0;
     virtual void Rewind(void) = 0;
+    virtual void Skip(float seconds) = 0;
     virtual void Pause(void) {  /* A toggle action */
         if ( paused ) {
             paused = false;
diff -Naur smpeg/MPEGaudio.h smpeg.patched/MPEGaudio.h
--- smpeg/MPEGaudio.h	Mon Mar  6 17:27:07 2000
+++ smpeg.patched/MPEGaudio.h	Thu Mar  9 15:32:34 2000
@@ -26,13 +26,15 @@
 #define THREADED_AUDIO
 
 #include "SDL.h"
-#include "MPEGstream.h"
+#include "MPEGerror.h"
 #include "MPEGaction.h"
 
 #ifdef THREADED_AUDIO
 #include "MPEGring.h"
 #endif
 
+class MPEGstream;
+
 /* MPEG/WAVE Sound library
 
    (C) 1997 by Woo-jae Jung */
@@ -165,6 +167,7 @@
     void Play(void);
     void Stop(void);
     void Rewind(void);
+    void Skip(float seconds);
     void Volume(int vol);
     MPEGstatus Status(void);
 
@@ -252,45 +255,13 @@
 private:
   Uint8 _buffer[4096];
   int  bitindex;
-  bool fillbuffer(int size)
-  {
-      bitindex=0;
-      return(mpeg->copy_data(_buffer, size) > 0);
-  };
-  void sync(void)  {bitindex=(bitindex+7)&0xFFFFFFF8;};
-  bool issync(void){return (bitindex&7);};
-  int getbyte(void) {
-      int r=(unsigned char)_buffer[bitindex>>3];
-
-      bitindex+=8;
-      return r;
-  }
-  int getbit(void) {
-      register int r=(_buffer[bitindex>>3]>>(7-(bitindex&7)))&1;
-
-      bitindex++;
-      return r;
-  }
-  int getbits8(void) {
-      register unsigned short a;
-      { int offset=bitindex>>3;
-
-        a=(((unsigned char)_buffer[offset])<<8) | ((unsigned char)_buffer[offset+1]);
-      }
-      a<<=(bitindex&7);
-      bitindex+=8;
-      return (int)((unsigned int)(a>>8));
-  }
-  int getbits9(int bits) {
-      register unsigned short a;
-      { int offset=bitindex>>3;
-
-        a=(((unsigned char)_buffer[offset])<<8) | ((unsigned char)_buffer[offset+1]);
-      }
-      a<<=(bitindex&7);
-      bitindex+=bits;
-      return (int)((unsigned int)(a>>(16-bits)));
-  }
+  bool fillbuffer(int size);
+  void sync(void);
+  bool issync(void);
+  int getbyte(void);
+  int getbit(void);
+  int getbits8(void);
+  int getbits9(int bits);
   int getbits(int bits);
 
 
diff -Naur smpeg/MPEGlist.cpp smpeg.patched/MPEGlist.cpp
--- smpeg/MPEGlist.cpp	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/MPEGlist.cpp	Thu Mar  9 01:19:03 2000
@@ -0,0 +1,56 @@
+#include "MPEGlist.h"
+
+MPEGlist::MPEGlist()
+{
+  size = 0;
+  data = 0;
+  lock = 0;
+  next = 0;
+  prev = 0;
+}
+
+MPEGlist::~MPEGlist()
+{
+  if(next) next->prev = prev;
+  if(prev) prev->next = next;
+  if(data)
+  {
+    delete data;
+    data = 0;
+  }
+}
+
+/* Return the next free buffer or allocate a new one if none is empty */
+MPEGlist * MPEGlist::Alloc(Uint32 Buffer_Size)
+{
+  MPEGlist * tmp;
+
+  tmp = next;
+
+  next = new MPEGlist;
+
+  next->next = tmp;
+  next->data = new Uint8[Buffer_Size];
+  next->size = Buffer_Size;
+  next->prev = this;
+
+  if(!next->data)
+  {
+    fprintf(stderr, "Alloc : Not enough memory\n");
+    exit(0);
+  }
+
+  return(next);
+}
+
+/* Lock current buffer */
+void MPEGlist::Lock()
+{
+  lock++;
+}
+
+/* Unlock current buffer */
+void MPEGlist::Unlock()
+{
+  if(lock != 0) lock--;
+}
diff -Naur smpeg/MPEGlist.h smpeg.patched/MPEGlist.h
--- smpeg/MPEGlist.h	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/MPEGlist.h	Thu Mar  9 01:19:07 2000
@@ -0,0 +1,43 @@
+/* bufferlist.h */
+
+/* A class for buffering the I/O and allow multiple streams to read the data
+   asynchronously */
+
+#ifndef _MPEGLIST_H_
+#define _MPEGLIST_H_
+
+#include "SDL.h"
+
+class MPEGlist {
+public:
+  MPEGlist();
+  ~MPEGlist();
+
+  /* Get to the next free buffer or allocate a new one if none is free */
+  MPEGlist * Alloc(Uint32 Buffer_Size);
+
+  /* Lock current buffer */
+  void Lock();
+
+  /* Unlock current buffer */
+  void Unlock();
+
+  /* Get the buffer */
+  inline void * Buffer() { return(data); };
+
+  inline Uint32 Size() { return(size); }; 
+
+  inline MPEGlist * Next() { return(next); };
+
+  inline MPEGlist * Prev() { return(prev); };
+
+  inline Uint32 IsLocked() { return(lock); };
+
+private:
+  class MPEGlist * next;
+  class MPEGlist * prev;
+  Uint32 lock;
+  Uint8 * data;
+  Uint32 size;
+};
+#endif
diff -Naur smpeg/MPEGstream.cpp smpeg.patched/MPEGstream.cpp
--- smpeg/MPEGstream.cpp	Wed Mar  1 09:26:35 2000
+++ smpeg.patched/MPEGstream.cpp	Thu Mar  9 01:19:30 2000
@@ -19,212 +19,182 @@
 
 /* The generic MPEG stream class */
 
-
+#include "MPEG.h"
 #include "MPEGstream.h"
+#include "video/video.h"
 
+/* This is the limit of the quantity of pre-read data */
+#define MAX_QUEUE (256 * 1024)
 
-MPEGstream:: MPEGstream(Uint8 *Mpeg, Uint32 Size, Uint8 StreamID) :
-                                                        MPEGerror()
+MPEGstream::MPEGstream(MPEGsystem * System, Uint8 Streamid)
 {
-    mpeg = Mpeg;
-    size = Size;
-    if ( StreamID == 0 ) { /* Autodetect StreamID */
-        if ( mpeg[3] == 0xba ) {
-            StreamID = SYSTEM_STREAMID;
-        } else
-        if ( mpeg[3] == 0xb3 ) {
-            StreamID = VIDEO_STREAMID;
-        } else
-        if ( mpeg[0] == 0xff ) {
-            StreamID = AUDIO_STREAMID;
-        }
-    }
-    streamid = StreamID;
-    reset_stream();
+  system = System;
+  streamid = Streamid;
+  br = new MPEGlist();
+  
+  data = 0;
+  stop = 0;
+  
+  preread_size = 0;
+  enabled = true;
+  mutex = SDL_CreateMutex();
 }
 
-void
-MPEGstream:: reset_stream(void)
+MPEGstream::~MPEGstream()
 {
-    if ( mpeg[3] == 0xba ) { /* System stream, set up for next packet */
-        packet = mpeg;
-        packetlen = 0;
-        data = stop = packet;
-    } else {
-        packet = mpeg;
-        packetlen = size;
-        data = packet;
-        stop = data + packetlen;
-    }
-    marked_packet = NULL;
-    marked_packetlen = 0;
-#ifdef USE_SYSTEM_TIMESTAMP
-    timestamp = 0.0;
-    timedrift = 0.0;
-#endif
-    endofstream = false;
-    errorstream = false;
+  SDL_DestroyMutex(mutex);
+  delete br;
 }
 
-bool
-MPEGstream:: next_packet(bool recurse)
+void
+MPEGstream::reset_stream()
 {
-    const Uint8 PACKET_START_CODE[] = { 0x00, 0x00, 0x01, 0xba };
-    Uint8 stream_id;
+  MPEGlist * newbr;
 
-    /* Get to the next packet */
-    packet += packetlen;
-    if ( packet >= (mpeg+size) ) {
-        endofstream = true;
-        return(false);
-    }
+  SDL_mutexP(mutex);
+  /* Seek the first buffer */
+  for(newbr = br; newbr->Prev(); newbr = newbr->Prev());
+  
+  /* Free buffers  */
+  while(newbr->Next())
+  {
+    newbr = newbr->Next();
+    delete newbr->Prev();
+  } 
+  delete newbr;
+
+  br = new MPEGlist();
+  data = 0;
+  stop = 0;
 
-    /* Check to see what kind of packet this is */
-    while ( packet < (mpeg+size) ) {
-        if ( memcmp(packet, PACKET_START_CODE, 3) == 0 )
-            break;
-        ++packet;
-    }
-    if ( packet >= (mpeg+size) ) {
-        errorstream = true;
-        return(false);
-    }
+  preread_size = 0;
+  SDL_mutexV(mutex);
+}
 
-    if ( memcmp(packet, PACKET_START_CODE, 4) == 0 ) {
-        packet += 4;
+void
+MPEGstream::rewind_stream()
+{
+  /* Note that this will rewind all streams, and other streams than this one */
+  /* will finish reading their prebuffured data (they are not reseted) */
+  /* This should works because there are always sequence start codes or */
+  /* audio start codes at the beginning of the streams */
+  /* Of course, this won't work on network streams */
 
-        /* The system stream timestamp is not very useful to us since we
-           don't coordinate the audio and video threads very tightly, and
-           we read in large amounts of data at once in the video stream.
-           BUT... if you need it, here it is.
-         */
-#ifdef USE_SYSTEM_TIMESTAMP
-#define FLOAT_0x10000 (double)((Uint32)1 << 16)
-#define STD_SYSTEM_CLOCK_FREQ 90000L
-        { Uint8 hibit; Uint32 lowbytes;
-          hibit = (packet[0]>>3)&0x01;
-          lowbytes = (((Uint32)packet[0] >> 1) & 0x03) << 30;
-          lowbytes |= (Uint32)packet[1] << 22;
-          lowbytes |= ((Uint32)packet[2] >> 1) << 15;
-          lowbytes |= (Uint32)packet[3] << 7;
-          lowbytes |= ((Uint32)packet[4]) >> 1;
-          timestamp = (double)hibit*FLOAT_0x10000*FLOAT_0x10000+(double)lowbytes;
-          timestamp /= STD_SYSTEM_CLOCK_FREQ;
-        }
-#endif
-        packet += 8;
-    }
+  /* Restart the system */
+  system->Rewind();
+}
 
-    /* Get the stream id, and packet length */
-    stream_id = packet[3];
-    packet += 4;
-    packetlen = (((unsigned short)packet[0]<<8)|packet[1]);
-    packet += 2;
-
-    /* If this is a system packet, skip it */
-    if ( stream_id != streamid ) {
-        if ( stream_id == SYSTEM_STREAMID ) {
-            packet += packetlen;
-            stream_id = packet[3];
-            packet += 4;
-            packetlen = (((unsigned short)packet[0]<<8)|packet[1]);
-            packet += 2;
-        }
-    }
+bool
+MPEGstream:: next_packet(bool recurse)
+{
+  SDL_mutexP(mutex);
 
-    /* We found a packet for us? */
-    if ( stream_id == streamid ) {
-        if ( stream_id != SYSTEM_STREAMID ) {
-            /* Skip stuffing bytes */
-            while ( packet[0] == 0xff ) {
-                ++packet;
-                --packetlen;
-            }
-            if ( (packet[0] & 0x40) == 0x40 ) {
-                packet += 2;
-                packetlen -= 2;
-            }
-            if ( (packet[0] & 0x30) == 0x30 ) {
-                packet += 9;
-                packetlen -= 9;
-            } else if ( (packet[0] & 0x20) == 0x20 ) {
-                packet += 4;
-                packetlen -= 4;
-            } else if ( packet[0] != 0x0f ) {
-                errorstream = true;
-                return(false);
-            }
-            ++packet;
-            --packetlen;
-        }
+  /* Return end of file if the stream is not enabled */
+  if(!enabled) return(false);
 
-        /* We have the packet data! */
-        if ( packetlen > 0 ) {
-            data = packet;
-            stop = data + packetlen;
-            return(true);
-        }
-    }
-    /* Hack to seek past raw video data in a system stream */
-    else if ( streamid == VIDEO_STREAMID ) {
-        /* Possibly an embedded video packet? */
-        if ( stream_id == 0xb3 ) {
-            packetlen = 6;
-        }
-    }
+  /* Unlock current buffer */
+  br->Unlock();
 
-    /* Look for another packet of ours? */
-    if ( recurse || !packetlen || (stream_id == PAD_STREAMID) ) {
-        return(next_packet(recurse));
-    }
+  /* No more buffer ? */
+  while(!br->Next() && !system->Eof())
+  {
+    /* Then ask the system to read a new buffer */
+    SDL_mutexV(mutex);
+    system->RequestBuffer();
+    SDL_mutexP(mutex);
+  }
+
+  /* Couln't get a new buffer, then this is the end of the stream */
+  if(eof())
+  {
+    SDL_mutexV(mutex);
     return(false);
+  }
+
+  br = br->Next();
+  preread_size -= br->Size();
+  br->Lock();
+
+  /* Make sure that we have read buffers in advance if possible */
+  if(preread_size < MAX_QUEUE)
+  {
+    //printf("[%d] preread: %d\n", streamid, preread_size);
+    system->RequestBuffer();
+  }
+  
+  /* Update stream datas */
+  data = (Uint8 *) br->Buffer();
+  stop = data + br->Size();
+
+  SDL_mutexV(mutex);
+
+  return(true);
 }
 
-bool
-MPEGstream:: mark_data(int offset)
+MPEGstream_marker const *
+MPEGstream:: new_marker(int offset)
 {
-    Uint8 *last_packet;
-    Uint32 last_packetlen;
+    MPEGstream_marker * marker;
 
+    SDL_mutexP(mutex);
     /* We can't mark past the end of the stream */
     if ( eof() ) {
-        return(false);
+      SDL_mutexV(mutex);
+      return(0);
     }
 
     /* It may be possible to seek in the data stream, but punt for now */
-    if ( ((data+offset) < packet) || ((data+offset) > stop) ) {
-        return(false);
+    if ( ((data+offset) < br->Buffer()) || ((data+offset) > stop) ) {
+        SDL_mutexV(mutex);
+        return(0);
     }
 
     /* Set up the mark */
-    marked_packet = packet;
-    marked_packetlen = packetlen;
-    marker = data+offset;
-    return(true);
+    marker = new MPEGstream_marker;
+    marker->marked_buffer = br;
+    marker->marked_data = data;
+    marker->marked_stop = stop;
+
+    /* Lock the current buffer */
+    br->Lock();
+
+    SDL_mutexV(mutex);
+
+    return(marker);
 }
 
 bool
-MPEGstream:: seek_marker(void)
+MPEGstream:: seek_marker(MPEGstream_marker const * marker)
 {
-    if ( marked_packet ) {
+    SDL_mutexP(mutex);
+
+    if ( marker ) {
         /* Reset the data positions */
-        packet = marked_packet;
-        packetlen = marked_packetlen;
-        data = marker;
-        stop = packet+packetlen;
-
-        /* Reset error conditions for the stream */
-        endofstream = false;
-        errorstream = false;
+	br = marker->marked_buffer;
+        data = marker->marked_data;
+        stop = marker->marked_stop;
+
+        /* Release current buffer */
+	br->Unlock();
     }
-    return(marked_packet != NULL);
+
+    SDL_mutexV(mutex);
+
+    return(marker != 0);
+}
+
+void
+MPEGstream:: delete_marker(MPEGstream_marker const * marker)
+{
+    delete marker;
 }
 
 Uint32
 MPEGstream:: copy_data(Uint8 *area, Uint32 size, bool short_read)
 {
     Uint32 copied = 0;
-    while ( (size > 0) && !endofstream ) {
+
+    while ( (size > 0) && !eof()) {
         Uint32 len;
 
         /* Get new data if necessary */
@@ -234,13 +204,17 @@
             }
         }
 
+	SDL_mutexP(mutex);
+
         /* Copy as much as we need */
         if ( size <= (Uint32)(stop-data) ) {
             len = size;
         } else {
             len = (stop-data);
         }
+
         memcpy(area, data, len);
+
         area += len;
         data += len;
         size -= len;
@@ -250,7 +224,81 @@
         if ( ((copied%4) == 0) && short_read ) {
             break;
         }
+
+	SDL_mutexV(mutex);
+
     }
+
     return(copied);
 }
 
+int MPEGstream::copy_byte(void)
+{
+  /* Get new data if necessary */
+  if ( data == stop ) {
+    if ( ! next_packet() ) {
+      return (-1);
+    }
+  }
+
+  return(*data++);
+}
+
+bool MPEGstream::eof() const
+{
+  return(!br->Next() && system->Eof());
+}
+
+void MPEGstream::insert_packet(Uint8 * Data, Uint32 Size)
+{
+  MPEGlist * newbr;
+
+  /* Discard the data if stream is not enabled */
+  if(!enabled) return;
+
+  SDL_mutexP(mutex);
+
+  preread_size += Size;
+
+  /* - Fill in a new buffer - */
+
+  /* Seek the last buffer */
+  for(newbr = br; newbr->Next(); newbr = newbr->Next());
+
+  /* Position ourselves at the end of the stream */
+  newbr = newbr->Alloc(Size);
+
+  memcpy(newbr->Buffer(), Data, Size);
+
+  /* - Check for unused buffers and free them - */
+
+  /* First of all seek the first buffer */
+  for(newbr = br; newbr->Prev(); newbr = newbr->Prev());
+
+  /* Now free buffers until we find a locked buffer */
+  while(newbr->Next())
+  {
+    newbr = newbr->Next();
+
+    if(newbr->Prev() == br) break;
+
+    /* Delete all unlocked buffers */
+    if(!newbr->Prev()->IsLocked())
+      delete newbr->Prev();
+  }
+  SDL_mutexV(mutex);
+}
+
+void MPEGstream::enable(bool state)
+{
+  if(enabled != state)
+  {
+    reset_stream();
+    enabled = state;
+  }
+}
+
+bool MPEGstream::is_enabled()
+{
+  return(enabled);
+}
diff -Naur smpeg/MPEGstream.h smpeg.patched/MPEGstream.h
--- smpeg/MPEGstream.h	Tue Jan  4 05:49:15 2000
+++ smpeg.patched/MPEGstream.h	Thu Mar  9 01:19:32 2000
@@ -24,74 +24,83 @@
 
 #include "SDL_types.h"
 #include "MPEGerror.h"
+#include "MPEGvideo.h"
+#include "MPEGaudio.h"
+#include "MPEGlist.h"
 
 #define AUDIO_STREAMID  0xc0
 #define VIDEO_STREAMID  0xe0
 #define SYSTEM_STREAMID 0xbb
-#define PAD_STREAMID    0xbe
 
-class MPEGstream : public MPEGerror {
+struct MPEGstream_marker
+{
+    /* Data to mark part of the stream */
+    MPEGlist * marked_buffer;
+    Uint8 *marked_data;
+    Uint8 *marked_stop;  
+};
+
+class MPEGstream
+{
 public:
-    MPEGstream(Uint8 *Mpeg, Uint32 Size, Uint8 StreamID);
+    MPEGstream(class MPEGsystem * System, Uint8 Streamid);
+    ~MPEGstream();
 
-    /* Rewind the stream to the beginning and reset eof/error conditions */
+    /* Cleanup the buffers and reset the stream */
     void reset_stream(void);
 
+    /* Rewind the stream */
+    void rewind_stream(void);
+
     /* Go to the next packet in the stream */
     bool next_packet(bool recurse = true);
 
     /* Mark a position in the data stream */
-    bool mark_data(int offset);
+    MPEGstream_marker const * new_marker(int offset);
+
+    /* Jump to the marked position */
+    bool seek_marker(MPEGstream_marker const * marker);
 
     /* Jump to last successfully marked position */
-    bool seek_marker(void);
+    void delete_marker(MPEGstream_marker const * marker);
 
     /* Copy data from the stream to a local buffer */
     Uint32 copy_data(Uint8 *area, Uint32 size, bool short_read = false);
 
     /* Copy a byte from the stream */
-    int copy_byte(void) {
-        /* Get new data if necessary */
-        if ( data == stop ) {
-            if ( ! next_packet() ) {
-                return (-1);
-            }
-        }
-        return(*data++);
-    }
+    int copy_byte(void);
 
     /* Check for end of file or an error in the stream */
-    bool eof(void) {
-        return(endofstream || errorstream);
-    }
+    bool eof(void) const;
 
-protected:
-    /* The actual memory mapped MPEG data */
-    Uint8 *mpeg;
-    Uint32 size;
+    /* Insert a new packet at the end of the stream */
+    void insert_packet(Uint8 * data, Uint32 size);
 
-    /* Data specific to this particular stream */
-    Uint8 streamid;
-    Uint8 *packet;
-    Uint32 packetlen;
-    bool endofstream;
-    bool errorstream;
+    /* Enable or disable the stream to receive data */
+    void enable(bool state);
 
-    /* Data to mark part of the stream */
-    Uint8 *marked_packet;
-    Uint32 marked_packetlen;
-    Uint8 *marker;
-
-#ifdef USE_SYSTEM_TIMESTAMP
-    /* Current timestamp for this stream */
-    double timestamp;
-    double timedrift;
-#endif
-
-/* Caution: these may go away (e.g. stream is based on stdio) */
+    /* Check if the stream is enabled */
+    bool is_enabled();
 public:
+    Uint8 streamid;
+
+    // TODO: That shouldn't be public
     Uint8 *data;
+
+protected:
     Uint8 *stop;
+
+    Uint32 preread_size;
+
+    class MPEGsystem * system;
+    MPEGlist * br;
+    bool enabled;
+
+    SDL_mutex * mutex;
+
+    bool next_buffer();
 };
 
 #endif /* _MPEGSTREAM_H_ */
+
+
diff -Naur smpeg/MPEGsystem.cpp smpeg.patched/MPEGsystem.cpp
--- smpeg/MPEGsystem.cpp	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/MPEGsystem.cpp	Thu Mar  9 21:29:50 2000
@@ -0,0 +1,644 @@
+#include <stdlib.h>        /* for realloc() */
+#include <string.h>        /* for memmove() */
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <assert.h>
+
+#include "MPEGsystem.h"
+#include "MPEGstream.h"
+
+Uint8 const PACKET_CODE[]       = { 0x00, 0x00, 0x01, 0xba };
+Uint8 const PACKET_MASK[]       = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const END_CODE[]          = { 0x00, 0x00, 0x01, 0xb9 };
+Uint8 const END_MASK[]          = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const END2_CODE[]         = { 0x00, 0x00, 0x01, 0xb7 };
+Uint8 const END2_MASK[]         = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const VIDEO_CODE[]        = { 0x00, 0x00, 0x01, 0xb3 };
+Uint8 const VIDEO_MASK[]        = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const AUDIO_CODE[]        = { 0xff, 0xf0, 0x00, 0x00 };
+Uint8 const AUDIO_MASK[]        = { 0xff, 0xf0, 0x00, 0x00 };
+Uint8 const VIDEOSTREAM_CODE[]  = { 0x00, 0x00, 0x01, 0xe0 };
+Uint8 const VIDEOSTREAM_MASK[]  = { 0xff, 0xff, 0xff, 0xe0 };
+Uint8 const AUDIOSTREAM_CODE[]  = { 0x00, 0x00, 0x01, 0xc0 };
+Uint8 const AUDIOSTREAM_MASK[]  = { 0xff, 0xff, 0xff, 0xc0 };
+Uint8 const PADSTREAM_CODE[]    = { 0x00, 0x00, 0x01, 0xbe };
+Uint8 const PADSTREAM_MASK[]    = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const SYSTEMSTREAM_CODE[] = { 0x00, 0x00, 0x01, 0xbb };
+Uint8 const SYSTEMSTREAM_MASK[] = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const GOP_CODE[]          = { 0x00, 0x00, 0x01, 0xb8 };
+Uint8 const GOP_MASK[]          = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const USER_CODE[]         = { 0x00, 0x00, 0x01, 0xb2 };
+Uint8 const USER_MASK[]         = { 0xff, 0xff, 0xff, 0xff };
+Uint8 const PICTURE_CODE[]      = { 0x00, 0x00, 0x01, 0x00 };
+Uint8 const PICTURE_MASK[]      = { 0xff, 0xff, 0xff, 0x00 };
+
+/* The size is arbitrary but should be sufficient to contain */
+/* two MPEG packets and reduce disk (or network) access.     */
+#define MPEG_BUFFER_SIZE (64 * 1024)
+
+/* The granularity (2^LG2_GRANULARITY) determine what length of read data */
+/* will be a multiple of, e.g. setting LG2_GRANULARITY to 12 will make    */
+/* read size (when calling the read function in Read method) to be a      */
+/* multiple of 4096                                                       */
+#define LG2_GRANULARITY 12
+#define READ_ALIGN(x) (((x) >> LG2_GRANULARITY) << LG2_GRANULARITY)
+
+/* This defines the maximum data that can be preread */
+/* It is to prevent filling the whole memory with buffers on systems */
+/* where read is immediate such as in the case of files */
+#define PRE_BUFFERED_MAX (256 * 1024)
+
+/* Timeout before read fails */
+#define READ_TIME_OUT 1000000
+
+/* This work only on little endian systems */
+/*
+#define REV(x) ((((x)&0x000000FF)<<24)| \
+                (((x)&0x0000FF00)<< 8)| \
+                (((x)&0x00FF0000)>> 8)| \
+                (((x)&0xFF000000)>>24))
+#define MATCH4(x, y, m) (((x) & REV(m)) == REV(y))
+*/
+
+/* Match two 4-byte codes */
+static inline bool Match4(Uint8 const code1[4], Uint8 const code2[4], Uint8 const mask[4])
+{
+  return( ((code1[0] & mask[0]) == (code2[0] & mask[0])) &&
+	  ((code1[1] & mask[1]) == (code2[1] & mask[1])) &&
+	  ((code1[2] & mask[2]) == (code2[2] & mask[2])) &&
+	  ((code1[3] & mask[3]) == (code2[3] & mask[3])) );
+}
+
+MPEGsystem::MPEGsystem(int Mpeg_FD)
+{
+  mpeg_fd = Mpeg_FD;
+
+  /* Create a new buffer for reading */
+  read_buffer = new Uint8[MPEG_BUFFER_SIZE];
+  
+  /* Create an empty stream list */
+  stream_list = 
+    (MPEGstream **) malloc(sizeof(MPEGstream *));
+  stream_list[0] = 0;
+
+  /* Create the system stream and add it to the list */
+  if(!get_stream(SYSTEM_STREAMID))
+    add_stream(new MPEGstream(this, SYSTEM_STREAMID));
+
+  /* Invalidate the read buffer */
+  pointer = read_buffer;
+  read_size = 0;
+  read_total = 0;
+  packet_total = 0;
+  endofstream = errorstream = false;
+#ifdef USE_SYSTEM_TIMESTAMP
+  timestamp = 0.0;
+  timedrift = 0.0;
+#endif
+
+  /* Search the MPEG for the first header */
+  if(!seek_next_header())
+  {
+    errorstream = true;
+    SetError("Could not find the beginning of MPEG data\n");
+    return;
+  }
+
+  request = PRE_BUFFERED_MAX;
+
+  /* Start the system thread */
+  system_thread_running = false;
+  system_thread = SDL_CreateThread(SystemThread, this);
+
+  /* Wait for the thread to start */
+  while(!system_thread_running)
+    SDL_Delay(1);
+
+  /* Wait for prebuffering */
+  while(request > 0)
+    SDL_Delay(1);
+
+  /* Look for streams */
+  do
+    RequestBuffer();
+  while(!exist_stream(VIDEO_STREAMID, 0xF0) &&
+	!exist_stream(AUDIO_STREAMID, 0xF0) &&
+	!Eof());
+
+  /* Wait for prebuffering */
+  while(request > 0)
+    SDL_Delay(1);
+}
+
+MPEGsystem::~MPEGsystem()
+{
+  MPEGstream ** list;
+
+  /* Kill the system thread */
+  system_thread_running = false;
+  SDL_WaitThread(system_thread, NULL);
+
+  /* Delete the streams */
+  for(list = stream_list; *list; list ++)
+    delete *list;
+
+  free(stream_list);
+}
+
+MPEGstream ** MPEGsystem::GetStreamList()
+{
+  return(stream_list);
+}
+
+void MPEGsystem::Read()
+{
+  int remaining;
+  int timeout;
+
+  timeout = READ_TIME_OUT;
+  remaining = read_buffer + read_size - pointer;
+
+  /* Only read data if buffer is rather empty */
+  if(remaining < MPEG_BUFFER_SIZE / 2)
+  {
+    if(remaining < 0)
+    {
+      /* Hum.. we'd better stop if we have already read past the buffer size */
+      errorstream = true;
+      return;
+    }
+
+    /* Replace unread data at the beginning of the stream */
+    memmove(read_buffer, pointer, remaining);
+
+    /* Read new data */
+    read_size = 
+      read(mpeg_fd, read_buffer + remaining, 
+	   READ_ALIGN(MPEG_BUFFER_SIZE - remaining));
+
+    while(read_size <= 0 && errno == EAGAIN && timeout)
+    {
+      /* Wait for packet */
+      wait(0);
+
+      read_size = 
+	read(mpeg_fd, read_buffer + remaining, MPEG_BUFFER_SIZE - remaining);
+
+      timeout --;
+    }
+
+    if(read_size < 0)
+    {
+      perror("Read");
+      errorstream = true;
+      return;
+    }
+    
+    read_total += read_size;
+    request -= read_size;
+
+    packet_total ++;
+
+    if((MPEG_BUFFER_SIZE - remaining) != 0 && read_size <= 0)
+    {
+      if(read_size != 0)
+      {
+	errorstream = true;
+	return;
+      }
+    }
+
+    read_size += remaining;
+
+    if(read_size == 0)
+    {
+      /* There is no more data */
+      endofstream = true;
+      return;
+    }
+
+    /* Move the pointer */
+    pointer = read_buffer;  
+  }
+
+}
+
+/* ASSUME: stream_list[0] = system stream */
+/*         packet length < MPEG_BUFFER_SIZE */
+Uint8 MPEGsystem::FillBuffer()
+{
+  Uint8 stream_id;
+  Uint32 packet_size;
+  Uint8 const zero[4] = {0x00,0x00,0x00,0x00};
+  Uint8 const one[4]  = {0x00,0x00,0x00,0x01};
+  Uint8 const mask[4] = {0xff,0xff,0xff,0xff};
+
+  /* - Read a new packet - */
+  Read();
+
+  if(Eof()) 
+    return(0);
+
+  /* Skip possible zeros at the beggining of the packet */
+  while(Match4(pointer, zero, mask))
+  {
+    pointer++;
+    Read();
+    if(Eof())
+      return(0);
+
+    if(Match4(pointer, one, mask))
+      pointer++;
+  }
+
+  /* Parse the packet header */
+  if(Match4(pointer, PACKET_CODE, PACKET_MASK))
+  {
+    Uint8 stuffing_byte;
+
+    /* Parse the packet information */
+    pointer += 4;
+
+    /* The system stream timestamp is not very useful to us since we
+       don't coordinate the audio and video threads very tightly, and
+       we read in large amounts of data at once in the video stream.
+       BUT... if you need it, here it is.
+    */
+
+#ifdef USE_SYSTEM_TIMESTAMP
+#define FLOAT_0x10000 (double)((Uint32)1 << 16)
+#define STD_SYSTEM_CLOCK_FREQ 90000L
+    { 
+      Uint8 hibit; Uint32 lowbytes;
+
+      hibit = (pointer[0]>>3)&0x01;
+      lowbytes = (((Uint32)pointer[0] >> 1) & 0x03) << 30;
+      lowbytes |= (Uint32)pointer[1] << 22;
+      lowbytes |= ((Uint32)pointer[2] >> 1) << 15;
+      lowbytes |= (Uint32)pointer[3] << 7;
+      lowbytes |= ((Uint32)pointer[4]) >> 1;
+      timestamp = (double)hibit*FLOAT_0x10000*FLOAT_0x10000+(double)lowbytes;
+      timestamp /= STD_SYSTEM_CLOCK_FREQ;
+    }
+#endif
+    pointer += 8;
+  }
+
+  /* Parse the stream packet */
+  if(Match4(pointer, SYSTEMSTREAM_CODE, SYSTEMSTREAM_MASK) ||
+     Match4(pointer, PADSTREAM_CODE, PADSTREAM_MASK) ||
+     Match4(pointer, AUDIOSTREAM_CODE, AUDIOSTREAM_MASK) ||
+     Match4(pointer, VIDEOSTREAM_CODE, VIDEOSTREAM_MASK))
+  {
+    /* Get the stream id, and packet length */
+    stream_id = pointer[3];
+    pointer += 4;
+    packet_size = (((unsigned short) pointer[0] << 8) | pointer[1]);
+    pointer += 2;
+
+    /* Skip stuffing bytes */
+    while ( pointer[0] == 0xff ) {
+      ++pointer;
+      --packet_size;
+    }
+    if ( (pointer[0] & 0x40) == 0x40 ) {
+      pointer += 2;
+      packet_size -= 2;
+    }
+    if ( (pointer[0] & 0x30) == 0x30 ) {
+      pointer += 9;
+      packet_size -= 9;
+    } else if ( (pointer[0] & 0x20) == 0x20 ) {
+      pointer += 4;
+      packet_size -= 4;
+    } else if ( pointer[0] != 0x0f && pointer[0] != 0x80) {
+      	errorstream = true;
+	return(0);
+      }
+    ++pointer;
+    --packet_size;
+
+    if(read_buffer + read_size - pointer < 0)
+    {
+      errorstream = true;
+      return(0);
+    }
+  }
+  else
+  if(Match4(pointer, END_CODE, END_MASK) ||
+     Match4(pointer, END2_CODE, END2_MASK))
+  {
+    /* End codes belong to video stream */
+    stream_id = exist_stream(VIDEO_STREAMID, 0xF0);
+    packet_size = read_buffer + read_size - pointer;
+  }
+  else
+  {
+    stream_id = stream_list[0]->streamid;
+
+    if(!stream_list[1])
+    {
+      /* There is no system info in the stream */
+
+      /* If we're still a system stream, morph to an audio */
+      /* or video stream */
+
+      if(Match4(pointer, AUDIO_CODE, AUDIO_MASK))
+      {
+	stream_id = AUDIO_STREAMID;
+	stream_list[0]->streamid = stream_id;
+      }
+      if(Match4(pointer, VIDEO_CODE, VIDEO_MASK))
+      {
+	stream_id = VIDEO_STREAMID;
+	stream_list[0]->streamid = stream_id;
+      }
+
+      if(stream_id == SYSTEM_STREAMID)
+	stream_id = 0;
+
+      packet_size = read_buffer + read_size - pointer;
+    }
+    else
+    {
+	fprintf(stderr,
+		"Warning: unexpected header %02x%02x%02x%02x at offset %d\n",
+		pointer[0],
+		pointer[1],
+		pointer[2],
+		pointer[3],
+		Tell() - read_size + (pointer - read_buffer));
+	pointer++;
+	seek_next_header();
+	return(0);
+    }
+  }
+
+  if(Eof())
+    return(0);
+
+  assert(packet_size <= MPEG_BUFFER_SIZE);
+
+  switch(stream_id)
+  {
+    case 0:
+      /* Unknown stream, just get another packet */
+      pointer += packet_size;
+    return(stream_id);
+
+    case SYSTEM_STREAMID:
+      /* System header */
+
+      /* This MPEG contain system information */
+      /* Parse the system header and create MPEG streams  */
+    
+      /* Read the stream table */
+      pointer += 5;
+
+      while (pointer[0] & 0x80 )
+      {
+	/* If the stream doesn't already exist */
+	if(!get_stream(pointer[1]))
+	{
+	  /* Create a new stream and add it to the list */
+	  add_stream(new MPEGstream(this, pointer[1]));
+	}
+	pointer += 3;
+      }          
+      /* Hack to detect video streams that are not advertised */
+      if ( ! exist_stream(VIDEO_STREAMID, 0xF0) ) {
+	// TEMP
+	printf("HACK operationnal\n");
+	if ( pointer[3] == 0xb3 ) {
+	  add_stream(new MPEGstream(this, VIDEO_STREAMID));
+	}
+      }
+    return(stream_id);
+
+    default:
+      MPEGstream * stream;
+
+      /* Look for the stream the data must be given to */
+      stream = get_stream(stream_id);
+
+      if(!stream)
+      {
+	/* No stream found for packet, skip it */
+	pointer += packet_size;
+	return(stream_id);
+      }
+
+      /* Insert the new data at the end of the stream */
+      stream->insert_packet(pointer, packet_size);
+      pointer += packet_size;
+    return(stream_id);
+  }
+}
+
+Uint32 MPEGsystem::Tell()
+{
+  /* Warning: 32 bits means that files > 4Go might return bad values */
+  return(read_total);
+}
+
+void MPEGsystem::Rewind()
+{
+  request = 0;
+
+  /* Force the system thread to die */
+  system_thread_running = false;
+  SDL_WaitThread(system_thread, NULL);
+
+  /* Reset the streams */
+  reset_all_streams();
+
+  /* Get back to the beginning of the stream */
+  if(lseek(mpeg_fd, 0, SEEK_SET) == (off_t) -1)
+  {
+    if(errno != ESPIPE)
+    {
+      errorstream = true;
+      SetError(strerror(errno));
+      return;
+    }
+    else
+    {
+      return;
+    }
+  }
+
+  /* Reinitialize the read buffer */
+  pointer = read_buffer;
+  read_size = 0;
+  read_total = 0;
+  packet_total = 0;
+  endofstream = false;
+  errorstream = false;
+
+  /* Get the first header */
+  if(!seek_next_header())
+  {
+    errorstream = true;
+    SetError("Could not find the beginning of MPEG data\n");
+    return;
+  }
+
+  request = PRE_BUFFERED_MAX;
+
+  /* Start the system thread */
+  system_thread_running = false;
+  system_thread = SDL_CreateThread(SystemThread, this);
+
+  /* Wait for prebuffering */
+  while(request > 0)
+    SDL_Delay(1);
+}
+
+void MPEGsystem::RequestBuffer()
+{
+  if(request < PRE_BUFFERED_MAX) request += MPEG_BUFFER_SIZE;
+}
+
+bool MPEGsystem::Eof() const
+{
+  return(errorstream || endofstream);
+}
+
+int MPEGsystem::SystemThread(void * udata)
+{
+  MPEGsystem * system = (MPEGsystem *) udata;
+
+  /* Set asynchronous I/O */
+  fcntl(system->mpeg_fd, F_SETFL, O_ASYNC | O_NONBLOCK);
+
+  /* Set the file descriptor owner */
+  fcntl(system->mpeg_fd, F_SETOWN, getpid());
+
+  /* Hook to the I/O signal */
+  signal(SIGIO, Handler_IO);
+  signal(SIGURG, Handler_IO);
+
+  /* Set low priority */
+  nice(1);
+
+  system->system_thread_running = true;
+
+  while(!system->Eof() && system->system_thread_running)
+  {
+    int delay = 1;
+
+    /* Is a buffer needed? */
+    if(system->request > 0)
+    {
+      /* Read the buffer */
+      system->FillBuffer();
+      delay >>= 1;
+    }
+    else
+    {
+      /* Wait more and more time to avoid take too much cpu time when */
+      /* there are no packets requested */
+      usleep(delay++);
+    }
+  }
+
+  system->system_thread_running = false;
+
+  return(true);
+}
+
+void MPEGsystem::Handler_IO(int signal)
+{
+  switch(signal)
+  {
+    case SIGIO:
+      //printf("I/O signal caught\n");
+    break;
+    case SIGURG:
+      //printf("URG signal caught\n");
+    break;
+  }
+}
+
+void MPEGsystem::add_stream(MPEGstream * stream)
+{
+  register int i;
+
+  /* Go to the end of the list */
+  for(i = 0; stream_list[i]; i++);
+
+  /* Resize list */
+  stream_list = 
+    (MPEGstream **) realloc(stream_list, (i+2)*sizeof(MPEGstream *));
+
+  /* Write the stream */
+  stream_list[i] = stream;
+  
+  /* Put the end marker (null) */
+  stream_list[i+1] = 0;
+}
+
+MPEGstream * MPEGsystem::get_stream(Uint8 stream_id)
+{
+  register int i;
+
+  for(i = 0; stream_list[i]; i++)
+    if(stream_list[i]->streamid == stream_id)
+      break;
+
+  return(stream_list[i]);
+}
+
+Uint8 MPEGsystem::exist_stream(Uint8 stream_id, Uint8 mask)
+{
+  register int i;
+
+  for(i = 0; stream_list[i]; i++)
+    if(((stream_list[i]->streamid) & mask) == (stream_id & mask))
+      return(stream_list[i]->streamid);
+
+  return(0);
+}
+
+void MPEGsystem::reset_all_streams()
+{
+  register int i;
+
+  /* Reset the streams */
+  for(i = 0; stream_list[i]; i++)
+    stream_list[i]->reset_stream();
+}
+
+bool MPEGsystem::seek_next_header()
+{
+  Read();
+
+  if(Eof())
+    return(false);
+
+  while(!(Match4(pointer, PACKET_CODE, PACKET_MASK) ||
+	  Match4(pointer, VIDEO_CODE, VIDEO_MASK) ||
+	  Match4(pointer, AUDIO_CODE, AUDIO_MASK) ||
+	  Match4(pointer, END_CODE, END_MASK) ||
+	  Match4(pointer, VIDEOSTREAM_CODE, VIDEOSTREAM_MASK) ||
+	  Match4(pointer, AUDIOSTREAM_CODE, AUDIOSTREAM_MASK) ||
+	  Match4(pointer, GOP_CODE, GOP_MASK) ||
+	  Match4(pointer, USER_CODE, USER_MASK) ||
+	  Match4(pointer, PICTURE_CODE, PICTURE_MASK)))
+  {
+       ++pointer;
+
+      /* Make sure buffer is always full */
+      Read();
+
+      if(Eof())
+	return(false);
+  }
+
+  return(true);
+}
diff -Naur smpeg/MPEGsystem.h smpeg.patched/MPEGsystem.h
--- smpeg/MPEGsystem.h	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/MPEGsystem.h	Thu Mar  9 19:09:08 2000
@@ -0,0 +1,85 @@
+/* A class based on the MPEG stream class, used to parse the system stream */
+
+#ifndef _MPEGSYSTEM_H_
+#define _MPEGSYSTEM_H_
+
+#include "SDL.h"
+#include "SDL_thread.h"
+#include "MPEGerror.h"
+
+class MPEGstream;
+
+/* MPEG System library
+   by Vivien Chappelier */
+
+/* The system class is necessary for splitting the MPEG stream into */
+/* peaces of data that will be sent to the audio or video decoder.  */
+
+class MPEGsystem : public MPEGerror
+{
+public:
+    MPEGsystem(int MPEG_Fd);
+    virtual ~MPEGsystem();
+
+    /* Buffered I/O functions */
+    void RequestBuffer();
+    Uint32 Tell();
+    void Rewind();
+    bool Eof() const;
+
+    /* Create all the streams present in the MPEG */
+    MPEGstream ** GetStreamList();
+
+protected:
+    /* Fill a buffer */
+    Uint8 FillBuffer();
+
+    /* Read a new packet */
+    void Read();
+
+    /* The system thread which fills the FIFO */
+    static int SystemThread(void * udata);
+
+    /* The handler for I/O signals */
+    static void Handler_IO(int signal);
+
+    /* Insert a stream in the list */
+    void add_stream(MPEGstream * stream);
+
+    /* Search for a stream in the list */
+    MPEGstream * get_stream(Uint8 stream_id);
+
+    /* Test if a stream is in the list */
+    Uint8 exist_stream(Uint8 stream_id, Uint8 mask);
+
+    /* Reset all the system streams */
+    void reset_all_streams();
+
+    /* Seek the next header */
+    bool seek_next_header();
+
+    int mpeg_fd;
+
+    SDL_Thread * system_thread;
+    bool system_thread_running;
+
+    MPEGstream ** stream_list;
+
+    Uint8 * read_buffer;
+    Uint8 * pointer;
+    int read_size;
+    Uint32 read_total;
+    Uint32 packet_total;
+    int request;
+
+    bool endofstream;
+    bool errorstream;
+
+#ifdef USE_SYSTEM_TIMESTAMP
+    /* Current timestamp for this stream */
+    double timestamp;
+    double timedrift;
+#endif
+};
+#endif
+
diff -Naur smpeg/MPEGvideo.h smpeg.patched/MPEGvideo.h
--- smpeg/MPEGvideo.h	Thu Feb  3 18:45:56 2000
+++ smpeg.patched/MPEGvideo.h	Thu Mar  9 15:32:59 2000
@@ -24,9 +24,10 @@
 
 #include "SDL.h"
 #include "SDL_thread.h"
-#include "MPEGstream.h"
+#include "MPEGerror.h"
 #include "MPEGaction.h"
 
+class MPEGstream;
 
 /* This is the MPEG video stream structure in the mpeg_play code */
 struct vid_stream;
@@ -48,10 +49,10 @@
     virtual ~MPEGvideo();
 
     /* MPEG actions */
-    void Loop(bool toggle);
     void Play(void);
     void Stop(void);
     void Rewind(void);
+    void Skip(float seconds);
     MPEGstatus Status(void);
 
     /* MPEG video actions */
@@ -85,6 +86,7 @@
     int _y;             // pixel y offset
     int _uw;            // update width
     int _uh;            // update height
+    float _fps;         // frames per second
 
     int _lum[ 8 ];  	// hardcoded LUM_RANGE = 8
     int _cr[ 4 ];   	// hardcoded CR_RANGE = 4
diff -Naur smpeg/Makefile.am smpeg.patched/Makefile.am
--- smpeg/Makefile.am	Wed Mar  8 00:55:47 2000
+++ smpeg.patched/Makefile.am	Thu Mar  9 01:20:58 2000
@@ -12,7 +12,9 @@
 libsmpeg_la_SOURCES =		\
 	MPEG.cpp		\
 	MPEGring.cpp		\
+	MPEGlist.cpp		\
 	MPEGstream.cpp		\
+	MPEGsystem.cpp		\
 	smpeg.cpp
 
 libsmpegincludedir = $(includedir)/smpeg
@@ -22,7 +24,9 @@
 	MPEGaudio.h		\
 	MPEGerror.h		\
 	MPEGring.h		\
+	MPEGlist.h		\
 	MPEGstream.h		\
+	MPEGsystem.h		\
 	MPEGvideo.h		\
 	smpeg.h
 
diff -Naur smpeg/Makefile.in smpeg.patched/Makefile.in
--- smpeg/Makefile.in	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/Makefile.in	Thu Mar  9 01:21:33 2000
@@ -0,0 +1,698 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# These are the subdirectories that are always built
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AS = @AS@
+BINARY_AGE = @BINARY_AGE@
+CC = @CC@
+CXX = @CXX@
+DLLTOOL = @DLLTOOL@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_CONFIG = @GTK_CONFIG@
+GTK_LIBS = @GTK_LIBS@
+INTERFACE_AGE = @INTERFACE_AGE@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+MAJOR_VERSION = @MAJOR_VERSION@
+MAKEINFO = @MAKEINFO@
+MICRO_VERSION = @MICRO_VERSION@
+MINOR_VERSION = @MINOR_VERSION@
+NM = @NM@
+OBJDUMP = @OBJDUMP@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+VERSION = @VERSION@
+
+SUBDIRS = audio video
+
+bin_SCRIPTS = smpeg-config
+
+# The smpeg library target
+lib_LTLIBRARIES = libsmpeg.la
+
+libsmpeg_la_SOURCES =  	MPEG.cpp			MPEGring.cpp			MPEGlist.cpp			MPEGstream.cpp			MPEGsystem.cpp			smpeg.cpp
+
+
+libsmpegincludedir = $(includedir)/smpeg
+libsmpeginclude_HEADERS =  	MPEG.h				MPEGaction.h			MPEGaudio.h			MPEGerror.h			MPEGring.h			MPEGlist.h			MPEGstream.h			MPEGsystem.h			MPEGvideo.h			smpeg.h
+
+
+libsmpeg_la_LDFLAGS =          -release $(LT_RELEASE)		-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+
+
+libsmpeg_la_LIBADD =  	audio/libaudio.la		video/libvideo.la
+
+
+EXTRA_DIST =  	CHANGES			COPYING			TODO			README			README.SDL_mixer 	plaympeg.1		gtv.1
+
+@HAVE_GTK_TRUE@GTK_PLAYER = gtv
+@HAVE_GTK_FALSE@GTK_PLAYER = 
+@HAVE_MESA_TRUE@MESA_PLAYER = glmovie
+@HAVE_MESA_FALSE@MESA_PLAYER = 
+bin_PROGRAMS = plaympeg $(GTK_PLAYER) $(MESA_PLAYER)
+
+# Sources for plaympeg
+man_MANS = plaympeg.1 gtv.1
+plaympeg_SOURCES = plaympeg.c
+plaympeg_LDADD = libsmpeg.la
+
+# Sources for gtv
+gtv_SOURCES = gtv.c gtv.h
+gtv_LDADD = @GTK_LIBS@ libsmpeg.la
+
+# Sources for glmovie
+glmovie_SOURCES = glmovie-tile.c glmovie.c glmovie.h
+glmovie_LDADD = -lGL -lGLU libsmpeg.la
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES =  smpeg-config smpeg.spec
+LTLIBRARIES =  $(lib_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libsmpeg_la_DEPENDENCIES =  audio/libaudio.la video/libvideo.la
+libsmpeg_la_OBJECTS =  MPEG.lo MPEGring.lo MPEGlist.lo MPEGstream.lo \
+MPEGsystem.lo smpeg.lo
+PROGRAMS =  $(bin_PROGRAMS)
+
+plaympeg_OBJECTS =  plaympeg.o
+plaympeg_DEPENDENCIES =  libsmpeg.la
+plaympeg_LDFLAGS = 
+gtv_OBJECTS =  gtv.o
+gtv_DEPENDENCIES =  libsmpeg.la
+gtv_LDFLAGS = 
+glmovie_OBJECTS =  glmovie-tile.o glmovie.o
+glmovie_DEPENDENCIES =  libsmpeg.la
+glmovie_LDFLAGS = 
+SCRIPTS =  $(bin_SCRIPTS)
+
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+man1dir = $(mandir)/man1
+MANS = $(man_MANS)
+
+NROFF = nroff
+HEADERS =  $(libsmpeginclude_HEADERS)
+
+DIST_COMMON =  README COPYING Makefile.am Makefile.in TODO acinclude.m4 \
+aclocal.m4 config.guess config.sub configure configure.in install-sh \
+ltconfig ltmain.sh missing mkinstalldirs smpeg-config.in smpeg.spec.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+DEP_FILES =  .deps/MPEG.P .deps/MPEGlist.P .deps/MPEGring.P \
+.deps/MPEGstream.P .deps/MPEGsystem.P .deps/glmovie-tile.P \
+.deps/glmovie.P .deps/gtv.P .deps/plaympeg.P .deps/smpeg.P
+SOURCES = $(libsmpeg_la_SOURCES) $(plaympeg_SOURCES) $(gtv_SOURCES) $(glmovie_SOURCES)
+OBJECTS = $(libsmpeg_la_OBJECTS) $(plaympeg_OBJECTS) $(gtv_OBJECTS) $(glmovie_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cpp .lo .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4):  configure.in  acinclude.m4
+	cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+	cd $(srcdir) && $(AUTOCONF)
+smpeg-config: $(top_builddir)/config.status smpeg-config.in
+	cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+smpeg.spec: $(top_builddir)/config.status smpeg.spec.in
+	cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+mostlyclean-libLTLIBRARIES:
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+
+distclean-libLTLIBRARIES:
+
+maintainer-clean-libLTLIBRARIES:
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(libdir)
+	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo "$(LIBTOOL)  --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p"; \
+	    $(LIBTOOL)  --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p; \
+	  else :; fi; \
+	done
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  $(LIBTOOL)  --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \
+	done
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+	$(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+	$(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libsmpeg.la: $(libsmpeg_la_OBJECTS) $(libsmpeg_la_DEPENDENCIES)
+	$(CXXLINK) -rpath $(libdir) $(libsmpeg_la_LDFLAGS) $(libsmpeg_la_OBJECTS) $(libsmpeg_la_LIBADD) $(LIBS)
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+	-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+	    $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+	  else :; fi; \
+	done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+	done
+
+plaympeg: $(plaympeg_OBJECTS) $(plaympeg_DEPENDENCIES)
+	@rm -f plaympeg
+	$(LINK) $(plaympeg_LDFLAGS) $(plaympeg_OBJECTS) $(plaympeg_LDADD) $(LIBS)
+
+gtv: $(gtv_OBJECTS) $(gtv_DEPENDENCIES)
+	@rm -f gtv
+	$(LINK) $(gtv_LDFLAGS) $(gtv_OBJECTS) $(gtv_LDADD) $(LIBS)
+
+glmovie: $(glmovie_OBJECTS) $(glmovie_DEPENDENCIES)
+	@rm -f glmovie
+	$(LINK) $(glmovie_LDFLAGS) $(glmovie_OBJECTS) $(glmovie_LDADD) $(LIBS)
+
+install-binSCRIPTS: $(bin_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	@list='$(bin_SCRIPTS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+	  else if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+	  else :; fi; fi; \
+	done
+
+uninstall-binSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	list='$(bin_SCRIPTS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+	done
+.cpp.o:
+	$(CXXCOMPILE) -c $<
+.cpp.lo:
+	$(LTCXXCOMPILE) -c $<
+
+install-man1:
+	$(mkinstalldirs) $(DESTDIR)$(man1dir)
+	@list='$(man1_MANS)'; \
+	l2='$(man_MANS)'; for i in $$l2; do \
+	  case "$$i" in \
+	    *.1*) list="$$list $$i" ;; \
+	  esac; \
+	done; \
+	for i in $$list; do \
+	  if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+	  else file=$$i; fi; \
+	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+	  echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \
+	  $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \
+	done
+
+uninstall-man1:
+	@list='$(man1_MANS)'; \
+	l2='$(man_MANS)'; for i in $$l2; do \
+	  case "$$i" in \
+	    *.1*) list="$$list $$i" ;; \
+	  esac; \
+	done; \
+	for i in $$list; do \
+	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+	  echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
+	  rm -f $(DESTDIR)$(man1dir)/$$inst; \
+	done
+install-man: $(MANS)
+	@$(NORMAL_INSTALL)
+	$(MAKE) $(AM_MAKEFLAGS) install-man1
+uninstall-man:
+	@$(NORMAL_UNINSTALL)
+	$(MAKE) $(AM_MAKEFLAGS) uninstall-man1
+
+install-libsmpegincludeHEADERS: $(libsmpeginclude_HEADERS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(libsmpegincludedir)
+	@list='$(libsmpeginclude_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
+	  echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(libsmpegincludedir)/$$p"; \
+	  $(INSTALL_DATA) $$d$$p $(DESTDIR)$(libsmpegincludedir)/$$p; \
+	done
+
+uninstall-libsmpegincludeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	list='$(libsmpeginclude_HEADERS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(libsmpegincludedir)/$$p; \
+	done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive  \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+	  rev="$$subdir $$rev"; \
+	  test "$$subdir" = "." && dot_seen=yes; \
+	done; \
+	test "$$dot_seen" = "no" && rev=". $$rev"; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+   if test "$$subdir" = .; then :; else \
+	    test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+   fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	-rm -rf $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+	mkdir $(distdir)/=build
+	mkdir $(distdir)/=inst
+	dc_install_base=`cd $(distdir)/=inst && pwd`; \
+	cd $(distdir)/=build \
+	  && ../configure --srcdir=.. --prefix=$$dc_install_base \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist
+	-rm -rf $(distdir)
+	@banner="$(distdir).tar.gz is ready for distribution"; \
+	dashes=`echo "$$banner" | sed s/./=/g`; \
+	echo "$$dashes"; \
+	echo "$$banner"; \
+	echo "$$dashes"
+dist: distdir
+	-chmod -R a+r $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+	-rm -rf $(distdir)
+dist-all: distdir
+	-chmod -R a+r $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+	-rm -rf $(distdir)
+distdir: $(DISTFILES)
+	-rm -rf $(distdir)
+	mkdir $(distdir)
+	-chmod 777 $(distdir)
+	here=`cd $(top_builddir) && pwd`; \
+	top_distdir=`cd $(distdir) && pwd`; \
+	distdir=`cd $(distdir) && pwd`; \
+	cd $(top_srcdir) \
+	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu Makefile
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$d/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+	for subdir in $(SUBDIRS); do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d $(distdir)/$$subdir \
+	    || mkdir $(distdir)/$$subdir \
+	    || exit 1; \
+	    chmod 777 $(distdir)/$$subdir; \
+	    (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+	-rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+	@echo '$(COMPILE) -c $<'; \
+	$(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-cp .deps/$(*F).pp .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm .deps/$(*F).pp
+
+%.lo: %.c
+	@echo '$(LTCOMPILE) -c $<'; \
+	$(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-sed -e 's/^\([^:]*\)\.o[ 	]*:/\1.lo \1.o :/' \
+	  < .deps/$(*F).pp > .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm -f .deps/$(*F).pp
+
+%.o: %.cpp
+	@echo '$(CXXCOMPILE) -c $<'; \
+	$(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-cp .deps/$(*F).pp .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm .deps/$(*F).pp
+
+%.lo: %.cpp
+	@echo '$(LTCXXCOMPILE) -c $<'; \
+	$(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-sed -e 's/^\([^:]*\)\.o[ 	]*:/\1.lo \1.o :/' \
+	  < .deps/$(*F).pp > .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm -f .deps/$(*F).pp
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am: all-am
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+install-exec-am: install-libLTLIBRARIES install-binPROGRAMS \
+		install-binSCRIPTS
+install-exec: install-exec-recursive
+
+install-data-am: install-man install-libsmpegincludeHEADERS
+install-data: install-data-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am: uninstall-libLTLIBRARIES uninstall-binPROGRAMS \
+		uninstall-binSCRIPTS uninstall-man \
+		uninstall-libsmpegincludeHEADERS
+uninstall: uninstall-recursive
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) $(MANS) \
+		$(HEADERS)
+all-redirect: all-recursive
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+	$(mkinstalldirs)  $(DESTDIR)$(libdir) $(DESTDIR)$(bindir) \
+		$(DESTDIR)$(bindir) $(DESTDIR)$(mandir)/man1 \
+		$(DESTDIR)$(libsmpegincludedir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-libLTLIBRARIES mostlyclean-compile \
+		mostlyclean-libtool mostlyclean-binPROGRAMS \
+		mostlyclean-tags mostlyclean-depend mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am:  clean-libLTLIBRARIES clean-compile clean-libtool \
+		clean-binPROGRAMS clean-tags clean-depend clean-generic \
+		mostlyclean-am
+
+clean: clean-recursive
+
+distclean-am:  distclean-libLTLIBRARIES distclean-compile \
+		distclean-libtool distclean-binPROGRAMS distclean-tags \
+		distclean-depend distclean-generic clean-am
+	-rm -f libtool
+
+distclean: distclean-recursive
+	-rm -f config.status
+
+maintainer-clean-am:  maintainer-clean-libLTLIBRARIES \
+		maintainer-clean-compile maintainer-clean-libtool \
+		maintainer-clean-binPROGRAMS maintainer-clean-tags \
+		maintainer-clean-depend maintainer-clean-generic \
+		distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f config.status
+
+.PHONY: mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \
+clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \
+uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \
+distclean-compile clean-compile maintainer-clean-compile \
+mostlyclean-libtool distclean-libtool clean-libtool \
+maintainer-clean-libtool mostlyclean-binPROGRAMS distclean-binPROGRAMS \
+clean-binPROGRAMS maintainer-clean-binPROGRAMS uninstall-binPROGRAMS \
+install-binPROGRAMS uninstall-binSCRIPTS install-binSCRIPTS \
+install-man1 uninstall-man1 install-man uninstall-man \
+uninstall-libsmpegincludeHEADERS install-libsmpegincludeHEADERS \
+install-data-recursive uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs-am installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Rule to build tar-gzipped distribution package
+$(PACKAGE)-$(VERSION).tar.gz: dist
+
+# Rule to build RPM distribution package
+rpm: $(PACKAGE)-$(VERSION).tar.gz
+	cp $(PACKAGE)-$(VERSION).tar.gz /usr/src/redhat/SOURCES
+	rpm -ba smpeg.spec
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff -Naur smpeg/aclocal.m4 smpeg.patched/aclocal.m4
--- smpeg/aclocal.m4	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/aclocal.m4	Thu Mar  9 01:21:30 2000
@@ -0,0 +1,918 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# Configure paths for SDL
+# Sam Lantinga 9/21/99
+# stolen from Manish Singh
+# stolen back from Frank Belew
+# stolen from Manish Singh
+# Shamelessly stolen from Owen Taylor
+
+dnl AM_PATH_SDL([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
+dnl
+AC_DEFUN(AM_PATH_SDL,
+[dnl 
+dnl Get the cflags and libraries from the sdl-config script
+dnl
+AC_ARG_WITH(sdl-prefix,[  --with-sdl-prefix=PFX   Prefix where SDL is installed (optional)],
+            sdl_prefix="$withval", sdl_prefix="")
+AC_ARG_WITH(sdl-exec-prefix,[  --with-sdl-exec-prefix=PFX Exec prefix where SDL is installed (optional)],
+            sdl_exec_prefix="$withval", sdl_exec_prefix="")
+AC_ARG_ENABLE(sdltest, [  --disable-sdltest       Do not try to compile and run a test SDL program],
+		    , enable_sdltest=yes)
+
+  if test x$sdl_exec_prefix != x ; then
+     sdl_args="$sdl_args --exec-prefix=$sdl_exec_prefix"
+     if test x${SDL_CONFIG+set} != xset ; then
+        SDL_CONFIG=$sdl_exec_prefix/bin/sdl-config
+     fi
+  fi
+  if test x$sdl_prefix != x ; then
+     sdl_args="$sdl_args --prefix=$sdl_prefix"
+     if test x${SDL_CONFIG+set} != xset ; then
+        SDL_CONFIG=$sdl_prefix/bin/sdl-config
+     fi
+  fi
+
+  AC_PATH_PROG(SDL_CONFIG, sdl-config, no)
+  min_sdl_version=ifelse([$1], ,0.11.0,$1)
+  AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)
+  no_sdl=""
+  if test "$SDL_CONFIG" = "no" ; then
+    no_sdl=yes
+  else
+    SDL_CFLAGS=`$SDL_CONFIG $sdlconf_args --cflags`
+    SDL_LIBS=`$SDL_CONFIG $sdlconf_args --libs`
+
+    sdl_major_version=`$SDL_CONFIG $sdl_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    sdl_minor_version=`$SDL_CONFIG $sdl_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    sdl_micro_version=`$SDL_CONFIG $sdl_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_sdltest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $SDL_CFLAGS"
+      LIBS="$LIBS $SDL_LIBS"
+dnl
+dnl Now check if the installed SDL is sufficiently new. (Also sanity
+dnl checks the results of sdl-config to some extent
+dnl
+      rm -f conf.sdltest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SDL.h"
+
+char*
+my_strdup (char *str)
+{
+  char *new_str;
+  
+  if (str)
+    {
+      new_str = malloc ((strlen (str) + 1) * sizeof(char));
+      strcpy (new_str, str);
+    }
+  else
+    new_str = NULL;
+  
+  return new_str;
+}
+
+int main ()
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  system ("touch conf.sdltest");
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = my_strdup("$min_sdl_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_sdl_version");
+     exit(1);
+   }
+
+   if (($sdl_major_version > major) ||
+      (($sdl_major_version == major) && ($sdl_minor_version > minor)) ||
+      (($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro)))
+    {
+      return 0;
+    }
+  else
+    {
+      printf("\n*** 'sdl-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version);
+      printf("*** of SDL required is %d.%d.%d. If sdl-config is correct, then it is\n", major, minor, micro);
+      printf("*** best to upgrade to the required version.\n");
+      printf("*** If sdl-config was wrong, set the environment variable SDL_CONFIG\n");
+      printf("*** to point to the correct copy of sdl-config, and remove the file\n");
+      printf("*** config.cache before re-running configure\n");
+      return 1;
+    }
+}
+
+],, no_sdl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_sdl" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])     
+  else
+     AC_MSG_RESULT(no)
+     if test "$SDL_CONFIG" = "no" ; then
+       echo "*** The sdl-config script installed by SDL could not be found"
+       echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the SDL_CONFIG environment variable to the"
+       echo "*** full path to sdl-config."
+     else
+       if test -f conf.sdltest ; then
+        :
+       else
+          echo "*** Could not run SDL test program, checking why..."
+          CFLAGS="$CFLAGS $SDL_CFLAGS"
+          LIBS="$LIBS $SDL_LIBS"
+          AC_TRY_LINK([
+#include <stdio.h>
+#include "SDL.h"
+],      [ return 0; ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding SDL or finding the wrong"
+          echo "*** version of SDL. If it is not finding SDL, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means SDL was incorrectly installed"
+          echo "*** or that you have moved SDL since it was installed. In the latter case, you"
+          echo "*** may want to edit the sdl-config script: $SDL_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     SDL_CFLAGS=""
+     SDL_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(SDL_CFLAGS)
+  AC_SUBST(SDL_LIBS)
+  rm -f conf.sdltest
+])
+
+# serial 41 AC_PROG_LIBTOOL
+AC_DEFUN(AC_PROG_LIBTOOL,
+[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+
+# Save cache, so that ltconfig can load it
+AC_CACHE_SAVE
+
+# Actually configure libtool.  ac_aux_dir is where install-sh is found.
+CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \
+LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \
+LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \
+DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \
+${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \
+$libtool_flags --no-verify --build="$build" $ac_aux_dir/ltmain.sh $host \
+|| AC_MSG_ERROR([libtool configure failed])
+
+# Reload cache, that may have been modified by ltconfig
+AC_CACHE_LOAD
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+# Redirect the config.log output again, so that the ltconfig log is not
+# clobbered by the next message.
+exec 5>>./config.log
+])
+
+AC_DEFUN(AC_LIBTOOL_SETUP,
+[AC_PREREQ(2.13)dnl
+AC_REQUIRE([AC_ENABLE_SHARED])dnl
+AC_REQUIRE([AC_ENABLE_STATIC])dnl
+AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_LD])dnl
+AC_REQUIRE([AC_PROG_NM])dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+dnl
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+
+# Check for any special flags to pass to ltconfig.
+libtool_flags="--cache-file=$cache_file"
+test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared"
+test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static"
+test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install"
+test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc"
+test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld"
+ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN],
+[libtool_flags="$libtool_flags --enable-dlopen"])
+ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
+[libtool_flags="$libtool_flags --enable-win32-dll"])
+AC_ARG_ENABLE(libtool-lock,
+  [  --disable-libtool-lock  avoid locking (might break parallel builds)])
+test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock"
+test x"$silent" = xyes && libtool_flags="$libtool_flags --silent"
+
+AC_ARG_WITH(pic,
+  [  --with-pic              try to use only PIC/non-PIC objects [default=use both]],
+     pic_mode="$withval", pic_mode=default)
+test x"$pic_mode" = xyes && libtool_flags="$libtool_flags --prefer-pic"
+test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic"
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case "$host" in
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case "`/usr/bin/file conftest.o`" in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+
+ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
+[*-*-cygwin* | *-*-mingw*)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+
+  # recent cygwin and mingw systems supply a stub DllMain which the user
+  # can override, but on older systems we have to supply one
+  AC_CACHE_CHECK([if libtool should supply DllMain function], lt_cv_need_dllmain,
+    [AC_TRY_LINK([DllMain (0, 0, 0);],
+      [extern int __attribute__((__stdcall__)) DllMain(void*, int, void*);],
+      [lt_cv_need_dllmain=yes],[lt_cv_need_dllmain=no])])
+
+  case $host in
+  *-*-cygwin*)
+    # cygwin systems need to pass --dll to the linker, and not link
+    # crt.o which will require a WinMain@16 definition.
+    lt_cv_cc_dll_switch="-Wl,--dll -nostartfiles" ;;
+  *-*-mingw*)
+    # old mingw systems require "-dll" to link a DLL, while more recent ones
+    # require "-mdll"
+    SAVE_CFLAGS="$CFLAGS"
+    CFLAGS="$CFLAGS -mdll"
+    AC_CACHE_CHECK([how to link DLLs], lt_cv_cc_dll_switch,
+      [AC_TRY_LINK([], [], [lt_cv_cc_dll_switch=-mdll],[lt_cv_cc_dll_switch=-dll])])
+    CFLAGS="$SAVE_CFLAGS" ;;
+  esac
+  ;;
+  ])
+esac
+])
+
+# AC_LIBTOOL_DLOPEN - enable checks for dlopen support
+AC_DEFUN(AC_LIBTOOL_DLOPEN, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])])
+
+# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's
+AC_DEFUN(AC_LIBTOOL_WIN32_DLL, [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])])
+
+# AC_ENABLE_SHARED - implement the --enable-shared flag
+# Usage: AC_ENABLE_SHARED[(DEFAULT)]
+#   Where DEFAULT is either `yes' or `no'.  If omitted, it defaults to
+#   `yes'.
+AC_DEFUN(AC_ENABLE_SHARED, [dnl
+define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(shared,
+changequote(<<, >>)dnl
+<<  --enable-shared[=PKGS]  build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT],
+changequote([, ])dnl
+[p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_shared=yes ;;
+no) enable_shared=no ;;
+*)
+  enable_shared=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_shared=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac],
+enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl
+])
+
+# AC_DISABLE_SHARED - set the default shared flag to --disable-shared
+AC_DEFUN(AC_DISABLE_SHARED, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_SHARED(no)])
+
+# AC_ENABLE_STATIC - implement the --enable-static flag
+# Usage: AC_ENABLE_STATIC[(DEFAULT)]
+#   Where DEFAULT is either `yes' or `no'.  If omitted, it defaults to
+#   `yes'.
+AC_DEFUN(AC_ENABLE_STATIC, [dnl
+define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(static,
+changequote(<<, >>)dnl
+<<  --enable-static[=PKGS]  build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT],
+changequote([, ])dnl
+[p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_static=yes ;;
+no) enable_static=no ;;
+*)
+  enable_static=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_static=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac],
+enable_static=AC_ENABLE_STATIC_DEFAULT)dnl
+])
+
+# AC_DISABLE_STATIC - set the default static flag to --disable-static
+AC_DEFUN(AC_DISABLE_STATIC, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_STATIC(no)])
+
+
+# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag
+# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)]
+#   Where DEFAULT is either `yes' or `no'.  If omitted, it defaults to
+#   `yes'.
+AC_DEFUN(AC_ENABLE_FAST_INSTALL, [dnl
+define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(fast-install,
+changequote(<<, >>)dnl
+<<  --enable-fast-install[=PKGS]  optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT],
+changequote([, ])dnl
+[p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_fast_install=yes ;;
+no) enable_fast_install=no ;;
+*)
+  enable_fast_install=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_fast_install=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac],
+enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl
+])
+
+# AC_ENABLE_FAST_INSTALL - set the default to --disable-fast-install
+AC_DEFUN(AC_DISABLE_FAST_INSTALL, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_FAST_INSTALL(no)])
+
+# AC_PROG_LD - find the path to the GNU or non-GNU linker
+AC_DEFUN(AC_PROG_LD,
+[AC_ARG_WITH(gnu-ld,
+[  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$ac_cv_prog_gcc" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by GCC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case "$ac_prog" in
+    # Accept absolute paths.
+changequote(,)dnl
+    [\\/]* | [A-Za-z]:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+changequote([,])dnl
+      # Canonicalize the path of ld
+      ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(ac_cv_path_LD,
+[if test -z "$LD"; then
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      ac_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+	test "$with_gnu_ld" != no && break
+      else
+	test "$with_gnu_ld" != yes && break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+else
+  ac_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$ac_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_SUBST(LD)
+AC_PROG_LD_GNU
+])
+
+AC_DEFUN(AC_PROG_LD_GNU,
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+  ac_cv_prog_gnu_ld=yes
+else
+  ac_cv_prog_gnu_ld=no
+fi])
+])
+
+# AC_PROG_NM - find the path to a BSD-compatible name lister
+AC_DEFUN(AC_PROG_NM,
+[AC_MSG_CHECKING([for BSD-compatible nm])
+AC_CACHE_VAL(ac_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  ac_cv_path_NM="$NM"
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+  for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then
+      # Check to see if the nm accepts a BSD-compat flag.
+      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+      #   nm: unknown option "B" ignored
+      if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+	ac_cv_path_NM="$ac_dir/nm -B"
+	break
+      elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+	ac_cv_path_NM="$ac_dir/nm -p"
+	break
+      else
+	ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but
+	continue # so that we can try to find one that supports BSD flags
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
+fi])
+NM="$ac_cv_path_NM"
+AC_MSG_RESULT([$NM])
+AC_SUBST(NM)
+])
+
+# AC_CHECK_LIBM - check for math library
+AC_DEFUN(AC_CHECK_LIBM,
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case "$host" in
+*-*-beos* | *-*-cygwin*)
+  # These system don't have libm
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, main, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, main, LIBM="-lm")
+  ;;
+esac
+])
+
+# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for
+# the libltdl convenience library, adds --enable-ltdl-convenience to
+# the configure arguments.  Note that LIBLTDL is not AC_SUBSTed, nor
+# is AC_CONFIG_SUBDIRS called.  If DIR is not provided, it is assumed
+# to be `${top_builddir}/libltdl'.  Make sure you start DIR with
+# '${top_builddir}/' (note the single quotes!) if your package is not
+# flat, and, if you're not using automake, define top_builddir as
+# appropriate in the Makefiles.
+AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  case "$enable_ltdl_convenience" in
+  no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+  "") enable_ltdl_convenience=yes
+      ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
+  esac
+  LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdlc.la
+  INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl'])
+])
+
+# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for
+# the libltdl installable library, and adds --enable-ltdl-install to
+# the configure arguments.  Note that LIBLTDL is not AC_SUBSTed, nor
+# is AC_CONFIG_SUBDIRS called.  If DIR is not provided, it is assumed
+# to be `${top_builddir}/libltdl'.  Make sure you start DIR with
+# '${top_builddir}/' (note the single quotes!) if your package is not
+# flat, and, if you're not using automake, define top_builddir as
+# appropriate in the Makefiles.
+# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  AC_CHECK_LIB(ltdl, main,
+  [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+  [if test x"$enable_ltdl_install" = xno; then
+     AC_MSG_WARN([libltdl not installed, but installation disabled])
+   else
+     enable_ltdl_install=yes
+   fi
+  ])
+  if test x"$enable_ltdl_install" = x"yes"; then
+    ac_configure_args="$ac_configure_args --enable-ltdl-install"
+    LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdl.la
+    INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl'])
+  else
+    ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+    LIBLTDL="-lltdl"
+    INCLTDL=
+  fi
+])
+
+dnl old names
+AC_DEFUN(AM_PROG_LIBTOOL, [indir([AC_PROG_LIBTOOL])])dnl
+AC_DEFUN(AM_ENABLE_SHARED, [indir([AC_ENABLE_SHARED], $@)])dnl
+AC_DEFUN(AM_ENABLE_STATIC, [indir([AC_ENABLE_STATIC], $@)])dnl
+AC_DEFUN(AM_DISABLE_SHARED, [indir([AC_DISABLE_SHARED], $@)])dnl
+AC_DEFUN(AM_DISABLE_STATIC, [indir([AC_DISABLE_STATIC], $@)])dnl
+AC_DEFUN(AM_PROG_LD, [indir([AC_PROG_LD])])dnl
+AC_DEFUN(AM_PROG_NM, [indir([AC_PROG_NM])])dnl
+
+dnl This is just to silence aclocal about the macro not being used
+ifelse([AC_DISABLE_FAST_INSTALL])dnl
+
+# Do all the work for Automake.  This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AC_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "[$]*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "[$]*" != "X $srcdir/configure conftestfile" \
+      && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "[$]2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+   $1=$2
+   AC_MSG_RESULT(found)
+else
+   $1="$3/missing $2"
+   AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
+# Configure paths for GTK+
+# Owen Taylor     97-11-3
+
+dnl AM_PATH_GTK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]])
+dnl Test for GTK, and define GTK_CFLAGS and GTK_LIBS
+dnl
+AC_DEFUN(AM_PATH_GTK,
+[dnl 
+dnl Get the cflags and libraries from the gtk-config script
+dnl
+AC_ARG_WITH(gtk-prefix,[  --with-gtk-prefix=PFX   Prefix where GTK is installed (optional)],
+            gtk_config_prefix="$withval", gtk_config_prefix="")
+AC_ARG_WITH(gtk-exec-prefix,[  --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)],
+            gtk_config_exec_prefix="$withval", gtk_config_exec_prefix="")
+AC_ARG_ENABLE(gtktest, [  --disable-gtktest       Do not try to compile and run a test GTK program],
+		    , enable_gtktest=yes)
+
+  for module in . $4
+  do
+      case "$module" in
+         gthread) 
+             gtk_config_args="$gtk_config_args gthread"
+         ;;
+      esac
+  done
+
+  if test x$gtk_config_exec_prefix != x ; then
+     gtk_config_args="$gtk_config_args --exec-prefix=$gtk_config_exec_prefix"
+     if test x${GTK_CONFIG+set} != xset ; then
+        GTK_CONFIG=$gtk_config_exec_prefix/bin/gtk-config
+     fi
+  fi
+  if test x$gtk_config_prefix != x ; then
+     gtk_config_args="$gtk_config_args --prefix=$gtk_config_prefix"
+     if test x${GTK_CONFIG+set} != xset ; then
+        GTK_CONFIG=$gtk_config_prefix/bin/gtk-config
+     fi
+  fi
+
+  AC_PATH_PROG(GTK_CONFIG, gtk-config, no)
+  min_gtk_version=ifelse([$1], ,0.99.7,$1)
+  AC_MSG_CHECKING(for GTK - version >= $min_gtk_version)
+  no_gtk=""
+  if test "$GTK_CONFIG" = "no" ; then
+    no_gtk=yes
+  else
+    GTK_CFLAGS=`$GTK_CONFIG $gtk_config_args --cflags`
+    GTK_LIBS=`$GTK_CONFIG $gtk_config_args --libs`
+    gtk_config_major_version=`$GTK_CONFIG $gtk_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    gtk_config_minor_version=`$GTK_CONFIG $gtk_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    gtk_config_micro_version=`$GTK_CONFIG $gtk_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_gtktest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $GTK_CFLAGS"
+      LIBS="$GTK_LIBS $LIBS"
+dnl
+dnl Now check if the installed GTK is sufficiently new. (Also sanity
+dnl checks the results of gtk-config to some extent
+dnl
+      rm -f conf.gtktest
+      AC_TRY_RUN([
+#include <gtk/gtk.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int 
+main ()
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  system ("touch conf.gtktest");
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = g_strdup("$min_gtk_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_gtk_version");
+     exit(1);
+   }
+
+  if ((gtk_major_version != $gtk_config_major_version) ||
+      (gtk_minor_version != $gtk_config_minor_version) ||
+      (gtk_micro_version != $gtk_config_micro_version))
+    {
+      printf("\n*** 'gtk-config --version' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", 
+             $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version,
+             gtk_major_version, gtk_minor_version, gtk_micro_version);
+      printf ("*** was found! If gtk-config was correct, then it is best\n");
+      printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n");
+      printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+      printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+      printf("*** required on your system.\n");
+      printf("*** If gtk-config was wrong, set the environment variable GTK_CONFIG\n");
+      printf("*** to point to the correct copy of gtk-config, and remove the file config.cache\n");
+      printf("*** before re-running configure\n");
+    } 
+#if defined (GTK_MAJOR_VERSION) && defined (GTK_MINOR_VERSION) && defined (GTK_MICRO_VERSION)
+  else if ((gtk_major_version != GTK_MAJOR_VERSION) ||
+	   (gtk_minor_version != GTK_MINOR_VERSION) ||
+           (gtk_micro_version != GTK_MICRO_VERSION))
+    {
+      printf("*** GTK+ header files (version %d.%d.%d) do not match\n",
+	     GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
+      printf("*** library (version %d.%d.%d)\n",
+	     gtk_major_version, gtk_minor_version, gtk_micro_version);
+    }
+#endif /* defined (GTK_MAJOR_VERSION) ... */
+  else
+    {
+      if ((gtk_major_version > major) ||
+        ((gtk_major_version == major) && (gtk_minor_version > minor)) ||
+        ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro)))
+      {
+        return 0;
+       }
+     else
+      {
+        printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n",
+               gtk_major_version, gtk_minor_version, gtk_micro_version);
+        printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n",
+	       major, minor, micro);
+        printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n");
+        printf("***\n");
+        printf("*** If you have already installed a sufficiently new version, this error\n");
+        printf("*** probably means that the wrong copy of the gtk-config shell script is\n");
+        printf("*** being found. The easiest way to fix this is to remove the old version\n");
+        printf("*** of GTK+, but you can also set the GTK_CONFIG environment to point to the\n");
+        printf("*** correct copy of gtk-config. (In this case, you will have to\n");
+        printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+        printf("*** so that the correct libraries are found at run-time))\n");
+      }
+    }
+  return 1;
+}
+],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_gtk" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])     
+  else
+     AC_MSG_RESULT(no)
+     if test "$GTK_CONFIG" = "no" ; then
+       echo "*** The gtk-config script installed by GTK could not be found"
+       echo "*** If GTK was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the GTK_CONFIG environment variable to the"
+       echo "*** full path to gtk-config."
+     else
+       if test -f conf.gtktest ; then
+        :
+       else
+          echo "*** Could not run GTK test program, checking why..."
+          CFLAGS="$CFLAGS $GTK_CFLAGS"
+          LIBS="$LIBS $GTK_LIBS"
+          AC_TRY_LINK([
+#include <gtk/gtk.h>
+#include <stdio.h>
+],      [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding GTK or finding the wrong"
+          echo "*** version of GTK. If it is not finding GTK, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+          echo "***"
+          echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that"
+          echo "*** came with the system with the command"
+          echo "***"
+          echo "***    rpm --erase --nodeps gtk gtk-devel" ],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means GTK was incorrectly installed"
+          echo "*** or that you have moved GTK since it was installed. In the latter case, you"
+          echo "*** may want to edit the gtk-config script: $GTK_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     GTK_CFLAGS=""
+     GTK_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(GTK_CFLAGS)
+  AC_SUBST(GTK_LIBS)
+  rm -f conf.gtktest
+])
+
+# Define a conditional.
+
+AC_DEFUN(AM_CONDITIONAL,
+[AC_SUBST($1_TRUE)
+AC_SUBST($1_FALSE)
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi])
+
diff -Naur smpeg/audio/MPEGaudio.cpp smpeg.patched/audio/MPEGaudio.cpp
--- smpeg/audio/MPEGaudio.cpp	Mon Mar  6 17:27:07 2000
+++ smpeg.patched/audio/MPEGaudio.cpp	Thu Mar  9 16:20:28 2000
@@ -20,7 +20,7 @@
 /* A class based on the MPEG stream class, used to parse and play audio */
 
 #include "MPEGaudio.h"
-
+#include "MPEGstream.h"
 
 MPEGaudio:: MPEGaudio(MPEGstream *stream, bool initSDL) : sdl_audio(initSDL)
 {
@@ -33,8 +33,6 @@
 
     /* Analyze the MPEG audio stream */
     if ( loadheader() ) {
-        mpeg->reset_stream();
-
         SDL_AudioSpec wanted;
         WantedSpec(&wanted);
 
@@ -202,7 +200,7 @@
     /* Stop the decode thread */
     StopDecoding();
 #endif
-    mpeg->reset_stream();
+
     clearrawdata();
     decodedframe = 0;
     currentframe = 0;
@@ -211,6 +209,17 @@
     play_time = 0.0;
 }
 void
+MPEGaudio:: Skip(float seconds)
+{
+  printf("Audio: Skipping %f seconds...\n", seconds);  
+  while(seconds > 0)
+  {
+    seconds -= (double) samplesperframe / ((double) frequencies[version][frequency]*(1+inputstereo));
+
+    if(!loadheader()) break;
+  }
+}
+void
 MPEGaudio:: Volume(int vol)
 {
     if ( (vol >= 0) && (vol <= 100) ) {
@@ -247,4 +256,66 @@
       info->bitrate = bitrate[version][layer-1][bitrateindex];
       info->current_frame = currentframe;
     }
+}
+bool
+MPEGaudio:: fillbuffer(int size)
+  {
+      bitindex=0;
+      return(mpeg->copy_data(_buffer, size) > 0);
+  };
+  
+void
+MPEGaudio:: sync(void)
+{
+  bitindex=(bitindex+7)&0xFFFFFFF8;
+}
+  
+bool
+MPEGaudio:: issync(void)
+{
+  return (bitindex&7);
+}
+  
+int 
+MPEGaudio::getbyte(void) 
+{
+  int r=(unsigned char)_buffer[bitindex>>3];
+
+  bitindex+=8;
+  return r;
+}
+  
+int 
+MPEGaudio::getbit(void) 
+{
+  register int r=(_buffer[bitindex>>3]>>(7-(bitindex&7)))&1;
+
+  bitindex++;
+  return r;
+}
+  
+int 
+MPEGaudio::getbits8(void) 
+{
+  register unsigned short a;
+  { int offset=bitindex>>3;
+
+  a=(((unsigned char)_buffer[offset])<<8) | ((unsigned char)_buffer[offset+1]);
+  }
+  a<<=(bitindex&7);
+  bitindex+=8;
+  return (int)((unsigned int)(a>>8));
+}
+  
+int 
+MPEGaudio::getbits9(int bits) 
+{
+  register unsigned short a;
+  { int offset=bitindex>>3;
+
+  a=(((unsigned char)_buffer[offset])<<8) | ((unsigned char)_buffer[offset+1]);
+  }
+  a<<=(bitindex&7);
+  bitindex+=bits;
+  return (int)((unsigned int)(a>>(16-bits)));
 }
diff -Naur smpeg/audio/Makefile.in smpeg.patched/audio/Makefile.in
--- smpeg/audio/Makefile.in	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/audio/Makefile.in	Thu Mar  9 01:21:04 2000
@@ -0,0 +1,369 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AS = @AS@
+BINARY_AGE = @BINARY_AGE@
+CC = @CC@
+CXX = @CXX@
+DLLTOOL = @DLLTOOL@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_CONFIG = @GTK_CONFIG@
+GTK_LIBS = @GTK_LIBS@
+INTERFACE_AGE = @INTERFACE_AGE@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+MAJOR_VERSION = @MAJOR_VERSION@
+MAKEINFO = @MAKEINFO@
+MICRO_VERSION = @MICRO_VERSION@
+MINOR_VERSION = @MINOR_VERSION@
+NM = @NM@
+OBJDUMP = @OBJDUMP@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+VERSION = @VERSION@
+
+noinst_LTLIBRARIES = libaudio.la
+
+libaudio_la_SOURCES =  	MPEGaudio.cpp			bitwindow.cpp			filter.cpp			filter_2.cpp			huffmantable.cpp		mpeglayer1.cpp			mpeglayer2.cpp			mpeglayer3.cpp			mpegtable.cpp			mpegtoraw.cpp
+
+
+EXTRA_DIST =  	AUTHORS				COPYING.LIB			README				README.LIB
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LTLIBRARIES =  $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libaudio_la_LDFLAGS = 
+libaudio_la_LIBADD = 
+libaudio_la_OBJECTS =  MPEGaudio.lo bitwindow.lo filter.lo filter_2.lo \
+huffmantable.lo mpeglayer1.lo mpeglayer2.lo mpeglayer3.lo mpegtable.lo \
+mpegtoraw.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  README AUTHORS COPYING.LIB Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+DEP_FILES =  .deps/MPEGaudio.P .deps/bitwindow.P .deps/filter.P \
+.deps/filter_2.P .deps/huffmantable.P .deps/mpeglayer1.P \
+.deps/mpeglayer2.P .deps/mpeglayer3.P .deps/mpegtable.P \
+.deps/mpegtoraw.P
+SOURCES = $(libaudio_la_SOURCES)
+OBJECTS = $(libaudio_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cpp .lo .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu audio/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+	$(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+	$(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libaudio.la: $(libaudio_la_OBJECTS) $(libaudio_la_DEPENDENCIES)
+	$(CXXLINK)  $(libaudio_la_LDFLAGS) $(libaudio_la_OBJECTS) $(libaudio_la_LIBADD) $(LIBS)
+.cpp.o:
+	$(CXXCOMPILE) -c $<
+.cpp.lo:
+	$(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = audio
+
+distdir: $(DISTFILES)
+	here=`cd $(top_builddir) && pwd`; \
+	top_distdir=`cd $(top_distdir) && pwd`; \
+	distdir=`cd $(distdir) && pwd`; \
+	cd $(top_srcdir) \
+	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu audio/Makefile
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$d/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+	-rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+	@echo '$(COMPILE) -c $<'; \
+	$(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-cp .deps/$(*F).pp .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm .deps/$(*F).pp
+
+%.lo: %.c
+	@echo '$(LTCOMPILE) -c $<'; \
+	$(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-sed -e 's/^\([^:]*\)\.o[ 	]*:/\1.lo \1.o :/' \
+	  < .deps/$(*F).pp > .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm -f .deps/$(*F).pp
+
+%.o: %.cpp
+	@echo '$(CXXCOMPILE) -c $<'; \
+	$(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-cp .deps/$(*F).pp .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm .deps/$(*F).pp
+
+%.lo: %.cpp
+	@echo '$(LTCXXCOMPILE) -c $<'; \
+	$(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-sed -e 's/^\([^:]*\)\.o[ 	]*:/\1.lo \1.o :/' \
+	  < .deps/$(*F).pp > .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+		mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+		mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLTLIBRARIES clean-compile clean-libtool \
+		clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLTLIBRARIES distclean-compile \
+		distclean-libtool distclean-tags distclean-depend \
+		distclean-generic clean-am
+	-rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLTLIBRARIES \
+		maintainer-clean-compile maintainer-clean-libtool \
+		maintainer-clean-tags maintainer-clean-depend \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff -Naur smpeg/audio/mpegtoraw.cpp smpeg.patched/audio/mpegtoraw.cpp
--- smpeg/audio/mpegtoraw.cpp	Mon Mar  6 17:27:07 2000
+++ smpeg.patched/audio/mpegtoraw.cpp	Thu Mar  9 02:20:45 2000
@@ -16,6 +16,7 @@
 #include <assert.h>
 
 #include "MPEGaudio.h"
+#include "MPEGstream.h"
 
 #define MY_PI 3.14159265358979323846
 
@@ -270,14 +271,7 @@
     for( ; frames; frames-- )
     {
         if( loadheader() == false ) {
-            if ( looping ) {
-                mpeg->reset_stream();
-                if ( loadheader() == false ) {
-                    return(false);
-                }
-            } else {
-                return false;
-            }
+	  return false;	  
         }
 
         if     ( layer == 3 ) extractlayer3();
@@ -322,6 +316,8 @@
             SDL_Delay(100);  /* The write buffer is full, wait a bit */
         }
     }
+    audio->decoding = false;
+    audio->decode_thread = NULL;
     return(0);
 }
 #endif /* THREADED_AUDIO */
@@ -371,7 +367,7 @@
             len -= copylen;
             stream += copylen;
         }
-    } while ( copylen && (len > 0) );
+    } while ( copylen && (len > 0) && ((audio->currentframe < audio->decodedframe) || audio->decoding));
 #else
     /* The length is interpreted as being in samples */
     len /= 2;
diff -Naur smpeg/configure smpeg.patched/configure
--- smpeg/configure	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/configure	Thu Mar  9 01:22:41 2000
@@ -0,0 +1,3232 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --enable-shared[=PKGS]  build shared libraries [default=yes]"
+ac_help="$ac_help
+  --enable-static[=PKGS]  build static libraries [default=yes]"
+ac_help="$ac_help
+  --enable-fast-install[=PKGS]  optimize for fast installation [default=yes]"
+ac_help="$ac_help
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]"
+ac_help="$ac_help
+  --disable-libtool-lock  avoid locking (might break parallel builds)"
+ac_help="$ac_help
+  --with-pic              try to use only PIC/non-PIC objects [default=use both]"
+ac_help="$ac_help
+  --with-sdl-prefix=PFX   Prefix where SDL is installed (optional)"
+ac_help="$ac_help
+  --with-sdl-exec-prefix=PFX Exec prefix where SDL is installed (optional)"
+ac_help="$ac_help
+  --disable-sdltest       Do not try to compile and run a test SDL program"
+ac_help="$ac_help
+  --enable-mmx            enable MMX IDCT decoding routines [default=yes]"
+ac_help="$ac_help
+  --enable-gtk-player     build a GTk sample SMPEG player [default=yes]"
+ac_help="$ac_help
+  --with-gtk-prefix=PFX   Prefix where GTK is installed (optional)"
+ac_help="$ac_help
+  --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)"
+ac_help="$ac_help
+  --disable-gtktest       Do not try to compile and run a test GTK program"
+ac_help="$ac_help
+  --enable-opengl-player  build an OpenGL sample SMPEG player [default=yes]"
+ac_help="$ac_help
+  --enable-assertions     Enable consistency checks in decoding [default=no]"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=README
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+#
+# Making releases:
+#   MICRO_VERSION += 1;
+#   INTERFACE_AGE += 1;
+#   BINARY_AGE += 1;
+# if any functions have been added, set INTERFACE_AGE to 0.
+# if backwards compatibility has been broken,
+# set BINARY_AGE and INTERFACE_AGE to 0.
+#
+MAJOR_VERSION=0
+MINOR_VERSION=3
+MICRO_VERSION=5
+INTERFACE_AGE=5
+BINARY_AGE=5
+VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION
+
+
+
+
+
+
+
+
+# libtool versioning
+LT_RELEASE=$MAJOR_VERSION.$MINOR_VERSION
+LT_CURRENT=`expr $MICRO_VERSION - $INTERFACE_AGE`
+LT_REVISION=$INTERFACE_AGE
+LT_AGE=`expr $BINARY_AGE - $INTERFACE_AGE`
+
+
+
+
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:623: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:676: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "$*" != "X $srcdir/configure conftestfile" \
+      && test "$*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      { echo "configure: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+   fi
+
+   test "$2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:733: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+PACKAGE=smpeg
+
+VERSION=$VERSION
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
+echo "configure:779: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+   ACLOCAL=aclocal
+   echo "$ac_t""found" 1>&6
+else
+   ACLOCAL="$missing_dir/missing aclocal"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:792: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+   AUTOCONF=autoconf
+   echo "$ac_t""found" 1>&6
+else
+   AUTOCONF="$missing_dir/missing autoconf"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:805: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+   AUTOMAKE=automake
+   echo "$ac_t""found" 1>&6
+else
+   AUTOMAKE="$missing_dir/missing automake"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:818: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+   AUTOHEADER=autoheader
+   echo "$ac_t""found" 1>&6
+else
+   AUTOHEADER="$missing_dir/missing autoheader"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:831: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+   MAKEINFO=makeinfo
+   echo "$ac_t""found" 1>&6
+else
+   MAKEINFO="$missing_dir/missing makeinfo"
+   echo "$ac_t""missing" 1>&6
+fi
+
+
+
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:847: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:876: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:906: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:957: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:989: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 1000 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:1005: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:1031: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:1036: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1045: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:1064: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1100: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CXX="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+  echo "$ac_t""$CXX" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:1132: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 1143 "configure"
+#include "confdefs.h"
+
+int main(){return(0);}
+EOF
+if { (eval echo configure:1148: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cxx_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cxx_cross=no
+  else
+    ac_cv_prog_cxx_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cxx_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
+if test $ac_cv_prog_cxx_works = no; then
+  { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:1174: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
+cross_compiling=$ac_cv_prog_cxx_cross
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+echo "configure:1179: checking whether we are using GNU C++" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.C <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1188: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gxx=yes
+else
+  ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+
+if test $ac_cv_prog_gxx = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+
+ac_test_CXXFLAGS="${CXXFLAGS+set}"
+ac_save_CXXFLAGS="$CXXFLAGS"
+CXXFLAGS=
+echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:1207: checking whether ${CXX-g++} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+  ac_cv_prog_cxx_g=yes
+else
+  ac_cv_prog_cxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS="$ac_save_CXXFLAGS"
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+
+# Check whether --enable-shared or --disable-shared was given.
+if test "${enable_shared+set}" = set; then
+  enableval="$enable_shared"
+  p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_shared=yes ;;
+no) enable_shared=no ;;
+*)
+  enable_shared=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_shared=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+else
+  enable_shared=yes
+fi
+
+# Check whether --enable-static or --disable-static was given.
+if test "${enable_static+set}" = set; then
+  enableval="$enable_static"
+  p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_static=yes ;;
+no) enable_static=no ;;
+*)
+  enable_static=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_static=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+else
+  enable_static=yes
+fi
+
+# Check whether --enable-fast-install or --disable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then
+  enableval="$enable_fast_install"
+  p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_fast_install=yes ;;
+no) enable_fast_install=no ;;
+*)
+  enable_fast_install=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_fast_install=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+else
+  enable_fast_install=yes
+fi
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:1314: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+  case $nonopt in
+  NONE)
+    if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+    else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+    fi ;;
+  *) host_alias=$nonopt ;;
+  esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+echo "configure:1335: checking build system type" >&5
+
+build_alias=$build
+case "$build_alias" in
+NONE)
+  case $nonopt in
+  NONE) build_alias=$host_alias ;;
+  *) build_alias=$nonopt ;;
+  esac ;;
+esac
+
+build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
+build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$build" 1>&6
+
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+  withval="$with_gnu_ld"
+  test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$ac_cv_prog_gcc" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6
+echo "configure:1364: checking for ld used by GCC" >&5
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case "$ac_prog" in
+    # Accept absolute paths.
+    [\\/]* | [A-Za-z]:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the path of ld
+      ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  echo $ac_n "checking for GNU ld""... $ac_c" 1>&6
+echo "configure:1394: checking for GNU ld" >&5
+else
+  echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6
+echo "configure:1397: checking for non-GNU ld" >&5
+fi
+if eval "test \"`echo '$''{'ac_cv_path_LD'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -z "$LD"; then
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      ac_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+	test "$with_gnu_ld" != no && break
+      else
+	test "$with_gnu_ld" != yes && break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+else
+  ac_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$ac_cv_path_LD"
+if test -n "$LD"; then
+  echo "$ac_t""$LD" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; }
+
+echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6
+echo "configure:1433: checking if the linker ($LD) is GNU ld" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gnu_ld'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+  ac_cv_prog_gnu_ld=yes
+else
+  ac_cv_prog_gnu_ld=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gnu_ld" 1>&6
+
+
+echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6
+echo "configure:1449: checking for BSD-compatible nm" >&5
+if eval "test \"`echo '$''{'ac_cv_path_NM'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  ac_cv_path_NM="$NM"
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+  for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then
+      # Check to see if the nm accepts a BSD-compat flag.
+      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+      #   nm: unknown option "B" ignored
+      if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+	ac_cv_path_NM="$ac_dir/nm -B"
+	break
+      elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+	ac_cv_path_NM="$ac_dir/nm -p"
+	break
+      else
+	ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but
+	continue # so that we can try to find one that supports BSD flags
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
+fi
+fi
+
+NM="$ac_cv_path_NM"
+echo "$ac_t""$NM" 1>&6
+
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1486: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test $host != $build; then
+  ac_tool_prefix=${host_alias}-
+else
+  ac_tool_prefix=
+fi
+
+
+# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1516: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+if test -z "$ac_cv_prog_RANLIB"; then
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1548: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+  RANLIB=":"
+fi
+fi
+
+
+# Check for any special flags to pass to ltconfig.
+libtool_flags="--cache-file=$cache_file"
+test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared"
+test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static"
+test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install"
+test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc"
+test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld"
+
+
+# Check whether --enable-libtool-lock or --disable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then
+  enableval="$enable_libtool_lock"
+  :
+fi
+
+test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock"
+test x"$silent" = xyes && libtool_flags="$libtool_flags --silent"
+
+# Check whether --with-pic or --without-pic was given.
+if test "${with_pic+set}" = set; then
+  withval="$with_pic"
+  pic_mode="$withval"
+else
+  pic_mode=default
+fi
+
+test x"$pic_mode" = xyes && libtool_flags="$libtool_flags --prefer-pic"
+test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic"
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case "$host" in
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '#line 1615 "configure"' > conftest.$ac_ext
+  if { (eval echo configure:1616: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+    case "`/usr/bin/file conftest.o`" in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  echo $ac_n "checking whether the C compiler needs -belf""... $ac_c" 1>&6
+echo "configure:1637: checking whether the C compiler needs -belf" >&5
+if eval "test \"`echo '$''{'lt_cv_cc_needs_belf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1642 "configure"
+#include "confdefs.h"
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:1649: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  lt_cv_cc_needs_belf=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  lt_cv_cc_needs_belf=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$lt_cv_cc_needs_belf" 1>&6
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+
+
+esac
+
+
+# Save cache, so that ltconfig can load it
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+
+# Actually configure libtool.  ac_aux_dir is where install-sh is found.
+CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \
+LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \
+LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \
+DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \
+${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \
+$libtool_flags --no-verify --build="$build" $ac_aux_dir/ltmain.sh $host \
+|| { echo "configure: error: libtool configure failed" 1>&2; exit 1; }
+
+# Reload cache, that may have been modified by ltconfig
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+# Redirect the config.log output again, so that the ltconfig log is not
+# clobbered by the next message.
+exec 5>>./config.log
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1762: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+echo $ac_n "checking target system type""... $ac_c" 1>&6
+echo "configure:1816: checking target system type" >&5
+
+target_alias=$target
+case "$target_alias" in
+NONE)
+  case $nonopt in
+  NONE) target_alias=$host_alias ;;
+  *) target_alias=$nonopt ;;
+  esac ;;
+esac
+
+target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
+target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$target" 1>&6
+
+case "$target" in
+    alpha*-*-linux*)
+        CFLAGS="$CFLAGS -mcpu=ev4 -Wa,-mall"
+        ;;
+esac
+
+case "$target" in
+    *-*-mingw32*)
+        MATHLIB=""
+        ;;
+    *-*-beos*)
+        MATHLIB=""
+        ;;
+    *)
+        MATHLIB="-lm"
+        ;;
+esac
+LIBS="$LIBS $MATHLIB"
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1853: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1868 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1874: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1885 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1891: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1902 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1908: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+for ac_hdr in unistd.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1936: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1941 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1946: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in getpagesize
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1975: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1980 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2003: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking for working mmap""... $ac_c" 1>&6
+echo "configure:2028: checking for working mmap" >&5
+if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_func_mmap_fixed_mapped=no
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2036 "configure"
+#include "confdefs.h"
+
+/* Thanks to Mike Haertel and Jim Avera for this test.
+   Here is a matrix of mmap possibilities:
+	mmap private not fixed
+	mmap private fixed at somewhere currently unmapped
+	mmap private fixed at somewhere already mapped
+	mmap shared not fixed
+	mmap shared fixed at somewhere currently unmapped
+	mmap shared fixed at somewhere already mapped
+   For private mappings, we should verify that changes cannot be read()
+   back from the file, nor mmap's back from the file at a different
+   address.  (There have been systems where private was not correctly
+   implemented like the infamous i386 svr4.0, and systems where the
+   VM page cache was not coherent with the filesystem buffer cache
+   like early versions of FreeBSD and possibly contemporary NetBSD.)
+   For shared mappings, we should conversely verify that changes get
+   propogated back to all the places they're supposed to be.
+
+   Grep wants private fixed already mapped.
+   The main things grep needs to know about mmap are:
+   * does it exist and is it safe to write into the mmap'd area
+   * how to use it (BSD variants)  */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+/* This mess was copied from the GNU getpagesize.h.  */
+#ifndef HAVE_GETPAGESIZE
+
+/* Assume that all systems that can run configure have sys/param.h.  */
+# ifndef HAVE_SYS_PARAM_H
+#  define HAVE_SYS_PARAM_H 1
+# endif
+
+# ifdef _SC_PAGESIZE
+#  define getpagesize() sysconf(_SC_PAGESIZE)
+# else /* no _SC_PAGESIZE */
+#  ifdef HAVE_SYS_PARAM_H
+#   include <sys/param.h>
+#   ifdef EXEC_PAGESIZE
+#    define getpagesize() EXEC_PAGESIZE
+#   else /* no EXEC_PAGESIZE */
+#    ifdef NBPG
+#     define getpagesize() NBPG * CLSIZE
+#     ifndef CLSIZE
+#      define CLSIZE 1
+#     endif /* no CLSIZE */
+#    else /* no NBPG */
+#     ifdef NBPC
+#      define getpagesize() NBPC
+#     else /* no NBPC */
+#      ifdef PAGESIZE
+#       define getpagesize() PAGESIZE
+#      endif /* PAGESIZE */
+#     endif /* no NBPC */
+#    endif /* no NBPG */
+#   endif /* no EXEC_PAGESIZE */
+#  else /* no HAVE_SYS_PARAM_H */
+#   define getpagesize() 8192	/* punt totally */
+#  endif /* no HAVE_SYS_PARAM_H */
+# endif /* no _SC_PAGESIZE */
+
+#endif /* no HAVE_GETPAGESIZE */
+
+#ifdef __cplusplus
+extern "C" { void *malloc(unsigned); }
+#else
+char *malloc();
+#endif
+
+int
+main()
+{
+	char *data, *data2, *data3;
+	int i, pagesize;
+	int fd;
+
+	pagesize = getpagesize();
+
+	/*
+	 * First, make a file with some known garbage in it.
+	 */
+	data = (char*)malloc(pagesize);
+	if (!data)
+		exit(1);
+	for (i = 0; i < pagesize; ++i)
+		*(data + i) = rand();
+	umask(0);
+	fd = creat("conftestmmap", 0600);
+	if (fd < 0)
+		exit(1);
+	if (write(fd, data, pagesize) != pagesize)
+		exit(1);
+	close(fd);
+
+	/*
+	 * Next, try to mmap the file at a fixed address which
+	 * already has something else allocated at it.  If we can,
+	 * also make sure that we see the same garbage.
+	 */
+	fd = open("conftestmmap", O_RDWR);
+	if (fd < 0)
+		exit(1);
+	data2 = (char*)malloc(2 * pagesize);
+	if (!data2)
+		exit(1);
+	data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1);
+	if (data2 != mmap(data2, pagesize, PROT_READ | PROT_WRITE,
+	    MAP_PRIVATE | MAP_FIXED, fd, 0L))
+		exit(1);
+	for (i = 0; i < pagesize; ++i)
+		if (*(data + i) != *(data2 + i))
+			exit(1);
+
+	/*
+	 * Finally, make sure that changes to the mapped area
+	 * do not percolate back to the file as seen by read().
+	 * (This is a bug on some variants of i386 svr4.0.)
+	 */
+	for (i = 0; i < pagesize; ++i)
+		*(data2 + i) = *(data2 + i) + 1;
+	data3 = (char*)malloc(pagesize);
+	if (!data3)
+		exit(1);
+	if (read(fd, data3, pagesize) != pagesize)
+		exit(1);
+	for (i = 0; i < pagesize; ++i)
+		if (*(data + i) != *(data3 + i))
+			exit(1);
+	close(fd);
+	unlink("conftestmmap");
+	exit(0);
+}
+
+EOF
+if { (eval echo configure:2179: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_mmap_fixed_mapped=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_mmap_fixed_mapped=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_mmap_fixed_mapped" 1>&6
+if test $ac_cv_func_mmap_fixed_mapped = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_MMAP 1
+EOF
+
+fi
+
+if test x$ac_cv_func_mmap_fixed_mapped != xyes; then
+    { echo "configure: error: SMPEG requires mmap() for file loading" 1>&2; exit 1; }
+fi
+
+SDL_VERSION=1.0.8
+# Check whether --with-sdl-prefix or --without-sdl-prefix was given.
+if test "${with_sdl_prefix+set}" = set; then
+  withval="$with_sdl_prefix"
+  sdl_prefix="$withval"
+else
+  sdl_prefix=""
+fi
+
+# Check whether --with-sdl-exec-prefix or --without-sdl-exec-prefix was given.
+if test "${with_sdl_exec_prefix+set}" = set; then
+  withval="$with_sdl_exec_prefix"
+  sdl_exec_prefix="$withval"
+else
+  sdl_exec_prefix=""
+fi
+
+# Check whether --enable-sdltest or --disable-sdltest was given.
+if test "${enable_sdltest+set}" = set; then
+  enableval="$enable_sdltest"
+  :
+else
+  enable_sdltest=yes
+fi
+
+
+  if test x$sdl_exec_prefix != x ; then
+     sdl_args="$sdl_args --exec-prefix=$sdl_exec_prefix"
+     if test x${SDL_CONFIG+set} != xset ; then
+        SDL_CONFIG=$sdl_exec_prefix/bin/sdl-config
+     fi
+  fi
+  if test x$sdl_prefix != x ; then
+     sdl_args="$sdl_args --prefix=$sdl_prefix"
+     if test x${SDL_CONFIG+set} != xset ; then
+        SDL_CONFIG=$sdl_prefix/bin/sdl-config
+     fi
+  fi
+
+  # Extract the first word of "sdl-config", so it can be a program name with args.
+set dummy sdl-config; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:2247: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_SDL_CONFIG'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$SDL_CONFIG" in
+  /*)
+  ac_cv_path_SDL_CONFIG="$SDL_CONFIG" # Let the user override the test with a path.
+  ;;
+  ?:/*)			 
+  ac_cv_path_SDL_CONFIG="$SDL_CONFIG" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_SDL_CONFIG="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_SDL_CONFIG" && ac_cv_path_SDL_CONFIG="no"
+  ;;
+esac
+fi
+SDL_CONFIG="$ac_cv_path_SDL_CONFIG"
+if test -n "$SDL_CONFIG"; then
+  echo "$ac_t""$SDL_CONFIG" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  min_sdl_version=$SDL_VERSION
+  echo $ac_n "checking for SDL - version >= $min_sdl_version""... $ac_c" 1>&6
+echo "configure:2282: checking for SDL - version >= $min_sdl_version" >&5
+  no_sdl=""
+  if test "$SDL_CONFIG" = "no" ; then
+    no_sdl=yes
+  else
+    SDL_CFLAGS=`$SDL_CONFIG $sdlconf_args --cflags`
+    SDL_LIBS=`$SDL_CONFIG $sdlconf_args --libs`
+
+    sdl_major_version=`$SDL_CONFIG $sdl_args --version | \
+           sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'`
+    sdl_minor_version=`$SDL_CONFIG $sdl_args --version | \
+           sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'`
+    sdl_micro_version=`$SDL_CONFIG $sdl_config_args --version | \
+           sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'`
+    if test "x$enable_sdltest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $SDL_CFLAGS"
+      LIBS="$LIBS $SDL_LIBS"
+      rm -f conf.sdltest
+      if test "$cross_compiling" = yes; then
+  echo $ac_n "cross compiling; assumed OK... $ac_c"
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2306 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SDL.h"
+
+char*
+my_strdup (char *str)
+{
+  char *new_str;
+  
+  if (str)
+    {
+      new_str = malloc ((strlen (str) + 1) * sizeof(char));
+      strcpy (new_str, str);
+    }
+  else
+    new_str = NULL;
+  
+  return new_str;
+}
+
+int main ()
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  system ("touch conf.sdltest");
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = my_strdup("$min_sdl_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_sdl_version");
+     exit(1);
+   }
+
+   if (($sdl_major_version > major) ||
+      (($sdl_major_version == major) && ($sdl_minor_version > minor)) ||
+      (($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro)))
+    {
+      return 0;
+    }
+  else
+    {
+      printf("\n*** 'sdl-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version);
+      printf("*** of SDL required is %d.%d.%d. If sdl-config is correct, then it is\n", major, minor, micro);
+      printf("*** best to upgrade to the required version.\n");
+      printf("*** If sdl-config was wrong, set the environment variable SDL_CONFIG\n");
+      printf("*** to point to the correct copy of sdl-config, and remove the file\n");
+      printf("*** config.cache before re-running configure\n");
+      return 1;
+    }
+}
+
+
+EOF
+if { (eval echo configure:2364: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  no_sdl=yes
+fi
+rm -fr conftest*
+fi
+
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_sdl" = x ; then
+     echo "$ac_t""yes" 1>&6
+     :     
+  else
+     echo "$ac_t""no" 1>&6
+     if test "$SDL_CONFIG" = "no" ; then
+       echo "*** The sdl-config script installed by SDL could not be found"
+       echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the SDL_CONFIG environment variable to the"
+       echo "*** full path to sdl-config."
+     else
+       if test -f conf.sdltest ; then
+        :
+       else
+          echo "*** Could not run SDL test program, checking why..."
+          CFLAGS="$CFLAGS $SDL_CFLAGS"
+          LIBS="$LIBS $SDL_LIBS"
+          cat > conftest.$ac_ext <<EOF
+#line 2398 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include "SDL.h"
+
+int main() {
+ return 0; 
+; return 0; }
+EOF
+if { (eval echo configure:2408: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+   echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding SDL or finding the wrong"
+          echo "*** version of SDL. If it is not finding SDL, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means SDL was incorrectly installed"
+          echo "*** or that you have moved SDL since it was installed. In the latter case, you"
+          echo "*** may want to edit the sdl-config script: $SDL_CONFIG" 
+fi
+rm -f conftest*
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     SDL_CFLAGS=""
+     SDL_LIBS=""
+     { echo "configure: error: *** SDL version $SDL_VERSION not found!" 1>&2; exit 1; }
+
+  fi
+  
+  
+  rm -f conf.sdltest
+
+CFLAGS="$CFLAGS $SDL_CFLAGS"
+LIBS="$LIBS $SDL_LIBS"
+
+CFLAGS="$CFLAGS -I.. -DNOCONTROLS"
+CXXFLAGS="$CFLAGS"
+
+# Check whether --enable-mmx or --disable-mmx was given.
+if test "${enable_mmx+set}" = set; then
+  enableval="$enable_mmx"
+  :
+else
+  enable_mmx=yes
+fi
+
+if test x$enable_mmx = xyes; then
+    case "$target" in
+        i?86*)
+            CFLAGS="$CFLAGS -DUSE_MMX"
+            ;;
+    esac
+fi
+
+# Check whether --enable-gtk_player or --disable-gtk_player was given.
+if test "${enable_gtk_player+set}" = set; then
+  enableval="$enable_gtk_player"
+  :
+else
+  enable_gtk_player=yes
+fi
+
+have_gtk=no
+if test x$enable_gtk_player = xyes; then
+    # Check whether --with-gtk-prefix or --without-gtk-prefix was given.
+if test "${with_gtk_prefix+set}" = set; then
+  withval="$with_gtk_prefix"
+  gtk_config_prefix="$withval"
+else
+  gtk_config_prefix=""
+fi
+
+# Check whether --with-gtk-exec-prefix or --without-gtk-exec-prefix was given.
+if test "${with_gtk_exec_prefix+set}" = set; then
+  withval="$with_gtk_exec_prefix"
+  gtk_config_exec_prefix="$withval"
+else
+  gtk_config_exec_prefix=""
+fi
+
+# Check whether --enable-gtktest or --disable-gtktest was given.
+if test "${enable_gtktest+set}" = set; then
+  enableval="$enable_gtktest"
+  :
+else
+  enable_gtktest=yes
+fi
+
+
+  for module in . 
+  do
+      case "$module" in
+         gthread) 
+             gtk_config_args="$gtk_config_args gthread"
+         ;;
+      esac
+  done
+
+  if test x$gtk_config_exec_prefix != x ; then
+     gtk_config_args="$gtk_config_args --exec-prefix=$gtk_config_exec_prefix"
+     if test x${GTK_CONFIG+set} != xset ; then
+        GTK_CONFIG=$gtk_config_exec_prefix/bin/gtk-config
+     fi
+  fi
+  if test x$gtk_config_prefix != x ; then
+     gtk_config_args="$gtk_config_args --prefix=$gtk_config_prefix"
+     if test x${GTK_CONFIG+set} != xset ; then
+        GTK_CONFIG=$gtk_config_prefix/bin/gtk-config
+     fi
+  fi
+
+  # Extract the first word of "gtk-config", so it can be a program name with args.
+set dummy gtk-config; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:2524: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_GTK_CONFIG'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$GTK_CONFIG" in
+  /*)
+  ac_cv_path_GTK_CONFIG="$GTK_CONFIG" # Let the user override the test with a path.
+  ;;
+  ?:/*)			 
+  ac_cv_path_GTK_CONFIG="$GTK_CONFIG" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_GTK_CONFIG="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_GTK_CONFIG" && ac_cv_path_GTK_CONFIG="no"
+  ;;
+esac
+fi
+GTK_CONFIG="$ac_cv_path_GTK_CONFIG"
+if test -n "$GTK_CONFIG"; then
+  echo "$ac_t""$GTK_CONFIG" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  min_gtk_version=1.2.1
+  echo $ac_n "checking for GTK - version >= $min_gtk_version""... $ac_c" 1>&6
+echo "configure:2559: checking for GTK - version >= $min_gtk_version" >&5
+  no_gtk=""
+  if test "$GTK_CONFIG" = "no" ; then
+    no_gtk=yes
+  else
+    GTK_CFLAGS=`$GTK_CONFIG $gtk_config_args --cflags`
+    GTK_LIBS=`$GTK_CONFIG $gtk_config_args --libs`
+    gtk_config_major_version=`$GTK_CONFIG $gtk_config_args --version | \
+           sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'`
+    gtk_config_minor_version=`$GTK_CONFIG $gtk_config_args --version | \
+           sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'`
+    gtk_config_micro_version=`$GTK_CONFIG $gtk_config_args --version | \
+           sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'`
+    if test "x$enable_gtktest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $GTK_CFLAGS"
+      LIBS="$GTK_LIBS $LIBS"
+      rm -f conf.gtktest
+      if test "$cross_compiling" = yes; then
+  echo $ac_n "cross compiling; assumed OK... $ac_c"
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2582 "configure"
+#include "confdefs.h"
+
+#include <gtk/gtk.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int 
+main ()
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  system ("touch conf.gtktest");
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = g_strdup("$min_gtk_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_gtk_version");
+     exit(1);
+   }
+
+  if ((gtk_major_version != $gtk_config_major_version) ||
+      (gtk_minor_version != $gtk_config_minor_version) ||
+      (gtk_micro_version != $gtk_config_micro_version))
+    {
+      printf("\n*** 'gtk-config --version' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", 
+             $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version,
+             gtk_major_version, gtk_minor_version, gtk_micro_version);
+      printf ("*** was found! If gtk-config was correct, then it is best\n");
+      printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n");
+      printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+      printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+      printf("*** required on your system.\n");
+      printf("*** If gtk-config was wrong, set the environment variable GTK_CONFIG\n");
+      printf("*** to point to the correct copy of gtk-config, and remove the file config.cache\n");
+      printf("*** before re-running configure\n");
+    } 
+#if defined (GTK_MAJOR_VERSION) && defined (GTK_MINOR_VERSION) && defined (GTK_MICRO_VERSION)
+  else if ((gtk_major_version != GTK_MAJOR_VERSION) ||
+	   (gtk_minor_version != GTK_MINOR_VERSION) ||
+           (gtk_micro_version != GTK_MICRO_VERSION))
+    {
+      printf("*** GTK+ header files (version %d.%d.%d) do not match\n",
+	     GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
+      printf("*** library (version %d.%d.%d)\n",
+	     gtk_major_version, gtk_minor_version, gtk_micro_version);
+    }
+#endif /* defined (GTK_MAJOR_VERSION) ... */
+  else
+    {
+      if ((gtk_major_version > major) ||
+        ((gtk_major_version == major) && (gtk_minor_version > minor)) ||
+        ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro)))
+      {
+        return 0;
+       }
+     else
+      {
+        printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n",
+               gtk_major_version, gtk_minor_version, gtk_micro_version);
+        printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n",
+	       major, minor, micro);
+        printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n");
+        printf("***\n");
+        printf("*** If you have already installed a sufficiently new version, this error\n");
+        printf("*** probably means that the wrong copy of the gtk-config shell script is\n");
+        printf("*** being found. The easiest way to fix this is to remove the old version\n");
+        printf("*** of GTK+, but you can also set the GTK_CONFIG environment to point to the\n");
+        printf("*** correct copy of gtk-config. (In this case, you will have to\n");
+        printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+        printf("*** so that the correct libraries are found at run-time))\n");
+      }
+    }
+  return 1;
+}
+
+EOF
+if { (eval echo configure:2660: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  no_gtk=yes
+fi
+rm -fr conftest*
+fi
+
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_gtk" = x ; then
+     echo "$ac_t""yes" 1>&6
+     have_gtk=yes     
+  else
+     echo "$ac_t""no" 1>&6
+     if test "$GTK_CONFIG" = "no" ; then
+       echo "*** The gtk-config script installed by GTK could not be found"
+       echo "*** If GTK was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the GTK_CONFIG environment variable to the"
+       echo "*** full path to gtk-config."
+     else
+       if test -f conf.gtktest ; then
+        :
+       else
+          echo "*** Could not run GTK test program, checking why..."
+          CFLAGS="$CFLAGS $GTK_CFLAGS"
+          LIBS="$LIBS $GTK_LIBS"
+          cat > conftest.$ac_ext <<EOF
+#line 2694 "configure"
+#include "confdefs.h"
+
+#include <gtk/gtk.h>
+#include <stdio.h>
+
+int main() {
+ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); 
+; return 0; }
+EOF
+if { (eval echo configure:2704: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+   echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding GTK or finding the wrong"
+          echo "*** version of GTK. If it is not finding GTK, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+          echo "***"
+          echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that"
+          echo "*** came with the system with the command"
+          echo "***"
+          echo "***    rpm --erase --nodeps gtk gtk-devel" 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means GTK was incorrectly installed"
+          echo "*** or that you have moved GTK since it was installed. In the latter case, you"
+          echo "*** may want to edit the gtk-config script: $GTK_CONFIG" 
+fi
+rm -f conftest*
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     GTK_CFLAGS=""
+     GTK_LIBS=""
+     :
+  fi
+  
+  
+  rm -f conf.gtktest
+
+    if test x$have_gtk = xyes; then
+        CFLAGS="$CFLAGS $GTK_CFLAGS"
+    fi
+    
+fi
+
+
+if test x$have_gtk = xyes; then
+  HAVE_GTK_TRUE=
+  HAVE_GTK_FALSE='#'
+else
+  HAVE_GTK_TRUE='#'
+  HAVE_GTK_FALSE=
+fi
+
+# Check whether --enable-opengl_player or --disable-opengl_player was given.
+if test "${enable_opengl_player+set}" = set; then
+  enableval="$enable_opengl_player"
+  :
+else
+  enable_opengl_player=yes
+fi
+
+have_glu=no
+if test x$enable_opengl_player = xyes; then
+        #AC_CHECK_HEADER(GL/gl.h, have_gl=yes)
+    echo $ac_n "checking for glXCreateContext in -lGL""... $ac_c" 1>&6
+echo "configure:2769: checking for glXCreateContext in -lGL" >&5
+ac_lib_var=`echo GL'_'glXCreateContext | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lGL  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2777 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char glXCreateContext();
+
+int main() {
+glXCreateContext()
+; return 0; }
+EOF
+if { (eval echo configure:2788: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  have_gl=yes
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    #AC_CHECK_HEADER(GL/glu.h, have_glu=yes)
+    echo $ac_n "checking for gluOrtho2D in -lGLU""... $ac_c" 1>&6
+echo "configure:2810: checking for gluOrtho2D in -lGLU" >&5
+ac_lib_var=`echo GLU'_'gluOrtho2D | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lGLU  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2818 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gluOrtho2D();
+
+int main() {
+gluOrtho2D()
+; return 0; }
+EOF
+if { (eval echo configure:2829: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  have_glu=yes
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+if test x$have_gl = xyes -a x$have_glu = xyes; then
+  HAVE_MESA_TRUE=
+  HAVE_MESA_FALSE='#'
+else
+  HAVE_MESA_TRUE='#'
+  HAVE_MESA_FALSE=
+fi
+
+# Check whether --enable-assertions or --disable-assertions was given.
+if test "${enable_assertions+set}" = set; then
+  enableval="$enable_assertions"
+  :
+else
+  enable_assertions=no
+fi
+
+if test x$enable_assertions != xyes; then
+    CFLAGS="$CFLAGS -DNDEBUG"
+fi
+
+CFLAGS="$CFLAGS -I\$(top_srcdir) -I\$(top_srcdir)/audio -I\$(top_srcdir)/video"
+
+CXXFLAGS="$CFLAGS"
+if test x$GCC = xyes; then
+    # Check to see if options -fno-rtti -fno-exceptions are supported
+    echo $ac_n "checking if $CXX supports -fno-rtti -fno-exceptions""... $ac_c" 1>&6
+echo "configure:2878: checking if $CXX supports -fno-rtti -fno-exceptions" >&5
+    use_fnoexceptions=no
+    save_CFLAGS="$CFLAGS"
+    save_CC="$CC"
+    CFLAGS="-fno-rtti -fno-exceptions"
+    CC="$CXX"
+    cat > conftest.$ac_ext <<EOF
+#line 2885 "configure"
+#include "confdefs.h"
+
+    
+int main() {
+
+    
+; return 0; }
+EOF
+if { (eval echo configure:2894: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  
+    use_fnoexceptions=yes
+    
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+    echo "$ac_t""$use_fnoexceptions" 1>&6
+    if test x$use_fnoexceptions = xyes; then
+        CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti"
+    fi
+    CC="$save_CC"
+    CFLAGS="$save_CFLAGS"
+fi
+
+# Finally create all the generated files
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[ 	`~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "
+Makefile
+audio/Makefile
+video/Makefile
+smpeg-config
+smpeg.spec
+" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@MAJOR_VERSION@%$MAJOR_VERSION%g
+s%@MINOR_VERSION@%$MINOR_VERSION%g
+s%@MICRO_VERSION@%$MICRO_VERSION%g
+s%@INTERFACE_AGE@%$INTERFACE_AGE%g
+s%@BINARY_AGE@%$BINARY_AGE%g
+s%@VERSION@%$VERSION%g
+s%@LT_RELEASE@%$LT_RELEASE%g
+s%@LT_CURRENT@%$LT_CURRENT%g
+s%@LT_REVISION@%$LT_REVISION%g
+s%@LT_AGE@%$LT_AGE%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PACKAGE@%$PACKAGE%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@CXX@%$CXX%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@LD@%$LD%g
+s%@NM@%$NM%g
+s%@LN_S@%$LN_S%g
+s%@RANLIB@%$RANLIB%g
+s%@LIBTOOL@%$LIBTOOL%g
+s%@target@%$target%g
+s%@target_alias@%$target_alias%g
+s%@target_cpu@%$target_cpu%g
+s%@target_vendor@%$target_vendor%g
+s%@target_os@%$target_os%g
+s%@CPP@%$CPP%g
+s%@SDL_CONFIG@%$SDL_CONFIG%g
+s%@SDL_CFLAGS@%$SDL_CFLAGS%g
+s%@SDL_LIBS@%$SDL_LIBS%g
+s%@GTK_CONFIG@%$GTK_CONFIG%g
+s%@GTK_CFLAGS@%$GTK_CFLAGS%g
+s%@GTK_LIBS@%$GTK_LIBS%g
+s%@HAVE_GTK_TRUE@%$HAVE_GTK_TRUE%g
+s%@HAVE_GTK_FALSE@%$HAVE_GTK_FALSE%g
+s%@HAVE_MESA_TRUE@%$HAVE_MESA_TRUE%g
+s%@HAVE_MESA_FALSE@%$HAVE_MESA_FALSE%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile
+audio/Makefile
+video/Makefile
+smpeg-config
+smpeg.spec
+"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
Only in smpeg.patched/: pipe
diff -Naur smpeg/plaympeg.c smpeg.patched/plaympeg.c
--- smpeg/plaympeg.c	Wed Mar  8 20:06:53 2000
+++ smpeg.patched/plaympeg.c	Thu Mar  9 21:35:48 2000
@@ -17,9 +17,24 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#define NET_SUPPORT
+
 #include <stdlib.h>
 #include <string.h>
-
+#ifdef NET_SUPPORT
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#endif
 #include "smpeg.h"
 
 
@@ -35,10 +50,19 @@
 "	--loop or -l	     Play MPEG over and over\n"
 "	--volume N or -v N   Set audio volume to N (0-100)\n"
 "	--scale S or -s S    Play MPEG at size S (1-)\n"
+"       --skip N or -S N     Skip N seconds\n"
 "	--help or -h\n"
 "	--version or -V\n", argv0);
 }
 
+#ifdef NET_SUPPORT
+int is_address_multicast(unsigned long address)
+{
+  if((address & 255) >= 224 && (address & 255) <= 239) return(1);
+  return(0);
+}
+#endif
+
 void update(SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
 {
     if ( screen->flags & SDL_DOUBLEBUF ) {
@@ -57,6 +81,7 @@
     int loop_play;
     int i, done, pause;
     int volume;
+    float skip;
     SMPEG *mpeg;
     SMPEG_Info info;
     char *basefile;
@@ -70,6 +95,7 @@
     scalesize = 1;
     loop_play = 0;
     volume = 100;
+    skip = 0;
     for ( i=1; argv[i] && (argv[i][0] == '-'); ++i ) {
         if ( (strcmp(argv[i], "--noaudio") == 0) ||
              (strcmp(argv[i], "--nosound") == 0) ) {
@@ -87,6 +113,12 @@
         if ((strcmp(argv[i], "--loop") == 0) || (strcmp(argv[i], "-l") == 0)) {
             loop_play = 1;
         } else
+        if ((strcmp(argv[i], "--skip") == 0)||(strcmp(argv[i], "-S") == 0)) {
+            ++i;
+            if ( argv[i] ) {
+                skip = atof(argv[i]);
+            }
+        } else
         if ((strcmp(argv[i], "--volume") == 0)||(strcmp(argv[i], "-v") == 0)) {
             ++i;
 	    if (i >= argc)
@@ -164,6 +196,80 @@
 	}
 	
         /* Create the MPEG stream */
+#ifdef NET_SUPPORT
+        /* Check if source is a file or an ip address */
+        if(strchr(argv[i], ':') != NULL)
+	{
+	  char * address;
+	  int port;
+	  int enable = 1L;
+	  struct sockaddr_in stAddr;
+	  struct sockaddr_in stLclAddr;
+	  struct ip_mreq stMreq;
+	  int sock;
+
+	  /* Source is an ip adress */
+	  port = atoi(strchr(argv[i], ':') + sizeof(char));
+	  *strchr(argv[i], ':') = '\0';
+	  address = argv[i];
+	  
+	  printf("Connecting to %s port %d...\n", address, port);
+	  
+          stAddr.sin_family = AF_INET; 
+	  stAddr.sin_addr.s_addr = inet_addr(address); 
+	  stAddr.sin_port = htons(port);
+
+	  /* Open socket */
+	  sock = socket(AF_INET, SOCK_DGRAM, 0);
+	  if (sock <= 0)
+	    fprintf(stderr, "socket() failed\n");
+	    
+	  /* Allow multiple instance of the client to share */
+	  /* the same address and port */
+ 	  if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+		        (char *) &enable, sizeof(unsigned long int)) < 0)
+	    fprintf(stderr, "setsockopt() SO_REUSEADDR failed, %s\n",
+		    strerror(errno));
+
+	  /* Do protocol specific initialization */
+	  /* If the address is multicast, register to the multicast group */
+	  if(is_address_multicast(stAddr.sin_addr.s_addr))
+	  {
+	    /* Bind the socket to port */
+	    stLclAddr.sin_family      = AF_INET;
+	    stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+	    stLclAddr.sin_port        = stAddr.sin_port;
+      
+	    if(bind(sock, (struct sockaddr*) & stLclAddr,
+		    sizeof(stLclAddr)) < 0)
+	    fprintf(stderr, "bind() failed, %s\n", strerror(errno));
+      
+	    /* Register to a multicast address */
+	    stMreq.imr_multiaddr.s_addr = stAddr.sin_addr.s_addr;
+	    stMreq.imr_interface.s_addr = INADDR_ANY;
+      
+	    if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+		 	  (char *) & stMreq, sizeof(stMreq)) < 0)
+	      fprintf(stderr, "setsockopt() IP_ADD_MEMBERSHIP failed\n");
+	  }
+	  else
+	  {
+	    /* Bind the socket to port */
+	    if(bind(sock, (struct sockaddr *) & stAddr, sizeof(stAddr)) < 0)
+	      fprintf(stderr, "bind() failed, %s\n", strerror(errno));
+	  }
+
+	  /* Connected, now the socket is just like a regular file */
+	  mpeg = SMPEG_new_descr(sock, &info, use_audio);
+
+	  if ( SMPEG_error(mpeg) ) {
+            fprintf(stderr, "%s: %s\n", argv[i], SMPEG_error(mpeg));
+            SMPEG_delete(mpeg);
+            continue;
+	  }
+	}
+	else
+#endif
         mpeg = SMPEG_new(argv[i], &info, use_audio);
         if ( SMPEG_error(mpeg) ) {
             fprintf(stderr, "%s: %s\n", argv[i], SMPEG_error(mpeg));
@@ -238,6 +344,9 @@
         if ( loop_play ) {
             SMPEG_loop(mpeg, 1);
         }
+	
+	/* Skip to starting position */
+	if(skip) SMPEG_skip(mpeg, skip);
 
         /* Play it, and wait for playback to complete */
         SMPEG_play(mpeg);
@@ -246,7 +355,7 @@
         while ( ! done && ( pause || (SMPEG_status(mpeg) == SMPEG_PLAYING) ) ) {
             SDL_Event event;
 
-            while ( SDL_PollEvent(&event) ) {
+            while ( use_video && SDL_PollEvent(&event) ) {
                 switch (event.type) {
                     case SDL_KEYDOWN:
                         if ( (event.key.keysym.sym == SDLK_ESCAPE) || (event.key.keysym.sym == SDLK_q) ) {
diff -Naur smpeg/smpeg.cpp smpeg.patched/smpeg.cpp
--- smpeg/smpeg.cpp	Mon Mar  6 17:27:07 2000
+++ smpeg.patched/smpeg.cpp	Thu Mar  9 16:04:41 2000
@@ -26,7 +26,7 @@
 
 /* This is the actual SMPEG object */
 struct _SMPEG {
-    MPEGfile *obj;
+    MPEG *obj;
 };
 
 /* Create a new SMPEG object from an MPEG file.
@@ -44,7 +44,23 @@
 
     /* Create a new SMPEG object! */
     mpeg = new SMPEG;
-    mpeg->obj = new MPEGfile(file, sdl_audio);
+    mpeg->obj = new MPEG(file, sdl_audio);
+
+    /* Find out the details of the stream, if requested */
+    SMPEG_getinfo(mpeg, info);
+
+    /* We're done! */
+    return(mpeg);
+}
+
+/* The same as above except for file descriptors */
+SMPEG* SMPEG_new_descr(int file, SMPEG_Info* info, int sdl_audio)
+{
+    SMPEG *mpeg;
+
+    /* Create a new SMPEG object! */
+    mpeg = new SMPEG;
+    mpeg->obj = new MPEG(file, sdl_audio);
 
     /* Find out the details of the stream, if requested */
     SMPEG_getinfo(mpeg, info);
@@ -61,8 +77,8 @@
         MPEG_VideoInfo vinfo;
 
         memset(info, 0, (sizeof *info));
-        if ( mpeg->obj->mpeg ) {
-            info->has_audio = (mpeg->obj->mpeg->audiostream != NULL);
+        if ( mpeg->obj ) {
+            info->has_audio = (mpeg->obj->audiostream != NULL);
             if ( info->has_audio ) {
                 mpeg->obj->GetAudioInfo(&ainfo);
 		info->audio_current_frame = ainfo.current_frame;
@@ -74,7 +90,7 @@
 			 ainfo.frequency,
 			 (ainfo.mode == 3) ? "mono" : "stereo");
             }
-            info->has_video = (mpeg->obj->mpeg->videostream != NULL);
+            info->has_video = (mpeg->obj->videostream != NULL);
             if ( info->has_video ) {
                 mpeg->obj->GetVideoInfo(&vinfo);
                 info->width = vinfo.width;
@@ -179,6 +195,14 @@
     mpeg->obj->Rewind();
 }
 
+/* Skip 'seconds' seconds of the MPEG */
+void SMPEG_skip( SMPEG* mpeg, float seconds )
+{
+  // TEMP
+  printf("smpeg skip %f\n", seconds);
+    mpeg->obj->Skip(seconds);
+}
+
 /* Render a particular frame in the MPEG video */
 void SMPEG_renderFrame( SMPEG* mpeg,
                         int framenum, SDL_Surface* dst, int x, int y )
@@ -195,7 +219,7 @@
 /* Exported function for SDL audio playback */
 void SMPEG_playAudio(void *udata, Uint8 *stream, int len)
 {
-    MPEGaudio *audio = ((SMPEG *)udata)->obj->mpeg->GetAudio();
+    MPEGaudio *audio = ((SMPEG *)udata)->obj->GetAudio();
     Play_MPEGaudio(audio, stream, len);
 }
 
diff -Naur smpeg/smpeg.h smpeg.patched/smpeg.h
--- smpeg/smpeg.h	Mon Mar  6 17:27:07 2000
+++ smpeg.patched/smpeg.h	Thu Mar  9 16:53:13 2000
@@ -88,6 +88,9 @@
  */
 extern SMPEG* SMPEG_new(const char *file, SMPEG_Info* info, int sdl_audio);
 
+/* The same as above for a file descriptor */
+extern SMPEG* SMPEG_new_descr(int file, SMPEG_Info* info, int sdl_audio);
+
 /* Get current information about an SMPEG object */
 extern void SMPEG_getinfo( SMPEG* mpeg, SMPEG_Info* info );
 
@@ -137,6 +140,9 @@
 
 /* Rewind the play position of an SMPEG object to the beginning of the MPEG */
 extern void SMPEG_rewind( SMPEG* mpeg );
+
+/* Skip 'seconds' seconds of the MPEG stream */
+void SMPEG_skip( SMPEG* mpeg, float seconds );
 
 /* Render a particular frame in the MPEG video */
 extern void SMPEG_renderFrame( SMPEG* mpeg, int framenum, SDL_Surface* dst,
diff -Naur smpeg/video/MPEGvideo.cpp smpeg.patched/video/MPEGvideo.cpp
--- smpeg/video/MPEGvideo.cpp	Wed Mar  8 00:52:51 2000
+++ smpeg.patched/video/MPEGvideo.cpp	Thu Mar  9 16:21:02 2000
@@ -128,6 +128,7 @@
 MPEGvideo::MPEGvideo(MPEGstream *stream)
 {
     Uint32 start_code;
+    MPEGstream_marker const * marker;
 
     /* Set the MPEG data stream */
     mpeg = stream;
@@ -142,6 +143,10 @@
     _mutex = NULL;
     _stream = NULL;
 
+    /* Mark the data to leave the stream unchanged */
+    /* after parsing */
+    marker = mpeg->new_marker(0);
+
     /* Get the width and height of the video */
     start_code = mpeg->copy_byte();
     start_code <<= 8;
@@ -159,12 +164,24 @@
         mpeg->copy_data(buf, 4);
         _w = (buf[0]<<4)|(buf[1]>>4);     /* 12 bits of width */
         _h = ((buf[1]&0xF)<<8)|buf[2];    /* 12 bits of height */
+	switch(buf[3]&0xF)                /*  4 bits of fps */
+	{
+	  case 1: _fps = 23.97; break;
+	  case 2: _fps = 24.00; break;
+	  case 3: _fps = 25.00; break;
+	  case 4: _fps = 29.90; break;
+	  case 5: _fps = 30.00; break;
+	  default: _fps = 0.00; break;
+	}
     } else {
         _w = 0;
         _h = 0;
+	_fps = 0.00;
         SetError("Not a valid MPEG video stream");
     }
-    mpeg->reset_stream();
+    /* Rewind back to the old position */
+    mpeg->seek_marker(marker);
+    mpeg->delete_marker(marker);
 }
 
 MPEGvideo:: ~MPEGvideo()
@@ -177,15 +194,6 @@
         DestroyVidStream( _stream );
 }
 
-
-void
-MPEGvideo:: Loop(bool toggle)
-{
-    if ( _stream ) {
-        _stream->loopFlag = toggle;
-    }
-}
-
 /* Simple thread play function */
 int Play_MPEGvideo( void *udata )
 {
@@ -206,12 +214,7 @@
 
         if( mpeg->_stream->film_has_ended )
         {
-            if( mpeg->_stream->loopFlag ) {
-                /* Rewind and start playback over */
-                mpeg->RewindStream();
-            } else {
-                mpeg->playing = false;
-            }
+	  mpeg->playing = false;
         }
     }
     return(0);
@@ -252,42 +255,51 @@
 }
 
 void
-MPEGvideo:: RewindStream(void)
+MPEGvideo:: Rewind(void)
 {
-    /* Reinitialize vid_stream pointers */
-    ResetVidStream( _stream );
-
-    mpeg->reset_stream();
-
+    Stop();
+    if ( _stream ) {
+      /* Reinitialize vid_stream pointers */
+      ResetVidStream( _stream );
 #ifdef ANALYSIS 
-    init_stats();
+      init_stats();
 #endif
-    /* Process start codes */
-    if( mpegVidRsrc( 0, _stream, 1 ) == NULL )
-    {
-        /* print something sensible here,
-           but we only get here if the file is changed while we
-           are decoding, right?
-        */
+      /* Process start codes */
+      if( mpegVidRsrc( 0, _stream, 1 ) == NULL )
+      {
+	SetError("Not an MPEG video stream");
+	return;
+      }
+      _stream->realTimeStart = 0.0;
     }
+    play_time = 0.0;
 }
-
 void
-MPEGvideo:: Rewind(void)
+MPEGvideo::Skip(float seconds)
 {
-    Stop();
-    if ( _stream ) {
-        RewindStream();
-        _stream->realTimeStart = 0.0;
+  Uint32 frame;
+
+  printf("Video: Skipping %f seconds... please wait\n", seconds);  
+  frame = (Uint32) (_fps * seconds);
+
+  if( _stream )
+  {
+    _stream->_jumpFrame = frame;
+    while( (_stream->totNumFrames < frame) &&
+	   ! _stream->film_has_ended )
+    {
+      mpegVidRsrc( 0, _stream, 0 );
     }
+    _stream->_jumpFrame = -1;
+    _stream->realTimeStart = 0.0;
     play_time = 0.0;
+  }
 }
-
 MPEGstatus
 MPEGvideo:: Status(void)
 {
     if ( _stream ) {
-        if( !_thread || (_stream->film_has_ended && !_stream->loopFlag) ) {
+        if( !_thread || (_stream->film_has_ended ) ) {
             return MPEG_STOPPED;
         } else {
             return MPEG_PLAYING;
@@ -434,6 +446,7 @@
     _surf = dst;
 
     if( _stream->totNumFrames > frame ) {
+        mpeg->rewind_stream();
         Rewind();
     }
 
@@ -465,8 +478,10 @@
     {
         /* Search for the last "group of pictures" start code */
         Uint32 start_code;
-
-        mpeg->reset_stream();
+	MPEGstream_marker const * marker;
+	
+	marker = 0;
+        mpeg->rewind_stream();
         start_code = mpeg->copy_byte();
         start_code <<= 8;
         start_code |= mpeg->copy_byte();
@@ -476,14 +491,16 @@
             start_code <<= 8;
             start_code |= mpeg->copy_byte();
             if ( start_code == GOP_START_CODE ) {
-                mpeg->mark_data(-4);
+	        if( marker ) mpeg->delete_marker( marker );
+                mpeg->new_marker(-4);
             }
         }
 
         /* Set the stream to the last spot marked */
-        if ( ! mpeg->seek_marker() ) {
-            mpeg->reset_stream();
+        if ( ! mpeg->seek_marker( marker ) ) {
+            mpeg->rewind_stream();
         }
+	mpeg->delete_marker( marker );
         _stream->buf_length = 0;
         _stream->bit_offset = 0;
 
diff -Naur smpeg/video/Makefile.in smpeg.patched/video/Makefile.in
--- smpeg/video/Makefile.in	Thu Jan  1 01:00:00 1970
+++ smpeg.patched/video/Makefile.in	Thu Mar  9 01:21:04 2000
@@ -0,0 +1,385 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AS = @AS@
+BINARY_AGE = @BINARY_AGE@
+CC = @CC@
+CXX = @CXX@
+DLLTOOL = @DLLTOOL@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_CONFIG = @GTK_CONFIG@
+GTK_LIBS = @GTK_LIBS@
+INTERFACE_AGE = @INTERFACE_AGE@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+MAJOR_VERSION = @MAJOR_VERSION@
+MAKEINFO = @MAKEINFO@
+MICRO_VERSION = @MICRO_VERSION@
+MINOR_VERSION = @MINOR_VERSION@
+NM = @NM@
+OBJDUMP = @OBJDUMP@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+VERSION = @VERSION@
+
+noinst_LTLIBRARIES = libvideo.la
+
+libvideo_la_SOURCES =  	16bit.cpp			16bit_mmx.cpp			32bit_mmx.cpp			MPEGvideo.cpp			decoders.cpp			decoders.h			dither.h			floatdct.cpp			gdith.cpp			jrevdct.cpp			motionvector.cpp		parseblock.cpp			proto.h				readfile.cpp			util.cpp			util.h				video.cpp			video.h				mmxflags_asm.S			mmxidct_asm.S
+
+
+EXTRA_DIST =  	README				COPYRIGHT
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LTLIBRARIES =  $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libvideo_la_LDFLAGS = 
+libvideo_la_LIBADD = 
+libvideo_la_OBJECTS =  16bit.lo 16bit_mmx.lo 32bit_mmx.lo MPEGvideo.lo \
+decoders.lo floatdct.lo gdith.lo jrevdct.lo motionvector.lo \
+parseblock.lo readfile.lo util.lo video.lo mmxflags_asm.lo \
+mmxidct_asm.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  README Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+DEP_FILES =  .deps/16bit.P .deps/16bit_mmx.P .deps/32bit_mmx.P \
+.deps/MPEGvideo.P .deps/decoders.P .deps/floatdct.P .deps/gdith.P \
+.deps/jrevdct.P .deps/mmxflags_asm.P .deps/mmxidct_asm.P \
+.deps/motionvector.P .deps/parseblock.P .deps/readfile.P .deps/util.P \
+.deps/video.P
+SOURCES = $(libvideo_la_SOURCES)
+OBJECTS = $(libvideo_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cpp .lo .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu video/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+	$(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+	$(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libvideo.la: $(libvideo_la_OBJECTS) $(libvideo_la_DEPENDENCIES)
+	$(CXXLINK)  $(libvideo_la_LDFLAGS) $(libvideo_la_OBJECTS) $(libvideo_la_LIBADD) $(LIBS)
+.cpp.o:
+	$(CXXCOMPILE) -c $<
+.cpp.lo:
+	$(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = video
+
+distdir: $(DISTFILES)
+	here=`cd $(top_builddir) && pwd`; \
+	top_distdir=`cd $(top_distdir) && pwd`; \
+	distdir=`cd $(distdir) && pwd`; \
+	cd $(top_srcdir) \
+	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu video/Makefile
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$d/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+	-rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+	@echo '$(COMPILE) -c $<'; \
+	$(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-cp .deps/$(*F).pp .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm .deps/$(*F).pp
+
+%.lo: %.c
+	@echo '$(LTCOMPILE) -c $<'; \
+	$(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-sed -e 's/^\([^:]*\)\.o[ 	]*:/\1.lo \1.o :/' \
+	  < .deps/$(*F).pp > .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm -f .deps/$(*F).pp
+
+%.o: %.cpp
+	@echo '$(CXXCOMPILE) -c $<'; \
+	$(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-cp .deps/$(*F).pp .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm .deps/$(*F).pp
+
+%.lo: %.cpp
+	@echo '$(LTCXXCOMPILE) -c $<'; \
+	$(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-sed -e 's/^\([^:]*\)\.o[ 	]*:/\1.lo \1.o :/' \
+	  < .deps/$(*F).pp > .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+		mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+		mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLTLIBRARIES clean-compile clean-libtool \
+		clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLTLIBRARIES distclean-compile \
+		distclean-libtool distclean-tags distclean-depend \
+		distclean-generic clean-am
+	-rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLTLIBRARIES \
+		maintainer-clean-compile maintainer-clean-libtool \
+		maintainer-clean-tags maintainer-clean-depend \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+#16bit_mmx.o: 16bit_mmx.cpp
+#	$(CXX) -c -o $@ $^ $(CXXFLAGS)
+16bit_mmx.lo: 16bit_mmx.cpp
+	$(CXX) -c -o $@ $^ $(CXXFLAGS)
+#32bit_mmx.o: 32bit_mmx.cpp
+#	$(CXX) -c -o $@ $^ $(CXXFLAGS)
+32bit_mmx.lo: 32bit_mmx.cpp
+	$(CXX) -c -o $@ $^ $(CXXFLAGS)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff -Naur smpeg/video/video.cpp smpeg.patched/video/video.cpp
--- smpeg/video/video.cpp	Wed Mar  8 00:52:51 2000
+++ smpeg.patched/video/video.cpp	Thu Mar  9 02:44:49 2000
@@ -1021,6 +1021,7 @@
     case SEQ_END_CODE:
     case 0x000001b9:   /*  handle ISO_11172_END_CODE too */
 
+        flush_bits32;
         /* Display last frame. */
 
         /* Set ended flag first so that ExecuteDisplay may check it. */
diff -Naur smpeg/video/video.h smpeg.patched/video/video.h
--- smpeg/video/video.h	Wed Mar  8 00:52:51 2000
+++ smpeg.patched/video/video.h	Thu Mar  9 01:17:42 2000
@@ -291,7 +291,6 @@
   PictImage *ring[RING_BUF_SIZE];              /* Ring buffer of frames.     */
 
 /* KR - beginning of added variables */
-  int loopFlag;
   int rate_deal;
   int _skipFrame;
   double _skipCount;
*************************************************************************
*** Applied ***
Date: Sun, 05 Mar 2000 02:36:24 +0900
From: Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>
Subject: smpeg-0.3.4 Report


FreeBSD 3.4STABLE & SDL-1.0.6
(gcc 2.95.2)

patch attached. (smpeg034.diff)

configure
  SDL Version Req 1.1.1 -> 1.0.6

ltmain.sh
  FreeBSD -lc not need

mpegtoraw.cpp
  48Kh Audio Can't Play fix;

MPEGaction.h
MPEGaudio.h
MPEGaudio.cpp
smpeg.cpp
smpeg.h
plaympeg.c
  Getting Audio Info.

MPEG.cpp
  I have Funny Hedaer MPEG1 Movie. that fix.
  Video Start Code 0xe0 0xe2.

header(od -cx)
----------------------------------------
0000000    R   I   F   F 200   9 314 002   R   M   P   3   d   a   t   a
            4952    4646    3980    02cc    4d52    3350    6164    6174
0000020  004   8 314 002  \0  \0 001 272   !  \0 001  \0 001 200   Q 215
            3804    02cc    0000    ba01    0021    0001    8001    8d51
0000040   \0  \0 001 273  \0  \f 200   Q 215 004 341 377 340 342 007 300
            0000    bb01    0c00    5180    048d    ffe1    e2e0    c007
0000060  300   .  \0  \0 001 276 007 334 017 377 377 377 377 377 377 377
            2ec0    0000    be01    dc07    ff0f    ffff    ffff    ffff
0000100  377 377 377 377 377 377 377 377 377 377 377 377 377 377 377 377
            ffff    ffff    ffff    ffff    ffff    ffff    ffff    ffff
*
0004020  377 377 377 377  \0  \0 001 272   !  \0 001 002 305 200   Q 215
            ffff    ffff    0000    ba01    0021    0201    80c5    8d51
0004040   \0  \0 001 340 007 356   b 007   1  \0 001 024 007 021  \0 001
            0000    e001    ee07    0762    0031    1401    1107    0100
0004060   \b   K  \0  \0 001 263 024  \0 360 027 377 377 350 001 020 021
            4b08    0000    b301    0014    17f0    ffff    01e8    1110
0004100  021 022 022 022 023 023 023 023 024 024 024 024 024 025 025 025
            1211    1212    1313    1313    1414    1414    1514    1515
0004120  025 025 025 026 026 026 026 026 026 026 027 027 027 027 027 027
            1515    1615    1616    1616    1616    1717    1717    1717
0004140  027 027 030 030 030 031 030 030 030 031 032 032 032 032 031 033
            1717    1818    1918    1818    1918    1a1a    1a1a    1b19

-----------------------------------------------
Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>

diff -Nru smpeg-0.3.4/MPEG.cpp smpeg-0.3.4.new/MPEG.cpp
--- smpeg-0.3.4/MPEG.cpp	Wed Mar  1 23:47:51 2000
+++ smpeg-0.3.4.new/MPEG.cpp	Sun Mar  5 02:06:28 2000
@@ -24,8 +24,8 @@
                     audioaction_enabled = true;
                 } else
 #endif
-                if ( (data[1] == VIDEO_STREAMID) && !videostream ) {
-                    videostream = new MPEG(mpeg, size, data[1], sdlaudio);
+                if ( ((data[1] & 0xF0) == VIDEO_STREAMID)  && !videostream ) {
+                    videostream = new MPEG(mpeg, size, data[1]&0xF0, sdlaudio);
                     if ( videostream->WasError() ) {
                         SetError(videostream->TheError());
                     }
diff -Nru smpeg-0.3.4/MPEGaction.h smpeg-0.3.4.new/MPEGaction.h
--- smpeg-0.3.4/MPEGaction.h	Fri Feb  4 02:45:56 2000
+++ smpeg-0.3.4.new/MPEGaction.h	Sun Mar  5 00:20:25 2000
@@ -71,7 +71,12 @@
 
 /* For getting info about the audio portion of the stream */
 typedef struct MPEG_AudioInfo {
-    int unused;
+    int mpegversion;
+    int mode;
+    int frequency;
+    int layer;
+    int bitrate;
+    int current_frame;
 } MPEG_AudioInfo;
 
 /* Audio action class */
diff -Nru smpeg-0.3.4/MPEGaudio.h smpeg-0.3.4.new/MPEGaudio.h
--- smpeg-0.3.4/MPEGaudio.h	Sat Mar  4 06:23:55 2000
+++ smpeg-0.3.4.new/MPEGaudio.h	Sat Mar  4 23:43:15 2000
@@ -160,6 +160,7 @@
     virtual ~MPEGaudio();
 
     /* MPEG actions */
+    bool GetAudioInfo(MPEG_AudioInfo *info);
     double Time(void);
     void Play(void);
     void Stop(void);
diff -Nru smpeg-0.3.4/audio/MPEGaudio.cpp smpeg-0.3.4.new/audio/MPEGaudio.cpp
--- smpeg-0.3.4/audio/MPEGaudio.cpp	Wed Mar  1 23:43:46 2000
+++ smpeg-0.3.4.new/audio/MPEGaudio.cpp	Sun Mar  5 00:24:15 2000
@@ -235,3 +235,16 @@
         return(MPEG_ERROR);
     }
 }
+
+bool
+MPEGaudio:: GetAudioInfo(MPEG_AudioInfo *info)
+{
+    if ( info ) {
+      info->mpegversion = version;
+      info->mode = mode;
+      info->frequency = frequencies[version][frequency];
+      info->layer = layer;
+      info->bitrate = bitrate[version][layer-1][bitrateindex];
+      info->current_frame = currentframe;
+    }
+}
diff -Nru smpeg-0.3.4/audio/mpegtoraw.cpp smpeg-0.3.4.new/audio/mpegtoraw.cpp
--- smpeg-0.3.4/audio/mpegtoraw.cpp	Sat Mar  4 06:24:49 2000
+++ smpeg-0.3.4.new/audio/mpegtoraw.cpp	Sat Mar  4 23:29:31 2000
@@ -167,7 +167,7 @@
     c = mpeg->copy_byte() >> 1;
     padding = (c & 1);
     c >>= 1;
-    frequency = (_frequency) (c&2);
+    frequency = (_frequency) (c&3);
     c >>= 2;
     bitrateindex = (int) c;
     if( bitrateindex == 15 )
diff -Nru smpeg-0.3.4/configure smpeg-0.3.4.new/configure
--- smpeg-0.3.4/configure	Sat Mar  4 10:56:25 2000
+++ smpeg-0.3.4.new/configure	Sat Mar  4 19:37:07 2000
@@ -2184,7 +2184,7 @@
     { echo "configure: error: SMPEG requires mmap() for file loading" 1>&2; exit 1; }
 fi
 
-SDL_VERSION=1.1.1
+SDL_VERSION=1.0.6
 # Check whether --with-sdl-prefix or --without-sdl-prefix was given.
 if test "${with_sdl_prefix+set}" = set; then
   withval="$with_sdl_prefix"
diff -Nru smpeg-0.3.4/ltmain.sh smpeg-0.3.4.new/ltmain.sh
--- smpeg-0.3.4/ltmain.sh	Wed Nov 24 05:25:13 1999
+++ smpeg-0.3.4.new/ltmain.sh	Sat Mar  4 19:35:32 2000
@@ -1993,7 +1993,7 @@
       if test "$build_libtool_libs" = yes; then
 	if test -n "$rpath"; then
 	  case "$host" in
-	  *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*)
+	  *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos* | *-*-freebsd*)
 	    # these systems don't actually have a c library (as such)!
 	    ;;
 	  *)
diff -Nru smpeg-0.3.4/plaympeg.c smpeg-0.3.4.new/plaympeg.c
--- smpeg-0.3.4/plaympeg.c	Thu Mar  2 00:05:07 2000
+++ smpeg-0.3.4.new/plaympeg.c	Sun Mar  5 00:51:42 2000
@@ -22,6 +22,8 @@
 
 #include "smpeg.h"
 
+    SMPEG *mpeg;
+
 void usage(char *argv0)
 {
     printf(
@@ -56,7 +58,6 @@
     int loop_play;
     int i, done, pause;
     int volume;
-    SMPEG *mpeg;
     SMPEG_Info info;
     char *basefile;
     SDL_version sdlver;
@@ -163,7 +164,6 @@
 	}
 	
 	
-	
         /* Create the MPEG stream */
         mpeg = SMPEG_new(argv[i], &info, use_audio);
         if ( SMPEG_error(mpeg) ) {
@@ -184,8 +184,10 @@
         }
         if ( info.has_audio && info.has_video ) {
             printf("%s: MPEG system stream (audio/video)\n", basefile);
+	    printf("%s\n",info.ainfo_str);
         } else if ( info.has_audio ) {
             printf("%s: MPEG audio stream\n", basefile);
+	    printf("%s\n",info.ainfo_str);
         } else if ( info.has_video ) {
             printf("%s: MPEG video stream\n", basefile);
         }
diff -Nru smpeg-0.3.4/smpeg.cpp smpeg-0.3.4.new/smpeg.cpp
--- smpeg-0.3.4/smpeg.cpp	Fri Feb  4 02:45:56 2000
+++ smpeg-0.3.4.new/smpeg.cpp	Sun Mar  5 01:40:36 2000
@@ -65,6 +65,13 @@
             info->has_audio = (mpeg->obj->mpeg->audiostream != NULL);
             if ( info->has_audio ) {
                 mpeg->obj->GetAudioInfo(&ainfo);
+		info->a_current_frame = ainfo.current_frame;
+		snprintf(info->ainfo_str,80,"MPEG%d layer%d %dkbit/s %dHz %s",
+			ainfo.mpegversion+1,
+			ainfo.layer,
+			ainfo.bitrate,
+			ainfo.frequency,
+			(ainfo.mode==3)?"mono":"stereo");
             }
             info->has_video = (mpeg->obj->mpeg->videostream != NULL);
             if ( info->has_video ) {
diff -Nru smpeg-0.3.4/smpeg.h smpeg-0.3.4.new/smpeg.h
--- smpeg-0.3.4/smpeg.h	Sun Feb  6 01:54:09 2000
+++ smpeg-0.3.4.new/smpeg.h	Sun Mar  5 01:40:19 2000
@@ -61,6 +61,8 @@
     int height;
     int current_frame;
     double current_fps;
+    int  a_current_frame;
+    char ainfo_str[80];
 } SMPEG_Info;
 
 /* Possible MPEG status codes */
*************************************************************************
*** Applied ***
smpeg-0.3.3-fixes
by Bill Kendrick

Apply CHANGES.patch to smpeg-0.3.3's "CHANGES" to see what's been changed.

Enjoy!

-bill!
3/Feb/2000
----------
--- smpeg-0.3.3/smpeg.h Tue Dec 21 09:17:35 1999
+++ smpeg-0.3.3-patched/smpeg.h Sat Jan 22 17:28:15 2000
@@ -30,6 +30,26 @@
 extern "C" {
 #endif

+#define SMPEG_MAJOR_VERSION      0
+#define SMPEG_MINOR_VERSION      3
+#define SMPEG_PATCHLEVEL         3
+
+typedef struct {
+        Uint8 major;
+        Uint8 minor;
+        Uint8 patch;
+} SMPEG_version;
+
+/* This macro can be used to fill a version structure with the compile-time
+ * version of the SDL library.
+ */
+#define SMPEG_VERSION(X)                                                \
+{                                                                       \
+        (X)->major = SMPEG_MAJOR_VERSION;                               \
+        (X)->minor = SMPEG_MINOR_VERSION;                               \
+        (X)->patch = SMPEG_PATCHLEVEL;                                  \
+}
+
 /* This is the actual SMPEG object */
 typedef struct _SMPEG SMPEG;
----------
35c35,37
< "	--volume N or -v N Set audio volume to N (0-100)\n", argv0);
---
> "	--volume N or -v N Set audio volume to N (0-100)\n"
> "	--help or -h\n"
> "	--version or -V\n", argv0);
53a56
>     int video_inited = 0, audio_inited = 0;
58,63c61,62
< 
<     /* Initialize SDL */
<     if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0 ) {
<         fprintf(stderr, "Couldn't init SDL: %s\n", SDL_GetError());
<         exit(1);
<     }
---
>     SDL_version sdlver;
>     SMPEG_version smpegver;
89a89,93
> 	    if (i >= argc)
> 	      {
> 		fprintf(stderr, "Please specify volume when using --volume or -v\n");
> 		exit(1);
> 	      }
96a101,110
> 	} else
>         if ((strcmp(argv[i], "--version") == 0) ||
> 	    (strcmp(argv[i], "-V") == 0)) {
>             SDL_VERSION(&sdlver);
>             SMPEG_VERSION(&smpegver);
> 	    printf("SDL version: %d.%d.%d\n"
>                    "SMPEG version: %d.%d.%d\n",
> 		   sdlver.major, sdlver.minor, sdlver.patch,
> 		   smpegver.major, smpegver.minor, smpegver.patch);
>             exit(0);
137a152,176
> 	/* Initialize SDL */
> 	if (info.has_video && !video_inited && use_video) {
> 	  if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
> 	    fprintf(stderr, "Warning: Couldn't init SDL video: %s\n",
> 		    SDL_GetError());
> 	    fprintf(stderr, "Will ignore video stream\n");
> 	    use_video = 0;
> 	  }
> 	  else
> 	    video_inited = 1;
> 	}
> 	
> 	if (info.has_audio && !audio_inited && use_audio) {
> 	  if ( SDL_Init(SDL_INIT_AUDIO) < 0 ) {
> 	    fprintf(stderr, "Warning: Couldn't init SDL audio: %s\n",
> 		    SDL_GetError());
> 	    fprintf(stderr, "Will ignore audio stream\n");
> 	    use_audio = 0;
> 	  }
> 	  else
> 	    audio_inited = 1;
> 	}
> 	
> 	
> 	
*************************************************************************
*** Applied ***
From: Jesper Pedersen <jep@systematic.dk>
Subject: Patch for SMPEG_pause() bug
Date: Mon, 31 Jan 2000 15:12:52 +0100

Hi Sam.

I've attached my patch which include the fix for the SMPEG_pause() bug.

BTW: I've noticed when another application is using my soundcard that
the playback of a MPEG stream doesn't work with plaympeg :/
(don't know whether this is a libSDL or libSMPEG bug yet)

BTW: All my problems with screen-updates disappeared when 
I upgraded to SDL-1.0.3: Keep up the good work !

Cheers,

 Jesper

diff -u -N -r smpeg-0.3.3/MPEG.h smpeg-cvs/MPEG.h
--- smpeg-0.3.3/MPEG.h	Thu Jan  6 22:02:23 2000
+++ smpeg-cvs/MPEG.h	Sat Jan 22 15:44:40 2000
@@ -273,9 +273,9 @@
             videoaction->MoveDisplay(x, y);
         }
     }
-    void DoubleDisplay(bool toggle) {
+    void ScaleDisplay(int scale) {
         if ( VideoEnabled() ) {
-            videoaction->DoubleDisplay(toggle);
+            videoaction->ScaleDisplay(scale);
         }
     }
     void RenderFrame(int frame, SDL_Surface *dst, int x, int y) {
@@ -501,9 +501,9 @@
             mpeg->MoveDisplay(x, y);
         }
     }
-    void DoubleDisplay(bool toggle) {
+    void ScaleDisplay(int scale) {
         if ( mpeg ) {
-            mpeg->DoubleDisplay(toggle);
+            mpeg->ScaleDisplay(scale);
         }
     }
     void RenderFrame(int frame, SDL_Surface *dst, int x, int y) {
diff -u -N -r smpeg-0.3.3/MPEGaction.h smpeg-cvs/MPEGaction.h
--- smpeg-0.3.3/MPEGaction.h	Tue Dec 21 18:17:35 1999
+++ smpeg-cvs/MPEGaction.h	Sun Jan 30 10:09:41 2000
@@ -36,6 +36,7 @@
         playing = false;
         paused = false;
         looping = false;
+	play_time = 0.0;
     }
     virtual void Loop(bool toggle) {
         looping = toggle;
@@ -106,7 +107,7 @@
     virtual bool SetDisplay(SDL_Surface *dst, SDL_mutex *lock,
                                 MPEG_DisplayCallback callback) = 0;
     virtual void MoveDisplay(int x, int y) = 0;
-    virtual void DoubleDisplay(bool toggle) = 0;
+    virtual void ScaleDisplay(int scale) = 0;
     virtual void RenderFrame(int frame, SDL_Surface *dst, int x, int y) = 0;
     virtual void RenderFinal(SDL_Surface *dst, int x, int y) = 0;
 protected:
diff -u -N -r smpeg-0.3.3/MPEGvideo.h smpeg-cvs/MPEGvideo.h
--- smpeg-0.3.3/MPEGvideo.h	Tue Dec 21 18:17:35 1999
+++ smpeg-cvs/MPEGvideo.h	Sat Jan 22 15:44:40 2000
@@ -59,7 +59,7 @@
     bool SetDisplay(SDL_Surface *dst, SDL_mutex *lock,
                                             MPEG_DisplayCallback callback);
     void MoveDisplay(int x, int y);
-    void DoubleDisplay(bool toggle);
+    void ScaleDisplay(int scale);
     void RenderFrame(int frame, SDL_Surface *dst, int x, int y);
     void RenderFinal(SDL_Surface *dst, int x, int y);
 
@@ -78,7 +78,7 @@
 
     MPEG_DisplayCallback _callback;
 
-    int _double;        // play back at double size
+    int _scale;         // play back at '_scale' size
     int _w;             // width of movie
     int _h;             // height of movie
     int _x;             // pixel x offset
diff -u -N -r smpeg-0.3.3/gtv.c smpeg-cvs/gtv.c
--- smpeg-0.3.3/gtv.c	Thu Oct 21 17:54:50 1999
+++ smpeg-cvs/gtv.c	Sat Jan 22 15:44:40 2000
@@ -445,6 +445,7 @@
 {
     SMPEG* mpeg = NULL;
     SDL_Surface* sdl_screen = NULL;
+    int scale = 1;
 
     assert( raw );
 
@@ -460,6 +461,7 @@
 
 	if( active ) {
 	    SMPEG_move( mpeg, 0, 0 );
+	    scale = 2;
 	} else {
 	    SMPEG_Info* info = NULL;
 
@@ -468,9 +470,10 @@
 	    SMPEG_move( mpeg,
 			( sdl_screen->w - info->width ) / 2,
 			( sdl_screen->h - info->height ) / 2 );
+	    scale = 1;
 	}
 
-	SMPEG_double( mpeg, active );
+	SMPEG_scale( mpeg, scale );
 	gtv_clear_screen( raw );
     }
 
diff -u -N -r smpeg-0.3.3/plaympeg.1 smpeg-cvs/plaympeg.1
--- smpeg-0.3.3/plaympeg.1	Mon Jan  3 21:16:24 2000
+++ smpeg-cvs/plaympeg.1	Sat Jan 22 15:44:40 2000
@@ -40,6 +40,9 @@
 .TP
 .B \-v N, \--volume N
 Set the volume of the audio stream to N% (N in the range of 0 to 100)
+.TP
+.B \-s S, \--scale S
+Play the MPEG video stream at S size
 .SH "SEE ALSO"
 SMPEG home page at http://www.lokigames.com/development/smpeg.php3
 .SH AUTHOR
diff -u -N -r smpeg-0.3.3/plaympeg.c smpeg-cvs/plaympeg.c
--- smpeg-0.3.3/plaympeg.c	Wed Jan 19 06:57:09 2000
+++ smpeg-cvs/plaympeg.c	Sun Jan 30 11:03:25 2000
@@ -27,12 +27,13 @@
     printf(
 "Usage: %s [options] file ...\n"
 "Where the options are one of:\n"
-"	--noaudio	Don't play audio stream\n"
-"	--novideo	Don't play video stream\n"
-"	--fullscreen	Play MPEG in fullscreen mode\n"
-"	--double or -2	Play MPEG at double size\n"
-"	--loop or -l	Play MPEG over and over\n"
-"	--volume N or -v N Set audio volume to N (0-100)\n", argv0);
+"	--noaudio	     Don't play audio stream\n"
+"	--novideo	     Don't play video stream\n"
+"	--fullscreen	     Play MPEG in fullscreen mode\n"
+"	--double or -2	     Play MPEG at double size\n"
+"	--loop or -l	     Play MPEG over and over\n"
+"	--volume N or -v N   Set audio volume to N (0-100)\n"
+"	--scale S or -s S    Play MPEG at size S (1-)\n", argv0);
 }
 
 void update(SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
@@ -48,9 +49,9 @@
 {
     int use_audio, use_video;
     int fullscreen;
-    int doublesize;
+    int scalesize;
     int loop_play;
-    int i, done;
+    int i, done, pause;
     int volume;
     SMPEG *mpeg;
     SMPEG_Info info;
@@ -66,7 +67,7 @@
     use_audio = 1;
     use_video = 1;
     fullscreen = 0;
-    doublesize = 0;
+    scalesize = 1;
     loop_play = 0;
     volume = 100;
     for ( i=1; argv[i] && (argv[i][0] == '-'); ++i ) {
@@ -80,7 +81,7 @@
             fullscreen = 1;
         } else
         if ((strcmp(argv[i], "--double") == 0)||(strcmp(argv[i], "-2") == 0)) {
-            doublesize = 1;
+            scalesize = 2;
         } else
         if ((strcmp(argv[i], "--loop") == 0) || (strcmp(argv[i], "-l") == 0)) {
             loop_play = 1;
@@ -90,6 +91,20 @@
             if ( argv[i] ) {
                 volume = atoi(argv[i]);
             }
+	    if ( ( volume < 0 ) || ( volume > 100 ) ) {
+	      fprintf(stderr, "Volume must be between 0 and 100\n");
+	      volume = 100;
+	    }
+        } else
+        if ((strcmp(argv[i], "--scale") == 0)||(strcmp(argv[i], "-s") == 0)) {
+            ++i;
+            if ( argv[i] ) {
+                scalesize = atoi(argv[i]);
+            }
+	    if (( scalesize < 1 ) || ( scalesize > 2)) {
+	      fprintf(stderr, "Scale must be 1 or 2 (work in progress)\n");
+	      scalesize = 1;
+	    }
         } else
         if ((strcmp(argv[i], "--help") == 0) || (strcmp(argv[i], "-h") == 0)) {
             usage(argv[0]);
@@ -139,18 +154,22 @@
         if ( info.has_video && use_video ) {
             SDL_Surface *screen;
             Uint32 video_flags;
+	    int height, width;
+
+	    width = info.width;
+	    height = info.height;
 
-            if ( doublesize ) {
-                SMPEG_double(mpeg, 1);
-                info.width *= 2;
-                info.height *= 2;
+            if ( scalesize != 1 ) {
+                SMPEG_scale(mpeg, scalesize);
+                width *= scalesize;
+                height *= scalesize;
             }
             video_flags = SDL_SWSURFACE;
             if ( fullscreen ) {
                 video_flags = SDL_FULLSCREEN|SDL_DOUBLEBUF|SDL_HWSURFACE;
                 SDL_ShowCursor(0);
             }
-            screen = SDL_SetVideoMode(info.width, info.height, 0, video_flags);
+            screen = SDL_SetVideoMode(width, height, 0, video_flags);
             SMPEG_setdisplay(mpeg, screen, NULL, update);
         }
 
@@ -162,15 +181,88 @@
         /* Play it, and wait for playback to complete */
         SMPEG_play(mpeg);
         done = 0;
-        while ( ! done && (SMPEG_status(mpeg) == SMPEG_PLAYING) ) {
+	pause = 0;
+        while ( ! done && ( pause || (SMPEG_status(mpeg) == SMPEG_PLAYING) ) ) {
             SDL_Event event;
 
             while ( SDL_PollEvent(&event) ) {
                 switch (event.type) {
                     case SDL_KEYDOWN:
-                        if ( event.key.keysym.sym == SDLK_ESCAPE ) {
-                            done = 1;
-                        }
+                        if ( (event.key.keysym.sym == SDLK_ESCAPE) || (event.key.keysym.sym == SDLK_q) ) {
+			  // Quit
+			  done = 1;
+                        } else if ( event.key.keysym.sym == SDLK_UP ) {
+			  // Volume up
+			  if ( volume < 100 ) {
+			    if ( SDL_GetModState() & KMOD_SHIFT ) {       // 10+
+			      volume += 10;
+			    } else if ( SDL_GetModState() & KMOD_CTRL ) { // 100+
+			      volume = 100;
+			    } else {                                      // 1+
+			      volume++;
+			    }
+			    if ( volume > 100 ) 
+			      volume = 100;
+			    SMPEG_setvolume(mpeg, volume);
+			  }
+                        } else if ( event.key.keysym.sym == SDLK_DOWN ) {
+			  // Volume down
+			  if ( volume > 0 ) {
+			    if ( SDL_GetModState() & KMOD_SHIFT ) {
+			      volume -= 10;
+			    } else if ( SDL_GetModState() & KMOD_CTRL ) {
+			      volume = 0;
+			    } else {
+			      volume--;
+			    }
+			    if ( volume < 0 ) 
+			      volume = 0;
+			    SMPEG_setvolume(mpeg, volume);
+			  }
+                        } else if ( event.key.keysym.sym == SDLK_PAGEUP ) {
+			  // Full volume
+			  volume = 100;
+			  SMPEG_setvolume(mpeg, volume);
+                        } else if ( event.key.keysym.sym == SDLK_PAGEDOWN ) {
+			  // Volume off
+			  volume = 0;
+			  SMPEG_setvolume(mpeg, volume);
+                        } else if ( event.key.keysym.sym == SDLK_SPACE ) {
+			  // Toggle play / pause
+			  if ( SMPEG_status(mpeg) == SMPEG_PLAYING ) {
+			    SMPEG_pause(mpeg);
+			    pause = 1;
+			  } else {
+			    SMPEG_play(mpeg);
+			    pause = 0;
+			  }
+			} else if ( event.key.keysym.sym == SDLK_RIGHT ) {
+			  // Forward
+			  if ( SDL_GetModState() & KMOD_SHIFT ) {
+
+			  } else if ( SDL_GetModState() & KMOD_CTRL ) {
+
+			  } else {
+			    
+			  }
+                        } else if ( event.key.keysym.sym == SDLK_LEFT ) {
+			  // Reverse
+			  if ( SDL_GetModState() & KMOD_SHIFT ) {
+
+			  } else if ( SDL_GetModState() & KMOD_CTRL ) {
+
+			  } else {
+
+			  }
+                        } else if ( event.key.keysym.sym == SDLK_KP_MINUS ) {
+			  // Scale minus
+			  if ( scalesize > 1 ) {
+			    scalesize--;
+			  }
+                        } else if ( event.key.keysym.sym == SDLK_KP_PLUS ) {
+			  // Scale plus
+			  scalesize++;
+			}
                         break;
                     case SDL_QUIT:
                         done = 1;
diff -u -N -r smpeg-0.3.3/smpeg.cpp smpeg-cvs/smpeg.cpp
--- smpeg-0.3.3/smpeg.cpp	Wed Nov 24 21:03:48 1999
+++ smpeg-cvs/smpeg.cpp	Sat Jan 22 15:44:40 2000
@@ -135,10 +135,10 @@
     mpeg->obj->Loop(repeat);
 }
 
-/* Set or clear pixel-doubled display on an SMPEG object */
-void SMPEG_double( SMPEG* mpeg, int big )
+/* Scale pixel display on an SMPEG object */
+void SMPEG_scale( SMPEG* mpeg, int scale )
 {
-    mpeg->obj->DoubleDisplay(big);
+    mpeg->obj->ScaleDisplay(scale);
 }
 
 /* Move the video display area within the destination surface */
diff -u -N -r smpeg-0.3.3/smpeg.h smpeg-cvs/smpeg.h
--- smpeg-0.3.3/smpeg.h	Tue Dec 21 18:17:35 1999
+++ smpeg-cvs/smpeg.h	Sat Jan 22 15:44:40 2000
@@ -95,8 +95,8 @@
 /* Set or clear looping play on an SMPEG object */
 extern void SMPEG_loop( SMPEG* mpeg, int repeat );
 
-/* Set or clear pixel-doubled display on an SMPEG object */
-extern void SMPEG_double( SMPEG* mpeg, int big );
+/* Scale pixel display on an SMPEG object */
+extern void SMPEG_scale( SMPEG* mpeg, int scale );
 
 /* Move the video display area within the destination surface */
 extern void SMPEG_move( SMPEG* mpeg, int x, int y );
diff -u -N -r smpeg-0.3.3/video/16bit.cpp smpeg-cvs/video/16bit.cpp
--- smpeg-0.3.3/video/16bit.cpp	Thu Oct 21 17:55:01 1999
+++ smpeg-cvs/video/16bit.cpp	Sun Jan 23 18:00:40 2000
@@ -583,9 +583,9 @@
 /*
  *--------------------------------------------------------------
  *
- * Twox2Color16DitherImage --
+ * ScaleColor16DitherImage --
  *
- *        Converts image into 16 bit color at double size.
+ *        Converts image into 16 bit color at a scale size.
  *
  * Results:
  *        None.
@@ -606,9 +606,9 @@
  * the horisontal doubling for free (almost).
  */
 
-void Twox2Color16DitherImageMod( unsigned char *lum, unsigned char *cr,
+void ScaleColor16DitherImageMod( unsigned char *lum, unsigned char *cr,
                                  unsigned char *cb, unsigned char *out,
-                                 int rows, int cols, int mod )
+                                 int rows, int cols, int mod, int scale )
 {
     unsigned int* row1 = (unsigned int*) out;
     const int next_row = cols+(mod/2);
@@ -618,13 +618,13 @@
     int cr_r;
     int crb_g;
     int cb_b;
-    int cols_2 = cols / 2;
+    int cols_2 = cols / scale;
 
     lum2 = lum + cols;
 
     mod = (next_row * 3) + (mod/2);
 
-    y = rows / 2;
+    y = rows / scale;
     while( y-- )
     {
         x = cols_2;
@@ -678,9 +678,9 @@
     }
 }
 
-void Twox2Color32DitherImageMod( unsigned char *lum, unsigned char *cr,
+void ScaleColor32DitherImageMod( unsigned char *lum, unsigned char *cr,
                                  unsigned char *cb, unsigned char *out,
-                                 int rows, int cols, int mod )
+                                 int rows, int cols, int mod, int scale )
 {
     unsigned int* row1 = (unsigned int*) out;
     const int next_row = cols*2+mod;
@@ -715,7 +715,7 @@
                                        (rgb_2_pix[ L + cr_r ] |
                                         rgb_2_pix[ L + crb_g ] |
                                         rgb_2_pix[ L + cb_b ]);
-            row1 += 2;
+            row1 += scale;
 
             L = L_tab[ (int) *lum++ ];
             row1[0] = row1[1] = row1[next_row] = row1[next_row+1] =
@@ -761,30 +761,30 @@
      framerate very much.  Optimization is better done in stream parsing.
  */
 #ifdef USE_INTERLACED_VIDEO
-void Twox2Color16DitherImageModInterlace( unsigned char *lum, unsigned char *cr,
-                                 unsigned char *cb, unsigned char *out,
-                                 int rows, int cols, int mod, int start )
+void ScaleColor16DitherImageModInterlace( unsigned char *lum, unsigned char *cr,
+					  unsigned char *cb, unsigned char *out,
+					  int rows, int cols, int mod, int start, int scale )
 {
     unsigned long* row1;
-    const int next_row = cols+(mod/2);
+    const int next_row = cols+(mod/scale);
     unsigned long* row2;
     unsigned char* lum2;
     int x, y;
     int cr_r;
     int crb_g;
     int cb_b;
-    int cols_2 = cols / 2;
+    int cols_2 = cols / scale;
 
     row1 = (unsigned long*) out;
     // Uncomment this to enable even-odd scanline rendering (looks terrible)
     //row1 += 2*start * next_row;
     //lum += start * cols;
-    row2 = row1 + 4*next_row;
-    lum2 = lum + 2*cols;
+    row2 = row1 + 2*scale*next_row;
+    lum2 = lum + scale*cols;
 
-    mod = ((cols + (mod/2)) * 3) + (mod/2);
+    mod = ((cols + (mod/scale)) * 3) + (mod/scale);
 
-    y = ((rows-2) / 2);
+    y = ((rows-2) / scale);
     while( y-- )
     {
         x = cols_2;
diff -u -N -r smpeg-0.3.3/video/MPEGvideo.cpp smpeg-cvs/video/MPEGvideo.cpp
--- smpeg-0.3.3/video/MPEGvideo.cpp	Fri Dec 24 00:59:56 1999
+++ smpeg-cvs/video/MPEGvideo.cpp	Sun Jan 30 10:28:25 2000
@@ -137,7 +137,7 @@
     _thread = NULL;
     _x = 0;
     _y = 0;
-    _double = false;
+    _scale = 1;
     _surf = NULL;
     _mutex = NULL;
     _stream = NULL;
@@ -191,7 +191,6 @@
 
     /* Get the time the playback started */
     mpeg->_stream->realTimeStart = ReadSysClock();
-    mpeg->play_time = 0.0;
 
     while( mpeg->playing )
     {
@@ -213,7 +212,7 @@
             }
         }
     }
-	return(0);
+    return(0);
 }
 
 void
@@ -255,6 +254,8 @@
 
     mpeg->reset_stream();
 
+    play_time = 0.0;
+
 #ifdef ANALYSIS 
     init_stats();
 #endif
@@ -402,9 +403,9 @@
 }
 
 void
-MPEGvideo:: DoubleDisplay( bool toggle )
+MPEGvideo:: ScaleDisplay( int scale )
 {
-    _double = toggle;
+    _scale = scale;
 }
 
 
diff -u -N -r smpeg-0.3.3/video/gdith.cpp smpeg-cvs/video/gdith.cpp
--- smpeg-0.3.3/video/gdith.cpp	Tue Dec 21 18:17:35 1999
+++ smpeg-cvs/video/gdith.cpp	Sat Jan 22 15:44:40 2000
@@ -430,33 +430,33 @@
     if ( mpeg->_mutex )
         SDL_mutexP( mpeg->_mutex );
 
-    if( mpeg->_double )
+    if( mpeg->_scale != 1 )
     {
 #ifdef USE_INTERLACED_VIDEO
         static int start = 1;
         if ( mpeg->_surf->format->BytesPerPixel == 2 ) {
-        	Twox2Color16DitherImageModInterlace( l, Cr, Cb, disp,
-                  vid_stream->v_size, vid_stream->h_size,
-                 (mpeg->_surf->pitch / 2) - (vid_stream->h_size * 2), start );
+	  ScaleColor16DitherImageModInterlace( l, Cr, Cb, disp,
+					       vid_stream->v_size, vid_stream->h_size,
+					       (mpeg->_surf->pitch / 2) - (vid_stream->h_size * mpeg->_scale), start, mpeg->_scale);
 	}
         start = !start;
 #else
         if ( mpeg->_surf->format->BytesPerPixel == 2 ) {
-            Twox2Color16DitherImageMod( l, Cr, Cb, disp,
-                  vid_stream->v_size, vid_stream->h_size,
-                 (mpeg->_surf->pitch / 2) - (vid_stream->h_size * 2) );
-        }
+            ScaleColor16DitherImageMod( l, Cr, Cb, disp,
+					vid_stream->v_size, vid_stream->h_size,
+					(mpeg->_surf->pitch / 2) - (vid_stream->h_size * mpeg->_scale), mpeg->_scale);
+        } else
         if ( mpeg->_surf->format->BytesPerPixel == 4 ) {
-            Twox2Color32DitherImageMod( l, Cr, Cb, disp,
-                  vid_stream->v_size, vid_stream->h_size,
-                 (mpeg->_surf->pitch / 4) - (vid_stream->h_size * 2) );
+            ScaleColor32DitherImageMod( l, Cr, Cb, disp,
+					vid_stream->v_size, vid_stream->h_size,
+					(mpeg->_surf->pitch / 4) - (vid_stream->h_size * mpeg->_scale), mpeg->_scale);
         }
 #endif
         if ( SDL_MUSTLOCK(mpeg->_surf) ) {
             SDL_UnlockSurface(mpeg->_surf);
         }
         mpeg->_callback( mpeg->_surf, mpeg->_x, mpeg->_y,
-                     vid_stream->h_size * 2, vid_stream->v_size * 2 );
+                     vid_stream->h_size * mpeg->_scale, vid_stream->v_size * mpeg->_scale );
     }
     else
     {
diff -u -N -r smpeg-0.3.3/video/proto.h smpeg-cvs/video/proto.h
--- smpeg-0.3.3/video/proto.h	Thu Oct 21 17:55:01 1999
+++ smpeg-cvs/video/proto.h	Sat Jan 22 15:44:40 2000
@@ -139,9 +139,9 @@
 void Color32DitherImageMod P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod ));
 void Color16DitherImageModInterlace P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod, int start ));
 void Color32DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int rows , int cols ));
-void Twox2Color16DitherImageMod P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod ));
-void Twox2Color32DitherImageMod P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod ));
-void Twox2Color16DitherImageModInterlace P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod, int start ));
+void ScaleColor16DitherImageMod P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod, int scale ));
+void ScaleColor32DitherImageMod P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod, int scale ));
+void ScaleColor16DitherImageModInterlace P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod, int start, int scale ));
 void Twox2Color32DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int rows , int cols ));
 
 /* ordered.c */
*************************************************************************
*** Applied ***
From: Laurent Bonnaud <Laurent.Bonnaud@inpg.fr>
Subject: Problems with crop table
Date: 25 Jan 2000 11:32:22 +0100

Hi,

some time ago, when you released the first versions of smpeg, I
reported a bug against the crop table which was too small for some
MPEG1 streams, and you increased its size.

With my recent tests, I found MPEG1 streams with crop values below
-3500 !  So I suggest this patch:

diff -rw smpeg-0.3.3.org/video/video.cpp smpeg-0.3.3/video/video.cpp
169c170
< #define MAX_NEG_CROP 2048
---
> #define MAX_NEG_CROP 4096


In order to get rid of the problem once and for all, I tried to replace
this table with an inline function.  With processors becoming always
faster than memory, I even observed a small speedup on my system (K6-2
and gcc -O2 -fstrict-aliasing with code optimization for K6).  Here is
my quick hack:

diff -rw smpeg-0.3.3.org/video/video.cpp smpeg-0.3.3/video/video.cpp
172a174,184
> inline unsigned char crop(int x)
> {
>   if(x<=0)
>     return 0;
>   if(x>=255)
>     return 255;
>   return x;
> }
> 
> //#define crop(x) cm[x]
> 
2176c2188
<       dest[0] = cm[sp[0]];
---
>       dest[0] = crop(sp[0]);
2178c2190
<       dest[1] = cm[sp[1]];
---
>       dest[1] = crop(sp[1]);
2180c2192
<       dest[2] = cm[sp[2]];
---
>       dest[2] = crop(sp[2]);
2182c2194
<       dest[3] = cm[sp[3]];
---
>       dest[3] = crop(sp[3]);
2184c2196
<       dest[4] = cm[sp[4]];
---
>       dest[4] = crop(sp[4]);
2186c2198
<       dest[5] = cm[sp[5]];
---
>       dest[5] = crop(sp[5]);
2188c2200
<       dest[6] = cm[sp[6]];
---
>       dest[6] = crop(sp[6]);
2190c2202
<       dest[7] = cm[sp[7]];
---
>       dest[7] = crop(sp[7]);
2194c2206
<       dest[0] = cm[sp[8]];
---
>       dest[0] = crop(sp[8]);
2196c2208
<       dest[1] = cm[sp[9]];
---
>       dest[1] = crop(sp[9]);
2198c2210
<       dest[2] = cm[sp[10]];
---
>       dest[2] = crop(sp[10]);
2200c2212
<       dest[3] = cm[sp[11]];
---
>       dest[3] = crop(sp[11]);
2202c2214
<       dest[4] = cm[sp[12]];
---
>       dest[4] = crop(sp[12]);
2204c2216
<       dest[5] = cm[sp[13]];
---
>       dest[5] = crop(sp[13]);
2206c2218
<       dest[6] = cm[sp[14]];
---
>       dest[6] = crop(sp[14]);
2208c2220
<       dest[7] = cm[sp[15]];
---
>       dest[7] = crop(sp[15]);
2497,2504c2509,2516
<           index[0] = cm[(int) rindex1[0] + (int) blockvals[0]];
<           index[1] = cm[(int) rindex1[1] + (int) blockvals[1]];
<           index[2] = cm[(int) rindex1[2] + (int) blockvals[2]];
<           index[3] = cm[(int) rindex1[3] + (int) blockvals[3]];
<           index[4] = cm[(int) rindex1[4] + (int) blockvals[4]];
<           index[5] = cm[(int) rindex1[5] + (int) blockvals[5]];
<           index[6] = cm[(int) rindex1[6] + (int) blockvals[6]];
<           index[7] = cm[(int) rindex1[7] + (int) blockvals[7]];
---
>           index[0] = crop((int) rindex1[0] + (int) blockvals[0]);
>           index[1] = crop((int) rindex1[1] + (int) blockvals[1]);
>           index[2] = crop((int) rindex1[2] + (int) blockvals[2]);
>           index[3] = crop((int) rindex1[3] + (int) blockvals[3]);
>           index[4] = crop((int) rindex1[4] + (int) blockvals[4]);
>           index[5] = crop((int) rindex1[5] + (int) blockvals[5]);
>           index[6] = crop((int) rindex1[6] + (int) blockvals[6]);
>           index[7] = crop((int) rindex1[7] + (int) blockvals[7]);
2508,2515c2520,2527
<           index[0] = cm[(int) rindex1[0] + (int) blockvals[8]];
<           index[1] = cm[(int) rindex1[1] + (int) blockvals[9]];
<           index[2] = cm[(int) rindex1[2] + (int) blockvals[10]];
<           index[3] = cm[(int) rindex1[3] + (int) blockvals[11]];
<           index[4] = cm[(int) rindex1[4] + (int) blockvals[12]];
<           index[5] = cm[(int) rindex1[5] + (int) blockvals[13]];
<           index[6] = cm[(int) rindex1[6] + (int) blockvals[14]];
<           index[7] = cm[(int) rindex1[7] + (int) blockvals[15]];
---
>           index[0] = crop((int) rindex1[0] + (int) blockvals[8]);
>           index[1] = crop((int) rindex1[1] + (int) blockvals[9]);
>           index[2] = crop((int) rindex1[2] + (int) blockvals[10]);
>           index[3] = crop((int) rindex1[3] + (int) blockvals[11]);
>           index[4] = crop((int) rindex1[4] + (int) blockvals[12]);
>           index[5] = crop((int) rindex1[5] + (int) blockvals[13]);
>           index[6] = crop((int) rindex1[6] + (int) blockvals[14]);
>           index[7] = crop((int) rindex1[7] + (int) blockvals[15]);
2595,2602c2607,2614
<             index[0] = cm[((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[0]];
<             index[1] = cm[((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[1]];
<             index[2] = cm[((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[2]];
<             index[3] = cm[((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[3]];
<             index[4] = cm[((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[4]];
<             index[5] = cm[((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[5]];
<             index[6] = cm[((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[6]];
<             index[7] = cm[((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[7]];
---
>             index[0] = crop(((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[0]);
>             index[1] = crop(((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[1]);
>             index[2] = crop(((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[2]);
>             index[3] = crop(((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[3]);
>             index[4] = crop(((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[4]);
>             index[5] = crop(((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[5]);
>             index[6] = crop(((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[6]);
>             index[7] = crop(((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[7]);
2607,2614c2619,2626
<             index[0] = cm[((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[8]];
<             index[1] = cm[((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[9]];
<             index[2] = cm[((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[10]];
<             index[3] = cm[((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[11]];
<             index[4] = cm[((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[12]];
<             index[5] = cm[((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[13]];
<             index[6] = cm[((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[14]];
<             index[7] = cm[((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[15]];
---
>             index[0] = crop(((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[8]);
>             index[1] = crop(((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[9]);
>             index[2] = crop(((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[10]);
>             index[3] = crop(((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[11]);
>             index[4] = crop(((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[12]);
>             index[5] = crop(((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[13]);
>             index[6] = crop(((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[14]);
>             index[7] = crop(((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[15]);
2640,2647c2652,2659
<             index[0] = cm[((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[0]];
<             index[1] = cm[((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[1]];
<             index[2] = cm[((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[2]];
<             index[3] = cm[((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[3]];
<             index[4] = cm[((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[4]];
<             index[5] = cm[((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[5]];
<             index[6] = cm[((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[6]];
<             index[7] = cm[((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[7]];
---
>             index[0] = crop(((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[0]);
>             index[1] = crop(((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[1]);
>             index[2] = crop(((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[2]);
>             index[3] = crop(((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[3]);
>             index[4] = crop(((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[4]);
>             index[5] = crop(((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[5]);
>             index[6] = crop(((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[6]);
>             index[7] = crop(((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[7]);
2654,2661c2666,2673
<             index[0] = cm[((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[8]];
<             index[1] = cm[((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[9]];
<             index[2] = cm[((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[10]];
<             index[3] = cm[((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[11]];
<             index[4] = cm[((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[12]];
<             index[5] = cm[((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[13]];
<             index[6] = cm[((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[14]];
<             index[7] = cm[((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[15]];
---
>             index[0] = crop(((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[8]);
>             index[1] = crop(((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[9]);
>             index[2] = crop(((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[10]);
>             index[3] = crop(((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[11]);
>             index[4] = crop(((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[12]);
>             index[5] = crop(((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[13]);
>             index[6] = crop(((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[14]);
>             index[7] = crop(((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[15]);
2970,2977c2982,2989
<           index[0] = cm[(int) rindex1[0] + (int) blockvals[0]];
<           index[1] = cm[(int) rindex1[1] + (int) blockvals[1]];
<           index[2] = cm[(int) rindex1[2] + (int) blockvals[2]];
<           index[3] = cm[(int) rindex1[3] + (int) blockvals[3]];
<           index[4] = cm[(int) rindex1[4] + (int) blockvals[4]];
<           index[5] = cm[(int) rindex1[5] + (int) blockvals[5]];
<           index[6] = cm[(int) rindex1[6] + (int) blockvals[6]];
<           index[7] = cm[(int) rindex1[7] + (int) blockvals[7]];
---
>           index[0] = crop((int) rindex1[0] + (int) blockvals[0]);
>           index[1] = crop((int) rindex1[1] + (int) blockvals[1]);
>           index[2] = crop((int) rindex1[2] + (int) blockvals[2]);
>           index[3] = crop((int) rindex1[3] + (int) blockvals[3]);
>           index[4] = crop((int) rindex1[4] + (int) blockvals[4]);
>           index[5] = crop((int) rindex1[5] + (int) blockvals[5]);
>           index[6] = crop((int) rindex1[6] + (int) blockvals[6]);
>           index[7] = crop((int) rindex1[7] + (int) blockvals[7]);
2981,2988c2993,3000
<           index[0] = cm[(int) rindex1[0] + (int) blockvals[8]];
<           index[1] = cm[(int) rindex1[1] + (int) blockvals[9]];
<           index[2] = cm[(int) rindex1[2] + (int) blockvals[10]];
<           index[3] = cm[(int) rindex1[3] + (int) blockvals[11]];
<           index[4] = cm[(int) rindex1[4] + (int) blockvals[12]];
<           index[5] = cm[(int) rindex1[5] + (int) blockvals[13]];
<           index[6] = cm[(int) rindex1[6] + (int) blockvals[14]];
<           index[7] = cm[(int) rindex1[7] + (int) blockvals[15]];
---
>           index[0] = crop((int) rindex1[0] + (int) blockvals[8]);
>           index[1] = crop((int) rindex1[1] + (int) blockvals[9]);
>           index[2] = crop((int) rindex1[2] + (int) blockvals[10]);
>           index[3] = crop((int) rindex1[3] + (int) blockvals[11]);
>           index[4] = crop((int) rindex1[4] + (int) blockvals[12]);
>           index[5] = crop((int) rindex1[5] + (int) blockvals[13]);
>           index[6] = crop((int) rindex1[6] + (int) blockvals[14]);
>           index[7] = crop((int) rindex1[7] + (int) blockvals[15]);
3064,3071c3076,3083
<             index[0] = cm[((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[0]];
<             index[1] = cm[((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[1]];
<             index[2] = cm[((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[2]];
<             index[3] = cm[((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[3]];
<             index[4] = cm[((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[4]];
<             index[5] = cm[((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[5]];
<             index[6] = cm[((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[6]];
<             index[7] = cm[((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[7]];
---
>             index[0] = crop(((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[0]);
>             index[1] = crop(((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[1]);
>             index[2] = crop(((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[2]);
>             index[3] = crop(((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[3]);
>             index[4] = crop(((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[4]);
>             index[5] = crop(((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[5]);
>             index[6] = crop(((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[6]);
>             index[7] = crop(((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[7]);
3076,3083c3088,3095
<             index[0] = cm[((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[8]];
<             index[1] = cm[((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[9]];
<             index[2] = cm[((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[10]];
<             index[3] = cm[((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[11]];
<             index[4] = cm[((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[12]];
<             index[5] = cm[((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[13]];
<             index[6] = cm[((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[14]];
<             index[7] = cm[((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[15]];
---
>             index[0] = crop(((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[8]);
>             index[1] = crop(((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[9]);
>             index[2] = crop(((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[10]);
>             index[3] = crop(((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[11]);
>             index[4] = crop(((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[12]);
>             index[5] = crop(((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[13]);
>             index[6] = crop(((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[14]);
>             index[7] = crop(((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[15]);
3109,3116c3121,3128
<             index[0] = cm[((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[0]];
<             index[1] = cm[((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[1]];
<             index[2] = cm[((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[2]];
<             index[3] = cm[((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[3]];
<             index[4] = cm[((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[4]];
<             index[5] = cm[((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[5]];
<             index[6] = cm[((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[6]];
<             index[7] = cm[((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[7]];
---
>             index[0] = crop(((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[0]);
>             index[1] = crop(((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[1]);
>             index[2] = crop(((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[2]);
>             index[3] = crop(((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[3]);
>             index[4] = crop(((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[4]);
>             index[5] = crop(((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[5]);
>             index[6] = crop(((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[6]);
>             index[7] = crop(((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[7]);
3123,3130c3135,3142
<             index[0] = cm[((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[8]];
<             index[1] = cm[((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[9]];
<             index[2] = cm[((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[10]];
<             index[3] = cm[((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[11]];
<             index[4] = cm[((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[12]];
<             index[5] = cm[((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[13]];
<             index[6] = cm[((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[14]];
<             index[7] = cm[((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[15]];
---
>             index[0] = crop(((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[8]);
>             index[1] = crop(((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[9]);
>             index[2] = crop(((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[10]);
>             index[3] = crop(((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[11]);
>             index[4] = crop(((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[12]);
>             index[5] = crop(((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[13]);
>             index[6] = crop(((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[14]);
>             index[7] = crop(((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[15]);
3403,3410c3415,3422
<       index[0] = cm[((int) (rindex1[0] + bindex1[0]) >> 1) + blockvals[0]];
<       index[1] = cm[((int) (rindex1[1] + bindex1[1]) >> 1) + blockvals[1]];
<       index[2] = cm[((int) (rindex1[2] + bindex1[2]) >> 1) + blockvals[2]];
<       index[3] = cm[((int) (rindex1[3] + bindex1[3]) >> 1) + blockvals[3]];
<       index[4] = cm[((int) (rindex1[4] + bindex1[4]) >> 1) + blockvals[4]];
<       index[5] = cm[((int) (rindex1[5] + bindex1[5]) >> 1) + blockvals[5]];
<       index[6] = cm[((int) (rindex1[6] + bindex1[6]) >> 1) + blockvals[6]];
<       index[7] = cm[((int) (rindex1[7] + bindex1[7]) >> 1) + blockvals[7]];
---
>       index[0] = crop(((int) (rindex1[0] + bindex1[0]) >> 1) + blockvals[0]);
>       index[1] = crop(((int) (rindex1[1] + bindex1[1]) >> 1) + blockvals[1]);
>       index[2] = crop(((int) (rindex1[2] + bindex1[2]) >> 1) + blockvals[2]);
>       index[3] = crop(((int) (rindex1[3] + bindex1[3]) >> 1) + blockvals[3]);
>       index[4] = crop(((int) (rindex1[4] + bindex1[4]) >> 1) + blockvals[4]);
>       index[5] = crop(((int) (rindex1[5] + bindex1[5]) >> 1) + blockvals[5]);
>       index[6] = crop(((int) (rindex1[6] + bindex1[6]) >> 1) + blockvals[6]);
>       index[7] = crop(((int) (rindex1[7] + bindex1[7]) >> 1) + blockvals[7]);
3415,3422c3427,3434
<       index[0] = cm[((int) (rindex1[0] + bindex1[0]) >> 1) + blockvals[8]];
<       index[1] = cm[((int) (rindex1[1] + bindex1[1]) >> 1) + blockvals[9]];
<       index[2] = cm[((int) (rindex1[2] + bindex1[2]) >> 1) + blockvals[10]];
<       index[3] = cm[((int) (rindex1[3] + bindex1[3]) >> 1) + blockvals[11]];
<       index[4] = cm[((int) (rindex1[4] + bindex1[4]) >> 1) + blockvals[12]];
<       index[5] = cm[((int) (rindex1[5] + bindex1[5]) >> 1) + blockvals[13]];
<       index[6] = cm[((int) (rindex1[6] + bindex1[6]) >> 1) + blockvals[14]];
<       index[7] = cm[((int) (rindex1[7] + bindex1[7]) >> 1) + blockvals[15]];
---
>       index[0] = crop(((int) (rindex1[0] + bindex1[0]) >> 1) + blockvals[8]);
>       index[1] = crop(((int) (rindex1[1] + bindex1[1]) >> 1) + blockvals[9]);
>       index[2] = crop(((int) (rindex1[2] + bindex1[2]) >> 1) + blockvals[10]);
>       index[3] = crop(((int) (rindex1[3] + bindex1[3]) >> 1) + blockvals[11]);
>       index[4] = crop(((int) (rindex1[4] + bindex1[4]) >> 1) + blockvals[12]);
>       index[5] = crop(((int) (rindex1[5] + bindex1[5]) >> 1) + blockvals[13]);
>       index[6] = crop(((int) (rindex1[6] + bindex1[6]) >> 1) + blockvals[14]);
>       index[7] = crop(((int) (rindex1[7] + bindex1[7]) >> 1) + blockvals[15]);

-- 
Laurent.
*************************************************************************
*** Applied ***
Date: Tue, 04 Jan 2000 00:48:34 +0100
From: Stefan Gybas <stefan@gybas.com>
Subject: Byte order detection patch for ARM architecture

Hi!

Jim Studt <jim@federated.com> submitted this patch for the SMPEG Debian
package so that the byte order on the ARM architecture will be properly
detected. This is also a fallback for other architectures in case the
other "#if defined ..." cases did not work.

-- 
Stefan Gybas

--- smpeg-0.3.2.orig/video/video.h
+++ smpeg-0.3.2/video/video.h
@@ -407,6 +407,18 @@
 #endif
 
 #if !defined(LITTLE_ENDIAN_ARCHITECTURE) && !defined(BIG_ENDIAN_ARCHITECTURE)
+#include </usr/include/endian.h>
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#undef  BIG_ENDIAN_ARCHITECTURE
+#define LITTLE_ENDIAN_ARCHITECTURE 1
+#endif
+#if __BYTE_ORDER == __BIG_ENDIAN
+#undef  LITTLE_ENDIAN_ARCHITECTURE
+#define BIG_ENDIAN_ARCHITECTURE 1
+#endif
+#endif
+
+#if !defined(LITTLE_ENDIAN_ARCHITECTURE) && !defined(BIG_ENDIAN_ARCHITECTURE)
 #error Unknown endianism of architecture
 #endif
 
*************************************************************************
*** Applied ***
From: C Hanish Menon <hanish@innomedia.soft.net>
Date: Fri, 10 Dec 1999 17:04:47 +0530
Subject: A patch to allow playing of mpeg files _having headers wrapped around them_

Hi

Recently I downloaded the smpeg source and tried it out.

We are also working on producing a MPEG player based on the Berkeley
mpeg code and mpg123 or Xaudio or so. Recently I was busy with some
other stuffs so I haven't looked into this much. We have tried to
integrate a MMX based DCT algo into the Berkely code. I or my friend
will get back to the list regarding this in a few days time. Till know
we were trying it only internaly.

As you people are also doing this and seem to have more info on
this.(Like we were basing most of the mpeg stream info and all based on
the available source code.) I am thinking of using smpeg source as the
base if possible. However I am interested in getting some of the
optimizations we did integrated into smpeg if possible. One of us will
get back to the list regarding this once we take a stock of what and all
we have done till now.


For now when I tried the smpeg code on certain files which had RIFF
header attached to them I found that the player didn't play them. I
didn't have the RIFF header structure immidiately at hand so I worked
out a _quick ugly fix_ which _never the less_ allows the player to play
these or any other mpeg file with some header structure warped on top of
it properly. It basically searchs the begining of the file for the id.



---------
Keep :-)
HanishKVC
http://hanishkvc.tripod.com/

--- smpeg-0.3.1/MPEG.h	Mon Nov  1 00:23:16 1999
+++ smpeg-0.3.1.new/MPEG.h	Fri Dec 10 15:31:25 1999
@@ -307,6 +307,8 @@
 #include <sys/mman.h>
 #include <fcntl.h>
 
+#define LENGTH_TO_CHECK_FOR_SYSTEM 0x50000	// Added by HanishKVC
+
 class MPEGfile : public MPEGerror,
                  public MPEGaudioaction, public MPEGvideoaction {
 public:
@@ -319,6 +321,11 @@
         Init(MPEG_fp, autoclose);
     }
     void Init(FILE *MPEG_fp, bool autoclose, bool sdlaudio = true) {
+	// Added by HanishKVC
+	Uint8 *pAreaToCheck;
+	long int iOffsetToMatch;
+        const Uint8 PACKET_START_CODE[] = { 0x00, 0x00, 0x01, 0xba };
+	// End of HanishKVC 
         /* Initialize everything to invalid values for cleanup */
         mpeg_fp = MPEG_fp;
         mpeg_area = (caddr_t)-1;
@@ -334,6 +341,56 @@
                 mpeg_size = statb.st_size;
                 mpeg_area = mmap(NULL, mpeg_size, PROT_READ, MAP_SHARED,
                                                      fileno(mpeg_fp), 0);
+		// Added by HanishKVC
+		if(memcmp(mpeg_area,PACKET_START_CODE,4) == 0)
+		{
+		  printf("DebugKVC: A Normal mpeg file\n");
+		}
+		else
+		{
+		  /*
+		  mpeg_area = mpeg_area+0x113e4;
+		  mpeg_size = mpeg_size-0x113e4;
+		  if(memcmp(mpeg_area,PACKET_START_CODE,4) == 0)
+		  {
+		    printf("DebugKVC: A RIFF format mpeg file\n");
+		  }
+		  else
+		  */
+		  printf("DebugKVC: A Not so normal mpeg file\n");
+		  iOffsetToMatch = pAreaToCheck = 0;
+		  while((pAreaToCheck = 
+			(Uint8*)memchr(mpeg_area+iOffsetToMatch,0xba,
+			LENGTH_TO_CHECK_FOR_SYSTEM-iOffsetToMatch)) != NULL)
+		  {
+		    pAreaToCheck = pAreaToCheck-3;
+		    iOffsetToMatch = pAreaToCheck-mpeg_area;
+		    printf("DebugKVC: Possible Location %x\n",iOffsetToMatch);
+		    if(memcmp(pAreaToCheck,PACKET_START_CODE,4) == 0)
+		    {
+		      printf("DebugKVC: System stream found\n");
+		      mpeg_size = mpeg_size-iOffsetToMatch;
+		      mpeg_area = pAreaToCheck;
+		      break;
+		    }
+		    else
+		    {
+		      printf("DebugKVC: Sorry spurious match\n");
+		      iOffsetToMatch = iOffsetToMatch+4; 
+		      // Actually I can skip 3 more chars as 0xba is not there 
+		      // anywhere else in the PACKET_START_CODE. I may be able
+		      // to do more optimizations to search, but as this search
+		      // occurs only once at the begining and that to in a small
+		      // data space, I think this dumb way should be sufficient.
+		    }
+		  } // of while
+		  if(pAreaToCheck == NULL)
+		  {
+		    printf("DebugKVC: Sorry no system stream\n");
+		    exit(1);
+		  }
+		}
+		// End of HanishKVC
                 if ( mpeg_area != (caddr_t)-1 ) {
                     mpeg = new MPEG((Uint8 *)mpeg_area, mpeg_size, 0, sdlaudio);
                     if ( mpeg->WasError() ) {
*************************************************************************
*** Applied ***
Subject: A little patch for smpeg
Date: Tue, 12 Oct 1999 23:11:05 -0500 (CDT)
From: Moses DeJong <dejong@cs.umn.edu>
To: smpeg@lokigames.com


When run with no arguments, smpeg really should print the usage
message out. Here is a quick little patch to 0.2.7 to do just that.


--- copy_plaympeg.c     Tue Oct 12 20:30:27 1999
+++ plaympeg.c  Tue Oct 12 20:33:21 1999
@@ -99,6 +99,11 @@
             fprintf(stderr, "Warning: Unknown option: %s\n", argv[i]);
         }
     }
+    /* If there were no arguments just print the usage */
+    if (argc == 1) {
+        usage(argv[0]);
+        exit(0);
+     }

     /* Play the mpeg files! */
     for ( ; argv[i]; ++i ) {

Thanks
Mo DeJong

*************************************************************************
*** Not applied ***
--- smpeg-0.2.7elgaard.patch ---
# This is a patch for smpeg-0.2.7 to update it to smpeg-0.2.7elgaard
# 
# To apply this patch:
# STEP 1: Chdir to the source directory.
# STEP 2: Run the 'applypatch' program with this patch file as input.
#
# If you do not have 'applypatch', it is part of the 'makepatch' package
# that you can fetch from the Comprehensive Perl Archive Network:
# http://www.perl.com/CPAN/authors/Johan_Vromans/makepatch-x.y.tar.gz
# In the above URL, 'x' should be 2 or higher.
#
# To apply this patch without the use of 'applypatch':
# STEP 1: Chdir to the source directory.
# STEP 2: Run the 'patch' program with this file as input.
#
#### End of Preamble ####

#### Patch data follows ####
diff -c 'smpeg-0.2.7/MPEGaudio.h' 'smpeg-0.2.7elgaard/MPEGaudio.h'
Index: ./MPEGaudio.h
*** ./MPEGaudio.h	Fri Aug  6 23:33:11 1999
--- ./MPEGaudio.h	Sat Oct  9 02:51:34 1999
***************
*** 32,38 ****
  #ifdef THREADED_AUDIO
  #include "MPEGring.h"
  #endif
- 
  /* MPEG/WAVE Sound library
  
     (C) 1997 by Woo-jae Jung */
--- 32,37 ----
***************
*** 208,219 ****
  public:
    void setforcetomono(bool flag);
    void setdownfrequency(int value);
- 
    /******************************/
    /* Frame management variables */
    /******************************/
  private:
!   int decodedframe,currentframe,totalframe;
  
    /***************************************/
    /* Variables made by MPEG-Audio header */
--- 207,217 ----
  public:
    void setforcetomono(bool flag);
    void setdownfrequency(int value);
    /******************************/
    /* Frame management variables */
    /******************************/
  private:
!   int decodedframe,totalframe;
  
    /***************************************/
    /* Variables made by MPEG-Audio header */
diff -c 'smpeg-0.2.7/audio/MPEGaudio.cpp' 'smpeg-0.2.7elgaard/audio/MPEGaudio.cpp'
Index: ./audio/MPEGaudio.cpp
*** ./audio/MPEGaudio.cpp	Fri Aug  6 23:33:11 1999
--- ./audio/MPEGaudio.cpp	Sat Oct  9 02:38:47 1999
***************
*** 18,30 ****
  */
  
  /* A class based on the MPEG stream class, used to parse and play audio */
- 
  #include "MPEGaudio.h"
  
  #ifdef SDL_MIXER             /* From the SDL mixer example library */
  #include "mixer.h"
  #endif
- 
  
  MPEGaudio:: MPEGaudio(MPEGstream *stream)
  {
--- 18,29 ----
  */
  
  /* A class based on the MPEG stream class, used to parse and play audio */
  #include "MPEGaudio.h"
+ extern  int currentframe;
  
  #ifdef SDL_MIXER             /* From the SDL mixer example library */
  #include "mixer.h"
  #endif
  
  MPEGaudio:: MPEGaudio(MPEGstream *stream)
  {
diff -c 'smpeg-0.2.7/audio/mpegtoraw.cpp' 'smpeg-0.2.7elgaard/audio/mpegtoraw.cpp'
Index: ./audio/mpegtoraw.cpp
*** ./audio/mpegtoraw.cpp	Fri Aug  6 23:33:11 1999
--- ./audio/mpegtoraw.cpp	Sat Oct  9 02:55:58 1999
***************
*** 8,14 ****
  #ifdef HAVE_CONFIG_H
  #include "config.h"
  #endif
! 
  #include <math.h>
  #include <stdlib.h>
  #include <string.h>
--- 8,15 ----
  #ifdef HAVE_CONFIG_H
  #include "config.h"
  #endif
! extern int currentframe;
! extern float audioFPS;
  #include <math.h>
  #include <stdlib.h>
  #include <string.h>
***************
*** 161,166 ****
--- 162,168 ----
      c &= 0xf;
      protection = c & 1;
      layer = 4 - ((c >> 1) & 3);
+ 
      version = (_mpegversion) ((c >> 3) ^ 1);
  
      c = mpeg->copy_byte() >> 1;
***************
*** 241,246 ****
--- 243,249 ----
  	                     -(protection?0:2)
  	                     -4;
      }
+     audioFPS = 1000.0*bitrate[version][layer-1][bitrateindex]/framesize/8.0;
    }
  
    /* Fill the buffer with new data */
***************
*** 258,263 ****
--- 261,267 ----
  
  bool MPEGaudio::run( int frames )
  {
+   printf("frames=%d\n", frames);
      for( ; frames; frames-- )
      {
          if( loadheader() == false ) {
***************
*** 326,332 ****
              len = 0;
          } else {
              SDL_MixAudio(stream, rbuf, copylen, volume);
!             ++audio->currentframe;
              audio->ring->ReadDone();
  //fprintf(stderr, "-");
              len -= copylen;
--- 330,336 ----
              len = 0;
          } else {
              SDL_MixAudio(stream, rbuf, copylen, volume);
!             ++currentframe;
              audio->ring->ReadDone();
  //fprintf(stderr, "-");
              len -= copylen;
***************
*** 357,362 ****
--- 361,368 ----
      audio->rawdata = (Sint16 *)stream;
      audio->rawdatawriteoffset = 0;
      audio->run(len/audio->samplesperframe);
+     printf("len = %d, samplesperframe=%d\n", len , samplesperframe);
+ 
      len -= audio->rawdatawriteoffset;
      stream += audio->rawdatawriteoffset*2;
  
diff -c 'smpeg-0.2.7/plaympeg.c' 'smpeg-0.2.7elgaard/plaympeg.c'
Index: ./plaympeg.c
*** ./plaympeg.c	Fri Aug  6 23:33:12 1999
--- ./plaympeg.c	Sat Oct  9 03:10:13 1999
***************
*** 22,27 ****
--- 22,28 ----
  
  #include "smpeg.h"
  
+ 
  void usage(char *argv0)
  {
      printf(
diff -c 'smpeg-0.2.7/video/gdith.cpp' 'smpeg-0.2.7elgaard/video/gdith.cpp'
Index: ./video/gdith.cpp
*** ./video/gdith.cpp	Thu Jul 15 20:39:57 1999
--- ./video/gdith.cpp	Sat Oct  9 02:38:47 1999
***************
*** 91,96 ****
--- 91,98 ----
  
  /* Frame Rate Info */
  extern int framerate;
+ extern float audioFPS;
+ extern int currentframe; //elgaard, audio
  
  /* Video rates table */
  /* Cheat on Vid rates, round to 30, and use 30 if illegal value 
***************
*** 276,283 ****
  #define SLOW_START_INCREMENT    0.3
  
  /* Define this to debug the frame scheduler */
! //#define DEBUG_MPEG_SCHEDULING
! 
  
  int timeSync( VidStream* vid_stream )
  {
--- 278,284 ----
  #define SLOW_START_INCREMENT    0.3
  
  /* Define this to debug the frame scheduler */
! #define DEBUG_MPEG_SCHEDULING // elgaard
  
  int timeSync( VidStream* vid_stream )
  {
***************
*** 309,317 ****
              vid_stream->rate_deal = framerate;
              break;
          }
          if ( vid_stream->rate_deal ) {
              vid_stream->_oneFrameTime = 1.0 / vid_stream->rate_deal;
!             vid_stream->_oneFrameTime *= 1.004;  /* Experimental */
  //printf( "One frame time %f, %d fps\n", vid_stream->_oneFrameTime, vid_stream->rate_deal );
          }
      }
--- 310,319 ----
              vid_stream->rate_deal = framerate;
              break;
          }
+         //vid_stream->rate_deal = vid_stream->rate_deal - (vid_stream->totNumFrames - currentframe);
          if ( vid_stream->rate_deal ) {
              vid_stream->_oneFrameTime = 1.0 / vid_stream->rate_deal;
!             //          vid_stream->_oneFrameTime *= 1.004;  /* Experimental */
  //printf( "One frame time %f, %d fps\n", vid_stream->_oneFrameTime, vid_stream->rate_deal );
          }
      }
***************
*** 331,346 ****
          double time_behind;
  
          /* Calculate the frame time relative to real time */
!         time_behind = ReadSysClock() - vid_stream->_nowFrameTime;
! 
  #ifdef DEBUG_MPEG_SCHEDULING
! //printf("Frame %d: frame time: %f, real time: %f, time behind: %f\n", vid_stream->totNumFrames, vid_stream->_nowFrameTime, ReadSysClock(), time_behind);
  #endif
  
          /* Allow up to MAX_FUDGE_TIME of delay in output */
          if ( time_behind < -TIMESLICE ) {
              time_behind = -time_behind;
!             vid_stream->_skipCount = 0;
  #ifdef DEBUG_MPEG_SCHEDULING
  printf("Ahead!  Sleeping %f\n", time_behind-TIMESLICE);
  #endif
--- 333,351 ----
          double time_behind;
  
          /* Calculate the frame time relative to real time */
! 	//        time_behind = ReadSysClock() - vid_stream->_nowFrameTime;
! 	//        time_behind = -(vid_stream->totNumFrames - currentframe) *vid_stream->_oneFrameTime;	
!         time_behind = -(vid_stream->totNumFrames*audioFPS - (int)((float)currentframe*vid_stream->rate_deal)) *vid_stream->_oneFrameTime/vid_stream->rate_deal;
  #ifdef DEBUG_MPEG_SCHEDULING
! printf("Frame %d/%d: frame time: %f, real time: %f, time behind: %f\n", vid_stream->totNumFrames, currentframe,vid_stream->_nowFrameTime, ReadSysClock(), time_behind);
  #endif
  
          /* Allow up to MAX_FUDGE_TIME of delay in output */
          if ( time_behind < -TIMESLICE ) {
              time_behind = -time_behind;
!             vid_stream->_skipCount = 0; //vid_stream->totNumFrames - currentframe ;
!             // elgaard
!             //vid_stream->_skipCount = 0;
  #ifdef DEBUG_MPEG_SCHEDULING
  printf("Ahead!  Sleeping %f\n", time_behind-TIMESLICE);
  #endif
***************
*** 370,375 ****
--- 375,381 ----
  printf("Way too far behind, losing time sync...\n");
  #endif
  #if 0 // This results in smoother video, but sync's terribly on slow machines
+ // elgaard, was 0
                  vid_stream->_nowFrameTime = ReadSysClock() - (MAX_FUDGE_TIME*2);
  #endif
              }
diff -c 'smpeg-0.2.7/video/video.cpp' 'smpeg-0.2.7elgaard/video/video.cpp'
Index: ./video/video.cpp
*** ./video/video.cpp	Tue Jun 22 23:50:44 1999
--- ./video/video.cpp	Sat Oct  9 02:38:47 1999
***************
*** 175,180 ****
--- 175,182 ----
    if ANALYSIS has been defined.
  */
  
+ int  currentframe;
+ float audioFPS=40.0;
  #ifdef ANALYSIS
  
  
#### End of Patch data ####

#### ApplyPatch data follows ####
# Data version        : 1.0
# Date generated      : Sat Oct  9 03:11:25 1999
# Generated by        : makepatch 2.00
# Recurse directories : Yes
# Excluded files      : (\A|/)Makefile\Z
#                       (\A|/)GNUmake\Z
# p 'MPEGaudio.h' 10062 939430294 0100644
# p 'audio/MPEGaudio.cpp' 5805 939429527 0100644
# p 'audio/mpegtoraw.cpp' 8373 939430558 0100644
# p 'plaympeg.c' 5111 939431413 0100644
# p 'video/gdith.cpp' 16046 939429527 0100644
# p 'video/video.cpp' 125492 939429527 0100644
#### End of ApplyPatch data ####

#### End of Patch kit [created: Sat Oct  9 03:11:25 1999] ####
#### Checksum: 320 9807 48717 ####
