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