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