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