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