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