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