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