change NULL to (NULL) for GST_ELEMENT_ERROR
[platform/upstream/gst-plugins-good.git] / gst / avi / gstavimux.c
1 /* AVI muxer plugin for GStreamer
2  * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /* based on:
21  * - the old avimuxer (by Wim Taymans)
22  * - xawtv's aviwriter (by Gerd Knorr)
23  * - mjpegtools' avilib (by Rainer Johanni)
24  * - openDML large-AVI docs
25  */
26
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "gst/gst-i18n-plugin.h"
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <gst/video/video.h>
37
38 #include "gstavimux.h"
39
40 #ifndef LE_FROM_GUINT16
41 #define LE_FROM_GUINT16 GUINT16_FROM_LE
42 #endif
43 #ifndef LE_FROM_GUINT32
44 #define LE_FROM_GUINT32 GUINT32_FROM_LE
45 #endif
46
47 /* AviMux signals and args */
48 enum {
49   /* FILL ME */
50   LAST_SIGNAL
51 };
52
53 enum {
54   ARG_0,
55   ARG_BIGFILE,
56 };
57
58 static GstStaticPadTemplate src_factory =
59 GST_STATIC_PAD_TEMPLATE (
60   "src",
61   GST_PAD_SRC,
62   GST_PAD_ALWAYS,
63   GST_STATIC_CAPS ("video/x-msvideo")
64 );
65     
66 static GstStaticPadTemplate video_sink_factory =
67 GST_STATIC_PAD_TEMPLATE (
68   "video_%d",
69   GST_PAD_SINK,
70   GST_PAD_REQUEST,
71   GST_STATIC_CAPS (
72     "video/x-raw-yuv, "
73       "format = (fourcc) { YUY2, I420 }, "
74       "width = (int) [ 16, 4096 ], "
75       "height = (int) [ 16, 4096 ]; "
76     "video/x-jpeg, "
77       "width = (int) [ 16, 4096 ], "
78       "height = (int) [ 16, 4096 ]; "
79     "video/x-divx, "
80       "width = (int) [ 16, 4096 ], "
81       "height = (int) [ 16, 4096 ], "
82       "divxversion = (int) [ 3, 5 ]; "
83     "video/x-xvid, "
84       "width = (int) [ 16, 4096 ], "
85       "height = (int) [ 16, 4096 ]; "
86     "video/x-3ivx, "
87       "width = (int) [ 16, 4096 ], "
88       "height = (int) [ 16, 4096 ]; "
89     "video/x-msmpeg, "
90       "width = (int) [ 16, 4096 ], "
91       "height = (int) [ 16, 4096 ], "
92       "msmpegversion = (int) [ 41, 43 ]; "
93     "video/mpeg, "
94       "width = (int) [ 16, 4096 ], "
95       "height = (int) [ 16, 4096 ], "
96       "mpegversion = (int) 1, "
97       "systemstream = (boolean) FALSE; "
98     "video/x-h263, "
99       "width = (int) [ 16, 4096 ], "
100       "height = (int) [ 16, 4096 ]; "
101     "video/x-dv, "
102       "width = (int) 720, "
103       "height = (int) { 576, 480 }, "
104       "systemstream = (boolean) FALSE; "
105     "video/x-huffyuv, "
106       "width = (int) [ 16, 4096 ], "
107       "height = (int) [ 16, 4096 ]"
108   )
109 );
110     
111 static GstStaticPadTemplate audio_sink_factory =
112 GST_STATIC_PAD_TEMPLATE (
113   "audio_%d",
114   GST_PAD_SINK,
115   GST_PAD_REQUEST,
116   GST_STATIC_CAPS (
117     "audio/x-raw-int, "
118       "endianness = (int) LITTLE_ENDIAN, "
119       "signed = (boolean) { TRUE, FALSE }, "
120       "width = (int) { 8, 16 }, "
121       "depth = (int) { 8, 16 }, "
122       "rate = (int) [ 1000, 96000 ], "
123       "channels = (int) [ 1, 2 ]; "
124     "audio/mpeg, "
125       "mpegversion = (int) 1, "
126       "layer = (int) [ 1, 3 ], "
127       "rate = (int) [ 1000, 96000 ], "
128       "channels = (int) [ 1, 2 ]; "
129     "audio/x-vorbis, "
130       "rate = (int) [ 1000, 96000 ], "
131       "channels = (int) [ 1, 2 ]; "
132     "audio/x-ac3, "
133       "rate = (int) [ 1000, 96000 ], "
134       "channels = (int) [ 1, 2 ]"
135   )
136 );
137     
138
139 static void     gst_avimux_base_init                 (gpointer g_class);
140 static void     gst_avimux_class_init                (GstAviMuxClass *klass);
141 static void     gst_avimux_init                      (GstAviMux      *avimux);
142
143 static void     gst_avimux_loop                      (GstElement     *element);
144 static gboolean gst_avimux_handle_event              (GstPad         *pad,
145                                                       GstEvent       *event);
146 static GstPad*  gst_avimux_request_new_pad           (GstElement     *element,
147                                                       GstPadTemplate *templ,
148                                                       const gchar    *name);
149 static void     gst_avimux_set_property              (GObject        *object,
150                                                       guint           prop_id,
151                                                       const GValue   *value,
152                                                       GParamSpec     *pspec);
153 static void     gst_avimux_get_property              (GObject        *object,
154                                                       guint           prop_id,
155                                                       GValue         *value,
156                                                       GParamSpec     *pspec);
157 static GstElementStateReturn gst_avimux_change_state (GstElement     *element);
158
159 static GstElementClass *parent_class = NULL;
160 /*static guint gst_avimux_signals[LAST_SIGNAL] = { 0 }; */
161
162 GType
163 gst_avimux_get_type (void) 
164 {
165   static GType avimux_type = 0;
166
167   if (!avimux_type) {
168     static const GTypeInfo avimux_info = {
169       sizeof(GstAviMuxClass),      
170       gst_avimux_base_init,
171       NULL,
172       (GClassInitFunc)gst_avimux_class_init,
173       NULL,
174       NULL,
175       sizeof(GstAviMux),
176       0,
177       (GInstanceInitFunc)gst_avimux_init,
178     };
179     avimux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviMux", &avimux_info, 0);
180   }
181   return avimux_type;
182 }
183
184 static void
185 gst_avimux_base_init (gpointer g_class)
186 {
187   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
188   static GstElementDetails gst_avimux_details = GST_ELEMENT_DETAILS (
189     "Avi multiplexer",
190     "Codec/Muxer",
191     "Muxes audio and video into an avi stream",
192     "Ronald Bultje <rbultje@ronald.bitfreak.net>"
193   );
194
195   gst_element_class_add_pad_template (element_class,
196       gst_static_pad_template_get (&src_factory));
197   gst_element_class_add_pad_template (element_class,
198       gst_static_pad_template_get (&audio_sink_factory));
199   gst_element_class_add_pad_template (element_class,
200       gst_static_pad_template_get (&video_sink_factory));
201
202   gst_element_class_set_details (element_class, &gst_avimux_details);
203 }
204
205 static void
206 gst_avimux_class_init (GstAviMuxClass *klass) 
207 {
208   GObjectClass *gobject_class;
209   GstElementClass *gstelement_class;
210
211   gobject_class = (GObjectClass*)klass;
212   gstelement_class = (GstElementClass*)klass;
213
214   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
215
216   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BIGFILE,
217     g_param_spec_boolean("bigfile","Bigfile Support",
218                          "Support for openDML-2.0 (big) AVI files",
219     0,G_PARAM_READWRITE));
220
221   gstelement_class->request_new_pad = gst_avimux_request_new_pad;
222
223   gstelement_class->change_state = gst_avimux_change_state;
224
225   gstelement_class->get_property = gst_avimux_get_property;
226   gstelement_class->set_property = gst_avimux_set_property;
227 }
228
229 static const GstEventMask *
230 gst_avimux_get_event_masks (GstPad *pad)
231 {
232   static const GstEventMask gst_avimux_sink_event_masks[] = {
233     { GST_EVENT_EOS, 0 },
234     { 0, }
235   };
236
237   return gst_avimux_sink_event_masks;
238 }
239
240 static void 
241 gst_avimux_init (GstAviMux *avimux) 
242 {
243   GstElementClass *klass = GST_ELEMENT_GET_CLASS (avimux);
244
245   avimux->srcpad = gst_pad_new_from_template (
246                   gst_element_class_get_pad_template (klass, "src"), "src");
247   gst_element_add_pad (GST_ELEMENT (avimux), avimux->srcpad);
248
249   GST_FLAG_SET (GST_ELEMENT(avimux), GST_ELEMENT_EVENT_AWARE);
250
251   avimux->audiosinkpad = NULL;
252   avimux->audio_pad_connected = FALSE;
253   avimux->videosinkpad = NULL;
254   avimux->video_pad_connected = FALSE;
255
256   avimux->audio_buffer_queue = NULL;
257   avimux->video_buffer_queue = NULL;
258
259   avimux->num_frames = 0;
260
261   /* audio/video/AVI header initialisation */
262   memset(&(avimux->avi_hdr),0,sizeof(gst_riff_avih));
263   memset(&(avimux->vids_hdr),0,sizeof(gst_riff_strh));
264   memset(&(avimux->vids),0,sizeof(gst_riff_strf_vids));
265   memset(&(avimux->auds_hdr),0,sizeof(gst_riff_strh));
266   memset(&(avimux->auds),0,sizeof(gst_riff_strf_auds));
267   avimux->vids_hdr.type = GST_MAKE_FOURCC('v','i','d','s');
268   avimux->vids_hdr.rate = 1000000;
269   avimux->avi_hdr.max_bps = 10000000;
270   avimux->auds_hdr.type = GST_MAKE_FOURCC('a','u','d','s');
271   avimux->vids_hdr.quality = 0xFFFFFFFF;
272   avimux->auds_hdr.quality = 0xFFFFFFFF;
273
274   avimux->idx = NULL;
275
276   avimux->write_header = TRUE;
277
278   avimux->enable_large_avi = TRUE;
279
280   gst_element_set_loop_function(GST_ELEMENT(avimux), gst_avimux_loop);
281 }
282
283 static GstPadLinkReturn
284 gst_avimux_vidsinkconnect (GstPad *pad, const GstCaps *vscaps)
285 {
286   GstAviMux *avimux;
287   GstStructure *structure;
288   const gchar* mimetype;
289   gdouble fps = 0.;
290   gboolean ret;
291
292   avimux = GST_AVIMUX (gst_pad_get_parent (pad));
293
294   GST_DEBUG ("avimux: video sinkconnect triggered on %s",
295              gst_pad_get_name (pad));
296
297   structure = gst_caps_get_structure (vscaps, 0);
298   mimetype = gst_structure_get_name (structure);
299
300   /* global */
301   avimux->vids.size        = sizeof(gst_riff_strf_vids);
302   avimux->vids.planes      = 1;
303   ret = gst_structure_get_int (structure, "width", &avimux->vids.width);
304   ret &= gst_structure_get_int (structure, "height", &avimux->vids.height);
305   ret &= gst_structure_get_double (structure, "framerate", &fps);
306   if (!ret) return GST_PAD_LINK_REFUSED;
307
308   if (fps != 0.)
309     avimux->vids_hdr.scale = avimux->vids_hdr.rate / fps;
310
311   if (!strcmp (mimetype, "video/x-raw-yuv")) {
312     guint32 format;
313
314     gst_structure_get_fourcc (structure, "format", &format);
315     avimux->vids.compression = format;
316     switch (format)
317     {
318       case GST_MAKE_FOURCC('Y','U','Y','2'):
319         avimux->vids.bit_cnt     = 16;
320         break;
321       case GST_MAKE_FOURCC('I','4','2','0'):
322         avimux->vids.bit_cnt     = 12;
323         break;
324     }
325   } else {
326     avimux->vids.bit_cnt = 24;
327     avimux->vids.compression = 0;
328
329     /* find format */
330     if (!strcmp (mimetype, "video/x-huffyuv")) {
331       avimux->vids.compression = GST_MAKE_FOURCC('H','F','Y','U');
332     } else if (!strcmp (mimetype, "video/x-jpeg")) {
333       avimux->vids.compression = GST_MAKE_FOURCC('M','J','P','G');
334     } else if (!strcmp (mimetype, "video/x-divx")) {
335       gint divxversion;
336       gst_structure_get_int (structure, "divxversion", &divxversion);
337       switch (divxversion) {
338         case 3:
339           avimux->vids.compression = GST_MAKE_FOURCC('D','I','V','3');
340           break;
341         case 4:
342           avimux->vids.compression = GST_MAKE_FOURCC('D','I','V','X');
343           break;
344         case 5:
345           avimux->vids.compression = GST_MAKE_FOURCC('D','X','5','0');
346             break;
347       }
348     } else if (!strcmp (mimetype, "video/x-xvid")) {
349       avimux->vids.compression = GST_MAKE_FOURCC('X','V','I','D');
350     } else if (!strcmp (mimetype, "video/x-3ivx")) {
351       avimux->vids.compression = GST_MAKE_FOURCC('3','I','V','2');
352     } else if (!strcmp (mimetype, "video/x-msmpeg")) {
353       gint msmpegversion;
354       gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
355       switch (msmpegversion) {
356         case 41:
357           avimux->vids.compression = GST_MAKE_FOURCC('M','P','G','4');
358           break;
359         case 42:
360           avimux->vids.compression = GST_MAKE_FOURCC('M','P','4','2');
361           break;
362         case 43:
363           avimux->vids.compression = GST_MAKE_FOURCC('M','P','4','3');
364           break;
365       }
366     } else if (!strcmp (mimetype, "video/x-dv")) {
367       avimux->vids.compression = GST_MAKE_FOURCC('D','V','S','D');
368     } else if (!strcmp (mimetype, "video/x-h263")) {
369       avimux->vids.compression = GST_MAKE_FOURCC('H','2','6','3');
370     } else if (!strcmp (mimetype, "video/mpeg")) {
371       avimux->vids.compression = GST_MAKE_FOURCC('M','P','E','G');
372     }
373
374     if (!avimux->vids.compression) {
375       return GST_PAD_LINK_DELAYED;
376     }
377   }
378
379   avimux->vids_hdr.fcc_handler = avimux->vids.compression;
380   avimux->vids.image_size = avimux->vids.height * avimux->vids.width;
381   avimux->avi_hdr.width = avimux->vids.width;
382   avimux->avi_hdr.height = avimux->vids.height;
383   avimux->avi_hdr.us_frame = avimux->vids_hdr.scale;
384   return GST_PAD_LINK_OK;
385 }
386
387 static GstPadLinkReturn
388 gst_avimux_audsinkconnect (GstPad *pad, const GstCaps *vscaps)
389 {
390   GstAviMux *avimux;
391   GstStructure *structure;
392   const gchar* mimetype;
393   int i;
394
395   avimux = GST_AVIMUX (gst_pad_get_parent (pad));
396
397   GST_DEBUG ("avimux: audio sinkconnect triggered on %s",
398              gst_pad_get_name (pad));
399
400   structure = gst_caps_get_structure (vscaps, 0);
401   mimetype = gst_structure_get_name (structure);
402
403   /* we want these for all */
404   gst_structure_get_int (structure, "channels", &i);
405   avimux->auds.channels = i;
406   gst_structure_get_int (structure, "rate", &i);
407   avimux->auds.rate = i;
408
409   if (!strcmp (mimetype, "audio/x-raw-int")) {
410     avimux->auds.format      = GST_RIFF_WAVE_FORMAT_PCM;
411
412     gst_structure_get_int (structure, "width", &i);
413     avimux->auds.blockalign = i;
414     gst_structure_get_int (structure, "depth", &i);
415     avimux->auds.size = i;
416
417     /* set some more info straight */
418     avimux->auds.blockalign /= 8;
419     avimux->auds.blockalign *= avimux->auds.channels;
420     avimux->auds.av_bps = avimux->auds.blockalign * avimux->auds.rate;
421   } else if (!strcmp (mimetype, "audio/mpeg") ||
422              !strcmp (mimetype, "audio/x-vorbis") ||
423              !strcmp (mimetype, "audio/x-ac3")) {
424     avimux->auds.format = 0;
425
426     if (!strcmp (mimetype, "audio/mpeg")) {
427       gint layer = 3;
428       gst_structure_get_int (structure, "layer", &layer);
429       switch (layer) {
430         case 3:
431           avimux->auds.format = GST_RIFF_WAVE_FORMAT_MPEGL3;
432           break;
433         case 1: case 2:
434           avimux->auds.format = GST_RIFF_WAVE_FORMAT_MPEGL12;
435           break;
436       }
437     } else if (!strcmp (mimetype, "audio/x-vorbis")) {
438       avimux->auds.format = GST_RIFF_WAVE_FORMAT_VORBIS3;
439     } else if (!strcmp (mimetype, "audio/x-ac3")) {
440       avimux->auds.format = GST_RIFF_WAVE_FORMAT_A52;
441     }
442
443     avimux->auds.blockalign = 1;
444     avimux->auds.av_bps = 0;
445     avimux->auds.size = 16;
446
447     if (!avimux->auds.format) {
448       return GST_PAD_LINK_REFUSED;
449     }
450   }
451
452   avimux->auds_hdr.rate = avimux->auds.blockalign * avimux->auds.rate; 
453   avimux->auds_hdr.samplesize = avimux->auds.blockalign;
454   avimux->auds_hdr.scale = avimux->auds.blockalign;
455   return GST_PAD_LINK_OK;
456 }
457
458 static void
459 gst_avimux_pad_link (GstPad   *pad,
460                      GstPad   *peer,
461                      gpointer  data)
462 {
463   GstAviMux *avimux = GST_AVIMUX(data);
464   const gchar *padname = gst_pad_get_name (pad);
465
466   if (pad == avimux->audiosinkpad)
467   {
468     avimux->audio_pad_connected = TRUE;
469   }
470   else if (pad == avimux->videosinkpad)
471   {
472     avimux->video_pad_connected = TRUE;
473   }
474   else
475   {
476     g_warning("Unknown padname '%s'", padname);
477     return;
478   }
479
480   GST_DEBUG ("pad '%s' connected", padname);
481 }
482
483 static void
484 gst_avimux_pad_unlink (GstPad   *pad,
485                        GstPad   *peer,
486                        gpointer  data)
487 {
488   GstAviMux *avimux = GST_AVIMUX(data);
489   const gchar *padname = gst_pad_get_name (pad);
490
491   if (pad == avimux->audiosinkpad)
492   {
493     avimux->audio_pad_connected = FALSE;
494     avimux->audiosinkpad = NULL;
495   }
496   else if (pad == avimux->videosinkpad)
497   {
498     avimux->video_pad_connected = FALSE;
499     avimux->videosinkpad = NULL;
500   }
501   else
502   {
503     g_warning("Unknown padname '%s'", padname);
504     return;
505   }
506
507   GST_DEBUG ("pad '%s' unlinked", padname);
508 }
509
510 static GstPad*
511 gst_avimux_request_new_pad (GstElement     *element,
512                             GstPadTemplate *templ,
513                             const gchar    *req_name)
514 {
515   GstAviMux *avimux;
516   GstPad *newpad;
517   GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
518
519   g_return_val_if_fail (templ != NULL, NULL);
520
521   if (templ->direction != GST_PAD_SINK) {
522     g_warning ("avimux: request pad that is not a SINK pad\n");
523     return NULL;
524   }
525
526   g_return_val_if_fail (GST_IS_AVIMUX (element), NULL);
527
528   avimux = GST_AVIMUX (element);
529
530   if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
531     g_return_val_if_fail(avimux->audiosinkpad == NULL, NULL);
532     newpad = gst_pad_new_from_template (templ, "audio_00");
533     gst_pad_set_link_function (newpad, gst_avimux_audsinkconnect);
534     avimux->audiosinkpad = newpad;
535   }
536   else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
537     g_return_val_if_fail(avimux->videosinkpad == NULL, NULL);
538     newpad = gst_pad_new_from_template (templ, "video_00");
539     gst_pad_set_link_function (newpad, gst_avimux_vidsinkconnect);
540     avimux->videosinkpad = newpad;
541   }
542   else {
543     g_warning ("avimux: this is not our template!\n");
544     return NULL;
545   }
546
547   g_signal_connect(newpad, "linked",
548     G_CALLBACK(gst_avimux_pad_link), (gpointer)avimux);
549   g_signal_connect(newpad, "unlinked",
550     G_CALLBACK(gst_avimux_pad_unlink), (gpointer)avimux);
551   gst_element_add_pad (element, newpad);
552   gst_pad_set_event_mask_function(newpad, gst_avimux_get_event_masks);
553   
554   return newpad;
555 }
556
557 /* maybe some of these functions should be moved to riff.h? */
558
559 /* DISCLAIMER: this function is ugly. So be it (i.e. it makes the rest easier) */
560
561 static GstBuffer *
562 gst_avimux_riff_get_avi_header (GstAviMux *avimux)
563 {
564   GstBuffer *buffer;
565   guint8 *buffdata;
566   guint16 temp16;
567   guint32 temp32;
568
569   buffer = gst_buffer_new();
570
571   /* first, let's see what actually needs to be in the buffer */
572   GST_BUFFER_SIZE(buffer) = 0;
573   GST_BUFFER_SIZE(buffer) += 32 + sizeof(gst_riff_avih); /* avi header */
574   if (avimux->video_pad_connected)
575   { /* we have video */
576     GST_BUFFER_SIZE(buffer) += 28 + sizeof(gst_riff_strh) + sizeof(gst_riff_strf_vids); /* vid hdr */
577     GST_BUFFER_SIZE(buffer) += 24; /* odml header */
578   }
579   if (avimux->audio_pad_connected)
580   { /* we have audio */
581     GST_BUFFER_SIZE(buffer) += 28 + sizeof(gst_riff_strh) + sizeof(gst_riff_strf_auds); /* aud hdr */
582   }
583   /* this is the "riff size" */
584   avimux->header_size = GST_BUFFER_SIZE(buffer);
585   GST_BUFFER_SIZE(buffer) += 12; /* avi data header */
586
587   /* allocate the buffer */
588   buffdata = GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(buffer));
589
590   /* avi header metadata */
591   memcpy(buffdata, "RIFF", 4); buffdata += 4;
592   temp32 = LE_FROM_GUINT32(avimux->header_size + avimux->idx_size + avimux->data_size);
593   memcpy(buffdata, &temp32, 4); buffdata += 4;
594   memcpy(buffdata, "AVI ", 4); buffdata += 4;
595   memcpy(buffdata, "LIST", 4); buffdata += 4;
596   temp32 = LE_FROM_GUINT32(avimux->header_size - 4*5);
597   memcpy(buffdata, &temp32, 4); buffdata += 4;
598   memcpy(buffdata, "hdrl", 4); buffdata += 4;
599   memcpy(buffdata, "avih", 4); buffdata += 4;
600   temp32 = LE_FROM_GUINT32(sizeof(gst_riff_avih));
601   memcpy(buffdata, &temp32, 4); buffdata += 4;
602   /* the AVI header itself */
603   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.us_frame);
604   memcpy(buffdata, &temp32, 4); buffdata += 4;
605   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.max_bps);
606   memcpy(buffdata, &temp32, 4); buffdata += 4;
607   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.pad_gran);
608   memcpy(buffdata, &temp32, 4); buffdata += 4;
609   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.flags);
610   memcpy(buffdata, &temp32, 4); buffdata += 4;
611   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.tot_frames);
612   memcpy(buffdata, &temp32, 4); buffdata += 4;
613   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.init_frames);
614   memcpy(buffdata, &temp32, 4); buffdata += 4;
615   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.streams);
616   memcpy(buffdata, &temp32, 4); buffdata += 4;
617   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.bufsize);
618   memcpy(buffdata, &temp32, 4); buffdata += 4;
619   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.width);
620   memcpy(buffdata, &temp32, 4); buffdata += 4;
621   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.height);
622   memcpy(buffdata, &temp32, 4); buffdata += 4;
623   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.scale);
624   memcpy(buffdata, &temp32, 4); buffdata += 4;
625   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.rate);
626   memcpy(buffdata, &temp32, 4); buffdata += 4;
627   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.start);
628   memcpy(buffdata, &temp32, 4); buffdata += 4;
629   temp32 = LE_FROM_GUINT32(avimux->avi_hdr.length);
630   memcpy(buffdata, &temp32, 4); buffdata += 4;
631
632   if (avimux->video_pad_connected)
633   {
634     /* video header metadata */
635     memcpy(buffdata, "LIST", 4); buffdata += 4;
636     temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strh) + sizeof(gst_riff_strf_vids) + 4*5);
637     memcpy(buffdata, &temp32, 4); buffdata += 4;
638     memcpy(buffdata, "strl", 4); buffdata += 4;
639     /* generic header */
640     memcpy(buffdata, "strh", 4); buffdata += 4;
641     temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strh));
642     memcpy(buffdata, &temp32, 4); buffdata += 4;
643     /* the actual header */
644     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.type);
645     memcpy(buffdata, &temp32, 4); buffdata += 4;
646     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.fcc_handler);
647     memcpy(buffdata, &temp32, 4); buffdata += 4;
648     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.flags);
649     memcpy(buffdata, &temp32, 4); buffdata += 4;
650     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.priority);
651     memcpy(buffdata, &temp32, 4); buffdata += 4;
652     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.init_frames);
653     memcpy(buffdata, &temp32, 4); buffdata += 4;
654     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.scale);
655     memcpy(buffdata, &temp32, 4); buffdata += 4;
656     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.rate);
657     memcpy(buffdata, &temp32, 4); buffdata += 4;
658     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.start);
659     memcpy(buffdata, &temp32, 4); buffdata += 4;
660     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.length);
661     memcpy(buffdata, &temp32, 4); buffdata += 4;
662     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.bufsize);
663     memcpy(buffdata, &temp32, 4); buffdata += 4;
664     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.quality);
665     memcpy(buffdata, &temp32, 4); buffdata += 4;
666     temp32 = LE_FROM_GUINT32(avimux->vids_hdr.samplesize);
667     memcpy(buffdata, &temp32, 4); buffdata += 4;
668     /* the video header */
669     memcpy(buffdata, "strf", 4); buffdata += 4;
670     temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strf_vids));
671     memcpy(buffdata, &temp32, 4); buffdata += 4;
672     /* the actual header */
673     temp32 = LE_FROM_GUINT32(avimux->vids.size);
674     memcpy(buffdata, &temp32, 4); buffdata += 4;
675     temp32 = LE_FROM_GUINT32(avimux->vids.width);
676     memcpy(buffdata, &temp32, 4); buffdata += 4;
677     temp32 = LE_FROM_GUINT32(avimux->vids.height);
678     memcpy(buffdata, &temp32, 4); buffdata += 4;
679     temp16 = LE_FROM_GUINT16(avimux->vids.planes);
680     memcpy(buffdata, &temp16, 2); buffdata += 2;
681     temp16 = LE_FROM_GUINT16(avimux->vids.bit_cnt);
682     memcpy(buffdata, &temp16, 2); buffdata += 2;
683     temp32 = LE_FROM_GUINT32(avimux->vids.compression);
684     memcpy(buffdata, &temp32, 4); buffdata += 4;
685     temp32 = LE_FROM_GUINT32(avimux->vids.image_size);
686     memcpy(buffdata, &temp32, 4); buffdata += 4;
687     temp32 = LE_FROM_GUINT32(avimux->vids.xpels_meter);
688     memcpy(buffdata, &temp32, 4); buffdata += 4;
689     temp32 = LE_FROM_GUINT32(avimux->vids.ypels_meter);
690     memcpy(buffdata, &temp32, 4); buffdata += 4;
691     temp32 = LE_FROM_GUINT32(avimux->vids.num_colors);
692     memcpy(buffdata, &temp32, 4); buffdata += 4;
693     temp32 = LE_FROM_GUINT32(avimux->vids.imp_colors);
694     memcpy(buffdata, &temp32, 4); buffdata += 4;
695   }
696
697   if (avimux->audio_pad_connected)
698   {
699     /* audio header */
700     memcpy(buffdata, "LIST", 4); buffdata += 4;
701     temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strh) + sizeof(gst_riff_strf_auds) + 4*5);
702     memcpy(buffdata, &temp32, 4); buffdata += 4;
703     memcpy(buffdata, "strl", 4); buffdata += 4;
704     /* generic header */
705     memcpy(buffdata, "strh", 4); buffdata += 4;
706     temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strh));
707     memcpy(buffdata, &temp32, 4); buffdata += 4;
708     /* the actual header */
709     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.type);
710     memcpy(buffdata, &temp32, 4); buffdata += 4;
711     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.fcc_handler);
712     memcpy(buffdata, &temp32, 4); buffdata += 4;
713     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.flags);
714     memcpy(buffdata, &temp32, 4); buffdata += 4;
715     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.priority);
716     memcpy(buffdata, &temp32, 4); buffdata += 4;
717     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.init_frames);
718     memcpy(buffdata, &temp32, 4); buffdata += 4;
719     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.scale);
720     memcpy(buffdata, &temp32, 4); buffdata += 4;
721     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.rate);
722     memcpy(buffdata, &temp32, 4); buffdata += 4;
723     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.start);
724     memcpy(buffdata, &temp32, 4); buffdata += 4;
725     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.length);
726     memcpy(buffdata, &temp32, 4); buffdata += 4;
727     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.bufsize);
728     memcpy(buffdata, &temp32, 4); buffdata += 4;
729     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.quality);
730     memcpy(buffdata, &temp32, 4); buffdata += 4;
731     temp32 = LE_FROM_GUINT32(avimux->auds_hdr.samplesize);
732     memcpy(buffdata, &temp32, 4); buffdata += 4;
733     /* the audio header */
734     memcpy(buffdata, "strf", 4); buffdata += 4;
735     temp32 = LE_FROM_GUINT32(sizeof(gst_riff_strf_auds));
736     memcpy(buffdata, &temp32, 4); buffdata += 4;
737     /* the actual header */
738     temp16 = LE_FROM_GUINT16(avimux->auds.format);
739     memcpy(buffdata, &temp16, 2); buffdata += 2;
740     temp16 = LE_FROM_GUINT16(avimux->auds.channels);
741     memcpy(buffdata, &temp16, 2); buffdata += 2;
742     temp32 = LE_FROM_GUINT32(avimux->auds.rate);
743     memcpy(buffdata, &temp32, 4); buffdata += 4;
744     temp32 = LE_FROM_GUINT32(avimux->auds.av_bps);
745     memcpy(buffdata, &temp32, 4); buffdata += 4;
746     temp16 = LE_FROM_GUINT16(avimux->auds.blockalign);
747     memcpy(buffdata, &temp16, 2); buffdata += 2;
748     temp16 = LE_FROM_GUINT16(avimux->auds.size);
749     memcpy(buffdata, &temp16, 2); buffdata += 2;
750   }
751
752   if (avimux->video_pad_connected)
753   {
754     /* odml header */
755     memcpy(buffdata, "LIST", 4); buffdata += 4;
756     temp32 = LE_FROM_GUINT32(sizeof(guint32)+4*3);
757     memcpy(buffdata, &temp32, 4); buffdata += 4;
758     memcpy(buffdata, "odml", 4); buffdata += 4;
759     memcpy(buffdata, "dmlh", 4); buffdata += 4;
760     temp32 = LE_FROM_GUINT32(sizeof(guint32));
761     memcpy(buffdata, &temp32, 4); buffdata += 4;
762     temp32 = LE_FROM_GUINT32(avimux->total_frames);
763     memcpy(buffdata, &temp32, 4); buffdata += 4;
764   }
765
766   /* avi data header */
767   memcpy(buffdata, "LIST", 4); buffdata += 4;
768   temp32 = LE_FROM_GUINT32(avimux->data_size);
769   memcpy(buffdata, &temp32, 4); buffdata += 4;
770   memcpy(buffdata, "movi", 4);
771
772   return buffer;
773 }
774
775 static GstBuffer *
776 gst_avimux_riff_get_avix_header (guint32 datax_size)
777 {
778   GstBuffer *buffer;
779   guint8 *buffdata;
780   guint32 temp32;
781
782   buffer = gst_buffer_new();
783   GST_BUFFER_SIZE(buffer) = 24;
784   buffdata = GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(buffer));
785
786   memcpy(buffdata, "LIST", 4); buffdata += 4;
787   temp32 = LE_FROM_GUINT32(datax_size+4*4);
788   memcpy(buffdata, &temp32, 4); buffdata += 4;
789   memcpy(buffdata, "AVIX", 4); buffdata += 4;
790   memcpy(buffdata, "LIST", 4); buffdata += 4;
791   temp32 = LE_FROM_GUINT32(datax_size);
792   memcpy(buffdata, &temp32, 4); buffdata += 4;
793   memcpy(buffdata, "movi", 4);
794
795   return buffer;
796 }
797
798 static GstBuffer *
799 gst_avimux_riff_get_video_header (guint32 video_frame_size)
800 {
801   GstBuffer *buffer;
802   guint32 temp32;
803
804   buffer = gst_buffer_new();
805   GST_BUFFER_DATA(buffer) = g_malloc(8);
806   GST_BUFFER_SIZE(buffer) = 8;
807   memcpy(GST_BUFFER_DATA(buffer), "00db", 4);
808   temp32 = LE_FROM_GUINT32(video_frame_size);
809   memcpy(GST_BUFFER_DATA(buffer)+4, &temp32, 4);
810
811   return buffer;
812 }
813
814 static GstBuffer *
815 gst_avimux_riff_get_audio_header (guint32 audio_sample_size)
816 {
817   GstBuffer *buffer;
818   guint32 temp32;
819
820   buffer = gst_buffer_new();
821   GST_BUFFER_DATA(buffer) = g_malloc(8);
822   GST_BUFFER_SIZE(buffer) = 8;
823   memcpy(GST_BUFFER_DATA(buffer), "01wb", 4);
824   temp32 = LE_FROM_GUINT32(audio_sample_size);
825   memcpy(GST_BUFFER_DATA(buffer)+4, &temp32, 4);
826
827   return buffer;
828 }
829
830 /* some other usable functions (thankyou xawtv ;-) ) */
831
832 static void
833 gst_avimux_add_index (GstAviMux *avimux, guchar *code, guint32 flags, guint32 size)
834 {
835   if (avimux->idx_index == avimux->idx_count)
836   {
837     avimux->idx_count += 256;
838     avimux->idx = realloc(avimux->idx, avimux->idx_count*sizeof(gst_riff_index_entry));
839   }
840   memcpy(&(avimux->idx[avimux->idx_index].id), code, 4);
841   avimux->idx[avimux->idx_index].flags = LE_FROM_GUINT32(flags);
842   avimux->idx[avimux->idx_index].offset = LE_FROM_GUINT32(avimux->idx_offset);
843   avimux->idx[avimux->idx_index].size = LE_FROM_GUINT32(size);
844   avimux->idx_index++;
845 }
846
847 static void
848 gst_avimux_write_index (GstAviMux *avimux)
849 {
850   GstBuffer *buffer;
851   guint32 temp32;
852
853   buffer = gst_buffer_new();
854   GST_BUFFER_SIZE(buffer) = 8;
855   GST_BUFFER_DATA(buffer) = g_malloc(8);
856   memcpy(GST_BUFFER_DATA(buffer), "idx1", 4);
857   temp32 = LE_FROM_GUINT32(avimux->idx_index * sizeof(gst_riff_index_entry)); 
858   memcpy(GST_BUFFER_DATA(buffer)+4, &temp32, 4);
859   gst_pad_push(avimux->srcpad, GST_DATA (buffer));
860
861   buffer = gst_buffer_new();
862   GST_BUFFER_SIZE(buffer) = avimux->idx_index * sizeof(gst_riff_index_entry);
863   GST_BUFFER_DATA(buffer) = (unsigned char*) avimux->idx;
864   avimux->idx = NULL; /* will be free()'ed by gst_buffer_unref() */
865   avimux->total_data += GST_BUFFER_SIZE(buffer);
866   gst_pad_push(avimux->srcpad, GST_DATA (buffer));
867
868   avimux->idx_size += avimux->idx_index * sizeof(gst_riff_index_entry) + 8;
869
870   /* update header */
871   avimux->avi_hdr.flags |= GST_RIFF_AVIH_HASINDEX;
872 }
873
874 static void
875 gst_avimux_bigfile(GstAviMux *avimux, gboolean last)
876 {
877   GstBuffer *header;
878   GstEvent *event;
879     
880   if (avimux->is_bigfile)
881   {
882     /* sarch back */
883     event = gst_event_new_seek (GST_FORMAT_BYTES | 
884                                 GST_SEEK_METHOD_SET | 
885                                 GST_SEEK_FLAG_FLUSH, 
886                                 avimux->avix_start);
887     /* if the event succeeds */
888     gst_pad_push(avimux->srcpad, GST_DATA(event));
889
890     /* rewrite AVIX header */
891     header = gst_avimux_riff_get_avix_header(avimux->datax_size);
892     gst_pad_push(avimux->srcpad, GST_DATA (header));
893
894     /* go back to current location */
895     event = gst_event_new_seek (GST_FORMAT_BYTES | 
896                                 GST_SEEK_METHOD_SET |
897                                 GST_SEEK_FLAG_FLUSH, 
898                                 avimux->total_data);
899     gst_pad_push(avimux->srcpad, GST_DATA(event));
900   }
901   avimux->avix_start = avimux->total_data;
902
903   if (last)
904     return;
905
906   avimux->is_bigfile = TRUE;
907   avimux->numx_frames = 0;
908   avimux->datax_size = 0;
909
910   header = gst_avimux_riff_get_avix_header(0);
911   avimux->total_data += GST_BUFFER_SIZE(header);
912   gst_pad_push(avimux->srcpad, GST_DATA (header));
913 }
914
915 /* enough header blabla now, let's go on to actually writing the headers */
916
917 static void
918 gst_avimux_start_file (GstAviMux *avimux)
919 {
920   GstBuffer *header;
921
922   avimux->total_data = 0;
923   avimux->total_frames = 0;
924   avimux->data_size = 4; /* ? */
925   avimux->datax_size = 0;
926   avimux->num_frames = 0;
927   avimux->numx_frames = 0;
928   avimux->audio_size = 0;
929   avimux->audio_time = 0;
930   avimux->avix_start = 0;
931
932   avimux->idx_index = 0;
933   avimux->idx_offset = 0; /* see 10 lines below */
934   avimux->idx_size = 0;
935   avimux->idx_count = 0;
936   avimux->idx = NULL;
937
938   /* header */
939   avimux->avi_hdr.streams = (avimux->video_pad_connected?1:0) + (avimux->audio_pad_connected?1:0);
940   avimux->is_bigfile = FALSE;
941
942   header = gst_avimux_riff_get_avi_header(avimux);
943   avimux->total_data += GST_BUFFER_SIZE(header);
944   avimux->idx_offset = avimux->total_data;
945   gst_pad_push(avimux->srcpad, GST_DATA (header));
946
947   avimux->write_header = FALSE;
948   avimux->restart = FALSE;
949 }
950
951 static void
952 gst_avimux_stop_file (GstAviMux *avimux)
953 {
954   GstEvent *event;
955   GstBuffer *header;
956
957   /* if bigfile, rewrite header, else write indexes */
958   if (avimux->video_pad_connected)
959   {
960     if (avimux->is_bigfile)
961     {
962       gst_avimux_bigfile(avimux, TRUE);
963       avimux->idx_size = 0;
964     }
965     else
966     {
967       gst_avimux_write_index(avimux);
968     }
969   }
970
971   /* statistics/total_frames/... */
972   avimux->avi_hdr.tot_frames = avimux->num_frames;
973   if (avimux->video_pad_connected) {
974     avimux->vids_hdr.length = avimux->num_frames;
975   }
976   if (avimux->audio_pad_connected) {
977     avimux->auds_hdr.length = (avimux->audio_time * avimux->auds.rate)/GST_SECOND;
978   }
979
980   /* set rate and everything having to do with that */
981   avimux->avi_hdr.max_bps = 0;
982   if (avimux->audio_pad_connected) {
983     /* calculate bps if needed */
984     if (!avimux->auds.av_bps) {
985       if (avimux->audio_time) {
986         avimux->auds_hdr.rate = (GST_SECOND * avimux->audio_size) / avimux->audio_time;
987       } else {
988         GST_ELEMENT_ERROR (avimux, STREAM, MUX,
989                            (_("No or invalid input audio, AVI stream will be corrupt.")), (NULL));
990         avimux->auds_hdr.rate = 0;
991       }
992       avimux->auds.av_bps = avimux->auds_hdr.rate * avimux->auds_hdr.scale;
993     }
994     avimux->avi_hdr.max_bps += avimux->auds.av_bps;
995   }
996   if (avimux->video_pad_connected) {
997     avimux->avi_hdr.max_bps += ((avimux->vids.bit_cnt+7)/8) *
998                                 (1000000. / avimux->avi_hdr.us_frame) *
999                                 avimux->vids.image_size;
1000   }
1001
1002   /* seek and rewrite the header */
1003   header = gst_avimux_riff_get_avi_header(avimux);
1004   event = gst_event_new_seek (GST_FORMAT_BYTES | 
1005                               GST_SEEK_METHOD_SET, 0);
1006   gst_pad_push(avimux->srcpad, GST_DATA(event));
1007   gst_pad_push(avimux->srcpad, GST_DATA (header));
1008   event = gst_event_new_seek (GST_FORMAT_BYTES |
1009                               GST_SEEK_METHOD_SET, avimux->total_data);
1010   gst_pad_push(avimux->srcpad, GST_DATA(event));
1011
1012   avimux->write_header = TRUE;
1013 }
1014
1015 static void
1016 gst_avimux_restart_file (GstAviMux *avimux)
1017 {
1018   GstEvent *event;
1019
1020   gst_avimux_stop_file(avimux);
1021
1022   event = gst_event_new(GST_EVENT_EOS);
1023   gst_pad_push(avimux->srcpad, GST_DATA(event));
1024
1025   gst_avimux_start_file(avimux);
1026 }
1027
1028 /* handle events (search) */
1029 static gboolean
1030 gst_avimux_handle_event (GstPad *pad, GstEvent *event)
1031 {
1032   GstAviMux *avimux;
1033   GstEventType type;
1034
1035   avimux = GST_AVIMUX (gst_pad_get_parent (pad));
1036   
1037   type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
1038
1039   switch (type) {
1040     case GST_EVENT_EOS:
1041       /* is this allright? */
1042       if (pad == avimux->videosinkpad) {
1043         avimux->video_pad_eos = TRUE;
1044       } else if (pad == avimux->audiosinkpad) {
1045         avimux->audio_pad_eos = TRUE;
1046       } else {
1047         g_warning("Unknown pad for EOS!");
1048       }
1049       break;
1050     default:
1051       break;
1052   }
1053
1054   return TRUE;
1055 }
1056
1057
1058 /* fill the internal queue for each available pad */
1059 static void
1060 gst_avimux_fill_queue (GstAviMux *avimux)
1061 {
1062   GstBuffer *buffer;
1063
1064   while (!avimux->audio_buffer_queue &&
1065           avimux->audiosinkpad &&
1066           avimux->audio_pad_connected &&
1067           GST_PAD_IS_USABLE(avimux->audiosinkpad) &&
1068          !avimux->audio_pad_eos)
1069   {
1070     buffer = GST_BUFFER (gst_pad_pull(avimux->audiosinkpad));
1071     if (GST_IS_EVENT(buffer)) {
1072       gst_avimux_handle_event(avimux->audiosinkpad, GST_EVENT(buffer));
1073     } else {
1074       avimux->audio_buffer_queue = buffer;
1075       break;
1076     }
1077   }
1078
1079   while (!avimux->video_buffer_queue &&
1080           avimux->videosinkpad &&
1081           avimux->video_pad_connected &&
1082           GST_PAD_IS_USABLE(avimux->videosinkpad) &&
1083          !avimux->video_pad_eos)
1084   {
1085     buffer = GST_BUFFER (gst_pad_pull(avimux->videosinkpad));
1086     if (GST_IS_EVENT(buffer)) {
1087       gst_avimux_handle_event(avimux->videosinkpad, GST_EVENT(buffer));
1088     } else {
1089       avimux->video_buffer_queue = buffer;
1090       break;
1091     }
1092   }
1093 }
1094
1095
1096 /* send extra 'padding' data */
1097 static void
1098 gst_avimux_send_pad_data (GstAviMux *avimux,
1099                           gulong     num_bytes)
1100 {
1101   GstBuffer *buffer;
1102
1103   buffer = gst_buffer_new();
1104   GST_BUFFER_SIZE(buffer) = num_bytes;
1105   GST_BUFFER_DATA(buffer) = g_malloc(num_bytes);
1106   memset(GST_BUFFER_DATA(buffer), 0, num_bytes);
1107
1108   gst_pad_push(avimux->srcpad, GST_DATA (buffer));
1109 }
1110
1111 /* do audio buffer */
1112 static void
1113 gst_avimux_do_audio_buffer (GstAviMux *avimux)
1114 {
1115   GstBuffer *data = avimux->audio_buffer_queue, *header;
1116   gulong total_size, pad_bytes = 0;
1117
1118   /* write a audio header + index entry */
1119   if (GST_BUFFER_SIZE(data) & 1) {
1120     pad_bytes = 2 - (GST_BUFFER_SIZE(data) & 1);
1121   }
1122   header = gst_avimux_riff_get_audio_header(GST_BUFFER_SIZE(data));
1123   total_size = GST_BUFFER_SIZE(header) + GST_BUFFER_SIZE(data) + pad_bytes;
1124
1125   if (avimux->is_bigfile)
1126   {
1127     avimux->datax_size += total_size;
1128   }
1129   else
1130   {
1131     avimux->data_size += total_size;
1132     avimux->audio_size += GST_BUFFER_SIZE(data);
1133     avimux->audio_time += GST_BUFFER_DURATION(data);
1134     gst_avimux_add_index(avimux, "01wb", 0x0, GST_BUFFER_SIZE(data));
1135   }
1136
1137   gst_pad_push(avimux->srcpad, GST_DATA (header));
1138   gst_pad_push(avimux->srcpad, GST_DATA (data));
1139   if (pad_bytes) {
1140     gst_avimux_send_pad_data(avimux, pad_bytes);
1141   }
1142   avimux->total_data += total_size;
1143   avimux->idx_offset += total_size;
1144
1145   avimux->audio_buffer_queue = NULL;
1146 }
1147
1148
1149 /* do video buffer */
1150 static void
1151 gst_avimux_do_video_buffer (GstAviMux *avimux)
1152 {
1153   GstBuffer *data = avimux->video_buffer_queue, *header;
1154   gulong total_size, pad_bytes = 0;
1155
1156   if (avimux->restart)
1157     gst_avimux_restart_file(avimux);
1158
1159   /* write a video header + index entry */
1160   if ((avimux->is_bigfile?avimux->datax_size:avimux->data_size)+GST_BUFFER_SIZE(data)>1024*1024*2000)
1161   {
1162     if (avimux->enable_large_avi)
1163       gst_avimux_bigfile(avimux, FALSE);
1164     else
1165       gst_avimux_restart_file(avimux);
1166   }
1167
1168   if (GST_BUFFER_SIZE(data) & 1) {
1169     pad_bytes = 2 - (GST_BUFFER_SIZE(data) & 1);
1170   }
1171   header = gst_avimux_riff_get_video_header(GST_BUFFER_SIZE(data));
1172   total_size = GST_BUFFER_SIZE(header) + GST_BUFFER_SIZE(data) + pad_bytes;
1173   avimux->total_frames++;
1174
1175   if (avimux->is_bigfile)
1176   {
1177     avimux->datax_size += total_size;
1178     avimux->numx_frames++;
1179   }
1180   else
1181   {
1182     guint flags = 0x2;
1183     if (GST_BUFFER_FLAG_IS_SET (data, GST_BUFFER_KEY_UNIT))
1184       flags |= 0x10;
1185     avimux->data_size += total_size;
1186     avimux->num_frames++;
1187     gst_avimux_add_index(avimux, "00db", flags, GST_BUFFER_SIZE(data));
1188   }
1189
1190   gst_pad_push(avimux->srcpad, GST_DATA (header));
1191   gst_pad_push(avimux->srcpad, GST_DATA (data));
1192   if (pad_bytes) {
1193     gst_avimux_send_pad_data(avimux, pad_bytes);
1194   }
1195   avimux->total_data += total_size;
1196   avimux->idx_offset += total_size;
1197
1198   avimux->video_buffer_queue = NULL;
1199 }
1200
1201
1202 /* take the oldest buffer in our internal queue and push-it */
1203 static gboolean
1204 gst_avimux_do_one_buffer (GstAviMux *avimux)
1205 {
1206   if (avimux->video_buffer_queue &&
1207       avimux->audio_buffer_queue)
1208   {
1209     if (GST_BUFFER_TIMESTAMP(avimux->video_buffer_queue) <=
1210         GST_BUFFER_TIMESTAMP(avimux->audio_buffer_queue))
1211       gst_avimux_do_video_buffer(avimux);
1212     else
1213       gst_avimux_do_audio_buffer(avimux);
1214   }
1215   else if (avimux->video_buffer_queue ||
1216            avimux->audio_buffer_queue)
1217   {
1218     if (avimux->video_buffer_queue)
1219       gst_avimux_do_video_buffer(avimux);
1220     else
1221       gst_avimux_do_audio_buffer(avimux);
1222   }
1223   else {
1224     /* simply finish off the file and send EOS */
1225     gst_avimux_stop_file(avimux);
1226     gst_pad_push(avimux->srcpad,
1227                  GST_DATA(gst_event_new(GST_EVENT_EOS)));
1228     gst_element_set_eos(GST_ELEMENT(avimux));
1229     return FALSE;
1230   }
1231
1232   return TRUE;
1233 }
1234
1235
1236 static void
1237 gst_avimux_loop (GstElement *element)
1238 {
1239   GstAviMux *avimux;
1240
1241   avimux = GST_AVIMUX(element);
1242
1243   /* first fill queue (some elements only set caps when
1244    * flowing data), then write header */
1245   gst_avimux_fill_queue(avimux);
1246   
1247   if (avimux->write_header)
1248     gst_avimux_start_file(avimux);
1249
1250   gst_avimux_do_one_buffer(avimux);
1251 }
1252
1253 static void
1254 gst_avimux_get_property (GObject    *object,
1255                          guint      prop_id,
1256                          GValue     *value,
1257                          GParamSpec *pspec)
1258 {
1259   GstAviMux *avimux;
1260
1261   /* it's not null if we got it, but it might not be ours */
1262   g_return_if_fail(GST_IS_AVIMUX(object));
1263   avimux = GST_AVIMUX(object);
1264
1265   switch (prop_id)
1266   {
1267     case ARG_BIGFILE:
1268       g_value_set_boolean(value, avimux->enable_large_avi);
1269       break;
1270     default:
1271       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1272       break;
1273   }
1274 }
1275
1276 static void
1277 gst_avimux_set_property (GObject      *object,
1278                          guint         prop_id,
1279                          const GValue *value,
1280                          GParamSpec   *pspec)
1281 {
1282   GstAviMux *avimux;
1283
1284   /* it's not null if we got it, but it might not be ours */
1285   g_return_if_fail(GST_IS_AVIMUX(object));
1286   avimux = GST_AVIMUX(object);
1287
1288   switch (prop_id)
1289   {
1290     case ARG_BIGFILE:
1291       avimux->enable_large_avi = g_value_get_boolean(value);
1292       break;
1293     default:
1294       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1295       break;
1296   }
1297 }
1298
1299 static GstElementStateReturn
1300 gst_avimux_change_state (GstElement *element)
1301 {
1302   GstAviMux *avimux;
1303   gint transition = GST_STATE_TRANSITION (element);
1304
1305   g_return_val_if_fail(GST_IS_AVIMUX(element), GST_STATE_FAILURE);
1306   
1307   avimux = GST_AVIMUX(element);
1308
1309   switch (transition) {
1310     case GST_STATE_PAUSED_TO_PLAYING:
1311       avimux->video_pad_eos = avimux->audio_pad_eos = FALSE;
1312       break;
1313   }
1314
1315   if (GST_ELEMENT_CLASS (parent_class)->change_state)
1316     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1317
1318   return GST_STATE_SUCCESS;
1319 }
1320