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