--- configure.in	(/mirror/xmoto)	(revision 1620)
+++ configure.in	(/rpl2mpg)	(revision 1620)
@@ -12,6 +12,7 @@
 AC_CHECK_LIB(png, png_read_image, [], [AC_MSG_ERROR(libpng required)])
 AC_CHECK_LIB(z, uncompress, [], [AC_MSG_ERROR(zlib required)])
 AM_PATH_SDL(1.0.0, [], [AC_MSG_ERROR(SDL required)])
+AM_PATH_FFMPEG([], [], [AC_MSG_ERROR(FFMPEG required)])
 AC_CHECK_LIB(SDL_mixer, Mix_OpenAudio, [], [AC_MSG_ERROR(SDL_mixer required)])
 AX_CHECK_GL()
 
--- src/Video.h	(/mirror/xmoto)	(revision 1620)
+++ src/Video.h	(/rpl2mpg)	(revision 1620)
@@ -0,0 +1,45 @@
+
+#ifndef __VIDEO_H__
+#define __VIDEO_H__
+#include <avformat.h>
+#include <string>
+
+namespace vapp {
+  class GameApp;
+
+  class Video {
+    public:
+      Video();
+      virtual ~Video();
+      void close();
+      void writeFrame();
+      void initVideo(std::string output, int fps, GameApp *theGame);
+
+    private:
+      AVOutputFormat *format;
+      AVFormatContext *context;
+      AVStream *videoStream;
+      AVFrame *rgbFrame;
+      AVFrame *yuvFrame;
+      GameApp *game;
+      bool open;
+      char *fileName;
+      int framesPerSec;
+      uint8_t *videoOutbuf;
+      int videoOutbufSize;
+      int frameCount;
+
+      /* Helper functions */
+      void _initVideoStream();
+      void _addVideoStream();
+
+      void _endVideoStream();
+
+      AVFrame *_allocPicture(int pix_fmt, int width, int height);
+
+      void _getCurrentScreen(AVCodecContext *c);
+    
+  };
+};
+	
+#endif
--- src/Game.h	(/mirror/xmoto)	(revision 1620)
+++ src/Game.h	(/rpl2mpg)	(revision 1620)
@@ -34,6 +34,7 @@
 #include "PlayerData.h"
 #include "Sound.h"
 #include "Input.h"
+#include "Video.h"
 
 namespace vapp {
 
@@ -249,6 +250,9 @@
       void _SimpleMessage(const std::string &Msg);
       
       int _IsKeyInUse(const std::string &Key);
+
+      Video m_VideoRecorder;
+      std::string m_VideoName;
   };
 
 };
--- src/VApp.cpp	(/mirror/xmoto)	(revision 1620)
+++ src/VApp.cpp	(/rpl2mpg)	(revision 1620)
@@ -595,9 +595,10 @@
       }
     }
     
+    m_bWindowed = true;
+    m_bCmdWindowed = true;
     /* Pass any arguments to the user app */
-    if(UserArgs.size() > 0)
-      parseUserArgs(UserArgs);
+    parseUserArgs(UserArgs);
   }
 
 };
--- src/Video.cpp	(/mirror/xmoto)	(revision 1620)
+++ src/Video.cpp	(/rpl2mpg)	(revision 1620)
@@ -0,0 +1,272 @@
+#include "Video.h"
+#include "Game.h"
+#include "Image.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+namespace vapp {
+
+Video::Video() {
+  open = false;
+}
+
+Video::~Video() {
+  this->close();
+}
+
+void Video::initVideo(std::string output, int fps, GameApp *theGame) {
+  if (open) return;
+
+  game = theGame;
+  open = true;
+  fileName = strdup(output.c_str());
+  framesPerSec = fps;
+  Log("Our fps is %d", fps);
+  frameCount = 0;
+
+  av_register_all();
+
+  format = guess_format(NULL, fileName, NULL);
+  if (!format) {
+    Log("Could not deduce output format from file extension: using MPEG.\n");
+    format = guess_format("mpeg", NULL, NULL);
+  }
+  if (!format) {
+    throw Exception("No suitable output format.");
+  }
+
+  /* allocate the output media context */
+  context = av_alloc_format_context();
+  if (!context) {
+    throw Exception("Couldn't allocate format context.");
+  }
+  context->oformat = format;
+  snprintf(context->filename, sizeof(context->filename), "%s", fileName);
+
+  /* add the audio and video streams using the default format codecs
+  and initialize the codecs */
+  videoStream = NULL;
+  if (format->video_codec != CODEC_ID_NONE) {
+    _addVideoStream();
+  }
+
+  /* set the output parameters (must be done even if no
+  parameters). */
+  if (av_set_parameters(context, NULL) < 0) {
+    throw Exception("Invalid output format parameters");
+  }
+
+  dump_format(context, 0, fileName, 1);
+
+  /* now that all the parameters are set, we can open the audio and
+  video codecs and allocate the necessary encode buffers */
+  if (videoStream)
+    _initVideoStream();
+
+  /* open the output file, if needed */
+  if (!(format->flags & AVFMT_NOFILE)) {
+    if (url_fopen(&context->pb, fileName, URL_WRONLY) < 0) {
+      throw Exception("Couldn't open output file");
+    }
+  }
+
+  /* write the stream header, if any */
+  av_write_header(context);
+
+}
+
+void Video::_addVideoStream() {
+  AVCodecContext *c;
+
+  videoStream = av_new_stream(context, 0);
+  if (!videoStream) {
+    throw Exception("Could not alloc stream");
+  }
+
+  c = videoStream->codec;
+  c->codec_id = (CodecID)format->video_codec;;
+  c->codec_type = CODEC_TYPE_VIDEO;
+
+  /* put sample parameters */
+  c->bit_rate = 400000;
+
+  /* resolution must be a multiple of two */
+  c->width = game->getDispWidth();
+  c->height = game->getDispHeight();
+
+  /* time base: this is the fundamental unit of time (in seconds) in terms
+  of which frame timestamps are represented. for fixed-fps content,
+  timebase should be 1/framerate and timestamp increments should be
+  identically 1. */
+  c->time_base.den = framesPerSec;
+  c->time_base.num = 1;
+  c->gop_size = 12; /* emit one intra frame every twelve frames at most */
+  c->pix_fmt = PIX_FMT_YUV420P;
+
+  // some formats want stream headers to be seperate
+  if(!strcmp(context->oformat->name, "mp4") || 
+     !strcmp(context->oformat->name, "mov") || 
+     !strcmp(context->oformat->name, "3gp"))
+    c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+}
+
+void Video::_initVideoStream() {
+  AVCodec *codec;
+  AVCodecContext *c;
+
+  c = videoStream->codec;
+
+  /* find the video encoder */
+  codec = avcodec_find_encoder(c->codec_id);
+  if (!codec) {
+    fprintf(stderr, "codec not found\n");
+    exit(1);
+  }
+
+  /* open the codec */
+  if (avcodec_open(c, codec) < 0) {
+    fprintf(stderr, "could not open codec\n");
+    exit(1);
+  }
+
+  videoOutbuf = NULL;
+  if (!(context->oformat->flags & AVFMT_RAWPICTURE)) {
+    /* allocate output buffer */
+    /* XXX: API change will be done */
+    videoOutbufSize = 200000;
+    videoOutbuf = (uint8_t *)malloc(videoOutbufSize);
+  }
+
+  yuvFrame = _allocPicture(c->pix_fmt, c->width, c->height);
+  rgbFrame = _allocPicture(PIX_FMT_RGB24, c->width, c->height);
+
+  if (!yuvFrame || !rgbFrame) {
+    throw Exception("Couldn't allocate AVFrame's :(");
+  }
+}
+
+void Video::writeFrame() {
+  int out_size, ret;
+  AVCodecContext *c;
+
+  c = videoStream->codec;
+
+  _getCurrentScreen(c);
+
+  if (context->oformat->flags & AVFMT_RAWPICTURE) {
+    /* raw video case. The API will change slightly in the near
+    futur for that */
+    AVPacket pkt;
+    av_init_packet(&pkt);
+
+    pkt.flags |= PKT_FLAG_KEY;
+    pkt.stream_index= videoStream->index;
+    pkt.data= (uint8_t *)yuvFrame;
+    pkt.size= sizeof(AVPicture);
+
+    ret = av_write_frame(context, &pkt);
+  } else {
+    /* encode the image */
+    out_size = avcodec_encode_video(c, videoOutbuf, videoOutbufSize, yuvFrame);
+    /* if zero size, it means the image was buffered */
+    if (out_size > 0) {
+      AVPacket pkt;
+      av_init_packet(&pkt);
+
+      pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, videoStream->time_base);
+      if(c->coded_frame->key_frame)
+        pkt.flags |= PKT_FLAG_KEY;
+      pkt.stream_index= videoStream->index;
+      pkt.data= videoOutbuf;
+      pkt.size= out_size;
+
+      /* write the compressed frame in the media file */
+      ret = av_write_frame(context, &pkt);
+    } else {
+      ret = 0;
+    }
+  }
+  if (ret != 0) {
+    throw Exception("Error while writing video frame");
+  }
+  frameCount++;
+}
+
+AVFrame *Video::_allocPicture(int pix_fmt, int width, int height) {
+  AVFrame *picture;
+  uint8_t *picture_buf;
+  int size;
+
+  picture = avcodec_alloc_frame();
+  if (!picture)
+    return NULL;
+  size = avpicture_get_size(pix_fmt, width, height);
+  picture_buf = (uint8_t *)malloc(size);
+  if (!picture_buf) {
+    av_free(picture);
+    return NULL;
+  }
+  avpicture_fill((AVPicture *)picture, picture_buf,
+                 pix_fmt, width, height);
+  return picture;
+}
+
+void Video::_getCurrentScreen(AVCodecContext *c) {
+  Img *img;
+  unsigned char *x;
+  int size;
+
+  img = game->grabScreen();
+
+  if (!img) {
+    throw Exception("Couldn't get screen image.");
+  }
+
+  x = img->convertToRGB24();
+  size = img->getWidth() * img->getHeight() * 3;
+  memcpy(rgbFrame->data[0], x, size);
+  delete x;
+  delete img;
+
+  img_convert((AVPicture *)yuvFrame, c->pix_fmt,
+    (AVPicture *)rgbFrame, PIX_FMT_RGB24,
+    c->width, c->height);
+}
+
+void Video::_endVideoStream() {
+  avcodec_close(videoStream->codec);
+  av_free(rgbFrame->data[0]);
+  av_free(rgbFrame);
+  av_free(yuvFrame->data[0]);
+  av_free(yuvFrame);
+  av_free(videoOutbuf);
+}
+
+void Video::close(void) {
+  int i;
+  if (!open) return;
+
+  open = false;
+
+  _endVideoStream();;
+
+  /* write the trailer, if any */
+  av_write_trailer(context);
+
+  /* free the streams */
+  for(i = 0; i < context->nb_streams; i++) {
+    av_freep(&context->streams[i]);
+  }
+
+  if (!(format->flags & AVFMT_NOFILE)) {
+    /* close the output file */
+    url_fclose(&context->pb);
+  }
+
+  /* free the stream */
+  av_free(context);
+}
+
+};
--- src/Game.cpp	(/mirror/xmoto)	(revision 1620)
+++ src/Game.cpp	(/rpl2mpg)	(revision 1620)
@@ -532,6 +532,7 @@
     else if(m_PlaySpecificReplay != "") {
       /* ======= PLAY SPECIFIC REPLAY ======= */
       setState(GS_REPLAYING);
+      m_VideoRecorder.initVideo(m_VideoName, (int)m_fCurrentReplayFrameRate*2, this);
     }
     else {
       /* Graphics? */
@@ -547,6 +548,7 @@
         setState(GS_MENU);
       }
     }            
+
   }
 
   /*===========================================================================
@@ -759,6 +761,7 @@
                 if(m_pReplay->didFinish()) {
                   /* Make sure that it's the same finish time */
                   m_MotoGame.setTime(m_pReplay->getFinishTime());
+                  quit();
                 }
               }
             }
@@ -840,6 +843,8 @@
       	  }
         }
 
+        m_VideoRecorder.writeFrame();
+
         /* Show fps (debug modish) */
         if(m_bDebugMode) {
           static char cBuf[256] = ""; 
@@ -914,6 +919,8 @@
   Shutdown game
   ===========================================================================*/
   void GameApp::userShutdown(void) {  
+    m_VideoRecorder.close();
+
     if(!isNoGraphics()) {
       m_Renderer.unprepareForNewLevel(); /* just to be sure, shutdown can happen quite hard */
       
@@ -1177,68 +1184,35 @@
   void GameApp::parseUserArgs(std::vector<std::string> &UserArgs) {
     /* Look through them... */
     for(int i=0;i<UserArgs.size();i++) {
-      if(UserArgs[i] == "-replay") {
-        if(i+1<UserArgs.size()) {
-          m_PlaySpecificReplay = UserArgs[i+1];
-        }
-        else
-          throw SyntaxError("no replay specified");        
-        i++;
-      }
-      else if(UserArgs[i] == "-level") {
-        if(i+1<UserArgs.size()) {
-          m_PlaySpecificLevel = UserArgs[i+1];
-          
-          /* If it is a plain number, it's for a internal level */
-          int nNum = atoi(m_PlaySpecificLevel.c_str());
-          if(nNum > 0) {
-            char cBuf[256];
-            sprintf(cBuf,"_iL%02d_",nNum-1);
-            m_PlaySpecificLevel = cBuf;
-          }
-        }
-        else
-          throw SyntaxError("no level specified");        
-        i++;
-      }
-      else if(UserArgs[i] == "-debug") {
+      if(UserArgs[i] == "-debug") {
         m_bDebugMode = true;
       }
-      else if(UserArgs[i] == "-profile") {
-        if(i+1<UserArgs.size())
-          m_ForceProfile = UserArgs[++i];
-        else
-          throw SyntaxError("no profile specified");        
-        i++;
-      }
-      else if(UserArgs[i] == "-gdebug") {
-        if(i+1<UserArgs.size())
-          m_GraphDebugInfoFile = UserArgs[++i];
-        else
-          throw SyntaxError("no debug file specified");        
-        i++;
-      }      
-      else if(UserArgs[i] == "-listlevels") {
-        m_bListLevels = true;
-        setNoGraphics(true);
-      }
       else if(UserArgs[i] == "-listreplays") {
         m_bListReplays = true;
         setNoGraphics(true);
       }
-      else if(UserArgs[i] == "-timedemo") {
-        m_bTimeDemo = true;
-      }
       else if(UserArgs[i] == "-fps") {
         m_bShowFrameRate = true;
       }
       else if(UserArgs[i] == "-ugly") {
-				m_bUglyMode = true;
+        m_bUglyMode = true;
       }
       else if(UserArgs[i] == "-benchmark") {
-				m_bBenchmark = true;
+        m_bBenchmark = true;
+      } else {
+        if (m_PlaySpecificReplay == "") {
+          m_PlaySpecificReplay = UserArgs[i];
+        } else if (m_VideoName == "") {
+          m_VideoName = UserArgs[i];
+        }
       }
     }
+    if (m_PlaySpecificReplay == "") {
+      throw SyntaxError("no replay specified");        
+    }
+    if (m_VideoName == "") {
+      throw SyntaxError("No output video specified");
+    }
   }
 
   /*===========================================================================
--- config/ffmpeg.m4	(/mirror/xmoto)	(revision 1620)
+++ config/ffmpeg.m4	(/rpl2mpg)	(revision 1620)
@@ -0,0 +1,35 @@
+# Configure paths for FFMPEG 
+# 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_FFMPEG([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for FFMPEG, and define FFMPEG_CFLAGS and FFMPEG_LIBS
+dnl
+AC_DEFUN([AM_PATH_FFMPEG],
+[dnl 
+dnl Get the cflags and libraries from the sdl-config script
+dnl
+AC_ARG_WITH(ffmpeg-config,[  --with-ffmpeg-config=CONFIG  Path to ffmpeg-config (autodetected in PATH)],
+            ffmpeg_config="$withval", ffmpeg_config="ffmpeg-config")
+
+  AC_MSG_CHECKING(for ffmpeg-config)
+  AC_REQUIRE([AC_CANONICAL_TARGET])
+  AC_PATH_PROG(FFMPEG_CONFIG, $ffmpeg_config, no, [$PATH])
+
+  if test "$FFMPEG_CONFIG" = "no" ; then
+    echo "Can't find ffmpeg-config"
+    AC_MSG_RESULT(no)
+    ifelse([$3], , :, [$3])
+  else
+    AC_MSG_RESULT(yes)
+    ifelse([$2], , :, [$2])
+  fi
+
+  FFMPEG_CFLAGS=`$FFMPEG_CONFIG --cflags`
+  FFMPEG_LIBS=`$FFMPEG_CONFIG --libs avformat`
+  AC_SUBST(FFMPEG_CFLAGS)
+  AC_SUBST(FFMPEG_LIBS)
+])
--- Makefile.am	(/mirror/xmoto)	(revision 1620)
+++ Makefile.am	(/rpl2mpg)	(revision 1620)
@@ -1,5 +1,5 @@
-AM_CXXFLAGS = -DNOMMGR -w -DGAMEDATADIR=\"$(datadir)/@PACKAGE@\" $(GL_CFLAGS)
-AM_CFLAGS = -DNOMMGR -w -DGAMEDATADIR=\"$(datadir)/@PACKAGE@\" $(GL_CFLAGS)
+AM_CXXFLAGS = -DNOMMGR -w -DGAMEDATADIR=\"$(datadir)/@PACKAGE@\" $(GL_CFLAGS) $(FFMPEG_CFLAGS)
+AM_CFLAGS = -DNOMMGR -w -DGAMEDATADIR=\"$(datadir)/@PACKAGE@\" $(GL_CFLAGS) $(FFMPEG_CFLAGS)
 
 image_SOURCES = src/image/tim.cpp src/image/tim_io_stdio.cpp \
 	src/image/tim_jpeg.cpp src/image/tim_memory_crt.cpp \
@@ -21,7 +21,7 @@
 	src/DBuffer.cpp \
 	src/DBuffer.h
 
-common_LDADD = $(GL_LIBS)
+common_LDADD = $(GL_LIBS) $(FFMPEG_LIBS)
 
 bin_PROGRAMS = xmoto xmoto-edit
 
@@ -53,6 +53,8 @@
 	src/Input.cpp \
 	src/Input.h \
 	src/GameSerializer.cpp \
+	src/Video.cpp \
+	src/Video.h \
 	src/Collision.cpp \
 	src/Collision.h
 
