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