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