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