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