matroskamux: remove obsolete variable, set but not used
[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
706 static void
707 gst_matroska_mux_free_codec_priv (GstMatroskaTrackContext * context)
708 {
709   if (context->codec_priv != NULL) {
710     g_free (context->codec_priv);
711     context->codec_priv = NULL;
712     context->codec_priv_size = 0;
713   }
714 }
715
716 static void
717 gst_matroska_mux_build_vobsub_private (GstMatroskaTrackContext * context,
718     const guint * clut)
719 {
720   gchar *clutv[17];
721   gchar *sclut;
722   gint i;
723   guint32 col;
724   gdouble y, u, v;
725   guint8 r, g, b;
726
727   /* produce comma-separated list in hex format */
728   for (i = 0; i < 16; ++i) {
729     col = clut[i];
730     /* replicate vobsub's slightly off RGB conversion calculation */
731     y = (((col >> 16) & 0xff) - 16) * 255 / 219;
732     u = ((col >> 8) & 0xff) - 128;
733     v = (col & 0xff) - 128;
734     r = CLAMP (1.0 * y + 1.4022 * u, 0, 255);
735     g = CLAMP (1.0 * y - 0.3456 * u - 0.7145 * v, 0, 255);
736     b = CLAMP (1.0 * y + 1.7710 * v, 0, 255);
737     clutv[i] = g_strdup_printf ("%02x%02x%02x", r, g, b);
738   }
739   clutv[i] = NULL;
740   sclut = g_strjoinv (",", clutv);
741
742   /* build codec private; only palette for now */
743   gst_matroska_mux_free_codec_priv (context);
744   context->codec_priv = (guint8 *) g_strdup_printf ("palette: %s", sclut);
745   /* include terminating 0 */
746   context->codec_priv_size = strlen ((gchar *) context->codec_priv) + 1;
747   g_free (sclut);
748   for (i = 0; i < 16; ++i) {
749     g_free (clutv[i]);
750   }
751 }
752
753
754 /**
755  * gst_matroska_mux_handle_sink_event:
756  * @pad: Pad which received the event.
757  * @event: Received event.
758  *
759  * handle events - informational ones like tags
760  *
761  * Returns: #TRUE on success.
762  */
763 static gboolean
764 gst_matroska_mux_handle_sink_event (GstCollectPads2 * pads,
765     GstCollectData2 * data, GstEvent * event, gpointer user_data)
766 {
767   GstMatroskaTrackContext *context;
768   GstMatroskaPad *collect_pad;
769   GstMatroskaMux *mux;
770   GstPad *pad;
771   GstTagList *list;
772
773   mux = GST_MATROSKA_MUX (user_data);
774   collect_pad = (GstMatroskaPad *) data;
775   pad = data->pad;
776   context = collect_pad->track;
777   g_assert (context);
778
779   switch (GST_EVENT_TYPE (event)) {
780     case GST_EVENT_TAG:{
781       gchar *lang = NULL;
782
783       GST_DEBUG_OBJECT (mux, "received tag event");
784       gst_event_parse_tag (event, &list);
785
786       /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
787       if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
788         const gchar *lang_code;
789
790         lang_code = gst_tag_get_language_code_iso_639_2B (lang);
791         if (lang_code) {
792           GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
793           context->language = g_strdup (lang_code);
794         } else {
795           GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
796         }
797         g_free (lang);
798       }
799
800       /* FIXME: what about stream-specific tags? */
801       gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
802           gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
803
804       gst_event_unref (event);
805       /* handled this, don't want collectpads to forward it downstream */
806       event = NULL;
807       break;
808     }
809     case GST_EVENT_NEWSEGMENT:{
810       GstFormat format;
811
812       gst_event_parse_new_segment (event, NULL, NULL, &format, NULL, NULL,
813           NULL);
814       if (format != GST_FORMAT_TIME) {
815         gst_event_unref (event);
816         event = NULL;
817       }
818       break;
819     }
820     case GST_EVENT_CUSTOM_DOWNSTREAM:{
821       const GstStructure *structure;
822
823       structure = gst_event_get_structure (event);
824       if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
825         gst_event_replace (&mux->force_key_unit_event, NULL);
826         mux->force_key_unit_event = event;
827         event = NULL;
828       } else if (gst_structure_has_name (structure, "application/x-gst-dvd") &&
829           !strcmp ("dvd-spu-clut-change",
830               gst_structure_get_string (structure, "event"))) {
831         gchar name[16];
832         gint i, value;
833         guint clut[16];
834
835         GST_DEBUG_OBJECT (pad, "New DVD colour table received");
836         if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
837           GST_DEBUG_OBJECT (pad, "... discarding");
838           break;
839         }
840         /* first transform event data into table form */
841         for (i = 0; i < 16; i++) {
842           g_snprintf (name, sizeof (name), "clut%02d", i);
843           if (!gst_structure_get_int (structure, name, &value)) {
844             GST_ERROR_OBJECT (mux, "dvd-spu-clut-change event did not "
845                 "contain %s field", name);
846             break;
847           }
848           clut[i] = value;
849         }
850
851         /* transform into private data for stream; text form */
852         gst_matroska_mux_build_vobsub_private (context, clut);
853       }
854       break;
855     }
856     default:
857       break;
858   }
859
860   /* now GstCollectPads2 can take care of the rest, e.g. EOS */
861   if (event)
862     return FALSE;
863   else
864     return TRUE;
865 }
866
867 static void
868 gst_matroska_mux_set_codec_id (GstMatroskaTrackContext * context,
869     const char *id)
870 {
871   g_assert (context && id);
872   if (context->codec_id)
873     g_free (context->codec_id);
874   context->codec_id = g_strdup (id);
875 }
876
877 /**
878  * gst_matroska_mux_video_pad_setcaps:
879  * @pad: Pad which got the caps.
880  * @caps: New caps.
881  *
882  * Setcaps function for video sink pad.
883  *
884  * Returns: #TRUE on success.
885  */
886 static gboolean
887 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
888 {
889   GstMatroskaTrackContext *context = NULL;
890   GstMatroskaTrackVideoContext *videocontext;
891   GstMatroskaMux *mux;
892   GstMatroskaPad *collect_pad;
893   GstStructure *structure;
894   const gchar *mimetype;
895   const GValue *value = NULL;
896   const GstBuffer *codec_buf = NULL;
897   gint width, height, pixel_width, pixel_height;
898   gint fps_d, fps_n;
899   gboolean interlaced = FALSE;
900
901   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
902
903   /* find context */
904   collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
905   g_assert (collect_pad);
906   context = collect_pad->track;
907   g_assert (context);
908   g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
909   videocontext = (GstMatroskaTrackVideoContext *) context;
910
911   /* gst -> matroska ID'ing */
912   structure = gst_caps_get_structure (caps, 0);
913
914   mimetype = gst_structure_get_name (structure);
915
916   if (gst_structure_get_boolean (structure, "interlaced", &interlaced)
917       && interlaced)
918     context->flags |= GST_MATROSKA_VIDEOTRACK_INTERLACED;
919
920   if (!strcmp (mimetype, "video/x-theora")) {
921     /* we'll extract the details later from the theora identification header */
922     goto skip_details;
923   }
924
925   /* get general properties */
926   /* spec says it is mandatory */
927   if (!gst_structure_get_int (structure, "width", &width) ||
928       !gst_structure_get_int (structure, "height", &height))
929     goto refuse_caps;
930
931   videocontext->pixel_width = width;
932   videocontext->pixel_height = height;
933
934   /* set vp8 defaults or let user override it */
935   if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration_user == FALSE
936       && (!strcmp (mimetype, "video/x-vp8")))
937     GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration =
938         DEFAULT_PAD_FRAME_DURATION_VP8;
939
940   if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
941       && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
942       && fps_n > 0) {
943     context->default_duration =
944         gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
945     GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
946         GST_TIME_ARGS (context->default_duration));
947   } else {
948     context->default_duration = 0;
949   }
950   if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
951           &pixel_width, &pixel_height)) {
952     if (pixel_width > pixel_height) {
953       videocontext->display_width = width * pixel_width / pixel_height;
954       videocontext->display_height = height;
955     } else if (pixel_width < pixel_height) {
956       videocontext->display_width = width;
957       videocontext->display_height = height * pixel_height / pixel_width;
958     } else {
959       videocontext->display_width = 0;
960       videocontext->display_height = 0;
961     }
962   } else {
963     videocontext->display_width = 0;
964     videocontext->display_height = 0;
965   }
966
967 skip_details:
968
969   videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
970   videocontext->fourcc = 0;
971
972   /* TODO: - check if we handle all codecs by the spec, i.e. codec private
973    *         data and other settings
974    *       - add new formats
975    */
976
977   /* extract codec_data, may turn out needed */
978   value = gst_structure_get_value (structure, "codec_data");
979   if (value)
980     codec_buf = gst_value_get_buffer (value);
981
982   /* find type */
983   if (!strcmp (mimetype, "video/x-raw-yuv")) {
984     gst_matroska_mux_set_codec_id (context,
985         GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
986     gst_structure_get_fourcc (structure, "format", &videocontext->fourcc);
987   } else if (!strcmp (mimetype, "video/x-xvid") /* MS/VfW compatibility cases */
988       ||!strcmp (mimetype, "video/x-huffyuv")
989       || !strcmp (mimetype, "video/x-divx")
990       || !strcmp (mimetype, "video/x-dv")
991       || !strcmp (mimetype, "video/x-h263")
992       || !strcmp (mimetype, "video/x-msmpeg")
993       || !strcmp (mimetype, "video/x-wmv")
994       || !strcmp (mimetype, "image/jpeg")) {
995     gst_riff_strf_vids *bih;
996     gint size = sizeof (gst_riff_strf_vids);
997     guint32 fourcc = 0;
998
999     if (!strcmp (mimetype, "video/x-xvid"))
1000       fourcc = GST_MAKE_FOURCC ('X', 'V', 'I', 'D');
1001     else if (!strcmp (mimetype, "video/x-huffyuv"))
1002       fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
1003     else if (!strcmp (mimetype, "video/x-dv"))
1004       fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
1005     else if (!strcmp (mimetype, "video/x-h263"))
1006       fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
1007     else if (!strcmp (mimetype, "video/x-divx")) {
1008       gint divxversion;
1009
1010       gst_structure_get_int (structure, "divxversion", &divxversion);
1011       switch (divxversion) {
1012         case 3:
1013           fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
1014           break;
1015         case 4:
1016           fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
1017           break;
1018         case 5:
1019           fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
1020           break;
1021       }
1022     } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1023       gint msmpegversion;
1024
1025       gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
1026       switch (msmpegversion) {
1027         case 41:
1028           fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
1029           break;
1030         case 42:
1031           fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
1032           break;
1033         case 43:
1034           goto msmpeg43;
1035           break;
1036       }
1037     } else if (!strcmp (mimetype, "video/x-wmv")) {
1038       gint wmvversion;
1039       guint32 format;
1040       if (gst_structure_get_fourcc (structure, "format", &format)) {
1041         fourcc = format;
1042       } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
1043         if (wmvversion == 2) {
1044           fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
1045         } else if (wmvversion == 1) {
1046           fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
1047         } else if (wmvversion == 3) {
1048           fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
1049         }
1050       }
1051     } else if (!strcmp (mimetype, "image/jpeg")) {
1052       fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
1053     }
1054
1055     if (!fourcc)
1056       goto refuse_caps;
1057
1058     bih = g_new0 (gst_riff_strf_vids, 1);
1059     GST_WRITE_UINT32_LE (&bih->size, size);
1060     GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
1061     GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
1062     GST_WRITE_UINT32_LE (&bih->compression, fourcc);
1063     GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
1064     GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
1065     GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
1066         videocontext->pixel_height * 3);
1067
1068     /* process codec private/initialization data, if any */
1069     if (codec_buf) {
1070       size += GST_BUFFER_SIZE (codec_buf);
1071       bih = g_realloc (bih, size);
1072       GST_WRITE_UINT32_LE (&bih->size, size);
1073       memcpy ((guint8 *) bih + sizeof (gst_riff_strf_vids),
1074           GST_BUFFER_DATA (codec_buf), GST_BUFFER_SIZE (codec_buf));
1075     }
1076
1077     gst_matroska_mux_set_codec_id (context,
1078         GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
1079     gst_matroska_mux_free_codec_priv (context);
1080     context->codec_priv = (gpointer) bih;
1081     context->codec_priv_size = size;
1082   } else if (!strcmp (mimetype, "video/x-h264")) {
1083     gst_matroska_mux_set_codec_id (context,
1084         GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
1085     gst_matroska_mux_free_codec_priv (context);
1086     /* Create avcC header */
1087     if (codec_buf != NULL) {
1088       context->codec_priv_size = GST_BUFFER_SIZE (codec_buf);
1089       context->codec_priv = g_malloc0 (context->codec_priv_size);
1090       memcpy (context->codec_priv, GST_BUFFER_DATA (codec_buf),
1091           context->codec_priv_size);
1092     }
1093   } else if (!strcmp (mimetype, "video/x-theora")) {
1094     const GValue *streamheader;
1095
1096     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
1097
1098     gst_matroska_mux_free_codec_priv (context);
1099
1100     streamheader = gst_structure_get_value (structure, "streamheader");
1101     if (!theora_streamheader_to_codecdata (streamheader, context)) {
1102       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1103           ("theora stream headers missing or malformed"));
1104       goto refuse_caps;
1105     }
1106   } else if (!strcmp (mimetype, "video/x-dirac")) {
1107     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
1108   } else if (!strcmp (mimetype, "video/x-vp8")) {
1109     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP8);
1110   } else if (!strcmp (mimetype, "video/mpeg")) {
1111     gint mpegversion;
1112
1113     gst_structure_get_int (structure, "mpegversion", &mpegversion);
1114     switch (mpegversion) {
1115       case 1:
1116         gst_matroska_mux_set_codec_id (context,
1117             GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
1118         break;
1119       case 2:
1120         gst_matroska_mux_set_codec_id (context,
1121             GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
1122         break;
1123       case 4:
1124         gst_matroska_mux_set_codec_id (context,
1125             GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
1126         break;
1127       default:
1128         goto refuse_caps;
1129     }
1130
1131     /* global headers may be in codec data */
1132     if (codec_buf != NULL) {
1133       gst_matroska_mux_free_codec_priv (context);
1134       context->codec_priv_size = GST_BUFFER_SIZE (codec_buf);
1135       context->codec_priv = g_malloc0 (context->codec_priv_size);
1136       memcpy (context->codec_priv, GST_BUFFER_DATA (codec_buf),
1137           context->codec_priv_size);
1138     }
1139   } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1140   msmpeg43:
1141     /* can only make it here if preceding case verified it was version 3 */
1142     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
1143   } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
1144     gint rmversion;
1145     const GValue *mdpr_data;
1146
1147     gst_structure_get_int (structure, "rmversion", &rmversion);
1148     switch (rmversion) {
1149       case 1:
1150         gst_matroska_mux_set_codec_id (context,
1151             GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
1152         break;
1153       case 2:
1154         gst_matroska_mux_set_codec_id (context,
1155             GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
1156         break;
1157       case 3:
1158         gst_matroska_mux_set_codec_id (context,
1159             GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
1160         break;
1161       case 4:
1162         gst_matroska_mux_set_codec_id (context,
1163             GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
1164         break;
1165       default:
1166         goto refuse_caps;
1167     }
1168
1169     mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1170     if (mdpr_data != NULL) {
1171       guint8 *priv_data = NULL;
1172       guint priv_data_size = 0;
1173
1174       GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1175
1176       priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
1177       priv_data = g_malloc0 (priv_data_size);
1178
1179       memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
1180
1181       gst_matroska_mux_free_codec_priv (context);
1182       context->codec_priv = priv_data;
1183       context->codec_priv_size = priv_data_size;
1184     }
1185   }
1186
1187   return TRUE;
1188
1189   /* ERRORS */
1190 refuse_caps:
1191   {
1192     GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1193         GST_PAD_NAME (pad), caps);
1194     return FALSE;
1195   }
1196 }
1197
1198 /* N > 0 to expect a particular number of headers, negative if the
1199    number of headers is variable */
1200 static gboolean
1201 xiphN_streamheader_to_codecdata (const GValue * streamheader,
1202     GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
1203 {
1204   GstBuffer **buf = NULL;
1205   GArray *bufarr;
1206   guint8 *priv_data;
1207   guint bufi, i, offset, priv_data_size;
1208
1209   if (streamheader == NULL)
1210     goto no_stream_headers;
1211
1212   if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1213     goto wrong_type;
1214
1215   bufarr = g_value_peek_pointer (streamheader);
1216   if (bufarr->len <= 0 || bufarr->len > 255)    /* at least one header, and count stored in a byte */
1217     goto wrong_count;
1218   if (N > 0 && bufarr->len != N)
1219     goto wrong_count;
1220
1221   context->xiph_headers_to_skip = bufarr->len;
1222
1223   buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1224   for (i = 0; i < bufarr->len; i++) {
1225     GValue *bufval = &g_array_index (bufarr, GValue, i);
1226
1227     if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1228       g_free (buf);
1229       goto wrong_content_type;
1230     }
1231
1232     buf[i] = g_value_peek_pointer (bufval);
1233   }
1234
1235   priv_data_size = 1;
1236   if (bufarr->len > 0) {
1237     for (i = 0; i < bufarr->len - 1; i++) {
1238       priv_data_size += GST_BUFFER_SIZE (buf[i]) / 0xff + 1;
1239     }
1240   }
1241
1242   for (i = 0; i < bufarr->len; ++i) {
1243     priv_data_size += GST_BUFFER_SIZE (buf[i]);
1244   }
1245
1246   priv_data = g_malloc0 (priv_data_size);
1247
1248   priv_data[0] = bufarr->len - 1;
1249   offset = 1;
1250
1251   if (bufarr->len > 0) {
1252     for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1253       for (i = 0; i < GST_BUFFER_SIZE (buf[bufi]) / 0xff; ++i) {
1254         priv_data[offset++] = 0xff;
1255       }
1256       priv_data[offset++] = GST_BUFFER_SIZE (buf[bufi]) % 0xff;
1257     }
1258   }
1259
1260   for (i = 0; i < bufarr->len; ++i) {
1261     memcpy (priv_data + offset, GST_BUFFER_DATA (buf[i]),
1262         GST_BUFFER_SIZE (buf[i]));
1263     offset += GST_BUFFER_SIZE (buf[i]);
1264   }
1265
1266   gst_matroska_mux_free_codec_priv (context);
1267   context->codec_priv = priv_data;
1268   context->codec_priv_size = priv_data_size;
1269
1270   if (p_buf0)
1271     *p_buf0 = gst_buffer_ref (buf[0]);
1272
1273   g_free (buf);
1274
1275   return TRUE;
1276
1277 /* ERRORS */
1278 no_stream_headers:
1279   {
1280     GST_WARNING ("required streamheaders missing in sink caps!");
1281     return FALSE;
1282   }
1283 wrong_type:
1284   {
1285     GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1286         G_VALUE_TYPE_NAME (streamheader));
1287     return FALSE;
1288   }
1289 wrong_count:
1290   {
1291     GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1292     return FALSE;
1293   }
1294 wrong_content_type:
1295   {
1296     GST_WARNING ("streamheaders array does not contain GstBuffers");
1297     return FALSE;
1298   }
1299 }
1300
1301 static gboolean
1302 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1303     GstMatroskaTrackContext * context)
1304 {
1305   GstBuffer *buf0 = NULL;
1306
1307   if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1308     return FALSE;
1309
1310   if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 4) {
1311     GST_WARNING ("First vorbis header too small, ignoring");
1312   } else {
1313     if (memcmp (GST_BUFFER_DATA (buf0) + 1, "vorbis", 6) == 0) {
1314       GstMatroskaTrackAudioContext *audiocontext;
1315       guint8 *hdr;
1316
1317       hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 4;
1318       audiocontext = (GstMatroskaTrackAudioContext *) context;
1319       audiocontext->channels = GST_READ_UINT8 (hdr);
1320       audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1321     }
1322   }
1323
1324   if (buf0)
1325     gst_buffer_unref (buf0);
1326
1327   return TRUE;
1328 }
1329
1330 static gboolean
1331 theora_streamheader_to_codecdata (const GValue * streamheader,
1332     GstMatroskaTrackContext * context)
1333 {
1334   GstBuffer *buf0 = NULL;
1335
1336   if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1337     return FALSE;
1338
1339   if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 26) {
1340     GST_WARNING ("First theora header too small, ignoring");
1341   } else if (memcmp (GST_BUFFER_DATA (buf0), "\200theora\003\002", 9) != 0) {
1342     GST_WARNING ("First header not a theora identification header, ignoring");
1343   } else {
1344     GstMatroskaTrackVideoContext *videocontext;
1345     guint fps_num, fps_denom, par_num, par_denom;
1346     guint8 *hdr;
1347
1348     hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 3 + 2 + 2;
1349
1350     videocontext = (GstMatroskaTrackVideoContext *) context;
1351     videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1352     videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1353     hdr += 3 + 3 + 1 + 1;
1354     fps_num = GST_READ_UINT32_BE (hdr);
1355     fps_denom = GST_READ_UINT32_BE (hdr + 4);
1356     context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1357         fps_denom, fps_num);
1358     hdr += 4 + 4;
1359     par_num = GST_READ_UINT32_BE (hdr) >> 8;
1360     par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1361     if (par_num > 0 && par_num > 0) {
1362       if (par_num > par_denom) {
1363         videocontext->display_width =
1364             videocontext->pixel_width * par_num / par_denom;
1365         videocontext->display_height = videocontext->pixel_height;
1366       } else if (par_num < par_denom) {
1367         videocontext->display_width = videocontext->pixel_width;
1368         videocontext->display_height =
1369             videocontext->pixel_height * par_denom / par_num;
1370       } else {
1371         videocontext->display_width = 0;
1372         videocontext->display_height = 0;
1373       }
1374     } else {
1375       videocontext->display_width = 0;
1376       videocontext->display_height = 0;
1377     }
1378     hdr += 3 + 3;
1379   }
1380
1381   if (buf0)
1382     gst_buffer_unref (buf0);
1383
1384   return TRUE;
1385 }
1386
1387 static gboolean
1388 kate_streamheader_to_codecdata (const GValue * streamheader,
1389     GstMatroskaTrackContext * context)
1390 {
1391   GstBuffer *buf0 = NULL;
1392
1393   if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1394     return FALSE;
1395
1396   if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 64) {    /* Kate ID header is 64 bytes */
1397     GST_WARNING ("First kate header too small, ignoring");
1398   } else if (memcmp (GST_BUFFER_DATA (buf0), "\200kate\0\0\0", 8) != 0) {
1399     GST_WARNING ("First header not a kate identification header, ignoring");
1400   }
1401
1402   if (buf0)
1403     gst_buffer_unref (buf0);
1404
1405   return TRUE;
1406 }
1407
1408 static gboolean
1409 flac_streamheader_to_codecdata (const GValue * streamheader,
1410     GstMatroskaTrackContext * context)
1411 {
1412   GArray *bufarr;
1413   gint i;
1414   GValue *bufval;
1415   GstBuffer *buffer;
1416
1417   if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1418     GST_WARNING ("No or invalid streamheader field in the caps");
1419     return FALSE;
1420   }
1421
1422   bufarr = g_value_peek_pointer (streamheader);
1423   if (bufarr->len < 2) {
1424     GST_WARNING ("Too few headers in streamheader field");
1425     return FALSE;
1426   }
1427
1428   context->xiph_headers_to_skip = bufarr->len + 1;
1429
1430   bufval = &g_array_index (bufarr, GValue, 0);
1431   if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1432     GST_WARNING ("streamheaders array does not contain GstBuffers");
1433     return FALSE;
1434   }
1435
1436   buffer = g_value_peek_pointer (bufval);
1437
1438   /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1439   if (GST_BUFFER_SIZE (buffer) < 9 + 4 + 4 + 34
1440       || memcmp (GST_BUFFER_DATA (buffer) + 1, "FLAC", 4) != 0
1441       || memcmp (GST_BUFFER_DATA (buffer) + 9, "fLaC", 4) != 0) {
1442     GST_WARNING ("Invalid streamheader for FLAC");
1443     return FALSE;
1444   }
1445
1446   gst_matroska_mux_free_codec_priv (context);
1447   context->codec_priv = g_malloc (GST_BUFFER_SIZE (buffer) - 9);
1448   context->codec_priv_size = GST_BUFFER_SIZE (buffer) - 9;
1449   memcpy (context->codec_priv, GST_BUFFER_DATA (buffer) + 9,
1450       GST_BUFFER_SIZE (buffer) - 9);
1451
1452   for (i = 1; i < bufarr->len; i++) {
1453     bufval = &g_array_index (bufarr, GValue, i);
1454
1455     if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1456       gst_matroska_mux_free_codec_priv (context);
1457       GST_WARNING ("streamheaders array does not contain GstBuffers");
1458       return FALSE;
1459     }
1460
1461     buffer = g_value_peek_pointer (bufval);
1462
1463     context->codec_priv =
1464         g_realloc (context->codec_priv,
1465         context->codec_priv_size + GST_BUFFER_SIZE (buffer));
1466     memcpy ((guint8 *) context->codec_priv + context->codec_priv_size,
1467         GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
1468     context->codec_priv_size =
1469         context->codec_priv_size + GST_BUFFER_SIZE (buffer);
1470   }
1471
1472   return TRUE;
1473 }
1474
1475 static gboolean
1476 speex_streamheader_to_codecdata (const GValue * streamheader,
1477     GstMatroskaTrackContext * context)
1478 {
1479   GArray *bufarr;
1480   GValue *bufval;
1481   GstBuffer *buffer;
1482
1483   if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1484     GST_WARNING ("No or invalid streamheader field in the caps");
1485     return FALSE;
1486   }
1487
1488   bufarr = g_value_peek_pointer (streamheader);
1489   if (bufarr->len != 2) {
1490     GST_WARNING ("Too few headers in streamheader field");
1491     return FALSE;
1492   }
1493
1494   context->xiph_headers_to_skip = bufarr->len + 1;
1495
1496   bufval = &g_array_index (bufarr, GValue, 0);
1497   if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1498     GST_WARNING ("streamheaders array does not contain GstBuffers");
1499     return FALSE;
1500   }
1501
1502   buffer = g_value_peek_pointer (bufval);
1503
1504   if (GST_BUFFER_SIZE (buffer) < 80
1505       || memcmp (GST_BUFFER_DATA (buffer), "Speex   ", 8) != 0) {
1506     GST_WARNING ("Invalid streamheader for Speex");
1507     return FALSE;
1508   }
1509
1510   gst_matroska_mux_free_codec_priv (context);
1511   context->codec_priv = g_malloc (GST_BUFFER_SIZE (buffer));
1512   context->codec_priv_size = GST_BUFFER_SIZE (buffer);
1513   memcpy (context->codec_priv, GST_BUFFER_DATA (buffer),
1514       GST_BUFFER_SIZE (buffer));
1515
1516   bufval = &g_array_index (bufarr, GValue, 1);
1517
1518   if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1519     gst_matroska_mux_free_codec_priv (context);
1520     GST_WARNING ("streamheaders array does not contain GstBuffers");
1521     return FALSE;
1522   }
1523
1524   buffer = g_value_peek_pointer (bufval);
1525
1526   context->codec_priv =
1527       g_realloc (context->codec_priv,
1528       context->codec_priv_size + GST_BUFFER_SIZE (buffer));
1529   memcpy ((guint8 *) context->codec_priv + context->codec_priv_size,
1530       GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
1531   context->codec_priv_size =
1532       context->codec_priv_size + GST_BUFFER_SIZE (buffer);
1533
1534   return TRUE;
1535 }
1536
1537 static const gchar *
1538 aac_codec_data_to_codec_id (const GstBuffer * buf)
1539 {
1540   const gchar *result;
1541   gint profile;
1542
1543   /* default to MAIN */
1544   profile = 1;
1545
1546   if (GST_BUFFER_SIZE (buf) >= 2) {
1547     profile = GST_READ_UINT8 (GST_BUFFER_DATA (buf));
1548     profile >>= 3;
1549   }
1550
1551   switch (profile) {
1552     case 1:
1553       result = "MAIN";
1554       break;
1555     case 2:
1556       result = "LC";
1557       break;
1558     case 3:
1559       result = "SSR";
1560       break;
1561     case 4:
1562       result = "LTP";
1563       break;
1564     default:
1565       GST_WARNING ("unknown AAC profile, defaulting to MAIN");
1566       result = "MAIN";
1567       break;
1568   }
1569
1570   return result;
1571 }
1572
1573 /**
1574  * gst_matroska_mux_audio_pad_setcaps:
1575  * @pad: Pad which got the caps.
1576  * @caps: New caps.
1577  *
1578  * Setcaps function for audio sink pad.
1579  *
1580  * Returns: #TRUE on success.
1581  */
1582 static gboolean
1583 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1584 {
1585   GstMatroskaTrackContext *context = NULL;
1586   GstMatroskaTrackAudioContext *audiocontext;
1587   GstMatroskaMux *mux;
1588   GstMatroskaPad *collect_pad;
1589   const gchar *mimetype;
1590   gint samplerate = 0, channels = 0;
1591   GstStructure *structure;
1592   const GValue *codec_data = NULL;
1593   const GstBuffer *buf = NULL;
1594   const gchar *stream_format = NULL;
1595
1596   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1597
1598   /* find context */
1599   collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1600   g_assert (collect_pad);
1601   context = collect_pad->track;
1602   g_assert (context);
1603   g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
1604   audiocontext = (GstMatroskaTrackAudioContext *) context;
1605
1606   structure = gst_caps_get_structure (caps, 0);
1607   mimetype = gst_structure_get_name (structure);
1608
1609   /* general setup */
1610   gst_structure_get_int (structure, "rate", &samplerate);
1611   gst_structure_get_int (structure, "channels", &channels);
1612
1613   audiocontext->samplerate = samplerate;
1614   audiocontext->channels = channels;
1615   audiocontext->bitdepth = 0;
1616   context->default_duration = 0;
1617
1618   codec_data = gst_structure_get_value (structure, "codec_data");
1619   if (codec_data)
1620     buf = gst_value_get_buffer (codec_data);
1621
1622   /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1623    *         data and other settings
1624    *       - add new formats
1625    */
1626
1627   if (!strcmp (mimetype, "audio/mpeg")) {
1628     gint mpegversion = 0;
1629
1630     gst_structure_get_int (structure, "mpegversion", &mpegversion);
1631     switch (mpegversion) {
1632       case 1:{
1633         gint layer;
1634         gint version = 1;
1635         gint spf;
1636
1637         gst_structure_get_int (structure, "layer", &layer);
1638
1639         if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
1640           GST_WARNING_OBJECT (mux,
1641               "Unable to determine MPEG audio version, assuming 1");
1642           version = 1;
1643         }
1644
1645         if (layer == 1)
1646           spf = 384;
1647         else if (layer == 2)
1648           spf = 1152;
1649         else if (version == 2)
1650           spf = 576;
1651         else
1652           spf = 1152;
1653
1654         context->default_duration =
1655             gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
1656
1657         switch (layer) {
1658           case 1:
1659             gst_matroska_mux_set_codec_id (context,
1660                 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
1661             break;
1662           case 2:
1663             gst_matroska_mux_set_codec_id (context,
1664                 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
1665             break;
1666           case 3:
1667             gst_matroska_mux_set_codec_id (context,
1668                 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
1669             break;
1670           default:
1671             goto refuse_caps;
1672         }
1673         break;
1674       }
1675       case 2:
1676       case 4:
1677         stream_format = gst_structure_get_string (structure, "stream-format");
1678         /* check this is raw aac */
1679         if (stream_format) {
1680           if (strcmp (stream_format, "raw") != 0) {
1681             GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
1682                 stream_format);
1683           }
1684         } else {
1685           GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
1686               "assuming 'raw'");
1687         }
1688
1689         if (buf) {
1690           if (mpegversion == 2)
1691             context->codec_id =
1692                 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2 "%s",
1693                 aac_codec_data_to_codec_id (buf));
1694           else if (mpegversion == 4)
1695             context->codec_id =
1696                 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4 "%s",
1697                 aac_codec_data_to_codec_id (buf));
1698           else
1699             g_assert_not_reached ();
1700         } else {
1701           GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
1702           goto refuse_caps;
1703         }
1704         break;
1705       default:
1706         goto refuse_caps;
1707     }
1708   } else if (!strcmp (mimetype, "audio/x-raw-int")) {
1709     gint width, depth;
1710     gint endianness = G_LITTLE_ENDIAN;
1711     gboolean signedness = TRUE;
1712
1713     if (!gst_structure_get_int (structure, "width", &width) ||
1714         !gst_structure_get_int (structure, "depth", &depth) ||
1715         !gst_structure_get_boolean (structure, "signed", &signedness)) {
1716       GST_DEBUG_OBJECT (mux, "broken caps, width/depth/signed field missing");
1717       goto refuse_caps;
1718     }
1719
1720     if (depth > 8 &&
1721         !gst_structure_get_int (structure, "endianness", &endianness)) {
1722       GST_DEBUG_OBJECT (mux, "broken caps, no endianness specified");
1723       goto refuse_caps;
1724     }
1725
1726     if (width != depth) {
1727       GST_DEBUG_OBJECT (mux, "width must be same as depth!");
1728       goto refuse_caps;
1729     }
1730
1731     /* FIXME: where is this spec'ed out? (tpm) */
1732     if ((width == 8 && signedness) || (width >= 16 && !signedness)) {
1733       GST_DEBUG_OBJECT (mux, "8-bit PCM must be unsigned, 16-bit PCM signed");
1734       goto refuse_caps;
1735     }
1736
1737     audiocontext->bitdepth = depth;
1738     if (endianness == G_BIG_ENDIAN)
1739       gst_matroska_mux_set_codec_id (context,
1740           GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
1741     else
1742       gst_matroska_mux_set_codec_id (context,
1743           GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
1744
1745   } else if (!strcmp (mimetype, "audio/x-raw-float")) {
1746     gint width;
1747
1748     if (!gst_structure_get_int (structure, "width", &width)) {
1749       GST_DEBUG_OBJECT (mux, "broken caps, width field missing");
1750       goto refuse_caps;
1751     }
1752
1753     audiocontext->bitdepth = width;
1754     gst_matroska_mux_set_codec_id (context,
1755         GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
1756
1757   } else if (!strcmp (mimetype, "audio/x-vorbis")) {
1758     const GValue *streamheader;
1759
1760     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
1761
1762     gst_matroska_mux_free_codec_priv (context);
1763
1764     streamheader = gst_structure_get_value (structure, "streamheader");
1765     if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
1766       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1767           ("vorbis stream headers missing or malformed"));
1768       goto refuse_caps;
1769     }
1770   } else if (!strcmp (mimetype, "audio/x-flac")) {
1771     const GValue *streamheader;
1772
1773     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
1774
1775     gst_matroska_mux_free_codec_priv (context);
1776
1777     streamheader = gst_structure_get_value (structure, "streamheader");
1778     if (!flac_streamheader_to_codecdata (streamheader, context)) {
1779       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1780           ("flac stream headers missing or malformed"));
1781       goto refuse_caps;
1782     }
1783   } else if (!strcmp (mimetype, "audio/x-speex")) {
1784     const GValue *streamheader;
1785
1786     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
1787     gst_matroska_mux_free_codec_priv (context);
1788
1789     streamheader = gst_structure_get_value (structure, "streamheader");
1790     if (!speex_streamheader_to_codecdata (streamheader, context)) {
1791       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1792           ("speex stream headers missing or malformed"));
1793       goto refuse_caps;
1794     }
1795   } else if (!strcmp (mimetype, "audio/x-ac3")) {
1796     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_AC3);
1797   } else if (!strcmp (mimetype, "audio/x-eac3")) {
1798     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
1799   } else if (!strcmp (mimetype, "audio/x-dts")) {
1800     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_DTS);
1801   } else if (!strcmp (mimetype, "audio/x-tta")) {
1802     gint width;
1803
1804     /* TTA frame duration */
1805     context->default_duration = 1.04489795918367346939 * GST_SECOND;
1806
1807     gst_structure_get_int (structure, "width", &width);
1808     audiocontext->bitdepth = width;
1809     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_TTA);
1810
1811   } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
1812     gint raversion;
1813     const GValue *mdpr_data;
1814
1815     gst_structure_get_int (structure, "raversion", &raversion);
1816     switch (raversion) {
1817       case 1:
1818         gst_matroska_mux_set_codec_id (context,
1819             GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
1820         break;
1821       case 2:
1822         gst_matroska_mux_set_codec_id (context,
1823             GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
1824         break;
1825       case 8:
1826         gst_matroska_mux_set_codec_id (context,
1827             GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
1828         break;
1829       default:
1830         goto refuse_caps;
1831     }
1832
1833     mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1834     if (mdpr_data != NULL) {
1835       guint8 *priv_data = NULL;
1836       guint priv_data_size = 0;
1837
1838       GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1839
1840       priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
1841       priv_data = g_malloc0 (priv_data_size);
1842
1843       memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
1844
1845       gst_matroska_mux_free_codec_priv (context);
1846
1847       context->codec_priv = priv_data;
1848       context->codec_priv_size = priv_data_size;
1849     }
1850
1851   } else if (!strcmp (mimetype, "audio/x-wma")
1852       || !strcmp (mimetype, "audio/x-alaw")
1853       || !strcmp (mimetype, "audio/x-mulaw")) {
1854     guint8 *codec_priv;
1855     guint codec_priv_size;
1856     guint16 format = 0;
1857     gint block_align;
1858     gint bitrate;
1859
1860     if (samplerate == 0 || channels == 0) {
1861       GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
1862       goto refuse_caps;
1863     }
1864
1865     if (!strcmp (mimetype, "audio/x-wma")) {
1866       gint wmaversion;
1867       gint depth;
1868
1869       if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
1870           || !gst_structure_get_int (structure, "block_align", &block_align)
1871           || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
1872         GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
1873             " on WMA caps");
1874         goto refuse_caps;
1875       }
1876
1877       switch (wmaversion) {
1878         case 1:
1879           format = GST_RIFF_WAVE_FORMAT_WMAV1;
1880           break;
1881         case 2:
1882           format = GST_RIFF_WAVE_FORMAT_WMAV2;
1883           break;
1884         case 3:
1885           format = GST_RIFF_WAVE_FORMAT_WMAV3;
1886           break;
1887         default:
1888           GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
1889           goto refuse_caps;
1890       }
1891
1892       if (gst_structure_get_int (structure, "depth", &depth))
1893         audiocontext->bitdepth = depth;
1894     } else if (!strcmp (mimetype, "audio/x-alaw")
1895         || !strcmp (mimetype, "audio/x-mulaw")) {
1896       audiocontext->bitdepth = 8;
1897       if (!strcmp (mimetype, "audio/x-alaw"))
1898         format = GST_RIFF_WAVE_FORMAT_ALAW;
1899       else
1900         format = GST_RIFF_WAVE_FORMAT_MULAW;
1901
1902       block_align = channels;
1903       bitrate = block_align * samplerate;
1904     }
1905     g_assert (format != 0);
1906
1907     codec_priv_size = WAVEFORMATEX_SIZE;
1908     if (buf)
1909       codec_priv_size += GST_BUFFER_SIZE (buf);
1910
1911     /* serialize waveformatex structure */
1912     codec_priv = g_malloc0 (codec_priv_size);
1913     GST_WRITE_UINT16_LE (codec_priv, format);
1914     GST_WRITE_UINT16_LE (codec_priv + 2, channels);
1915     GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
1916     GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
1917     GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
1918     GST_WRITE_UINT16_LE (codec_priv + 14, 0);
1919     if (buf)
1920       GST_WRITE_UINT16_LE (codec_priv + 16, GST_BUFFER_SIZE (buf));
1921     else
1922       GST_WRITE_UINT16_LE (codec_priv + 16, 0);
1923
1924     /* process codec private/initialization data, if any */
1925     if (buf) {
1926       memcpy ((guint8 *) codec_priv + WAVEFORMATEX_SIZE,
1927           GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
1928     }
1929
1930     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
1931     gst_matroska_mux_free_codec_priv (context);
1932     context->codec_priv = (gpointer) codec_priv;
1933     context->codec_priv_size = codec_priv_size;
1934   }
1935
1936   return TRUE;
1937
1938   /* ERRORS */
1939 refuse_caps:
1940   {
1941     GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1942         GST_PAD_NAME (pad), caps);
1943     return FALSE;
1944   }
1945 }
1946
1947 /* we probably don't have the data at start,
1948  * so have to reserve (a maximum) space to write this at the end.
1949  * bit spacy, but some formats can hold quite some */
1950 #define SUBTITLE_MAX_CODEC_PRIVATE   2048       /* must be > 128 */
1951
1952 /**
1953  * gst_matroska_mux_subtitle_pad_setcaps:
1954  * @pad: Pad which got the caps.
1955  * @caps: New caps.
1956  *
1957  * Setcaps function for subtitle sink pad.
1958  *
1959  * Returns: #TRUE on success.
1960  */
1961 static gboolean
1962 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
1963 {
1964   /* There is now (at least) one such alement (kateenc), and I'm going
1965      to handle it here and claim it works when it can be piped back
1966      through GStreamer and VLC */
1967
1968   GstMatroskaTrackContext *context = NULL;
1969   GstMatroskaTrackSubtitleContext *scontext;
1970   GstMatroskaMux *mux;
1971   GstMatroskaPad *collect_pad;
1972   const gchar *mimetype;
1973   GstStructure *structure;
1974   const GValue *value = NULL;
1975   const GstBuffer *buf = NULL;
1976   gboolean ret = TRUE;
1977
1978   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1979
1980   /* find context */
1981   collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1982   g_assert (collect_pad);
1983   context = collect_pad->track;
1984   g_assert (context);
1985   g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
1986   scontext = (GstMatroskaTrackSubtitleContext *) context;
1987
1988   structure = gst_caps_get_structure (caps, 0);
1989   mimetype = gst_structure_get_name (structure);
1990
1991   /* general setup */
1992   scontext->check_utf8 = 1;
1993   scontext->invalid_utf8 = 0;
1994   context->default_duration = 0;
1995
1996   if (!strcmp (mimetype, "subtitle/x-kate")) {
1997     const GValue *streamheader;
1998
1999     gst_matroska_mux_set_codec_id (context,
2000         GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
2001
2002     gst_matroska_mux_free_codec_priv (context);
2003
2004     streamheader = gst_structure_get_value (structure, "streamheader");
2005     if (!kate_streamheader_to_codecdata (streamheader, context)) {
2006       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2007           ("kate stream headers missing or malformed"));
2008       ret = FALSE;
2009       goto exit;
2010     }
2011   } else if (!strcmp (mimetype, "text/plain")) {
2012     gst_matroska_mux_set_codec_id (context,
2013         GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
2014   } else if (!strcmp (mimetype, "application/x-ssa")) {
2015     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
2016   } else if (!strcmp (mimetype, "application/x-ass")) {
2017     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
2018   } else if (!strcmp (mimetype, "application/x-usf")) {
2019     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
2020   } else if (!strcmp (mimetype, "video/x-dvd-subpicture")) {
2021     gst_matroska_mux_set_codec_id (context,
2022         GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
2023   } else {
2024     ret = FALSE;
2025     goto exit;
2026   }
2027
2028   /* maybe some private data, e.g. vobsub */
2029   value = gst_structure_get_value (structure, "codec_data");
2030   if (value)
2031     buf = gst_value_get_buffer (value);
2032   if (buf != NULL) {
2033     guint8 *priv_data = NULL;
2034     guint priv_data_size = 0;
2035
2036     priv_data_size = GST_BUFFER_SIZE (buf);
2037     if (priv_data_size > SUBTITLE_MAX_CODEC_PRIVATE) {
2038       GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
2039           " exceeded maximum (%d); discarding", pad,
2040           SUBTITLE_MAX_CODEC_PRIVATE);
2041       return TRUE;
2042     }
2043
2044     gst_matroska_mux_free_codec_priv (context);
2045
2046     priv_data = g_malloc0 (priv_data_size);
2047     memcpy (priv_data, GST_BUFFER_DATA (buf), priv_data_size);
2048     context->codec_priv = priv_data;
2049     context->codec_priv_size = priv_data_size;
2050   }
2051
2052   GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %u",
2053       GST_STR_NULL (context->codec_id), context->codec_priv_size);
2054
2055 exit:
2056
2057   return ret;
2058 }
2059
2060
2061 /**
2062  * gst_matroska_mux_request_new_pad:
2063  * @element: #GstMatroskaMux.
2064  * @templ: #GstPadTemplate.
2065  * @pad_name: New pad name.
2066  *
2067  * Request pad function for sink templates.
2068  *
2069  * Returns: New #GstPad.
2070  */
2071 static GstPad *
2072 gst_matroska_mux_request_new_pad (GstElement * element,
2073     GstPadTemplate * templ, const gchar * req_name)
2074 {
2075   GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
2076   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
2077   GstMatroskaPad *collect_pad;
2078   GstMatroskamuxPad *newpad;
2079   gchar *name = NULL;
2080   const gchar *pad_name = NULL;
2081   GstPadSetCapsFunction setcapsfunc = NULL;
2082   GstMatroskaTrackContext *context = NULL;
2083   gint pad_id;
2084   gboolean locked = TRUE;
2085   gchar *id = NULL;
2086
2087   if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
2088     /* don't mix named and unnamed pads, if the pad already exists we fail when
2089      * trying to add it */
2090     if (req_name != NULL && sscanf (req_name, "audio_%d", &pad_id) == 1) {
2091       pad_name = req_name;
2092     } else {
2093       name = g_strdup_printf ("audio_%d", mux->num_a_streams++);
2094       pad_name = name;
2095     }
2096     setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
2097     context = (GstMatroskaTrackContext *)
2098         g_new0 (GstMatroskaTrackAudioContext, 1);
2099     context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
2100     context->name = g_strdup ("Audio");
2101   } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
2102     /* don't mix named and unnamed pads, if the pad already exists we fail when
2103      * trying to add it */
2104     if (req_name != NULL && sscanf (req_name, "video_%d", &pad_id) == 1) {
2105       pad_name = req_name;
2106     } else {
2107       name = g_strdup_printf ("video_%d", mux->num_v_streams++);
2108       pad_name = name;
2109     }
2110     setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
2111     context = (GstMatroskaTrackContext *)
2112         g_new0 (GstMatroskaTrackVideoContext, 1);
2113     context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
2114     context->name = g_strdup ("Video");
2115   } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%d")) {
2116     /* don't mix named and unnamed pads, if the pad already exists we fail when
2117      * trying to add it */
2118     if (req_name != NULL && sscanf (req_name, "subtitle_%d", &pad_id) == 1) {
2119       pad_name = req_name;
2120     } else {
2121       name = g_strdup_printf ("subtitle_%d", mux->num_t_streams++);
2122       pad_name = name;
2123     }
2124     setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
2125     context = (GstMatroskaTrackContext *)
2126         g_new0 (GstMatroskaTrackSubtitleContext, 1);
2127     context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
2128     context->name = g_strdup ("Subtitle");
2129     /* setcaps may only provide proper one a lot later */
2130     id = g_strdup ("S_SUB_UNKNOWN");
2131     locked = FALSE;
2132   } else {
2133     GST_WARNING_OBJECT (mux, "This is not our template!");
2134     return NULL;
2135   }
2136
2137   newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
2138       "name", pad_name, "direction", templ->direction, "template", templ, NULL);
2139   g_free (name);
2140
2141   gst_matroskamux_pad_init (newpad);
2142   collect_pad = (GstMatroskaPad *)
2143       gst_collect_pads2_add_pad_full (mux->collect, GST_PAD (newpad),
2144       sizeof (GstMatroskamuxPad),
2145       (GstCollectData2DestroyNotify) gst_matroska_pad_free, locked);
2146
2147   collect_pad->track = context;
2148   gst_matroska_pad_reset (collect_pad, FALSE);
2149   collect_pad->track->codec_id = id;
2150
2151   gst_pad_set_setcaps_function (GST_PAD (newpad), setcapsfunc);
2152   gst_pad_set_active (GST_PAD (newpad), TRUE);
2153   if (!gst_element_add_pad (element, GST_PAD (newpad)))
2154     goto pad_add_failed;
2155
2156   mux->num_streams++;
2157
2158   GST_DEBUG_OBJECT (newpad, "Added new request pad");
2159
2160   return GST_PAD (newpad);
2161
2162   /* ERROR cases */
2163 pad_add_failed:
2164   {
2165     GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
2166     gst_object_unref (newpad);
2167     return NULL;
2168   }
2169 }
2170
2171 /**
2172  * gst_matroska_mux_release_pad:
2173  * @element: #GstMatroskaMux.
2174  * @pad: Pad to release.
2175  *
2176  * Release a previously requested pad.
2177 */
2178 static void
2179 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
2180 {
2181   GstMatroskaMux *mux;
2182   GSList *walk;
2183
2184   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2185
2186   for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
2187     GstCollectData2 *cdata = (GstCollectData2 *) walk->data;
2188     GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
2189
2190     if (cdata->pad == pad) {
2191       GstClockTime min_dur;     /* observed minimum duration */
2192
2193       if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2194           GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2195         min_dur = GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2196         if (collect_pad->duration < min_dur)
2197           collect_pad->duration = min_dur;
2198       }
2199
2200       if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
2201           mux->duration < collect_pad->duration)
2202         mux->duration = collect_pad->duration;
2203
2204       break;
2205     }
2206   }
2207
2208   gst_collect_pads2_remove_pad (mux->collect, pad);
2209   if (gst_element_remove_pad (element, pad))
2210     mux->num_streams--;
2211 }
2212
2213
2214 /**
2215  * gst_matroska_mux_track_header:
2216  * @mux: #GstMatroskaMux
2217  * @context: Tack context.
2218  *
2219  * Write a track header.
2220  */
2221 static void
2222 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2223     GstMatroskaTrackContext * context)
2224 {
2225   GstEbmlWrite *ebml = mux->ebml_write;
2226   guint64 master;
2227
2228   /* TODO: check if everything necessary is written and check default values */
2229
2230   /* track type goes before the type-specific stuff */
2231   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2232   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2233
2234   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID,
2235       gst_matroska_mux_create_uid ());
2236   if (context->default_duration) {
2237     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2238         context->default_duration);
2239   }
2240   if (context->language) {
2241     gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2242         context->language);
2243   }
2244
2245   /* FIXME: until we have a nice way of getting the codecname
2246    * out of the caps, I'm not going to enable this. Too much
2247    * (useless, double, boring) work... */
2248   /* TODO: Use value from tags if any */
2249   /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2250      context->codec_name); */
2251   gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2252
2253   /* type-specific stuff */
2254   switch (context->type) {
2255     case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2256       GstMatroskaTrackVideoContext *videocontext =
2257           (GstMatroskaTrackVideoContext *) context;
2258
2259       master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2260       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2261           videocontext->pixel_width);
2262       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2263           videocontext->pixel_height);
2264       if (videocontext->display_width && videocontext->display_height) {
2265         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2266             videocontext->display_width);
2267         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2268             videocontext->display_height);
2269       }
2270       if (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED)
2271         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2272       if (videocontext->fourcc) {
2273         guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2274
2275         gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2276             (gpointer) & fcc_le, 4);
2277       }
2278       gst_ebml_write_master_finish (ebml, master);
2279
2280       break;
2281     }
2282
2283     case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2284       GstMatroskaTrackAudioContext *audiocontext =
2285           (GstMatroskaTrackAudioContext *) context;
2286
2287       master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2288       if (audiocontext->samplerate != 8000)
2289         gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2290             audiocontext->samplerate);
2291       if (audiocontext->channels != 1)
2292         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2293             audiocontext->channels);
2294       if (audiocontext->bitdepth) {
2295         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2296             audiocontext->bitdepth);
2297       }
2298       gst_ebml_write_master_finish (ebml, master);
2299
2300       break;
2301     }
2302
2303       /* this is what we write for now and must be filled
2304        * and remainder void'ed later on */
2305 #define SUBTITLE_DUMMY_SIZE   (1 + 1 + 14 + 1 + 2 + SUBTITLE_MAX_CODEC_PRIVATE)
2306
2307     case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
2308       gpointer buf;
2309
2310       context->pos = ebml->pos;
2311       /* CodecID is mandatory ... */
2312       gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, "S_SUB_UNKNOWN");
2313       /* reserve space */
2314       buf = g_malloc0 (SUBTITLE_MAX_CODEC_PRIVATE);
2315       gst_ebml_write_binary (ebml, GST_EBML_ID_VOID, buf,
2316           SUBTITLE_MAX_CODEC_PRIVATE);
2317       g_free (buf);
2318       /* real data has to be written at finish */
2319       return;
2320     }
2321     default:
2322       /* doesn't need type-specific data */
2323       break;
2324   }
2325
2326   gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2327   if (context->codec_priv)
2328     gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2329         context->codec_priv, context->codec_priv_size);
2330 }
2331
2332
2333 /**
2334  * gst_matroska_mux_start:
2335  * @mux: #GstMatroskaMux
2336  *
2337  * Start a new matroska file (write headers etc...)
2338  */
2339 static void
2340 gst_matroska_mux_start (GstMatroskaMux * mux)
2341 {
2342   GstEbmlWrite *ebml = mux->ebml_write;
2343   const gchar *doctype;
2344   guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
2345     GST_MATROSKA_ID_TRACKS,
2346     GST_MATROSKA_ID_CUES,
2347     GST_MATROSKA_ID_TAGS,
2348     0
2349   };
2350   guint64 master, child;
2351   GSList *collected;
2352   int i;
2353   guint tracknum = 1;
2354   GstClockTime duration = 0;
2355   guint32 segment_uid[4];
2356   GTimeVal time = { 0, 0 };
2357
2358   if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2359     ebml->caps = gst_caps_new_simple ("video/webm", NULL);
2360   } else {
2361     ebml->caps = gst_caps_new_simple ("video/x-matroska", NULL);
2362   }
2363   /* we start with a EBML header */
2364   doctype = mux->doctype;
2365   GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
2366       doctype, mux->doctype_version);
2367   gst_ebml_write_header (ebml, doctype, mux->doctype_version);
2368
2369   /* the rest of the header is cached */
2370   gst_ebml_write_set_cache (ebml, 0x1000);
2371
2372   /* start a segment */
2373   mux->segment_pos =
2374       gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
2375   mux->segment_master = ebml->pos;
2376
2377   if (!mux->streamable) {
2378     /* seekhead (table of contents) - we set the positions later */
2379     mux->seekhead_pos = ebml->pos;
2380     master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
2381     for (i = 0; seekhead_id[i] != 0; i++) {
2382       child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
2383       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
2384       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
2385       gst_ebml_write_master_finish (ebml, child);
2386     }
2387     gst_ebml_write_master_finish (ebml, master);
2388   }
2389
2390   if (mux->streamable) {
2391     const GstTagList *tags;
2392
2393     /* tags */
2394     tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2395
2396     if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2397       guint64 master_tags, master_tag;
2398
2399       GST_DEBUG_OBJECT (mux, "Writing tags");
2400
2401       /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2402       mux->tags_pos = ebml->pos;
2403       master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2404       master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2405       gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2406       gst_ebml_write_master_finish (ebml, master_tag);
2407       gst_ebml_write_master_finish (ebml, master_tags);
2408     }
2409   }
2410
2411   /* segment info */
2412   mux->info_pos = ebml->pos;
2413   master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
2414   for (i = 0; i < 4; i++) {
2415     segment_uid[i] = g_random_int ();
2416   }
2417   gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
2418       (guint8 *) segment_uid, 16);
2419   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
2420   mux->duration_pos = ebml->pos;
2421   /* get duration */
2422   if (!mux->streamable) {
2423     for (collected = mux->collect->data; collected;
2424         collected = g_slist_next (collected)) {
2425       GstMatroskaPad *collect_pad;
2426       GstFormat format = GST_FORMAT_TIME;
2427       GstPad *thepad;
2428       gint64 trackduration;
2429
2430       collect_pad = (GstMatroskaPad *) collected->data;
2431       thepad = collect_pad->collect.pad;
2432
2433       /* Query the total length of the track. */
2434       GST_DEBUG_OBJECT (thepad, "querying peer duration");
2435       if (gst_pad_query_peer_duration (thepad, &format, &trackduration)) {
2436         GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
2437             GST_TIME_ARGS (trackduration));
2438         if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
2439           duration = (GstClockTime) trackduration;
2440         }
2441       }
2442     }
2443     gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2444         gst_guint64_to_gdouble (duration) /
2445         gst_guint64_to_gdouble (mux->time_scale));
2446   }
2447   gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
2448       "GStreamer plugin version " PACKAGE_VERSION);
2449   if (mux->writing_app && mux->writing_app[0]) {
2450     gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
2451   }
2452   g_get_current_time (&time);
2453   gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
2454   gst_ebml_write_master_finish (ebml, master);
2455
2456   /* tracks */
2457   mux->tracks_pos = ebml->pos;
2458   master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
2459
2460   for (collected = mux->collect->data; collected;
2461       collected = g_slist_next (collected)) {
2462     GstMatroskaPad *collect_pad;
2463     GstPad *thepad;
2464
2465     collect_pad = (GstMatroskaPad *) collected->data;
2466     thepad = collect_pad->collect.pad;
2467
2468     if (gst_pad_is_linked (thepad) && gst_pad_is_active (thepad) &&
2469         collect_pad->track->codec_id != 0) {
2470       collect_pad->track->num = tracknum++;
2471       child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
2472       gst_matroska_mux_track_header (mux, collect_pad->track);
2473       gst_ebml_write_master_finish (ebml, child);
2474       /* some remaining pad/track setup */
2475       collect_pad->default_duration_scaled =
2476           gst_util_uint64_scale (collect_pad->track->default_duration,
2477           1, mux->time_scale);
2478     }
2479   }
2480   gst_ebml_write_master_finish (ebml, master);
2481
2482   /* lastly, flush the cache */
2483   gst_ebml_write_flush_cache (ebml, FALSE, 0);
2484 }
2485
2486 static void
2487 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
2488     gpointer data)
2489 {
2490   /* TODO: more sensible tag mappings */
2491   static const struct
2492   {
2493     const gchar *matroska_tagname;
2494     const gchar *gstreamer_tagname;
2495   }
2496   tag_conv[] = {
2497     {
2498     GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
2499     GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
2500     GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
2501     GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
2502     GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
2503     GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
2504     GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
2505     GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
2506     GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
2507     GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
2508     GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
2509     GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
2510     GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
2511     GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
2512     GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
2513   };
2514   GstEbmlWrite *ebml = (GstEbmlWrite *) data;
2515   guint i;
2516   guint64 simpletag_master;
2517
2518   for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) {
2519     const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
2520     const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
2521
2522     if (strcmp (tagname_gst, tag) == 0) {
2523       GValue src = { 0, };
2524       gchar *dest;
2525
2526       if (!gst_tag_list_copy_value (&src, list, tag))
2527         break;
2528       if ((dest = gst_value_serialize (&src))) {
2529
2530         simpletag_master = gst_ebml_write_master_start (ebml,
2531             GST_MATROSKA_ID_SIMPLETAG);
2532         gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
2533         gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
2534         gst_ebml_write_master_finish (ebml, simpletag_master);
2535         g_free (dest);
2536       } else {
2537         GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
2538       }
2539       g_value_unset (&src);
2540       break;
2541     }
2542   }
2543 }
2544
2545
2546 /**
2547  * gst_matroska_mux_finish:
2548  * @mux: #GstMatroskaMux
2549  *
2550  * Finish a new matroska file (write index etc...)
2551  */
2552 static void
2553 gst_matroska_mux_finish (GstMatroskaMux * mux)
2554 {
2555   GstEbmlWrite *ebml = mux->ebml_write;
2556   guint64 pos;
2557   guint64 duration = 0;
2558   GSList *collected;
2559   const GstTagList *tags;
2560
2561   /* finish last cluster */
2562   if (mux->cluster) {
2563     gst_ebml_write_master_finish (ebml, mux->cluster);
2564   }
2565
2566   /* cues */
2567   if (mux->index != NULL) {
2568     guint n;
2569     guint64 master, pointentry_master, trackpos_master;
2570
2571     mux->cues_pos = ebml->pos;
2572     gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
2573     master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
2574
2575     for (n = 0; n < mux->num_indexes; n++) {
2576       GstMatroskaIndex *idx = &mux->index[n];
2577
2578       pointentry_master = gst_ebml_write_master_start (ebml,
2579           GST_MATROSKA_ID_POINTENTRY);
2580       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
2581           idx->time / mux->time_scale);
2582       trackpos_master = gst_ebml_write_master_start (ebml,
2583           GST_MATROSKA_ID_CUETRACKPOSITIONS);
2584       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
2585       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
2586           idx->pos - mux->segment_master);
2587       gst_ebml_write_master_finish (ebml, trackpos_master);
2588       gst_ebml_write_master_finish (ebml, pointentry_master);
2589     }
2590
2591     gst_ebml_write_master_finish (ebml, master);
2592     gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
2593   }
2594
2595   /* tags */
2596   tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2597
2598   if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2599     guint64 master_tags, master_tag;
2600
2601     GST_DEBUG_OBJECT (mux, "Writing tags");
2602
2603     /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2604     mux->tags_pos = ebml->pos;
2605     master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2606     master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2607     gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2608     gst_ebml_write_master_finish (ebml, master_tag);
2609     gst_ebml_write_master_finish (ebml, master_tags);
2610   }
2611
2612   /* update seekhead. We know that:
2613    * - a seekhead contains 4 entries.
2614    * - order of entries is as above.
2615    * - a seekhead has a 4-byte header + 8-byte length
2616    * - each entry is 2-byte master, 2-byte ID pointer,
2617    *     2-byte length pointer, all 8/1-byte length, 4-
2618    *     byte ID and 8-byte length pointer, where the
2619    *     length pointer starts at 20.
2620    * - all entries are local to the segment (so pos - segment_master).
2621    * - so each entry is at 12 + 20 + num * 28. */
2622   gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
2623       mux->info_pos - mux->segment_master);
2624   gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
2625       mux->tracks_pos - mux->segment_master);
2626   if (mux->index != NULL) {
2627     gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
2628         mux->cues_pos - mux->segment_master);
2629   } else {
2630     /* void'ify */
2631     guint64 my_pos = ebml->pos;
2632
2633     gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
2634     gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2635     gst_ebml_write_seek (ebml, my_pos);
2636   }
2637   if (tags != NULL) {
2638     gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
2639         mux->tags_pos - mux->segment_master);
2640   } else {
2641     /* void'ify */
2642     guint64 my_pos = ebml->pos;
2643
2644     gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
2645     gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2646     gst_ebml_write_seek (ebml, my_pos);
2647   }
2648
2649   /* loop tracks:
2650    * - first get the overall duration
2651    *   (a released track may have left a duration in here)
2652    * - write some track header data for subtitles
2653    */
2654   duration = mux->duration;
2655   pos = ebml->pos;
2656   for (collected = mux->collect->data; collected;
2657       collected = g_slist_next (collected)) {
2658     GstMatroskaPad *collect_pad;
2659     GstClockTime min_duration;  /* observed minimum duration */
2660     GstMatroskaTrackContext *context;
2661     gint voidleft = 0, fill = 0;
2662     gpointer codec_id;
2663
2664     collect_pad = (GstMatroskaPad *) collected->data;
2665     context = collect_pad->track;
2666
2667     GST_DEBUG_OBJECT (mux,
2668         "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
2669         " end ts %" GST_TIME_FORMAT, collect_pad,
2670         GST_TIME_ARGS (collect_pad->start_ts),
2671         GST_TIME_ARGS (collect_pad->end_ts));
2672
2673     if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2674         GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2675       min_duration =
2676           GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2677       if (collect_pad->duration < min_duration)
2678         collect_pad->duration = min_duration;
2679       GST_DEBUG_OBJECT (collect_pad,
2680           "final track duration: %" GST_TIME_FORMAT,
2681           GST_TIME_ARGS (collect_pad->duration));
2682     }
2683
2684     if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
2685         duration < collect_pad->duration)
2686       duration = collect_pad->duration;
2687
2688     if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE || !context->pos)
2689       continue;
2690
2691   again:
2692     /* write subtitle type and possible private data */
2693     gst_ebml_write_seek (ebml, context->pos);
2694     /* complex way to write ascii to account for extra filling */
2695     codec_id = g_malloc0 (strlen (context->codec_id) + 1 + fill);
2696     strcpy (codec_id, context->codec_id);
2697     gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECID,
2698         codec_id, strlen (context->codec_id) + 1 + fill);
2699     g_free (codec_id);
2700     if (context->codec_priv)
2701       gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2702           context->codec_priv, context->codec_priv_size);
2703     voidleft = SUBTITLE_DUMMY_SIZE - (ebml->pos - context->pos);
2704     /* void'ify; sigh, variable sized length field */
2705     if (voidleft == 1) {
2706       fill = 1;
2707       goto again;
2708     } else if (voidleft && voidleft <= 128)
2709       gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, voidleft - 2);
2710     else if (voidleft >= 130)
2711       gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, voidleft - 3);
2712     else if (voidleft == 129) {
2713       gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 64);
2714       gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 63);
2715     }
2716   }
2717
2718   /* seek back (optional, but do anyway) */
2719   gst_ebml_write_seek (ebml, pos);
2720
2721   /* update duration */
2722   if (duration != 0) {
2723     GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
2724         GST_TIME_ARGS (duration));
2725     pos = mux->ebml_write->pos;
2726     gst_ebml_write_seek (ebml, mux->duration_pos);
2727     gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2728         gst_guint64_to_gdouble (duration) /
2729         gst_guint64_to_gdouble (mux->time_scale));
2730     gst_ebml_write_seek (ebml, pos);
2731   } else {
2732     /* void'ify */
2733     guint64 my_pos = ebml->pos;
2734
2735     gst_ebml_write_seek (ebml, mux->duration_pos);
2736     gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
2737     gst_ebml_write_seek (ebml, my_pos);
2738   }
2739   GST_DEBUG_OBJECT (mux, "finishing segment");
2740   /* finish segment - this also writes element length */
2741   gst_ebml_write_master_finish (ebml, mux->segment_pos);
2742 }
2743
2744 /**
2745  * gst_matroska_mux_buffer_header:
2746  * @track: Track context.
2747  * @relative_timestamp: relative timestamp of the buffer
2748  * @flags: Buffer flags.
2749  *
2750  * Create a buffer containing buffer header.
2751  *
2752  * Returns: New buffer.
2753  */
2754 static GstBuffer *
2755 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
2756     gint16 relative_timestamp, int flags)
2757 {
2758   GstBuffer *hdr;
2759
2760   hdr = gst_buffer_new_and_alloc (4);
2761   /* track num - FIXME: what if num >= 0x80 (unlikely)? */
2762   GST_BUFFER_DATA (hdr)[0] = track->num | 0x80;
2763   /* time relative to clustertime */
2764   GST_WRITE_UINT16_BE (GST_BUFFER_DATA (hdr) + 1, relative_timestamp);
2765
2766   /* flags */
2767   GST_BUFFER_DATA (hdr)[3] = flags;
2768
2769   return hdr;
2770 }
2771
2772 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
2773 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
2774 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
2775
2776 static GstBuffer *
2777 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
2778     GstMatroskaPad * collect_pad, GstBuffer * buf)
2779 {
2780   GstMatroskaTrackVideoContext *ctx =
2781       (GstMatroskaTrackVideoContext *) collect_pad->track;
2782   const guint8 *data = GST_BUFFER_DATA (buf);
2783   guint size = GST_BUFFER_SIZE (buf);
2784   guint8 parse_code;
2785   guint32 next_parse_offset;
2786   GstBuffer *ret = NULL;
2787   gboolean is_muxing_unit = FALSE;
2788
2789   if (GST_BUFFER_SIZE (buf) < 13) {
2790     gst_buffer_unref (buf);
2791     return ret;
2792   }
2793
2794   /* Check if this buffer contains a picture or end-of-sequence packet */
2795   while (size >= 13) {
2796     if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
2797       gst_buffer_unref (buf);
2798       return ret;
2799     }
2800
2801     parse_code = GST_READ_UINT8 (data + 4);
2802     if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
2803       if (ctx->dirac_unit) {
2804         gst_buffer_unref (ctx->dirac_unit);
2805         ctx->dirac_unit = NULL;
2806       }
2807     } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
2808         parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
2809       is_muxing_unit = TRUE;
2810       break;
2811     }
2812
2813     next_parse_offset = GST_READ_UINT32_BE (data + 5);
2814
2815     if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
2816       break;
2817
2818     data += next_parse_offset;
2819     size -= next_parse_offset;
2820   }
2821
2822   if (ctx->dirac_unit)
2823     ctx->dirac_unit = gst_buffer_join (ctx->dirac_unit, gst_buffer_ref (buf));
2824   else
2825     ctx->dirac_unit = gst_buffer_ref (buf);
2826
2827   if (is_muxing_unit) {
2828     ret = gst_buffer_make_metadata_writable (ctx->dirac_unit);
2829     ctx->dirac_unit = NULL;
2830     gst_buffer_copy_metadata (ret, buf,
2831         GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
2832         GST_BUFFER_COPY_CAPS);
2833     gst_buffer_unref (buf);
2834   } else {
2835     gst_buffer_unref (buf);
2836     ret = NULL;
2837   }
2838
2839   return ret;
2840 }
2841
2842 static void
2843 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
2844 {
2845   GstCaps *caps;
2846   GstStructure *s;
2847   GValue streamheader = { 0 };
2848   GValue bufval = { 0 };
2849   GstBuffer *streamheader_buffer;
2850   GstEbmlWrite *ebml = mux->ebml_write;
2851
2852   streamheader_buffer = gst_ebml_stop_streamheader (ebml);
2853   if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2854     caps = gst_caps_new_simple ("video/webm", NULL);
2855   } else {
2856     caps = gst_caps_new_simple ("video/x-matroska", NULL);
2857   }
2858   s = gst_caps_get_structure (caps, 0);
2859   g_value_init (&streamheader, GST_TYPE_ARRAY);
2860   g_value_init (&bufval, GST_TYPE_BUFFER);
2861   GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_IN_CAPS);
2862   gst_value_set_buffer (&bufval, streamheader_buffer);
2863   gst_value_array_append_value (&streamheader, &bufval);
2864   g_value_unset (&bufval);
2865   gst_structure_set_value (s, "streamheader", &streamheader);
2866   g_value_unset (&streamheader);
2867   gst_caps_replace (&ebml->caps, caps);
2868   gst_buffer_unref (streamheader_buffer);
2869   gst_caps_unref (caps);
2870 }
2871
2872 /**
2873  * gst_matroska_mux_write_data:
2874  * @mux: #GstMatroskaMux
2875  * @collect_pad: #GstMatroskaPad with the data
2876  *
2877  * Write collected data (called from gst_matroska_mux_collected).
2878  *
2879  * Returns: Result of the gst_pad_push issued to write the data.
2880  */
2881 static GstFlowReturn
2882 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
2883     GstBuffer * buf)
2884 {
2885   GstEbmlWrite *ebml = mux->ebml_write;
2886   GstBuffer *hdr;
2887   guint64 blockgroup;
2888   gboolean write_duration;
2889   gint16 relative_timestamp;
2890   gint64 relative_timestamp64;
2891   guint64 block_duration;
2892   gboolean is_video_keyframe = FALSE;
2893   GstMatroskamuxPad *pad;
2894
2895   /* write data */
2896   pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
2897
2898   /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
2899   if (collect_pad->track->xiph_headers_to_skip > 0) {
2900     GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
2901     gst_buffer_unref (buf);
2902     --collect_pad->track->xiph_headers_to_skip;
2903     return GST_FLOW_OK;
2904   }
2905
2906   /* for dirac we have to queue up everything up to a picture unit */
2907   if (collect_pad->track->codec_id != NULL &&
2908       strcmp (collect_pad->track->codec_id,
2909           GST_MATROSKA_CODEC_ID_VIDEO_DIRAC) == 0) {
2910     buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
2911     if (!buf)
2912       return GST_FLOW_OK;
2913   }
2914
2915   /* hm, invalid timestamp (due to --to be fixed--- element upstream);
2916    * this would wreak havoc with time stored in matroska file */
2917   /* TODO: maybe calculate a timestamp by using the previous timestamp
2918    * and default duration */
2919   if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2920     GST_WARNING_OBJECT (collect_pad->collect.pad,
2921         "Invalid buffer timestamp; dropping buffer");
2922     gst_buffer_unref (buf);
2923     return GST_FLOW_OK;
2924   }
2925
2926   /* set the timestamp for outgoing buffers */
2927   ebml->timestamp = GST_BUFFER_TIMESTAMP (buf);
2928
2929   if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
2930       !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
2931     GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
2932         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2933     is_video_keyframe = TRUE;
2934   }
2935
2936   if (mux->cluster) {
2937     /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
2938      * or when we may be reaching the limit of the relative timestamp */
2939     if (mux->cluster_time +
2940         mux->max_cluster_duration < GST_BUFFER_TIMESTAMP (buf)
2941         || is_video_keyframe || mux->force_key_unit_event) {
2942       if (!mux->streamable)
2943         gst_ebml_write_master_finish (ebml, mux->cluster);
2944
2945       /* Forward the GstForceKeyUnit event after finishing the cluster */
2946       if (mux->force_key_unit_event) {
2947         gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
2948         mux->force_key_unit_event = NULL;
2949       }
2950
2951       mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
2952       mux->cluster_pos = ebml->pos;
2953       gst_ebml_write_set_cache (ebml, 0x20);
2954       mux->cluster =
2955           gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2956       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2957           gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2958               mux->time_scale));
2959       GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
2960           gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2961               mux->time_scale));
2962       gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2963       mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2964       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
2965           mux->prev_cluster_size);
2966     }
2967   } else {
2968     /* first cluster */
2969
2970     mux->cluster_pos = ebml->pos;
2971     gst_ebml_write_set_cache (ebml, 0x20);
2972     mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2973     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2974         gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1, mux->time_scale));
2975     gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2976     mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2977   }
2978
2979   /* update duration of this track */
2980   if (GST_BUFFER_DURATION_IS_VALID (buf))
2981     collect_pad->duration += GST_BUFFER_DURATION (buf);
2982
2983   /* We currently write index entries for all video tracks or for the audio
2984    * track in a single-track audio file.  This could be improved by keeping the
2985    * index only for the *first* video track. */
2986
2987   /* TODO: index is useful for every track, should contain the number of
2988    * the block in the cluster which contains the timestamp, should also work
2989    * for files with multiple audio tracks.
2990    */
2991   if (!mux->streamable &&
2992       (is_video_keyframe ||
2993           ((collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
2994               (mux->num_streams == 1)))) {
2995     gint last_idx = -1;
2996
2997     if (mux->min_index_interval != 0) {
2998       for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
2999         if (mux->index[last_idx].track == collect_pad->track->num)
3000           break;
3001       }
3002     }
3003
3004     if (last_idx < 0 || mux->min_index_interval == 0 ||
3005         (GST_CLOCK_DIFF (mux->index[last_idx].time, GST_BUFFER_TIMESTAMP (buf))
3006             >= mux->min_index_interval)) {
3007       GstMatroskaIndex *idx;
3008
3009       if (mux->num_indexes % 32 == 0) {
3010         mux->index = g_renew (GstMatroskaIndex, mux->index,
3011             mux->num_indexes + 32);
3012       }
3013       idx = &mux->index[mux->num_indexes++];
3014
3015       idx->pos = mux->cluster_pos;
3016       idx->time = GST_BUFFER_TIMESTAMP (buf);
3017       idx->track = collect_pad->track->num;
3018     }
3019   }
3020
3021   /* Check if the duration differs from the default duration. */
3022   write_duration = FALSE;
3023   block_duration = 0;
3024   if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
3025     block_duration = gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
3026         1, mux->time_scale);
3027
3028     /* small difference should be ok. */
3029     if (block_duration > collect_pad->default_duration_scaled + 1 ||
3030         block_duration < collect_pad->default_duration_scaled - 1) {
3031       write_duration = TRUE;
3032     }
3033   }
3034
3035   /* write the block, for doctype v2 use SimpleBlock if possible
3036    * one slice (*breath*).
3037    * FIXME: Need to do correct lacing! */
3038   relative_timestamp64 = GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time;
3039   if (relative_timestamp64 >= 0) {
3040     /* round the timestamp */
3041     relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
3042   } else {
3043     /* round the timestamp */
3044     relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
3045   }
3046   relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
3047       mux->time_scale);
3048   if (mux->doctype_version > 1 && !write_duration) {
3049     int flags =
3050         GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : 0x80;
3051
3052     hdr =
3053         gst_matroska_mux_create_buffer_header (collect_pad->track,
3054         relative_timestamp, flags);
3055     gst_ebml_write_set_cache (ebml, 0x40);
3056     gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
3057         GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
3058     gst_ebml_write_buffer (ebml, hdr);
3059     gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
3060     gst_ebml_write_buffer (ebml, buf);
3061
3062     return gst_ebml_last_write_result (ebml);
3063   } else {
3064     gst_ebml_write_set_cache (ebml, GST_BUFFER_SIZE (buf) * 2);
3065     /* write and call order slightly unnatural,
3066      * but avoids seek and minizes pushing */
3067     blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
3068     hdr =
3069         gst_matroska_mux_create_buffer_header (collect_pad->track,
3070         relative_timestamp, 0);
3071     if (write_duration)
3072       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
3073     gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
3074         GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
3075     gst_ebml_write_buffer (ebml, hdr);
3076     gst_ebml_write_master_finish_full (ebml, blockgroup, GST_BUFFER_SIZE (buf));
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   }
3082 }
3083
3084 /**
3085  * gst_matroska_mux_handle_buffer:
3086  * @pads: #GstCollectPads2
3087  * @uuser_data: #GstMatroskaMux
3088  *
3089  * Collectpads callback.
3090  *
3091  * Returns: #GstFlowReturn
3092  */
3093 static GstFlowReturn
3094 gst_matroska_mux_handle_buffer (GstCollectPads2 * pads, GstCollectData2 * data,
3095     GstBuffer * buf, gpointer user_data)
3096 {
3097   GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
3098   GstEbmlWrite *ebml = mux->ebml_write;
3099   GstMatroskaPad *best;
3100   GstFlowReturn ret = GST_FLOW_OK;
3101
3102   GST_DEBUG_OBJECT (mux, "Collected pads");
3103
3104   /* start with a header */
3105   if (mux->state == GST_MATROSKA_MUX_STATE_START) {
3106     if (mux->collect->data == NULL) {
3107       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
3108           ("No input streams configured"));
3109       return GST_FLOW_ERROR;
3110     }
3111     mux->state = GST_MATROSKA_MUX_STATE_HEADER;
3112     gst_ebml_start_streamheader (ebml);
3113     gst_matroska_mux_start (mux);
3114     gst_matroska_mux_stop_streamheader (mux);
3115     mux->state = GST_MATROSKA_MUX_STATE_DATA;
3116   }
3117
3118   /* provided with stream to write from */
3119   best = (GstMatroskaPad *) data;
3120
3121   /* if there is no best pad, we have reached EOS */
3122   if (best == NULL) {
3123     GST_DEBUG_OBJECT (mux, "No best pad finishing...");
3124     if (!mux->streamable) {
3125       gst_matroska_mux_finish (mux);
3126     } else {
3127       GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
3128     }
3129     gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
3130     ret = GST_FLOW_UNEXPECTED;
3131     goto exit;
3132   }
3133
3134   /* if we have a best stream, should also have a buffer */
3135   g_assert (buf);
3136
3137   GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
3138       GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
3139       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
3140       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
3141
3142   /* make note of first and last encountered timestamps, so we can calculate
3143    * the actual duration later when we send an updated header on eos */
3144   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
3145     GstClockTime start_ts = GST_BUFFER_TIMESTAMP (buf);
3146     GstClockTime end_ts = start_ts;
3147
3148     if (GST_BUFFER_DURATION_IS_VALID (buf))
3149       end_ts += GST_BUFFER_DURATION (buf);
3150     else if (best->track->default_duration)
3151       end_ts += best->track->default_duration;
3152
3153     if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
3154       best->end_ts = end_ts;
3155
3156     if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
3157             start_ts < best->start_ts))
3158       best->start_ts = start_ts;
3159   }
3160
3161   /* write one buffer */
3162   ret = gst_matroska_mux_write_data (mux, best, buf);
3163
3164 exit:
3165   return ret;
3166 }
3167
3168
3169 /**
3170  * gst_matroska_mux_change_state:
3171  * @element: #GstMatroskaMux
3172  * @transition: State change transition.
3173  *
3174  * Change the muxer state.
3175  *
3176  * Returns: #GstStateChangeReturn
3177  */
3178 static GstStateChangeReturn
3179 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
3180 {
3181   GstStateChangeReturn ret;
3182   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
3183
3184   switch (transition) {
3185     case GST_STATE_CHANGE_NULL_TO_READY:
3186       break;
3187     case GST_STATE_CHANGE_READY_TO_PAUSED:
3188       gst_collect_pads2_start (mux->collect);
3189       break;
3190     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
3191       break;
3192     case GST_STATE_CHANGE_PAUSED_TO_READY:
3193       gst_collect_pads2_stop (mux->collect);
3194       break;
3195     default:
3196       break;
3197   }
3198
3199   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3200
3201   switch (transition) {
3202     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3203       break;
3204     case GST_STATE_CHANGE_PAUSED_TO_READY:
3205       gst_matroska_mux_reset (GST_ELEMENT (mux));
3206       break;
3207     case GST_STATE_CHANGE_READY_TO_NULL:
3208       break;
3209     default:
3210       break;
3211   }
3212
3213   return ret;
3214 }
3215
3216 static void
3217 gst_matroska_mux_set_property (GObject * object,
3218     guint prop_id, const GValue * value, GParamSpec * pspec)
3219 {
3220   GstMatroskaMux *mux;
3221
3222   g_return_if_fail (GST_IS_MATROSKA_MUX (object));
3223   mux = GST_MATROSKA_MUX (object);
3224
3225   switch (prop_id) {
3226     case ARG_WRITING_APP:
3227       if (!g_value_get_string (value)) {
3228         GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
3229         break;
3230       }
3231       g_free (mux->writing_app);
3232       mux->writing_app = g_value_dup_string (value);
3233       break;
3234     case ARG_DOCTYPE_VERSION:
3235       mux->doctype_version = g_value_get_int (value);
3236       break;
3237     case ARG_MIN_INDEX_INTERVAL:
3238       mux->min_index_interval = g_value_get_int64 (value);
3239       break;
3240     case ARG_STREAMABLE:
3241       mux->streamable = g_value_get_boolean (value);
3242       break;
3243     default:
3244       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3245       break;
3246   }
3247 }
3248
3249 static void
3250 gst_matroska_mux_get_property (GObject * object,
3251     guint prop_id, GValue * value, GParamSpec * pspec)
3252 {
3253   GstMatroskaMux *mux;
3254
3255   g_return_if_fail (GST_IS_MATROSKA_MUX (object));
3256   mux = GST_MATROSKA_MUX (object);
3257
3258   switch (prop_id) {
3259     case ARG_WRITING_APP:
3260       g_value_set_string (value, mux->writing_app);
3261       break;
3262     case ARG_DOCTYPE_VERSION:
3263       g_value_set_int (value, mux->doctype_version);
3264       break;
3265     case ARG_MIN_INDEX_INTERVAL:
3266       g_value_set_int64 (value, mux->min_index_interval);
3267       break;
3268     case ARG_STREAMABLE:
3269       g_value_set_boolean (value, mux->streamable);
3270       break;
3271     default:
3272       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3273       break;
3274   }
3275 }