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/riff/riff-media.h>
53 #include <gst/tag/tag.h>
55 #include "matroska-mux.h"
56 #include "matroska-ids.h"
58 GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
59 #define GST_CAT_DEFAULT matroskamux_debug
66 ARG_MIN_INDEX_INTERVAL,
70 #define DEFAULT_DOCTYPE_VERSION 2
71 #define DEFAULT_WRITING_APP "GStreamer Matroska muxer"
72 #define DEFAULT_MIN_INDEX_INTERVAL 0
73 #define DEFAULT_STREAMABLE FALSE
75 /* WAVEFORMATEX is gst_riff_strf_auds + an extra guint16 extension size */
76 #define WAVEFORMATEX_SIZE (2 + sizeof (gst_riff_strf_auds))
78 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
81 GST_STATIC_CAPS ("video/x-matroska")
84 #define COMMON_VIDEO_CAPS \
85 "width = (int) [ 16, 4096 ], " \
86 "height = (int) [ 16, 4096 ], " \
87 "framerate = (fraction) [ 0, MAX ]"
89 #define COMMON_VIDEO_CAPS_NO_FRAMERATE \
90 "width = (int) [ 16, 4096 ], " \
91 "height = (int) [ 16, 4096 ] "
94 * * require codec data, etc as needed
97 static GstStaticPadTemplate videosink_templ =
98 GST_STATIC_PAD_TEMPLATE ("video_%d",
101 GST_STATIC_CAPS ("video/mpeg, "
102 "mpegversion = (int) { 1, 2, 4 }, "
103 "systemstream = (boolean) false, "
104 COMMON_VIDEO_CAPS "; "
105 "video/x-h264, stream-format=avc, alignment=au, "
106 COMMON_VIDEO_CAPS "; "
108 COMMON_VIDEO_CAPS "; "
110 COMMON_VIDEO_CAPS "; "
112 COMMON_VIDEO_CAPS "; "
114 COMMON_VIDEO_CAPS "; "
116 COMMON_VIDEO_CAPS "; "
118 COMMON_VIDEO_CAPS "; "
120 COMMON_VIDEO_CAPS_NO_FRAMERATE "; "
123 COMMON_VIDEO_CAPS "; "
124 "video/x-pn-realvideo, "
125 "rmversion = (int) [1, 4], "
126 COMMON_VIDEO_CAPS "; "
128 COMMON_VIDEO_CAPS "; "
130 "format = (fourcc) { YUY2, I420, YV12, UYVY, AYUV }, "
131 COMMON_VIDEO_CAPS "; "
132 "video/x-wmv, " "wmvversion = (int) [ 1, 3 ], " COMMON_VIDEO_CAPS)
135 #define COMMON_AUDIO_CAPS \
136 "channels = (int) [ 1, MAX ], " \
137 "rate = (int) [ 1, MAX ]"
140 * * require codec data, etc as needed
142 static GstStaticPadTemplate audiosink_templ =
143 GST_STATIC_PAD_TEMPLATE ("audio_%d",
146 GST_STATIC_CAPS ("audio/mpeg, "
147 "mpegversion = (int) 1, "
148 "layer = (int) [ 1, 3 ], "
149 COMMON_AUDIO_CAPS "; "
151 "mpegversion = (int) { 2, 4 }, "
152 "stream-format = (string) raw, "
153 COMMON_AUDIO_CAPS "; "
155 COMMON_AUDIO_CAPS "; "
157 COMMON_AUDIO_CAPS "; "
159 COMMON_AUDIO_CAPS "; "
161 COMMON_AUDIO_CAPS "; "
163 COMMON_AUDIO_CAPS "; "
165 COMMON_AUDIO_CAPS "; "
169 "signed = (boolean) false, "
170 COMMON_AUDIO_CAPS ";"
174 "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
175 "signed = (boolean) true, "
176 COMMON_AUDIO_CAPS ";"
180 "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
181 "signed = (boolean) true, "
182 COMMON_AUDIO_CAPS ";"
186 "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
187 "signed = (boolean) true, "
188 COMMON_AUDIO_CAPS ";"
189 "audio/x-raw-float, "
190 "width = (int) [ 32, 64 ], "
191 "endianness = (int) LITTLE_ENDIAN, "
192 COMMON_AUDIO_CAPS ";"
194 "width = (int) { 8, 16, 24 }, "
195 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
196 "audio/x-pn-realaudio, "
197 "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS "; "
198 "audio/x-wma, " "wmaversion = (int) [ 1, 3 ], "
199 "block_align = (int) [ 0, 65535 ], bitrate = (int) [ 0, 524288 ], "
200 COMMON_AUDIO_CAPS ";"
202 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
204 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]")
207 static GstStaticPadTemplate subtitlesink_templ =
208 GST_STATIC_PAD_TEMPLATE ("subtitle_%d",
211 GST_STATIC_CAPS ("subtitle/x-kate"));
213 static GArray *used_uids;
214 G_LOCK_DEFINE_STATIC (used_uids);
216 static void gst_matroska_mux_add_interfaces (GType type);
218 GST_BOILERPLATE_FULL (GstMatroskaMux, gst_matroska_mux, GstElement,
219 GST_TYPE_ELEMENT, gst_matroska_mux_add_interfaces);
221 /* Matroska muxer destructor */
222 static void gst_matroska_mux_finalize (GObject * object);
224 /* Pads collected callback */
226 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data);
229 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
231 static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
232 GstPadTemplate * templ, const gchar * name);
233 static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
235 /* gst internal change state handler */
236 static GstStateChangeReturn
237 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
239 /* gobject bla bla */
240 static void gst_matroska_mux_set_property (GObject * object,
241 guint prop_id, const GValue * value, GParamSpec * pspec);
242 static void gst_matroska_mux_get_property (GObject * object,
243 guint prop_id, GValue * value, GParamSpec * pspec);
246 static void gst_matroska_mux_reset (GstElement * element);
249 static guint64 gst_matroska_mux_create_uid ();
251 static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
252 GstMatroskaTrackContext * context);
253 static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
254 GstMatroskaTrackContext * context);
255 static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
256 GstMatroskaTrackContext * context);
257 static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
258 GstMatroskaTrackContext * context);
259 static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
260 GstMatroskaTrackContext * context);
262 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
266 gst_matroska_mux_add_interfaces (GType type)
268 static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
270 g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
274 gst_matroska_mux_base_init (gpointer g_class)
279 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
281 GObjectClass *gobject_class;
282 GstElementClass *gstelement_class;
284 gobject_class = (GObjectClass *) klass;
285 gstelement_class = (GstElementClass *) klass;
287 gst_element_class_add_static_pad_template (gstelement_class,
289 gst_element_class_add_static_pad_template (gstelement_class,
291 gst_element_class_add_static_pad_template (gstelement_class,
292 &subtitlesink_templ);
293 gst_element_class_add_static_pad_template (gstelement_class, &src_templ);
294 gst_element_class_set_details_simple (gstelement_class, "Matroska muxer",
296 "Muxes video/audio/subtitle streams into a matroska stream",
297 "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
299 GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
302 gobject_class->finalize = gst_matroska_mux_finalize;
304 gobject_class->get_property = gst_matroska_mux_get_property;
305 gobject_class->set_property = gst_matroska_mux_set_property;
307 g_object_class_install_property (gobject_class, ARG_WRITING_APP,
308 g_param_spec_string ("writing-app", "Writing application.",
309 "The name the application that creates the matroska file.",
310 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
311 g_object_class_install_property (gobject_class, ARG_DOCTYPE_VERSION,
312 g_param_spec_int ("version", "DocType version",
313 "This parameter determines what Matroska features can be used.",
314 1, 2, DEFAULT_DOCTYPE_VERSION,
315 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
316 g_object_class_install_property (gobject_class, ARG_MIN_INDEX_INTERVAL,
317 g_param_spec_int64 ("min-index-interval", "Minimum time between index "
318 "entries", "An index entry is created every so many nanoseconds.",
319 0, G_MAXINT64, DEFAULT_MIN_INDEX_INTERVAL,
320 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
321 g_object_class_install_property (gobject_class, ARG_STREAMABLE,
322 g_param_spec_boolean ("streamable", "Determines whether output should "
323 "be streamable", "If set to true, the output should be as if it is "
324 "to be streamed and hence no indexes written or duration written.",
326 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_STATIC_STRINGS));
328 gstelement_class->change_state =
329 GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
330 gstelement_class->request_new_pad =
331 GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
332 gstelement_class->release_pad =
333 GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
337 * Start of pad option handler code
339 #define DEFAULT_PAD_FRAME_DURATION TRUE
340 #define DEFAULT_PAD_FRAME_DURATION_VP8 FALSE
345 PROP_PAD_FRAME_DURATION
351 gboolean frame_duration;
352 gboolean frame_duration_user;
355 static void gst_matroskamux_pad_class_init (GstPadClass * klass);
358 gst_matroskamux_pad_get_type (void)
360 static GType type = 0;
362 if (G_UNLIKELY (type == 0)) {
363 type = g_type_register_static_simple (GST_TYPE_PAD,
364 g_intern_static_string ("GstMatroskamuxPad"), sizeof (GstPadClass),
365 (GClassInitFunc) gst_matroskamux_pad_class_init,
366 sizeof (GstMatroskamuxPad), NULL, 0);
371 #define GST_TYPE_MATROSKAMUX_PAD (gst_matroskamux_pad_get_type())
372 #define GST_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_MATROSKAMUX_PAD,GstMatroskamuxPad))
373 #define GST_MATROSKAMUX_PAD_CAST(pad) ((GstMatroskamuxPad *) pad)
374 #define GST_IS_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_MATROSKAMUX_PAD))
377 gst_matroskamux_pad_get_property (GObject * object, guint prop_id,
378 GValue * value, GParamSpec * pspec)
380 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
383 case PROP_PAD_FRAME_DURATION:
384 g_value_set_boolean (value, pad->frame_duration);
387 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
393 gst_matroskamux_pad_set_property (GObject * object, guint prop_id,
394 const GValue * value, GParamSpec * pspec)
396 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
399 case PROP_PAD_FRAME_DURATION:
400 pad->frame_duration = g_value_get_boolean (value);
401 pad->frame_duration_user = TRUE;
404 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
410 gst_matroskamux_pad_class_init (GstPadClass * klass)
412 GObjectClass *gobject_class = (GObjectClass *) klass;
414 gobject_class->set_property = gst_matroskamux_pad_set_property;
415 gobject_class->get_property = gst_matroskamux_pad_get_property;
417 g_object_class_install_property (gobject_class, PROP_PAD_FRAME_DURATION,
418 g_param_spec_boolean ("frame-duration", "Frame duration",
419 "Default frame duration", DEFAULT_PAD_FRAME_DURATION,
420 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
424 gst_matroskamux_pad_init (GstMatroskamuxPad * pad)
426 pad->frame_duration = DEFAULT_PAD_FRAME_DURATION;
427 pad->frame_duration_user = FALSE;
431 * End of pad option handler code
435 * gst_matroska_mux_init:
436 * @mux: #GstMatroskaMux that should be initialized.
437 * @g_class: Class of the muxer.
439 * Matroska muxer constructor.
442 gst_matroska_mux_init (GstMatroskaMux * mux, GstMatroskaMuxClass * g_class)
444 GstPadTemplate *templ;
447 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
448 mux->srcpad = gst_pad_new_from_template (templ, "src");
450 gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
451 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
453 mux->collect = gst_collect_pads_new ();
454 gst_collect_pads_set_function (mux->collect,
455 (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_matroska_mux_collected),
458 mux->ebml_write = gst_ebml_write_new (mux->srcpad);
459 mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
461 /* property defaults */
462 mux->doctype_version = DEFAULT_DOCTYPE_VERSION;
463 mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
464 mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
465 mux->streamable = DEFAULT_STREAMABLE;
467 /* initialize internal variables */
469 mux->num_streams = 0;
470 mux->num_a_streams = 0;
471 mux->num_t_streams = 0;
472 mux->num_v_streams = 0;
474 /* initialize remaining variables */
475 gst_matroska_mux_reset (GST_ELEMENT (mux));
480 * gst_matroska_mux_finalize:
481 * @object: #GstMatroskaMux that should be finalized.
483 * Finalize matroska muxer.
486 gst_matroska_mux_finalize (GObject * object)
488 GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
490 gst_event_replace (&mux->force_key_unit_event, NULL);
492 gst_object_unref (mux->collect);
493 gst_object_unref (mux->ebml_write);
494 if (mux->writing_app)
495 g_free (mux->writing_app);
497 G_OBJECT_CLASS (parent_class)->finalize (object);
502 * gst_matroska_mux_create_uid:
504 * Generate new unused track UID.
506 * Returns: New track UID.
509 gst_matroska_mux_create_uid (void)
516 used_uids = g_array_sized_new (FALSE, FALSE, sizeof (guint64), 10);
521 uid = (((guint64) g_random_int ()) << 32) | g_random_int ();
522 for (i = 0; i < used_uids->len; i++) {
523 if (g_array_index (used_uids, guint64, i) == uid) {
528 g_array_append_val (used_uids, uid);
531 G_UNLOCK (used_uids);
537 * gst_matroska_pad_reset:
538 * @collect_pad: the #GstMatroskaPad
540 * Reset and/or release resources of a matroska collect pad.
543 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
546 GstMatroskaTrackType type = 0;
548 /* free track information */
549 if (collect_pad->track != NULL) {
550 /* retrieve for optional later use */
551 name = collect_pad->track->name;
552 type = collect_pad->track->type;
553 /* extra for video */
554 if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
555 GstMatroskaTrackVideoContext *ctx =
556 (GstMatroskaTrackVideoContext *) collect_pad->track;
558 if (ctx->dirac_unit) {
559 gst_buffer_unref (ctx->dirac_unit);
560 ctx->dirac_unit = NULL;
563 g_free (collect_pad->track->codec_id);
564 g_free (collect_pad->track->codec_name);
566 g_free (collect_pad->track->name);
567 g_free (collect_pad->track->language);
568 g_free (collect_pad->track->codec_priv);
569 g_free (collect_pad->track);
570 collect_pad->track = NULL;
573 /* free cached buffer */
574 if (collect_pad->buffer != NULL) {
575 gst_buffer_unref (collect_pad->buffer);
576 collect_pad->buffer = NULL;
579 if (!full && type != 0) {
580 GstMatroskaTrackContext *context;
582 /* create a fresh context */
584 case GST_MATROSKA_TRACK_TYPE_VIDEO:
585 context = (GstMatroskaTrackContext *)
586 g_new0 (GstMatroskaTrackVideoContext, 1);
588 case GST_MATROSKA_TRACK_TYPE_AUDIO:
589 context = (GstMatroskaTrackContext *)
590 g_new0 (GstMatroskaTrackAudioContext, 1);
592 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
593 context = (GstMatroskaTrackContext *)
594 g_new0 (GstMatroskaTrackSubtitleContext, 1);
597 g_assert_not_reached ();
601 context->type = type;
602 context->name = name;
603 /* TODO: check default values for the context */
604 context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
605 collect_pad->track = context;
606 collect_pad->buffer = NULL;
607 collect_pad->duration = 0;
608 collect_pad->start_ts = GST_CLOCK_TIME_NONE;
609 collect_pad->end_ts = GST_CLOCK_TIME_NONE;
614 * gst_matroska_pad_free:
615 * @collect_pad: the #GstMatroskaPad
617 * Release resources of a matroska collect pad.
620 gst_matroska_pad_free (GstMatroskaPad * collect_pad)
622 gst_matroska_pad_reset (collect_pad, TRUE);
627 * gst_matroska_mux_reset:
628 * @element: #GstMatroskaMux that should be reseted.
630 * Reset matroska muxer back to initial state.
633 gst_matroska_mux_reset (GstElement * element)
635 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
638 /* reset EBML write */
639 gst_ebml_write_reset (mux->ebml_write);
642 mux->state = GST_MATROSKA_MUX_STATE_START;
644 /* clean up existing streams */
646 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
647 GstMatroskaPad *collect_pad;
649 collect_pad = (GstMatroskaPad *) walk->data;
651 /* reset collect pad to pristine state */
652 gst_matroska_pad_reset (collect_pad, FALSE);
656 mux->num_indexes = 0;
661 mux->time_scale = GST_MSECOND;
662 mux->max_cluster_duration = G_MAXINT16 * mux->time_scale;
667 mux->cluster_time = 0;
668 mux->cluster_pos = 0;
669 mux->prev_cluster_size = 0;
672 gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
676 * gst_matroska_mux_handle_src_event:
677 * @pad: Pad which received the event.
678 * @event: Received event.
680 * handle events - copied from oggmux without understanding
682 * Returns: #TRUE on success.
685 gst_matroska_mux_handle_src_event (GstPad * pad, GstEvent * event)
689 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
693 /* disable seeking for now */
699 return gst_pad_event_default (pad, event);
703 * gst_matroska_mux_handle_sink_event:
704 * @pad: Pad which received the event.
705 * @event: Received event.
707 * handle events - informational ones like tags
709 * Returns: #TRUE on success.
712 gst_matroska_mux_handle_sink_event (GstPad * pad, GstEvent * event)
714 GstMatroskaTrackContext *context;
715 GstMatroskaPad *collect_pad;
720 mux = GST_MATROSKA_MUX (gst_pad_get_parent (pad));
722 switch (GST_EVENT_TYPE (event)) {
726 GST_DEBUG_OBJECT (mux, "received tag event");
727 gst_event_parse_tag (event, &list);
729 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
730 g_assert (collect_pad);
731 context = collect_pad->track;
734 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
735 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
736 const gchar *lang_code;
738 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
740 GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
741 context->language = g_strdup (lang_code);
743 GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
748 /* FIXME: what about stream-specific tags? */
749 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
750 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
752 gst_event_unref (event);
753 /* handled this, don't want collectpads to forward it downstream */
757 case GST_EVENT_NEWSEGMENT:{
760 gst_event_parse_new_segment (event, NULL, NULL, &format, NULL, NULL,
762 if (format != GST_FORMAT_TIME) {
764 gst_event_unref (event);
769 case GST_EVENT_CUSTOM_DOWNSTREAM:{
770 const GstStructure *structure;
772 structure = gst_event_get_structure (event);
773 if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
774 gst_event_replace (&mux->force_key_unit_event, NULL);
775 mux->force_key_unit_event = event;
784 /* now GstCollectPads can take care of the rest, e.g. EOS */
786 ret = mux->collect_event (pad, event);
788 gst_object_unref (mux);
795 * gst_matroska_mux_video_pad_setcaps:
796 * @pad: Pad which got the caps.
799 * Setcaps function for video sink pad.
801 * Returns: #TRUE on success.
804 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
806 GstMatroskaTrackContext *context = NULL;
807 GstMatroskaTrackVideoContext *videocontext;
809 GstMatroskaPad *collect_pad;
810 GstStructure *structure;
811 const gchar *mimetype;
812 const GValue *value = NULL;
813 const GstBuffer *codec_buf = NULL;
814 gint width, height, pixel_width, pixel_height;
816 gboolean interlaced = FALSE;
818 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
821 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
822 g_assert (collect_pad);
823 context = collect_pad->track;
825 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
826 videocontext = (GstMatroskaTrackVideoContext *) context;
828 /* gst -> matroska ID'ing */
829 structure = gst_caps_get_structure (caps, 0);
831 mimetype = gst_structure_get_name (structure);
833 if (gst_structure_get_boolean (structure, "interlaced", &interlaced)
835 context->flags |= GST_MATROSKA_VIDEOTRACK_INTERLACED;
837 if (!strcmp (mimetype, "video/x-theora")) {
838 /* we'll extract the details later from the theora identification header */
842 /* get general properties */
843 /* spec says it is mandatory */
844 if (!gst_structure_get_int (structure, "width", &width) ||
845 !gst_structure_get_int (structure, "height", &height))
848 videocontext->pixel_width = width;
849 videocontext->pixel_height = height;
851 /* set vp8 defaults or let user override it */
852 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration_user == FALSE
853 && (!strcmp (mimetype, "video/x-vp8")))
854 GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration =
855 DEFAULT_PAD_FRAME_DURATION_VP8;
857 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
858 && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
860 context->default_duration =
861 gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
862 GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
863 GST_TIME_ARGS (context->default_duration));
865 context->default_duration = 0;
867 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
868 &pixel_width, &pixel_height)) {
869 if (pixel_width > pixel_height) {
870 videocontext->display_width = width * pixel_width / pixel_height;
871 videocontext->display_height = height;
872 } else if (pixel_width < pixel_height) {
873 videocontext->display_width = width;
874 videocontext->display_height = height * pixel_height / pixel_width;
876 videocontext->display_width = 0;
877 videocontext->display_height = 0;
880 videocontext->display_width = 0;
881 videocontext->display_height = 0;
886 videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
887 videocontext->fourcc = 0;
889 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
890 * data and other settings
894 /* extract codec_data, may turn out needed */
895 value = gst_structure_get_value (structure, "codec_data");
897 codec_buf = gst_value_get_buffer (value);
900 if (!strcmp (mimetype, "video/x-raw-yuv")) {
901 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
902 gst_structure_get_fourcc (structure, "format", &videocontext->fourcc);
903 } else if (!strcmp (mimetype, "video/x-xvid") /* MS/VfW compatibility cases */
904 ||!strcmp (mimetype, "video/x-huffyuv")
905 || !strcmp (mimetype, "video/x-divx")
906 || !strcmp (mimetype, "video/x-dv")
907 || !strcmp (mimetype, "video/x-h263")
908 || !strcmp (mimetype, "video/x-msmpeg")
909 || !strcmp (mimetype, "video/x-wmv")
910 || !strcmp (mimetype, "image/jpeg")) {
911 gst_riff_strf_vids *bih;
912 gint size = sizeof (gst_riff_strf_vids);
915 if (!strcmp (mimetype, "video/x-xvid"))
916 fourcc = GST_MAKE_FOURCC ('X', 'V', 'I', 'D');
917 else if (!strcmp (mimetype, "video/x-huffyuv"))
918 fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
919 else if (!strcmp (mimetype, "video/x-dv"))
920 fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
921 else if (!strcmp (mimetype, "video/x-h263"))
922 fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
923 else if (!strcmp (mimetype, "video/x-divx")) {
926 gst_structure_get_int (structure, "divxversion", &divxversion);
927 switch (divxversion) {
929 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
932 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
935 fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
938 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
941 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
942 switch (msmpegversion) {
944 fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
947 fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
953 } else if (!strcmp (mimetype, "video/x-wmv")) {
956 if (gst_structure_get_fourcc (structure, "format", &format)) {
958 } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
959 if (wmvversion == 2) {
960 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
961 } else if (wmvversion == 1) {
962 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
963 } else if (wmvversion == 3) {
964 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
967 } else if (!strcmp (mimetype, "image/jpeg")) {
968 fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
974 bih = g_new0 (gst_riff_strf_vids, 1);
975 GST_WRITE_UINT32_LE (&bih->size, size);
976 GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
977 GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
978 GST_WRITE_UINT32_LE (&bih->compression, fourcc);
979 GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
980 GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
981 GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
982 videocontext->pixel_height * 3);
984 /* process codec private/initialization data, if any */
986 size += GST_BUFFER_SIZE (codec_buf);
987 bih = g_realloc (bih, size);
988 GST_WRITE_UINT32_LE (&bih->size, size);
989 memcpy ((guint8 *) bih + sizeof (gst_riff_strf_vids),
990 GST_BUFFER_DATA (codec_buf), GST_BUFFER_SIZE (codec_buf));
993 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
994 context->codec_priv = (gpointer) bih;
995 context->codec_priv_size = size;
996 } else if (!strcmp (mimetype, "video/x-h264")) {
997 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
999 if (context->codec_priv != NULL) {
1000 g_free (context->codec_priv);
1001 context->codec_priv = NULL;
1002 context->codec_priv_size = 0;
1005 /* Create avcC header */
1006 if (codec_buf != NULL) {
1007 context->codec_priv_size = GST_BUFFER_SIZE (codec_buf);
1008 context->codec_priv = g_malloc0 (context->codec_priv_size);
1009 memcpy (context->codec_priv, GST_BUFFER_DATA (codec_buf),
1010 context->codec_priv_size);
1012 } else if (!strcmp (mimetype, "video/x-theora")) {
1013 const GValue *streamheader;
1015 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
1017 if (context->codec_priv != NULL) {
1018 g_free (context->codec_priv);
1019 context->codec_priv = NULL;
1020 context->codec_priv_size = 0;
1023 streamheader = gst_structure_get_value (structure, "streamheader");
1024 if (!theora_streamheader_to_codecdata (streamheader, context)) {
1025 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1026 ("theora stream headers missing or malformed"));
1029 } else if (!strcmp (mimetype, "video/x-dirac")) {
1030 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
1031 } else if (!strcmp (mimetype, "video/x-vp8")) {
1032 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VP8);
1033 } else if (!strcmp (mimetype, "video/mpeg")) {
1036 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1037 switch (mpegversion) {
1039 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
1042 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
1045 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
1051 /* global headers may be in codec data */
1052 if (codec_buf != NULL) {
1053 context->codec_priv_size = GST_BUFFER_SIZE (codec_buf);
1054 context->codec_priv = g_malloc0 (context->codec_priv_size);
1055 memcpy (context->codec_priv, GST_BUFFER_DATA (codec_buf),
1056 context->codec_priv_size);
1058 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1060 /* can only make it here if preceding case verified it was version 3 */
1061 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
1062 } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
1064 const GValue *mdpr_data;
1066 gst_structure_get_int (structure, "rmversion", &rmversion);
1067 switch (rmversion) {
1069 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
1072 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
1075 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
1078 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
1084 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1085 if (mdpr_data != NULL) {
1086 guint8 *priv_data = NULL;
1087 guint priv_data_size = 0;
1089 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1091 priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
1092 priv_data = g_malloc0 (priv_data_size);
1094 memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
1096 context->codec_priv = priv_data;
1097 context->codec_priv_size = priv_data_size;
1106 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1107 GST_PAD_NAME (pad), caps);
1112 /* N > 0 to expect a particular number of headers, negative if the
1113 number of headers is variable */
1115 xiphN_streamheader_to_codecdata (const GValue * streamheader,
1116 GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
1118 GstBuffer **buf = NULL;
1121 guint bufi, i, offset, priv_data_size;
1123 if (streamheader == NULL)
1124 goto no_stream_headers;
1126 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1129 bufarr = g_value_peek_pointer (streamheader);
1130 if (bufarr->len <= 0 || bufarr->len > 255) /* at least one header, and count stored in a byte */
1132 if (N > 0 && bufarr->len != N)
1135 context->xiph_headers_to_skip = bufarr->len;
1137 buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1138 for (i = 0; i < bufarr->len; i++) {
1139 GValue *bufval = &g_array_index (bufarr, GValue, i);
1141 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1143 goto wrong_content_type;
1146 buf[i] = g_value_peek_pointer (bufval);
1150 if (bufarr->len > 0) {
1151 for (i = 0; i < bufarr->len - 1; i++) {
1152 priv_data_size += GST_BUFFER_SIZE (buf[i]) / 0xff + 1;
1156 for (i = 0; i < bufarr->len; ++i) {
1157 priv_data_size += GST_BUFFER_SIZE (buf[i]);
1160 priv_data = g_malloc0 (priv_data_size);
1162 priv_data[0] = bufarr->len - 1;
1165 if (bufarr->len > 0) {
1166 for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1167 for (i = 0; i < GST_BUFFER_SIZE (buf[bufi]) / 0xff; ++i) {
1168 priv_data[offset++] = 0xff;
1170 priv_data[offset++] = GST_BUFFER_SIZE (buf[bufi]) % 0xff;
1174 for (i = 0; i < bufarr->len; ++i) {
1175 memcpy (priv_data + offset, GST_BUFFER_DATA (buf[i]),
1176 GST_BUFFER_SIZE (buf[i]));
1177 offset += GST_BUFFER_SIZE (buf[i]);
1180 context->codec_priv = priv_data;
1181 context->codec_priv_size = priv_data_size;
1184 *p_buf0 = gst_buffer_ref (buf[0]);
1193 GST_WARNING ("required streamheaders missing in sink caps!");
1198 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1199 G_VALUE_TYPE_NAME (streamheader));
1204 GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1209 GST_WARNING ("streamheaders array does not contain GstBuffers");
1215 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1216 GstMatroskaTrackContext * context)
1218 GstBuffer *buf0 = NULL;
1220 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1223 if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 4) {
1224 GST_WARNING ("First vorbis header too small, ignoring");
1226 if (memcmp (GST_BUFFER_DATA (buf0) + 1, "vorbis", 6) == 0) {
1227 GstMatroskaTrackAudioContext *audiocontext;
1230 hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 4;
1231 audiocontext = (GstMatroskaTrackAudioContext *) context;
1232 audiocontext->channels = GST_READ_UINT8 (hdr);
1233 audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1238 gst_buffer_unref (buf0);
1244 theora_streamheader_to_codecdata (const GValue * streamheader,
1245 GstMatroskaTrackContext * context)
1247 GstBuffer *buf0 = NULL;
1249 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1252 if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 26) {
1253 GST_WARNING ("First theora header too small, ignoring");
1254 } else if (memcmp (GST_BUFFER_DATA (buf0), "\200theora\003\002", 9) != 0) {
1255 GST_WARNING ("First header not a theora identification header, ignoring");
1257 GstMatroskaTrackVideoContext *videocontext;
1258 guint fps_num, fps_denom, par_num, par_denom;
1261 hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 3 + 2 + 2;
1263 videocontext = (GstMatroskaTrackVideoContext *) context;
1264 videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1265 videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1266 hdr += 3 + 3 + 1 + 1;
1267 fps_num = GST_READ_UINT32_BE (hdr);
1268 fps_denom = GST_READ_UINT32_BE (hdr + 4);
1269 context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1270 fps_denom, fps_num);
1272 par_num = GST_READ_UINT32_BE (hdr) >> 8;
1273 par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1274 if (par_num > 0 && par_num > 0) {
1275 if (par_num > par_denom) {
1276 videocontext->display_width =
1277 videocontext->pixel_width * par_num / par_denom;
1278 videocontext->display_height = videocontext->pixel_height;
1279 } else if (par_num < par_denom) {
1280 videocontext->display_width = videocontext->pixel_width;
1281 videocontext->display_height =
1282 videocontext->pixel_height * par_denom / par_num;
1284 videocontext->display_width = 0;
1285 videocontext->display_height = 0;
1288 videocontext->display_width = 0;
1289 videocontext->display_height = 0;
1295 gst_buffer_unref (buf0);
1301 kate_streamheader_to_codecdata (const GValue * streamheader,
1302 GstMatroskaTrackContext * context)
1304 GstBuffer *buf0 = NULL;
1306 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1309 if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 64) { /* Kate ID header is 64 bytes */
1310 GST_WARNING ("First kate header too small, ignoring");
1311 } else if (memcmp (GST_BUFFER_DATA (buf0), "\200kate\0\0\0", 8) != 0) {
1312 GST_WARNING ("First header not a kate identification header, ignoring");
1316 gst_buffer_unref (buf0);
1322 flac_streamheader_to_codecdata (const GValue * streamheader,
1323 GstMatroskaTrackContext * context)
1330 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1331 GST_WARNING ("No or invalid streamheader field in the caps");
1335 bufarr = g_value_peek_pointer (streamheader);
1336 if (bufarr->len < 2) {
1337 GST_WARNING ("Too few headers in streamheader field");
1341 context->xiph_headers_to_skip = bufarr->len + 1;
1343 bufval = &g_array_index (bufarr, GValue, 0);
1344 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1345 GST_WARNING ("streamheaders array does not contain GstBuffers");
1349 buffer = g_value_peek_pointer (bufval);
1351 /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1352 if (GST_BUFFER_SIZE (buffer) < 9 + 4 + 4 + 34
1353 || memcmp (GST_BUFFER_DATA (buffer) + 1, "FLAC", 4) != 0
1354 || memcmp (GST_BUFFER_DATA (buffer) + 9, "fLaC", 4) != 0) {
1355 GST_WARNING ("Invalid streamheader for FLAC");
1359 context->codec_priv = g_malloc (GST_BUFFER_SIZE (buffer) - 9);
1360 context->codec_priv_size = GST_BUFFER_SIZE (buffer) - 9;
1361 memcpy (context->codec_priv, GST_BUFFER_DATA (buffer) + 9,
1362 GST_BUFFER_SIZE (buffer) - 9);
1364 for (i = 1; i < bufarr->len; i++) {
1365 bufval = &g_array_index (bufarr, GValue, i);
1367 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1368 g_free (context->codec_priv);
1369 context->codec_priv = NULL;
1370 context->codec_priv_size = 0;
1371 GST_WARNING ("streamheaders array does not contain GstBuffers");
1375 buffer = g_value_peek_pointer (bufval);
1377 context->codec_priv =
1378 g_realloc (context->codec_priv,
1379 context->codec_priv_size + GST_BUFFER_SIZE (buffer));
1380 memcpy ((guint8 *) context->codec_priv + context->codec_priv_size,
1381 GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
1382 context->codec_priv_size =
1383 context->codec_priv_size + GST_BUFFER_SIZE (buffer);
1390 speex_streamheader_to_codecdata (const GValue * streamheader,
1391 GstMatroskaTrackContext * context)
1397 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1398 GST_WARNING ("No or invalid streamheader field in the caps");
1402 bufarr = g_value_peek_pointer (streamheader);
1403 if (bufarr->len != 2) {
1404 GST_WARNING ("Too few headers in streamheader field");
1408 context->xiph_headers_to_skip = bufarr->len + 1;
1410 bufval = &g_array_index (bufarr, GValue, 0);
1411 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1412 GST_WARNING ("streamheaders array does not contain GstBuffers");
1416 buffer = g_value_peek_pointer (bufval);
1418 if (GST_BUFFER_SIZE (buffer) < 80
1419 || memcmp (GST_BUFFER_DATA (buffer), "Speex ", 8) != 0) {
1420 GST_WARNING ("Invalid streamheader for Speex");
1424 context->codec_priv = g_malloc (GST_BUFFER_SIZE (buffer));
1425 context->codec_priv_size = GST_BUFFER_SIZE (buffer);
1426 memcpy (context->codec_priv, GST_BUFFER_DATA (buffer),
1427 GST_BUFFER_SIZE (buffer));
1429 bufval = &g_array_index (bufarr, GValue, 1);
1431 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1432 g_free (context->codec_priv);
1433 context->codec_priv = NULL;
1434 context->codec_priv_size = 0;
1435 GST_WARNING ("streamheaders array does not contain GstBuffers");
1439 buffer = g_value_peek_pointer (bufval);
1441 context->codec_priv =
1442 g_realloc (context->codec_priv,
1443 context->codec_priv_size + GST_BUFFER_SIZE (buffer));
1444 memcpy ((guint8 *) context->codec_priv + context->codec_priv_size,
1445 GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
1446 context->codec_priv_size =
1447 context->codec_priv_size + GST_BUFFER_SIZE (buffer);
1452 static const gchar *
1453 aac_codec_data_to_codec_id (const GstBuffer * buf)
1455 const gchar *result;
1458 /* default to MAIN */
1461 if (GST_BUFFER_SIZE (buf) >= 2) {
1462 profile = GST_READ_UINT8 (GST_BUFFER_DATA (buf));
1480 GST_WARNING ("unknown AAC profile, defaulting to MAIN");
1489 * gst_matroska_mux_audio_pad_setcaps:
1490 * @pad: Pad which got the caps.
1493 * Setcaps function for audio sink pad.
1495 * Returns: #TRUE on success.
1498 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1500 GstMatroskaTrackContext *context = NULL;
1501 GstMatroskaTrackAudioContext *audiocontext;
1502 GstMatroskaMux *mux;
1503 GstMatroskaPad *collect_pad;
1504 const gchar *mimetype;
1505 gint samplerate = 0, channels = 0;
1506 GstStructure *structure;
1507 const GValue *codec_data = NULL;
1508 const GstBuffer *buf = NULL;
1509 const gchar *stream_format = NULL;
1511 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1514 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1515 g_assert (collect_pad);
1516 context = collect_pad->track;
1518 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
1519 audiocontext = (GstMatroskaTrackAudioContext *) context;
1521 structure = gst_caps_get_structure (caps, 0);
1522 mimetype = gst_structure_get_name (structure);
1525 gst_structure_get_int (structure, "rate", &samplerate);
1526 gst_structure_get_int (structure, "channels", &channels);
1528 audiocontext->samplerate = samplerate;
1529 audiocontext->channels = channels;
1530 audiocontext->bitdepth = 0;
1531 context->default_duration = 0;
1533 codec_data = gst_structure_get_value (structure, "codec_data");
1535 buf = gst_value_get_buffer (codec_data);
1537 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1538 * data and other settings
1542 if (!strcmp (mimetype, "audio/mpeg")) {
1543 gint mpegversion = 0;
1545 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1546 switch (mpegversion) {
1552 gst_structure_get_int (structure, "layer", &layer);
1554 if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
1555 GST_WARNING_OBJECT (mux,
1556 "Unable to determine MPEG audio version, assuming 1");
1562 else if (layer == 2)
1564 else if (version == 2)
1569 context->default_duration =
1570 gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
1574 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
1577 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
1580 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
1589 stream_format = gst_structure_get_string (structure, "stream-format");
1590 /* check this is raw aac */
1591 if (stream_format) {
1592 if (strcmp (stream_format, "raw") != 0) {
1593 GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
1597 GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
1602 if (mpegversion == 2)
1604 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2 "%s",
1605 aac_codec_data_to_codec_id (buf));
1606 else if (mpegversion == 4)
1608 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4 "%s",
1609 aac_codec_data_to_codec_id (buf));
1611 g_assert_not_reached ();
1613 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
1620 } else if (!strcmp (mimetype, "audio/x-raw-int")) {
1622 gint endianness = G_LITTLE_ENDIAN;
1623 gboolean signedness = TRUE;
1625 if (!gst_structure_get_int (structure, "width", &width) ||
1626 !gst_structure_get_int (structure, "depth", &depth) ||
1627 !gst_structure_get_boolean (structure, "signed", &signedness)) {
1628 GST_DEBUG_OBJECT (mux, "broken caps, width/depth/signed field missing");
1633 !gst_structure_get_int (structure, "endianness", &endianness)) {
1634 GST_DEBUG_OBJECT (mux, "broken caps, no endianness specified");
1638 if (width != depth) {
1639 GST_DEBUG_OBJECT (mux, "width must be same as depth!");
1643 /* FIXME: where is this spec'ed out? (tpm) */
1644 if ((width == 8 && signedness) || (width >= 16 && !signedness)) {
1645 GST_DEBUG_OBJECT (mux, "8-bit PCM must be unsigned, 16-bit PCM signed");
1649 audiocontext->bitdepth = depth;
1650 if (endianness == G_BIG_ENDIAN)
1651 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
1653 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
1655 } else if (!strcmp (mimetype, "audio/x-raw-float")) {
1658 if (!gst_structure_get_int (structure, "width", &width)) {
1659 GST_DEBUG_OBJECT (mux, "broken caps, width field missing");
1663 audiocontext->bitdepth = width;
1664 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
1666 } else if (!strcmp (mimetype, "audio/x-vorbis")) {
1667 const GValue *streamheader;
1669 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
1671 if (context->codec_priv != NULL) {
1672 g_free (context->codec_priv);
1673 context->codec_priv = NULL;
1674 context->codec_priv_size = 0;
1677 streamheader = gst_structure_get_value (structure, "streamheader");
1678 if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
1679 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1680 ("vorbis stream headers missing or malformed"));
1683 } else if (!strcmp (mimetype, "audio/x-flac")) {
1684 const GValue *streamheader;
1686 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
1687 if (context->codec_priv != NULL) {
1688 g_free (context->codec_priv);
1689 context->codec_priv = NULL;
1690 context->codec_priv_size = 0;
1693 streamheader = gst_structure_get_value (structure, "streamheader");
1694 if (!flac_streamheader_to_codecdata (streamheader, context)) {
1695 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1696 ("flac stream headers missing or malformed"));
1699 } else if (!strcmp (mimetype, "audio/x-speex")) {
1700 const GValue *streamheader;
1702 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
1703 if (context->codec_priv != NULL) {
1704 g_free (context->codec_priv);
1705 context->codec_priv = NULL;
1706 context->codec_priv_size = 0;
1709 streamheader = gst_structure_get_value (structure, "streamheader");
1710 if (!speex_streamheader_to_codecdata (streamheader, context)) {
1711 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1712 ("speex stream headers missing or malformed"));
1715 } else if (!strcmp (mimetype, "audio/x-ac3")) {
1716 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AC3);
1717 } else if (!strcmp (mimetype, "audio/x-eac3")) {
1718 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
1719 } else if (!strcmp (mimetype, "audio/x-dts")) {
1720 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_DTS);
1721 } else if (!strcmp (mimetype, "audio/x-tta")) {
1724 /* TTA frame duration */
1725 context->default_duration = 1.04489795918367346939 * GST_SECOND;
1727 gst_structure_get_int (structure, "width", &width);
1728 audiocontext->bitdepth = width;
1729 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_TTA);
1731 } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
1733 const GValue *mdpr_data;
1735 gst_structure_get_int (structure, "raversion", &raversion);
1736 switch (raversion) {
1738 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
1741 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
1744 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
1750 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1751 if (mdpr_data != NULL) {
1752 guint8 *priv_data = NULL;
1753 guint priv_data_size = 0;
1755 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1757 priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
1758 priv_data = g_malloc0 (priv_data_size);
1760 memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
1762 context->codec_priv = priv_data;
1763 context->codec_priv_size = priv_data_size;
1766 } else if (!strcmp (mimetype, "audio/x-wma")
1767 || !strcmp (mimetype, "audio/x-alaw")
1768 || !strcmp (mimetype, "audio/x-mulaw")) {
1770 guint codec_priv_size;
1775 if (samplerate == 0 || channels == 0) {
1776 GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
1780 if (!strcmp (mimetype, "audio/x-wma")) {
1784 if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
1785 || !gst_structure_get_int (structure, "block_align", &block_align)
1786 || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
1787 GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
1792 switch (wmaversion) {
1794 format = GST_RIFF_WAVE_FORMAT_WMAV1;
1797 format = GST_RIFF_WAVE_FORMAT_WMAV2;
1800 format = GST_RIFF_WAVE_FORMAT_WMAV3;
1803 GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
1807 if (gst_structure_get_int (structure, "depth", &depth))
1808 audiocontext->bitdepth = depth;
1809 } else if (!strcmp (mimetype, "audio/x-alaw")
1810 || !strcmp (mimetype, "audio/x-mulaw")) {
1811 audiocontext->bitdepth = 8;
1812 if (!strcmp (mimetype, "audio/x-alaw"))
1813 format = GST_RIFF_WAVE_FORMAT_ALAW;
1815 format = GST_RIFF_WAVE_FORMAT_MULAW;
1817 block_align = channels;
1818 bitrate = block_align * samplerate;
1820 g_assert (format != 0);
1822 codec_priv_size = WAVEFORMATEX_SIZE;
1824 codec_priv_size += GST_BUFFER_SIZE (buf);
1826 /* serialize waveformatex structure */
1827 codec_priv = g_malloc0 (codec_priv_size);
1828 GST_WRITE_UINT16_LE (codec_priv, format);
1829 GST_WRITE_UINT16_LE (codec_priv + 2, channels);
1830 GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
1831 GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
1832 GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
1833 GST_WRITE_UINT16_LE (codec_priv + 14, 0);
1835 GST_WRITE_UINT16_LE (codec_priv + 16, GST_BUFFER_SIZE (buf));
1837 GST_WRITE_UINT16_LE (codec_priv + 16, 0);
1839 /* process codec private/initialization data, if any */
1841 memcpy ((guint8 *) codec_priv + WAVEFORMATEX_SIZE,
1842 GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
1845 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_ACM);
1846 context->codec_priv = (gpointer) codec_priv;
1847 context->codec_priv_size = codec_priv_size;
1855 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1856 GST_PAD_NAME (pad), caps);
1863 * gst_matroska_mux_subtitle_pad_setcaps:
1864 * @pad: Pad which got the caps.
1867 * Setcaps function for subtitle sink pad.
1869 * Returns: #TRUE on success.
1872 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
1875 * Consider this as boilerplate code for now. There is
1876 * no single subtitle creation element in GStreamer,
1877 * neither do I know how subtitling works at all. */
1879 /* There is now (at least) one such alement (kateenc), and I'm going
1880 to handle it here and claim it works when it can be piped back
1881 through GStreamer and VLC */
1883 GstMatroskaTrackContext *context = NULL;
1884 GstMatroskaTrackSubtitleContext *scontext;
1885 GstMatroskaMux *mux;
1886 GstMatroskaPad *collect_pad;
1887 const gchar *mimetype;
1888 GstStructure *structure;
1890 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1893 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1894 g_assert (collect_pad);
1895 context = collect_pad->track;
1897 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
1898 scontext = (GstMatroskaTrackSubtitleContext *) context;
1900 structure = gst_caps_get_structure (caps, 0);
1901 mimetype = gst_structure_get_name (structure);
1904 scontext->check_utf8 = 1;
1905 scontext->invalid_utf8 = 0;
1906 context->default_duration = 0;
1908 /* TODO: - other format than Kate */
1910 if (!strcmp (mimetype, "subtitle/x-kate")) {
1911 const GValue *streamheader;
1913 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
1915 if (context->codec_priv != NULL) {
1916 g_free (context->codec_priv);
1917 context->codec_priv = NULL;
1918 context->codec_priv_size = 0;
1921 streamheader = gst_structure_get_value (structure, "streamheader");
1922 if (!kate_streamheader_to_codecdata (streamheader, context)) {
1923 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1924 ("kate stream headers missing or malformed"));
1935 * gst_matroska_mux_request_new_pad:
1936 * @element: #GstMatroskaMux.
1937 * @templ: #GstPadTemplate.
1938 * @pad_name: New pad name.
1940 * Request pad function for sink templates.
1942 * Returns: New #GstPad.
1945 gst_matroska_mux_request_new_pad (GstElement * element,
1946 GstPadTemplate * templ, const gchar * req_name)
1948 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
1949 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
1950 GstMatroskaPad *collect_pad;
1951 GstMatroskamuxPad *newpad;
1953 const gchar *pad_name = NULL;
1954 GstPadSetCapsFunction setcapsfunc = NULL;
1955 GstMatroskaTrackContext *context = NULL;
1958 if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
1959 /* don't mix named and unnamed pads, if the pad already exists we fail when
1960 * trying to add it */
1961 if (req_name != NULL && sscanf (req_name, "audio_%d", &pad_id) == 1) {
1962 pad_name = req_name;
1964 name = g_strdup_printf ("audio_%d", mux->num_a_streams++);
1967 setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
1968 context = (GstMatroskaTrackContext *)
1969 g_new0 (GstMatroskaTrackAudioContext, 1);
1970 context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
1971 context->name = g_strdup ("Audio");
1972 } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
1973 /* don't mix named and unnamed pads, if the pad already exists we fail when
1974 * trying to add it */
1975 if (req_name != NULL && sscanf (req_name, "video_%d", &pad_id) == 1) {
1976 pad_name = req_name;
1978 name = g_strdup_printf ("video_%d", mux->num_v_streams++);
1981 setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
1982 context = (GstMatroskaTrackContext *)
1983 g_new0 (GstMatroskaTrackVideoContext, 1);
1984 context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
1985 context->name = g_strdup ("Video");
1986 } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%d")) {
1987 /* don't mix named and unnamed pads, if the pad already exists we fail when
1988 * trying to add it */
1989 if (req_name != NULL && sscanf (req_name, "subtitle_%d", &pad_id) == 1) {
1990 pad_name = req_name;
1992 name = g_strdup_printf ("subtitle_%d", mux->num_t_streams++);
1995 setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
1996 context = (GstMatroskaTrackContext *)
1997 g_new0 (GstMatroskaTrackSubtitleContext, 1);
1998 context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
1999 context->name = g_strdup ("Subtitle");
2001 GST_WARNING_OBJECT (mux, "This is not our template!");
2005 newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
2006 "name", pad_name, "direction", templ->direction, "template", templ, NULL);
2009 gst_matroskamux_pad_init (newpad);
2010 collect_pad = (GstMatroskaPad *)
2011 gst_collect_pads_add_pad_full (mux->collect, GST_PAD (newpad),
2012 sizeof (GstMatroskamuxPad),
2013 (GstCollectDataDestroyNotify) gst_matroska_pad_free);
2015 collect_pad->track = context;
2016 gst_matroska_pad_reset (collect_pad, FALSE);
2018 /* FIXME: hacked way to override/extend the event function of
2019 * GstCollectPads; because it sets its own event function giving the
2020 * element no access to events.
2021 * TODO GstCollectPads should really give its 'users' a clean chance to
2022 * properly handle events that are not meant for collectpads itself.
2023 * Perhaps a callback or so, though rejected (?) in #340060.
2024 * This would allow (clean) transcoding of info from demuxer/streams
2025 * to another muxer */
2026 mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
2027 gst_pad_set_event_function (GST_PAD (newpad),
2028 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event));
2030 gst_pad_set_setcaps_function (GST_PAD (newpad), setcapsfunc);
2031 gst_pad_set_active (GST_PAD (newpad), TRUE);
2032 if (!gst_element_add_pad (element, GST_PAD (newpad)))
2033 goto pad_add_failed;
2037 GST_DEBUG_OBJECT (newpad, "Added new request pad");
2039 return GST_PAD (newpad);
2044 GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
2045 gst_object_unref (newpad);
2051 * gst_matroska_mux_release_pad:
2052 * @element: #GstMatroskaMux.
2053 * @pad: Pad to release.
2055 * Release a previously requested pad.
2058 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
2060 GstMatroskaMux *mux;
2063 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2065 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
2066 GstCollectData *cdata = (GstCollectData *) walk->data;
2067 GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
2069 if (cdata->pad == pad) {
2070 GstClockTime min_dur; /* observed minimum duration */
2072 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2073 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2074 min_dur = GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2075 if (collect_pad->duration < min_dur)
2076 collect_pad->duration = min_dur;
2079 if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
2080 mux->duration < collect_pad->duration)
2081 mux->duration = collect_pad->duration;
2087 gst_collect_pads_remove_pad (mux->collect, pad);
2088 if (gst_element_remove_pad (element, pad))
2094 * gst_matroska_mux_track_header:
2095 * @mux: #GstMatroskaMux
2096 * @context: Tack context.
2098 * Write a track header.
2101 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2102 GstMatroskaTrackContext * context)
2104 GstEbmlWrite *ebml = mux->ebml_write;
2107 /* TODO: check if everything necessary is written and check default values */
2109 /* track type goes before the type-specific stuff */
2110 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2111 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2113 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID,
2114 gst_matroska_mux_create_uid ());
2115 if (context->default_duration) {
2116 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2117 context->default_duration);
2119 if (context->language) {
2120 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2124 /* type-specific stuff */
2125 switch (context->type) {
2126 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2127 GstMatroskaTrackVideoContext *videocontext =
2128 (GstMatroskaTrackVideoContext *) context;
2130 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2131 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2132 videocontext->pixel_width);
2133 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2134 videocontext->pixel_height);
2135 if (videocontext->display_width && videocontext->display_height) {
2136 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2137 videocontext->display_width);
2138 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2139 videocontext->display_height);
2141 if (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED)
2142 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2143 if (videocontext->fourcc) {
2144 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2146 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2147 (gpointer) & fcc_le, 4);
2149 gst_ebml_write_master_finish (ebml, master);
2154 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2155 GstMatroskaTrackAudioContext *audiocontext =
2156 (GstMatroskaTrackAudioContext *) context;
2158 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2159 if (audiocontext->samplerate != 8000)
2160 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2161 audiocontext->samplerate);
2162 if (audiocontext->channels != 1)
2163 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2164 audiocontext->channels);
2165 if (audiocontext->bitdepth) {
2166 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2167 audiocontext->bitdepth);
2169 gst_ebml_write_master_finish (ebml, master);
2175 /* doesn't need type-specific data */
2179 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2180 if (context->codec_priv)
2181 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2182 context->codec_priv, context->codec_priv_size);
2183 /* FIXME: until we have a nice way of getting the codecname
2184 * out of the caps, I'm not going to enable this. Too much
2185 * (useless, double, boring) work... */
2186 /* TODO: Use value from tags if any */
2187 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2188 context->codec_name); */
2189 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2194 * gst_matroska_mux_start:
2195 * @mux: #GstMatroskaMux
2197 * Start a new matroska file (write headers etc...)
2200 gst_matroska_mux_start (GstMatroskaMux * mux)
2202 GstEbmlWrite *ebml = mux->ebml_write;
2203 const gchar *doctype;
2204 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
2205 GST_MATROSKA_ID_TRACKS,
2206 GST_MATROSKA_ID_CUES,
2207 GST_MATROSKA_ID_TAGS,
2210 guint64 master, child;
2214 GstClockTime duration = 0;
2215 guint32 segment_uid[4];
2216 GTimeVal time = { 0, 0 };
2218 if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2219 ebml->caps = gst_caps_new_simple ("video/webm", NULL);
2221 ebml->caps = gst_caps_new_simple ("video/x-matroska", NULL);
2223 /* we start with a EBML header */
2224 doctype = mux->doctype;
2225 GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
2226 doctype, mux->doctype_version);
2227 gst_ebml_write_header (ebml, doctype, mux->doctype_version);
2229 /* the rest of the header is cached */
2230 gst_ebml_write_set_cache (ebml, 0x1000);
2232 /* start a segment */
2234 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
2235 mux->segment_master = ebml->pos;
2237 if (!mux->streamable) {
2238 /* seekhead (table of contents) - we set the positions later */
2239 mux->seekhead_pos = ebml->pos;
2240 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
2241 for (i = 0; seekhead_id[i] != 0; i++) {
2242 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
2243 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
2244 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
2245 gst_ebml_write_master_finish (ebml, child);
2247 gst_ebml_write_master_finish (ebml, master);
2250 if (mux->streamable) {
2251 const GstTagList *tags;
2254 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2256 if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2257 guint64 master_tags, master_tag;
2259 GST_DEBUG ("Writing tags");
2261 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2262 mux->tags_pos = ebml->pos;
2263 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2264 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2265 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2266 gst_ebml_write_master_finish (ebml, master_tag);
2267 gst_ebml_write_master_finish (ebml, master_tags);
2272 mux->info_pos = ebml->pos;
2273 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
2274 for (i = 0; i < 4; i++) {
2275 segment_uid[i] = g_random_int ();
2277 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
2278 (guint8 *) segment_uid, 16);
2279 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
2280 mux->duration_pos = ebml->pos;
2282 if (!mux->streamable) {
2283 for (collected = mux->collect->data; collected;
2284 collected = g_slist_next (collected)) {
2285 GstMatroskaPad *collect_pad;
2286 GstFormat format = GST_FORMAT_TIME;
2288 gint64 trackduration;
2290 collect_pad = (GstMatroskaPad *) collected->data;
2291 thepad = collect_pad->collect.pad;
2293 /* Query the total length of the track. */
2294 GST_DEBUG_OBJECT (thepad, "querying peer duration");
2295 if (gst_pad_query_peer_duration (thepad, &format, &trackduration)) {
2296 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
2297 GST_TIME_ARGS (trackduration));
2298 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
2299 duration = (GstClockTime) trackduration;
2303 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2304 gst_guint64_to_gdouble (duration) /
2305 gst_guint64_to_gdouble (mux->time_scale));
2307 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
2308 "GStreamer plugin version " PACKAGE_VERSION);
2309 if (mux->writing_app && mux->writing_app[0]) {
2310 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
2312 g_get_current_time (&time);
2313 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
2314 gst_ebml_write_master_finish (ebml, master);
2317 mux->tracks_pos = ebml->pos;
2318 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
2320 for (collected = mux->collect->data; collected;
2321 collected = g_slist_next (collected)) {
2322 GstMatroskaPad *collect_pad;
2325 collect_pad = (GstMatroskaPad *) collected->data;
2326 thepad = collect_pad->collect.pad;
2328 if (gst_pad_is_linked (thepad) && gst_pad_is_active (thepad) &&
2329 collect_pad->track->codec_id != 0) {
2330 collect_pad->track->num = tracknum++;
2331 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
2332 gst_matroska_mux_track_header (mux, collect_pad->track);
2333 gst_ebml_write_master_finish (ebml, child);
2334 /* some remaing pad/track setup */
2335 collect_pad->default_duration_scaled =
2336 gst_util_uint64_scale (collect_pad->track->default_duration,
2337 1, mux->time_scale);
2340 gst_ebml_write_master_finish (ebml, master);
2342 /* lastly, flush the cache */
2343 gst_ebml_write_flush_cache (ebml, FALSE, 0);
2347 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
2350 /* TODO: more sensible tag mappings */
2353 const gchar *matroska_tagname;
2354 const gchar *gstreamer_tagname;
2358 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
2359 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
2360 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
2361 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
2362 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
2363 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
2364 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
2365 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
2366 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
2367 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
2368 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
2369 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
2370 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
2371 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
2372 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
2374 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
2376 guint64 simpletag_master;
2378 for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) {
2379 const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
2380 const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
2382 if (strcmp (tagname_gst, tag) == 0) {
2383 GValue src = { 0, };
2386 if (!gst_tag_list_copy_value (&src, list, tag))
2388 if ((dest = gst_value_serialize (&src))) {
2390 simpletag_master = gst_ebml_write_master_start (ebml,
2391 GST_MATROSKA_ID_SIMPLETAG);
2392 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
2393 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
2394 gst_ebml_write_master_finish (ebml, simpletag_master);
2397 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
2399 g_value_unset (&src);
2407 * gst_matroska_mux_finish:
2408 * @mux: #GstMatroskaMux
2410 * Finish a new matroska file (write index etc...)
2413 gst_matroska_mux_finish (GstMatroskaMux * mux)
2415 GstEbmlWrite *ebml = mux->ebml_write;
2417 guint64 duration = 0;
2419 const GstTagList *tags;
2421 /* finish last cluster */
2423 gst_ebml_write_master_finish (ebml, mux->cluster);
2427 if (mux->index != NULL) {
2429 guint64 master, pointentry_master, trackpos_master;
2431 mux->cues_pos = ebml->pos;
2432 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
2433 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
2435 for (n = 0; n < mux->num_indexes; n++) {
2436 GstMatroskaIndex *idx = &mux->index[n];
2438 pointentry_master = gst_ebml_write_master_start (ebml,
2439 GST_MATROSKA_ID_POINTENTRY);
2440 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
2441 idx->time / mux->time_scale);
2442 trackpos_master = gst_ebml_write_master_start (ebml,
2443 GST_MATROSKA_ID_CUETRACKPOSITIONS);
2444 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
2445 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
2446 idx->pos - mux->segment_master);
2447 gst_ebml_write_master_finish (ebml, trackpos_master);
2448 gst_ebml_write_master_finish (ebml, pointentry_master);
2451 gst_ebml_write_master_finish (ebml, master);
2452 gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
2456 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2458 if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2459 guint64 master_tags, master_tag;
2461 GST_DEBUG ("Writing tags");
2463 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2464 mux->tags_pos = ebml->pos;
2465 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2466 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2467 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2468 gst_ebml_write_master_finish (ebml, master_tag);
2469 gst_ebml_write_master_finish (ebml, master_tags);
2472 /* update seekhead. We know that:
2473 * - a seekhead contains 4 entries.
2474 * - order of entries is as above.
2475 * - a seekhead has a 4-byte header + 8-byte length
2476 * - each entry is 2-byte master, 2-byte ID pointer,
2477 * 2-byte length pointer, all 8/1-byte length, 4-
2478 * byte ID and 8-byte length pointer, where the
2479 * length pointer starts at 20.
2480 * - all entries are local to the segment (so pos - segment_master).
2481 * - so each entry is at 12 + 20 + num * 28. */
2482 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
2483 mux->info_pos - mux->segment_master);
2484 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
2485 mux->tracks_pos - mux->segment_master);
2486 if (mux->index != NULL) {
2487 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
2488 mux->cues_pos - mux->segment_master);
2491 guint64 my_pos = ebml->pos;
2493 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
2494 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2495 gst_ebml_write_seek (ebml, my_pos);
2498 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
2499 mux->tags_pos - mux->segment_master);
2502 guint64 my_pos = ebml->pos;
2504 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
2505 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2506 gst_ebml_write_seek (ebml, my_pos);
2509 /* update duration */
2510 /* first get the overall duration */
2511 /* a released track may have left a duration in here */
2512 duration = mux->duration;
2513 for (collected = mux->collect->data; collected;
2514 collected = g_slist_next (collected)) {
2515 GstMatroskaPad *collect_pad;
2516 GstClockTime min_duration; /* observed minimum duration */
2518 collect_pad = (GstMatroskaPad *) collected->data;
2520 GST_DEBUG_OBJECT (mux,
2521 "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
2522 " end ts %" GST_TIME_FORMAT, collect_pad,
2523 GST_TIME_ARGS (collect_pad->start_ts),
2524 GST_TIME_ARGS (collect_pad->end_ts));
2526 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2527 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2529 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2530 if (collect_pad->duration < min_duration)
2531 collect_pad->duration = min_duration;
2532 GST_DEBUG_OBJECT (collect_pad,
2533 "final track duration: %" GST_TIME_FORMAT,
2534 GST_TIME_ARGS (collect_pad->duration));
2537 if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
2538 duration < collect_pad->duration)
2539 duration = collect_pad->duration;
2541 if (duration != 0) {
2542 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
2543 GST_TIME_ARGS (duration));
2544 pos = mux->ebml_write->pos;
2545 gst_ebml_write_seek (ebml, mux->duration_pos);
2546 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2547 gst_guint64_to_gdouble (duration) /
2548 gst_guint64_to_gdouble (mux->time_scale));
2549 gst_ebml_write_seek (ebml, pos);
2552 guint64 my_pos = ebml->pos;
2554 gst_ebml_write_seek (ebml, mux->duration_pos);
2555 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
2556 gst_ebml_write_seek (ebml, my_pos);
2558 GST_DEBUG_OBJECT (mux, "finishing segment");
2559 /* finish segment - this also writes element length */
2560 gst_ebml_write_master_finish (ebml, mux->segment_pos);
2565 * gst_matroska_mux_best_pad:
2566 * @mux: #GstMatroskaMux
2567 * @popped: True if at least one buffer was popped from #GstCollectPads
2569 * Find a pad with the oldest data
2570 * (data from this pad should be written first).
2572 * Returns: Selected pad.
2574 static GstMatroskaPad *
2575 gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
2578 GstMatroskaPad *best = NULL;
2581 for (collected = mux->collect->data; collected;
2582 collected = g_slist_next (collected)) {
2583 GstMatroskaPad *collect_pad;
2585 collect_pad = (GstMatroskaPad *) collected->data;
2586 /* fetch a new buffer if needed */
2587 if (collect_pad->buffer == NULL) {
2588 collect_pad->buffer = gst_collect_pads_pop (mux->collect,
2589 (GstCollectData *) collect_pad);
2591 if (collect_pad->buffer != NULL) {
2595 /* convert to running time */
2596 time = GST_BUFFER_TIMESTAMP (collect_pad->buffer);
2597 /* invalid should pass */
2598 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
2599 time = gst_segment_to_running_time (&collect_pad->collect.segment,
2600 GST_FORMAT_TIME, time);
2601 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
2602 GST_DEBUG_OBJECT (mux, "clipping buffer on pad %s outside segment",
2603 GST_PAD_NAME (collect_pad->collect.pad));
2604 gst_buffer_unref (collect_pad->buffer);
2605 collect_pad->buffer = NULL;
2608 GST_LOG_OBJECT (mux, "buffer ts %" GST_TIME_FORMAT " -> %"
2609 GST_TIME_FORMAT " running time",
2610 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (collect_pad->buffer)),
2611 GST_TIME_ARGS (time));
2612 collect_pad->buffer =
2613 gst_buffer_make_metadata_writable (collect_pad->buffer);
2614 GST_BUFFER_TIMESTAMP (collect_pad->buffer) = time;
2620 /* if we have a buffer check if it is better then the current best one */
2621 if (collect_pad->buffer != NULL) {
2622 if (best == NULL || !GST_BUFFER_TIMESTAMP_IS_VALID (collect_pad->buffer)
2623 || (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)
2624 && GST_BUFFER_TIMESTAMP (collect_pad->buffer) <
2625 GST_BUFFER_TIMESTAMP (best->buffer))) {
2635 * gst_matroska_mux_buffer_header:
2636 * @track: Track context.
2637 * @relative_timestamp: relative timestamp of the buffer
2638 * @flags: Buffer flags.
2640 * Create a buffer containing buffer header.
2642 * Returns: New buffer.
2645 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
2646 gint16 relative_timestamp, int flags)
2650 hdr = gst_buffer_new_and_alloc (4);
2651 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
2652 GST_BUFFER_DATA (hdr)[0] = track->num | 0x80;
2653 /* time relative to clustertime */
2654 GST_WRITE_UINT16_BE (GST_BUFFER_DATA (hdr) + 1, relative_timestamp);
2657 GST_BUFFER_DATA (hdr)[3] = flags;
2662 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
2663 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
2664 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
2667 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
2668 GstMatroskaPad * collect_pad, GstBuffer * buf)
2670 GstMatroskaTrackVideoContext *ctx =
2671 (GstMatroskaTrackVideoContext *) collect_pad->track;
2672 const guint8 *data = GST_BUFFER_DATA (buf);
2673 guint size = GST_BUFFER_SIZE (buf);
2675 guint32 next_parse_offset;
2676 GstBuffer *ret = NULL;
2677 gboolean is_muxing_unit = FALSE;
2679 if (GST_BUFFER_SIZE (buf) < 13) {
2680 gst_buffer_unref (buf);
2684 /* Check if this buffer contains a picture or end-of-sequence packet */
2685 while (size >= 13) {
2686 if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
2687 gst_buffer_unref (buf);
2691 parse_code = GST_READ_UINT8 (data + 4);
2692 if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
2693 if (ctx->dirac_unit) {
2694 gst_buffer_unref (ctx->dirac_unit);
2695 ctx->dirac_unit = NULL;
2697 } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
2698 parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
2699 is_muxing_unit = TRUE;
2703 next_parse_offset = GST_READ_UINT32_BE (data + 5);
2705 if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
2708 data += next_parse_offset;
2709 size -= next_parse_offset;
2712 if (ctx->dirac_unit)
2713 ctx->dirac_unit = gst_buffer_join (ctx->dirac_unit, gst_buffer_ref (buf));
2715 ctx->dirac_unit = gst_buffer_ref (buf);
2717 if (is_muxing_unit) {
2718 ret = gst_buffer_make_metadata_writable (ctx->dirac_unit);
2719 ctx->dirac_unit = NULL;
2720 gst_buffer_copy_metadata (ret, buf,
2721 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
2722 GST_BUFFER_COPY_CAPS);
2723 gst_buffer_unref (buf);
2725 gst_buffer_unref (buf);
2733 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
2737 GValue streamheader = { 0 };
2738 GValue bufval = { 0 };
2739 GstBuffer *streamheader_buffer;
2740 GstEbmlWrite *ebml = mux->ebml_write;
2742 streamheader_buffer = gst_ebml_stop_streamheader (ebml);
2743 if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2744 caps = gst_caps_new_simple ("video/webm", NULL);
2746 caps = gst_caps_new_simple ("video/x-matroska", NULL);
2748 s = gst_caps_get_structure (caps, 0);
2749 g_value_init (&streamheader, GST_TYPE_ARRAY);
2750 g_value_init (&bufval, GST_TYPE_BUFFER);
2751 GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_IN_CAPS);
2752 gst_value_set_buffer (&bufval, streamheader_buffer);
2753 gst_value_array_append_value (&streamheader, &bufval);
2754 g_value_unset (&bufval);
2755 gst_structure_set_value (s, "streamheader", &streamheader);
2756 g_value_unset (&streamheader);
2757 gst_caps_replace (&ebml->caps, caps);
2758 gst_buffer_unref (streamheader_buffer);
2759 gst_caps_unref (caps);
2763 * gst_matroska_mux_write_data:
2764 * @mux: #GstMatroskaMux
2765 * @collect_pad: #GstMatroskaPad with the data
2767 * Write collected data (called from gst_matroska_mux_collected).
2769 * Returns: Result of the gst_pad_push issued to write the data.
2771 static GstFlowReturn
2772 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
2774 GstEbmlWrite *ebml = mux->ebml_write;
2775 GstBuffer *buf, *hdr;
2777 gboolean write_duration;
2778 gint16 relative_timestamp;
2779 gint64 relative_timestamp64;
2780 guint64 block_duration;
2781 gboolean is_video_keyframe = FALSE;
2782 GstMatroskamuxPad *pad;
2785 buf = collect_pad->buffer;
2786 collect_pad->buffer = NULL;
2787 pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
2789 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
2790 if (collect_pad->track->xiph_headers_to_skip > 0) {
2791 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
2792 gst_buffer_unref (buf);
2793 --collect_pad->track->xiph_headers_to_skip;
2797 /* for dirac we have to queue up everything up to a picture unit */
2798 if (collect_pad->track->codec_id != NULL &&
2799 strcmp (collect_pad->track->codec_id,
2800 GST_MATROSKA_CODEC_ID_VIDEO_DIRAC) == 0) {
2801 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
2806 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
2807 * this would wreak havoc with time stored in matroska file */
2808 /* TODO: maybe calculate a timestamp by using the previous timestamp
2809 * and default duration */
2810 if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2811 GST_WARNING_OBJECT (collect_pad->collect.pad,
2812 "Invalid buffer timestamp; dropping buffer");
2813 gst_buffer_unref (buf);
2817 /* set the timestamp for outgoing buffers */
2818 ebml->timestamp = GST_BUFFER_TIMESTAMP (buf);
2820 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
2821 !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
2822 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
2823 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2824 is_video_keyframe = TRUE;
2828 /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
2829 * or when we may be reaching the limit of the relative timestamp */
2830 if (mux->cluster_time +
2831 mux->max_cluster_duration < GST_BUFFER_TIMESTAMP (buf)
2832 || is_video_keyframe || mux->force_key_unit_event) {
2833 if (!mux->streamable)
2834 gst_ebml_write_master_finish (ebml, mux->cluster);
2836 /* Forward the GstForceKeyUnit event after finishing the cluster */
2837 if (mux->force_key_unit_event) {
2838 gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
2839 mux->force_key_unit_event = NULL;
2842 mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
2843 mux->cluster_pos = ebml->pos;
2844 gst_ebml_write_set_cache (ebml, 0x20);
2846 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2847 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2848 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2850 GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
2851 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2853 gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2854 mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2855 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
2856 mux->prev_cluster_size);
2861 mux->cluster_pos = ebml->pos;
2862 gst_ebml_write_set_cache (ebml, 0x20);
2863 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2864 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2865 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1, mux->time_scale));
2866 gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2867 mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2870 /* update duration of this track */
2871 if (GST_BUFFER_DURATION_IS_VALID (buf))
2872 collect_pad->duration += GST_BUFFER_DURATION (buf);
2874 /* We currently write index entries for all video tracks or for the audio
2875 * track in a single-track audio file. This could be improved by keeping the
2876 * index only for the *first* video track. */
2878 /* TODO: index is useful for every track, should contain the number of
2879 * the block in the cluster which contains the timestamp, should also work
2880 * for files with multiple audio tracks.
2882 if (!mux->streamable &&
2883 (is_video_keyframe ||
2884 ((collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
2885 (mux->num_streams == 1)))) {
2888 if (mux->min_index_interval != 0) {
2889 for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
2890 if (mux->index[last_idx].track == collect_pad->track->num)
2895 if (last_idx < 0 || mux->min_index_interval == 0 ||
2896 (GST_CLOCK_DIFF (mux->index[last_idx].time, GST_BUFFER_TIMESTAMP (buf))
2897 >= mux->min_index_interval)) {
2898 GstMatroskaIndex *idx;
2900 if (mux->num_indexes % 32 == 0) {
2901 mux->index = g_renew (GstMatroskaIndex, mux->index,
2902 mux->num_indexes + 32);
2904 idx = &mux->index[mux->num_indexes++];
2906 idx->pos = mux->cluster_pos;
2907 idx->time = GST_BUFFER_TIMESTAMP (buf);
2908 idx->track = collect_pad->track->num;
2912 /* Check if the duration differs from the default duration. */
2913 write_duration = FALSE;
2915 if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
2916 block_duration = gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
2917 1, mux->time_scale);
2919 /* small difference should be ok. */
2920 if (block_duration > collect_pad->default_duration_scaled + 1 ||
2921 block_duration < collect_pad->default_duration_scaled - 1) {
2922 write_duration = TRUE;
2926 /* write the block, for doctype v2 use SimpleBlock if possible
2927 * one slice (*breath*).
2928 * FIXME: Need to do correct lacing! */
2929 relative_timestamp64 = GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time;
2930 if (relative_timestamp64 >= 0) {
2931 /* round the timestamp */
2932 relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
2934 /* round the timestamp */
2935 relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
2937 relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
2939 if (mux->doctype_version > 1 && !write_duration) {
2941 GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : 0x80;
2944 gst_matroska_mux_create_buffer_header (collect_pad->track,
2945 relative_timestamp, flags);
2946 gst_ebml_write_set_cache (ebml, 0x40);
2947 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
2948 GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
2949 gst_ebml_write_buffer (ebml, hdr);
2950 gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
2951 gst_ebml_write_buffer (ebml, buf);
2953 return gst_ebml_last_write_result (ebml);
2955 gst_ebml_write_set_cache (ebml, GST_BUFFER_SIZE (buf) * 2);
2956 /* write and call order slightly unnatural,
2957 * but avoids seek and minizes pushing */
2958 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
2960 gst_matroska_mux_create_buffer_header (collect_pad->track,
2961 relative_timestamp, 0);
2963 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
2964 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
2965 GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
2966 gst_ebml_write_buffer (ebml, hdr);
2967 gst_ebml_write_master_finish_full (ebml, blockgroup, GST_BUFFER_SIZE (buf));
2968 gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
2969 gst_ebml_write_buffer (ebml, buf);
2971 return gst_ebml_last_write_result (ebml);
2977 * gst_matroska_mux_collected:
2978 * @pads: #GstCollectPads
2979 * @uuser_data: #GstMatroskaMux
2981 * Collectpads callback.
2983 * Returns: #GstFlowReturn
2985 static GstFlowReturn
2986 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
2988 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
2989 GstEbmlWrite *ebml = mux->ebml_write;
2990 GstMatroskaPad *best;
2992 GstFlowReturn ret = GST_FLOW_OK;
2994 GST_DEBUG_OBJECT (mux, "Collected pads");
2996 /* start with a header */
2997 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
2998 if (mux->collect->data == NULL) {
2999 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
3000 ("No input streams configured"));
3001 return GST_FLOW_ERROR;
3003 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
3004 gst_ebml_start_streamheader (ebml);
3005 gst_matroska_mux_start (mux);
3006 gst_matroska_mux_stop_streamheader (mux);
3007 mux->state = GST_MATROSKA_MUX_STATE_DATA;
3011 /* which stream to write from? */
3012 best = gst_matroska_mux_best_pad (mux, &popped);
3014 /* if there is no best pad, we have reached EOS */
3016 /* buffer popped, but none returned means it was clipped */
3019 GST_DEBUG_OBJECT (mux, "No best pad finishing...");
3020 if (!mux->streamable) {
3021 gst_matroska_mux_finish (mux);
3023 GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
3025 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
3026 ret = GST_FLOW_UNEXPECTED;
3029 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
3030 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
3031 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (best->buffer)),
3032 GST_TIME_ARGS (GST_BUFFER_DURATION (best->buffer)));
3034 /* make note of first and last encountered timestamps, so we can calculate
3035 * the actual duration later when we send an updated header on eos */
3036 if (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)) {
3037 GstClockTime start_ts = GST_BUFFER_TIMESTAMP (best->buffer);
3038 GstClockTime end_ts = start_ts;
3040 if (GST_BUFFER_DURATION_IS_VALID (best->buffer))
3041 end_ts += GST_BUFFER_DURATION (best->buffer);
3042 else if (best->track->default_duration)
3043 end_ts += best->track->default_duration;
3045 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
3046 best->end_ts = end_ts;
3048 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
3049 start_ts < best->start_ts))
3050 best->start_ts = start_ts;
3053 /* write one buffer */
3054 ret = gst_matroska_mux_write_data (mux, best);
3055 } while (ret == GST_FLOW_OK && !popped);
3062 * gst_matroska_mux_change_state:
3063 * @element: #GstMatroskaMux
3064 * @transition: State change transition.
3066 * Change the muxer state.
3068 * Returns: #GstStateChangeReturn
3070 static GstStateChangeReturn
3071 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
3073 GstStateChangeReturn ret;
3074 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
3076 switch (transition) {
3077 case GST_STATE_CHANGE_NULL_TO_READY:
3079 case GST_STATE_CHANGE_READY_TO_PAUSED:
3080 gst_collect_pads_start (mux->collect);
3082 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
3084 case GST_STATE_CHANGE_PAUSED_TO_READY:
3085 gst_collect_pads_stop (mux->collect);
3091 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3093 switch (transition) {
3094 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3096 case GST_STATE_CHANGE_PAUSED_TO_READY:
3097 gst_matroska_mux_reset (GST_ELEMENT (mux));
3099 case GST_STATE_CHANGE_READY_TO_NULL:
3109 gst_matroska_mux_set_property (GObject * object,
3110 guint prop_id, const GValue * value, GParamSpec * pspec)
3112 GstMatroskaMux *mux;
3114 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
3115 mux = GST_MATROSKA_MUX (object);
3118 case ARG_WRITING_APP:
3119 if (!g_value_get_string (value)) {
3120 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
3123 g_free (mux->writing_app);
3124 mux->writing_app = g_value_dup_string (value);
3126 case ARG_DOCTYPE_VERSION:
3127 mux->doctype_version = g_value_get_int (value);
3129 case ARG_MIN_INDEX_INTERVAL:
3130 mux->min_index_interval = g_value_get_int64 (value);
3132 case ARG_STREAMABLE:
3133 mux->streamable = g_value_get_boolean (value);
3136 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3142 gst_matroska_mux_get_property (GObject * object,
3143 guint prop_id, GValue * value, GParamSpec * pspec)
3145 GstMatroskaMux *mux;
3147 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
3148 mux = GST_MATROSKA_MUX (object);
3151 case ARG_WRITING_APP:
3152 g_value_set_string (value, mux->writing_app);
3154 case ARG_DOCTYPE_VERSION:
3155 g_value_set_int (value, mux->doctype_version);
3157 case ARG_MIN_INDEX_INTERVAL:
3158 g_value_set_int64 (value, mux->min_index_interval);
3160 case ARG_STREAMABLE:
3161 g_value_set_boolean (value, mux->streamable);
3164 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);