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