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 "layout = (string) interleaved, "
170 COMMON_AUDIO_CAPS ";"
172 "width = (int) { 8, 16, 24 }, "
173 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
174 "audio/x-pn-realaudio, "
175 "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS "; "
176 "audio/x-wma, " "wmaversion = (int) [ 1, 3 ], "
177 "block_align = (int) [ 0, 65535 ], bitrate = (int) [ 0, 524288 ], "
178 COMMON_AUDIO_CAPS ";"
180 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
182 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]")
185 static GstStaticPadTemplate subtitlesink_templ =
186 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
189 GST_STATIC_CAPS ("subtitle/x-kate"));
191 static GArray *used_uids;
192 G_LOCK_DEFINE_STATIC (used_uids);
194 #define parent_class gst_matroska_mux_parent_class
195 G_DEFINE_TYPE_WITH_CODE (GstMatroskaMux, gst_matroska_mux, GST_TYPE_ELEMENT,
196 G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
198 /* Matroska muxer destructor */
199 static void gst_matroska_mux_finalize (GObject * object);
201 /* Pads collected callback */
203 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data);
206 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
207 GstObject * parent, GstEvent * event);
208 static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
209 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
210 static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
212 /* gst internal change state handler */
213 static GstStateChangeReturn
214 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
216 /* gobject bla bla */
217 static void gst_matroska_mux_set_property (GObject * object,
218 guint prop_id, const GValue * value, GParamSpec * pspec);
219 static void gst_matroska_mux_get_property (GObject * object,
220 guint prop_id, GValue * value, GParamSpec * pspec);
223 static void gst_matroska_mux_reset (GstElement * element);
226 static guint64 gst_matroska_mux_create_uid ();
228 static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
229 GstMatroskaTrackContext * context);
230 static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
231 GstMatroskaTrackContext * context);
232 static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
233 GstMatroskaTrackContext * context);
234 static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
235 GstMatroskaTrackContext * context);
236 static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
237 GstMatroskaTrackContext * context);
239 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
243 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
245 GObjectClass *gobject_class;
246 GstElementClass *gstelement_class;
248 gobject_class = (GObjectClass *) klass;
249 gstelement_class = (GstElementClass *) klass;
251 gst_element_class_add_pad_template (gstelement_class,
252 gst_static_pad_template_get (&videosink_templ));
253 gst_element_class_add_pad_template (gstelement_class,
254 gst_static_pad_template_get (&audiosink_templ));
255 gst_element_class_add_pad_template (gstelement_class,
256 gst_static_pad_template_get (&subtitlesink_templ));
257 gst_element_class_add_pad_template (gstelement_class,
258 gst_static_pad_template_get (&src_templ));
259 gst_element_class_set_details_simple (gstelement_class, "Matroska muxer",
261 "Muxes video/audio/subtitle streams into a matroska stream",
262 "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
264 GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
267 gobject_class->finalize = gst_matroska_mux_finalize;
269 gobject_class->get_property = gst_matroska_mux_get_property;
270 gobject_class->set_property = gst_matroska_mux_set_property;
272 g_object_class_install_property (gobject_class, ARG_WRITING_APP,
273 g_param_spec_string ("writing-app", "Writing application.",
274 "The name the application that creates the matroska file.",
275 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
276 g_object_class_install_property (gobject_class, ARG_DOCTYPE_VERSION,
277 g_param_spec_int ("version", "DocType version",
278 "This parameter determines what Matroska features can be used.",
279 1, 2, DEFAULT_DOCTYPE_VERSION,
280 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
281 g_object_class_install_property (gobject_class, ARG_MIN_INDEX_INTERVAL,
282 g_param_spec_int64 ("min-index-interval", "Minimum time between index "
283 "entries", "An index entry is created every so many nanoseconds.",
284 0, G_MAXINT64, DEFAULT_MIN_INDEX_INTERVAL,
285 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286 g_object_class_install_property (gobject_class, ARG_STREAMABLE,
287 g_param_spec_boolean ("streamable", "Determines whether output should "
288 "be streamable", "If set to true, the output should be as if it is "
289 "to be streamed and hence no indexes written or duration written.",
291 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_STATIC_STRINGS));
293 gstelement_class->change_state =
294 GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
295 gstelement_class->request_new_pad =
296 GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
297 gstelement_class->release_pad =
298 GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
302 * Start of pad option handler code
304 #define DEFAULT_PAD_FRAME_DURATION TRUE
305 #define DEFAULT_PAD_FRAME_DURATION_VP8 FALSE
310 PROP_PAD_FRAME_DURATION
316 gboolean frame_duration;
317 gboolean frame_duration_user;
320 static void gst_matroskamux_pad_class_init (GstPadClass * klass);
323 gst_matroskamux_pad_get_type (void)
325 static GType type = 0;
327 if (G_UNLIKELY (type == 0)) {
328 type = g_type_register_static_simple (GST_TYPE_PAD,
329 g_intern_static_string ("GstMatroskamuxPad"), sizeof (GstPadClass),
330 (GClassInitFunc) gst_matroskamux_pad_class_init,
331 sizeof (GstMatroskamuxPad), NULL, 0);
336 #define GST_TYPE_MATROSKAMUX_PAD (gst_matroskamux_pad_get_type())
337 #define GST_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_MATROSKAMUX_PAD,GstMatroskamuxPad))
338 #define GST_MATROSKAMUX_PAD_CAST(pad) ((GstMatroskamuxPad *) pad)
339 #define GST_IS_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_MATROSKAMUX_PAD))
342 gst_matroskamux_pad_get_property (GObject * object, guint prop_id,
343 GValue * value, GParamSpec * pspec)
345 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
348 case PROP_PAD_FRAME_DURATION:
349 g_value_set_boolean (value, pad->frame_duration);
352 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
358 gst_matroskamux_pad_set_property (GObject * object, guint prop_id,
359 const GValue * value, GParamSpec * pspec)
361 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
364 case PROP_PAD_FRAME_DURATION:
365 pad->frame_duration = g_value_get_boolean (value);
366 pad->frame_duration_user = TRUE;
369 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
375 gst_matroskamux_pad_class_init (GstPadClass * klass)
377 GObjectClass *gobject_class = (GObjectClass *) klass;
379 gobject_class->set_property = gst_matroskamux_pad_set_property;
380 gobject_class->get_property = gst_matroskamux_pad_get_property;
382 g_object_class_install_property (gobject_class, PROP_PAD_FRAME_DURATION,
383 g_param_spec_boolean ("frame-duration", "Frame duration",
384 "Default frame duration", DEFAULT_PAD_FRAME_DURATION,
385 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
389 gst_matroskamux_pad_init (GstMatroskamuxPad * pad)
391 pad->frame_duration = DEFAULT_PAD_FRAME_DURATION;
392 pad->frame_duration_user = FALSE;
396 * End of pad option handler code
400 * gst_matroska_mux_init:
401 * @mux: #GstMatroskaMux that should be initialized.
402 * @g_class: Class of the muxer.
404 * Matroska muxer constructor.
407 gst_matroska_mux_init (GstMatroskaMux * mux)
409 GstPadTemplate *templ;
412 gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (mux), "src");
413 mux->srcpad = gst_pad_new_from_template (templ, "src");
415 gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
416 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
418 mux->collect = gst_collect_pads_new ();
419 gst_collect_pads_set_function (mux->collect,
420 (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_matroska_mux_collected),
423 mux->ebml_write = gst_ebml_write_new (mux->srcpad);
424 mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
426 /* property defaults */
427 mux->doctype_version = DEFAULT_DOCTYPE_VERSION;
428 mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
429 mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
430 mux->streamable = DEFAULT_STREAMABLE;
432 /* initialize internal variables */
434 mux->num_streams = 0;
435 mux->num_a_streams = 0;
436 mux->num_t_streams = 0;
437 mux->num_v_streams = 0;
439 /* initialize remaining variables */
440 gst_matroska_mux_reset (GST_ELEMENT (mux));
445 * gst_matroska_mux_finalize:
446 * @object: #GstMatroskaMux that should be finalized.
448 * Finalize matroska muxer.
451 gst_matroska_mux_finalize (GObject * object)
453 GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
455 gst_event_replace (&mux->force_key_unit_event, NULL);
457 gst_object_unref (mux->collect);
458 gst_object_unref (mux->ebml_write);
459 if (mux->writing_app)
460 g_free (mux->writing_app);
462 G_OBJECT_CLASS (parent_class)->finalize (object);
467 * gst_matroska_mux_create_uid:
469 * Generate new unused track UID.
471 * Returns: New track UID.
474 gst_matroska_mux_create_uid (void)
481 used_uids = g_array_sized_new (FALSE, FALSE, sizeof (guint64), 10);
486 uid = (((guint64) g_random_int ()) << 32) | g_random_int ();
487 for (i = 0; i < used_uids->len; i++) {
488 if (g_array_index (used_uids, guint64, i) == uid) {
493 g_array_append_val (used_uids, uid);
496 G_UNLOCK (used_uids);
502 * gst_matroska_pad_reset:
503 * @collect_pad: the #GstMatroskaPad
505 * Reset and/or release resources of a matroska collect pad.
508 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
511 GstMatroskaTrackType type = 0;
513 /* free track information */
514 if (collect_pad->track != NULL) {
515 /* retrieve for optional later use */
516 name = collect_pad->track->name;
517 type = collect_pad->track->type;
518 /* extra for video */
519 if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
520 GstMatroskaTrackVideoContext *ctx =
521 (GstMatroskaTrackVideoContext *) collect_pad->track;
523 if (ctx->dirac_unit) {
524 gst_buffer_unref (ctx->dirac_unit);
525 ctx->dirac_unit = NULL;
528 g_free (collect_pad->track->codec_id);
529 g_free (collect_pad->track->codec_name);
531 g_free (collect_pad->track->name);
532 g_free (collect_pad->track->language);
533 g_free (collect_pad->track->codec_priv);
534 g_free (collect_pad->track);
535 collect_pad->track = NULL;
538 /* free cached buffer */
539 if (collect_pad->buffer != NULL) {
540 gst_buffer_unref (collect_pad->buffer);
541 collect_pad->buffer = NULL;
544 if (!full && type != 0) {
545 GstMatroskaTrackContext *context;
547 /* create a fresh context */
549 case GST_MATROSKA_TRACK_TYPE_VIDEO:
550 context = (GstMatroskaTrackContext *)
551 g_new0 (GstMatroskaTrackVideoContext, 1);
553 case GST_MATROSKA_TRACK_TYPE_AUDIO:
554 context = (GstMatroskaTrackContext *)
555 g_new0 (GstMatroskaTrackAudioContext, 1);
557 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
558 context = (GstMatroskaTrackContext *)
559 g_new0 (GstMatroskaTrackSubtitleContext, 1);
562 g_assert_not_reached ();
566 context->type = type;
567 context->name = name;
568 /* TODO: check default values for the context */
569 context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
570 collect_pad->track = context;
571 collect_pad->buffer = NULL;
572 collect_pad->duration = 0;
573 collect_pad->start_ts = GST_CLOCK_TIME_NONE;
574 collect_pad->end_ts = GST_CLOCK_TIME_NONE;
579 * gst_matroska_pad_free:
580 * @collect_pad: the #GstMatroskaPad
582 * Release resources of a matroska collect pad.
585 gst_matroska_pad_free (GstPad * collect_pad)
587 gst_matroska_pad_reset ((GstMatroskaPad *) collect_pad, TRUE);
592 * gst_matroska_mux_reset:
593 * @element: #GstMatroskaMux that should be reseted.
595 * Reset matroska muxer back to initial state.
598 gst_matroska_mux_reset (GstElement * element)
600 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
603 /* reset EBML write */
604 gst_ebml_write_reset (mux->ebml_write);
607 mux->state = GST_MATROSKA_MUX_STATE_START;
609 /* clean up existing streams */
611 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
612 GstMatroskaPad *collect_pad;
614 collect_pad = (GstMatroskaPad *) walk->data;
616 /* reset collect pad to pristine state */
617 gst_matroska_pad_reset (collect_pad, FALSE);
621 mux->num_indexes = 0;
626 mux->time_scale = GST_MSECOND;
627 mux->max_cluster_duration = G_MAXINT16 * mux->time_scale;
632 mux->cluster_time = 0;
633 mux->cluster_pos = 0;
634 mux->prev_cluster_size = 0;
637 gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
641 * gst_matroska_mux_handle_src_event:
642 * @pad: Pad which received the event.
643 * @event: Received event.
645 * handle events - copied from oggmux without understanding
647 * Returns: #TRUE on success.
650 gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
655 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
659 /* disable seeking for now */
665 return gst_pad_event_default (pad, parent, event);
669 * gst_matroska_mux_handle_sink_event:
670 * @pad: Pad which received the event.
671 * @event: Received event.
673 * handle events - informational ones like tags
675 * Returns: #TRUE on success.
678 gst_matroska_mux_handle_sink_event (GstPad * pad, GstObject * parent,
681 GstMatroskaTrackContext *context;
682 GstMatroskaPad *collect_pad;
683 GstMatroskaMux *mux = GST_MATROSKA_MUX (parent);
687 switch (GST_EVENT_TYPE (event)) {
688 case GST_EVENT_CAPS:{
691 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
692 gst_event_parse_caps (event, &caps);
694 ret = collect_pad->capsfunc (pad, caps);
695 gst_event_unref (event);
702 GST_DEBUG_OBJECT (mux, "received tag event");
703 gst_event_parse_tag (event, &list);
705 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
706 g_assert (collect_pad);
707 context = collect_pad->track;
710 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
711 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
712 const gchar *lang_code;
714 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
716 GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
717 context->language = g_strdup (lang_code);
719 GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
724 /* FIXME: what about stream-specific tags? */
725 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
726 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
728 gst_event_unref (event);
729 /* handled this, don't want collectpads to forward it downstream */
733 case GST_EVENT_SEGMENT:{
734 const GstSegment *segment;
736 gst_event_parse_segment (event, &segment);
737 if (segment->format != GST_FORMAT_TIME) {
739 gst_event_unref (event);
744 case GST_EVENT_CUSTOM_DOWNSTREAM:{
745 const GstStructure *structure;
747 structure = gst_event_get_structure (event);
748 if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
749 gst_event_replace (&mux->force_key_unit_event, NULL);
750 mux->force_key_unit_event = event;
759 /* now GstCollectPads can take care of the rest, e.g. EOS */
761 ret = mux->collect_event (pad, parent, event);
768 * gst_matroska_mux_video_pad_setcaps:
769 * @pad: Pad which got the caps.
772 * Setcaps function for video sink pad.
774 * Returns: #TRUE on success.
777 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
779 GstMatroskaTrackContext *context = NULL;
780 GstMatroskaTrackVideoContext *videocontext;
782 GstMatroskaPad *collect_pad;
783 GstStructure *structure;
784 const gchar *mimetype;
785 const GValue *value = NULL;
786 GstBuffer *codec_buf = NULL;
787 gint width, height, pixel_width, pixel_height;
789 gboolean interlaced = FALSE;
791 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
794 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
795 g_assert (collect_pad);
796 context = collect_pad->track;
798 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
799 videocontext = (GstMatroskaTrackVideoContext *) context;
801 /* gst -> matroska ID'ing */
802 structure = gst_caps_get_structure (caps, 0);
804 mimetype = gst_structure_get_name (structure);
806 if (gst_structure_get_boolean (structure, "interlaced", &interlaced)
808 context->flags |= GST_MATROSKA_VIDEOTRACK_INTERLACED;
810 if (!strcmp (mimetype, "video/x-theora")) {
811 /* we'll extract the details later from the theora identification header */
815 /* get general properties */
816 /* spec says it is mandatory */
817 if (!gst_structure_get_int (structure, "width", &width) ||
818 !gst_structure_get_int (structure, "height", &height))
821 videocontext->pixel_width = width;
822 videocontext->pixel_height = height;
824 /* set vp8 defaults or let user override it */
825 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration_user == FALSE
826 && (!strcmp (mimetype, "video/x-vp8")))
827 GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration =
828 DEFAULT_PAD_FRAME_DURATION_VP8;
830 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
831 && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
833 context->default_duration =
834 gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
835 GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
836 GST_TIME_ARGS (context->default_duration));
838 context->default_duration = 0;
840 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
841 &pixel_width, &pixel_height)) {
842 if (pixel_width > pixel_height) {
843 videocontext->display_width = width * pixel_width / pixel_height;
844 videocontext->display_height = height;
845 } else if (pixel_width < pixel_height) {
846 videocontext->display_width = width;
847 videocontext->display_height = height * pixel_height / pixel_width;
849 videocontext->display_width = 0;
850 videocontext->display_height = 0;
853 videocontext->display_width = 0;
854 videocontext->display_height = 0;
859 videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
860 videocontext->fourcc = 0;
862 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
863 * data and other settings
867 /* extract codec_data, may turn out needed */
868 value = gst_structure_get_value (structure, "codec_data");
870 codec_buf = (GstBuffer *) gst_value_get_buffer (value);
873 if (!strcmp (mimetype, "video/x-raw")) {
875 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
876 fstr = gst_structure_get_string (structure, "format");
877 if (fstr && strlen (fstr) == 4)
878 videocontext->fourcc = GST_STR_FOURCC (fstr);
879 } else if (!strcmp (mimetype, "image/jpeg")) {
880 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
881 } else if (!strcmp (mimetype, "video/x-xvid") /* MS/VfW compatibility cases */
882 ||!strcmp (mimetype, "video/x-huffyuv")
883 || !strcmp (mimetype, "video/x-divx")
884 || !strcmp (mimetype, "video/x-dv")
885 || !strcmp (mimetype, "video/x-h263")
886 || !strcmp (mimetype, "video/x-msmpeg")
887 || !strcmp (mimetype, "video/x-wmv")
888 || !strcmp (mimetype, "image/jpeg")) {
889 gst_riff_strf_vids *bih;
890 gint size = sizeof (gst_riff_strf_vids);
893 if (!strcmp (mimetype, "video/x-xvid"))
894 fourcc = GST_MAKE_FOURCC ('X', 'V', 'I', 'D');
895 else if (!strcmp (mimetype, "video/x-huffyuv"))
896 fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
897 else if (!strcmp (mimetype, "video/x-dv"))
898 fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
899 else if (!strcmp (mimetype, "video/x-h263"))
900 fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
901 else if (!strcmp (mimetype, "video/x-divx")) {
904 gst_structure_get_int (structure, "divxversion", &divxversion);
905 switch (divxversion) {
907 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
910 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
913 fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
916 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
919 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
920 switch (msmpegversion) {
922 fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
925 fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
931 } else if (!strcmp (mimetype, "video/x-wmv")) {
935 fstr = gst_structure_get_string (structure, "format");
936 if (fstr && strlen (fstr) == 4) {
937 fourcc = GST_STR_FOURCC (fstr);
938 } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
939 if (wmvversion == 2) {
940 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
941 } else if (wmvversion == 1) {
942 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
943 } else if (wmvversion == 3) {
944 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
947 } else if (!strcmp (mimetype, "image/jpeg")) {
948 fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
954 bih = g_new0 (gst_riff_strf_vids, 1);
955 GST_WRITE_UINT32_LE (&bih->size, size);
956 GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
957 GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
958 GST_WRITE_UINT32_LE (&bih->compression, fourcc);
959 GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
960 GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
961 GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
962 videocontext->pixel_height * 3);
964 /* process codec private/initialization data, if any */
966 size += gst_buffer_get_size (codec_buf);
967 bih = g_realloc (bih, size);
968 GST_WRITE_UINT32_LE (&bih->size, size);
969 gst_buffer_extract (codec_buf, 0,
970 (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
973 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
974 context->codec_priv = (gpointer) bih;
975 context->codec_priv_size = size;
976 } else if (!strcmp (mimetype, "video/x-h264")) {
977 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
979 if (context->codec_priv != NULL) {
980 g_free (context->codec_priv);
981 context->codec_priv = NULL;
982 context->codec_priv_size = 0;
985 /* Create avcC header */
986 if (codec_buf != NULL) {
987 context->codec_priv_size = gst_buffer_get_size (codec_buf);
988 context->codec_priv = g_malloc0 (context->codec_priv_size);
989 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
991 } else if (!strcmp (mimetype, "video/x-theora")) {
992 const GValue *streamheader;
994 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
996 if (context->codec_priv != NULL) {
997 g_free (context->codec_priv);
998 context->codec_priv = NULL;
999 context->codec_priv_size = 0;
1002 streamheader = gst_structure_get_value (structure, "streamheader");
1003 if (!theora_streamheader_to_codecdata (streamheader, context)) {
1004 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1005 ("theora stream headers missing or malformed"));
1008 } else if (!strcmp (mimetype, "video/x-dirac")) {
1009 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
1010 } else if (!strcmp (mimetype, "video/x-vp8")) {
1011 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VP8);
1012 } else if (!strcmp (mimetype, "video/mpeg")) {
1015 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1016 switch (mpegversion) {
1018 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
1021 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
1024 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
1030 /* global headers may be in codec data */
1031 if (codec_buf != NULL) {
1032 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1033 context->codec_priv = g_malloc0 (context->codec_priv_size);
1034 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1036 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1038 /* can only make it here if preceding case verified it was version 3 */
1039 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
1040 } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
1042 const GValue *mdpr_data;
1044 gst_structure_get_int (structure, "rmversion", &rmversion);
1045 switch (rmversion) {
1047 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
1050 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
1053 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
1056 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
1062 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1063 if (mdpr_data != NULL) {
1064 guint8 *priv_data = NULL;
1065 guint priv_data_size = 0;
1067 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1069 priv_data_size = gst_buffer_get_size (codec_data_buf);
1070 priv_data = g_malloc0 (priv_data_size);
1072 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1074 context->codec_priv = priv_data;
1075 context->codec_priv_size = priv_data_size;
1084 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1085 GST_PAD_NAME (pad), caps);
1090 /* N > 0 to expect a particular number of headers, negative if the
1091 number of headers is variable */
1093 xiphN_streamheader_to_codecdata (const GValue * streamheader,
1094 GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
1096 GstBuffer **buf = NULL;
1099 guint bufi, i, offset, priv_data_size;
1101 if (streamheader == NULL)
1102 goto no_stream_headers;
1104 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1107 bufarr = g_value_peek_pointer (streamheader);
1108 if (bufarr->len <= 0 || bufarr->len > 255) /* at least one header, and count stored in a byte */
1110 if (N > 0 && bufarr->len != N)
1113 context->xiph_headers_to_skip = bufarr->len;
1115 buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1116 for (i = 0; i < bufarr->len; i++) {
1117 GValue *bufval = &g_array_index (bufarr, GValue, i);
1119 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1121 goto wrong_content_type;
1124 buf[i] = g_value_peek_pointer (bufval);
1128 if (bufarr->len > 0) {
1129 for (i = 0; i < bufarr->len - 1; i++) {
1130 priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
1134 for (i = 0; i < bufarr->len; ++i) {
1135 priv_data_size += gst_buffer_get_size (buf[i]);
1138 priv_data = g_malloc0 (priv_data_size);
1140 priv_data[0] = bufarr->len - 1;
1143 if (bufarr->len > 0) {
1144 for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1145 for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
1146 priv_data[offset++] = 0xff;
1148 priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
1152 for (i = 0; i < bufarr->len; ++i) {
1153 gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
1154 offset += gst_buffer_get_size (buf[i]);
1157 context->codec_priv = priv_data;
1158 context->codec_priv_size = priv_data_size;
1161 *p_buf0 = gst_buffer_ref (buf[0]);
1170 GST_WARNING ("required streamheaders missing in sink caps!");
1175 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1176 G_VALUE_TYPE_NAME (streamheader));
1181 GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1186 GST_WARNING ("streamheaders array does not contain GstBuffers");
1192 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1193 GstMatroskaTrackContext * context)
1195 GstBuffer *buf0 = NULL;
1197 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1200 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
1201 GST_WARNING ("First vorbis header too small, ignoring");
1203 if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
1204 GstMatroskaTrackAudioContext *audiocontext;
1207 data = gst_buffer_map (buf0, NULL, NULL, GST_MAP_READ);
1208 hdr = data + 1 + 6 + 4;
1209 audiocontext = (GstMatroskaTrackAudioContext *) context;
1210 audiocontext->channels = GST_READ_UINT8 (hdr);
1211 audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1212 gst_buffer_unmap (buf0, data, -1);
1217 gst_buffer_unref (buf0);
1223 theora_streamheader_to_codecdata (const GValue * streamheader,
1224 GstMatroskaTrackContext * context)
1226 GstBuffer *buf0 = NULL;
1228 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1231 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
1232 GST_WARNING ("First theora header too small, ignoring");
1233 } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
1234 GST_WARNING ("First header not a theora identification header, ignoring");
1236 GstMatroskaTrackVideoContext *videocontext;
1237 guint fps_num, fps_denom, par_num, par_denom;
1240 data = gst_buffer_map (buf0, NULL, NULL, GST_MAP_READ);
1241 hdr = data + 1 + 6 + 3 + 2 + 2;
1243 videocontext = (GstMatroskaTrackVideoContext *) context;
1244 videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1245 videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1246 hdr += 3 + 3 + 1 + 1;
1247 fps_num = GST_READ_UINT32_BE (hdr);
1248 fps_denom = GST_READ_UINT32_BE (hdr + 4);
1249 context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1250 fps_denom, fps_num);
1252 par_num = GST_READ_UINT32_BE (hdr) >> 8;
1253 par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1254 if (par_num > 0 && par_num > 0) {
1255 if (par_num > par_denom) {
1256 videocontext->display_width =
1257 videocontext->pixel_width * par_num / par_denom;
1258 videocontext->display_height = videocontext->pixel_height;
1259 } else if (par_num < par_denom) {
1260 videocontext->display_width = videocontext->pixel_width;
1261 videocontext->display_height =
1262 videocontext->pixel_height * par_denom / par_num;
1264 videocontext->display_width = 0;
1265 videocontext->display_height = 0;
1268 videocontext->display_width = 0;
1269 videocontext->display_height = 0;
1273 gst_buffer_unmap (buf0, data, -1);
1277 gst_buffer_unref (buf0);
1283 kate_streamheader_to_codecdata (const GValue * streamheader,
1284 GstMatroskaTrackContext * context)
1286 GstBuffer *buf0 = NULL;
1288 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1291 if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) { /* Kate ID header is 64 bytes */
1292 GST_WARNING ("First kate header too small, ignoring");
1293 } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
1294 GST_WARNING ("First header not a kate identification header, ignoring");
1298 gst_buffer_unref (buf0);
1304 flac_streamheader_to_codecdata (const GValue * streamheader,
1305 GstMatroskaTrackContext * context)
1312 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1313 GST_WARNING ("No or invalid streamheader field in the caps");
1317 bufarr = g_value_peek_pointer (streamheader);
1318 if (bufarr->len < 2) {
1319 GST_WARNING ("Too few headers in streamheader field");
1323 context->xiph_headers_to_skip = bufarr->len + 1;
1325 bufval = &g_array_index (bufarr, GValue, 0);
1326 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1327 GST_WARNING ("streamheaders array does not contain GstBuffers");
1331 buffer = g_value_peek_pointer (bufval);
1333 /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1334 if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
1335 || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
1336 || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
1337 GST_WARNING ("Invalid streamheader for FLAC");
1341 context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
1342 context->codec_priv = g_malloc (context->codec_priv_size);
1343 gst_buffer_extract (buffer, 9, context->codec_priv, -1);
1345 for (i = 1; i < bufarr->len; i++) {
1347 bufval = &g_array_index (bufarr, GValue, i);
1349 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1350 g_free (context->codec_priv);
1351 context->codec_priv = NULL;
1352 context->codec_priv_size = 0;
1353 GST_WARNING ("streamheaders array does not contain GstBuffers");
1357 buffer = g_value_peek_pointer (bufval);
1359 old_size = context->codec_priv_size;
1360 context->codec_priv_size += gst_buffer_get_size (buffer);
1362 context->codec_priv = g_realloc (context->codec_priv,
1363 context->codec_priv_size);
1364 gst_buffer_extract (buffer, 0,
1365 (guint8 *) context->codec_priv + old_size, -1);
1372 speex_streamheader_to_codecdata (const GValue * streamheader,
1373 GstMatroskaTrackContext * context)
1380 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1381 GST_WARNING ("No or invalid streamheader field in the caps");
1385 bufarr = g_value_peek_pointer (streamheader);
1386 if (bufarr->len != 2) {
1387 GST_WARNING ("Too few headers in streamheader field");
1391 context->xiph_headers_to_skip = bufarr->len + 1;
1393 bufval = &g_array_index (bufarr, GValue, 0);
1394 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1395 GST_WARNING ("streamheaders array does not contain GstBuffers");
1399 buffer = g_value_peek_pointer (bufval);
1401 if (gst_buffer_get_size (buffer) < 80
1402 || gst_buffer_memcmp (buffer, 0, "Speex ", 8) != 0) {
1403 GST_WARNING ("Invalid streamheader for Speex");
1407 context->codec_priv_size = gst_buffer_get_size (buffer);
1408 context->codec_priv = g_malloc (context->codec_priv_size);
1409 gst_buffer_extract (buffer, 0, context->codec_priv, -1);
1411 bufval = &g_array_index (bufarr, GValue, 1);
1413 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1414 g_free (context->codec_priv);
1415 context->codec_priv = NULL;
1416 context->codec_priv_size = 0;
1417 GST_WARNING ("streamheaders array does not contain GstBuffers");
1421 buffer = g_value_peek_pointer (bufval);
1423 old_size = context->codec_priv_size;
1424 context->codec_priv_size += gst_buffer_get_size (buffer);
1425 context->codec_priv = g_realloc (context->codec_priv,
1426 context->codec_priv_size);
1427 gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
1432 static const gchar *
1433 aac_codec_data_to_codec_id (GstBuffer * buf)
1435 const gchar *result;
1438 /* default to MAIN */
1441 if (gst_buffer_get_size (buf) >= 2) {
1442 gst_buffer_extract (buf, 0, &profile, 1);
1460 GST_WARNING ("unknown AAC profile, defaulting to MAIN");
1469 * gst_matroska_mux_audio_pad_setcaps:
1470 * @pad: Pad which got the caps.
1473 * Setcaps function for audio sink pad.
1475 * Returns: #TRUE on success.
1478 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1480 GstMatroskaTrackContext *context = NULL;
1481 GstMatroskaTrackAudioContext *audiocontext;
1482 GstMatroskaMux *mux;
1483 GstMatroskaPad *collect_pad;
1484 const gchar *mimetype;
1485 gint samplerate = 0, channels = 0;
1486 GstStructure *structure;
1487 const GValue *codec_data = NULL;
1488 GstBuffer *buf = NULL;
1489 const gchar *stream_format = NULL;
1491 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1494 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1495 g_assert (collect_pad);
1496 context = collect_pad->track;
1498 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
1499 audiocontext = (GstMatroskaTrackAudioContext *) context;
1501 structure = gst_caps_get_structure (caps, 0);
1502 mimetype = gst_structure_get_name (structure);
1505 gst_structure_get_int (structure, "rate", &samplerate);
1506 gst_structure_get_int (structure, "channels", &channels);
1508 audiocontext->samplerate = samplerate;
1509 audiocontext->channels = channels;
1510 audiocontext->bitdepth = 0;
1511 context->default_duration = 0;
1513 codec_data = gst_structure_get_value (structure, "codec_data");
1515 buf = gst_value_get_buffer (codec_data);
1517 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1518 * data and other settings
1522 if (!strcmp (mimetype, "audio/mpeg")) {
1523 gint mpegversion = 0;
1525 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1526 switch (mpegversion) {
1532 gst_structure_get_int (structure, "layer", &layer);
1534 if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
1535 GST_WARNING_OBJECT (mux,
1536 "Unable to determine MPEG audio version, assuming 1");
1542 else if (layer == 2)
1544 else if (version == 2)
1549 context->default_duration =
1550 gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
1554 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
1557 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
1560 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
1569 stream_format = gst_structure_get_string (structure, "stream-format");
1570 /* check this is raw aac */
1571 if (stream_format) {
1572 if (strcmp (stream_format, "raw") != 0) {
1573 GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
1577 GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
1582 if (mpegversion == 2)
1584 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2 "%s",
1585 aac_codec_data_to_codec_id (buf));
1586 else if (mpegversion == 4)
1588 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4 "%s",
1589 aac_codec_data_to_codec_id (buf));
1591 g_assert_not_reached ();
1593 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
1600 } else if (!strcmp (mimetype, "audio/x-raw")) {
1603 gst_audio_info_init (&info);
1604 if (!gst_audio_info_from_caps (&info, caps)) {
1605 GST_DEBUG_OBJECT (mux,
1606 "broken caps, rejected by gst_audio_info_from_caps");
1610 switch (GST_AUDIO_INFO_FORMAT (&info)) {
1611 case GST_AUDIO_FORMAT_U8:
1612 case GST_AUDIO_FORMAT_S16BE:
1613 case GST_AUDIO_FORMAT_S16LE:
1614 case GST_AUDIO_FORMAT_S24BE:
1615 case GST_AUDIO_FORMAT_S24LE:
1616 case GST_AUDIO_FORMAT_S32BE:
1617 case GST_AUDIO_FORMAT_S32LE:
1618 if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
1619 GST_DEBUG_OBJECT (mux, "width must be same as depth!");
1622 if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
1623 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
1625 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
1628 case GST_AUDIO_FORMAT_F32LE:
1629 case GST_AUDIO_FORMAT_F64LE:
1630 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
1634 GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
1638 audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
1640 } else if (!strcmp (mimetype, "audio/x-vorbis")) {
1641 const GValue *streamheader;
1643 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
1645 if (context->codec_priv != NULL) {
1646 g_free (context->codec_priv);
1647 context->codec_priv = NULL;
1648 context->codec_priv_size = 0;
1651 streamheader = gst_structure_get_value (structure, "streamheader");
1652 if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
1653 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1654 ("vorbis stream headers missing or malformed"));
1657 } else if (!strcmp (mimetype, "audio/x-flac")) {
1658 const GValue *streamheader;
1660 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
1661 if (context->codec_priv != NULL) {
1662 g_free (context->codec_priv);
1663 context->codec_priv = NULL;
1664 context->codec_priv_size = 0;
1667 streamheader = gst_structure_get_value (structure, "streamheader");
1668 if (!flac_streamheader_to_codecdata (streamheader, context)) {
1669 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1670 ("flac stream headers missing or malformed"));
1673 } else if (!strcmp (mimetype, "audio/x-speex")) {
1674 const GValue *streamheader;
1676 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
1677 if (context->codec_priv != NULL) {
1678 g_free (context->codec_priv);
1679 context->codec_priv = NULL;
1680 context->codec_priv_size = 0;
1683 streamheader = gst_structure_get_value (structure, "streamheader");
1684 if (!speex_streamheader_to_codecdata (streamheader, context)) {
1685 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1686 ("speex stream headers missing or malformed"));
1689 } else if (!strcmp (mimetype, "audio/x-ac3")) {
1690 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AC3);
1691 } else if (!strcmp (mimetype, "audio/x-eac3")) {
1692 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
1693 } else if (!strcmp (mimetype, "audio/x-dts")) {
1694 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_DTS);
1695 } else if (!strcmp (mimetype, "audio/x-tta")) {
1698 /* TTA frame duration */
1699 context->default_duration = 1.04489795918367346939 * GST_SECOND;
1701 gst_structure_get_int (structure, "width", &width);
1702 audiocontext->bitdepth = width;
1703 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_TTA);
1705 } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
1707 const GValue *mdpr_data;
1709 gst_structure_get_int (structure, "raversion", &raversion);
1710 switch (raversion) {
1712 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
1715 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
1718 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
1724 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1725 if (mdpr_data != NULL) {
1726 guint8 *priv_data = NULL;
1727 guint priv_data_size = 0;
1729 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1731 priv_data_size = gst_buffer_get_size (codec_data_buf);
1732 priv_data = g_malloc0 (priv_data_size);
1734 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1736 context->codec_priv = priv_data;
1737 context->codec_priv_size = priv_data_size;
1740 } else if (!strcmp (mimetype, "audio/x-wma")
1741 || !strcmp (mimetype, "audio/x-alaw")
1742 || !strcmp (mimetype, "audio/x-mulaw")) {
1744 guint codec_priv_size;
1749 if (samplerate == 0 || channels == 0) {
1750 GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
1754 if (!strcmp (mimetype, "audio/x-wma")) {
1758 if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
1759 || !gst_structure_get_int (structure, "block_align", &block_align)
1760 || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
1761 GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
1766 switch (wmaversion) {
1768 format = GST_RIFF_WAVE_FORMAT_WMAV1;
1771 format = GST_RIFF_WAVE_FORMAT_WMAV2;
1774 format = GST_RIFF_WAVE_FORMAT_WMAV3;
1777 GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
1781 if (gst_structure_get_int (structure, "depth", &depth))
1782 audiocontext->bitdepth = depth;
1783 } else if (!strcmp (mimetype, "audio/x-alaw")
1784 || !strcmp (mimetype, "audio/x-mulaw")) {
1785 audiocontext->bitdepth = 8;
1786 if (!strcmp (mimetype, "audio/x-alaw"))
1787 format = GST_RIFF_WAVE_FORMAT_ALAW;
1789 format = GST_RIFF_WAVE_FORMAT_MULAW;
1791 block_align = channels;
1792 bitrate = block_align * samplerate;
1794 g_assert (format != 0);
1796 codec_priv_size = WAVEFORMATEX_SIZE;
1798 codec_priv_size += gst_buffer_get_size (buf);
1800 /* serialize waveformatex structure */
1801 codec_priv = g_malloc0 (codec_priv_size);
1802 GST_WRITE_UINT16_LE (codec_priv, format);
1803 GST_WRITE_UINT16_LE (codec_priv + 2, channels);
1804 GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
1805 GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
1806 GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
1807 GST_WRITE_UINT16_LE (codec_priv + 14, 0);
1809 GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
1811 GST_WRITE_UINT16_LE (codec_priv + 16, 0);
1813 /* process codec private/initialization data, if any */
1815 gst_buffer_extract (buf, 0,
1816 (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
1819 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_ACM);
1820 context->codec_priv = (gpointer) codec_priv;
1821 context->codec_priv_size = codec_priv_size;
1829 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1830 GST_PAD_NAME (pad), caps);
1837 * gst_matroska_mux_subtitle_pad_setcaps:
1838 * @pad: Pad which got the caps.
1841 * Setcaps function for subtitle sink pad.
1843 * Returns: #TRUE on success.
1846 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
1849 * Consider this as boilerplate code for now. There is
1850 * no single subtitle creation element in GStreamer,
1851 * neither do I know how subtitling works at all. */
1853 /* There is now (at least) one such alement (kateenc), and I'm going
1854 to handle it here and claim it works when it can be piped back
1855 through GStreamer and VLC */
1857 GstMatroskaTrackContext *context = NULL;
1858 GstMatroskaTrackSubtitleContext *scontext;
1859 GstMatroskaMux *mux;
1860 GstMatroskaPad *collect_pad;
1861 const gchar *mimetype;
1862 GstStructure *structure;
1864 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1867 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1868 g_assert (collect_pad);
1869 context = collect_pad->track;
1871 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
1872 scontext = (GstMatroskaTrackSubtitleContext *) context;
1874 structure = gst_caps_get_structure (caps, 0);
1875 mimetype = gst_structure_get_name (structure);
1878 scontext->check_utf8 = 1;
1879 scontext->invalid_utf8 = 0;
1880 context->default_duration = 0;
1882 /* TODO: - other format than Kate */
1884 if (!strcmp (mimetype, "subtitle/x-kate")) {
1885 const GValue *streamheader;
1887 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
1889 if (context->codec_priv != NULL) {
1890 g_free (context->codec_priv);
1891 context->codec_priv = NULL;
1892 context->codec_priv_size = 0;
1895 streamheader = gst_structure_get_value (structure, "streamheader");
1896 if (!kate_streamheader_to_codecdata (streamheader, context)) {
1897 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1898 ("kate stream headers missing or malformed"));
1909 * gst_matroska_mux_request_new_pad:
1910 * @element: #GstMatroskaMux.
1911 * @templ: #GstPadTemplate.
1912 * @pad_name: New pad name.
1914 * Request pad function for sink templates.
1916 * Returns: New #GstPad.
1919 gst_matroska_mux_request_new_pad (GstElement * element,
1920 GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
1922 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
1923 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
1924 GstMatroskaPad *collect_pad;
1925 GstMatroskamuxPad *newpad;
1927 const gchar *pad_name = NULL;
1928 GstMatroskaCapsFunc capsfunc = NULL;
1929 GstMatroskaTrackContext *context = NULL;
1932 if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
1933 /* don't mix named and unnamed pads, if the pad already exists we fail when
1934 * trying to add it */
1935 if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
1936 pad_name = req_name;
1938 name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
1941 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
1942 context = (GstMatroskaTrackContext *)
1943 g_new0 (GstMatroskaTrackAudioContext, 1);
1944 context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
1945 context->name = g_strdup ("Audio");
1946 } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
1947 /* don't mix named and unnamed pads, if the pad already exists we fail when
1948 * trying to add it */
1949 if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
1950 pad_name = req_name;
1952 name = g_strdup_printf ("video_%u", mux->num_v_streams++);
1955 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
1956 context = (GstMatroskaTrackContext *)
1957 g_new0 (GstMatroskaTrackVideoContext, 1);
1958 context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
1959 context->name = g_strdup ("Video");
1960 } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
1961 /* don't mix named and unnamed pads, if the pad already exists we fail when
1962 * trying to add it */
1963 if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
1964 pad_name = req_name;
1966 name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
1969 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
1970 context = (GstMatroskaTrackContext *)
1971 g_new0 (GstMatroskaTrackSubtitleContext, 1);
1972 context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
1973 context->name = g_strdup ("Subtitle");
1975 GST_WARNING_OBJECT (mux, "This is not our template!");
1979 newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
1980 "name", pad_name, "direction", templ->direction, "template", templ, NULL);
1983 gst_matroskamux_pad_init (newpad);
1984 collect_pad = (GstMatroskaPad *)
1985 gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad),
1986 sizeof (GstMatroskaPad),
1987 (GstCollectDataDestroyNotify) gst_matroska_pad_free);
1989 collect_pad->track = context;
1990 gst_matroska_pad_reset (collect_pad, FALSE);
1992 /* FIXME: hacked way to override/extend the event function of
1993 * GstCollectPads; because it sets its own event function giving the
1994 * element no access to events.
1995 * TODO GstCollectPads should really give its 'users' a clean chance to
1996 * properly handle events that are not meant for collectpads itself.
1997 * Perhaps a callback or so, though rejected (?) in #340060.
1998 * This would allow (clean) transcoding of info from demuxer/streams
1999 * to another muxer */
2000 mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
2001 gst_pad_set_event_function (GST_PAD (newpad),
2002 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event));
2004 collect_pad->capsfunc = capsfunc;
2005 gst_pad_set_active (GST_PAD (newpad), TRUE);
2006 if (!gst_element_add_pad (element, GST_PAD (newpad)))
2007 goto pad_add_failed;
2011 GST_DEBUG_OBJECT (newpad, "Added new request pad");
2013 return GST_PAD (newpad);
2018 GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
2019 gst_object_unref (newpad);
2025 * gst_matroska_mux_release_pad:
2026 * @element: #GstMatroskaMux.
2027 * @pad: Pad to release.
2029 * Release a previously requested pad.
2032 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
2034 GstMatroskaMux *mux;
2037 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2039 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
2040 GstCollectData *cdata = (GstCollectData *) walk->data;
2041 GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
2043 if (cdata->pad == pad) {
2044 GstClockTime min_dur; /* observed minimum duration */
2046 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2047 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2048 min_dur = GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2049 if (collect_pad->duration < min_dur)
2050 collect_pad->duration = min_dur;
2053 if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
2054 mux->duration < collect_pad->duration)
2055 mux->duration = collect_pad->duration;
2061 gst_collect_pads_remove_pad (mux->collect, pad);
2062 if (gst_element_remove_pad (element, pad))
2068 * gst_matroska_mux_track_header:
2069 * @mux: #GstMatroskaMux
2070 * @context: Tack context.
2072 * Write a track header.
2075 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2076 GstMatroskaTrackContext * context)
2078 GstEbmlWrite *ebml = mux->ebml_write;
2081 /* TODO: check if everything necessary is written and check default values */
2083 /* track type goes before the type-specific stuff */
2084 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2085 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2087 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID,
2088 gst_matroska_mux_create_uid ());
2089 if (context->default_duration) {
2090 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2091 context->default_duration);
2093 if (context->language) {
2094 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2098 /* type-specific stuff */
2099 switch (context->type) {
2100 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2101 GstMatroskaTrackVideoContext *videocontext =
2102 (GstMatroskaTrackVideoContext *) context;
2104 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2105 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2106 videocontext->pixel_width);
2107 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2108 videocontext->pixel_height);
2109 if (videocontext->display_width && videocontext->display_height) {
2110 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2111 videocontext->display_width);
2112 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2113 videocontext->display_height);
2115 if (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED)
2116 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2117 if (videocontext->fourcc) {
2118 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2120 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2121 (gpointer) & fcc_le, 4);
2123 gst_ebml_write_master_finish (ebml, master);
2128 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2129 GstMatroskaTrackAudioContext *audiocontext =
2130 (GstMatroskaTrackAudioContext *) context;
2132 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2133 if (audiocontext->samplerate != 8000)
2134 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2135 audiocontext->samplerate);
2136 if (audiocontext->channels != 1)
2137 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2138 audiocontext->channels);
2139 if (audiocontext->bitdepth) {
2140 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2141 audiocontext->bitdepth);
2143 gst_ebml_write_master_finish (ebml, master);
2149 /* doesn't need type-specific data */
2153 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2154 if (context->codec_priv)
2155 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2156 context->codec_priv, context->codec_priv_size);
2157 /* FIXME: until we have a nice way of getting the codecname
2158 * out of the caps, I'm not going to enable this. Too much
2159 * (useless, double, boring) work... */
2160 /* TODO: Use value from tags if any */
2161 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2162 context->codec_name); */
2163 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2168 * gst_matroska_mux_start:
2169 * @mux: #GstMatroskaMux
2171 * Start a new matroska file (write headers etc...)
2174 gst_matroska_mux_start (GstMatroskaMux * mux)
2176 GstEbmlWrite *ebml = mux->ebml_write;
2177 const gchar *doctype;
2178 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
2179 GST_MATROSKA_ID_TRACKS,
2180 GST_MATROSKA_ID_CUES,
2181 GST_MATROSKA_ID_TAGS,
2184 guint64 master, child;
2188 GstClockTime duration = 0;
2189 guint32 segment_uid[4];
2190 GTimeVal time = { 0, 0 };
2192 if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2193 ebml->caps = gst_caps_new_empty_simple ("video/webm");
2195 ebml->caps = gst_caps_new_empty_simple ("video/x-matroska");
2197 /* we start with a EBML header */
2198 doctype = mux->doctype;
2199 GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
2200 doctype, mux->doctype_version);
2201 gst_ebml_write_header (ebml, doctype, mux->doctype_version);
2203 /* the rest of the header is cached */
2204 gst_ebml_write_set_cache (ebml, 0x1000);
2206 /* start a segment */
2208 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
2209 mux->segment_master = ebml->pos;
2211 if (!mux->streamable) {
2212 /* seekhead (table of contents) - we set the positions later */
2213 mux->seekhead_pos = ebml->pos;
2214 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
2215 for (i = 0; seekhead_id[i] != 0; i++) {
2216 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
2217 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
2218 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
2219 gst_ebml_write_master_finish (ebml, child);
2221 gst_ebml_write_master_finish (ebml, master);
2224 if (mux->streamable) {
2225 const GstTagList *tags;
2228 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2230 if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2231 guint64 master_tags, master_tag;
2233 GST_DEBUG ("Writing tags");
2235 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2236 mux->tags_pos = ebml->pos;
2237 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2238 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2239 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2240 gst_ebml_write_master_finish (ebml, master_tag);
2241 gst_ebml_write_master_finish (ebml, master_tags);
2246 mux->info_pos = ebml->pos;
2247 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
2248 for (i = 0; i < 4; i++) {
2249 segment_uid[i] = g_random_int ();
2251 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
2252 (guint8 *) segment_uid, 16);
2253 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
2254 mux->duration_pos = ebml->pos;
2256 if (!mux->streamable) {
2257 for (collected = mux->collect->data; collected;
2258 collected = g_slist_next (collected)) {
2259 GstMatroskaPad *collect_pad;
2261 gint64 trackduration;
2263 collect_pad = (GstMatroskaPad *) collected->data;
2264 thepad = collect_pad->collect.pad;
2266 /* Query the total length of the track. */
2267 GST_DEBUG_OBJECT (thepad, "querying peer duration");
2268 if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
2269 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
2270 GST_TIME_ARGS (trackduration));
2271 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
2272 duration = (GstClockTime) trackduration;
2276 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2277 gst_guint64_to_gdouble (duration) /
2278 gst_guint64_to_gdouble (mux->time_scale));
2280 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
2281 "GStreamer plugin version " PACKAGE_VERSION);
2282 if (mux->writing_app && mux->writing_app[0]) {
2283 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
2285 g_get_current_time (&time);
2286 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
2287 gst_ebml_write_master_finish (ebml, master);
2290 mux->tracks_pos = ebml->pos;
2291 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
2293 for (collected = mux->collect->data; collected;
2294 collected = g_slist_next (collected)) {
2295 GstMatroskaPad *collect_pad;
2298 collect_pad = (GstMatroskaPad *) collected->data;
2299 thepad = collect_pad->collect.pad;
2301 if (gst_pad_is_linked (thepad) && gst_pad_is_active (thepad) &&
2302 collect_pad->track->codec_id != 0) {
2303 collect_pad->track->num = tracknum++;
2304 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
2305 gst_matroska_mux_track_header (mux, collect_pad->track);
2306 gst_ebml_write_master_finish (ebml, child);
2307 /* some remaing pad/track setup */
2308 collect_pad->default_duration_scaled =
2309 gst_util_uint64_scale (collect_pad->track->default_duration,
2310 1, mux->time_scale);
2313 gst_ebml_write_master_finish (ebml, master);
2315 /* lastly, flush the cache */
2316 gst_ebml_write_flush_cache (ebml, FALSE, 0);
2320 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
2323 /* TODO: more sensible tag mappings */
2326 const gchar *matroska_tagname;
2327 const gchar *gstreamer_tagname;
2331 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
2332 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
2333 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
2334 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
2335 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
2336 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
2337 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
2338 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
2339 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
2340 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
2341 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
2342 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
2343 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
2344 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
2345 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
2347 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
2349 guint64 simpletag_master;
2351 for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) {
2352 const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
2353 const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
2355 if (strcmp (tagname_gst, tag) == 0) {
2356 GValue src = { 0, };
2359 if (!gst_tag_list_copy_value (&src, list, tag))
2361 if ((dest = gst_value_serialize (&src))) {
2363 simpletag_master = gst_ebml_write_master_start (ebml,
2364 GST_MATROSKA_ID_SIMPLETAG);
2365 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
2366 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
2367 gst_ebml_write_master_finish (ebml, simpletag_master);
2370 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
2372 g_value_unset (&src);
2380 * gst_matroska_mux_finish:
2381 * @mux: #GstMatroskaMux
2383 * Finish a new matroska file (write index etc...)
2386 gst_matroska_mux_finish (GstMatroskaMux * mux)
2388 GstEbmlWrite *ebml = mux->ebml_write;
2390 guint64 duration = 0;
2392 const GstTagList *tags;
2394 /* finish last cluster */
2396 gst_ebml_write_master_finish (ebml, mux->cluster);
2400 if (mux->index != NULL) {
2402 guint64 master, pointentry_master, trackpos_master;
2404 mux->cues_pos = ebml->pos;
2405 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
2406 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
2408 for (n = 0; n < mux->num_indexes; n++) {
2409 GstMatroskaIndex *idx = &mux->index[n];
2411 pointentry_master = gst_ebml_write_master_start (ebml,
2412 GST_MATROSKA_ID_POINTENTRY);
2413 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
2414 idx->time / mux->time_scale);
2415 trackpos_master = gst_ebml_write_master_start (ebml,
2416 GST_MATROSKA_ID_CUETRACKPOSITIONS);
2417 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
2418 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
2419 idx->pos - mux->segment_master);
2420 gst_ebml_write_master_finish (ebml, trackpos_master);
2421 gst_ebml_write_master_finish (ebml, pointentry_master);
2424 gst_ebml_write_master_finish (ebml, master);
2425 gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
2429 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2431 if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2432 guint64 master_tags, master_tag;
2434 GST_DEBUG ("Writing tags");
2436 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2437 mux->tags_pos = ebml->pos;
2438 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2439 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2440 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2441 gst_ebml_write_master_finish (ebml, master_tag);
2442 gst_ebml_write_master_finish (ebml, master_tags);
2445 /* update seekhead. We know that:
2446 * - a seekhead contains 4 entries.
2447 * - order of entries is as above.
2448 * - a seekhead has a 4-byte header + 8-byte length
2449 * - each entry is 2-byte master, 2-byte ID pointer,
2450 * 2-byte length pointer, all 8/1-byte length, 4-
2451 * byte ID and 8-byte length pointer, where the
2452 * length pointer starts at 20.
2453 * - all entries are local to the segment (so pos - segment_master).
2454 * - so each entry is at 12 + 20 + num * 28. */
2455 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
2456 mux->info_pos - mux->segment_master);
2457 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
2458 mux->tracks_pos - mux->segment_master);
2459 if (mux->index != NULL) {
2460 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
2461 mux->cues_pos - mux->segment_master);
2464 guint64 my_pos = ebml->pos;
2466 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
2467 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2468 gst_ebml_write_seek (ebml, my_pos);
2471 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
2472 mux->tags_pos - mux->segment_master);
2475 guint64 my_pos = ebml->pos;
2477 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
2478 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2479 gst_ebml_write_seek (ebml, my_pos);
2482 /* update duration */
2483 /* first get the overall duration */
2484 /* a released track may have left a duration in here */
2485 duration = mux->duration;
2486 for (collected = mux->collect->data; collected;
2487 collected = g_slist_next (collected)) {
2488 GstMatroskaPad *collect_pad;
2489 GstClockTime min_duration; /* observed minimum duration */
2491 collect_pad = (GstMatroskaPad *) collected->data;
2493 GST_DEBUG_OBJECT (mux,
2494 "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
2495 " end ts %" GST_TIME_FORMAT, collect_pad,
2496 GST_TIME_ARGS (collect_pad->start_ts),
2497 GST_TIME_ARGS (collect_pad->end_ts));
2499 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2500 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2502 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2503 if (collect_pad->duration < min_duration)
2504 collect_pad->duration = min_duration;
2505 GST_DEBUG_OBJECT (collect_pad,
2506 "final track duration: %" GST_TIME_FORMAT,
2507 GST_TIME_ARGS (collect_pad->duration));
2510 if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
2511 duration < collect_pad->duration)
2512 duration = collect_pad->duration;
2514 if (duration != 0) {
2515 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
2516 GST_TIME_ARGS (duration));
2517 pos = mux->ebml_write->pos;
2518 gst_ebml_write_seek (ebml, mux->duration_pos);
2519 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2520 gst_guint64_to_gdouble (duration) /
2521 gst_guint64_to_gdouble (mux->time_scale));
2522 gst_ebml_write_seek (ebml, pos);
2525 guint64 my_pos = ebml->pos;
2527 gst_ebml_write_seek (ebml, mux->duration_pos);
2528 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
2529 gst_ebml_write_seek (ebml, my_pos);
2531 GST_DEBUG_OBJECT (mux, "finishing segment");
2532 /* finish segment - this also writes element length */
2533 gst_ebml_write_master_finish (ebml, mux->segment_pos);
2538 * gst_matroska_mux_best_pad:
2539 * @mux: #GstMatroskaMux
2540 * @popped: True if at least one buffer was popped from #GstCollectPads
2542 * Find a pad with the oldest data
2543 * (data from this pad should be written first).
2545 * Returns: Selected pad.
2547 static GstMatroskaPad *
2548 gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
2551 GstMatroskaPad *best = NULL;
2554 for (collected = mux->collect->data; collected;
2555 collected = g_slist_next (collected)) {
2556 GstMatroskaPad *collect_pad;
2558 collect_pad = (GstMatroskaPad *) collected->data;
2559 /* fetch a new buffer if needed */
2560 if (collect_pad->buffer == NULL) {
2561 collect_pad->buffer = gst_collect_pads_pop (mux->collect,
2562 (GstCollectData *) collect_pad);
2564 if (collect_pad->buffer != NULL) {
2568 /* convert to running time */
2569 time = GST_BUFFER_TIMESTAMP (collect_pad->buffer);
2570 /* invalid should pass */
2571 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
2572 time = gst_segment_to_running_time (&collect_pad->collect.segment,
2573 GST_FORMAT_TIME, time);
2574 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
2575 GST_DEBUG_OBJECT (mux, "clipping buffer on pad %s outside segment",
2576 GST_PAD_NAME (collect_pad->collect.pad));
2577 gst_buffer_unref (collect_pad->buffer);
2578 collect_pad->buffer = NULL;
2581 GST_LOG_OBJECT (mux, "buffer ts %" GST_TIME_FORMAT " -> %"
2582 GST_TIME_FORMAT " running time",
2583 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (collect_pad->buffer)),
2584 GST_TIME_ARGS (time));
2585 collect_pad->buffer =
2586 gst_buffer_make_writable (collect_pad->buffer);
2587 GST_BUFFER_TIMESTAMP (collect_pad->buffer) = time;
2593 /* if we have a buffer check if it is better then the current best one */
2594 if (collect_pad->buffer != NULL) {
2595 if (best == NULL || !GST_BUFFER_TIMESTAMP_IS_VALID (collect_pad->buffer)
2596 || (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)
2597 && GST_BUFFER_TIMESTAMP (collect_pad->buffer) <
2598 GST_BUFFER_TIMESTAMP (best->buffer))) {
2608 * gst_matroska_mux_buffer_header:
2609 * @track: Track context.
2610 * @relative_timestamp: relative timestamp of the buffer
2611 * @flags: Buffer flags.
2613 * Create a buffer containing buffer header.
2615 * Returns: New buffer.
2618 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
2619 gint16 relative_timestamp, int flags)
2622 guint8 *data = g_malloc (4);
2624 hdr = gst_buffer_new_wrapped (data, 4);
2625 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
2626 data[0] = track->num | 0x80;
2627 /* time relative to clustertime */
2628 GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
2636 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
2637 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
2638 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
2641 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
2642 GstMatroskaPad * collect_pad, GstBuffer * buf)
2644 GstMatroskaTrackVideoContext *ctx =
2645 (GstMatroskaTrackVideoContext *) collect_pad->track;
2646 guint8 *buf_data, *data;
2649 guint32 next_parse_offset;
2650 GstBuffer *ret = NULL;
2651 gboolean is_muxing_unit = FALSE;
2653 buf_data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
2657 gst_buffer_unmap (buf, buf_data, -1);
2658 gst_buffer_unref (buf);
2662 /* Check if this buffer contains a picture or end-of-sequence packet */
2663 while (size >= 13) {
2664 if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
2665 gst_buffer_unmap (buf, buf_data, -1);
2666 gst_buffer_unref (buf);
2670 parse_code = GST_READ_UINT8 (data + 4);
2671 if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
2672 if (ctx->dirac_unit) {
2673 gst_buffer_unref (ctx->dirac_unit);
2674 ctx->dirac_unit = NULL;
2676 } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
2677 parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
2678 is_muxing_unit = TRUE;
2682 next_parse_offset = GST_READ_UINT32_BE (data + 5);
2684 if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
2687 data += next_parse_offset;
2688 size -= next_parse_offset;
2691 if (ctx->dirac_unit)
2692 ctx->dirac_unit = gst_buffer_join (ctx->dirac_unit, gst_buffer_ref (buf));
2694 ctx->dirac_unit = gst_buffer_ref (buf);
2696 gst_buffer_unmap (buf, buf_data, -1);
2698 if (is_muxing_unit) {
2699 ret = gst_buffer_make_writable (ctx->dirac_unit);
2700 ctx->dirac_unit = NULL;
2701 gst_buffer_copy_into (ret, buf,
2702 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2703 gst_buffer_unref (buf);
2705 gst_buffer_unref (buf);
2713 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
2717 GValue streamheader = { 0 };
2718 GValue bufval = { 0 };
2719 GstBuffer *streamheader_buffer;
2720 GstEbmlWrite *ebml = mux->ebml_write;
2722 streamheader_buffer = gst_ebml_stop_streamheader (ebml);
2723 if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2724 caps = gst_caps_new_empty_simple ("video/webm");
2726 caps = gst_caps_new_empty_simple ("video/x-matroska");
2728 s = gst_caps_get_structure (caps, 0);
2729 g_value_init (&streamheader, GST_TYPE_ARRAY);
2730 g_value_init (&bufval, GST_TYPE_BUFFER);
2731 GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_IN_CAPS);
2732 gst_value_set_buffer (&bufval, streamheader_buffer);
2733 gst_value_array_append_value (&streamheader, &bufval);
2734 g_value_unset (&bufval);
2735 gst_structure_set_value (s, "streamheader", &streamheader);
2736 g_value_unset (&streamheader);
2737 gst_caps_replace (&ebml->caps, caps);
2738 gst_buffer_unref (streamheader_buffer);
2739 gst_caps_unref (caps);
2743 * gst_matroska_mux_write_data:
2744 * @mux: #GstMatroskaMux
2745 * @collect_pad: #GstMatroskaPad with the data
2747 * Write collected data (called from gst_matroska_mux_collected).
2749 * Returns: Result of the gst_pad_push issued to write the data.
2751 static GstFlowReturn
2752 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
2754 GstEbmlWrite *ebml = mux->ebml_write;
2755 GstBuffer *buf, *hdr;
2757 gboolean write_duration;
2758 gint16 relative_timestamp;
2759 gint64 relative_timestamp64;
2760 guint64 block_duration;
2761 gboolean is_video_keyframe = FALSE;
2762 GstMatroskamuxPad *pad;
2765 buf = collect_pad->buffer;
2766 collect_pad->buffer = NULL;
2767 pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
2769 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
2770 if (collect_pad->track->xiph_headers_to_skip > 0) {
2771 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
2772 gst_buffer_unref (buf);
2773 --collect_pad->track->xiph_headers_to_skip;
2777 /* for dirac we have to queue up everything up to a picture unit */
2778 if (collect_pad->track->codec_id != NULL &&
2779 strcmp (collect_pad->track->codec_id,
2780 GST_MATROSKA_CODEC_ID_VIDEO_DIRAC) == 0) {
2781 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
2786 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
2787 * this would wreak havoc with time stored in matroska file */
2788 /* TODO: maybe calculate a timestamp by using the previous timestamp
2789 * and default duration */
2790 if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2791 GST_WARNING_OBJECT (collect_pad->collect.pad,
2792 "Invalid buffer timestamp; dropping buffer");
2793 gst_buffer_unref (buf);
2797 /* set the timestamp for outgoing buffers */
2798 ebml->timestamp = GST_BUFFER_TIMESTAMP (buf);
2800 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
2801 !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
2802 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
2803 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2804 is_video_keyframe = TRUE;
2808 /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
2809 * or when we may be reaching the limit of the relative timestamp */
2810 if (mux->cluster_time +
2811 mux->max_cluster_duration < GST_BUFFER_TIMESTAMP (buf)
2812 || is_video_keyframe || mux->force_key_unit_event) {
2813 if (!mux->streamable)
2814 gst_ebml_write_master_finish (ebml, mux->cluster);
2816 /* Forward the GstForceKeyUnit event after finishing the cluster */
2817 if (mux->force_key_unit_event) {
2818 gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
2819 mux->force_key_unit_event = NULL;
2822 mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
2823 mux->cluster_pos = ebml->pos;
2824 gst_ebml_write_set_cache (ebml, 0x20);
2826 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2827 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2828 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2830 GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
2831 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2833 gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2834 mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2835 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
2836 mux->prev_cluster_size);
2841 mux->cluster_pos = ebml->pos;
2842 gst_ebml_write_set_cache (ebml, 0x20);
2843 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2844 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2845 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1, mux->time_scale));
2846 gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2847 mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2850 /* update duration of this track */
2851 if (GST_BUFFER_DURATION_IS_VALID (buf))
2852 collect_pad->duration += GST_BUFFER_DURATION (buf);
2854 /* We currently write index entries for all video tracks or for the audio
2855 * track in a single-track audio file. This could be improved by keeping the
2856 * index only for the *first* video track. */
2858 /* TODO: index is useful for every track, should contain the number of
2859 * the block in the cluster which contains the timestamp, should also work
2860 * for files with multiple audio tracks.
2862 if (!mux->streamable &&
2863 (is_video_keyframe ||
2864 ((collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
2865 (mux->num_streams == 1)))) {
2868 if (mux->min_index_interval != 0) {
2869 for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
2870 if (mux->index[last_idx].track == collect_pad->track->num)
2875 if (last_idx < 0 || mux->min_index_interval == 0 ||
2876 (GST_CLOCK_DIFF (mux->index[last_idx].time, GST_BUFFER_TIMESTAMP (buf))
2877 >= mux->min_index_interval)) {
2878 GstMatroskaIndex *idx;
2880 if (mux->num_indexes % 32 == 0) {
2881 mux->index = g_renew (GstMatroskaIndex, mux->index,
2882 mux->num_indexes + 32);
2884 idx = &mux->index[mux->num_indexes++];
2886 idx->pos = mux->cluster_pos;
2887 idx->time = GST_BUFFER_TIMESTAMP (buf);
2888 idx->track = collect_pad->track->num;
2892 /* Check if the duration differs from the default duration. */
2893 write_duration = FALSE;
2895 if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
2896 block_duration = gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
2897 1, mux->time_scale);
2899 /* small difference should be ok. */
2900 if (block_duration > collect_pad->default_duration_scaled + 1 ||
2901 block_duration < collect_pad->default_duration_scaled - 1) {
2902 write_duration = TRUE;
2906 /* write the block, for doctype v2 use SimpleBlock if possible
2907 * one slice (*breath*).
2908 * FIXME: Need to do correct lacing! */
2909 relative_timestamp64 = GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time;
2910 if (relative_timestamp64 >= 0) {
2911 /* round the timestamp */
2912 relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
2914 /* round the timestamp */
2915 relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
2917 relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
2919 if (mux->doctype_version > 1 && !write_duration) {
2921 GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : 0x80;
2924 gst_matroska_mux_create_buffer_header (collect_pad->track,
2925 relative_timestamp, flags);
2926 gst_ebml_write_set_cache (ebml, 0x40);
2927 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
2928 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
2929 gst_ebml_write_buffer (ebml, hdr);
2930 gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
2931 gst_ebml_write_buffer (ebml, buf);
2933 return gst_ebml_last_write_result (ebml);
2935 gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
2936 /* write and call order slightly unnatural,
2937 * but avoids seek and minizes pushing */
2938 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
2940 gst_matroska_mux_create_buffer_header (collect_pad->track,
2941 relative_timestamp, 0);
2943 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
2944 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
2945 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
2946 gst_ebml_write_buffer (ebml, hdr);
2947 gst_ebml_write_master_finish_full (ebml, blockgroup,
2948 gst_buffer_get_size (buf));
2949 gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
2950 gst_ebml_write_buffer (ebml, buf);
2952 return gst_ebml_last_write_result (ebml);
2958 * gst_matroska_mux_collected:
2959 * @pads: #GstCollectPads
2960 * @uuser_data: #GstMatroskaMux
2962 * Collectpads callback.
2964 * Returns: #GstFlowReturn
2966 static GstFlowReturn
2967 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
2969 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
2970 GstEbmlWrite *ebml = mux->ebml_write;
2971 GstMatroskaPad *best;
2973 GstFlowReturn ret = GST_FLOW_OK;
2975 GST_DEBUG_OBJECT (mux, "Collected pads");
2977 /* start with a header */
2978 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
2979 if (mux->collect->data == NULL) {
2980 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2981 ("No input streams configured"));
2982 return GST_FLOW_ERROR;
2984 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
2985 gst_ebml_start_streamheader (ebml);
2986 gst_matroska_mux_start (mux);
2987 gst_matroska_mux_stop_streamheader (mux);
2988 mux->state = GST_MATROSKA_MUX_STATE_DATA;
2992 /* which stream to write from? */
2993 best = gst_matroska_mux_best_pad (mux, &popped);
2995 /* if there is no best pad, we have reached EOS */
2997 /* buffer popped, but none returned means it was clipped */
3000 GST_DEBUG_OBJECT (mux, "No best pad finishing...");
3001 if (!mux->streamable) {
3002 gst_matroska_mux_finish (mux);
3004 GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
3006 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
3010 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
3011 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
3012 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (best->buffer)),
3013 GST_TIME_ARGS (GST_BUFFER_DURATION (best->buffer)));
3015 /* make note of first and last encountered timestamps, so we can calculate
3016 * the actual duration later when we send an updated header on eos */
3017 if (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)) {
3018 GstClockTime start_ts = GST_BUFFER_TIMESTAMP (best->buffer);
3019 GstClockTime end_ts = start_ts;
3021 if (GST_BUFFER_DURATION_IS_VALID (best->buffer))
3022 end_ts += GST_BUFFER_DURATION (best->buffer);
3023 else if (best->track->default_duration)
3024 end_ts += best->track->default_duration;
3026 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
3027 best->end_ts = end_ts;
3029 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
3030 start_ts < best->start_ts))
3031 best->start_ts = start_ts;
3034 /* write one buffer */
3035 ret = gst_matroska_mux_write_data (mux, best);
3036 } while (ret == GST_FLOW_OK && !popped);
3043 * gst_matroska_mux_change_state:
3044 * @element: #GstMatroskaMux
3045 * @transition: State change transition.
3047 * Change the muxer state.
3049 * Returns: #GstStateChangeReturn
3051 static GstStateChangeReturn
3052 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
3054 GstStateChangeReturn ret;
3055 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
3057 switch (transition) {
3058 case GST_STATE_CHANGE_NULL_TO_READY:
3060 case GST_STATE_CHANGE_READY_TO_PAUSED:
3061 gst_collect_pads_start (mux->collect);
3063 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
3065 case GST_STATE_CHANGE_PAUSED_TO_READY:
3066 gst_collect_pads_stop (mux->collect);
3072 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3074 switch (transition) {
3075 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3077 case GST_STATE_CHANGE_PAUSED_TO_READY:
3078 gst_matroska_mux_reset (GST_ELEMENT (mux));
3080 case GST_STATE_CHANGE_READY_TO_NULL:
3090 gst_matroska_mux_set_property (GObject * object,
3091 guint prop_id, const GValue * value, GParamSpec * pspec)
3093 GstMatroskaMux *mux;
3095 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
3096 mux = GST_MATROSKA_MUX (object);
3099 case ARG_WRITING_APP:
3100 if (!g_value_get_string (value)) {
3101 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
3104 g_free (mux->writing_app);
3105 mux->writing_app = g_value_dup_string (value);
3107 case ARG_DOCTYPE_VERSION:
3108 mux->doctype_version = g_value_get_int (value);
3110 case ARG_MIN_INDEX_INTERVAL:
3111 mux->min_index_interval = g_value_get_int64 (value);
3113 case ARG_STREAMABLE:
3114 mux->streamable = g_value_get_boolean (value);
3117 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3123 gst_matroska_mux_get_property (GObject * object,
3124 guint prop_id, GValue * value, GParamSpec * pspec)
3126 GstMatroskaMux *mux;
3128 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
3129 mux = GST_MATROSKA_MUX (object);
3132 case ARG_WRITING_APP:
3133 g_value_set_string (value, mux->writing_app);
3135 case ARG_DOCTYPE_VERSION:
3136 g_value_set_int (value, mux->doctype_version);
3138 case ARG_MIN_INDEX_INTERVAL:
3139 g_value_set_int64 (value, mux->min_index_interval);
3141 case ARG_STREAMABLE:
3142 g_value_set_boolean (value, mux->streamable);
3145 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);