WARNING: avimux is still broken, but less broken than it used to be... Code is under...
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>
Sat, 2 Feb 2002 16:27:20 +0000 (16:27 +0000)
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>
Sat, 2 Feb 2002 16:27:20 +0000 (16:27 +0000)
Original commit message from CVS:
WARNING: avimux is still broken, but less broken than it used to be... Code is under heavy development and will work sooner or later... Uploaded for generic development and testing purposes, not intended for generic use whatsoever

gst/avi/gstavimux.c
gst/avi/gstavimux.h

index d79b6ee..12f13c6 100644 (file)
@@ -1,5 +1,5 @@
-/* Gnome-Streamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+/* AVI muxer plugin for GStreamer
+ * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * Boston, MA 02111-1307, USA.
  */
 
+/* based on:
+ * - the old avimuxer (by Wim Taymans)
+ * - xawtv's aviwriter (by Gerd Knorr)
+ * - mjpegtools' avilib (by Rainer Johanni)
+ * - openDML large-AVI docs
+ */
+
 
+#include <config.h>
 
 #include <stdlib.h>
 #include <string.h>
 
 #include "gstavimux.h"
 
+#ifndef LE_FROM_GUINT16
+#define LE_FROM_GUINT16 GUINT16_FROM_LE
+#endif
+
+#ifndef LE_FROM_GUINT32
+#define LE_FROM_GUINT32 GUINT32_FROM_LE
+#endif
 
 
 /* elementfactory information */
@@ -32,10 +47,10 @@ gst_avimux_details =
 {
   ".avi mux",
   "Mux/Video",
-  "Encodes audio and video into an avi stream",
+  "Muxes audio and video into an avi stream",
   VERSION,
-  "Wim Taymans <wim.taymans@chello.be>",
-  "(C) 2000",
+  "Ronald Bultje <rbultje@ronald.bitfreak.net>",
+  "(C) 2002",
 };
 
 /* AviMux signals and args */
@@ -46,7 +61,7 @@ enum {
 
 enum {
   ARG_0,
-  /* FILL ME */
+  ARG_BIGFILE,
 };
 
 GST_PADTEMPLATE_FACTORY (src_factory,
@@ -54,44 +69,116 @@ GST_PADTEMPLATE_FACTORY (src_factory,
   GST_PAD_SRC,
   GST_PAD_ALWAYS,
   GST_CAPS_NEW (
-    "sink_video",
+    "avimux_src_video",
     "video/avi",
     NULL
   )
 )
     
 GST_PADTEMPLATE_FACTORY (video_sink_factory,
-  "video_%02d",
+  "video_[00-63]",
   GST_PAD_SINK,
   GST_PAD_REQUEST,
   GST_CAPS_NEW (
-    "sink_video",
+    "avimux_sink_video",
     "video/avi",
       "format",   GST_PROPS_STRING ("strf_vids")
+  ),
+  GST_CAPS_NEW (
+    "avimux_sink_video",
+    "video/raw",
+      "format", GST_PROPS_LIST (
+                  GST_PROPS_FOURCC (GST_MAKE_FOURCC('Y','U','Y','2')),
+                  GST_PROPS_FOURCC (GST_MAKE_FOURCC('I','4','2','0')),
+                  GST_PROPS_FOURCC (GST_MAKE_FOURCC('Y','4','1','P'))
+                ),
+      "width",  GST_PROPS_INT_RANGE (16, 4096),
+      "height", GST_PROPS_INT_RANGE (16, 4096)
+  ),
+  GST_CAPS_NEW (
+    "avimux_sink_video",
+    "video/raw",
+      "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC('R','G','B',' ')),
+      "width",  GST_PROPS_INT_RANGE (16, 4096),
+      "height", GST_PROPS_INT_RANGE (16, 4096),
+      "depth",  GST_PROPS_LIST(
+                  GST_PROPS_INT(16),
+                  GST_PROPS_INT(16),
+                  GST_PROPS_INT(24),
+                  GST_PROPS_INT(32)
+                ),
+      "bpp",    GST_PROPS_LIST(
+                  GST_PROPS_INT(15),
+                  GST_PROPS_INT(16),
+                  GST_PROPS_INT(24),
+                  GST_PROPS_INT(32)
+                )
+  ),
+  GST_CAPS_NEW (
+    "avimux_sink_video",
+    "video/jpeg",
+      "width",  GST_PROPS_INT_RANGE (16, 4096),
+      "height", GST_PROPS_INT_RANGE (16, 4096)
   )
 )
     
 GST_PADTEMPLATE_FACTORY (audio_sink_factory,
-  "audio_%02d",
+  "audio_[00-63]",
   GST_PAD_SINK,
   GST_PAD_REQUEST,
   GST_CAPS_NEW (
-    "sink_audio",
+    "avimux_sink_audio",
     "video/avi",
       "format",   GST_PROPS_STRING ("strf_auds")
+  ),
+  GST_CAPS_NEW (
+    "avimux_sink_audio",
+    "audio/raw",
+      "format",           GST_PROPS_STRING ("int"),
+      "law",              GST_PROPS_INT (0),
+      "endianness",       GST_PROPS_INT (G_BYTE_ORDER),
+      "signed",           GST_PROPS_LIST (
+                           GST_PROPS_BOOLEAN (TRUE),
+                           GST_PROPS_BOOLEAN (FALSE)
+                         ),
+      "width",            GST_PROPS_LIST (
+                           GST_PROPS_INT (8),
+                           GST_PROPS_INT (16)
+                         ),
+      "depth",            GST_PROPS_LIST (
+                           GST_PROPS_INT (8),
+                           GST_PROPS_INT (16)
+                         ),
+      "rate",             GST_PROPS_INT_RANGE (11025, 44100),
+      "channels",         GST_PROPS_INT_RANGE (1, 2)
+  ),
+  GST_CAPS_NEW (
+    "avimux_sink_audio",
+    "audio/mp3",
+      NULL
   )
 )
     
 
-static void    gst_avimux_class_init           (GstAviMuxClass *klass);
-static void    gst_avimux_init                 (GstAviMux *avimux);
-
-static void    gst_avimux_chain                (GstPad *pad, GstBuffer *buf);
-static GstPad*         gst_avimux_request_new_pad      (GstElement *element, GstPadTemplate *templ, const gchar *name);
-       
-static void     gst_avimux_set_property         (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static void     gst_avimux_get_property         (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-
+static void    gst_avimux_class_init                (GstAviMuxClass *klass);
+static void    gst_avimux_init                      (GstAviMux      *avimux);
+
+static void     gst_avimux_chain                     (GstPad         *pad,
+                                                      GstBuffer      *buf);
+static gboolean gst_avimux_handle_event              (GstPad         *pad,
+                                                      GstEvent       *event);
+static GstPad*  gst_avimux_request_new_pad           (GstElement     *element,
+                                                      GstPadTemplate *templ,
+                                                      const gchar    *name);
+static void     gst_avimux_set_property              (GObject        *object,
+                                                      guint           prop_id,
+                                                      const GValue   *value,
+                                                      GParamSpec     *pspec);
+static void     gst_avimux_get_property              (GObject        *object,
+                                                      guint           prop_id,
+                                                      GValue         *value,
+                                                      GParamSpec     *pspec);
+static GstElementStateReturn gst_avimux_change_state (GstElement     *element);
 
 static GstElementClass *parent_class = NULL;
 /*static guint gst_avimux_signals[LAST_SIGNAL] = { 0 }; */
@@ -129,61 +216,160 @@ gst_avimux_class_init (GstAviMuxClass *klass)
 
   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
 
-  gobject_class->set_property = gst_avimux_set_property;
-  gobject_class->get_property = gst_avimux_get_property;
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BIGFILE,
+    g_param_spec_boolean("bigfile","Bigfile Support","Whether to capture large or small AVI files",
+    0,G_PARAM_READWRITE));
 
   gstelement_class->request_new_pad = gst_avimux_request_new_pad;
+
+  gstelement_class->change_state = gst_avimux_change_state;
+
+  gstelement_class->get_property = gst_avimux_get_property;
+  gstelement_class->set_property = gst_avimux_set_property;
 }
 
 static void 
 gst_avimux_init (GstAviMux *avimux) 
 {
+  gint i;
   avimux->srcpad = gst_pad_new_from_template (
                  GST_PADTEMPLATE_GET (src_factory), "src");
   gst_element_add_pad (GST_ELEMENT (avimux), avimux->srcpad);
 
-  avimux->state = GST_AVIMUX_INITIAL;
-  avimux->riff = NULL;
+  GST_FLAG_SET (GST_ELEMENT(avimux), GST_ELEMENT_EVENT_AWARE);
+  /*gst_pad_set_event_function(avimux->srcpad, gst_avimux_handle_event);*/
+
+  for (i=0;i<MAX_NUM_AUDIO_PADS;i++)
+    avimux->audiosinkpad[i] = NULL;
   avimux->num_audio_pads = 0;
+  for (i=0;i<MAX_NUM_VIDEO_PADS;i++)
+    avimux->videosinkpad[i] = NULL;
   avimux->num_video_pads = 0;
-  avimux->next_time = 0;
 
-  avimux->riff = gst_riff_encoder_new (GST_RIFF_RIFF_AVI);
-  avimux->aviheader = g_malloc0 (sizeof (gst_riff_avih));
+  avimux->num_frames = 0;
+
+  /* audio/video/AVI header initialisation */
+  memset(&(avimux->avi_hdr),0,sizeof(gst_riff_avih));
+  memset(&(avimux->vids_hdr),0,sizeof(gst_riff_strh));
+  memset(&(avimux->vids),0,sizeof(gst_riff_strf_vids));
+  memset(&(avimux->auds_hdr),0,sizeof(gst_riff_strh));
+  memset(&(avimux->auds),0,sizeof(gst_riff_strf_auds));
+  avimux->vids_hdr.type = GST_MAKE_FOURCC('v','i','d','s');
+  avimux->vids_hdr.rate = 1000000;
+  avimux->auds_hdr.type = GST_MAKE_FOURCC('a','u','d','s');
+
+  avimux->idx = NULL;
+
+  avimux->write_header = TRUE;
+
+  avimux->enable_large_avi = TRUE;
 }
 
 static GstPadConnectReturn
-gst_avimux_sinkconnect (GstPad *pad, GstCaps *caps)
+gst_avimux_sinkconnect (GstPad *pad, GstCaps *vscaps)
 {
   GstAviMux *avimux;
-  const gchar* format = gst_caps_get_string (caps, "format");
-  gint padnum = GPOINTER_TO_INT (gst_pad_get_element_private (pad));
+  GstCaps *caps;
 
   avimux = GST_AVIMUX (gst_pad_get_parent (pad));
 
-  GST_DEBUG (0, "avimux: sinkconnect triggered on %s (%d), %s\n", gst_pad_get_name (pad), 
-                 padnum, format);
-
-  if (!strncmp (format, "strf_vids", 9)) {
-    gst_riff_strf_vids *strf_vids = g_malloc(sizeof(gst_riff_strf_vids));
-
-    strf_vids->size        = sizeof(gst_riff_strf_vids);
-    strf_vids->width       = gst_caps_get_int (caps, "width");
-    strf_vids->height      = gst_caps_get_int (caps, "height");;
-    strf_vids->planes      = gst_caps_get_int (caps, "planes");;
-    strf_vids->bit_cnt     = gst_caps_get_int (caps, "bit_cnt");;
-    strf_vids->compression = gst_caps_get_fourcc_int (caps, "compression");;
-    strf_vids->image_size  = gst_caps_get_int (caps, "image_size");;
-    strf_vids->xpels_meter = gst_caps_get_int (caps, "xpels_meter");;
-    strf_vids->ypels_meter = gst_caps_get_int (caps, "ypels_meter");;
-    strf_vids->num_colors  = gst_caps_get_int (caps, "num_colors");;
-    strf_vids->imp_colors  = gst_caps_get_int (caps, "imp_colors");;
-
-    avimux->video_header[padnum] = strf_vids;
+  GST_DEBUG (0, "avimux: sinkconnect triggered on %s (%d)\n", gst_pad_get_name (pad));
+
+  for (caps = vscaps; caps != NULL; caps = vscaps = vscaps->next)
+  {
+    const gchar* format = gst_caps_get_string(caps, "format");
+    const gchar* mimetype = gst_caps_get_mime(caps);
+
+    if (!strcmp (mimetype, "video/avi"))
+    {
+      if (!strncmp (format, "strf_vids", 9)) {
+        avimux->vids.size        = sizeof(gst_riff_strf_vids);
+        avimux->vids.width       = gst_caps_get_int (caps, "width");
+        avimux->vids.height      = gst_caps_get_int (caps, "height");
+        avimux->vids.planes      = gst_caps_get_int (caps, "planes");
+        avimux->vids.bit_cnt     = gst_caps_get_int (caps, "bit_cnt");
+        avimux->vids.compression = gst_caps_get_fourcc_int (caps, "compression");
+        avimux->vids.image_size  = gst_caps_get_int (caps, "image_size");
+        avimux->vids.xpels_meter = gst_caps_get_int (caps, "xpels_meter");
+        avimux->vids.ypels_meter = gst_caps_get_int (caps, "ypels_meter");
+        avimux->vids.num_colors  = gst_caps_get_int (caps, "num_colors");
+        avimux->vids.imp_colors  = gst_caps_get_int (caps, "imp_colors");
+      }
+      else if (!strncmp (format, "strf_auds", 9)) {
+        avimux->auds.format      = gst_caps_get_int (caps, "format");
+        avimux->auds.channels    = gst_caps_get_int (caps, "channels");
+        avimux->auds.rate        = gst_caps_get_int (caps, "rate");
+        avimux->auds.av_bps      = gst_caps_get_int (caps, "av_bps");
+        avimux->auds.blockalign  = gst_caps_get_int (caps, "blockalign");
+        avimux->auds.size        = gst_caps_get_int (caps, "size");
+      }
+      goto done;
+    }
+    else if (!strcmp (mimetype, "video/raw"))
+    {
+      switch (gst_caps_get_fourcc_int(caps, "format"))
+      {
+        case GST_MAKE_FOURCC('Y','U','Y','2'):
+        case GST_MAKE_FOURCC('I','4','2','0'):
+        case GST_MAKE_FOURCC('Y','4','1','P'):
+        case GST_MAKE_FOURCC('R','G','B',' '):
+          avimux->vids.size        = sizeof(gst_riff_strf_vids);
+          avimux->vids.width       = gst_caps_get_int (caps, "width");
+          avimux->vids.height      = gst_caps_get_int (caps, "height");
+          avimux->vids.planes      = 1;
+          switch (gst_caps_get_fourcc_int(caps, "format"))
+          {
+            case GST_MAKE_FOURCC('Y','U','Y','2'):
+              avimux->vids.bit_cnt     = 16; /* YUY2 */
+              break;
+            case GST_MAKE_FOURCC('R','G','B',' '):
+              avimux->vids.bit_cnt     = gst_caps_get_fourcc_int(caps, "bpp"); /* RGB */
+              break;
+            case GST_MAKE_FOURCC('Y','4','1','P'):
+            case GST_MAKE_FOURCC('I','4','2','0'):
+              avimux->vids.bit_cnt     = 12; /* Y41P or I420 */
+              break;
+          }
+          avimux->vids.compression = gst_caps_get_fourcc_int(caps, "format");
+          avimux->vids.image_size  = avimux->vids.height * avimux->vids.width;
+          goto done;
+        default:
+          break;
+      }
+    }
+    else if (!strcmp (mimetype, "video/jpeg"))
+    {
+      avimux->vids.size        = sizeof(gst_riff_strf_vids);
+      avimux->vids.width       = gst_caps_get_int (caps, "width");
+      avimux->vids.height      = gst_caps_get_int (caps, "height");
+      avimux->vids.planes      = 1;
+      avimux->vids.bit_cnt     = 24;
+      avimux->vids.compression = GST_MAKE_FOURCC('M','J','P','G');
+      avimux->vids.image_size  = avimux->vids.height * avimux->vids.width;
+      goto done;
+    }
+    else if (!strcmp (mimetype, "audio/raw"))
+    {
+      avimux->auds.format      = GST_RIFF_WAVE_FORMAT_PCM;
+      avimux->auds.channels    = gst_caps_get_int (caps, "channels");
+      avimux->auds.rate        = gst_caps_get_int (caps, "rate");
+      avimux->auds.av_bps      = gst_caps_get_int (caps, "width")*avimux->auds.rate*
+                                               avimux->auds.channels/8;
+      avimux->auds.blockalign  = gst_caps_get_int (caps, "width")*avimux->auds.channels/8;
+      avimux->auds.size        = gst_caps_get_int (caps, "depth");
+      goto done;
+    }
+    else if (!strcmp (mimetype, "audio/mp3"))
+    {
+      /* we don't need to do anything here, compressed mp3 contains it all */
+      avimux->auds.format      = gst_caps_get_int(caps, "layer")==3?
+                                   GST_RIFF_WAVE_FORMAT_MPEGL3:GST_RIFF_WAVE_FORMAT_MPEGL12;
+      goto done;
+    }
   }
-  else if (!strncmp (format, "strf_auds", 9)) {
+  return GST_PAD_CONNECT_REFUSED;
 
-  }
+done:
   return GST_PAD_CONNECT_OK;
 }
 
@@ -208,19 +394,21 @@ gst_avimux_request_new_pad (GstElement     *element,
   avimux = GST_AVIMUX (element);
 
   if (templ == GST_PADTEMPLATE_GET (audio_sink_factory)) {
+    g_return_val_if_fail(avimux->num_audio_pads == 0 /*< MAX_NUM_AUDIO_PADS*/, NULL);
     name = g_strdup_printf ("audio_%02d", avimux->num_audio_pads);
     newpad = gst_pad_new_from_template (templ, name);
     gst_pad_set_element_private (newpad, GINT_TO_POINTER (avimux->num_audio_pads));
 
-    avimux->audio_pad[avimux->num_audio_pads] = newpad;
+    avimux->audiosinkpad[avimux->num_audio_pads] = newpad;
     avimux->num_audio_pads++;
   }
   else if (templ == GST_PADTEMPLATE_GET (video_sink_factory)) {
+    g_return_val_if_fail(avimux->num_video_pads == 0 /*< MAX_NUM_VIDEO_PADS*/, NULL);
     name = g_strdup_printf ("video_%02d", avimux->num_video_pads);
     newpad = gst_pad_new_from_template (templ, name);
     gst_pad_set_element_private (newpad, GINT_TO_POINTER (avimux->num_video_pads));
 
-    avimux->video_pad[avimux->num_video_pads] = newpad;
+    avimux->videosinkpad[avimux->num_video_pads] = newpad;
     avimux->num_video_pads++;
   }
   else {
@@ -235,38 +423,459 @@ gst_avimux_request_new_pad (GstElement     *element,
   return newpad;
 }
 
+/* maybe some of these functions should be moved to riff.h? */
+
+/* DISCLAIMER: this function is ugly. So be it (i.e. it makes the rest easier) */
+
+static GstBuffer *
+gst_avimux_riff_get_avi_header (GstAviMux *avimux)
+{
+  GstBuffer *buffer;
+  guint8 *buffdata;
+  guint16 temp16;
+  guint32 temp32;
+
+  buffer = gst_buffer_new();
+
+  /* first, let's see what actually needs to be in the buffer */
+  GST_BUFFER_SIZE(buffer) = 0;
+  GST_BUFFER_SIZE(buffer) += 32 + sizeof(gst_riff_avih); /* avi header */
+  if (avimux->num_video_pads)
+  { /* we have video */
+    GST_BUFFER_SIZE(buffer) += 28 + sizeof(gst_riff_strh) + sizeof(gst_riff_strf_vids); /* vid hdr */
+    GST_BUFFER_SIZE(buffer) += 24; /* odml header */
+  }
+  if (avimux->num_audio_pads)
+  { /* we have audio */
+    GST_BUFFER_SIZE(buffer) += 28 + sizeof(gst_riff_strh) + sizeof(gst_riff_strf_auds); /* aud hdr */
+  }
+  /* this is the "riff size" */
+  avimux->header_size = GST_BUFFER_SIZE(buffer);
+  GST_BUFFER_SIZE(buffer) += 12; /* avi data header */
+
+  /* allocate the buffer */
+  buffdata = GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(buffer));
+
+  /* avi header metadata */
+  memcpy(buffdata, "RIFF", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->header_size + avimux->idx_size + avimux->data_size);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  memcpy(buffdata, "AVI ", 4); buffdata += 4;
+  memcpy(buffdata, "LIST", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->header_size - 4*5);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  memcpy(buffdata, "hdrl", 4); buffdata += 4;
+  memcpy(buffdata, "avih", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(sizeof(gst_riff_avih));
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  /* the AVI header itself */
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.us_frame);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.max_bps);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.pad_gran);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.flags);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.tot_frames);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.init_frames);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.streams);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.bufsize);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.width);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.height);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.scale);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.rate);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.start);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->avi_hdr.length);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+
+  /* video header metadata */
+  memcpy(buffdata, "LIST", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strh) + sizeof(gst_riff_strf_vids) + 4*5);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  memcpy(buffdata, "strl", 4); buffdata += 4;
+  /* generic header */
+  memcpy(buffdata, "strh", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strh));
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  /* the actual header */
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.type);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.fcc_handler);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.flags);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.priority);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.init_frames);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.scale);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.rate);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.start);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.length);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.bufsize);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.quality);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids_hdr.samplesize);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  /* the video header */
+  memcpy(buffdata, "strf", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strf_vids));
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  /* the actual header */
+  temp32 = LE_FROM_GUINT32(avimux->vids.size);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids.width);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids.height);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp16 = LE_FROM_GUINT16(avimux->vids.planes);
+  memcpy(buffdata, &temp16, 2); buffdata += 2;
+  temp16 = LE_FROM_GUINT16(avimux->vids.bit_cnt);
+  memcpy(buffdata, &temp16, 2); buffdata += 2;
+  temp32 = LE_FROM_GUINT32(avimux->vids.compression);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids.image_size);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids.xpels_meter);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids.ypels_meter);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids.num_colors);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->vids.imp_colors);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+
+  /* audio header */
+  memcpy(buffdata, "LIST", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strh) + sizeof(gst_riff_strf_auds) + 4*5);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  memcpy(buffdata, "strl", 4); buffdata += 4;
+  /* generic header */
+  memcpy(buffdata, "strh", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strh));
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  /* the actual header */
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.type);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.fcc_handler);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.flags);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.priority);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.init_frames);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.scale);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.rate);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.start);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.length);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.bufsize);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.quality);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds_hdr.samplesize);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  /* the audio header */
+  memcpy(buffdata, "strf", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strf_vids));
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  /* the actual header */
+  temp16 = LE_FROM_GUINT16(avimux->auds.format);
+  memcpy(buffdata, &temp16, 2); buffdata += 2;
+  temp16 = LE_FROM_GUINT16(avimux->auds.channels);
+  memcpy(buffdata, &temp16, 2); buffdata += 2;
+  temp32 = LE_FROM_GUINT32(avimux->auds.rate);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->auds.av_bps);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp16 = LE_FROM_GUINT16(avimux->auds.blockalign);
+  memcpy(buffdata, &temp16, 2); buffdata += 2;
+  temp16 = LE_FROM_GUINT16(avimux->auds.size);
+  memcpy(buffdata, &temp16, 2); buffdata += 2;
+
+  /* odml header */
+  memcpy(buffdata, "LIST", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(sizeof(guint32)+4*3);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  memcpy(buffdata, "odml", 4); buffdata += 4;
+  memcpy(buffdata, "dmlh", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(sizeof(guint32));
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->total_frames);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+
+  /* avi data header */
+  memcpy(buffdata, "LIST", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(avimux->data_size);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  memcpy(buffdata, "movi", 4); buffdata += 4;
+
+  return buffer;
+}
+
+static GstBuffer *
+gst_avimux_riff_get_avix_header (guint32 datax_size)
+{
+  GstBuffer *buffer;
+  guint8 *buffdata;
+  guint32 temp32;
+
+  buffer = gst_buffer_new();
+  GST_BUFFER_SIZE(buffer) = 24;
+  buffdata = GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(buffer));
+
+  memcpy(buffdata, "LIST", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(datax_size+4*4);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  memcpy(buffdata, "AVIX", 4); buffdata += 4;
+  memcpy(buffdata, "LIST", 4); buffdata += 4;
+  temp32 = LE_FROM_GUINT32(datax_size);
+  memcpy(buffdata, &temp32, 4); buffdata += 4;
+  memcpy(buffdata, "movi", 4); buffdata += 4;
+
+  return buffer;
+}
+
+static GstBuffer *
+gst_avimux_riff_get_video_header (guint32 video_frame_size)
+{
+  GstBuffer *buffer;
+  guint32 temp32;
+
+  buffer = gst_buffer_new();
+  GST_BUFFER_DATA(buffer) = g_malloc(8);
+  GST_BUFFER_SIZE(buffer) = 8;
+  memcpy(GST_BUFFER_DATA(buffer), "00db", 4);
+  temp32 = LE_FROM_GUINT32(video_frame_size);
+  memcpy(GST_BUFFER_DATA(buffer)+4, &temp32, 4);
+
+  return buffer;
+}
+
+static GstBuffer *
+gst_avimux_riff_get_audio_header (guint32 audio_sample_size)
+{
+  GstBuffer *buffer;
+  guint32 temp32;
+
+  buffer = gst_buffer_new();
+  GST_BUFFER_DATA(buffer) = g_malloc(8);
+  GST_BUFFER_SIZE(buffer) = 8;
+  memcpy(GST_BUFFER_DATA(buffer), "01wb", 4);
+  temp32 = LE_FROM_GUINT32(audio_sample_size);
+  memcpy(GST_BUFFER_DATA(buffer)+4, &temp32, 4);
+
+  return buffer;
+}
+
+/* some other usable functions (thankyou xawtv ;-) ) */
+
 static void
-gst_avimux_make_header (GstAviMux *avimux)
+gst_avimux_add_index (GstAviMux *avimux, guint32 fourcc, guint32 flags, guint32 size)
 {
-  gint i;
+  guint32 temp32;
+  
+  if (avimux->idx_index == avimux->idx_count)
+  {
+    avimux->idx_count += 256;
+    avimux->idx = realloc(avimux->idx, avimux->idx_count*sizeof(gst_riff_index_entry));
+  }
+  temp32 = LE_FROM_GUINT32(fourcc);
+  memcpy(&(avimux->idx[avimux->idx_index].id), &temp32, 4);
+  avimux->idx[avimux->idx_index].flags = LE_FROM_GUINT32(flags);
+  avimux->idx[avimux->idx_index].offset = LE_FROM_GUINT32(avimux->idx_offset-avimux->header_size-8);
+  avimux->idx[avimux->idx_index].size = LE_FROM_GUINT32(size);
+  avimux->idx_index++;
+  avimux->idx_offset += size + sizeof(gst_riff_index_entry);
+}
+
+static void
+gst_avimux_write_index (GstAviMux *avimux)
+{
+  GstBuffer *buffer;
+  guint32 temp32;
+
+  buffer = gst_buffer_new();
+  GST_BUFFER_SIZE(buffer) = 8;
+  GST_BUFFER_DATA(buffer) = g_malloc(8);
+  memcpy(GST_BUFFER_DATA(buffer), "idx1", 4);
+  temp32 = LE_FROM_GUINT32(avimux->idx_index * sizeof(gst_riff_index_entry)); 
+  memcpy(GST_BUFFER_DATA(buffer)+4, &temp32, 4);
+  gst_pad_push(avimux->srcpad, buffer);
+
+  buffer = gst_buffer_new();
+  GST_BUFFER_SIZE(buffer) = avimux->idx_index * sizeof(gst_riff_index_entry);
+  GST_BUFFER_DATA(buffer) = (unsigned char*) avimux->idx;
+  avimux->idx = NULL; /* will be free()'ed by gsT_buffer_unref() */
+  avimux->total_data += GST_BUFFER_SIZE(buffer);
+  gst_pad_push(avimux->srcpad, buffer);
+
+  avimux->idx_size += avimux->idx_index * sizeof(gst_riff_index_entry) + 8;
+
+  /* update header */
+  avimux->avi_hdr.flags |= GST_RIFF_AVIH_HASINDEX;
+}
+
+static void
+gst_avimux_bigfile(GstAviMux *avimux, gboolean last)
+{
+  GstBuffer *header;
+  GstEvent *event;
+    
+  if (avimux->is_bigfile)
+  {
+    /* sarch back */
+    event = gst_event_new_seek(GST_SEEK_BYTEOFFSET_SET, avimux->avix_start, TRUE);
+    gst_pad_push(avimux->srcpad, GST_BUFFER(event));
+
+    /* rewrite AVIX header */
+    header = gst_avimux_riff_get_avix_header(avimux->datax_size);
+    gst_pad_push(avimux->srcpad, header);
+
+    /* go back to current location */
+    event = gst_event_new_seek(GST_SEEK_BYTEOFFSET_SET, avimux->total_data, TRUE);
+    gst_pad_push(avimux->srcpad, GST_BUFFER(event));
+  }
+  avimux->avix_start = avimux->total_data;
+
+  if (last)
+    return;
+
+  avimux->is_bigfile = TRUE;
+  avimux->numx_frames = 0;
+  avimux->datax_size = 0;
+
+  header = gst_avimux_riff_get_avix_header(0);
+  avimux->total_data += GST_BUFFER_SIZE(header);
+  gst_pad_push(avimux->srcpad, header);
+}
+
+/* enough header blabla now, let's go on to actually writing the headers */
+
+static void
+gst_avimux_start_file (GstAviMux *avimux)
+{
+  GstBuffer *header;
+
+  avimux->total_data = 0;
+  avimux->total_frames = 0;
+  avimux->data_size = 4; /* ? */
+  avimux->datax_size = 0;
+  avimux->num_frames = 0;
+  avimux->numx_frames = 0;
+  avimux->audio_size = 0;
+
+  avimux->idx_index = 0;
+  avimux->idx_offset = avimux->header_size + 12;
+  avimux->idx_size = 0;
+  avimux->idx_count = 0;
+  avimux->idx = NULL;
+
+  avimux->is_bigfile = FALSE;
+  header = gst_avimux_riff_get_avi_header(avimux);
+  avimux->total_data += GST_BUFFER_SIZE(header);
+
+  gst_pad_push(avimux->srcpad, header);
+
+  avimux->write_header = FALSE;
+}
+
+static void
+gst_avimux_stop_file (GstAviMux *avimux)
+{
+  GstEvent *event;
+  GstBuffer *header;
+
+  /* if bigfile, rewrite header, else write indexes */
+  if (avimux->num_video_pads)
+  {
+    if (avimux->is_bigfile)
+    {
+      gst_avimux_bigfile(avimux, TRUE);
+      avimux->idx_size = 0;
+    }
+    else
+    {
+      gst_avimux_write_index(avimux);
+    }
+  }
+
+  /* statistics/total_frames/... */
+  avimux->avi_hdr.tot_frames = avimux->num_frames;
+  if (avimux->num_video_pads)
+    avimux->auds_hdr.length = avimux->num_frames;
+  if (avimux->num_audio_pads)
+    avimux->auds_hdr.length = avimux->audio_size/avimux->auds_hdr.scale;
+
+  /* seek and rewrite the header */
+  header = gst_avimux_riff_get_avi_header(avimux);
+  event = gst_event_new_seek(GST_SEEK_BYTEOFFSET_SET, 0, TRUE);
+  gst_pad_push(avimux->srcpad, GST_BUFFER(event));
+  gst_pad_push(avimux->srcpad, header);
+
+  avimux->write_header = TRUE;
+}
+
+static void
+gst_avimux_restart_file (GstAviMux *avimux)
+{
+  GstEvent *event;
 
-  gst_riff_strh strh;
+  gst_avimux_stop_file(avimux);
 
-  avimux->aviheader->us_frame = 40000;
-  avimux->aviheader->streams  = avimux->num_video_pads + avimux->num_audio_pads;
-  avimux->aviheader->width    = -1;
-  avimux->aviheader->height   = -1;
-  gst_riff_encoder_avih(avimux->riff, avimux->aviheader, sizeof(gst_riff_avih));
+  event = gst_event_new(GST_EVENT_NEW_MEDIA);
+  gst_pad_push(avimux->srcpad, GST_BUFFER(event));
+
+  /*gst_avimux_start_file(avimux);*/
+}
 
-  memset(&strh, 0, sizeof(gst_riff_strh));
-  strh.scale = 40000;
+/* handle events (search) */
+static gboolean
+gst_avimux_handle_event (GstPad *pad, GstEvent *event)
+{
+  GstAviMux *avimux;
+  GstEventType type;
 
-  gst_riff_encoder_strh(avimux->riff, GST_RIFF_FCC_vids, &strh, sizeof(gst_riff_strh));
+  avimux = GST_AVIMUX (gst_pad_get_parent (pad));
+  
+  type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
 
-  for (i=0; i<avimux->num_video_pads; i++) {
-    gst_riff_encoder_strf(avimux->riff, avimux->video_header[i], sizeof(gst_riff_strf_vids));
+  switch (type) {
+    case GST_EVENT_NEW_MEDIA:
+      gst_avimux_restart_file(avimux);
+      break;
+    default:
+      break;
   }
+
+  return TRUE;
 }
 
 static void
 gst_avimux_chain (GstPad *pad, GstBuffer *buf)
 {
   GstAviMux *avimux;
-  guchar *data;
-  gulong size;
-  const gchar *padname;
-  gint channel;
   GstBuffer *newbuf;
+  const gchar *padname = gst_pad_get_name (pad);
 
   g_return_if_fail (pad != NULL);
   g_return_if_fail (GST_IS_PAD (pad));
@@ -274,85 +883,166 @@ gst_avimux_chain (GstPad *pad, GstBuffer *buf)
   g_return_if_fail (GST_BUFFER_DATA (buf) != NULL);
 
   avimux = GST_AVIMUX (gst_pad_get_parent (pad));
+  
+  if (GST_IS_EVENT(buf))
+  {
+    gst_avimux_handle_event(pad, GST_EVENT(buf));
+    return;
+  }
 
-  data = (guchar *)GST_BUFFER_DATA(buf);
-  size = GST_BUFFER_SIZE(buf);
-
-  switch(avimux->state) {
-    case GST_AVIMUX_INITIAL:
-      GST_DEBUG (0,"gst_avimux_chain: writing header\n");
-      gst_avimux_make_header(avimux);
-      newbuf = gst_riff_encoder_get_and_reset_buffer(avimux->riff);
-      gst_pad_push(avimux->srcpad, newbuf);
-      avimux->state = GST_AVIMUX_MOVI;
-    case GST_AVIMUX_MOVI:
-      padname = gst_pad_get_name (pad);
-      channel = GPOINTER_TO_INT (gst_pad_get_element_private (pad));
-
-      if (strncmp(padname, "audio_", 6) == 0) {
-        GST_DEBUG (0,"gst_avimux_chain: got audio buffer in from channel %02d %lu\n", channel, size);
-        gst_riff_encoder_chunk(avimux->riff, GST_RIFF_01wb, NULL, size); 
-        newbuf = gst_riff_encoder_get_and_reset_buffer(avimux->riff);
-        gst_pad_push(avimux->srcpad, newbuf);
-      }
-      else if (strncmp(padname, "video_", 6) == 0) {
-        GST_DEBUG (0,"gst_avimux_chain: got video buffer in from channel %02d %lu\n", channel, size);
-        gst_riff_encoder_chunk(avimux->riff, GST_RIFF_00db, NULL, size); 
-        newbuf = gst_riff_encoder_get_and_reset_buffer(avimux->riff);
-        GST_DEBUG (0,"gst_avimux_chain: encoded %u\n", GST_BUFFER_SIZE(newbuf));
-        gst_pad_push(avimux->srcpad, newbuf);
-      }
-      GST_BUFFER_SIZE(buf) = (GST_BUFFER_SIZE(buf)+1)&~1;
-      gst_pad_push(avimux->srcpad, buf);
-      break;
-    default:
-      break;
+  if (avimux->write_header)
+    gst_avimux_start_file(avimux);
+
+  if (strncmp(padname, "audio_", 6) == 0)
+  {
+    /* write a audio header + index entry */
+    newbuf = gst_avimux_riff_get_audio_header(GST_BUFFER_SIZE(buf));
+    avimux->total_data += GST_BUFFER_SIZE(newbuf) + GST_BUFFER_SIZE(buf);
+
+    if (avimux->is_bigfile)
+    {
+      avimux->datax_size += GST_BUFFER_SIZE(newbuf) + GST_BUFFER_SIZE(buf);
+    }
+    else
+    {
+      avimux->data_size += GST_BUFFER_SIZE(newbuf) + GST_BUFFER_SIZE(buf);
+      avimux->audio_size += GST_BUFFER_SIZE(buf);
+      gst_avimux_add_index(avimux, avimux->auds.format, 0x0, GST_BUFFER_SIZE(buf));
+    }
+
+    gst_pad_push(avimux->srcpad, newbuf);
+  }
+  else if (strncmp(padname, "video_", 6) == 0)
+  {
+    /* write a video header + index entry */
+    GST_BUFFER_SIZE(buf) = (GST_BUFFER_SIZE(buf)+3)&~3;
+
+    if ((avimux->is_bigfile?avimux->datax_size:avimux->data_size)+GST_BUFFER_SIZE(buf)>1024*1024*2000)
+    {
+      if (avimux->enable_large_avi)
+        gst_avimux_bigfile(avimux, FALSE);
+      else
+        gst_avimux_restart_file(avimux);
+    }
+
+    newbuf = gst_avimux_riff_get_video_header(GST_BUFFER_SIZE(buf));
+    avimux->total_data += GST_BUFFER_SIZE(newbuf) + GST_BUFFER_SIZE(buf);
+    avimux->total_frames++;
+
+    if (avimux->is_bigfile)
+    {
+      avimux->datax_size += GST_BUFFER_SIZE(newbuf) + GST_BUFFER_SIZE(buf);
+      avimux->numx_frames++;
+    }
+    else
+    {
+      avimux->data_size += GST_BUFFER_SIZE(newbuf) + GST_BUFFER_SIZE(buf);
+      avimux->num_frames++;
+      gst_avimux_add_index(avimux, avimux->vids.compression, 0x12, GST_BUFFER_SIZE(buf));
+    }
+
+    gst_pad_push(avimux->srcpad, newbuf);
+  }
+  else
+  {
+    g_warning("Unknown padname \'%s\'\n", padname);
+    return;
   }
 
-  /*gst_buffer_unref(buf); */
+  /* data */
+  gst_pad_push(avimux->srcpad, buf);
 }
 
-static void 
-gst_avimux_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+static void
+gst_avimux_get_property (GObject    *object,
+                         guint      prop_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
 {
-  GstAviMux *src;
+  GstAviMux *avimux;
 
   /* it's not null if we got it, but it might not be ours */
   g_return_if_fail(GST_IS_AVIMUX(object));
-  src = GST_AVIMUX(object);
+  avimux = GST_AVIMUX(object);
 
-  switch(prop_id) {
+  switch (prop_id)
+  {
+    case ARG_BIGFILE:
+      g_value_set_boolean(value, avimux->enable_large_avi);
+      break;
     default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
 }
 
-static void 
-gst_avimux_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+static void
+gst_avimux_set_property (GObject      *object,
+                         guint         prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
 {
-  GstAviMux *src;
+  GstAviMux *avimux;
 
   /* it's not null if we got it, but it might not be ours */
   g_return_if_fail(GST_IS_AVIMUX(object));
-  src = GST_AVIMUX(object);
+  avimux = GST_AVIMUX(object);
 
-  switch(prop_id) {
+  switch (prop_id)
+  {
+    case ARG_BIGFILE:
+      avimux->enable_large_avi = g_value_get_boolean(value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
 }
 
+static GstElementStateReturn
+gst_avimux_change_state (GstElement *element)
+{
+  GstAviMux *avimux;
+  gint transition = GST_STATE_TRANSITION (element);
+
+  /* TODO: PLAY->READY pauses the timer (for fps calculations) */
+
+  g_return_val_if_fail(GST_IS_AVIMUX(element), GST_STATE_FAILURE);
+  
+  avimux = GST_AVIMUX(element);
+
+  switch (transition) {
+    case GST_STATE_READY_TO_PAUSED:
+      /*gst_avimux_start_file(avimux);*/
+      break;
+    case GST_STATE_PAUSED_TO_PLAYING:
+      break;
+    case GST_STATE_PLAYING_TO_PAUSED:
+      gst_avimux_stop_file(avimux);
+      break;
+    case GST_STATE_PAUSED_TO_READY:
+      /*gst_avimux_stop_file(avimux);*/
+      break;
+  }
+
+  if (GST_ELEMENT_CLASS (parent_class)->change_state)
+    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+  return GST_STATE_SUCCESS;
+}
+
 static gboolean
 plugin_init (GModule *module, GstPlugin *plugin)
 {
   GstElementFactory *factory;
 
   /* this filter needs the riff parser */
+#if 0
   if (!gst_library_load ("gstriff")) {
     gst_info ("avimux: could not load support library: 'gstriff'\n");
     return FALSE;
   }
+#endif
 
   /* create an elementfactory for the avimux element */
   factory = gst_elementfactory_new ("avimux", GST_TYPE_AVIMUX,
@@ -374,4 +1064,3 @@ GstPluginDesc plugin_desc = {
   "avimux",
   plugin_init
 };
-
index d21566e..c03ae7e 100644 (file)
@@ -1,5 +1,5 @@
-/* Gnome-Streamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+/* AVI muxer plugin for GStreamer
+ * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -22,7 +22,6 @@
 #define __GST_AVIMUX_H__
 
 
-#include <config.h>
 #include <gst/gst.h>
 #include <gst/riff/riff.h>
 
@@ -44,39 +43,55 @@ extern "C" {
   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVIMUX))
 
 
-#define GST_AVIMUX_INITIAL       0     /* initialized state */
-#define GST_AVIMUX_MOVI          1     /* encoding movi */
-
-#define GST_AVIMUX_MAX_AUDIO_PADS      8       
-#define GST_AVIMUX_MAX_VIDEO_PADS      8       
-
 typedef struct _GstAviMux GstAviMux;
 typedef struct _GstAviMuxClass GstAviMuxClass;
 
+#define MAX_NUM_AUDIO_PADS 8
+#define MAX_NUM_VIDEO_PADS 8
+
 struct _GstAviMux {
   GstElement element;
 
   /* pads */
   GstPad *srcpad;
-
-  /* AVI encoding state */
-  gint state;
-
-  /* RIFF encoding state */
-  GstRiff *riff;
-
-  guint64 next_time;
-  guint64 time_interval;
-
-  gst_riff_avih  *aviheader;    /* the avi header */
-  guint num_audio_pads;
-  guint num_video_pads;
-
-  GstPad             *audio_pad[GST_AVIMUX_MAX_AUDIO_PADS];
-  gst_riff_strf_auds *audio_header[GST_AVIMUX_MAX_AUDIO_PADS];
-  
-  GstPad             *video_pad[GST_AVIMUX_MAX_VIDEO_PADS];
-  gst_riff_strf_vids *video_header[GST_AVIMUX_MAX_VIDEO_PADS];
+  GstPad *audiosinkpad[MAX_NUM_AUDIO_PADS];
+  gint num_audio_pads;
+  GstPad *videosinkpad[MAX_NUM_VIDEO_PADS];
+  gint num_video_pads;
+
+  /* timestamps of first and current frame + num_frames for fps calculation */
+  guint64 first_timestamp;
+  guint64 current_timestamp;
+
+  /* the AVI header */
+  gst_riff_avih avi_hdr;
+  guint32 total_frames; /* total number of frames */
+  guint64 total_data; /* amount of total data */
+  guint32 data_size, datax_size; /* amount of data (bytes) in the AVI/AVIX block */
+  guint32 num_frames, numx_frames; /* num frames in the AVI/AVIX block */
+  guint32 header_size;
+  gboolean write_header;
+  guint32 audio_size;
+
+  /* video header */
+  gst_riff_strh vids_hdr;
+  gst_riff_strf_vids vids;
+
+  /* audio header */
+  gst_riff_strh auds_hdr;
+  gst_riff_strf_auds auds;
+
+  /* information about the AVI index ('idx') */
+  gst_riff_index_entry *idx;
+  gint idx_index, idx_count;
+  guint32 idx_offset, idx_size;
+
+  /* are we a big file already? */
+  gboolean is_bigfile;
+  guint64 avix_start;
+
+  /* whether to use "large AVI files" or just stick to small indexed files */
+  gboolean enable_large_avi;
 };
 
 struct _GstAviMuxClass {