1 /* AVI muxer plugin for GStreamer
2 * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
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.
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.
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.
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
32 #include "gst/gst-i18n-plugin.h"
36 #include <gst/video/video.h>
38 #include "gstavimux.h"
40 #ifndef LE_FROM_GUINT16
41 #define LE_FROM_GUINT16 GUINT16_FROM_LE
43 #ifndef LE_FROM_GUINT32
44 #define LE_FROM_GUINT32 GUINT32_FROM_LE
47 /* AviMux signals and args */
60 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
63 GST_STATIC_CAPS ("video/x-msvideo")
66 static GstStaticPadTemplate video_sink_factory =
67 GST_STATIC_PAD_TEMPLATE ("video_%d",
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 ]; "
76 "width = (int) [ 16, 4096 ], "
77 "height = (int) [ 16, 4096 ], "
78 "framerate = (fraction) [ 0, MAX ]; "
80 "width = (int) [ 16, 4096 ], "
81 "height = (int) [ 16, 4096 ], "
82 "framerate = (fraction) [ 0, MAX ], "
83 "divxversion = (int) [ 3, 5 ]; "
85 "width = (int) [ 16, 4096 ], "
86 "height = (int) [ 16, 4096 ], "
87 "framerate = (fraction) [ 0, MAX ]; "
89 "width = (int) [ 16, 4096 ], "
90 "height = (int) [ 16, 4096 ], "
91 "framerate = (fraction) [ 0, MAX ]; "
93 "width = (int) [ 16, 4096 ], "
94 "height = (int) [ 16, 4096 ], "
95 "framerate = (fraction) [ 0, MAX ], "
96 "msmpegversion = (int) [ 41, 43 ]; "
98 "width = (int) [ 16, 4096 ], "
99 "height = (int) [ 16, 4096 ], "
100 "framerate = (fraction) [ 0, MAX ], "
101 "mpegversion = (int) 1, "
102 "systemstream = (boolean) FALSE; "
104 "width = (int) [ 16, 4096 ], "
105 "height = (int) [ 16, 4096 ], "
106 "framerate = (fraction) [ 0, MAX ]; "
108 "width = (int) [ 16, 4096 ], "
109 "height = (int) [ 16, 4096 ], "
110 "framerate = (fraction) [ 0, MAX ]; "
112 "width = (int) 720, "
113 "height = (int) { 576, 480 }, "
114 "framerate = (fraction) [ 0, MAX ], "
115 "systemstream = (boolean) FALSE; "
117 "width = (int) [ 16, 4096 ], "
118 "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0, MAX ]")
121 static GstStaticPadTemplate audio_sink_factory =
122 GST_STATIC_PAD_TEMPLATE ("audio_%d",
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 ]; "
133 "mpegversion = (int) 1, "
134 "layer = (int) [ 1, 3 ], "
135 "rate = (int) [ 1000, 96000 ], "
136 "channels = (int) [ 1, 2 ]; "
138 "rate = (int) [ 1000, 96000 ], "
139 "channels = (int) [ 1, 2 ]; "
141 "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]")
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);
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);
161 static GstElementClass *parent_class = NULL;
163 /*static guint gst_avimux_signals[LAST_SIGNAL] = { 0 }; */
166 gst_avimux_get_type (void)
168 static GType avimux_type = 0;
171 static const GTypeInfo avimux_info = {
172 sizeof (GstAviMuxClass),
173 gst_avimux_base_init,
175 (GClassInitFunc) gst_avimux_class_init,
180 (GInstanceInitFunc) gst_avimux_init,
182 static const GInterfaceInfo tag_setter_info = {
189 g_type_register_static (GST_TYPE_ELEMENT, "GstAviMux", &avimux_info, 0);
190 g_type_add_interface_static (avimux_type, GST_TYPE_TAG_SETTER,
197 gst_avimux_base_init (gpointer g_class)
199 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
200 static GstElementDetails gst_avimux_details =
201 GST_ELEMENT_DETAILS ("Avi multiplexer",
203 "Muxes audio and video into an avi stream",
204 "Ronald Bultje <rbultje@ronald.bitfreak.net>");
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));
213 gst_element_class_set_details (element_class, &gst_avimux_details);
217 gst_avimux_class_init (GstAviMuxClass * klass)
219 GObjectClass *gobject_class;
220 GstElementClass *gstelement_class;
222 gobject_class = (GObjectClass *) klass;
223 gstelement_class = (GstElementClass *) klass;
225 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
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));
231 gstelement_class->request_new_pad = gst_avimux_request_new_pad;
232 gstelement_class->release_pad = gst_avimux_release_pad;
234 gstelement_class->change_state = gst_avimux_change_state;
236 gstelement_class->get_property = gst_avimux_get_property;
237 gstelement_class->set_property = gst_avimux_set_property;
240 static const GstEventMask *
241 gst_avimux_get_event_masks (GstPad * pad)
243 static const GstEventMask gst_avimux_sink_event_masks[] = {
248 return gst_avimux_sink_event_masks;
252 gst_avimux_init (GstAviMux * avimux)
254 GstElementClass *klass = GST_ELEMENT_GET_CLASS (avimux);
257 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
259 gst_element_add_pad (GST_ELEMENT (avimux), avimux->srcpad);
261 GST_OBJECT_FLAG_SET (GST_ELEMENT (avimux), GST_ELEMENT_EVENT_AWARE);
263 avimux->audiosinkpad = NULL;
264 avimux->audio_pad_connected = FALSE;
265 avimux->videosinkpad = NULL;
266 avimux->video_pad_connected = FALSE;
268 avimux->audio_buffer_queue = NULL;
269 avimux->video_buffer_queue = NULL;
271 avimux->num_frames = 0;
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;
289 avimux->write_header = TRUE;
291 avimux->enable_large_avi = TRUE;
293 gst_element_set_loop_function (GST_ELEMENT (avimux), gst_avimux_loop);
296 static GstPadLinkReturn
297 gst_avimux_vidsinkconnect (GstPad * pad, const GstCaps * vscaps)
300 GstStructure *structure;
301 const gchar *mimetype;
305 avimux = GST_AVIMUX (gst_pad_get_parent (pad));
307 GST_DEBUG ("avimux: video sinkconnect triggered on %s",
308 gst_pad_get_name (pad));
310 structure = gst_caps_get_structure (vscaps, 0);
311 mimetype = gst_structure_get_name (structure);
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));
321 gst_object_unref (avimux);
322 return GST_PAD_LINK_REFUSED;
325 avimux->vids_hdr.rate = gst_value_get_fraction_numerator (fps);
326 avimux->vids_hdr.scale = gst_value_get_fraction_denominator (fps);
328 if (!strcmp (mimetype, "video/x-raw-yuv")) {
331 gst_structure_get_fourcc (structure, "format", &format);
332 avimux->vids.compression = format;
334 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
335 avimux->vids.bit_cnt = 16;
337 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
338 avimux->vids.bit_cnt = 12;
342 avimux->vids.bit_cnt = 24;
343 avimux->vids.compression = 0;
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")) {
353 gst_structure_get_int (structure, "divxversion", &divxversion);
354 switch (divxversion) {
356 avimux->vids.compression = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
359 avimux->vids.compression = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
362 avimux->vids.compression = GST_MAKE_FOURCC ('D', 'X', '5', '0');
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")) {
372 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
373 switch (msmpegversion) {
375 avimux->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
378 avimux->vids.compression = GST_MAKE_FOURCC ('M', 'P', '4', '2');
381 avimux->vids.compression = GST_MAKE_FOURCC ('M', 'P', '4', '3');
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');
392 if (!avimux->vids.compression) {
393 gst_object_unref (avimux);
394 return GST_PAD_LINK_DELAYED;
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;
404 gst_object_unref (avimux);
406 return GST_PAD_LINK_OK;
409 static GstPadLinkReturn
410 gst_avimux_audsinkconnect (GstPad * pad, const GstCaps * vscaps)
413 GstStructure *structure;
414 const gchar *mimetype;
417 avimux = GST_AVIMUX (gst_pad_get_parent (pad));
419 GST_DEBUG ("avimux: audio sinkconnect triggered on %s",
420 gst_pad_get_name (pad));
422 structure = gst_caps_get_structure (vscaps, 0);
423 mimetype = gst_structure_get_name (structure);
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;
431 if (!strcmp (mimetype, "audio/x-raw-int")) {
432 avimux->auds.format = GST_RIFF_WAVE_FORMAT_PCM;
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;
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;
448 if (!strcmp (mimetype, "audio/mpeg")) {
451 gst_structure_get_int (structure, "layer", &layer);
454 avimux->auds.format = GST_RIFF_WAVE_FORMAT_MPEGL3;
458 avimux->auds.format = GST_RIFF_WAVE_FORMAT_MPEGL12;
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;
467 avimux->auds.blockalign = 1;
468 avimux->auds.av_bps = 0;
469 avimux->auds.size = 16;
471 if (!avimux->auds.format) {
472 gst_object_unref (avimux);
473 return GST_PAD_LINK_REFUSED;
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;
481 gst_object_unref (avimux);
483 return GST_PAD_LINK_OK;
487 gst_avimux_pad_link (GstPad * pad, GstPad * peer, gpointer data)
489 GstAviMux *avimux = GST_AVIMUX (data);
490 const gchar *padname = gst_pad_get_name (pad);
492 if (pad == avimux->audiosinkpad) {
493 avimux->audio_pad_connected = TRUE;
494 } else if (pad == avimux->videosinkpad) {
495 avimux->video_pad_connected = TRUE;
497 g_warning ("Unknown padname '%s'", padname);
501 GST_DEBUG ("pad '%s' connected", padname);
505 gst_avimux_pad_unlink (GstPad * pad, GstPad * peer, gpointer data)
507 GstAviMux *avimux = GST_AVIMUX (data);
508 const gchar *padname = gst_pad_get_name (pad);
510 if (pad == avimux->audiosinkpad) {
511 avimux->audio_pad_connected = FALSE;
512 } else if (pad == avimux->videosinkpad) {
513 avimux->video_pad_connected = FALSE;
515 g_warning ("Unknown padname '%s'", padname);
519 GST_DEBUG ("pad '%s' unlinked", padname);
523 gst_avimux_request_new_pad (GstElement * element,
524 GstPadTemplate * templ, const gchar * req_name)
528 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
530 g_return_val_if_fail (templ != NULL, NULL);
532 if (templ->direction != GST_PAD_SINK) {
533 g_warning ("avimux: request pad that is not a SINK pad\n");
537 g_return_val_if_fail (GST_IS_AVIMUX (element), NULL);
539 avimux = GST_AVIMUX (element);
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;
552 g_warning ("avimux: this is not our template!\n");
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);
567 gst_avimux_release_pad (GstElement * element, GstPad * pad)
569 GstAviMux *avimux = GST_AVIMUX (element);
571 if (pad == avimux->videosinkpad) {
572 avimux->videosinkpad = NULL;
573 } else if (pad == avimux->audiosinkpad) {
574 avimux->audiosinkpad = NULL;
576 g_warning ("Unknown pad %s", gst_pad_get_name (pad));
580 GST_DEBUG ("Removed pad '%s'", gst_pad_get_name (pad));
581 gst_element_remove_pad (element, pad);
584 /* maybe some of these functions should be moved to riff.h? */
586 /* DISCLAIMER: this function is ugly. So be it (i.e. it makes the rest easier) */
589 gst_avimux_write_tag (const GstTagList * list, const gchar * tag, gpointer data)
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}, {
607 GstBuffer *buf = data;
608 guint8 *buffdata = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
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)) {
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;
631 gst_avimux_riff_get_avi_header (GstAviMux * avimux)
634 const GstTagList *iface_tags;
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 */
645 if (avimux->audio_pad_connected) { /* we have audio */
646 size += 28 + sizeof (gst_riff_strh) + sizeof (gst_riff_strf_auds); /* aud hdr */
648 /* this is the "riff size" */
649 avimux->header_size = size;
650 size += 12; /* avi data header */
653 iface_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (avimux));
654 if (iface_tags || avimux->tags) {
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);
662 tags = gst_tag_list_copy (avimux->tags);
668 /* allocate the buffer */
669 buffer = gst_buffer_new_and_alloc (size);
670 buffdata = GST_BUFFER_DATA (buffer);
671 GST_BUFFER_SIZE (buffer) = 0;
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));
684 GST_BUFFER_SIZE (buffer) += 32;
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);
702 GST_BUFFER_SIZE (buffer) += 56;
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);
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);
742 GST_BUFFER_SIZE (buffer) += 116;
745 if (avimux->audio_pad_connected) {
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);
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);
778 GST_BUFFER_SIZE (buffer) += 92;
781 if (avimux->video_pad_connected) {
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);
790 GST_BUFFER_SIZE (buffer) += 24;
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);
803 GST_BUFFER_SIZE (buffer) += 12;
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);
812 /* update list size */
813 GST_WRITE_UINT32_LE (ptr, GST_BUFFER_SIZE (buffer) - startsize - 4);
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);
821 GST_BUFFER_SIZE (buffer) += 12;
827 gst_avimux_riff_get_avix_header (guint32 datax_size)
832 buffer = gst_buffer_new_and_alloc (24);
833 buffdata = GST_BUFFER_DATA (buffer);
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);
846 gst_avimux_riff_get_video_header (guint32 video_frame_size)
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);
860 gst_avimux_riff_get_audio_header (guint32 audio_sample_size)
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);
873 /* some other usable functions (thankyou xawtv ;-) ) */
876 gst_avimux_add_index (GstAviMux * avimux, guchar * code, guint32 flags,
879 if (avimux->idx_index == avimux->idx_count) {
880 avimux->idx_count += 256;
882 realloc (avimux->idx,
883 avimux->idx_count * sizeof (gst_riff_index_entry));
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);
893 gst_avimux_write_index (GstAviMux * avimux)
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));
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));
912 avimux->idx_size += avimux->idx_index * sizeof (gst_riff_index_entry) + 8;
915 avimux->avi_hdr.flags |= GST_RIFF_AVIH_HASINDEX;
919 gst_avimux_bigfile (GstAviMux * avimux, gboolean last)
924 if (avimux->is_bigfile) {
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));
931 /* rewrite AVIX header */
932 header = gst_avimux_riff_get_avix_header (avimux->datax_size);
933 gst_pad_push (avimux->srcpad, GST_DATA (header));
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));
940 avimux->avix_start = avimux->total_data;
945 avimux->is_bigfile = TRUE;
946 avimux->numx_frames = 0;
947 avimux->datax_size = 0;
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));
954 /* enough header blabla now, let's go on to actually writing the headers */
957 gst_avimux_start_file (GstAviMux * avimux)
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;
971 avimux->idx_index = 0;
972 avimux->idx_offset = 0; /* see 10 lines below */
973 avimux->idx_size = 0;
974 avimux->idx_count = 0;
978 avimux->avi_hdr.streams =
979 (avimux->video_pad_connected ? 1 : 0) +
980 (avimux->audio_pad_connected ? 1 : 0);
981 avimux->is_bigfile = FALSE;
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));
987 avimux->idx_offset = avimux->total_data;
989 avimux->write_header = FALSE;
990 avimux->restart = FALSE;
994 gst_avimux_stop_file (GstAviMux * avimux)
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;
1005 gst_avimux_write_index (avimux);
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;
1018 GST_ELEMENT_ERROR (avimux, STREAM, MUX,
1019 (_("No or invalid input audio, AVI stream will be corrupt.")),
1021 avimux->auds.av_bps = 0;
1023 avimux->auds_hdr.rate = avimux->auds.av_bps * avimux->auds_hdr.scale;
1025 avimux->avi_hdr.max_bps += avimux->auds.av_bps;
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;
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;
1037 if (avimux->audio_pad_connected) {
1038 avimux->auds_hdr.length =
1039 (avimux->audio_time * avimux->auds_hdr.rate) / GST_SECOND;
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));
1051 avimux->write_header = TRUE;
1055 gst_avimux_restart_file (GstAviMux * avimux)
1059 gst_avimux_stop_file (avimux);
1061 event = gst_event_new (GST_EVENT_EOS);
1062 gst_pad_push (avimux->srcpad, GST_DATA (event));
1064 gst_avimux_start_file (avimux);
1067 /* handle events (search) */
1069 gst_avimux_handle_event (GstPad * pad, GstEvent * event)
1074 avimux = GST_AVIMUX (gst_pad_get_parent (pad));
1076 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
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;
1086 g_warning ("Unknown pad for EOS!");
1091 gst_tag_list_insert (avimux->tags, gst_event_tag_get_list (event),
1092 GST_TAG_MERGE_PREPEND);
1094 avimux->tags = gst_tag_list_copy (gst_event_tag_get_list (event));
1101 gst_event_unref (event);
1102 gst_object_unref (avimux);
1108 /* fill the internal queue for each available pad */
1110 gst_avimux_fill_queue (GstAviMux * avimux)
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));
1122 avimux->audio_buffer_queue = buffer;
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));
1135 avimux->video_buffer_queue = buffer;
1142 /* send extra 'padding' data */
1144 gst_avimux_send_pad_data (GstAviMux * avimux, gulong num_bytes)
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);
1153 gst_pad_push (avimux->srcpad, GST_DATA (buffer));
1156 /* do audio buffer */
1158 gst_avimux_do_audio_buffer (GstAviMux * avimux)
1160 GstBuffer *data = avimux->audio_buffer_queue, *header;
1161 gulong total_size, pad_bytes = 0;
1163 /* write a audio header + index entry */
1164 if (GST_BUFFER_SIZE (data) & 1) {
1165 pad_bytes = 2 - (GST_BUFFER_SIZE (data) & 1);
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;
1170 if (avimux->is_bigfile) {
1171 avimux->datax_size += total_size;
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));
1179 gst_pad_push (avimux->srcpad, GST_DATA (header));
1180 gst_pad_push (avimux->srcpad, GST_DATA (data));
1182 gst_avimux_send_pad_data (avimux, pad_bytes);
1184 avimux->total_data += total_size;
1185 avimux->idx_offset += total_size;
1187 avimux->audio_buffer_queue = NULL;
1191 /* do video buffer */
1193 gst_avimux_do_video_buffer (GstAviMux * avimux)
1195 GstBuffer *data = avimux->video_buffer_queue, *header;
1196 gulong total_size, pad_bytes = 0;
1198 if (avimux->restart)
1199 gst_avimux_restart_file (avimux);
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);
1207 gst_avimux_restart_file (avimux);
1210 if (GST_BUFFER_SIZE (data) & 1) {
1211 pad_bytes = 2 - (GST_BUFFER_SIZE (data) & 1);
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++;
1217 if (avimux->is_bigfile) {
1218 avimux->datax_size += total_size;
1219 avimux->numx_frames++;
1223 if (GST_BUFFER_FLAG_IS_SET (data, GST_BUFFER_KEY_UNIT))
1225 avimux->data_size += total_size;
1226 avimux->num_frames++;
1227 gst_avimux_add_index (avimux, "00db", flags, GST_BUFFER_SIZE (data));
1230 gst_pad_push (avimux->srcpad, GST_DATA (header));
1231 gst_pad_push (avimux->srcpad, GST_DATA (data));
1233 gst_avimux_send_pad_data (avimux, pad_bytes);
1235 avimux->total_data += total_size;
1236 avimux->idx_offset += total_size;
1238 avimux->video_buffer_queue = NULL;
1242 /* take the oldest buffer in our internal queue and push-it */
1244 gst_avimux_do_one_buffer (GstAviMux * avimux)
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);
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);
1256 gst_avimux_do_audio_buffer (avimux);
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));
1270 gst_avimux_loop (GstElement * element)
1274 avimux = GST_AVIMUX (element);
1276 /* first fill queue (some elements only set caps when
1277 * flowing data), then write header */
1278 gst_avimux_fill_queue (avimux);
1280 if (avimux->write_header)
1281 gst_avimux_start_file (avimux);
1283 gst_avimux_do_one_buffer (avimux);
1287 gst_avimux_get_property (GObject * object,
1288 guint prop_id, GValue * value, GParamSpec * pspec)
1292 g_return_if_fail (GST_IS_AVIMUX (object));
1293 avimux = GST_AVIMUX (object);
1297 g_value_set_boolean (value, avimux->enable_large_avi);
1300 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1306 gst_avimux_set_property (GObject * object,
1307 guint prop_id, const GValue * value, GParamSpec * pspec)
1311 g_return_if_fail (GST_IS_AVIMUX (object));
1312 avimux = GST_AVIMUX (object);
1316 avimux->enable_large_avi = g_value_get_boolean (value);
1319 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1324 static GstStateChangeReturn
1325 gst_avimux_change_state (GstElement * element, GstStateChange transition)
1329 g_return_val_if_fail (GST_IS_AVIMUX (element), GST_STATE_CHANGE_FAILURE);
1331 avimux = GST_AVIMUX (element);
1333 switch (transition) {
1334 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1335 avimux->video_pad_eos = avimux->audio_pad_eos = FALSE;
1337 case GST_STATE_CHANGE_PAUSED_TO_READY:
1339 gst_tag_list_free (avimux->tags);
1340 avimux->tags = NULL;
1345 if (GST_ELEMENT_CLASS (parent_class)->change_state)
1346 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1348 return GST_STATE_CHANGE_SUCCESS;