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