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