Merge branch 'master' into 0.11-fdo
[platform/upstream/gst-plugins-good.git] / gst / matroska / matroska-mux.c
1 /* GStreamer Matroska muxer/demuxer
2  * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  * (c) 2005 Michal Benes <michal.benes@xeris.cz>
4  * (c) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5  *
6  * matroska-mux.c: matroska file/stream muxer
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /* TODO: - check everywhere that we don't write invalid values
25  *       - make sure timestamps are correctly scaled everywhere
26  */
27
28 /**
29  * SECTION:element-matroskamux
30  *
31  * matroskamux muxes different input streams into a Matroska file.
32  *
33  * <refsect2>
34  * <title>Example launch line</title>
35  * |[
36  * gst-launch -v filesrc location=/path/to/mp3 ! mp3parse ! matroskamux name=mux ! filesink location=test.mkv  filesrc location=/path/to/theora.ogg ! oggdemux ! theoraparse ! mux.
37  * ]| This pipeline muxes an MP3 file and a Ogg Theora video into a Matroska file.
38  * |[
39  * gst-launch -v audiotestsrc num-buffers=100 ! audioconvert ! vorbisenc ! matroskamux ! filesink location=test.mka
40  * ]| This pipeline muxes a 440Hz sine wave encoded with the Vorbis codec into a Matroska file.
41  * </refsect2>
42  */
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #include <math.h>
49 #include <stdio.h>
50 #include <string.h>
51
52 #include <gst/riff/riff-media.h>
53 #include <gst/tag/tag.h>
54
55 #include "matroska-mux.h"
56 #include "matroska-ids.h"
57
58 GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
59 #define GST_CAT_DEFAULT matroskamux_debug
60
61 enum
62 {
63   ARG_0,
64   ARG_WRITING_APP,
65   ARG_DOCTYPE_VERSION,
66   ARG_MIN_INDEX_INTERVAL,
67   ARG_STREAMABLE
68 };
69
70 #define  DEFAULT_DOCTYPE_VERSION         2
71 #define  DEFAULT_WRITING_APP             "GStreamer Matroska muxer"
72 #define  DEFAULT_MIN_INDEX_INTERVAL      0
73 #define  DEFAULT_STREAMABLE              FALSE
74
75 /* WAVEFORMATEX is gst_riff_strf_auds + an extra guint16 extension size */
76 #define WAVEFORMATEX_SIZE  (2 + sizeof (gst_riff_strf_auds))
77
78 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
79     GST_PAD_SRC,
80     GST_PAD_ALWAYS,
81     GST_STATIC_CAPS ("video/x-matroska")
82     );
83
84 #define COMMON_VIDEO_CAPS \
85   "width = (int) [ 16, 4096 ], " \
86   "height = (int) [ 16, 4096 ], " \
87   "framerate = (fraction) [ 0, MAX ]"
88
89 #define COMMON_VIDEO_CAPS_NO_FRAMERATE \
90   "width = (int) [ 16, 4096 ], " \
91   "height = (int) [ 16, 4096 ] "
92
93 /* FIXME:
94  * * require codec data, etc as needed
95  */
96
97 static GstStaticPadTemplate videosink_templ =
98     GST_STATIC_PAD_TEMPLATE ("video_%d",
99     GST_PAD_SINK,
100     GST_PAD_REQUEST,
101     GST_STATIC_CAPS ("video/mpeg, "
102         "mpegversion = (int) { 1, 2, 4 }, "
103         "systemstream = (boolean) false, "
104         COMMON_VIDEO_CAPS "; "
105         "video/x-h264, "
106         COMMON_VIDEO_CAPS "; "
107         "video/x-divx, "
108         COMMON_VIDEO_CAPS "; "
109         "video/x-xvid, "
110         COMMON_VIDEO_CAPS "; "
111         "video/x-huffyuv, "
112         COMMON_VIDEO_CAPS "; "
113         "video/x-dv, "
114         COMMON_VIDEO_CAPS "; "
115         "video/x-h263, "
116         COMMON_VIDEO_CAPS "; "
117         "video/x-msmpeg, "
118         COMMON_VIDEO_CAPS "; "
119         "image/jpeg, "
120         COMMON_VIDEO_CAPS_NO_FRAMERATE "; "
121         "video/x-theora; "
122         "video/x-dirac, "
123         COMMON_VIDEO_CAPS "; "
124         "video/x-pn-realvideo, "
125         "rmversion = (int) [1, 4], "
126         COMMON_VIDEO_CAPS "; "
127         "video/x-vp8, "
128         COMMON_VIDEO_CAPS "; "
129         "video/x-raw-yuv, "
130         "format = (fourcc) { YUY2, I420, YV12, UYVY, AYUV }, "
131         COMMON_VIDEO_CAPS "; "
132         "video/x-wmv, " "wmvversion = (int) [ 1, 3 ], " COMMON_VIDEO_CAPS)
133     );
134
135 #define COMMON_AUDIO_CAPS \
136   "channels = (int) [ 1, MAX ], " \
137   "rate = (int) [ 1, MAX ]"
138
139 /* FIXME:
140  * * require codec data, etc as needed
141  */
142 static GstStaticPadTemplate audiosink_templ =
143     GST_STATIC_PAD_TEMPLATE ("audio_%d",
144     GST_PAD_SINK,
145     GST_PAD_REQUEST,
146     GST_STATIC_CAPS ("audio/mpeg, "
147         "mpegversion = (int) 1, "
148         "layer = (int) [ 1, 3 ], "
149         "stream-format = (string) { raw }, "
150         COMMON_AUDIO_CAPS "; "
151         "audio/mpeg, "
152         "mpegversion = (int) { 2, 4 }, "
153         COMMON_AUDIO_CAPS "; "
154         "audio/x-ac3, "
155         COMMON_AUDIO_CAPS "; "
156         "audio/x-eac3, "
157         COMMON_AUDIO_CAPS "; "
158         "audio/x-dts, "
159         COMMON_AUDIO_CAPS "; "
160         "audio/x-vorbis, "
161         COMMON_AUDIO_CAPS "; "
162         "audio/x-flac, "
163         COMMON_AUDIO_CAPS "; "
164         "audio/x-speex, "
165         COMMON_AUDIO_CAPS "; "
166         "audio/x-raw-int, "
167         "width = (int) 8, "
168         "depth = (int) 8, "
169         "signed = (boolean) false, "
170         COMMON_AUDIO_CAPS ";"
171         "audio/x-raw-int, "
172         "width = (int) 16, "
173         "depth = (int) 16, "
174         "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
175         "signed = (boolean) true, "
176         COMMON_AUDIO_CAPS ";"
177         "audio/x-raw-int, "
178         "width = (int) 24, "
179         "depth = (int) 24, "
180         "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
181         "signed = (boolean) true, "
182         COMMON_AUDIO_CAPS ";"
183         "audio/x-raw-int, "
184         "width = (int) 32, "
185         "depth = (int) 32, "
186         "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
187         "signed = (boolean) true, "
188         COMMON_AUDIO_CAPS ";"
189         "audio/x-raw-float, "
190         "width = (int) [ 32, 64 ], "
191         "endianness = (int) LITTLE_ENDIAN, "
192         COMMON_AUDIO_CAPS ";"
193         "audio/x-tta, "
194         "width = (int) { 8, 16, 24 }, "
195         "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
196         "audio/x-pn-realaudio, "
197         "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS "; "
198         "audio/x-wma, " "wmaversion = (int) [ 1, 3 ], "
199         "block_align = (int) [ 0, 65535 ], bitrate = (int) [ 0, 524288 ], "
200         COMMON_AUDIO_CAPS)
201     );
202
203 static GstStaticPadTemplate subtitlesink_templ =
204 GST_STATIC_PAD_TEMPLATE ("subtitle_%d",
205     GST_PAD_SINK,
206     GST_PAD_REQUEST,
207     GST_STATIC_CAPS ("subtitle/x-kate"));
208
209 static GArray *used_uids;
210 G_LOCK_DEFINE_STATIC (used_uids);
211
212 static void gst_matroska_mux_add_interfaces (GType type);
213
214 GST_BOILERPLATE_FULL (GstMatroskaMux, gst_matroska_mux, GstElement,
215     GST_TYPE_ELEMENT, gst_matroska_mux_add_interfaces);
216
217 /* Matroska muxer destructor */
218 static void gst_matroska_mux_finalize (GObject * object);
219
220 /* Pads collected callback */
221 static GstFlowReturn
222 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data);
223
224 /* pad functions */
225 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
226     GstEvent * event);
227 static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
228     GstPadTemplate * templ, const gchar * name);
229 static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
230
231 /* gst internal change state handler */
232 static GstStateChangeReturn
233 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
234
235 /* gobject bla bla */
236 static void gst_matroska_mux_set_property (GObject * object,
237     guint prop_id, const GValue * value, GParamSpec * pspec);
238 static void gst_matroska_mux_get_property (GObject * object,
239     guint prop_id, GValue * value, GParamSpec * pspec);
240
241 /* reset muxer */
242 static void gst_matroska_mux_reset (GstElement * element);
243
244 /* uid generation */
245 static guint64 gst_matroska_mux_create_uid ();
246
247 static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
248     GstMatroskaTrackContext * context);
249 static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
250     GstMatroskaTrackContext * context);
251 static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
252     GstMatroskaTrackContext * context);
253 static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
254     GstMatroskaTrackContext * context);
255 static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
256     GstMatroskaTrackContext * context);
257
258 static void
259 gst_matroska_mux_add_interfaces (GType type)
260 {
261   static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
262
263   g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
264 }
265
266 static void
267 gst_matroska_mux_base_init (gpointer g_class)
268 {
269 }
270
271 static void
272 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
273 {
274   GObjectClass *gobject_class;
275   GstElementClass *gstelement_class;
276
277   gobject_class = (GObjectClass *) klass;
278   gstelement_class = (GstElementClass *) klass;
279
280   gst_element_class_add_pad_template (gstelement_class,
281       gst_static_pad_template_get (&videosink_templ));
282   gst_element_class_add_pad_template (gstelement_class,
283       gst_static_pad_template_get (&audiosink_templ));
284   gst_element_class_add_pad_template (gstelement_class,
285       gst_static_pad_template_get (&subtitlesink_templ));
286   gst_element_class_add_pad_template (gstelement_class,
287       gst_static_pad_template_get (&src_templ));
288   gst_element_class_set_details_simple (gstelement_class, "Matroska muxer",
289       "Codec/Muxer",
290       "Muxes video/audio/subtitle streams into a matroska stream",
291       "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
292
293   GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
294       "Matroska muxer");
295
296   gobject_class->finalize = gst_matroska_mux_finalize;
297
298   gobject_class->get_property = gst_matroska_mux_get_property;
299   gobject_class->set_property = gst_matroska_mux_set_property;
300
301   g_object_class_install_property (gobject_class, ARG_WRITING_APP,
302       g_param_spec_string ("writing-app", "Writing application.",
303           "The name the application that creates the matroska file.",
304           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
305   g_object_class_install_property (gobject_class, ARG_DOCTYPE_VERSION,
306       g_param_spec_int ("version", "DocType version",
307           "This parameter determines what Matroska features can be used.",
308           1, 2, DEFAULT_DOCTYPE_VERSION,
309           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
310   g_object_class_install_property (gobject_class, ARG_MIN_INDEX_INTERVAL,
311       g_param_spec_int64 ("min-index-interval", "Minimum time between index "
312           "entries", "An index entry is created every so many nanoseconds.",
313           0, G_MAXINT64, DEFAULT_MIN_INDEX_INTERVAL,
314           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
315   g_object_class_install_property (gobject_class, ARG_STREAMABLE,
316       g_param_spec_boolean ("streamable", "Determines whether output should "
317           "be streamable", "If set to true, the output should be as if it is "
318           "to be streamed and hence no indexes written or duration written.",
319           DEFAULT_STREAMABLE,
320           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_STATIC_STRINGS));
321
322   gstelement_class->change_state =
323       GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
324   gstelement_class->request_new_pad =
325       GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
326   gstelement_class->release_pad =
327       GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
328 }
329
330
331 /**
332  * gst_matroska_mux_init:
333  * @mux: #GstMatroskaMux that should be initialized.
334  * @g_class: Class of the muxer.
335  *
336  * Matroska muxer constructor.
337  */
338 static void
339 gst_matroska_mux_init (GstMatroskaMux * mux, GstMatroskaMuxClass * g_class)
340 {
341   GstPadTemplate *templ;
342
343   templ =
344       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
345   mux->srcpad = gst_pad_new_from_template (templ, "src");
346
347   gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
348   gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
349
350   mux->collect = gst_collect_pads_new ();
351   gst_collect_pads_set_function (mux->collect,
352       (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_matroska_mux_collected),
353       mux);
354
355   mux->ebml_write = gst_ebml_write_new (mux->srcpad);
356   mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
357
358   /* property defaults */
359   mux->doctype_version = DEFAULT_DOCTYPE_VERSION;
360   mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
361   mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
362   mux->streamable = DEFAULT_STREAMABLE;
363
364   /* initialize internal variables */
365   mux->index = NULL;
366   mux->num_streams = 0;
367   mux->num_a_streams = 0;
368   mux->num_t_streams = 0;
369   mux->num_v_streams = 0;
370
371   /* initialize remaining variables */
372   gst_matroska_mux_reset (GST_ELEMENT (mux));
373 }
374
375
376 /**
377  * gst_matroska_mux_finalize:
378  * @object: #GstMatroskaMux that should be finalized.
379  *
380  * Finalize matroska muxer.
381  */
382 static void
383 gst_matroska_mux_finalize (GObject * object)
384 {
385   GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
386
387   gst_object_unref (mux->collect);
388   gst_object_unref (mux->ebml_write);
389   if (mux->writing_app)
390     g_free (mux->writing_app);
391
392   G_OBJECT_CLASS (parent_class)->finalize (object);
393 }
394
395
396 /**
397  * gst_matroska_mux_create_uid:
398  *
399  * Generate new unused track UID.
400  *
401  * Returns: New track UID.
402  */
403 static guint64
404 gst_matroska_mux_create_uid (void)
405 {
406   guint64 uid = 0;
407
408   G_LOCK (used_uids);
409
410   if (!used_uids)
411     used_uids = g_array_sized_new (FALSE, FALSE, sizeof (guint64), 10);
412
413   while (!uid) {
414     guint i;
415
416     uid = (((guint64) g_random_int ()) << 32) | g_random_int ();
417     for (i = 0; i < used_uids->len; i++) {
418       if (g_array_index (used_uids, guint64, i) == uid) {
419         uid = 0;
420         break;
421       }
422     }
423     g_array_append_val (used_uids, uid);
424   }
425
426   G_UNLOCK (used_uids);
427   return uid;
428 }
429
430
431 /**
432  * gst_matroska_pad_reset:
433  * @collect_pad: the #GstMatroskaPad
434  *
435  * Reset and/or release resources of a matroska collect pad.
436  */
437 static void
438 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
439 {
440   gchar *name = NULL;
441   GstMatroskaTrackType type = 0;
442
443   /* free track information */
444   if (collect_pad->track != NULL) {
445     /* retrieve for optional later use */
446     name = collect_pad->track->name;
447     type = collect_pad->track->type;
448     /* extra for video */
449     if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
450       GstMatroskaTrackVideoContext *ctx =
451           (GstMatroskaTrackVideoContext *) collect_pad->track;
452
453       if (ctx->dirac_unit) {
454         gst_buffer_unref (ctx->dirac_unit);
455         ctx->dirac_unit = NULL;
456       }
457     }
458     g_free (collect_pad->track->codec_id);
459     g_free (collect_pad->track->codec_name);
460     if (full)
461       g_free (collect_pad->track->name);
462     g_free (collect_pad->track->language);
463     g_free (collect_pad->track->codec_priv);
464     g_free (collect_pad->track);
465     collect_pad->track = NULL;
466   }
467
468   /* free cached buffer */
469   if (collect_pad->buffer != NULL) {
470     gst_buffer_unref (collect_pad->buffer);
471     collect_pad->buffer = NULL;
472   }
473
474   if (!full && type != 0) {
475     GstMatroskaTrackContext *context;
476
477     /* create a fresh context */
478     switch (type) {
479       case GST_MATROSKA_TRACK_TYPE_VIDEO:
480         context = (GstMatroskaTrackContext *)
481             g_new0 (GstMatroskaTrackVideoContext, 1);
482         break;
483       case GST_MATROSKA_TRACK_TYPE_AUDIO:
484         context = (GstMatroskaTrackContext *)
485             g_new0 (GstMatroskaTrackAudioContext, 1);
486         break;
487       case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
488         context = (GstMatroskaTrackContext *)
489             g_new0 (GstMatroskaTrackSubtitleContext, 1);
490         break;
491       default:
492         g_assert_not_reached ();
493         break;
494     }
495
496     context->type = type;
497     context->name = name;
498     /* TODO: check default values for the context */
499     context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
500     collect_pad->track = context;
501     collect_pad->buffer = NULL;
502     collect_pad->duration = 0;
503     collect_pad->start_ts = GST_CLOCK_TIME_NONE;
504     collect_pad->end_ts = GST_CLOCK_TIME_NONE;
505   }
506 }
507
508 /**
509  * gst_matroska_pad_free:
510  * @collect_pad: the #GstMatroskaPad
511  *
512  * Release resources of a matroska collect pad.
513  */
514 static void
515 gst_matroska_pad_free (GstMatroskaPad * collect_pad)
516 {
517   gst_matroska_pad_reset (collect_pad, TRUE);
518 }
519
520
521 /**
522  * gst_matroska_mux_reset:
523  * @element: #GstMatroskaMux that should be reseted.
524  *
525  * Reset matroska muxer back to initial state.
526  */
527 static void
528 gst_matroska_mux_reset (GstElement * element)
529 {
530   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
531   GSList *walk;
532
533   /* reset EBML write */
534   gst_ebml_write_reset (mux->ebml_write);
535
536   /* reset input */
537   mux->state = GST_MATROSKA_MUX_STATE_START;
538
539   /* clean up existing streams */
540
541   for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
542     GstMatroskaPad *collect_pad;
543
544     collect_pad = (GstMatroskaPad *) walk->data;
545
546     /* reset collect pad to pristine state */
547     gst_matroska_pad_reset (collect_pad, FALSE);
548   }
549
550   /* reset indexes */
551   mux->num_indexes = 0;
552   g_free (mux->index);
553   mux->index = NULL;
554
555   /* reset timers */
556   mux->time_scale = GST_MSECOND;
557   mux->max_cluster_duration = G_MAXINT16 * mux->time_scale;
558   mux->duration = 0;
559
560   /* reset cluster */
561   mux->cluster = 0;
562   mux->cluster_time = 0;
563   mux->cluster_pos = 0;
564   mux->prev_cluster_size = 0;
565
566   /* reset tags */
567   gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
568 }
569
570 /**
571  * gst_matroska_mux_handle_src_event:
572  * @pad: Pad which received the event.
573  * @event: Received event.
574  *
575  * handle events - copied from oggmux without understanding
576  *
577  * Returns: #TRUE on success.
578  */
579 static gboolean
580 gst_matroska_mux_handle_src_event (GstPad * pad, GstEvent * event)
581 {
582   GstEventType type;
583
584   type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
585
586   switch (type) {
587     case GST_EVENT_SEEK:
588       /* disable seeking for now */
589       return FALSE;
590     default:
591       break;
592   }
593
594   return gst_pad_event_default (pad, event);
595 }
596
597 /**
598  * gst_matroska_mux_handle_sink_event:
599  * @pad: Pad which received the event.
600  * @event: Received event.
601  *
602  * handle events - informational ones like tags
603  *
604  * Returns: #TRUE on success.
605  */
606 static gboolean
607 gst_matroska_mux_handle_sink_event (GstPad * pad, GstEvent * event)
608 {
609   GstMatroskaTrackContext *context;
610   GstMatroskaPad *collect_pad;
611   GstMatroskaMux *mux;
612   GstTagList *list;
613   gboolean ret = TRUE;
614
615   mux = GST_MATROSKA_MUX (gst_pad_get_parent (pad));
616
617   switch (GST_EVENT_TYPE (event)) {
618     case GST_EVENT_TAG:{
619       gchar *lang = NULL;
620
621       GST_DEBUG_OBJECT (mux, "received tag event");
622       gst_event_parse_tag (event, &list);
623
624       collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
625       g_assert (collect_pad);
626       context = collect_pad->track;
627       g_assert (context);
628
629       /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
630       if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
631         const gchar *lang_code;
632
633         lang_code = gst_tag_get_language_code_iso_639_2B (lang);
634         if (lang_code) {
635           GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
636           context->language = g_strdup (lang_code);
637         } else {
638           GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
639         }
640         g_free (lang);
641       }
642
643       /* FIXME: what about stream-specific tags? */
644       gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
645           gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
646
647       gst_event_unref (event);
648       /* handled this, don't want collectpads to forward it downstream */
649       event = NULL;
650       break;
651     }
652     case GST_EVENT_NEWSEGMENT:
653       /* We don't support NEWSEGMENT events */
654       ret = FALSE;
655       gst_event_unref (event);
656       event = NULL;
657       break;
658     default:
659       break;
660   }
661
662   /* now GstCollectPads can take care of the rest, e.g. EOS */
663   if (event)
664     ret = mux->collect_event (pad, event);
665
666   gst_object_unref (mux);
667
668   return ret;
669 }
670
671
672 /**
673  * gst_matroska_mux_video_pad_setcaps:
674  * @pad: Pad which got the caps.
675  * @caps: New caps.
676  *
677  * Setcaps function for video sink pad.
678  *
679  * Returns: #TRUE on success.
680  */
681 static gboolean
682 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
683 {
684   GstMatroskaTrackContext *context = NULL;
685   GstMatroskaTrackVideoContext *videocontext;
686   GstMatroskaMux *mux;
687   GstMatroskaPad *collect_pad;
688   GstStructure *structure;
689   const gchar *mimetype;
690   const GValue *value = NULL;
691   const GstBuffer *codec_buf = NULL;
692   gint width, height, pixel_width, pixel_height;
693   gint fps_d, fps_n;
694   gboolean interlaced = FALSE;
695
696   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
697
698   /* find context */
699   collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
700   g_assert (collect_pad);
701   context = collect_pad->track;
702   g_assert (context);
703   g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
704   videocontext = (GstMatroskaTrackVideoContext *) context;
705
706   /* gst -> matroska ID'ing */
707   structure = gst_caps_get_structure (caps, 0);
708
709   mimetype = gst_structure_get_name (structure);
710
711   if (gst_structure_get_boolean (structure, "interlaced", &interlaced)
712       && interlaced)
713     context->flags |= GST_MATROSKA_VIDEOTRACK_INTERLACED;
714
715   if (!strcmp (mimetype, "video/x-theora")) {
716     /* we'll extract the details later from the theora identification header */
717     goto skip_details;
718   }
719
720   /* get general properties */
721   /* spec says it is mandatory */
722   if (!gst_structure_get_int (structure, "width", &width) ||
723       !gst_structure_get_int (structure, "height", &height))
724     goto refuse_caps;
725
726   videocontext->pixel_width = width;
727   videocontext->pixel_height = height;
728   if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
729       && fps_n > 0) {
730     context->default_duration =
731         gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
732     GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
733         GST_TIME_ARGS (context->default_duration));
734   } else {
735     context->default_duration = 0;
736   }
737   if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
738           &pixel_width, &pixel_height)) {
739     if (pixel_width > pixel_height) {
740       videocontext->display_width = width * pixel_width / pixel_height;
741       videocontext->display_height = height;
742     } else if (pixel_width < pixel_height) {
743       videocontext->display_width = width;
744       videocontext->display_height = height * pixel_height / pixel_width;
745     } else {
746       videocontext->display_width = 0;
747       videocontext->display_height = 0;
748     }
749   } else {
750     videocontext->display_width = 0;
751     videocontext->display_height = 0;
752   }
753
754 skip_details:
755
756   videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
757   videocontext->fourcc = 0;
758
759   /* TODO: - check if we handle all codecs by the spec, i.e. codec private
760    *         data and other settings
761    *       - add new formats
762    */
763
764   /* extract codec_data, may turn out needed */
765   value = gst_structure_get_value (structure, "codec_data");
766   if (value)
767     codec_buf = gst_value_get_buffer (value);
768
769   /* find type */
770   if (!strcmp (mimetype, "video/x-raw-yuv")) {
771     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
772     gst_structure_get_fourcc (structure, "format", &videocontext->fourcc);
773   } else if (!strcmp (mimetype, "image/jpeg")) {
774     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
775   } else if (!strcmp (mimetype, "video/x-xvid") /* MS/VfW compatibility cases */
776       ||!strcmp (mimetype, "video/x-huffyuv")
777       || !strcmp (mimetype, "video/x-divx")
778       || !strcmp (mimetype, "video/x-dv")
779       || !strcmp (mimetype, "video/x-h263")
780       || !strcmp (mimetype, "video/x-msmpeg")
781       || !strcmp (mimetype, "video/x-wmv")) {
782     gst_riff_strf_vids *bih;
783     gint size = sizeof (gst_riff_strf_vids);
784     guint32 fourcc = 0;
785
786     if (!strcmp (mimetype, "video/x-xvid"))
787       fourcc = GST_MAKE_FOURCC ('X', 'V', 'I', 'D');
788     else if (!strcmp (mimetype, "video/x-huffyuv"))
789       fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
790     else if (!strcmp (mimetype, "video/x-dv"))
791       fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
792     else if (!strcmp (mimetype, "video/x-h263"))
793       fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
794     else if (!strcmp (mimetype, "video/x-divx")) {
795       gint divxversion;
796
797       gst_structure_get_int (structure, "divxversion", &divxversion);
798       switch (divxversion) {
799         case 3:
800           fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
801           break;
802         case 4:
803           fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
804           break;
805         case 5:
806           fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
807           break;
808       }
809     } else if (!strcmp (mimetype, "video/x-msmpeg")) {
810       gint msmpegversion;
811
812       gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
813       switch (msmpegversion) {
814         case 41:
815           fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
816           break;
817         case 42:
818           fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
819           break;
820         case 43:
821           goto msmpeg43;
822           break;
823       }
824     } else if (!strcmp (mimetype, "video/x-wmv")) {
825       gint wmvversion;
826       guint32 format;
827       if (gst_structure_get_fourcc (structure, "format", &format)) {
828         fourcc = format;
829       } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
830         if (wmvversion == 2) {
831           fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
832         } else if (wmvversion == 1) {
833           fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
834         } else if (wmvversion == 3) {
835           fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
836         }
837       }
838     }
839
840     if (!fourcc)
841       goto refuse_caps;
842
843     bih = g_new0 (gst_riff_strf_vids, 1);
844     GST_WRITE_UINT32_LE (&bih->size, size);
845     GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
846     GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
847     GST_WRITE_UINT32_LE (&bih->compression, fourcc);
848     GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
849     GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
850     GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
851         videocontext->pixel_height * 3);
852
853     /* process codec private/initialization data, if any */
854     if (codec_buf) {
855       size += GST_BUFFER_SIZE (codec_buf);
856       bih = g_realloc (bih, size);
857       GST_WRITE_UINT32_LE (&bih->size, size);
858       memcpy ((guint8 *) bih + sizeof (gst_riff_strf_vids),
859           GST_BUFFER_DATA (codec_buf), GST_BUFFER_SIZE (codec_buf));
860     }
861
862     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
863     context->codec_priv = (gpointer) bih;
864     context->codec_priv_size = size;
865   } else if (!strcmp (mimetype, "video/x-h264")) {
866     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
867
868     if (context->codec_priv != NULL) {
869       g_free (context->codec_priv);
870       context->codec_priv = NULL;
871       context->codec_priv_size = 0;
872     }
873
874     /* Create avcC header */
875     if (codec_buf != NULL) {
876       context->codec_priv_size = GST_BUFFER_SIZE (codec_buf);
877       context->codec_priv = g_malloc0 (context->codec_priv_size);
878       memcpy (context->codec_priv, GST_BUFFER_DATA (codec_buf),
879           context->codec_priv_size);
880     }
881   } else if (!strcmp (mimetype, "video/x-theora")) {
882     const GValue *streamheader;
883
884     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
885
886     if (context->codec_priv != NULL) {
887       g_free (context->codec_priv);
888       context->codec_priv = NULL;
889       context->codec_priv_size = 0;
890     }
891
892     streamheader = gst_structure_get_value (structure, "streamheader");
893     if (!theora_streamheader_to_codecdata (streamheader, context)) {
894       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
895           ("theora stream headers missing or malformed"));
896       goto refuse_caps;
897     }
898   } else if (!strcmp (mimetype, "video/x-dirac")) {
899     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
900   } else if (!strcmp (mimetype, "video/x-vp8")) {
901     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VP8);
902   } else if (!strcmp (mimetype, "video/mpeg")) {
903     gint mpegversion;
904
905     gst_structure_get_int (structure, "mpegversion", &mpegversion);
906     switch (mpegversion) {
907       case 1:
908         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
909         break;
910       case 2:
911         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
912         break;
913       case 4:
914         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
915         break;
916       default:
917         goto refuse_caps;
918     }
919
920     /* global headers may be in codec data */
921     if (codec_buf != NULL) {
922       context->codec_priv_size = GST_BUFFER_SIZE (codec_buf);
923       context->codec_priv = g_malloc0 (context->codec_priv_size);
924       memcpy (context->codec_priv, GST_BUFFER_DATA (codec_buf),
925           context->codec_priv_size);
926     }
927   } else if (!strcmp (mimetype, "video/x-msmpeg")) {
928   msmpeg43:
929     /* can only make it here if preceding case verified it was version 3 */
930     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
931   } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
932     gint rmversion;
933     const GValue *mdpr_data;
934
935     gst_structure_get_int (structure, "rmversion", &rmversion);
936     switch (rmversion) {
937       case 1:
938         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
939         break;
940       case 2:
941         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
942         break;
943       case 3:
944         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
945         break;
946       case 4:
947         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
948         break;
949       default:
950         goto refuse_caps;
951     }
952
953     mdpr_data = gst_structure_get_value (structure, "mdpr_data");
954     if (mdpr_data != NULL) {
955       guint8 *priv_data = NULL;
956       guint priv_data_size = 0;
957
958       GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
959
960       priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
961       priv_data = g_malloc0 (priv_data_size);
962
963       memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
964
965       context->codec_priv = priv_data;
966       context->codec_priv_size = priv_data_size;
967     }
968   }
969
970   return TRUE;
971
972   /* ERRORS */
973 refuse_caps:
974   {
975     GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
976         GST_PAD_NAME (pad), caps);
977     return FALSE;
978   }
979 }
980
981 /* N > 0 to expect a particular number of headers, negative if the
982    number of headers is variable */
983 static gboolean
984 xiphN_streamheader_to_codecdata (const GValue * streamheader,
985     GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
986 {
987   GstBuffer **buf = NULL;
988   GArray *bufarr;
989   guint8 *priv_data;
990   guint bufi, i, offset, priv_data_size;
991
992   if (streamheader == NULL)
993     goto no_stream_headers;
994
995   if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
996     goto wrong_type;
997
998   bufarr = g_value_peek_pointer (streamheader);
999   if (bufarr->len <= 0 || bufarr->len > 255)    /* at least one header, and count stored in a byte */
1000     goto wrong_count;
1001   if (N > 0 && bufarr->len != N)
1002     goto wrong_count;
1003
1004   context->xiph_headers_to_skip = bufarr->len;
1005
1006   buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1007   for (i = 0; i < bufarr->len; i++) {
1008     GValue *bufval = &g_array_index (bufarr, GValue, i);
1009
1010     if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1011       g_free (buf);
1012       goto wrong_content_type;
1013     }
1014
1015     buf[i] = g_value_peek_pointer (bufval);
1016   }
1017
1018   priv_data_size = 1;
1019   if (bufarr->len > 0) {
1020     for (i = 0; i < bufarr->len - 1; i++) {
1021       priv_data_size += GST_BUFFER_SIZE (buf[i]) / 0xff + 1;
1022     }
1023   }
1024
1025   for (i = 0; i < bufarr->len; ++i) {
1026     priv_data_size += GST_BUFFER_SIZE (buf[i]);
1027   }
1028
1029   priv_data = g_malloc0 (priv_data_size);
1030
1031   priv_data[0] = bufarr->len - 1;
1032   offset = 1;
1033
1034   if (bufarr->len > 0) {
1035     for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1036       for (i = 0; i < GST_BUFFER_SIZE (buf[bufi]) / 0xff; ++i) {
1037         priv_data[offset++] = 0xff;
1038       }
1039       priv_data[offset++] = GST_BUFFER_SIZE (buf[bufi]) % 0xff;
1040     }
1041   }
1042
1043   for (i = 0; i < bufarr->len; ++i) {
1044     memcpy (priv_data + offset, GST_BUFFER_DATA (buf[i]),
1045         GST_BUFFER_SIZE (buf[i]));
1046     offset += GST_BUFFER_SIZE (buf[i]);
1047   }
1048
1049   context->codec_priv = priv_data;
1050   context->codec_priv_size = priv_data_size;
1051
1052   if (p_buf0)
1053     *p_buf0 = gst_buffer_ref (buf[0]);
1054
1055   g_free (buf);
1056
1057   return TRUE;
1058
1059 /* ERRORS */
1060 no_stream_headers:
1061   {
1062     GST_WARNING ("required streamheaders missing in sink caps!");
1063     return FALSE;
1064   }
1065 wrong_type:
1066   {
1067     GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1068         G_VALUE_TYPE_NAME (streamheader));
1069     return FALSE;
1070   }
1071 wrong_count:
1072   {
1073     GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1074     return FALSE;
1075   }
1076 wrong_content_type:
1077   {
1078     GST_WARNING ("streamheaders array does not contain GstBuffers");
1079     return FALSE;
1080   }
1081 }
1082
1083 static gboolean
1084 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1085     GstMatroskaTrackContext * context)
1086 {
1087   GstBuffer *buf0 = NULL;
1088
1089   if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1090     return FALSE;
1091
1092   if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 4) {
1093     GST_WARNING ("First vorbis header too small, ignoring");
1094   } else {
1095     if (memcmp (GST_BUFFER_DATA (buf0) + 1, "vorbis", 6) == 0) {
1096       GstMatroskaTrackAudioContext *audiocontext;
1097       guint8 *hdr;
1098
1099       hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 4;
1100       audiocontext = (GstMatroskaTrackAudioContext *) context;
1101       audiocontext->channels = GST_READ_UINT8 (hdr);
1102       audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1103     }
1104   }
1105
1106   if (buf0)
1107     gst_buffer_unref (buf0);
1108
1109   return TRUE;
1110 }
1111
1112 static gboolean
1113 theora_streamheader_to_codecdata (const GValue * streamheader,
1114     GstMatroskaTrackContext * context)
1115 {
1116   GstBuffer *buf0 = NULL;
1117
1118   if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1119     return FALSE;
1120
1121   if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 26) {
1122     GST_WARNING ("First theora header too small, ignoring");
1123   } else if (memcmp (GST_BUFFER_DATA (buf0), "\200theora\003\002", 9) != 0) {
1124     GST_WARNING ("First header not a theora identification header, ignoring");
1125   } else {
1126     GstMatroskaTrackVideoContext *videocontext;
1127     guint fps_num, fps_denom, par_num, par_denom;
1128     guint8 *hdr;
1129
1130     hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 3 + 2 + 2;
1131
1132     videocontext = (GstMatroskaTrackVideoContext *) context;
1133     videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1134     videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1135     hdr += 3 + 3 + 1 + 1;
1136     fps_num = GST_READ_UINT32_BE (hdr);
1137     fps_denom = GST_READ_UINT32_BE (hdr + 4);
1138     context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1139         fps_denom, fps_num);
1140     hdr += 4 + 4;
1141     par_num = GST_READ_UINT32_BE (hdr) >> 8;
1142     par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1143     if (par_num > 0 && par_num > 0) {
1144       if (par_num > par_denom) {
1145         videocontext->display_width =
1146             videocontext->pixel_width * par_num / par_denom;
1147         videocontext->display_height = videocontext->pixel_height;
1148       } else if (par_num < par_denom) {
1149         videocontext->display_width = videocontext->pixel_width;
1150         videocontext->display_height =
1151             videocontext->pixel_height * par_denom / par_num;
1152       } else {
1153         videocontext->display_width = 0;
1154         videocontext->display_height = 0;
1155       }
1156     } else {
1157       videocontext->display_width = 0;
1158       videocontext->display_height = 0;
1159     }
1160     hdr += 3 + 3;
1161   }
1162
1163   if (buf0)
1164     gst_buffer_unref (buf0);
1165
1166   return TRUE;
1167 }
1168
1169 static gboolean
1170 kate_streamheader_to_codecdata (const GValue * streamheader,
1171     GstMatroskaTrackContext * context)
1172 {
1173   GstBuffer *buf0 = NULL;
1174
1175   if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1176     return FALSE;
1177
1178   if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 64) {    /* Kate ID header is 64 bytes */
1179     GST_WARNING ("First kate header too small, ignoring");
1180   } else if (memcmp (GST_BUFFER_DATA (buf0), "\200kate\0\0\0", 8) != 0) {
1181     GST_WARNING ("First header not a kate identification header, ignoring");
1182   }
1183
1184   if (buf0)
1185     gst_buffer_unref (buf0);
1186
1187   return TRUE;
1188 }
1189
1190 static gboolean
1191 flac_streamheader_to_codecdata (const GValue * streamheader,
1192     GstMatroskaTrackContext * context)
1193 {
1194   GArray *bufarr;
1195   gint i;
1196   GValue *bufval;
1197   GstBuffer *buffer;
1198
1199   if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1200     GST_WARNING ("No or invalid streamheader field in the caps");
1201     return FALSE;
1202   }
1203
1204   bufarr = g_value_peek_pointer (streamheader);
1205   if (bufarr->len < 2) {
1206     GST_WARNING ("Too few headers in streamheader field");
1207     return FALSE;
1208   }
1209
1210   context->xiph_headers_to_skip = bufarr->len + 1;
1211
1212   bufval = &g_array_index (bufarr, GValue, 0);
1213   if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1214     GST_WARNING ("streamheaders array does not contain GstBuffers");
1215     return FALSE;
1216   }
1217
1218   buffer = g_value_peek_pointer (bufval);
1219
1220   /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1221   if (GST_BUFFER_SIZE (buffer) < 9 + 4 + 4 + 34
1222       || memcmp (GST_BUFFER_DATA (buffer) + 1, "FLAC", 4) != 0
1223       || memcmp (GST_BUFFER_DATA (buffer) + 9, "fLaC", 4) != 0) {
1224     GST_WARNING ("Invalid streamheader for FLAC");
1225     return FALSE;
1226   }
1227
1228   context->codec_priv = g_malloc (GST_BUFFER_SIZE (buffer) - 9);
1229   context->codec_priv_size = GST_BUFFER_SIZE (buffer) - 9;
1230   memcpy (context->codec_priv, GST_BUFFER_DATA (buffer) + 9,
1231       GST_BUFFER_SIZE (buffer) - 9);
1232
1233   for (i = 1; i < bufarr->len; i++) {
1234     bufval = &g_array_index (bufarr, GValue, i);
1235
1236     if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1237       g_free (context->codec_priv);
1238       context->codec_priv = NULL;
1239       context->codec_priv_size = 0;
1240       GST_WARNING ("streamheaders array does not contain GstBuffers");
1241       return FALSE;
1242     }
1243
1244     buffer = g_value_peek_pointer (bufval);
1245
1246     context->codec_priv =
1247         g_realloc (context->codec_priv,
1248         context->codec_priv_size + GST_BUFFER_SIZE (buffer));
1249     memcpy ((guint8 *) context->codec_priv + context->codec_priv_size,
1250         GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
1251     context->codec_priv_size =
1252         context->codec_priv_size + GST_BUFFER_SIZE (buffer);
1253   }
1254
1255   return TRUE;
1256 }
1257
1258 static gboolean
1259 speex_streamheader_to_codecdata (const GValue * streamheader,
1260     GstMatroskaTrackContext * context)
1261 {
1262   GArray *bufarr;
1263   GValue *bufval;
1264   GstBuffer *buffer;
1265
1266   if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1267     GST_WARNING ("No or invalid streamheader field in the caps");
1268     return FALSE;
1269   }
1270
1271   bufarr = g_value_peek_pointer (streamheader);
1272   if (bufarr->len != 2) {
1273     GST_WARNING ("Too few headers in streamheader field");
1274     return FALSE;
1275   }
1276
1277   context->xiph_headers_to_skip = bufarr->len + 1;
1278
1279   bufval = &g_array_index (bufarr, GValue, 0);
1280   if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1281     GST_WARNING ("streamheaders array does not contain GstBuffers");
1282     return FALSE;
1283   }
1284
1285   buffer = g_value_peek_pointer (bufval);
1286
1287   if (GST_BUFFER_SIZE (buffer) < 80
1288       || memcmp (GST_BUFFER_DATA (buffer), "Speex   ", 8) != 0) {
1289     GST_WARNING ("Invalid streamheader for Speex");
1290     return FALSE;
1291   }
1292
1293   context->codec_priv = g_malloc (GST_BUFFER_SIZE (buffer));
1294   context->codec_priv_size = GST_BUFFER_SIZE (buffer);
1295   memcpy (context->codec_priv, GST_BUFFER_DATA (buffer),
1296       GST_BUFFER_SIZE (buffer));
1297
1298   bufval = &g_array_index (bufarr, GValue, 1);
1299
1300   if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1301     g_free (context->codec_priv);
1302     context->codec_priv = NULL;
1303     context->codec_priv_size = 0;
1304     GST_WARNING ("streamheaders array does not contain GstBuffers");
1305     return FALSE;
1306   }
1307
1308   buffer = g_value_peek_pointer (bufval);
1309
1310   context->codec_priv =
1311       g_realloc (context->codec_priv,
1312       context->codec_priv_size + GST_BUFFER_SIZE (buffer));
1313   memcpy ((guint8 *) context->codec_priv + context->codec_priv_size,
1314       GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
1315   context->codec_priv_size =
1316       context->codec_priv_size + GST_BUFFER_SIZE (buffer);
1317
1318   return TRUE;
1319 }
1320
1321 static const gchar *
1322 aac_codec_data_to_codec_id (const GstBuffer * buf)
1323 {
1324   const gchar *result;
1325   gint profile;
1326
1327   /* default to MAIN */
1328   profile = 1;
1329
1330   if (GST_BUFFER_SIZE (buf) >= 2) {
1331     profile = GST_READ_UINT8 (GST_BUFFER_DATA (buf));
1332     profile >>= 3;
1333   }
1334
1335   switch (profile) {
1336     case 1:
1337       result = "MAIN";
1338       break;
1339     case 2:
1340       result = "LC";
1341       break;
1342     case 3:
1343       result = "SSR";
1344       break;
1345     case 4:
1346       result = "LTP";
1347       break;
1348     default:
1349       GST_WARNING ("unknown AAC profile, defaulting to MAIN");
1350       result = "MAIN";
1351       break;
1352   }
1353
1354   return result;
1355 }
1356
1357 /**
1358  * gst_matroska_mux_audio_pad_setcaps:
1359  * @pad: Pad which got the caps.
1360  * @caps: New caps.
1361  *
1362  * Setcaps function for audio sink pad.
1363  *
1364  * Returns: #TRUE on success.
1365  */
1366 static gboolean
1367 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1368 {
1369   GstMatroskaTrackContext *context = NULL;
1370   GstMatroskaTrackAudioContext *audiocontext;
1371   GstMatroskaMux *mux;
1372   GstMatroskaPad *collect_pad;
1373   const gchar *mimetype;
1374   gint samplerate = 0, channels = 0;
1375   GstStructure *structure;
1376   const GValue *codec_data = NULL;
1377   const GstBuffer *buf = NULL;
1378   const gchar *stream_format = NULL;
1379
1380   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1381
1382   /* find context */
1383   collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1384   g_assert (collect_pad);
1385   context = collect_pad->track;
1386   g_assert (context);
1387   g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
1388   audiocontext = (GstMatroskaTrackAudioContext *) context;
1389
1390   structure = gst_caps_get_structure (caps, 0);
1391   mimetype = gst_structure_get_name (structure);
1392
1393   /* general setup */
1394   gst_structure_get_int (structure, "rate", &samplerate);
1395   gst_structure_get_int (structure, "channels", &channels);
1396
1397   audiocontext->samplerate = samplerate;
1398   audiocontext->channels = channels;
1399   audiocontext->bitdepth = 0;
1400   context->default_duration = 0;
1401
1402   codec_data = gst_structure_get_value (structure, "codec_data");
1403   if (codec_data)
1404     buf = gst_value_get_buffer (codec_data);
1405
1406   /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1407    *         data and other settings
1408    *       - add new formats
1409    */
1410
1411   if (!strcmp (mimetype, "audio/mpeg")) {
1412     gint mpegversion = 0;
1413
1414     gst_structure_get_int (structure, "mpegversion", &mpegversion);
1415     switch (mpegversion) {
1416       case 1:{
1417         gint layer;
1418         gint version = 1;
1419         gint spf;
1420
1421         gst_structure_get_int (structure, "layer", &layer);
1422
1423         if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
1424           GST_WARNING_OBJECT (mux,
1425               "Unable to determine MPEG audio version, assuming 1");
1426           version = 1;
1427         }
1428
1429         if (layer == 1)
1430           spf = 384;
1431         else if (layer == 2)
1432           spf = 1152;
1433         else if (version == 2)
1434           spf = 576;
1435         else
1436           spf = 1152;
1437
1438         context->default_duration =
1439             gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
1440
1441         switch (layer) {
1442           case 1:
1443             context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
1444             break;
1445           case 2:
1446             context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
1447             break;
1448           case 3:
1449             context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
1450             break;
1451           default:
1452             goto refuse_caps;
1453         }
1454         break;
1455       }
1456       case 2:
1457       case 4:
1458         stream_format = gst_structure_get_string (structure, "stream-format");
1459         /* check this is raw aac */
1460         if (stream_format) {
1461           if (strcmp (stream_format, "raw") != 0) {
1462             GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
1463                 stream_format);
1464           }
1465         } else {
1466           GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
1467               "assuming 'raw'");
1468         }
1469
1470         if (buf) {
1471           if (mpegversion == 2)
1472             context->codec_id =
1473                 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2 "%s",
1474                 aac_codec_data_to_codec_id (buf));
1475           else if (mpegversion == 4)
1476             context->codec_id =
1477                 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4 "%s",
1478                 aac_codec_data_to_codec_id (buf));
1479           else
1480             g_assert_not_reached ();
1481         } else {
1482           GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
1483           goto refuse_caps;
1484         }
1485         break;
1486       default:
1487         goto refuse_caps;
1488     }
1489   } else if (!strcmp (mimetype, "audio/x-raw-int")) {
1490     gint width, depth;
1491     gint endianness = G_LITTLE_ENDIAN;
1492     gboolean signedness = TRUE;
1493
1494     if (!gst_structure_get_int (structure, "width", &width) ||
1495         !gst_structure_get_int (structure, "depth", &depth) ||
1496         !gst_structure_get_boolean (structure, "signed", &signedness)) {
1497       GST_DEBUG_OBJECT (mux, "broken caps, width/depth/signed field missing");
1498       goto refuse_caps;
1499     }
1500
1501     if (depth > 8 &&
1502         !gst_structure_get_int (structure, "endianness", &endianness)) {
1503       GST_DEBUG_OBJECT (mux, "broken caps, no endianness specified");
1504       goto refuse_caps;
1505     }
1506
1507     if (width != depth) {
1508       GST_DEBUG_OBJECT (mux, "width must be same as depth!");
1509       goto refuse_caps;
1510     }
1511
1512     /* FIXME: where is this spec'ed out? (tpm) */
1513     if ((width == 8 && signedness) || (width >= 16 && !signedness)) {
1514       GST_DEBUG_OBJECT (mux, "8-bit PCM must be unsigned, 16-bit PCM signed");
1515       goto refuse_caps;
1516     }
1517
1518     audiocontext->bitdepth = depth;
1519     if (endianness == G_BIG_ENDIAN)
1520       context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
1521     else
1522       context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
1523
1524   } else if (!strcmp (mimetype, "audio/x-raw-float")) {
1525     gint width;
1526
1527     if (!gst_structure_get_int (structure, "width", &width)) {
1528       GST_DEBUG_OBJECT (mux, "broken caps, width field missing");
1529       goto refuse_caps;
1530     }
1531
1532     audiocontext->bitdepth = width;
1533     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
1534
1535   } else if (!strcmp (mimetype, "audio/x-vorbis")) {
1536     const GValue *streamheader;
1537
1538     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
1539
1540     if (context->codec_priv != NULL) {
1541       g_free (context->codec_priv);
1542       context->codec_priv = NULL;
1543       context->codec_priv_size = 0;
1544     }
1545
1546     streamheader = gst_structure_get_value (structure, "streamheader");
1547     if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
1548       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1549           ("vorbis stream headers missing or malformed"));
1550       goto refuse_caps;
1551     }
1552   } else if (!strcmp (mimetype, "audio/x-flac")) {
1553     const GValue *streamheader;
1554
1555     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
1556     if (context->codec_priv != NULL) {
1557       g_free (context->codec_priv);
1558       context->codec_priv = NULL;
1559       context->codec_priv_size = 0;
1560     }
1561
1562     streamheader = gst_structure_get_value (structure, "streamheader");
1563     if (!flac_streamheader_to_codecdata (streamheader, context)) {
1564       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1565           ("flac stream headers missing or malformed"));
1566       goto refuse_caps;
1567     }
1568   } else if (!strcmp (mimetype, "audio/x-speex")) {
1569     const GValue *streamheader;
1570
1571     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
1572     if (context->codec_priv != NULL) {
1573       g_free (context->codec_priv);
1574       context->codec_priv = NULL;
1575       context->codec_priv_size = 0;
1576     }
1577
1578     streamheader = gst_structure_get_value (structure, "streamheader");
1579     if (!speex_streamheader_to_codecdata (streamheader, context)) {
1580       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1581           ("speex stream headers missing or malformed"));
1582       goto refuse_caps;
1583     }
1584   } else if (!strcmp (mimetype, "audio/x-ac3")) {
1585     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AC3);
1586   } else if (!strcmp (mimetype, "audio/x-eac3")) {
1587     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
1588   } else if (!strcmp (mimetype, "audio/x-dts")) {
1589     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_DTS);
1590   } else if (!strcmp (mimetype, "audio/x-tta")) {
1591     gint width;
1592
1593     /* TTA frame duration */
1594     context->default_duration = 1.04489795918367346939 * GST_SECOND;
1595
1596     gst_structure_get_int (structure, "width", &width);
1597     audiocontext->bitdepth = width;
1598     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_TTA);
1599
1600   } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
1601     gint raversion;
1602     const GValue *mdpr_data;
1603
1604     gst_structure_get_int (structure, "raversion", &raversion);
1605     switch (raversion) {
1606       case 1:
1607         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
1608         break;
1609       case 2:
1610         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
1611         break;
1612       case 8:
1613         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
1614         break;
1615       default:
1616         goto refuse_caps;
1617     }
1618
1619     mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1620     if (mdpr_data != NULL) {
1621       guint8 *priv_data = NULL;
1622       guint priv_data_size = 0;
1623
1624       GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1625
1626       priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
1627       priv_data = g_malloc0 (priv_data_size);
1628
1629       memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
1630
1631       context->codec_priv = priv_data;
1632       context->codec_priv_size = priv_data_size;
1633     }
1634
1635   } else if (!strcmp (mimetype, "audio/x-wma")) {
1636     guint8 *codec_priv;
1637     guint codec_priv_size;
1638     guint16 format;
1639     gint block_align;
1640     gint bitrate;
1641     gint wmaversion;
1642     gint depth;
1643
1644     if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
1645         || !gst_structure_get_int (structure, "block_align", &block_align)
1646         || !gst_structure_get_int (structure, "bitrate", &bitrate)
1647         || samplerate == 0 || channels == 0) {
1648       GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate/"
1649           "channels/rate on WMA caps");
1650       goto refuse_caps;
1651     }
1652
1653     switch (wmaversion) {
1654       case 1:
1655         format = GST_RIFF_WAVE_FORMAT_WMAV1;
1656         break;
1657       case 2:
1658         format = GST_RIFF_WAVE_FORMAT_WMAV2;
1659         break;
1660       case 3:
1661         format = GST_RIFF_WAVE_FORMAT_WMAV3;
1662         break;
1663       default:
1664         GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
1665         goto refuse_caps;
1666     }
1667
1668     if (gst_structure_get_int (structure, "depth", &depth))
1669       audiocontext->bitdepth = depth;
1670
1671     codec_priv_size = WAVEFORMATEX_SIZE;
1672     if (buf)
1673       codec_priv_size += GST_BUFFER_SIZE (buf);
1674
1675     /* serialize waveformatex structure */
1676     codec_priv = g_malloc0 (codec_priv_size);
1677     GST_WRITE_UINT16_LE (codec_priv, format);
1678     GST_WRITE_UINT16_LE (codec_priv + 2, channels);
1679     GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
1680     GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
1681     GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
1682     GST_WRITE_UINT16_LE (codec_priv + 14, 0);
1683     if (buf)
1684       GST_WRITE_UINT16_LE (codec_priv + 16, GST_BUFFER_SIZE (buf));
1685     else
1686       GST_WRITE_UINT16_LE (codec_priv + 16, 0);
1687
1688     /* process codec private/initialization data, if any */
1689     if (buf) {
1690       memcpy ((guint8 *) codec_priv + WAVEFORMATEX_SIZE,
1691           GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
1692     }
1693
1694     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_ACM);
1695     context->codec_priv = (gpointer) codec_priv;
1696     context->codec_priv_size = codec_priv_size;
1697   }
1698
1699   return TRUE;
1700
1701   /* ERRORS */
1702 refuse_caps:
1703   {
1704     GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1705         GST_PAD_NAME (pad), caps);
1706     return FALSE;
1707   }
1708 }
1709
1710
1711 /**
1712  * gst_matroska_mux_subtitle_pad_setcaps:
1713  * @pad: Pad which got the caps.
1714  * @caps: New caps.
1715  *
1716  * Setcaps function for subtitle sink pad.
1717  *
1718  * Returns: #TRUE on success.
1719  */
1720 static gboolean
1721 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
1722 {
1723   /* FIXME:
1724    * Consider this as boilerplate code for now. There is
1725    * no single subtitle creation element in GStreamer,
1726    * neither do I know how subtitling works at all. */
1727
1728   /* There is now (at least) one such alement (kateenc), and I'm going
1729      to handle it here and claim it works when it can be piped back
1730      through GStreamer and VLC */
1731
1732   GstMatroskaTrackContext *context = NULL;
1733   GstMatroskaTrackSubtitleContext *scontext;
1734   GstMatroskaMux *mux;
1735   GstMatroskaPad *collect_pad;
1736   const gchar *mimetype;
1737   GstStructure *structure;
1738
1739   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1740
1741   /* find context */
1742   collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1743   g_assert (collect_pad);
1744   context = collect_pad->track;
1745   g_assert (context);
1746   g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
1747   scontext = (GstMatroskaTrackSubtitleContext *) context;
1748
1749   structure = gst_caps_get_structure (caps, 0);
1750   mimetype = gst_structure_get_name (structure);
1751
1752   /* general setup */
1753   scontext->check_utf8 = 1;
1754   scontext->invalid_utf8 = 0;
1755   context->default_duration = 0;
1756
1757   /* TODO: - other format than Kate */
1758
1759   if (!strcmp (mimetype, "subtitle/x-kate")) {
1760     const GValue *streamheader;
1761
1762     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
1763
1764     if (context->codec_priv != NULL) {
1765       g_free (context->codec_priv);
1766       context->codec_priv = NULL;
1767       context->codec_priv_size = 0;
1768     }
1769
1770     streamheader = gst_structure_get_value (structure, "streamheader");
1771     if (!kate_streamheader_to_codecdata (streamheader, context)) {
1772       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1773           ("kate stream headers missing or malformed"));
1774       return FALSE;
1775     }
1776     return TRUE;
1777   }
1778
1779   return FALSE;
1780 }
1781
1782
1783 /**
1784  * gst_matroska_mux_request_new_pad:
1785  * @element: #GstMatroskaMux.
1786  * @templ: #GstPadTemplate.
1787  * @pad_name: New pad name.
1788  *
1789  * Request pad function for sink templates.
1790  *
1791  * Returns: New #GstPad.
1792  */
1793 static GstPad *
1794 gst_matroska_mux_request_new_pad (GstElement * element,
1795     GstPadTemplate * templ, const gchar * req_name)
1796 {
1797   GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
1798   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
1799   GstMatroskaPad *collect_pad;
1800   GstPad *newpad = NULL;
1801   gchar *name = NULL;
1802   const gchar *pad_name = NULL;
1803   GstPadSetCapsFunction setcapsfunc = NULL;
1804   GstMatroskaTrackContext *context = NULL;
1805   gint pad_id;
1806
1807   if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
1808     /* don't mix named and unnamed pads, if the pad already exists we fail when
1809      * trying to add it */
1810     if (req_name != NULL && sscanf (req_name, "audio_%d", &pad_id) == 1) {
1811       pad_name = req_name;
1812     } else {
1813       name = g_strdup_printf ("audio_%d", mux->num_a_streams++);
1814       pad_name = name;
1815     }
1816     setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
1817     context = (GstMatroskaTrackContext *)
1818         g_new0 (GstMatroskaTrackAudioContext, 1);
1819     context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
1820     context->name = g_strdup ("Audio");
1821   } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
1822     /* don't mix named and unnamed pads, if the pad already exists we fail when
1823      * trying to add it */
1824     if (req_name != NULL && sscanf (req_name, "video_%d", &pad_id) == 1) {
1825       pad_name = req_name;
1826     } else {
1827       name = g_strdup_printf ("video_%d", mux->num_v_streams++);
1828       pad_name = name;
1829     }
1830     setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
1831     context = (GstMatroskaTrackContext *)
1832         g_new0 (GstMatroskaTrackVideoContext, 1);
1833     context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
1834     context->name = g_strdup ("Video");
1835   } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%d")) {
1836     /* don't mix named and unnamed pads, if the pad already exists we fail when
1837      * trying to add it */
1838     if (req_name != NULL && sscanf (req_name, "subtitle_%d", &pad_id) == 1) {
1839       pad_name = req_name;
1840     } else {
1841       name = g_strdup_printf ("subtitle_%d", mux->num_t_streams++);
1842       pad_name = name;
1843     }
1844     setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
1845     context = (GstMatroskaTrackContext *)
1846         g_new0 (GstMatroskaTrackSubtitleContext, 1);
1847     context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
1848     context->name = g_strdup ("Subtitle");
1849   } else {
1850     GST_WARNING_OBJECT (mux, "This is not our template!");
1851     return NULL;
1852   }
1853
1854   newpad = gst_pad_new_from_template (templ, pad_name);
1855   g_free (name);
1856   collect_pad = (GstMatroskaPad *)
1857       gst_collect_pads_add_pad_full (mux->collect, newpad,
1858       sizeof (GstMatroskaPad),
1859       (GstCollectDataDestroyNotify) gst_matroska_pad_free);
1860
1861   collect_pad->track = context;
1862   gst_matroska_pad_reset (collect_pad, FALSE);
1863
1864   /* FIXME: hacked way to override/extend the event function of
1865    * GstCollectPads; because it sets its own event function giving the
1866    * element no access to events.
1867    * TODO GstCollectPads should really give its 'users' a clean chance to
1868    * properly handle events that are not meant for collectpads itself.
1869    * Perhaps a callback or so, though rejected (?) in #340060.
1870    * This would allow (clean) transcoding of info from demuxer/streams
1871    * to another muxer */
1872   mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
1873   gst_pad_set_event_function (newpad,
1874       GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event));
1875
1876   gst_pad_set_setcaps_function (newpad, setcapsfunc);
1877   gst_pad_set_active (newpad, TRUE);
1878   if (!gst_element_add_pad (element, newpad))
1879     goto pad_add_failed;
1880
1881   mux->num_streams++;
1882
1883   GST_DEBUG_OBJECT (newpad, "Added new request pad");
1884
1885   return newpad;
1886
1887   /* ERROR cases */
1888 pad_add_failed:
1889   {
1890     GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
1891     gst_object_unref (newpad);
1892     return NULL;
1893   }
1894 }
1895
1896 /**
1897  * gst_matroska_mux_release_pad:
1898  * @element: #GstMatroskaMux.
1899  * @pad: Pad to release.
1900  *
1901  * Release a previously requested pad.
1902 */
1903 static void
1904 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
1905 {
1906   GstMatroskaMux *mux;
1907   GSList *walk;
1908
1909   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1910
1911   for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
1912     GstCollectData *cdata = (GstCollectData *) walk->data;
1913     GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
1914
1915     if (cdata->pad == pad) {
1916       GstClockTime min_dur;     /* observed minimum duration */
1917
1918       if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
1919           GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
1920         min_dur = GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
1921         if (collect_pad->duration < min_dur)
1922           collect_pad->duration = min_dur;
1923       }
1924
1925       if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
1926           mux->duration < collect_pad->duration)
1927         mux->duration = collect_pad->duration;
1928
1929       break;
1930     }
1931   }
1932
1933   gst_collect_pads_remove_pad (mux->collect, pad);
1934   if (gst_element_remove_pad (element, pad))
1935     mux->num_streams--;
1936 }
1937
1938
1939 /**
1940  * gst_matroska_mux_track_header:
1941  * @mux: #GstMatroskaMux
1942  * @context: Tack context.
1943  *
1944  * Write a track header.
1945  */
1946 static void
1947 gst_matroska_mux_track_header (GstMatroskaMux * mux,
1948     GstMatroskaTrackContext * context)
1949 {
1950   GstEbmlWrite *ebml = mux->ebml_write;
1951   guint64 master;
1952
1953   /* TODO: check if everything necessary is written and check default values */
1954
1955   /* track type goes before the type-specific stuff */
1956   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
1957   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
1958
1959   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID,
1960       gst_matroska_mux_create_uid ());
1961   if (context->default_duration) {
1962     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
1963         context->default_duration);
1964   }
1965   if (context->language) {
1966     gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
1967         context->language);
1968   }
1969
1970   /* type-specific stuff */
1971   switch (context->type) {
1972     case GST_MATROSKA_TRACK_TYPE_VIDEO:{
1973       GstMatroskaTrackVideoContext *videocontext =
1974           (GstMatroskaTrackVideoContext *) context;
1975
1976       master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
1977       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
1978           videocontext->pixel_width);
1979       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
1980           videocontext->pixel_height);
1981       if (videocontext->display_width && videocontext->display_height) {
1982         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
1983             videocontext->display_width);
1984         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
1985             videocontext->display_height);
1986       }
1987       if (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED)
1988         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
1989       if (videocontext->fourcc) {
1990         guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
1991
1992         gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
1993             (gpointer) & fcc_le, 4);
1994       }
1995       gst_ebml_write_master_finish (ebml, master);
1996
1997       break;
1998     }
1999
2000     case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2001       GstMatroskaTrackAudioContext *audiocontext =
2002           (GstMatroskaTrackAudioContext *) context;
2003
2004       master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2005       if (audiocontext->samplerate != 8000)
2006         gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2007             audiocontext->samplerate);
2008       if (audiocontext->channels != 1)
2009         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2010             audiocontext->channels);
2011       if (audiocontext->bitdepth) {
2012         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2013             audiocontext->bitdepth);
2014       }
2015       gst_ebml_write_master_finish (ebml, master);
2016
2017       break;
2018     }
2019
2020     default:
2021       /* doesn't need type-specific data */
2022       break;
2023   }
2024
2025   gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2026   if (context->codec_priv)
2027     gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2028         context->codec_priv, context->codec_priv_size);
2029   /* FIXME: until we have a nice way of getting the codecname
2030    * out of the caps, I'm not going to enable this. Too much
2031    * (useless, double, boring) work... */
2032   /* TODO: Use value from tags if any */
2033   /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2034      context->codec_name); */
2035   gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2036 }
2037
2038
2039 /**
2040  * gst_matroska_mux_start:
2041  * @mux: #GstMatroskaMux
2042  *
2043  * Start a new matroska file (write headers etc...)
2044  */
2045 static void
2046 gst_matroska_mux_start (GstMatroskaMux * mux)
2047 {
2048   GstEbmlWrite *ebml = mux->ebml_write;
2049   const gchar *doctype;
2050   guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
2051     GST_MATROSKA_ID_TRACKS,
2052     GST_MATROSKA_ID_CUES,
2053     GST_MATROSKA_ID_TAGS,
2054     0
2055   };
2056   guint64 master, child;
2057   GSList *collected;
2058   int i;
2059   guint tracknum = 1;
2060   GstClockTime duration = 0;
2061   guint32 segment_uid[4];
2062   GTimeVal time = { 0, 0 };
2063
2064   if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2065     ebml->caps = gst_caps_new_simple ("video/webm", NULL);
2066   } else {
2067     ebml->caps = gst_caps_new_simple ("video/x-matroska", NULL);
2068   }
2069   /* we start with a EBML header */
2070   doctype = mux->doctype;
2071   GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
2072       doctype, mux->doctype_version);
2073   gst_ebml_write_header (ebml, doctype, mux->doctype_version);
2074
2075   /* the rest of the header is cached */
2076   gst_ebml_write_set_cache (ebml, 0x1000);
2077
2078   /* start a segment */
2079   mux->segment_pos =
2080       gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
2081   mux->segment_master = ebml->pos;
2082
2083   if (!mux->streamable) {
2084     /* seekhead (table of contents) - we set the positions later */
2085     mux->seekhead_pos = ebml->pos;
2086     master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
2087     for (i = 0; seekhead_id[i] != 0; i++) {
2088       child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
2089       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
2090       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
2091       gst_ebml_write_master_finish (ebml, child);
2092     }
2093     gst_ebml_write_master_finish (ebml, master);
2094   }
2095
2096   /* segment info */
2097   mux->info_pos = ebml->pos;
2098   master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
2099   for (i = 0; i < 4; i++) {
2100     segment_uid[i] = g_random_int ();
2101   }
2102   gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
2103       (guint8 *) segment_uid, 16);
2104   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
2105   mux->duration_pos = ebml->pos;
2106   /* get duration */
2107   if (!mux->streamable) {
2108     for (collected = mux->collect->data; collected;
2109         collected = g_slist_next (collected)) {
2110       GstMatroskaPad *collect_pad;
2111       GstFormat format = GST_FORMAT_TIME;
2112       GstPad *thepad;
2113       gint64 trackduration;
2114
2115       collect_pad = (GstMatroskaPad *) collected->data;
2116       thepad = collect_pad->collect.pad;
2117
2118       /* Query the total length of the track. */
2119       GST_DEBUG_OBJECT (thepad, "querying peer duration");
2120       if (gst_pad_query_peer_duration (thepad, &format, &trackduration)) {
2121         GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
2122             GST_TIME_ARGS (trackduration));
2123         if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
2124           duration = (GstClockTime) trackduration;
2125         }
2126       }
2127     }
2128     gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2129         gst_guint64_to_gdouble (duration) /
2130         gst_guint64_to_gdouble (mux->time_scale));
2131   }
2132   gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
2133       "GStreamer plugin version " PACKAGE_VERSION);
2134   if (mux->writing_app && mux->writing_app[0]) {
2135     gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
2136   }
2137   g_get_current_time (&time);
2138   gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
2139   gst_ebml_write_master_finish (ebml, master);
2140
2141   /* tracks */
2142   mux->tracks_pos = ebml->pos;
2143   master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
2144
2145   for (collected = mux->collect->data; collected;
2146       collected = g_slist_next (collected)) {
2147     GstMatroskaPad *collect_pad;
2148     GstPad *thepad;
2149
2150     collect_pad = (GstMatroskaPad *) collected->data;
2151     thepad = collect_pad->collect.pad;
2152
2153     if (gst_pad_is_linked (thepad) && gst_pad_is_active (thepad) &&
2154         collect_pad->track->codec_id != 0) {
2155       collect_pad->track->num = tracknum++;
2156       child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
2157       gst_matroska_mux_track_header (mux, collect_pad->track);
2158       gst_ebml_write_master_finish (ebml, child);
2159     }
2160   }
2161   gst_ebml_write_master_finish (ebml, master);
2162
2163   /* lastly, flush the cache */
2164   gst_ebml_write_flush_cache (ebml, FALSE, 0);
2165 }
2166
2167 static void
2168 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
2169     gpointer data)
2170 {
2171   /* TODO: more sensible tag mappings */
2172   static const struct
2173   {
2174     const gchar *matroska_tagname;
2175     const gchar *gstreamer_tagname;
2176   }
2177   tag_conv[] = {
2178     {
2179     GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
2180     GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
2181     GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
2182     GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
2183     GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
2184     GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
2185     GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
2186     GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
2187     GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
2188     GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
2189     GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
2190     GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
2191     GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
2192     GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
2193     GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
2194   };
2195   GstEbmlWrite *ebml = (GstEbmlWrite *) data;
2196   guint i;
2197   guint64 simpletag_master;
2198
2199   for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) {
2200     const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
2201     const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
2202
2203     if (strcmp (tagname_gst, tag) == 0) {
2204       GValue src = { 0, };
2205       gchar *dest;
2206
2207       if (!gst_tag_list_copy_value (&src, list, tag))
2208         break;
2209       if ((dest = gst_value_serialize (&src))) {
2210
2211         simpletag_master = gst_ebml_write_master_start (ebml,
2212             GST_MATROSKA_ID_SIMPLETAG);
2213         gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
2214         gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
2215         gst_ebml_write_master_finish (ebml, simpletag_master);
2216         g_free (dest);
2217       } else {
2218         GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
2219       }
2220       g_value_unset (&src);
2221       break;
2222     }
2223   }
2224 }
2225
2226
2227 /**
2228  * gst_matroska_mux_finish:
2229  * @mux: #GstMatroskaMux
2230  *
2231  * Finish a new matroska file (write index etc...)
2232  */
2233 static void
2234 gst_matroska_mux_finish (GstMatroskaMux * mux)
2235 {
2236   GstEbmlWrite *ebml = mux->ebml_write;
2237   guint64 pos;
2238   guint64 duration = 0;
2239   GSList *collected;
2240   const GstTagList *tags;
2241
2242   /* finish last cluster */
2243   if (mux->cluster) {
2244     gst_ebml_write_master_finish (ebml, mux->cluster);
2245   }
2246
2247   /* cues */
2248   if (mux->index != NULL) {
2249     guint n;
2250     guint64 master, pointentry_master, trackpos_master;
2251
2252     mux->cues_pos = ebml->pos;
2253     gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
2254     master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
2255
2256     for (n = 0; n < mux->num_indexes; n++) {
2257       GstMatroskaIndex *idx = &mux->index[n];
2258
2259       pointentry_master = gst_ebml_write_master_start (ebml,
2260           GST_MATROSKA_ID_POINTENTRY);
2261       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
2262           idx->time / mux->time_scale);
2263       trackpos_master = gst_ebml_write_master_start (ebml,
2264           GST_MATROSKA_ID_CUETRACKPOSITIONS);
2265       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
2266       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
2267           idx->pos - mux->segment_master);
2268       gst_ebml_write_master_finish (ebml, trackpos_master);
2269       gst_ebml_write_master_finish (ebml, pointentry_master);
2270     }
2271
2272     gst_ebml_write_master_finish (ebml, master);
2273     gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
2274   }
2275
2276   /* tags */
2277   tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2278
2279   if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2280     guint64 master_tags, master_tag;
2281
2282     GST_DEBUG ("Writing tags");
2283
2284     /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2285     mux->tags_pos = ebml->pos;
2286     master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2287     master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2288     gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2289     gst_ebml_write_master_finish (ebml, master_tag);
2290     gst_ebml_write_master_finish (ebml, master_tags);
2291   }
2292
2293   /* update seekhead. We know that:
2294    * - a seekhead contains 4 entries.
2295    * - order of entries is as above.
2296    * - a seekhead has a 4-byte header + 8-byte length
2297    * - each entry is 2-byte master, 2-byte ID pointer,
2298    *     2-byte length pointer, all 8/1-byte length, 4-
2299    *     byte ID and 8-byte length pointer, where the
2300    *     length pointer starts at 20.
2301    * - all entries are local to the segment (so pos - segment_master).
2302    * - so each entry is at 12 + 20 + num * 28. */
2303   gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
2304       mux->info_pos - mux->segment_master);
2305   gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
2306       mux->tracks_pos - mux->segment_master);
2307   if (mux->index != NULL) {
2308     gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
2309         mux->cues_pos - mux->segment_master);
2310   } else {
2311     /* void'ify */
2312     guint64 my_pos = ebml->pos;
2313
2314     gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
2315     gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2316     gst_ebml_write_seek (ebml, my_pos);
2317   }
2318   if (tags != NULL) {
2319     gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
2320         mux->tags_pos - mux->segment_master);
2321   } else {
2322     /* void'ify */
2323     guint64 my_pos = ebml->pos;
2324
2325     gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
2326     gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2327     gst_ebml_write_seek (ebml, my_pos);
2328   }
2329
2330   /* update duration */
2331   /* first get the overall duration */
2332   /* a released track may have left a duration in here */
2333   duration = mux->duration;
2334   for (collected = mux->collect->data; collected;
2335       collected = g_slist_next (collected)) {
2336     GstMatroskaPad *collect_pad;
2337     GstClockTime min_duration;  /* observed minimum duration */
2338
2339     collect_pad = (GstMatroskaPad *) collected->data;
2340
2341     GST_DEBUG_OBJECT (mux,
2342         "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
2343         " end ts %" GST_TIME_FORMAT, collect_pad,
2344         GST_TIME_ARGS (collect_pad->start_ts),
2345         GST_TIME_ARGS (collect_pad->end_ts));
2346
2347     if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2348         GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2349       min_duration =
2350           GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2351       if (collect_pad->duration < min_duration)
2352         collect_pad->duration = min_duration;
2353       GST_DEBUG_OBJECT (collect_pad,
2354           "final track duration: %" GST_TIME_FORMAT,
2355           GST_TIME_ARGS (collect_pad->duration));
2356     }
2357
2358     if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
2359         duration < collect_pad->duration)
2360       duration = collect_pad->duration;
2361   }
2362   if (duration != 0) {
2363     GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
2364         GST_TIME_ARGS (duration));
2365     pos = mux->ebml_write->pos;
2366     gst_ebml_write_seek (ebml, mux->duration_pos);
2367     gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2368         gst_guint64_to_gdouble (duration) /
2369         gst_guint64_to_gdouble (mux->time_scale));
2370     gst_ebml_write_seek (ebml, pos);
2371   } else {
2372     /* void'ify */
2373     guint64 my_pos = ebml->pos;
2374
2375     gst_ebml_write_seek (ebml, mux->duration_pos);
2376     gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
2377     gst_ebml_write_seek (ebml, my_pos);
2378   }
2379   GST_DEBUG_OBJECT (mux, "finishing segment");
2380   /* finish segment - this also writes element length */
2381   gst_ebml_write_master_finish (ebml, mux->segment_pos);
2382 }
2383
2384
2385 /**
2386  * gst_matroska_mux_best_pad:
2387  * @mux: #GstMatroskaMux
2388  * @popped: True if at least one buffer was popped from #GstCollectPads
2389  *
2390  * Find a pad with the oldest data
2391  * (data from this pad should be written first).
2392  *
2393  * Returns: Selected pad.
2394  */
2395 static GstMatroskaPad *
2396 gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
2397 {
2398   GSList *collected;
2399   GstMatroskaPad *best = NULL;
2400
2401   *popped = FALSE;
2402   for (collected = mux->collect->data; collected;
2403       collected = g_slist_next (collected)) {
2404     GstMatroskaPad *collect_pad;
2405
2406     collect_pad = (GstMatroskaPad *) collected->data;
2407     /* fetch a new buffer if needed */
2408     if (collect_pad->buffer == NULL) {
2409       collect_pad->buffer = gst_collect_pads_pop (mux->collect,
2410           (GstCollectData *) collect_pad);
2411
2412       if (collect_pad->buffer != NULL) {
2413         GstClockTime time;
2414
2415         *popped = TRUE;
2416         /* convert to running time */
2417         time = GST_BUFFER_TIMESTAMP (collect_pad->buffer);
2418         /* invalid should pass */
2419         if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
2420           time = gst_segment_to_running_time (&collect_pad->collect.segment,
2421               GST_FORMAT_TIME, time);
2422           if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
2423             GST_DEBUG_OBJECT (mux, "clipping buffer on pad %s outside segment",
2424                 GST_PAD_NAME (collect_pad->collect.pad));
2425             gst_buffer_unref (collect_pad->buffer);
2426             collect_pad->buffer = NULL;
2427             return NULL;
2428           } else {
2429             collect_pad->buffer =
2430                 gst_buffer_make_metadata_writable (collect_pad->buffer);
2431             GST_BUFFER_TIMESTAMP (collect_pad->buffer) = time;
2432           }
2433         }
2434       }
2435     }
2436
2437     /* if we have a buffer check if it is better then the current best one */
2438     if (collect_pad->buffer != NULL) {
2439       if (best == NULL || !GST_BUFFER_TIMESTAMP_IS_VALID (collect_pad->buffer)
2440           || (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)
2441               && GST_BUFFER_TIMESTAMP (collect_pad->buffer) <
2442               GST_BUFFER_TIMESTAMP (best->buffer))) {
2443         best = collect_pad;
2444       }
2445     }
2446   }
2447
2448   return best;
2449 }
2450
2451 /**
2452  * gst_matroska_mux_buffer_header:
2453  * @track: Track context.
2454  * @relative_timestamp: relative timestamp of the buffer
2455  * @flags: Buffer flags.
2456  *
2457  * Create a buffer containing buffer header.
2458  *
2459  * Returns: New buffer.
2460  */
2461 static GstBuffer *
2462 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
2463     gint16 relative_timestamp, int flags)
2464 {
2465   GstBuffer *hdr;
2466
2467   hdr = gst_buffer_new_and_alloc (4);
2468   /* track num - FIXME: what if num >= 0x80 (unlikely)? */
2469   GST_BUFFER_DATA (hdr)[0] = track->num | 0x80;
2470   /* time relative to clustertime */
2471   GST_WRITE_UINT16_BE (GST_BUFFER_DATA (hdr) + 1, relative_timestamp);
2472
2473   /* flags */
2474   GST_BUFFER_DATA (hdr)[3] = flags;
2475
2476   return hdr;
2477 }
2478
2479 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
2480 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
2481 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
2482
2483 static GstBuffer *
2484 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
2485     GstMatroskaPad * collect_pad, GstBuffer * buf)
2486 {
2487   GstMatroskaTrackVideoContext *ctx =
2488       (GstMatroskaTrackVideoContext *) collect_pad->track;
2489   const guint8 *data = GST_BUFFER_DATA (buf);
2490   guint size = GST_BUFFER_SIZE (buf);
2491   guint8 parse_code;
2492   guint32 next_parse_offset;
2493   GstBuffer *ret = NULL;
2494   gboolean is_muxing_unit = FALSE;
2495
2496   if (GST_BUFFER_SIZE (buf) < 13) {
2497     gst_buffer_unref (buf);
2498     return ret;
2499   }
2500
2501   /* Check if this buffer contains a picture or end-of-sequence packet */
2502   while (size >= 13) {
2503     if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
2504       gst_buffer_unref (buf);
2505       return ret;
2506     }
2507
2508     parse_code = GST_READ_UINT8 (data + 4);
2509     if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
2510       if (ctx->dirac_unit) {
2511         gst_buffer_unref (ctx->dirac_unit);
2512         ctx->dirac_unit = NULL;
2513       }
2514     } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
2515         parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
2516       is_muxing_unit = TRUE;
2517       break;
2518     }
2519
2520     next_parse_offset = GST_READ_UINT32_BE (data + 5);
2521
2522     if (G_UNLIKELY (next_parse_offset == 0))
2523       break;
2524
2525     data += next_parse_offset;
2526     size -= next_parse_offset;
2527   }
2528
2529   if (ctx->dirac_unit)
2530     ctx->dirac_unit = gst_buffer_join (ctx->dirac_unit, gst_buffer_ref (buf));
2531   else
2532     ctx->dirac_unit = gst_buffer_ref (buf);
2533
2534   if (is_muxing_unit) {
2535     ret = gst_buffer_make_metadata_writable (ctx->dirac_unit);
2536     ctx->dirac_unit = NULL;
2537     gst_buffer_copy_metadata (ret, buf,
2538         GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
2539         GST_BUFFER_COPY_CAPS);
2540     gst_buffer_unref (buf);
2541   } else {
2542     gst_buffer_unref (buf);
2543     ret = NULL;
2544   }
2545
2546   return ret;
2547 }
2548
2549 static void
2550 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
2551 {
2552   GstCaps *caps;
2553   GstStructure *s;
2554   GValue streamheader = { 0 };
2555   GValue bufval = { 0 };
2556   GstBuffer *streamheader_buffer;
2557   GstEbmlWrite *ebml = mux->ebml_write;
2558
2559   streamheader_buffer = gst_ebml_stop_streamheader (ebml);
2560   if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2561     caps = gst_caps_new_simple ("video/webm", NULL);
2562   } else {
2563     caps = gst_caps_new_simple ("video/x-matroska", NULL);
2564   }
2565   s = gst_caps_get_structure (caps, 0);
2566   g_value_init (&streamheader, GST_TYPE_ARRAY);
2567   g_value_init (&bufval, GST_TYPE_BUFFER);
2568   GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_IN_CAPS);
2569   gst_value_set_buffer (&bufval, streamheader_buffer);
2570   gst_value_array_append_value (&streamheader, &bufval);
2571   g_value_unset (&bufval);
2572   gst_structure_set_value (s, "streamheader", &streamheader);
2573   g_value_unset (&streamheader);
2574   gst_caps_replace (&ebml->caps, caps);
2575   gst_buffer_unref (streamheader_buffer);
2576   gst_caps_unref (caps);
2577 }
2578
2579 /**
2580  * gst_matroska_mux_write_data:
2581  * @mux: #GstMatroskaMux
2582  * @collect_pad: #GstMatroskaPad with the data
2583  *
2584  * Write collected data (called from gst_matroska_mux_collected).
2585  *
2586  * Returns: Result of the gst_pad_push issued to write the data.
2587  */
2588 static GstFlowReturn
2589 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
2590 {
2591   GstEbmlWrite *ebml = mux->ebml_write;
2592   GstBuffer *buf, *hdr;
2593   guint64 blockgroup;
2594   gboolean write_duration;
2595   gint16 relative_timestamp;
2596   gint64 relative_timestamp64;
2597   guint64 block_duration;
2598   gboolean is_video_keyframe = FALSE;
2599
2600   /* write data */
2601   buf = collect_pad->buffer;
2602   collect_pad->buffer = NULL;
2603
2604   /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
2605   if (collect_pad->track->xiph_headers_to_skip > 0) {
2606     GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
2607     gst_buffer_unref (buf);
2608     --collect_pad->track->xiph_headers_to_skip;
2609     return GST_FLOW_OK;
2610   }
2611
2612   /* for dirac we have to queue up everything up to a picture unit */
2613   if (collect_pad->track->codec_id != NULL &&
2614       strcmp (collect_pad->track->codec_id,
2615           GST_MATROSKA_CODEC_ID_VIDEO_DIRAC) == 0) {
2616     buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
2617     if (!buf)
2618       return GST_FLOW_OK;
2619   }
2620
2621   /* hm, invalid timestamp (due to --to be fixed--- element upstream);
2622    * this would wreak havoc with time stored in matroska file */
2623   /* TODO: maybe calculate a timestamp by using the previous timestamp
2624    * and default duration */
2625   if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2626     GST_WARNING_OBJECT (collect_pad->collect.pad,
2627         "Invalid buffer timestamp; dropping buffer");
2628     gst_buffer_unref (buf);
2629     return GST_FLOW_OK;
2630   }
2631
2632   /* set the timestamp for outgoing buffers */
2633   ebml->timestamp = GST_BUFFER_TIMESTAMP (buf);
2634
2635   if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
2636       !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
2637     GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
2638         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2639     is_video_keyframe = TRUE;
2640   }
2641
2642   if (mux->cluster) {
2643     /* start a new cluster at every keyframe or when we may be reaching the
2644      * limit of the relative timestamp */
2645     if (mux->cluster_time +
2646         mux->max_cluster_duration < GST_BUFFER_TIMESTAMP (buf)
2647         || is_video_keyframe) {
2648       if (!mux->streamable)
2649         gst_ebml_write_master_finish (ebml, mux->cluster);
2650       mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
2651       mux->cluster_pos = ebml->pos;
2652       gst_ebml_write_set_cache (ebml, 0x20);
2653       mux->cluster =
2654           gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2655       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2656           gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2657               mux->time_scale));
2658       GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
2659           gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2660               mux->time_scale));
2661       gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2662       mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2663       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
2664           mux->prev_cluster_size);
2665     }
2666   } else {
2667     /* first cluster */
2668
2669     mux->cluster_pos = ebml->pos;
2670     gst_ebml_write_set_cache (ebml, 0x20);
2671     mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2672     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2673         gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1, mux->time_scale));
2674     gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2675     mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2676   }
2677
2678   /* update duration of this track */
2679   if (GST_BUFFER_DURATION_IS_VALID (buf))
2680     collect_pad->duration += GST_BUFFER_DURATION (buf);
2681
2682   /* We currently write index entries for all video tracks or for the audio
2683    * track in a single-track audio file.  This could be improved by keeping the
2684    * index only for the *first* video track. */
2685
2686   /* TODO: index is useful for every track, should contain the number of
2687    * the block in the cluster which contains the timestamp, should also work
2688    * for files with multiple audio tracks.
2689    */
2690   if (is_video_keyframe ||
2691       ((collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
2692           (mux->num_streams == 1))) {
2693     gint last_idx = -1;
2694
2695     if (mux->min_index_interval != 0) {
2696       for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
2697         if (mux->index[last_idx].track == collect_pad->track->num)
2698           break;
2699       }
2700     }
2701
2702     if (last_idx < 0 || mux->min_index_interval == 0 ||
2703         (GST_CLOCK_DIFF (mux->index[last_idx].time, GST_BUFFER_TIMESTAMP (buf))
2704             >= mux->min_index_interval)) {
2705       GstMatroskaIndex *idx;
2706
2707       if (mux->num_indexes % 32 == 0) {
2708         mux->index = g_renew (GstMatroskaIndex, mux->index,
2709             mux->num_indexes + 32);
2710       }
2711       idx = &mux->index[mux->num_indexes++];
2712
2713       idx->pos = mux->cluster_pos;
2714       idx->time = GST_BUFFER_TIMESTAMP (buf);
2715       idx->track = collect_pad->track->num;
2716     }
2717   }
2718
2719   /* Check if the duration differs from the default duration. */
2720   write_duration = FALSE;
2721   block_duration = GST_BUFFER_DURATION (buf);
2722   if (GST_BUFFER_DURATION_IS_VALID (buf)) {
2723     if (block_duration != collect_pad->track->default_duration) {
2724       write_duration = TRUE;
2725     }
2726   }
2727
2728   /* write the block, for doctype v2 use SimpleBlock if possible
2729    * one slice (*breath*).
2730    * FIXME: Need to do correct lacing! */
2731   relative_timestamp64 = GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time;
2732   if (relative_timestamp64 >= 0) {
2733     /* round the timestamp */
2734     relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
2735   } else {
2736     /* round the timestamp */
2737     relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
2738   }
2739   relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
2740       mux->time_scale);
2741   if (mux->doctype_version > 1 && !write_duration) {
2742     int flags =
2743         GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : 0x80;
2744
2745     hdr =
2746         gst_matroska_mux_create_buffer_header (collect_pad->track,
2747         relative_timestamp, flags);
2748     gst_ebml_write_set_cache (ebml, 0x40);
2749     gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
2750         GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
2751     gst_ebml_write_buffer (ebml, hdr);
2752     gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
2753     gst_ebml_write_buffer (ebml, buf);
2754
2755     return gst_ebml_last_write_result (ebml);
2756   } else {
2757     gst_ebml_write_set_cache (ebml, GST_BUFFER_SIZE (buf) * 2);
2758     /* write and call order slightly unnatural,
2759      * but avoids seek and minizes pushing */
2760     blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
2761     hdr =
2762         gst_matroska_mux_create_buffer_header (collect_pad->track,
2763         relative_timestamp, 0);
2764     if (write_duration) {
2765       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION,
2766           gst_util_uint64_scale (block_duration, 1, mux->time_scale));
2767     }
2768     gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
2769         GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
2770     gst_ebml_write_buffer (ebml, hdr);
2771     gst_ebml_write_master_finish_full (ebml, blockgroup, GST_BUFFER_SIZE (buf));
2772     gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
2773     gst_ebml_write_buffer (ebml, buf);
2774
2775     return gst_ebml_last_write_result (ebml);
2776   }
2777 }
2778
2779
2780 /**
2781  * gst_matroska_mux_collected:
2782  * @pads: #GstCollectPads
2783  * @uuser_data: #GstMatroskaMux
2784  *
2785  * Collectpads callback.
2786  *
2787  * Returns: #GstFlowReturn
2788  */
2789 static GstFlowReturn
2790 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
2791 {
2792   GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
2793   GstEbmlWrite *ebml = mux->ebml_write;
2794   GstMatroskaPad *best;
2795   gboolean popped;
2796   GstFlowReturn ret = GST_FLOW_OK;
2797
2798   GST_DEBUG_OBJECT (mux, "Collected pads");
2799
2800   /* start with a header */
2801   if (mux->state == GST_MATROSKA_MUX_STATE_START) {
2802     if (mux->collect->data == NULL) {
2803       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2804           ("No input streams configured"));
2805       return GST_FLOW_ERROR;
2806     }
2807     mux->state = GST_MATROSKA_MUX_STATE_HEADER;
2808     gst_ebml_start_streamheader (ebml);
2809     gst_matroska_mux_start (mux);
2810     gst_matroska_mux_stop_streamheader (mux);
2811     mux->state = GST_MATROSKA_MUX_STATE_DATA;
2812   }
2813
2814   do {
2815     /* which stream to write from? */
2816     best = gst_matroska_mux_best_pad (mux, &popped);
2817
2818     /* if there is no best pad, we have reached EOS */
2819     if (best == NULL) {
2820       /* buffer popped, but none returned means it was clipped */
2821       if (popped)
2822         break;
2823       GST_DEBUG_OBJECT (mux, "No best pad finishing...");
2824       if (!mux->streamable) {
2825         gst_matroska_mux_finish (mux);
2826       } else {
2827         GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
2828       }
2829       gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
2830       ret = GST_FLOW_UNEXPECTED;
2831       break;
2832     }
2833     GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
2834         GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
2835         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (best->buffer)),
2836         GST_TIME_ARGS (GST_BUFFER_DURATION (best->buffer)));
2837
2838     /* make note of first and last encountered timestamps, so we can calculate
2839      * the actual duration later when we send an updated header on eos */
2840     if (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)) {
2841       GstClockTime start_ts = GST_BUFFER_TIMESTAMP (best->buffer);
2842       GstClockTime end_ts = start_ts;
2843
2844       if (GST_BUFFER_DURATION_IS_VALID (best->buffer))
2845         end_ts += GST_BUFFER_DURATION (best->buffer);
2846       else if (best->track->default_duration)
2847         end_ts += best->track->default_duration;
2848
2849       if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
2850         best->end_ts = end_ts;
2851
2852       if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
2853               start_ts < best->start_ts))
2854         best->start_ts = start_ts;
2855     }
2856
2857     /* write one buffer */
2858     ret = gst_matroska_mux_write_data (mux, best);
2859   } while (ret == GST_FLOW_OK && !popped);
2860
2861   return ret;
2862 }
2863
2864
2865 /**
2866  * gst_matroska_mux_change_state:
2867  * @element: #GstMatroskaMux
2868  * @transition: State change transition.
2869  *
2870  * Change the muxer state.
2871  *
2872  * Returns: #GstStateChangeReturn
2873  */
2874 static GstStateChangeReturn
2875 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
2876 {
2877   GstStateChangeReturn ret;
2878   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
2879
2880   switch (transition) {
2881     case GST_STATE_CHANGE_NULL_TO_READY:
2882       break;
2883     case GST_STATE_CHANGE_READY_TO_PAUSED:
2884       gst_collect_pads_start (mux->collect);
2885       break;
2886     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2887       break;
2888     case GST_STATE_CHANGE_PAUSED_TO_READY:
2889       gst_collect_pads_stop (mux->collect);
2890       break;
2891     default:
2892       break;
2893   }
2894
2895   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2896
2897   switch (transition) {
2898     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2899       break;
2900     case GST_STATE_CHANGE_PAUSED_TO_READY:
2901       gst_matroska_mux_reset (GST_ELEMENT (mux));
2902       break;
2903     case GST_STATE_CHANGE_READY_TO_NULL:
2904       break;
2905     default:
2906       break;
2907   }
2908
2909   return ret;
2910 }
2911
2912 static void
2913 gst_matroska_mux_set_property (GObject * object,
2914     guint prop_id, const GValue * value, GParamSpec * pspec)
2915 {
2916   GstMatroskaMux *mux;
2917
2918   g_return_if_fail (GST_IS_MATROSKA_MUX (object));
2919   mux = GST_MATROSKA_MUX (object);
2920
2921   switch (prop_id) {
2922     case ARG_WRITING_APP:
2923       if (!g_value_get_string (value)) {
2924         GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
2925         break;
2926       }
2927       g_free (mux->writing_app);
2928       mux->writing_app = g_value_dup_string (value);
2929       break;
2930     case ARG_DOCTYPE_VERSION:
2931       mux->doctype_version = g_value_get_int (value);
2932       break;
2933     case ARG_MIN_INDEX_INTERVAL:
2934       mux->min_index_interval = g_value_get_int64 (value);
2935       break;
2936     case ARG_STREAMABLE:
2937       mux->streamable = g_value_get_boolean (value);
2938       break;
2939     default:
2940       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2941       break;
2942   }
2943 }
2944
2945 static void
2946 gst_matroska_mux_get_property (GObject * object,
2947     guint prop_id, GValue * value, GParamSpec * pspec)
2948 {
2949   GstMatroskaMux *mux;
2950
2951   g_return_if_fail (GST_IS_MATROSKA_MUX (object));
2952   mux = GST_MATROSKA_MUX (object);
2953
2954   switch (prop_id) {
2955     case ARG_WRITING_APP:
2956       g_value_set_string (value, mux->writing_app);
2957       break;
2958     case ARG_DOCTYPE_VERSION:
2959       g_value_set_int (value, mux->doctype_version);
2960       break;
2961     case ARG_MIN_INDEX_INTERVAL:
2962       g_value_set_int64 (value, mux->min_index_interval);
2963       break;
2964     case ARG_STREAMABLE:
2965       g_value_set_boolean (value, mux->streamable);
2966       break;
2967     default:
2968       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2969       break;
2970   }
2971 }