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