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