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