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