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>
6 * matroska-mux.c: matroska file/stream muxer
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.
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.
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.
24 /* TODO: - check everywhere that we don't write invalid values
25 * - make sure timestamps are correctly scaled everywhere
29 * SECTION:element-matroskamux
31 * matroskamux muxes different input streams into a Matroska file.
34 * <title>Example launch line</title>
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.
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.
52 #include <gst/audio/audio.h>
53 #include <gst/riff/riff-media.h>
54 #include <gst/tag/tag.h>
56 #include "matroska-mux.h"
57 #include "matroska-ids.h"
59 GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
60 #define GST_CAT_DEFAULT matroskamux_debug
67 ARG_MIN_INDEX_INTERVAL,
71 #define DEFAULT_DOCTYPE_VERSION 2
72 #define DEFAULT_WRITING_APP "GStreamer Matroska muxer"
73 #define DEFAULT_MIN_INDEX_INTERVAL 0
74 #define DEFAULT_STREAMABLE FALSE
76 /* WAVEFORMATEX is gst_riff_strf_auds + an extra guint16 extension size */
77 #define WAVEFORMATEX_SIZE (2 + sizeof (gst_riff_strf_auds))
79 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
82 GST_STATIC_CAPS ("video/x-matroska")
85 #define COMMON_VIDEO_CAPS \
86 "width = (int) [ 16, 4096 ], " \
87 "height = (int) [ 16, 4096 ], " \
88 "framerate = (fraction) [ 0, MAX ]"
90 #define COMMON_VIDEO_CAPS_NO_FRAMERATE \
91 "width = (int) [ 16, 4096 ], " \
92 "height = (int) [ 16, 4096 ] "
95 * * require codec data, etc as needed
98 static GstStaticPadTemplate videosink_templ =
99 GST_STATIC_PAD_TEMPLATE ("video_%u",
102 GST_STATIC_CAPS ("video/mpeg, "
103 "mpegversion = (int) { 1, 2, 4 }, "
104 "systemstream = (boolean) false, "
105 COMMON_VIDEO_CAPS "; "
106 "video/x-h264, stream-format=avc, alignment=au, "
107 COMMON_VIDEO_CAPS "; "
109 COMMON_VIDEO_CAPS "; "
111 COMMON_VIDEO_CAPS "; "
113 COMMON_VIDEO_CAPS "; "
115 COMMON_VIDEO_CAPS "; "
117 COMMON_VIDEO_CAPS "; "
119 COMMON_VIDEO_CAPS "; "
121 COMMON_VIDEO_CAPS_NO_FRAMERATE "; "
124 COMMON_VIDEO_CAPS "; "
125 "video/x-pn-realvideo, "
126 "rmversion = (int) [1, 4], "
127 COMMON_VIDEO_CAPS "; "
129 COMMON_VIDEO_CAPS "; "
131 "format = (string) { YUY2, I420, YV12, UYVY, AYUV }, "
132 COMMON_VIDEO_CAPS "; "
133 "video/x-wmv, " "wmvversion = (int) [ 1, 3 ], " COMMON_VIDEO_CAPS)
136 #define COMMON_AUDIO_CAPS \
137 "channels = (int) [ 1, MAX ], " \
138 "rate = (int) [ 1, MAX ]"
141 * * require codec data, etc as needed
143 static GstStaticPadTemplate audiosink_templ =
144 GST_STATIC_PAD_TEMPLATE ("audio_%u",
147 GST_STATIC_CAPS ("audio/mpeg, "
148 "mpegversion = (int) 1, "
149 "layer = (int) [ 1, 3 ], "
150 COMMON_AUDIO_CAPS "; "
152 "mpegversion = (int) { 2, 4 }, "
153 "stream-format = (string) raw, "
154 COMMON_AUDIO_CAPS "; "
156 COMMON_AUDIO_CAPS "; "
158 COMMON_AUDIO_CAPS "; "
160 COMMON_AUDIO_CAPS "; "
162 COMMON_AUDIO_CAPS "; "
164 COMMON_AUDIO_CAPS "; "
166 COMMON_AUDIO_CAPS "; "
168 "format = (string) { U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }, "
169 COMMON_AUDIO_CAPS ";"
171 "width = (int) { 8, 16, 24 }, "
172 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
173 "audio/x-pn-realaudio, "
174 "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS "; "
175 "audio/x-wma, " "wmaversion = (int) [ 1, 3 ], "
176 "block_align = (int) [ 0, 65535 ], bitrate = (int) [ 0, 524288 ], "
177 COMMON_AUDIO_CAPS ";"
179 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
181 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]")
184 static GstStaticPadTemplate subtitlesink_templ =
185 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
188 GST_STATIC_CAPS ("subtitle/x-kate"));
190 static GArray *used_uids;
191 G_LOCK_DEFINE_STATIC (used_uids);
193 #define parent_class gst_matroska_mux_parent_class
194 G_DEFINE_TYPE_WITH_CODE (GstMatroskaMux, gst_matroska_mux, GST_TYPE_ELEMENT,
195 G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
197 /* Matroska muxer destructor */
198 static void gst_matroska_mux_finalize (GObject * object);
200 /* Pads collected callback */
202 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data);
205 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
206 GstObject * parent, GstEvent * event);
207 static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
208 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
209 static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
211 /* gst internal change state handler */
212 static GstStateChangeReturn
213 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
215 /* gobject bla bla */
216 static void gst_matroska_mux_set_property (GObject * object,
217 guint prop_id, const GValue * value, GParamSpec * pspec);
218 static void gst_matroska_mux_get_property (GObject * object,
219 guint prop_id, GValue * value, GParamSpec * pspec);
222 static void gst_matroska_mux_reset (GstElement * element);
225 static guint64 gst_matroska_mux_create_uid ();
227 static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
228 GstMatroskaTrackContext * context);
229 static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
230 GstMatroskaTrackContext * context);
231 static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
232 GstMatroskaTrackContext * context);
233 static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
234 GstMatroskaTrackContext * context);
235 static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
236 GstMatroskaTrackContext * context);
238 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
242 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
244 GObjectClass *gobject_class;
245 GstElementClass *gstelement_class;
247 gobject_class = (GObjectClass *) klass;
248 gstelement_class = (GstElementClass *) klass;
250 gst_element_class_add_pad_template (gstelement_class,
251 gst_static_pad_template_get (&videosink_templ));
252 gst_element_class_add_pad_template (gstelement_class,
253 gst_static_pad_template_get (&audiosink_templ));
254 gst_element_class_add_pad_template (gstelement_class,
255 gst_static_pad_template_get (&subtitlesink_templ));
256 gst_element_class_add_pad_template (gstelement_class,
257 gst_static_pad_template_get (&src_templ));
258 gst_element_class_set_details_simple (gstelement_class, "Matroska muxer",
260 "Muxes video/audio/subtitle streams into a matroska stream",
261 "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
263 GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
266 gobject_class->finalize = gst_matroska_mux_finalize;
268 gobject_class->get_property = gst_matroska_mux_get_property;
269 gobject_class->set_property = gst_matroska_mux_set_property;
271 g_object_class_install_property (gobject_class, ARG_WRITING_APP,
272 g_param_spec_string ("writing-app", "Writing application.",
273 "The name the application that creates the matroska file.",
274 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
275 g_object_class_install_property (gobject_class, ARG_DOCTYPE_VERSION,
276 g_param_spec_int ("version", "DocType version",
277 "This parameter determines what Matroska features can be used.",
278 1, 2, DEFAULT_DOCTYPE_VERSION,
279 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
280 g_object_class_install_property (gobject_class, ARG_MIN_INDEX_INTERVAL,
281 g_param_spec_int64 ("min-index-interval", "Minimum time between index "
282 "entries", "An index entry is created every so many nanoseconds.",
283 0, G_MAXINT64, DEFAULT_MIN_INDEX_INTERVAL,
284 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
285 g_object_class_install_property (gobject_class, ARG_STREAMABLE,
286 g_param_spec_boolean ("streamable", "Determines whether output should "
287 "be streamable", "If set to true, the output should be as if it is "
288 "to be streamed and hence no indexes written or duration written.",
290 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_STATIC_STRINGS));
292 gstelement_class->change_state =
293 GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
294 gstelement_class->request_new_pad =
295 GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
296 gstelement_class->release_pad =
297 GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
301 * Start of pad option handler code
303 #define DEFAULT_PAD_FRAME_DURATION TRUE
304 #define DEFAULT_PAD_FRAME_DURATION_VP8 FALSE
309 PROP_PAD_FRAME_DURATION
315 gboolean frame_duration;
316 gboolean frame_duration_user;
319 static void gst_matroskamux_pad_class_init (GstPadClass * klass);
322 gst_matroskamux_pad_get_type (void)
324 static GType type = 0;
326 if (G_UNLIKELY (type == 0)) {
327 type = g_type_register_static_simple (GST_TYPE_PAD,
328 g_intern_static_string ("GstMatroskamuxPad"), sizeof (GstPadClass),
329 (GClassInitFunc) gst_matroskamux_pad_class_init,
330 sizeof (GstMatroskamuxPad), NULL, 0);
335 #define GST_TYPE_MATROSKAMUX_PAD (gst_matroskamux_pad_get_type())
336 #define GST_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_MATROSKAMUX_PAD,GstMatroskamuxPad))
337 #define GST_MATROSKAMUX_PAD_CAST(pad) ((GstMatroskamuxPad *) pad)
338 #define GST_IS_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_MATROSKAMUX_PAD))
341 gst_matroskamux_pad_get_property (GObject * object, guint prop_id,
342 GValue * value, GParamSpec * pspec)
344 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
347 case PROP_PAD_FRAME_DURATION:
348 g_value_set_boolean (value, pad->frame_duration);
351 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
357 gst_matroskamux_pad_set_property (GObject * object, guint prop_id,
358 const GValue * value, GParamSpec * pspec)
360 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
363 case PROP_PAD_FRAME_DURATION:
364 pad->frame_duration = g_value_get_boolean (value);
365 pad->frame_duration_user = TRUE;
368 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
374 gst_matroskamux_pad_class_init (GstPadClass * klass)
376 GObjectClass *gobject_class = (GObjectClass *) klass;
378 gobject_class->set_property = gst_matroskamux_pad_set_property;
379 gobject_class->get_property = gst_matroskamux_pad_get_property;
381 g_object_class_install_property (gobject_class, PROP_PAD_FRAME_DURATION,
382 g_param_spec_boolean ("frame-duration", "Frame duration",
383 "Default frame duration", DEFAULT_PAD_FRAME_DURATION,
384 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
388 gst_matroskamux_pad_init (GstMatroskamuxPad * pad)
390 pad->frame_duration = DEFAULT_PAD_FRAME_DURATION;
391 pad->frame_duration_user = FALSE;
395 * End of pad option handler code
399 * gst_matroska_mux_init:
400 * @mux: #GstMatroskaMux that should be initialized.
401 * @g_class: Class of the muxer.
403 * Matroska muxer constructor.
406 gst_matroska_mux_init (GstMatroskaMux * mux)
408 GstPadTemplate *templ;
411 gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (mux), "src");
412 mux->srcpad = gst_pad_new_from_template (templ, "src");
414 gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
415 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
417 mux->collect = gst_collect_pads_new ();
418 gst_collect_pads_set_function (mux->collect,
419 (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_matroska_mux_collected),
422 mux->ebml_write = gst_ebml_write_new (mux->srcpad);
423 mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
425 /* property defaults */
426 mux->doctype_version = DEFAULT_DOCTYPE_VERSION;
427 mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
428 mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
429 mux->streamable = DEFAULT_STREAMABLE;
431 /* initialize internal variables */
433 mux->num_streams = 0;
434 mux->num_a_streams = 0;
435 mux->num_t_streams = 0;
436 mux->num_v_streams = 0;
438 /* initialize remaining variables */
439 gst_matroska_mux_reset (GST_ELEMENT (mux));
444 * gst_matroska_mux_finalize:
445 * @object: #GstMatroskaMux that should be finalized.
447 * Finalize matroska muxer.
450 gst_matroska_mux_finalize (GObject * object)
452 GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
454 gst_event_replace (&mux->force_key_unit_event, NULL);
456 gst_object_unref (mux->collect);
457 gst_object_unref (mux->ebml_write);
458 if (mux->writing_app)
459 g_free (mux->writing_app);
461 G_OBJECT_CLASS (parent_class)->finalize (object);
466 * gst_matroska_mux_create_uid:
468 * Generate new unused track UID.
470 * Returns: New track UID.
473 gst_matroska_mux_create_uid (void)
480 used_uids = g_array_sized_new (FALSE, FALSE, sizeof (guint64), 10);
485 uid = (((guint64) g_random_int ()) << 32) | g_random_int ();
486 for (i = 0; i < used_uids->len; i++) {
487 if (g_array_index (used_uids, guint64, i) == uid) {
492 g_array_append_val (used_uids, uid);
495 G_UNLOCK (used_uids);
501 * gst_matroska_pad_reset:
502 * @collect_pad: the #GstMatroskaPad
504 * Reset and/or release resources of a matroska collect pad.
507 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
510 GstMatroskaTrackType type = 0;
512 /* free track information */
513 if (collect_pad->track != NULL) {
514 /* retrieve for optional later use */
515 name = collect_pad->track->name;
516 type = collect_pad->track->type;
517 /* extra for video */
518 if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
519 GstMatroskaTrackVideoContext *ctx =
520 (GstMatroskaTrackVideoContext *) collect_pad->track;
522 if (ctx->dirac_unit) {
523 gst_buffer_unref (ctx->dirac_unit);
524 ctx->dirac_unit = NULL;
527 g_free (collect_pad->track->codec_id);
528 g_free (collect_pad->track->codec_name);
530 g_free (collect_pad->track->name);
531 g_free (collect_pad->track->language);
532 g_free (collect_pad->track->codec_priv);
533 g_free (collect_pad->track);
534 collect_pad->track = NULL;
537 /* free cached buffer */
538 if (collect_pad->buffer != NULL) {
539 gst_buffer_unref (collect_pad->buffer);
540 collect_pad->buffer = NULL;
543 if (!full && type != 0) {
544 GstMatroskaTrackContext *context;
546 /* create a fresh context */
548 case GST_MATROSKA_TRACK_TYPE_VIDEO:
549 context = (GstMatroskaTrackContext *)
550 g_new0 (GstMatroskaTrackVideoContext, 1);
552 case GST_MATROSKA_TRACK_TYPE_AUDIO:
553 context = (GstMatroskaTrackContext *)
554 g_new0 (GstMatroskaTrackAudioContext, 1);
556 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
557 context = (GstMatroskaTrackContext *)
558 g_new0 (GstMatroskaTrackSubtitleContext, 1);
561 g_assert_not_reached ();
565 context->type = type;
566 context->name = name;
567 /* TODO: check default values for the context */
568 context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
569 collect_pad->track = context;
570 collect_pad->buffer = NULL;
571 collect_pad->duration = 0;
572 collect_pad->start_ts = GST_CLOCK_TIME_NONE;
573 collect_pad->end_ts = GST_CLOCK_TIME_NONE;
578 * gst_matroska_pad_free:
579 * @collect_pad: the #GstMatroskaPad
581 * Release resources of a matroska collect pad.
584 gst_matroska_pad_free (GstPad * collect_pad)
586 gst_matroska_pad_reset ((GstMatroskaPad *) collect_pad, TRUE);
591 * gst_matroska_mux_reset:
592 * @element: #GstMatroskaMux that should be reseted.
594 * Reset matroska muxer back to initial state.
597 gst_matroska_mux_reset (GstElement * element)
599 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
602 /* reset EBML write */
603 gst_ebml_write_reset (mux->ebml_write);
606 mux->state = GST_MATROSKA_MUX_STATE_START;
608 /* clean up existing streams */
610 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
611 GstMatroskaPad *collect_pad;
613 collect_pad = (GstMatroskaPad *) walk->data;
615 /* reset collect pad to pristine state */
616 gst_matroska_pad_reset (collect_pad, FALSE);
620 mux->num_indexes = 0;
625 mux->time_scale = GST_MSECOND;
626 mux->max_cluster_duration = G_MAXINT16 * mux->time_scale;
631 mux->cluster_time = 0;
632 mux->cluster_pos = 0;
633 mux->prev_cluster_size = 0;
636 gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
640 * gst_matroska_mux_handle_src_event:
641 * @pad: Pad which received the event.
642 * @event: Received event.
644 * handle events - copied from oggmux without understanding
646 * Returns: #TRUE on success.
649 gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
654 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
658 /* disable seeking for now */
664 return gst_pad_event_default (pad, parent, event);
668 * gst_matroska_mux_handle_sink_event:
669 * @pad: Pad which received the event.
670 * @event: Received event.
672 * handle events - informational ones like tags
674 * Returns: #TRUE on success.
677 gst_matroska_mux_handle_sink_event (GstPad * pad, GstObject * parent,
680 GstMatroskaTrackContext *context;
681 GstMatroskaPad *collect_pad;
682 GstMatroskaMux *mux = GST_MATROSKA_MUX (parent);
686 switch (GST_EVENT_TYPE (event)) {
687 case GST_EVENT_CAPS:{
690 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
691 gst_event_parse_caps (event, &caps);
693 ret = collect_pad->capsfunc (pad, caps);
694 gst_event_unref (event);
701 GST_DEBUG_OBJECT (mux, "received tag event");
702 gst_event_parse_tag (event, &list);
704 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
705 g_assert (collect_pad);
706 context = collect_pad->track;
709 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
710 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
711 const gchar *lang_code;
713 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
715 GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
716 context->language = g_strdup (lang_code);
718 GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
723 /* FIXME: what about stream-specific tags? */
724 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
725 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
727 gst_event_unref (event);
728 /* handled this, don't want collectpads to forward it downstream */
732 case GST_EVENT_SEGMENT:{
733 const GstSegment *segment;
735 gst_event_parse_segment (event, &segment);
736 if (segment->format != GST_FORMAT_TIME) {
738 gst_event_unref (event);
743 case GST_EVENT_CUSTOM_DOWNSTREAM:{
744 const GstStructure *structure;
746 structure = gst_event_get_structure (event);
747 if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
748 gst_event_replace (&mux->force_key_unit_event, NULL);
749 mux->force_key_unit_event = event;
758 /* now GstCollectPads can take care of the rest, e.g. EOS */
760 ret = mux->collect_event (pad, parent, event);
767 * gst_matroska_mux_video_pad_setcaps:
768 * @pad: Pad which got the caps.
771 * Setcaps function for video sink pad.
773 * Returns: #TRUE on success.
776 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
778 GstMatroskaTrackContext *context = NULL;
779 GstMatroskaTrackVideoContext *videocontext;
781 GstMatroskaPad *collect_pad;
782 GstStructure *structure;
783 const gchar *mimetype;
784 const GValue *value = NULL;
785 GstBuffer *codec_buf = NULL;
786 gint width, height, pixel_width, pixel_height;
788 gboolean interlaced = FALSE;
790 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
793 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
794 g_assert (collect_pad);
795 context = collect_pad->track;
797 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
798 videocontext = (GstMatroskaTrackVideoContext *) context;
800 /* gst -> matroska ID'ing */
801 structure = gst_caps_get_structure (caps, 0);
803 mimetype = gst_structure_get_name (structure);
805 if (gst_structure_get_boolean (structure, "interlaced", &interlaced)
807 context->flags |= GST_MATROSKA_VIDEOTRACK_INTERLACED;
809 if (!strcmp (mimetype, "video/x-theora")) {
810 /* we'll extract the details later from the theora identification header */
814 /* get general properties */
815 /* spec says it is mandatory */
816 if (!gst_structure_get_int (structure, "width", &width) ||
817 !gst_structure_get_int (structure, "height", &height))
820 videocontext->pixel_width = width;
821 videocontext->pixel_height = height;
823 /* set vp8 defaults or let user override it */
824 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration_user == FALSE
825 && (!strcmp (mimetype, "video/x-vp8")))
826 GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration =
827 DEFAULT_PAD_FRAME_DURATION_VP8;
829 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
830 && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
832 context->default_duration =
833 gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
834 GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
835 GST_TIME_ARGS (context->default_duration));
837 context->default_duration = 0;
839 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
840 &pixel_width, &pixel_height)) {
841 if (pixel_width > pixel_height) {
842 videocontext->display_width = width * pixel_width / pixel_height;
843 videocontext->display_height = height;
844 } else if (pixel_width < pixel_height) {
845 videocontext->display_width = width;
846 videocontext->display_height = height * pixel_height / pixel_width;
848 videocontext->display_width = 0;
849 videocontext->display_height = 0;
852 videocontext->display_width = 0;
853 videocontext->display_height = 0;
858 videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
859 videocontext->fourcc = 0;
861 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
862 * data and other settings
866 /* extract codec_data, may turn out needed */
867 value = gst_structure_get_value (structure, "codec_data");
869 codec_buf = (GstBuffer *) gst_value_get_buffer (value);
872 if (!strcmp (mimetype, "video/x-raw")) {
874 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
875 fstr = gst_structure_get_string (structure, "format");
876 if (fstr && strlen (fstr) == 4)
877 videocontext->fourcc = GST_STR_FOURCC (fstr);
878 } else if (!strcmp (mimetype, "image/jpeg")) {
879 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
880 } else if (!strcmp (mimetype, "video/x-xvid") /* MS/VfW compatibility cases */
881 ||!strcmp (mimetype, "video/x-huffyuv")
882 || !strcmp (mimetype, "video/x-divx")
883 || !strcmp (mimetype, "video/x-dv")
884 || !strcmp (mimetype, "video/x-h263")
885 || !strcmp (mimetype, "video/x-msmpeg")
886 || !strcmp (mimetype, "video/x-wmv")
887 || !strcmp (mimetype, "image/jpeg")) {
888 gst_riff_strf_vids *bih;
889 gint size = sizeof (gst_riff_strf_vids);
892 if (!strcmp (mimetype, "video/x-xvid"))
893 fourcc = GST_MAKE_FOURCC ('X', 'V', 'I', 'D');
894 else if (!strcmp (mimetype, "video/x-huffyuv"))
895 fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
896 else if (!strcmp (mimetype, "video/x-dv"))
897 fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
898 else if (!strcmp (mimetype, "video/x-h263"))
899 fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
900 else if (!strcmp (mimetype, "video/x-divx")) {
903 gst_structure_get_int (structure, "divxversion", &divxversion);
904 switch (divxversion) {
906 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
909 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
912 fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
915 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
918 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
919 switch (msmpegversion) {
921 fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
924 fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
930 } else if (!strcmp (mimetype, "video/x-wmv")) {
934 fstr = gst_structure_get_string (structure, "format");
935 if (fstr && strlen (fstr) == 4) {
936 fourcc = GST_STR_FOURCC (fstr);
937 } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
938 if (wmvversion == 2) {
939 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
940 } else if (wmvversion == 1) {
941 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
942 } else if (wmvversion == 3) {
943 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
946 } else if (!strcmp (mimetype, "image/jpeg")) {
947 fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
953 bih = g_new0 (gst_riff_strf_vids, 1);
954 GST_WRITE_UINT32_LE (&bih->size, size);
955 GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
956 GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
957 GST_WRITE_UINT32_LE (&bih->compression, fourcc);
958 GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
959 GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
960 GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
961 videocontext->pixel_height * 3);
963 /* process codec private/initialization data, if any */
965 size += gst_buffer_get_size (codec_buf);
966 bih = g_realloc (bih, size);
967 GST_WRITE_UINT32_LE (&bih->size, size);
968 gst_buffer_extract (codec_buf, 0,
969 (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
972 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
973 context->codec_priv = (gpointer) bih;
974 context->codec_priv_size = size;
975 } else if (!strcmp (mimetype, "video/x-h264")) {
976 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
978 if (context->codec_priv != NULL) {
979 g_free (context->codec_priv);
980 context->codec_priv = NULL;
981 context->codec_priv_size = 0;
984 /* Create avcC header */
985 if (codec_buf != NULL) {
986 context->codec_priv_size = gst_buffer_get_size (codec_buf);
987 context->codec_priv = g_malloc0 (context->codec_priv_size);
988 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
990 } else if (!strcmp (mimetype, "video/x-theora")) {
991 const GValue *streamheader;
993 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
995 if (context->codec_priv != NULL) {
996 g_free (context->codec_priv);
997 context->codec_priv = NULL;
998 context->codec_priv_size = 0;
1001 streamheader = gst_structure_get_value (structure, "streamheader");
1002 if (!theora_streamheader_to_codecdata (streamheader, context)) {
1003 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1004 ("theora stream headers missing or malformed"));
1007 } else if (!strcmp (mimetype, "video/x-dirac")) {
1008 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
1009 } else if (!strcmp (mimetype, "video/x-vp8")) {
1010 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VP8);
1011 } else if (!strcmp (mimetype, "video/mpeg")) {
1014 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1015 switch (mpegversion) {
1017 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
1020 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
1023 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
1029 /* global headers may be in codec data */
1030 if (codec_buf != NULL) {
1031 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1032 context->codec_priv = g_malloc0 (context->codec_priv_size);
1033 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1035 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1037 /* can only make it here if preceding case verified it was version 3 */
1038 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
1039 } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
1041 const GValue *mdpr_data;
1043 gst_structure_get_int (structure, "rmversion", &rmversion);
1044 switch (rmversion) {
1046 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
1049 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
1052 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
1055 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
1061 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1062 if (mdpr_data != NULL) {
1063 guint8 *priv_data = NULL;
1064 guint priv_data_size = 0;
1066 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1068 priv_data_size = gst_buffer_get_size (codec_data_buf);
1069 priv_data = g_malloc0 (priv_data_size);
1071 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1073 context->codec_priv = priv_data;
1074 context->codec_priv_size = priv_data_size;
1083 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1084 GST_PAD_NAME (pad), caps);
1089 /* N > 0 to expect a particular number of headers, negative if the
1090 number of headers is variable */
1092 xiphN_streamheader_to_codecdata (const GValue * streamheader,
1093 GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
1095 GstBuffer **buf = NULL;
1098 guint bufi, i, offset, priv_data_size;
1100 if (streamheader == NULL)
1101 goto no_stream_headers;
1103 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1106 bufarr = g_value_peek_pointer (streamheader);
1107 if (bufarr->len <= 0 || bufarr->len > 255) /* at least one header, and count stored in a byte */
1109 if (N > 0 && bufarr->len != N)
1112 context->xiph_headers_to_skip = bufarr->len;
1114 buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1115 for (i = 0; i < bufarr->len; i++) {
1116 GValue *bufval = &g_array_index (bufarr, GValue, i);
1118 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1120 goto wrong_content_type;
1123 buf[i] = g_value_peek_pointer (bufval);
1127 if (bufarr->len > 0) {
1128 for (i = 0; i < bufarr->len - 1; i++) {
1129 priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
1133 for (i = 0; i < bufarr->len; ++i) {
1134 priv_data_size += gst_buffer_get_size (buf[i]);
1137 priv_data = g_malloc0 (priv_data_size);
1139 priv_data[0] = bufarr->len - 1;
1142 if (bufarr->len > 0) {
1143 for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1144 for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
1145 priv_data[offset++] = 0xff;
1147 priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
1151 for (i = 0; i < bufarr->len; ++i) {
1152 gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
1153 offset += gst_buffer_get_size (buf[i]);
1156 context->codec_priv = priv_data;
1157 context->codec_priv_size = priv_data_size;
1160 *p_buf0 = gst_buffer_ref (buf[0]);
1169 GST_WARNING ("required streamheaders missing in sink caps!");
1174 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1175 G_VALUE_TYPE_NAME (streamheader));
1180 GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1185 GST_WARNING ("streamheaders array does not contain GstBuffers");
1191 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1192 GstMatroskaTrackContext * context)
1194 GstBuffer *buf0 = NULL;
1196 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1199 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
1200 GST_WARNING ("First vorbis header too small, ignoring");
1202 if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
1203 GstMatroskaTrackAudioContext *audiocontext;
1206 data = gst_buffer_map (buf0, NULL, NULL, GST_MAP_READ);
1207 hdr = data + 1 + 6 + 4;
1208 audiocontext = (GstMatroskaTrackAudioContext *) context;
1209 audiocontext->channels = GST_READ_UINT8 (hdr);
1210 audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1211 gst_buffer_unmap (buf0, data, -1);
1216 gst_buffer_unref (buf0);
1222 theora_streamheader_to_codecdata (const GValue * streamheader,
1223 GstMatroskaTrackContext * context)
1225 GstBuffer *buf0 = NULL;
1227 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1230 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
1231 GST_WARNING ("First theora header too small, ignoring");
1232 } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
1233 GST_WARNING ("First header not a theora identification header, ignoring");
1235 GstMatroskaTrackVideoContext *videocontext;
1236 guint fps_num, fps_denom, par_num, par_denom;
1239 data = gst_buffer_map (buf0, NULL, NULL, GST_MAP_READ);
1240 hdr = data + 1 + 6 + 3 + 2 + 2;
1242 videocontext = (GstMatroskaTrackVideoContext *) context;
1243 videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1244 videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1245 hdr += 3 + 3 + 1 + 1;
1246 fps_num = GST_READ_UINT32_BE (hdr);
1247 fps_denom = GST_READ_UINT32_BE (hdr + 4);
1248 context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1249 fps_denom, fps_num);
1251 par_num = GST_READ_UINT32_BE (hdr) >> 8;
1252 par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1253 if (par_num > 0 && par_num > 0) {
1254 if (par_num > par_denom) {
1255 videocontext->display_width =
1256 videocontext->pixel_width * par_num / par_denom;
1257 videocontext->display_height = videocontext->pixel_height;
1258 } else if (par_num < par_denom) {
1259 videocontext->display_width = videocontext->pixel_width;
1260 videocontext->display_height =
1261 videocontext->pixel_height * par_denom / par_num;
1263 videocontext->display_width = 0;
1264 videocontext->display_height = 0;
1267 videocontext->display_width = 0;
1268 videocontext->display_height = 0;
1272 gst_buffer_unmap (buf0, data, -1);
1276 gst_buffer_unref (buf0);
1282 kate_streamheader_to_codecdata (const GValue * streamheader,
1283 GstMatroskaTrackContext * context)
1285 GstBuffer *buf0 = NULL;
1287 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1290 if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) { /* Kate ID header is 64 bytes */
1291 GST_WARNING ("First kate header too small, ignoring");
1292 } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
1293 GST_WARNING ("First header not a kate identification header, ignoring");
1297 gst_buffer_unref (buf0);
1303 flac_streamheader_to_codecdata (const GValue * streamheader,
1304 GstMatroskaTrackContext * context)
1311 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1312 GST_WARNING ("No or invalid streamheader field in the caps");
1316 bufarr = g_value_peek_pointer (streamheader);
1317 if (bufarr->len < 2) {
1318 GST_WARNING ("Too few headers in streamheader field");
1322 context->xiph_headers_to_skip = bufarr->len + 1;
1324 bufval = &g_array_index (bufarr, GValue, 0);
1325 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1326 GST_WARNING ("streamheaders array does not contain GstBuffers");
1330 buffer = g_value_peek_pointer (bufval);
1332 /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1333 if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
1334 || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
1335 || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
1336 GST_WARNING ("Invalid streamheader for FLAC");
1340 context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
1341 context->codec_priv = g_malloc (context->codec_priv_size);
1342 gst_buffer_extract (buffer, 9, context->codec_priv, -1);
1344 for (i = 1; i < bufarr->len; i++) {
1346 bufval = &g_array_index (bufarr, GValue, i);
1348 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1349 g_free (context->codec_priv);
1350 context->codec_priv = NULL;
1351 context->codec_priv_size = 0;
1352 GST_WARNING ("streamheaders array does not contain GstBuffers");
1356 buffer = g_value_peek_pointer (bufval);
1358 old_size = context->codec_priv_size;
1359 context->codec_priv_size += gst_buffer_get_size (buffer);
1361 context->codec_priv = g_realloc (context->codec_priv,
1362 context->codec_priv_size);
1363 gst_buffer_extract (buffer, 0,
1364 (guint8 *) context->codec_priv + old_size, -1);
1371 speex_streamheader_to_codecdata (const GValue * streamheader,
1372 GstMatroskaTrackContext * context)
1379 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1380 GST_WARNING ("No or invalid streamheader field in the caps");
1384 bufarr = g_value_peek_pointer (streamheader);
1385 if (bufarr->len != 2) {
1386 GST_WARNING ("Too few headers in streamheader field");
1390 context->xiph_headers_to_skip = bufarr->len + 1;
1392 bufval = &g_array_index (bufarr, GValue, 0);
1393 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1394 GST_WARNING ("streamheaders array does not contain GstBuffers");
1398 buffer = g_value_peek_pointer (bufval);
1400 if (gst_buffer_get_size (buffer) < 80
1401 || gst_buffer_memcmp (buffer, 0, "Speex ", 8) != 0) {
1402 GST_WARNING ("Invalid streamheader for Speex");
1406 context->codec_priv_size = gst_buffer_get_size (buffer);
1407 context->codec_priv = g_malloc (context->codec_priv_size);
1408 gst_buffer_extract (buffer, 0, context->codec_priv, -1);
1410 bufval = &g_array_index (bufarr, GValue, 1);
1412 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1413 g_free (context->codec_priv);
1414 context->codec_priv = NULL;
1415 context->codec_priv_size = 0;
1416 GST_WARNING ("streamheaders array does not contain GstBuffers");
1420 buffer = g_value_peek_pointer (bufval);
1422 old_size = context->codec_priv_size;
1423 context->codec_priv_size += gst_buffer_get_size (buffer);
1424 context->codec_priv = g_realloc (context->codec_priv,
1425 context->codec_priv_size);
1426 gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
1431 static const gchar *
1432 aac_codec_data_to_codec_id (GstBuffer * buf)
1434 const gchar *result;
1437 /* default to MAIN */
1440 if (gst_buffer_get_size (buf) >= 2) {
1441 gst_buffer_extract (buf, 0, &profile, 1);
1459 GST_WARNING ("unknown AAC profile, defaulting to MAIN");
1468 * gst_matroska_mux_audio_pad_setcaps:
1469 * @pad: Pad which got the caps.
1472 * Setcaps function for audio sink pad.
1474 * Returns: #TRUE on success.
1477 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1479 GstMatroskaTrackContext *context = NULL;
1480 GstMatroskaTrackAudioContext *audiocontext;
1481 GstMatroskaMux *mux;
1482 GstMatroskaPad *collect_pad;
1483 const gchar *mimetype;
1484 gint samplerate = 0, channels = 0;
1485 GstStructure *structure;
1486 const GValue *codec_data = NULL;
1487 GstBuffer *buf = NULL;
1488 const gchar *stream_format = NULL;
1490 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1493 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1494 g_assert (collect_pad);
1495 context = collect_pad->track;
1497 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
1498 audiocontext = (GstMatroskaTrackAudioContext *) context;
1500 structure = gst_caps_get_structure (caps, 0);
1501 mimetype = gst_structure_get_name (structure);
1504 gst_structure_get_int (structure, "rate", &samplerate);
1505 gst_structure_get_int (structure, "channels", &channels);
1507 audiocontext->samplerate = samplerate;
1508 audiocontext->channels = channels;
1509 audiocontext->bitdepth = 0;
1510 context->default_duration = 0;
1512 codec_data = gst_structure_get_value (structure, "codec_data");
1514 buf = gst_value_get_buffer (codec_data);
1516 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1517 * data and other settings
1521 if (!strcmp (mimetype, "audio/mpeg")) {
1522 gint mpegversion = 0;
1524 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1525 switch (mpegversion) {
1531 gst_structure_get_int (structure, "layer", &layer);
1533 if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
1534 GST_WARNING_OBJECT (mux,
1535 "Unable to determine MPEG audio version, assuming 1");
1541 else if (layer == 2)
1543 else if (version == 2)
1548 context->default_duration =
1549 gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
1553 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
1556 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
1559 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
1568 stream_format = gst_structure_get_string (structure, "stream-format");
1569 /* check this is raw aac */
1570 if (stream_format) {
1571 if (strcmp (stream_format, "raw") != 0) {
1572 GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
1576 GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
1581 if (mpegversion == 2)
1583 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2 "%s",
1584 aac_codec_data_to_codec_id (buf));
1585 else if (mpegversion == 4)
1587 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4 "%s",
1588 aac_codec_data_to_codec_id (buf));
1590 g_assert_not_reached ();
1592 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
1599 } else if (!strcmp (mimetype, "audio/x-raw")) {
1602 gst_audio_info_init (&info);
1603 if (!gst_audio_info_from_caps (&info, caps)) {
1604 GST_DEBUG_OBJECT (mux,
1605 "broken caps, rejected by gst_audio_info_from_caps");
1609 switch (GST_AUDIO_INFO_FORMAT (&info)) {
1610 case GST_AUDIO_FORMAT_U8:
1611 case GST_AUDIO_FORMAT_S16BE:
1612 case GST_AUDIO_FORMAT_S16LE:
1613 case GST_AUDIO_FORMAT_S24BE:
1614 case GST_AUDIO_FORMAT_S24LE:
1615 case GST_AUDIO_FORMAT_S32BE:
1616 case GST_AUDIO_FORMAT_S32LE:
1617 if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
1618 GST_DEBUG_OBJECT (mux, "width must be same as depth!");
1621 if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
1622 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
1624 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
1627 case GST_AUDIO_FORMAT_F32LE:
1628 case GST_AUDIO_FORMAT_F64LE:
1629 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
1633 GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
1637 audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
1639 } else if (!strcmp (mimetype, "audio/x-vorbis")) {
1640 const GValue *streamheader;
1642 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
1644 if (context->codec_priv != NULL) {
1645 g_free (context->codec_priv);
1646 context->codec_priv = NULL;
1647 context->codec_priv_size = 0;
1650 streamheader = gst_structure_get_value (structure, "streamheader");
1651 if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
1652 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1653 ("vorbis stream headers missing or malformed"));
1656 } else if (!strcmp (mimetype, "audio/x-flac")) {
1657 const GValue *streamheader;
1659 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
1660 if (context->codec_priv != NULL) {
1661 g_free (context->codec_priv);
1662 context->codec_priv = NULL;
1663 context->codec_priv_size = 0;
1666 streamheader = gst_structure_get_value (structure, "streamheader");
1667 if (!flac_streamheader_to_codecdata (streamheader, context)) {
1668 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1669 ("flac stream headers missing or malformed"));
1672 } else if (!strcmp (mimetype, "audio/x-speex")) {
1673 const GValue *streamheader;
1675 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
1676 if (context->codec_priv != NULL) {
1677 g_free (context->codec_priv);
1678 context->codec_priv = NULL;
1679 context->codec_priv_size = 0;
1682 streamheader = gst_structure_get_value (structure, "streamheader");
1683 if (!speex_streamheader_to_codecdata (streamheader, context)) {
1684 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1685 ("speex stream headers missing or malformed"));
1688 } else if (!strcmp (mimetype, "audio/x-ac3")) {
1689 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AC3);
1690 } else if (!strcmp (mimetype, "audio/x-eac3")) {
1691 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
1692 } else if (!strcmp (mimetype, "audio/x-dts")) {
1693 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_DTS);
1694 } else if (!strcmp (mimetype, "audio/x-tta")) {
1697 /* TTA frame duration */
1698 context->default_duration = 1.04489795918367346939 * GST_SECOND;
1700 gst_structure_get_int (structure, "width", &width);
1701 audiocontext->bitdepth = width;
1702 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_TTA);
1704 } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
1706 const GValue *mdpr_data;
1708 gst_structure_get_int (structure, "raversion", &raversion);
1709 switch (raversion) {
1711 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
1714 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
1717 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
1723 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1724 if (mdpr_data != NULL) {
1725 guint8 *priv_data = NULL;
1726 guint priv_data_size = 0;
1728 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1730 priv_data_size = gst_buffer_get_size (codec_data_buf);
1731 priv_data = g_malloc0 (priv_data_size);
1733 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1735 context->codec_priv = priv_data;
1736 context->codec_priv_size = priv_data_size;
1739 } else if (!strcmp (mimetype, "audio/x-wma")
1740 || !strcmp (mimetype, "audio/x-alaw")
1741 || !strcmp (mimetype, "audio/x-mulaw")) {
1743 guint codec_priv_size;
1748 if (samplerate == 0 || channels == 0) {
1749 GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
1753 if (!strcmp (mimetype, "audio/x-wma")) {
1757 if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
1758 || !gst_structure_get_int (structure, "block_align", &block_align)
1759 || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
1760 GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
1765 switch (wmaversion) {
1767 format = GST_RIFF_WAVE_FORMAT_WMAV1;
1770 format = GST_RIFF_WAVE_FORMAT_WMAV2;
1773 format = GST_RIFF_WAVE_FORMAT_WMAV3;
1776 GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
1780 if (gst_structure_get_int (structure, "depth", &depth))
1781 audiocontext->bitdepth = depth;
1782 } else if (!strcmp (mimetype, "audio/x-alaw")
1783 || !strcmp (mimetype, "audio/x-mulaw")) {
1784 audiocontext->bitdepth = 8;
1785 if (!strcmp (mimetype, "audio/x-alaw"))
1786 format = GST_RIFF_WAVE_FORMAT_ALAW;
1788 format = GST_RIFF_WAVE_FORMAT_MULAW;
1790 block_align = channels;
1791 bitrate = block_align * samplerate;
1793 g_assert (format != 0);
1795 codec_priv_size = WAVEFORMATEX_SIZE;
1797 codec_priv_size += gst_buffer_get_size (buf);
1799 /* serialize waveformatex structure */
1800 codec_priv = g_malloc0 (codec_priv_size);
1801 GST_WRITE_UINT16_LE (codec_priv, format);
1802 GST_WRITE_UINT16_LE (codec_priv + 2, channels);
1803 GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
1804 GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
1805 GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
1806 GST_WRITE_UINT16_LE (codec_priv + 14, 0);
1808 GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
1810 GST_WRITE_UINT16_LE (codec_priv + 16, 0);
1812 /* process codec private/initialization data, if any */
1814 gst_buffer_extract (buf, 0,
1815 (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
1818 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_ACM);
1819 context->codec_priv = (gpointer) codec_priv;
1820 context->codec_priv_size = codec_priv_size;
1828 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1829 GST_PAD_NAME (pad), caps);
1836 * gst_matroska_mux_subtitle_pad_setcaps:
1837 * @pad: Pad which got the caps.
1840 * Setcaps function for subtitle sink pad.
1842 * Returns: #TRUE on success.
1845 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
1848 * Consider this as boilerplate code for now. There is
1849 * no single subtitle creation element in GStreamer,
1850 * neither do I know how subtitling works at all. */
1852 /* There is now (at least) one such alement (kateenc), and I'm going
1853 to handle it here and claim it works when it can be piped back
1854 through GStreamer and VLC */
1856 GstMatroskaTrackContext *context = NULL;
1857 GstMatroskaTrackSubtitleContext *scontext;
1858 GstMatroskaMux *mux;
1859 GstMatroskaPad *collect_pad;
1860 const gchar *mimetype;
1861 GstStructure *structure;
1863 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1866 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1867 g_assert (collect_pad);
1868 context = collect_pad->track;
1870 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
1871 scontext = (GstMatroskaTrackSubtitleContext *) context;
1873 structure = gst_caps_get_structure (caps, 0);
1874 mimetype = gst_structure_get_name (structure);
1877 scontext->check_utf8 = 1;
1878 scontext->invalid_utf8 = 0;
1879 context->default_duration = 0;
1881 /* TODO: - other format than Kate */
1883 if (!strcmp (mimetype, "subtitle/x-kate")) {
1884 const GValue *streamheader;
1886 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
1888 if (context->codec_priv != NULL) {
1889 g_free (context->codec_priv);
1890 context->codec_priv = NULL;
1891 context->codec_priv_size = 0;
1894 streamheader = gst_structure_get_value (structure, "streamheader");
1895 if (!kate_streamheader_to_codecdata (streamheader, context)) {
1896 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1897 ("kate stream headers missing or malformed"));
1908 * gst_matroska_mux_request_new_pad:
1909 * @element: #GstMatroskaMux.
1910 * @templ: #GstPadTemplate.
1911 * @pad_name: New pad name.
1913 * Request pad function for sink templates.
1915 * Returns: New #GstPad.
1918 gst_matroska_mux_request_new_pad (GstElement * element,
1919 GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
1921 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
1922 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
1923 GstMatroskaPad *collect_pad;
1924 GstMatroskamuxPad *newpad;
1926 const gchar *pad_name = NULL;
1927 GstMatroskaCapsFunc capsfunc = NULL;
1928 GstMatroskaTrackContext *context = NULL;
1931 if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
1932 /* don't mix named and unnamed pads, if the pad already exists we fail when
1933 * trying to add it */
1934 if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
1935 pad_name = req_name;
1937 name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
1940 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
1941 context = (GstMatroskaTrackContext *)
1942 g_new0 (GstMatroskaTrackAudioContext, 1);
1943 context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
1944 context->name = g_strdup ("Audio");
1945 } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
1946 /* don't mix named and unnamed pads, if the pad already exists we fail when
1947 * trying to add it */
1948 if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
1949 pad_name = req_name;
1951 name = g_strdup_printf ("video_%u", mux->num_v_streams++);
1954 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
1955 context = (GstMatroskaTrackContext *)
1956 g_new0 (GstMatroskaTrackVideoContext, 1);
1957 context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
1958 context->name = g_strdup ("Video");
1959 } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
1960 /* don't mix named and unnamed pads, if the pad already exists we fail when
1961 * trying to add it */
1962 if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
1963 pad_name = req_name;
1965 name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
1968 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
1969 context = (GstMatroskaTrackContext *)
1970 g_new0 (GstMatroskaTrackSubtitleContext, 1);
1971 context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
1972 context->name = g_strdup ("Subtitle");
1974 GST_WARNING_OBJECT (mux, "This is not our template!");
1978 newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
1979 "name", pad_name, "direction", templ->direction, "template", templ, NULL);
1982 gst_matroskamux_pad_init (newpad);
1983 collect_pad = (GstMatroskaPad *)
1984 gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad),
1985 sizeof (GstMatroskaPad),
1986 (GstCollectDataDestroyNotify) gst_matroska_pad_free);
1988 collect_pad->track = context;
1989 gst_matroska_pad_reset (collect_pad, FALSE);
1991 /* FIXME: hacked way to override/extend the event function of
1992 * GstCollectPads; because it sets its own event function giving the
1993 * element no access to events.
1994 * TODO GstCollectPads should really give its 'users' a clean chance to
1995 * properly handle events that are not meant for collectpads itself.
1996 * Perhaps a callback or so, though rejected (?) in #340060.
1997 * This would allow (clean) transcoding of info from demuxer/streams
1998 * to another muxer */
1999 mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
2000 gst_pad_set_event_function (GST_PAD (newpad),
2001 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event));
2003 collect_pad->capsfunc = capsfunc;
2004 gst_pad_set_active (GST_PAD (newpad), TRUE);
2005 if (!gst_element_add_pad (element, GST_PAD (newpad)))
2006 goto pad_add_failed;
2010 GST_DEBUG_OBJECT (newpad, "Added new request pad");
2012 return GST_PAD (newpad);
2017 GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
2018 gst_object_unref (newpad);
2024 * gst_matroska_mux_release_pad:
2025 * @element: #GstMatroskaMux.
2026 * @pad: Pad to release.
2028 * Release a previously requested pad.
2031 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
2033 GstMatroskaMux *mux;
2036 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2038 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
2039 GstCollectData *cdata = (GstCollectData *) walk->data;
2040 GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
2042 if (cdata->pad == pad) {
2043 GstClockTime min_dur; /* observed minimum duration */
2045 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2046 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2047 min_dur = GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2048 if (collect_pad->duration < min_dur)
2049 collect_pad->duration = min_dur;
2052 if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
2053 mux->duration < collect_pad->duration)
2054 mux->duration = collect_pad->duration;
2060 gst_collect_pads_remove_pad (mux->collect, pad);
2061 if (gst_element_remove_pad (element, pad))
2067 * gst_matroska_mux_track_header:
2068 * @mux: #GstMatroskaMux
2069 * @context: Tack context.
2071 * Write a track header.
2074 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2075 GstMatroskaTrackContext * context)
2077 GstEbmlWrite *ebml = mux->ebml_write;
2080 /* TODO: check if everything necessary is written and check default values */
2082 /* track type goes before the type-specific stuff */
2083 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2084 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2086 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID,
2087 gst_matroska_mux_create_uid ());
2088 if (context->default_duration) {
2089 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2090 context->default_duration);
2092 if (context->language) {
2093 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2097 /* type-specific stuff */
2098 switch (context->type) {
2099 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2100 GstMatroskaTrackVideoContext *videocontext =
2101 (GstMatroskaTrackVideoContext *) context;
2103 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2104 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2105 videocontext->pixel_width);
2106 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2107 videocontext->pixel_height);
2108 if (videocontext->display_width && videocontext->display_height) {
2109 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2110 videocontext->display_width);
2111 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2112 videocontext->display_height);
2114 if (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED)
2115 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2116 if (videocontext->fourcc) {
2117 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2119 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2120 (gpointer) & fcc_le, 4);
2122 gst_ebml_write_master_finish (ebml, master);
2127 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2128 GstMatroskaTrackAudioContext *audiocontext =
2129 (GstMatroskaTrackAudioContext *) context;
2131 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2132 if (audiocontext->samplerate != 8000)
2133 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2134 audiocontext->samplerate);
2135 if (audiocontext->channels != 1)
2136 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2137 audiocontext->channels);
2138 if (audiocontext->bitdepth) {
2139 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2140 audiocontext->bitdepth);
2142 gst_ebml_write_master_finish (ebml, master);
2148 /* doesn't need type-specific data */
2152 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2153 if (context->codec_priv)
2154 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2155 context->codec_priv, context->codec_priv_size);
2156 /* FIXME: until we have a nice way of getting the codecname
2157 * out of the caps, I'm not going to enable this. Too much
2158 * (useless, double, boring) work... */
2159 /* TODO: Use value from tags if any */
2160 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2161 context->codec_name); */
2162 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2167 * gst_matroska_mux_start:
2168 * @mux: #GstMatroskaMux
2170 * Start a new matroska file (write headers etc...)
2173 gst_matroska_mux_start (GstMatroskaMux * mux)
2175 GstEbmlWrite *ebml = mux->ebml_write;
2176 const gchar *doctype;
2177 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
2178 GST_MATROSKA_ID_TRACKS,
2179 GST_MATROSKA_ID_CUES,
2180 GST_MATROSKA_ID_TAGS,
2183 guint64 master, child;
2187 GstClockTime duration = 0;
2188 guint32 segment_uid[4];
2189 GTimeVal time = { 0, 0 };
2191 if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2192 ebml->caps = gst_caps_new_empty_simple ("video/webm");
2194 ebml->caps = gst_caps_new_empty_simple ("video/x-matroska");
2196 /* we start with a EBML header */
2197 doctype = mux->doctype;
2198 GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
2199 doctype, mux->doctype_version);
2200 gst_ebml_write_header (ebml, doctype, mux->doctype_version);
2202 /* the rest of the header is cached */
2203 gst_ebml_write_set_cache (ebml, 0x1000);
2205 /* start a segment */
2207 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
2208 mux->segment_master = ebml->pos;
2210 if (!mux->streamable) {
2211 /* seekhead (table of contents) - we set the positions later */
2212 mux->seekhead_pos = ebml->pos;
2213 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
2214 for (i = 0; seekhead_id[i] != 0; i++) {
2215 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
2216 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
2217 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
2218 gst_ebml_write_master_finish (ebml, child);
2220 gst_ebml_write_master_finish (ebml, master);
2223 if (mux->streamable) {
2224 const GstTagList *tags;
2227 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2229 if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2230 guint64 master_tags, master_tag;
2232 GST_DEBUG ("Writing tags");
2234 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2235 mux->tags_pos = ebml->pos;
2236 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2237 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2238 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2239 gst_ebml_write_master_finish (ebml, master_tag);
2240 gst_ebml_write_master_finish (ebml, master_tags);
2245 mux->info_pos = ebml->pos;
2246 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
2247 for (i = 0; i < 4; i++) {
2248 segment_uid[i] = g_random_int ();
2250 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
2251 (guint8 *) segment_uid, 16);
2252 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
2253 mux->duration_pos = ebml->pos;
2255 if (!mux->streamable) {
2256 for (collected = mux->collect->data; collected;
2257 collected = g_slist_next (collected)) {
2258 GstMatroskaPad *collect_pad;
2260 gint64 trackduration;
2262 collect_pad = (GstMatroskaPad *) collected->data;
2263 thepad = collect_pad->collect.pad;
2265 /* Query the total length of the track. */
2266 GST_DEBUG_OBJECT (thepad, "querying peer duration");
2267 if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
2268 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
2269 GST_TIME_ARGS (trackduration));
2270 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
2271 duration = (GstClockTime) trackduration;
2275 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2276 gst_guint64_to_gdouble (duration) /
2277 gst_guint64_to_gdouble (mux->time_scale));
2279 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
2280 "GStreamer plugin version " PACKAGE_VERSION);
2281 if (mux->writing_app && mux->writing_app[0]) {
2282 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
2284 g_get_current_time (&time);
2285 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
2286 gst_ebml_write_master_finish (ebml, master);
2289 mux->tracks_pos = ebml->pos;
2290 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
2292 for (collected = mux->collect->data; collected;
2293 collected = g_slist_next (collected)) {
2294 GstMatroskaPad *collect_pad;
2297 collect_pad = (GstMatroskaPad *) collected->data;
2298 thepad = collect_pad->collect.pad;
2300 if (gst_pad_is_linked (thepad) && gst_pad_is_active (thepad) &&
2301 collect_pad->track->codec_id != 0) {
2302 collect_pad->track->num = tracknum++;
2303 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
2304 gst_matroska_mux_track_header (mux, collect_pad->track);
2305 gst_ebml_write_master_finish (ebml, child);
2306 /* some remaing pad/track setup */
2307 collect_pad->default_duration_scaled =
2308 gst_util_uint64_scale (collect_pad->track->default_duration,
2309 1, mux->time_scale);
2312 gst_ebml_write_master_finish (ebml, master);
2314 /* lastly, flush the cache */
2315 gst_ebml_write_flush_cache (ebml, FALSE, 0);
2319 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
2322 /* TODO: more sensible tag mappings */
2325 const gchar *matroska_tagname;
2326 const gchar *gstreamer_tagname;
2330 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
2331 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
2332 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
2333 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
2334 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
2335 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
2336 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
2337 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
2338 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
2339 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
2340 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
2341 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
2342 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
2343 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
2344 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
2346 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
2348 guint64 simpletag_master;
2350 for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) {
2351 const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
2352 const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
2354 if (strcmp (tagname_gst, tag) == 0) {
2355 GValue src = { 0, };
2358 if (!gst_tag_list_copy_value (&src, list, tag))
2360 if ((dest = gst_value_serialize (&src))) {
2362 simpletag_master = gst_ebml_write_master_start (ebml,
2363 GST_MATROSKA_ID_SIMPLETAG);
2364 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
2365 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
2366 gst_ebml_write_master_finish (ebml, simpletag_master);
2369 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
2371 g_value_unset (&src);
2379 * gst_matroska_mux_finish:
2380 * @mux: #GstMatroskaMux
2382 * Finish a new matroska file (write index etc...)
2385 gst_matroska_mux_finish (GstMatroskaMux * mux)
2387 GstEbmlWrite *ebml = mux->ebml_write;
2389 guint64 duration = 0;
2391 const GstTagList *tags;
2393 /* finish last cluster */
2395 gst_ebml_write_master_finish (ebml, mux->cluster);
2399 if (mux->index != NULL) {
2401 guint64 master, pointentry_master, trackpos_master;
2403 mux->cues_pos = ebml->pos;
2404 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
2405 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
2407 for (n = 0; n < mux->num_indexes; n++) {
2408 GstMatroskaIndex *idx = &mux->index[n];
2410 pointentry_master = gst_ebml_write_master_start (ebml,
2411 GST_MATROSKA_ID_POINTENTRY);
2412 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
2413 idx->time / mux->time_scale);
2414 trackpos_master = gst_ebml_write_master_start (ebml,
2415 GST_MATROSKA_ID_CUETRACKPOSITIONS);
2416 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
2417 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
2418 idx->pos - mux->segment_master);
2419 gst_ebml_write_master_finish (ebml, trackpos_master);
2420 gst_ebml_write_master_finish (ebml, pointentry_master);
2423 gst_ebml_write_master_finish (ebml, master);
2424 gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
2428 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2430 if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2431 guint64 master_tags, master_tag;
2433 GST_DEBUG ("Writing tags");
2435 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2436 mux->tags_pos = ebml->pos;
2437 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2438 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2439 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2440 gst_ebml_write_master_finish (ebml, master_tag);
2441 gst_ebml_write_master_finish (ebml, master_tags);
2444 /* update seekhead. We know that:
2445 * - a seekhead contains 4 entries.
2446 * - order of entries is as above.
2447 * - a seekhead has a 4-byte header + 8-byte length
2448 * - each entry is 2-byte master, 2-byte ID pointer,
2449 * 2-byte length pointer, all 8/1-byte length, 4-
2450 * byte ID and 8-byte length pointer, where the
2451 * length pointer starts at 20.
2452 * - all entries are local to the segment (so pos - segment_master).
2453 * - so each entry is at 12 + 20 + num * 28. */
2454 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
2455 mux->info_pos - mux->segment_master);
2456 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
2457 mux->tracks_pos - mux->segment_master);
2458 if (mux->index != NULL) {
2459 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
2460 mux->cues_pos - mux->segment_master);
2463 guint64 my_pos = ebml->pos;
2465 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
2466 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2467 gst_ebml_write_seek (ebml, my_pos);
2470 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
2471 mux->tags_pos - mux->segment_master);
2474 guint64 my_pos = ebml->pos;
2476 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
2477 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2478 gst_ebml_write_seek (ebml, my_pos);
2481 /* update duration */
2482 /* first get the overall duration */
2483 /* a released track may have left a duration in here */
2484 duration = mux->duration;
2485 for (collected = mux->collect->data; collected;
2486 collected = g_slist_next (collected)) {
2487 GstMatroskaPad *collect_pad;
2488 GstClockTime min_duration; /* observed minimum duration */
2490 collect_pad = (GstMatroskaPad *) collected->data;
2492 GST_DEBUG_OBJECT (mux,
2493 "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
2494 " end ts %" GST_TIME_FORMAT, collect_pad,
2495 GST_TIME_ARGS (collect_pad->start_ts),
2496 GST_TIME_ARGS (collect_pad->end_ts));
2498 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2499 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2501 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2502 if (collect_pad->duration < min_duration)
2503 collect_pad->duration = min_duration;
2504 GST_DEBUG_OBJECT (collect_pad,
2505 "final track duration: %" GST_TIME_FORMAT,
2506 GST_TIME_ARGS (collect_pad->duration));
2509 if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
2510 duration < collect_pad->duration)
2511 duration = collect_pad->duration;
2513 if (duration != 0) {
2514 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
2515 GST_TIME_ARGS (duration));
2516 pos = mux->ebml_write->pos;
2517 gst_ebml_write_seek (ebml, mux->duration_pos);
2518 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2519 gst_guint64_to_gdouble (duration) /
2520 gst_guint64_to_gdouble (mux->time_scale));
2521 gst_ebml_write_seek (ebml, pos);
2524 guint64 my_pos = ebml->pos;
2526 gst_ebml_write_seek (ebml, mux->duration_pos);
2527 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
2528 gst_ebml_write_seek (ebml, my_pos);
2530 GST_DEBUG_OBJECT (mux, "finishing segment");
2531 /* finish segment - this also writes element length */
2532 gst_ebml_write_master_finish (ebml, mux->segment_pos);
2537 * gst_matroska_mux_best_pad:
2538 * @mux: #GstMatroskaMux
2539 * @popped: True if at least one buffer was popped from #GstCollectPads
2541 * Find a pad with the oldest data
2542 * (data from this pad should be written first).
2544 * Returns: Selected pad.
2546 static GstMatroskaPad *
2547 gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
2550 GstMatroskaPad *best = NULL;
2553 for (collected = mux->collect->data; collected;
2554 collected = g_slist_next (collected)) {
2555 GstMatroskaPad *collect_pad;
2557 collect_pad = (GstMatroskaPad *) collected->data;
2558 /* fetch a new buffer if needed */
2559 if (collect_pad->buffer == NULL) {
2560 collect_pad->buffer = gst_collect_pads_pop (mux->collect,
2561 (GstCollectData *) collect_pad);
2563 if (collect_pad->buffer != NULL) {
2567 /* convert to running time */
2568 time = GST_BUFFER_TIMESTAMP (collect_pad->buffer);
2569 /* invalid should pass */
2570 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
2571 time = gst_segment_to_running_time (&collect_pad->collect.segment,
2572 GST_FORMAT_TIME, time);
2573 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
2574 GST_DEBUG_OBJECT (mux, "clipping buffer on pad %s outside segment",
2575 GST_PAD_NAME (collect_pad->collect.pad));
2576 gst_buffer_unref (collect_pad->buffer);
2577 collect_pad->buffer = NULL;
2580 GST_LOG_OBJECT (mux, "buffer ts %" GST_TIME_FORMAT " -> %"
2581 GST_TIME_FORMAT " running time",
2582 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (collect_pad->buffer)),
2583 GST_TIME_ARGS (time));
2584 collect_pad->buffer =
2585 gst_buffer_make_writable (collect_pad->buffer);
2586 GST_BUFFER_TIMESTAMP (collect_pad->buffer) = time;
2592 /* if we have a buffer check if it is better then the current best one */
2593 if (collect_pad->buffer != NULL) {
2594 if (best == NULL || !GST_BUFFER_TIMESTAMP_IS_VALID (collect_pad->buffer)
2595 || (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)
2596 && GST_BUFFER_TIMESTAMP (collect_pad->buffer) <
2597 GST_BUFFER_TIMESTAMP (best->buffer))) {
2607 * gst_matroska_mux_buffer_header:
2608 * @track: Track context.
2609 * @relative_timestamp: relative timestamp of the buffer
2610 * @flags: Buffer flags.
2612 * Create a buffer containing buffer header.
2614 * Returns: New buffer.
2617 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
2618 gint16 relative_timestamp, int flags)
2621 guint8 *data = g_malloc (4);
2623 hdr = gst_buffer_new_wrapped (data, 4);
2624 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
2625 data[0] = track->num | 0x80;
2626 /* time relative to clustertime */
2627 GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
2635 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
2636 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
2637 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
2640 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
2641 GstMatroskaPad * collect_pad, GstBuffer * buf)
2643 GstMatroskaTrackVideoContext *ctx =
2644 (GstMatroskaTrackVideoContext *) collect_pad->track;
2645 guint8 *buf_data, *data;
2648 guint32 next_parse_offset;
2649 GstBuffer *ret = NULL;
2650 gboolean is_muxing_unit = FALSE;
2652 buf_data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
2656 gst_buffer_unmap (buf, buf_data, -1);
2657 gst_buffer_unref (buf);
2661 /* Check if this buffer contains a picture or end-of-sequence packet */
2662 while (size >= 13) {
2663 if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
2664 gst_buffer_unmap (buf, buf_data, -1);
2665 gst_buffer_unref (buf);
2669 parse_code = GST_READ_UINT8 (data + 4);
2670 if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
2671 if (ctx->dirac_unit) {
2672 gst_buffer_unref (ctx->dirac_unit);
2673 ctx->dirac_unit = NULL;
2675 } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
2676 parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
2677 is_muxing_unit = TRUE;
2681 next_parse_offset = GST_READ_UINT32_BE (data + 5);
2683 if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
2686 data += next_parse_offset;
2687 size -= next_parse_offset;
2690 if (ctx->dirac_unit)
2691 ctx->dirac_unit = gst_buffer_join (ctx->dirac_unit, gst_buffer_ref (buf));
2693 ctx->dirac_unit = gst_buffer_ref (buf);
2695 gst_buffer_unmap (buf, buf_data, -1);
2697 if (is_muxing_unit) {
2698 ret = gst_buffer_make_writable (ctx->dirac_unit);
2699 ctx->dirac_unit = NULL;
2700 gst_buffer_copy_into (ret, buf,
2701 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2702 gst_buffer_unref (buf);
2704 gst_buffer_unref (buf);
2712 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
2716 GValue streamheader = { 0 };
2717 GValue bufval = { 0 };
2718 GstBuffer *streamheader_buffer;
2719 GstEbmlWrite *ebml = mux->ebml_write;
2721 streamheader_buffer = gst_ebml_stop_streamheader (ebml);
2722 if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2723 caps = gst_caps_new_empty_simple ("video/webm");
2725 caps = gst_caps_new_empty_simple ("video/x-matroska");
2727 s = gst_caps_get_structure (caps, 0);
2728 g_value_init (&streamheader, GST_TYPE_ARRAY);
2729 g_value_init (&bufval, GST_TYPE_BUFFER);
2730 GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_IN_CAPS);
2731 gst_value_set_buffer (&bufval, streamheader_buffer);
2732 gst_value_array_append_value (&streamheader, &bufval);
2733 g_value_unset (&bufval);
2734 gst_structure_set_value (s, "streamheader", &streamheader);
2735 g_value_unset (&streamheader);
2736 gst_caps_replace (&ebml->caps, caps);
2737 gst_buffer_unref (streamheader_buffer);
2738 gst_caps_unref (caps);
2742 * gst_matroska_mux_write_data:
2743 * @mux: #GstMatroskaMux
2744 * @collect_pad: #GstMatroskaPad with the data
2746 * Write collected data (called from gst_matroska_mux_collected).
2748 * Returns: Result of the gst_pad_push issued to write the data.
2750 static GstFlowReturn
2751 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
2753 GstEbmlWrite *ebml = mux->ebml_write;
2754 GstBuffer *buf, *hdr;
2756 gboolean write_duration;
2757 gint16 relative_timestamp;
2758 gint64 relative_timestamp64;
2759 guint64 block_duration;
2760 gboolean is_video_keyframe = FALSE;
2761 GstMatroskamuxPad *pad;
2764 buf = collect_pad->buffer;
2765 collect_pad->buffer = NULL;
2766 pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
2768 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
2769 if (collect_pad->track->xiph_headers_to_skip > 0) {
2770 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
2771 gst_buffer_unref (buf);
2772 --collect_pad->track->xiph_headers_to_skip;
2776 /* for dirac we have to queue up everything up to a picture unit */
2777 if (collect_pad->track->codec_id != NULL &&
2778 strcmp (collect_pad->track->codec_id,
2779 GST_MATROSKA_CODEC_ID_VIDEO_DIRAC) == 0) {
2780 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
2785 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
2786 * this would wreak havoc with time stored in matroska file */
2787 /* TODO: maybe calculate a timestamp by using the previous timestamp
2788 * and default duration */
2789 if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2790 GST_WARNING_OBJECT (collect_pad->collect.pad,
2791 "Invalid buffer timestamp; dropping buffer");
2792 gst_buffer_unref (buf);
2796 /* set the timestamp for outgoing buffers */
2797 ebml->timestamp = GST_BUFFER_TIMESTAMP (buf);
2799 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
2800 !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
2801 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
2802 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2803 is_video_keyframe = TRUE;
2807 /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
2808 * or when we may be reaching the limit of the relative timestamp */
2809 if (mux->cluster_time +
2810 mux->max_cluster_duration < GST_BUFFER_TIMESTAMP (buf)
2811 || is_video_keyframe || mux->force_key_unit_event) {
2812 if (!mux->streamable)
2813 gst_ebml_write_master_finish (ebml, mux->cluster);
2815 /* Forward the GstForceKeyUnit event after finishing the cluster */
2816 if (mux->force_key_unit_event) {
2817 gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
2818 mux->force_key_unit_event = NULL;
2821 mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
2822 mux->cluster_pos = ebml->pos;
2823 gst_ebml_write_set_cache (ebml, 0x20);
2825 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2826 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2827 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2829 GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
2830 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2832 gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2833 mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2834 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
2835 mux->prev_cluster_size);
2840 mux->cluster_pos = ebml->pos;
2841 gst_ebml_write_set_cache (ebml, 0x20);
2842 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2843 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2844 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1, mux->time_scale));
2845 gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2846 mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2849 /* update duration of this track */
2850 if (GST_BUFFER_DURATION_IS_VALID (buf))
2851 collect_pad->duration += GST_BUFFER_DURATION (buf);
2853 /* We currently write index entries for all video tracks or for the audio
2854 * track in a single-track audio file. This could be improved by keeping the
2855 * index only for the *first* video track. */
2857 /* TODO: index is useful for every track, should contain the number of
2858 * the block in the cluster which contains the timestamp, should also work
2859 * for files with multiple audio tracks.
2861 if (!mux->streamable &&
2862 (is_video_keyframe ||
2863 ((collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
2864 (mux->num_streams == 1)))) {
2867 if (mux->min_index_interval != 0) {
2868 for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
2869 if (mux->index[last_idx].track == collect_pad->track->num)
2874 if (last_idx < 0 || mux->min_index_interval == 0 ||
2875 (GST_CLOCK_DIFF (mux->index[last_idx].time, GST_BUFFER_TIMESTAMP (buf))
2876 >= mux->min_index_interval)) {
2877 GstMatroskaIndex *idx;
2879 if (mux->num_indexes % 32 == 0) {
2880 mux->index = g_renew (GstMatroskaIndex, mux->index,
2881 mux->num_indexes + 32);
2883 idx = &mux->index[mux->num_indexes++];
2885 idx->pos = mux->cluster_pos;
2886 idx->time = GST_BUFFER_TIMESTAMP (buf);
2887 idx->track = collect_pad->track->num;
2891 /* Check if the duration differs from the default duration. */
2892 write_duration = FALSE;
2894 if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
2895 block_duration = gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
2896 1, mux->time_scale);
2898 /* small difference should be ok. */
2899 if (block_duration > collect_pad->default_duration_scaled + 1 ||
2900 block_duration < collect_pad->default_duration_scaled - 1) {
2901 write_duration = TRUE;
2905 /* write the block, for doctype v2 use SimpleBlock if possible
2906 * one slice (*breath*).
2907 * FIXME: Need to do correct lacing! */
2908 relative_timestamp64 = GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time;
2909 if (relative_timestamp64 >= 0) {
2910 /* round the timestamp */
2911 relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
2913 /* round the timestamp */
2914 relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
2916 relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
2918 if (mux->doctype_version > 1 && !write_duration) {
2920 GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : 0x80;
2923 gst_matroska_mux_create_buffer_header (collect_pad->track,
2924 relative_timestamp, flags);
2925 gst_ebml_write_set_cache (ebml, 0x40);
2926 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
2927 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
2928 gst_ebml_write_buffer (ebml, hdr);
2929 gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
2930 gst_ebml_write_buffer (ebml, buf);
2932 return gst_ebml_last_write_result (ebml);
2934 gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
2935 /* write and call order slightly unnatural,
2936 * but avoids seek and minizes pushing */
2937 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
2939 gst_matroska_mux_create_buffer_header (collect_pad->track,
2940 relative_timestamp, 0);
2942 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
2943 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
2944 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
2945 gst_ebml_write_buffer (ebml, hdr);
2946 gst_ebml_write_master_finish_full (ebml, blockgroup,
2947 gst_buffer_get_size (buf));
2948 gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
2949 gst_ebml_write_buffer (ebml, buf);
2951 return gst_ebml_last_write_result (ebml);
2957 * gst_matroska_mux_collected:
2958 * @pads: #GstCollectPads
2959 * @uuser_data: #GstMatroskaMux
2961 * Collectpads callback.
2963 * Returns: #GstFlowReturn
2965 static GstFlowReturn
2966 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
2968 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
2969 GstEbmlWrite *ebml = mux->ebml_write;
2970 GstMatroskaPad *best;
2972 GstFlowReturn ret = GST_FLOW_OK;
2974 GST_DEBUG_OBJECT (mux, "Collected pads");
2976 /* start with a header */
2977 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
2978 if (mux->collect->data == NULL) {
2979 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2980 ("No input streams configured"));
2981 return GST_FLOW_ERROR;
2983 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
2984 gst_ebml_start_streamheader (ebml);
2985 gst_matroska_mux_start (mux);
2986 gst_matroska_mux_stop_streamheader (mux);
2987 mux->state = GST_MATROSKA_MUX_STATE_DATA;
2991 /* which stream to write from? */
2992 best = gst_matroska_mux_best_pad (mux, &popped);
2994 /* if there is no best pad, we have reached EOS */
2996 /* buffer popped, but none returned means it was clipped */
2999 GST_DEBUG_OBJECT (mux, "No best pad finishing...");
3000 if (!mux->streamable) {
3001 gst_matroska_mux_finish (mux);
3003 GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
3005 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
3006 ret = GST_FLOW_UNEXPECTED;
3009 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
3010 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
3011 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (best->buffer)),
3012 GST_TIME_ARGS (GST_BUFFER_DURATION (best->buffer)));
3014 /* make note of first and last encountered timestamps, so we can calculate
3015 * the actual duration later when we send an updated header on eos */
3016 if (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)) {
3017 GstClockTime start_ts = GST_BUFFER_TIMESTAMP (best->buffer);
3018 GstClockTime end_ts = start_ts;
3020 if (GST_BUFFER_DURATION_IS_VALID (best->buffer))
3021 end_ts += GST_BUFFER_DURATION (best->buffer);
3022 else if (best->track->default_duration)
3023 end_ts += best->track->default_duration;
3025 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
3026 best->end_ts = end_ts;
3028 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
3029 start_ts < best->start_ts))
3030 best->start_ts = start_ts;
3033 /* write one buffer */
3034 ret = gst_matroska_mux_write_data (mux, best);
3035 } while (ret == GST_FLOW_OK && !popped);
3042 * gst_matroska_mux_change_state:
3043 * @element: #GstMatroskaMux
3044 * @transition: State change transition.
3046 * Change the muxer state.
3048 * Returns: #GstStateChangeReturn
3050 static GstStateChangeReturn
3051 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
3053 GstStateChangeReturn ret;
3054 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
3056 switch (transition) {
3057 case GST_STATE_CHANGE_NULL_TO_READY:
3059 case GST_STATE_CHANGE_READY_TO_PAUSED:
3060 gst_collect_pads_start (mux->collect);
3062 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
3064 case GST_STATE_CHANGE_PAUSED_TO_READY:
3065 gst_collect_pads_stop (mux->collect);
3071 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3073 switch (transition) {
3074 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3076 case GST_STATE_CHANGE_PAUSED_TO_READY:
3077 gst_matroska_mux_reset (GST_ELEMENT (mux));
3079 case GST_STATE_CHANGE_READY_TO_NULL:
3089 gst_matroska_mux_set_property (GObject * object,
3090 guint prop_id, const GValue * value, GParamSpec * pspec)
3092 GstMatroskaMux *mux;
3094 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
3095 mux = GST_MATROSKA_MUX (object);
3098 case ARG_WRITING_APP:
3099 if (!g_value_get_string (value)) {
3100 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
3103 g_free (mux->writing_app);
3104 mux->writing_app = g_value_dup_string (value);
3106 case ARG_DOCTYPE_VERSION:
3107 mux->doctype_version = g_value_get_int (value);
3109 case ARG_MIN_INDEX_INTERVAL:
3110 mux->min_index_interval = g_value_get_int64 (value);
3112 case ARG_STREAMABLE:
3113 mux->streamable = g_value_get_boolean (value);
3116 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3122 gst_matroska_mux_get_property (GObject * object,
3123 guint prop_id, GValue * value, GParamSpec * pspec)
3125 GstMatroskaMux *mux;
3127 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
3128 mux = GST_MATROSKA_MUX (object);
3131 case ARG_WRITING_APP:
3132 g_value_set_string (value, mux->writing_app);
3134 case ARG_DOCTYPE_VERSION:
3135 g_value_set_int (value, mux->doctype_version);
3137 case ARG_MIN_INDEX_INTERVAL:
3138 g_value_set_int64 (value, mux->min_index_interval);
3140 case ARG_STREAMABLE:
3141 g_value_set_boolean (value, mux->streamable);
3144 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);