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