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