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