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 "stream-format = (string) { raw }, "
151 COMMON_AUDIO_CAPS "; "
153 "mpegversion = (int) { 2, 4 }, "
154 COMMON_AUDIO_CAPS "; "
156 COMMON_AUDIO_CAPS "; "
158 COMMON_AUDIO_CAPS "; "
160 COMMON_AUDIO_CAPS "; "
162 COMMON_AUDIO_CAPS "; "
164 COMMON_AUDIO_CAPS "; "
166 COMMON_AUDIO_CAPS "; "
168 "format = (string) { U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }, "
169 COMMON_AUDIO_CAPS ";"
171 "width = (int) { 8, 16, 24 }, "
172 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
173 "audio/x-pn-realaudio, "
174 "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS "; "
175 "audio/x-wma, " "wmaversion = (int) [ 1, 3 ], "
176 "block_align = (int) [ 0, 65535 ], bitrate = (int) [ 0, 524288 ], "
177 COMMON_AUDIO_CAPS ";"
179 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
181 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]")
184 static GstStaticPadTemplate subtitlesink_templ =
185 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
188 GST_STATIC_CAPS ("subtitle/x-kate"));
190 static GArray *used_uids;
191 G_LOCK_DEFINE_STATIC (used_uids);
193 #define parent_class gst_matroska_mux_parent_class
194 G_DEFINE_TYPE_WITH_CODE (GstMatroskaMux, gst_matroska_mux, GST_TYPE_ELEMENT,
195 G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
197 /* Matroska muxer destructor */
198 static void gst_matroska_mux_finalize (GObject * object);
200 /* Pads collected callback */
202 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data);
205 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
206 GstObject * parent, GstEvent * event);
207 static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
208 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
209 static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
211 /* gst internal change state handler */
212 static GstStateChangeReturn
213 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
215 /* gobject bla bla */
216 static void gst_matroska_mux_set_property (GObject * object,
217 guint prop_id, const GValue * value, GParamSpec * pspec);
218 static void gst_matroska_mux_get_property (GObject * object,
219 guint prop_id, GValue * value, GParamSpec * pspec);
222 static void gst_matroska_mux_reset (GstElement * element);
225 static guint64 gst_matroska_mux_create_uid ();
227 static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
228 GstMatroskaTrackContext * context);
229 static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
230 GstMatroskaTrackContext * context);
231 static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
232 GstMatroskaTrackContext * context);
233 static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
234 GstMatroskaTrackContext * context);
235 static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
236 GstMatroskaTrackContext * context);
238 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
242 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
244 GObjectClass *gobject_class;
245 GstElementClass *gstelement_class;
247 gobject_class = (GObjectClass *) klass;
248 gstelement_class = (GstElementClass *) klass;
250 gst_element_class_add_pad_template (gstelement_class,
251 gst_static_pad_template_get (&videosink_templ));
252 gst_element_class_add_pad_template (gstelement_class,
253 gst_static_pad_template_get (&audiosink_templ));
254 gst_element_class_add_pad_template (gstelement_class,
255 gst_static_pad_template_get (&subtitlesink_templ));
256 gst_element_class_add_pad_template (gstelement_class,
257 gst_static_pad_template_get (&src_templ));
258 gst_element_class_set_details_simple (gstelement_class, "Matroska muxer",
260 "Muxes video/audio/subtitle streams into a matroska stream",
261 "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
263 GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
266 gobject_class->finalize = gst_matroska_mux_finalize;
268 gobject_class->get_property = gst_matroska_mux_get_property;
269 gobject_class->set_property = gst_matroska_mux_set_property;
271 g_object_class_install_property (gobject_class, ARG_WRITING_APP,
272 g_param_spec_string ("writing-app", "Writing application.",
273 "The name the application that creates the matroska file.",
274 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
275 g_object_class_install_property (gobject_class, ARG_DOCTYPE_VERSION,
276 g_param_spec_int ("version", "DocType version",
277 "This parameter determines what Matroska features can be used.",
278 1, 2, DEFAULT_DOCTYPE_VERSION,
279 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
280 g_object_class_install_property (gobject_class, ARG_MIN_INDEX_INTERVAL,
281 g_param_spec_int64 ("min-index-interval", "Minimum time between index "
282 "entries", "An index entry is created every so many nanoseconds.",
283 0, G_MAXINT64, DEFAULT_MIN_INDEX_INTERVAL,
284 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
285 g_object_class_install_property (gobject_class, ARG_STREAMABLE,
286 g_param_spec_boolean ("streamable", "Determines whether output should "
287 "be streamable", "If set to true, the output should be as if it is "
288 "to be streamed and hence no indexes written or duration written.",
290 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_STATIC_STRINGS));
292 gstelement_class->change_state =
293 GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
294 gstelement_class->request_new_pad =
295 GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
296 gstelement_class->release_pad =
297 GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
302 * gst_matroska_mux_init:
303 * @mux: #GstMatroskaMux that should be initialized.
304 * @g_class: Class of the muxer.
306 * Matroska muxer constructor.
309 gst_matroska_mux_init (GstMatroskaMux * mux)
311 GstPadTemplate *templ;
314 gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (mux), "src");
315 mux->srcpad = gst_pad_new_from_template (templ, "src");
317 gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
318 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
320 mux->collect = gst_collect_pads_new ();
321 gst_collect_pads_set_function (mux->collect,
322 (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_matroska_mux_collected),
325 mux->ebml_write = gst_ebml_write_new (mux->srcpad);
326 mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
328 /* property defaults */
329 mux->doctype_version = DEFAULT_DOCTYPE_VERSION;
330 mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
331 mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
332 mux->streamable = DEFAULT_STREAMABLE;
334 /* initialize internal variables */
336 mux->num_streams = 0;
337 mux->num_a_streams = 0;
338 mux->num_t_streams = 0;
339 mux->num_v_streams = 0;
341 /* initialize remaining variables */
342 gst_matroska_mux_reset (GST_ELEMENT (mux));
347 * gst_matroska_mux_finalize:
348 * @object: #GstMatroskaMux that should be finalized.
350 * Finalize matroska muxer.
353 gst_matroska_mux_finalize (GObject * object)
355 GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
357 gst_event_replace (&mux->force_key_unit_event, NULL);
359 gst_object_unref (mux->collect);
360 gst_object_unref (mux->ebml_write);
361 if (mux->writing_app)
362 g_free (mux->writing_app);
364 G_OBJECT_CLASS (parent_class)->finalize (object);
369 * gst_matroska_mux_create_uid:
371 * Generate new unused track UID.
373 * Returns: New track UID.
376 gst_matroska_mux_create_uid (void)
383 used_uids = g_array_sized_new (FALSE, FALSE, sizeof (guint64), 10);
388 uid = (((guint64) g_random_int ()) << 32) | g_random_int ();
389 for (i = 0; i < used_uids->len; i++) {
390 if (g_array_index (used_uids, guint64, i) == uid) {
395 g_array_append_val (used_uids, uid);
398 G_UNLOCK (used_uids);
404 * gst_matroska_pad_reset:
405 * @collect_pad: the #GstMatroskaPad
407 * Reset and/or release resources of a matroska collect pad.
410 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
413 GstMatroskaTrackType type = 0;
415 /* free track information */
416 if (collect_pad->track != NULL) {
417 /* retrieve for optional later use */
418 name = collect_pad->track->name;
419 type = collect_pad->track->type;
420 /* extra for video */
421 if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
422 GstMatroskaTrackVideoContext *ctx =
423 (GstMatroskaTrackVideoContext *) collect_pad->track;
425 if (ctx->dirac_unit) {
426 gst_buffer_unref (ctx->dirac_unit);
427 ctx->dirac_unit = NULL;
430 g_free (collect_pad->track->codec_id);
431 g_free (collect_pad->track->codec_name);
433 g_free (collect_pad->track->name);
434 g_free (collect_pad->track->language);
435 g_free (collect_pad->track->codec_priv);
436 g_free (collect_pad->track);
437 collect_pad->track = NULL;
440 /* free cached buffer */
441 if (collect_pad->buffer != NULL) {
442 gst_buffer_unref (collect_pad->buffer);
443 collect_pad->buffer = NULL;
446 if (!full && type != 0) {
447 GstMatroskaTrackContext *context;
449 /* create a fresh context */
451 case GST_MATROSKA_TRACK_TYPE_VIDEO:
452 context = (GstMatroskaTrackContext *)
453 g_new0 (GstMatroskaTrackVideoContext, 1);
455 case GST_MATROSKA_TRACK_TYPE_AUDIO:
456 context = (GstMatroskaTrackContext *)
457 g_new0 (GstMatroskaTrackAudioContext, 1);
459 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
460 context = (GstMatroskaTrackContext *)
461 g_new0 (GstMatroskaTrackSubtitleContext, 1);
464 g_assert_not_reached ();
468 context->type = type;
469 context->name = name;
470 /* TODO: check default values for the context */
471 context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
472 collect_pad->track = context;
473 collect_pad->buffer = NULL;
474 collect_pad->duration = 0;
475 collect_pad->start_ts = GST_CLOCK_TIME_NONE;
476 collect_pad->end_ts = GST_CLOCK_TIME_NONE;
481 * gst_matroska_pad_free:
482 * @collect_pad: the #GstMatroskaPad
484 * Release resources of a matroska collect pad.
487 gst_matroska_pad_free (GstMatroskaPad * collect_pad)
489 gst_matroska_pad_reset (collect_pad, TRUE);
494 * gst_matroska_mux_reset:
495 * @element: #GstMatroskaMux that should be reseted.
497 * Reset matroska muxer back to initial state.
500 gst_matroska_mux_reset (GstElement * element)
502 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
505 /* reset EBML write */
506 gst_ebml_write_reset (mux->ebml_write);
509 mux->state = GST_MATROSKA_MUX_STATE_START;
511 /* clean up existing streams */
513 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
514 GstMatroskaPad *collect_pad;
516 collect_pad = (GstMatroskaPad *) walk->data;
518 /* reset collect pad to pristine state */
519 gst_matroska_pad_reset (collect_pad, FALSE);
523 mux->num_indexes = 0;
528 mux->time_scale = GST_MSECOND;
529 mux->max_cluster_duration = G_MAXINT16 * mux->time_scale;
534 mux->cluster_time = 0;
535 mux->cluster_pos = 0;
536 mux->prev_cluster_size = 0;
539 gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
543 * gst_matroska_mux_handle_src_event:
544 * @pad: Pad which received the event.
545 * @event: Received event.
547 * handle events - copied from oggmux without understanding
549 * Returns: #TRUE on success.
552 gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
557 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
561 /* disable seeking for now */
567 return gst_pad_event_default (pad, parent, event);
571 * gst_matroska_mux_handle_sink_event:
572 * @pad: Pad which received the event.
573 * @event: Received event.
575 * handle events - informational ones like tags
577 * Returns: #TRUE on success.
580 gst_matroska_mux_handle_sink_event (GstPad * pad, GstObject * parent,
583 GstMatroskaTrackContext *context;
584 GstMatroskaPad *collect_pad;
585 GstMatroskaMux *mux = GST_MATROSKA_MUX (parent);
589 switch (GST_EVENT_TYPE (event)) {
590 case GST_EVENT_CAPS:{
593 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
594 gst_event_parse_caps (event, &caps);
596 ret = collect_pad->capsfunc (pad, caps);
597 gst_event_unref (event);
604 GST_DEBUG_OBJECT (mux, "received tag event");
605 gst_event_parse_tag (event, &list);
607 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
608 g_assert (collect_pad);
609 context = collect_pad->track;
612 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
613 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
614 const gchar *lang_code;
616 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
618 GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
619 context->language = g_strdup (lang_code);
621 GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
626 /* FIXME: what about stream-specific tags? */
627 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
628 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
630 gst_event_unref (event);
631 /* handled this, don't want collectpads to forward it downstream */
635 case GST_EVENT_SEGMENT:{
636 const GstSegment *segment;
638 gst_event_parse_segment (event, &segment);
639 if (segment->format != GST_FORMAT_TIME) {
641 gst_event_unref (event);
646 case GST_EVENT_CUSTOM_DOWNSTREAM:{
647 const GstStructure *structure;
649 structure = gst_event_get_structure (event);
650 if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
651 gst_event_replace (&mux->force_key_unit_event, NULL);
652 mux->force_key_unit_event = event;
661 /* now GstCollectPads can take care of the rest, e.g. EOS */
663 ret = mux->collect_event (pad, parent, event);
670 * gst_matroska_mux_video_pad_setcaps:
671 * @pad: Pad which got the caps.
674 * Setcaps function for video sink pad.
676 * Returns: #TRUE on success.
679 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
681 GstMatroskaTrackContext *context = NULL;
682 GstMatroskaTrackVideoContext *videocontext;
684 GstMatroskaPad *collect_pad;
685 GstStructure *structure;
686 const gchar *mimetype;
687 const GValue *value = NULL;
688 GstBuffer *codec_buf = NULL;
689 gint width, height, pixel_width, pixel_height;
691 gboolean interlaced = FALSE;
693 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
696 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
697 g_assert (collect_pad);
698 context = collect_pad->track;
700 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
701 videocontext = (GstMatroskaTrackVideoContext *) context;
703 /* gst -> matroska ID'ing */
704 structure = gst_caps_get_structure (caps, 0);
706 mimetype = gst_structure_get_name (structure);
708 if (gst_structure_get_boolean (structure, "interlaced", &interlaced)
710 context->flags |= GST_MATROSKA_VIDEOTRACK_INTERLACED;
712 if (!strcmp (mimetype, "video/x-theora")) {
713 /* we'll extract the details later from the theora identification header */
717 /* get general properties */
718 /* spec says it is mandatory */
719 if (!gst_structure_get_int (structure, "width", &width) ||
720 !gst_structure_get_int (structure, "height", &height))
723 videocontext->pixel_width = width;
724 videocontext->pixel_height = height;
725 if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
727 context->default_duration =
728 gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
729 GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
730 GST_TIME_ARGS (context->default_duration));
732 context->default_duration = 0;
734 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
735 &pixel_width, &pixel_height)) {
736 if (pixel_width > pixel_height) {
737 videocontext->display_width = width * pixel_width / pixel_height;
738 videocontext->display_height = height;
739 } else if (pixel_width < pixel_height) {
740 videocontext->display_width = width;
741 videocontext->display_height = height * pixel_height / pixel_width;
743 videocontext->display_width = 0;
744 videocontext->display_height = 0;
747 videocontext->display_width = 0;
748 videocontext->display_height = 0;
753 videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
754 videocontext->fourcc = 0;
756 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
757 * data and other settings
761 /* extract codec_data, may turn out needed */
762 value = gst_structure_get_value (structure, "codec_data");
764 codec_buf = (GstBuffer *) gst_value_get_buffer (value);
767 if (!strcmp (mimetype, "video/x-raw")) {
769 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
770 fstr = gst_structure_get_string (structure, "format");
771 if (fstr && strlen (fstr) == 4)
772 videocontext->fourcc = GST_STR_FOURCC (fstr);
773 } else if (!strcmp (mimetype, "image/jpeg")) {
774 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
775 } else if (!strcmp (mimetype, "video/x-xvid") /* MS/VfW compatibility cases */
776 ||!strcmp (mimetype, "video/x-huffyuv")
777 || !strcmp (mimetype, "video/x-divx")
778 || !strcmp (mimetype, "video/x-dv")
779 || !strcmp (mimetype, "video/x-h263")
780 || !strcmp (mimetype, "video/x-msmpeg")
781 || !strcmp (mimetype, "video/x-wmv")
782 || !strcmp (mimetype, "image/jpeg")) {
783 gst_riff_strf_vids *bih;
784 gint size = sizeof (gst_riff_strf_vids);
787 if (!strcmp (mimetype, "video/x-xvid"))
788 fourcc = GST_MAKE_FOURCC ('X', 'V', 'I', 'D');
789 else if (!strcmp (mimetype, "video/x-huffyuv"))
790 fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
791 else if (!strcmp (mimetype, "video/x-dv"))
792 fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
793 else if (!strcmp (mimetype, "video/x-h263"))
794 fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
795 else if (!strcmp (mimetype, "video/x-divx")) {
798 gst_structure_get_int (structure, "divxversion", &divxversion);
799 switch (divxversion) {
801 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
804 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
807 fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
810 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
813 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
814 switch (msmpegversion) {
816 fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
819 fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
825 } else if (!strcmp (mimetype, "video/x-wmv")) {
829 fstr = gst_structure_get_string (structure, "format");
830 if (fstr && strlen (fstr) == 4) {
831 fourcc = GST_STR_FOURCC (fstr);
832 } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
833 if (wmvversion == 2) {
834 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
835 } else if (wmvversion == 1) {
836 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
837 } else if (wmvversion == 3) {
838 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
841 } else if (!strcmp (mimetype, "image/jpeg")) {
842 fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
848 bih = g_new0 (gst_riff_strf_vids, 1);
849 GST_WRITE_UINT32_LE (&bih->size, size);
850 GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
851 GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
852 GST_WRITE_UINT32_LE (&bih->compression, fourcc);
853 GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
854 GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
855 GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
856 videocontext->pixel_height * 3);
858 /* process codec private/initialization data, if any */
860 size += gst_buffer_get_size (codec_buf);
861 bih = g_realloc (bih, size);
862 GST_WRITE_UINT32_LE (&bih->size, size);
863 gst_buffer_extract (codec_buf, 0,
864 (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
867 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
868 context->codec_priv = (gpointer) bih;
869 context->codec_priv_size = size;
870 } else if (!strcmp (mimetype, "video/x-h264")) {
871 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
873 if (context->codec_priv != NULL) {
874 g_free (context->codec_priv);
875 context->codec_priv = NULL;
876 context->codec_priv_size = 0;
879 /* Create avcC header */
880 if (codec_buf != NULL) {
881 context->codec_priv_size = gst_buffer_get_size (codec_buf);
882 context->codec_priv = g_malloc0 (context->codec_priv_size);
883 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
885 } else if (!strcmp (mimetype, "video/x-theora")) {
886 const GValue *streamheader;
888 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
890 if (context->codec_priv != NULL) {
891 g_free (context->codec_priv);
892 context->codec_priv = NULL;
893 context->codec_priv_size = 0;
896 streamheader = gst_structure_get_value (structure, "streamheader");
897 if (!theora_streamheader_to_codecdata (streamheader, context)) {
898 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
899 ("theora stream headers missing or malformed"));
902 } else if (!strcmp (mimetype, "video/x-dirac")) {
903 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
904 } else if (!strcmp (mimetype, "video/x-vp8")) {
905 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VP8);
906 } else if (!strcmp (mimetype, "video/mpeg")) {
909 gst_structure_get_int (structure, "mpegversion", &mpegversion);
910 switch (mpegversion) {
912 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
915 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
918 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
924 /* global headers may be in codec data */
925 if (codec_buf != NULL) {
926 context->codec_priv_size = gst_buffer_get_size (codec_buf);
927 context->codec_priv = g_malloc0 (context->codec_priv_size);
928 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
930 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
932 /* can only make it here if preceding case verified it was version 3 */
933 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
934 } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
936 const GValue *mdpr_data;
938 gst_structure_get_int (structure, "rmversion", &rmversion);
941 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
944 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
947 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
950 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
956 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
957 if (mdpr_data != NULL) {
958 guint8 *priv_data = NULL;
959 guint priv_data_size = 0;
961 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
963 priv_data_size = gst_buffer_get_size (codec_data_buf);
964 priv_data = g_malloc0 (priv_data_size);
966 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
968 context->codec_priv = priv_data;
969 context->codec_priv_size = priv_data_size;
978 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
979 GST_PAD_NAME (pad), caps);
984 /* N > 0 to expect a particular number of headers, negative if the
985 number of headers is variable */
987 xiphN_streamheader_to_codecdata (const GValue * streamheader,
988 GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
990 GstBuffer **buf = NULL;
993 guint bufi, i, offset, priv_data_size;
995 if (streamheader == NULL)
996 goto no_stream_headers;
998 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1001 bufarr = g_value_peek_pointer (streamheader);
1002 if (bufarr->len <= 0 || bufarr->len > 255) /* at least one header, and count stored in a byte */
1004 if (N > 0 && bufarr->len != N)
1007 context->xiph_headers_to_skip = bufarr->len;
1009 buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1010 for (i = 0; i < bufarr->len; i++) {
1011 GValue *bufval = &g_array_index (bufarr, GValue, i);
1013 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1015 goto wrong_content_type;
1018 buf[i] = g_value_peek_pointer (bufval);
1022 if (bufarr->len > 0) {
1023 for (i = 0; i < bufarr->len - 1; i++) {
1024 priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
1028 for (i = 0; i < bufarr->len; ++i) {
1029 priv_data_size += gst_buffer_get_size (buf[i]);
1032 priv_data = g_malloc0 (priv_data_size);
1034 priv_data[0] = bufarr->len - 1;
1037 if (bufarr->len > 0) {
1038 for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1039 for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
1040 priv_data[offset++] = 0xff;
1042 priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
1046 for (i = 0; i < bufarr->len; ++i) {
1047 gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
1048 offset += gst_buffer_get_size (buf[i]);
1051 context->codec_priv = priv_data;
1052 context->codec_priv_size = priv_data_size;
1055 *p_buf0 = gst_buffer_ref (buf[0]);
1064 GST_WARNING ("required streamheaders missing in sink caps!");
1069 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1070 G_VALUE_TYPE_NAME (streamheader));
1075 GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1080 GST_WARNING ("streamheaders array does not contain GstBuffers");
1086 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1087 GstMatroskaTrackContext * context)
1089 GstBuffer *buf0 = NULL;
1091 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1094 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
1095 GST_WARNING ("First vorbis header too small, ignoring");
1097 if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
1098 GstMatroskaTrackAudioContext *audiocontext;
1101 data = gst_buffer_map (buf0, NULL, NULL, GST_MAP_READ);
1102 hdr = data + 1 + 6 + 4;
1103 audiocontext = (GstMatroskaTrackAudioContext *) context;
1104 audiocontext->channels = GST_READ_UINT8 (hdr);
1105 audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1106 gst_buffer_unmap (buf0, data, -1);
1111 gst_buffer_unref (buf0);
1117 theora_streamheader_to_codecdata (const GValue * streamheader,
1118 GstMatroskaTrackContext * context)
1120 GstBuffer *buf0 = NULL;
1122 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1125 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
1126 GST_WARNING ("First theora header too small, ignoring");
1127 } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
1128 GST_WARNING ("First header not a theora identification header, ignoring");
1130 GstMatroskaTrackVideoContext *videocontext;
1131 guint fps_num, fps_denom, par_num, par_denom;
1134 data = gst_buffer_map (buf0, NULL, NULL, GST_MAP_READ);
1135 hdr = data + 1 + 6 + 3 + 2 + 2;
1137 videocontext = (GstMatroskaTrackVideoContext *) context;
1138 videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1139 videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1140 hdr += 3 + 3 + 1 + 1;
1141 fps_num = GST_READ_UINT32_BE (hdr);
1142 fps_denom = GST_READ_UINT32_BE (hdr + 4);
1143 context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1144 fps_denom, fps_num);
1146 par_num = GST_READ_UINT32_BE (hdr) >> 8;
1147 par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1148 if (par_num > 0 && par_num > 0) {
1149 if (par_num > par_denom) {
1150 videocontext->display_width =
1151 videocontext->pixel_width * par_num / par_denom;
1152 videocontext->display_height = videocontext->pixel_height;
1153 } else if (par_num < par_denom) {
1154 videocontext->display_width = videocontext->pixel_width;
1155 videocontext->display_height =
1156 videocontext->pixel_height * par_denom / par_num;
1158 videocontext->display_width = 0;
1159 videocontext->display_height = 0;
1162 videocontext->display_width = 0;
1163 videocontext->display_height = 0;
1167 gst_buffer_unmap (buf0, data, -1);
1171 gst_buffer_unref (buf0);
1177 kate_streamheader_to_codecdata (const GValue * streamheader,
1178 GstMatroskaTrackContext * context)
1180 GstBuffer *buf0 = NULL;
1182 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1185 if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) { /* Kate ID header is 64 bytes */
1186 GST_WARNING ("First kate header too small, ignoring");
1187 } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
1188 GST_WARNING ("First header not a kate identification header, ignoring");
1192 gst_buffer_unref (buf0);
1198 flac_streamheader_to_codecdata (const GValue * streamheader,
1199 GstMatroskaTrackContext * context)
1206 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1207 GST_WARNING ("No or invalid streamheader field in the caps");
1211 bufarr = g_value_peek_pointer (streamheader);
1212 if (bufarr->len < 2) {
1213 GST_WARNING ("Too few headers in streamheader field");
1217 context->xiph_headers_to_skip = bufarr->len + 1;
1219 bufval = &g_array_index (bufarr, GValue, 0);
1220 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1221 GST_WARNING ("streamheaders array does not contain GstBuffers");
1225 buffer = g_value_peek_pointer (bufval);
1227 /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1228 if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
1229 || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
1230 || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
1231 GST_WARNING ("Invalid streamheader for FLAC");
1235 context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
1236 context->codec_priv = g_malloc (context->codec_priv_size);
1237 gst_buffer_extract (buffer, 9, context->codec_priv, -1);
1239 for (i = 1; i < bufarr->len; i++) {
1241 bufval = &g_array_index (bufarr, GValue, i);
1243 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1244 g_free (context->codec_priv);
1245 context->codec_priv = NULL;
1246 context->codec_priv_size = 0;
1247 GST_WARNING ("streamheaders array does not contain GstBuffers");
1251 buffer = g_value_peek_pointer (bufval);
1253 old_size = context->codec_priv_size;
1254 context->codec_priv_size += gst_buffer_get_size (buffer);
1256 context->codec_priv = g_realloc (context->codec_priv,
1257 context->codec_priv_size);
1258 gst_buffer_extract (buffer, 0,
1259 (guint8 *) context->codec_priv + old_size, -1);
1266 speex_streamheader_to_codecdata (const GValue * streamheader,
1267 GstMatroskaTrackContext * context)
1274 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1275 GST_WARNING ("No or invalid streamheader field in the caps");
1279 bufarr = g_value_peek_pointer (streamheader);
1280 if (bufarr->len != 2) {
1281 GST_WARNING ("Too few headers in streamheader field");
1285 context->xiph_headers_to_skip = bufarr->len + 1;
1287 bufval = &g_array_index (bufarr, GValue, 0);
1288 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1289 GST_WARNING ("streamheaders array does not contain GstBuffers");
1293 buffer = g_value_peek_pointer (bufval);
1295 if (gst_buffer_get_size (buffer) < 80
1296 || gst_buffer_memcmp (buffer, 0, "Speex ", 8) != 0) {
1297 GST_WARNING ("Invalid streamheader for Speex");
1301 context->codec_priv_size = gst_buffer_get_size (buffer);
1302 context->codec_priv = g_malloc (context->codec_priv_size);
1303 gst_buffer_extract (buffer, 0, context->codec_priv, -1);
1305 bufval = &g_array_index (bufarr, GValue, 1);
1307 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1308 g_free (context->codec_priv);
1309 context->codec_priv = NULL;
1310 context->codec_priv_size = 0;
1311 GST_WARNING ("streamheaders array does not contain GstBuffers");
1315 buffer = g_value_peek_pointer (bufval);
1317 old_size = context->codec_priv_size;
1318 context->codec_priv_size += gst_buffer_get_size (buffer);
1319 context->codec_priv = g_realloc (context->codec_priv,
1320 context->codec_priv_size);
1321 gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
1326 static const gchar *
1327 aac_codec_data_to_codec_id (GstBuffer * buf)
1329 const gchar *result;
1332 /* default to MAIN */
1335 if (gst_buffer_get_size (buf) >= 2) {
1336 gst_buffer_extract (buf, 0, &profile, 1);
1354 GST_WARNING ("unknown AAC profile, defaulting to MAIN");
1363 * gst_matroska_mux_audio_pad_setcaps:
1364 * @pad: Pad which got the caps.
1367 * Setcaps function for audio sink pad.
1369 * Returns: #TRUE on success.
1372 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1374 GstMatroskaTrackContext *context = NULL;
1375 GstMatroskaTrackAudioContext *audiocontext;
1376 GstMatroskaMux *mux;
1377 GstMatroskaPad *collect_pad;
1378 const gchar *mimetype;
1379 gint samplerate = 0, channels = 0;
1380 GstStructure *structure;
1381 const GValue *codec_data = NULL;
1382 GstBuffer *buf = NULL;
1383 const gchar *stream_format = NULL;
1385 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1388 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1389 g_assert (collect_pad);
1390 context = collect_pad->track;
1392 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
1393 audiocontext = (GstMatroskaTrackAudioContext *) context;
1395 structure = gst_caps_get_structure (caps, 0);
1396 mimetype = gst_structure_get_name (structure);
1399 gst_structure_get_int (structure, "rate", &samplerate);
1400 gst_structure_get_int (structure, "channels", &channels);
1402 audiocontext->samplerate = samplerate;
1403 audiocontext->channels = channels;
1404 audiocontext->bitdepth = 0;
1405 context->default_duration = 0;
1407 codec_data = gst_structure_get_value (structure, "codec_data");
1409 buf = gst_value_get_buffer (codec_data);
1411 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1412 * data and other settings
1416 if (!strcmp (mimetype, "audio/mpeg")) {
1417 gint mpegversion = 0;
1419 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1420 switch (mpegversion) {
1426 gst_structure_get_int (structure, "layer", &layer);
1428 if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
1429 GST_WARNING_OBJECT (mux,
1430 "Unable to determine MPEG audio version, assuming 1");
1436 else if (layer == 2)
1438 else if (version == 2)
1443 context->default_duration =
1444 gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
1448 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
1451 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
1454 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
1463 stream_format = gst_structure_get_string (structure, "stream-format");
1464 /* check this is raw aac */
1465 if (stream_format) {
1466 if (strcmp (stream_format, "raw") != 0) {
1467 GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
1471 GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
1476 if (mpegversion == 2)
1478 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2 "%s",
1479 aac_codec_data_to_codec_id (buf));
1480 else if (mpegversion == 4)
1482 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4 "%s",
1483 aac_codec_data_to_codec_id (buf));
1485 g_assert_not_reached ();
1487 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
1494 } else if (!strcmp (mimetype, "audio/x-raw")) {
1497 gst_audio_info_init (&info);
1498 if (!gst_audio_info_from_caps (&info, caps)) {
1499 GST_DEBUG_OBJECT (mux,
1500 "broken caps, rejected by gst_audio_info_from_caps");
1504 switch (GST_AUDIO_INFO_FORMAT (&info)) {
1505 case GST_AUDIO_FORMAT_U8:
1506 case GST_AUDIO_FORMAT_S16BE:
1507 case GST_AUDIO_FORMAT_S16LE:
1508 case GST_AUDIO_FORMAT_S24BE:
1509 case GST_AUDIO_FORMAT_S24LE:
1510 case GST_AUDIO_FORMAT_S32BE:
1511 case GST_AUDIO_FORMAT_S32LE:
1512 if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
1513 GST_DEBUG_OBJECT (mux, "width must be same as depth!");
1516 if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
1517 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
1519 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
1522 case GST_AUDIO_FORMAT_F32LE:
1523 case GST_AUDIO_FORMAT_F64LE:
1524 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
1528 GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
1532 audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
1534 } else if (!strcmp (mimetype, "audio/x-vorbis")) {
1535 const GValue *streamheader;
1537 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
1539 if (context->codec_priv != NULL) {
1540 g_free (context->codec_priv);
1541 context->codec_priv = NULL;
1542 context->codec_priv_size = 0;
1545 streamheader = gst_structure_get_value (structure, "streamheader");
1546 if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
1547 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1548 ("vorbis stream headers missing or malformed"));
1551 } else if (!strcmp (mimetype, "audio/x-flac")) {
1552 const GValue *streamheader;
1554 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
1555 if (context->codec_priv != NULL) {
1556 g_free (context->codec_priv);
1557 context->codec_priv = NULL;
1558 context->codec_priv_size = 0;
1561 streamheader = gst_structure_get_value (structure, "streamheader");
1562 if (!flac_streamheader_to_codecdata (streamheader, context)) {
1563 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1564 ("flac stream headers missing or malformed"));
1567 } else if (!strcmp (mimetype, "audio/x-speex")) {
1568 const GValue *streamheader;
1570 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
1571 if (context->codec_priv != NULL) {
1572 g_free (context->codec_priv);
1573 context->codec_priv = NULL;
1574 context->codec_priv_size = 0;
1577 streamheader = gst_structure_get_value (structure, "streamheader");
1578 if (!speex_streamheader_to_codecdata (streamheader, context)) {
1579 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1580 ("speex stream headers missing or malformed"));
1583 } else if (!strcmp (mimetype, "audio/x-ac3")) {
1584 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AC3);
1585 } else if (!strcmp (mimetype, "audio/x-eac3")) {
1586 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
1587 } else if (!strcmp (mimetype, "audio/x-dts")) {
1588 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_DTS);
1589 } else if (!strcmp (mimetype, "audio/x-tta")) {
1592 /* TTA frame duration */
1593 context->default_duration = 1.04489795918367346939 * GST_SECOND;
1595 gst_structure_get_int (structure, "width", &width);
1596 audiocontext->bitdepth = width;
1597 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_TTA);
1599 } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
1601 const GValue *mdpr_data;
1603 gst_structure_get_int (structure, "raversion", &raversion);
1604 switch (raversion) {
1606 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
1609 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
1612 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
1618 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1619 if (mdpr_data != NULL) {
1620 guint8 *priv_data = NULL;
1621 guint priv_data_size = 0;
1623 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1625 priv_data_size = gst_buffer_get_size (codec_data_buf);
1626 priv_data = g_malloc0 (priv_data_size);
1628 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1630 context->codec_priv = priv_data;
1631 context->codec_priv_size = priv_data_size;
1634 } else if (!strcmp (mimetype, "audio/x-wma")
1635 || !strcmp (mimetype, "audio/x-alaw")
1636 || !strcmp (mimetype, "audio/x-mulaw")) {
1638 guint codec_priv_size;
1643 if (samplerate == 0 || channels == 0) {
1644 GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
1648 if (!strcmp (mimetype, "audio/x-wma")) {
1652 if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
1653 || !gst_structure_get_int (structure, "block_align", &block_align)
1654 || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
1655 GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
1660 switch (wmaversion) {
1662 format = GST_RIFF_WAVE_FORMAT_WMAV1;
1665 format = GST_RIFF_WAVE_FORMAT_WMAV2;
1668 format = GST_RIFF_WAVE_FORMAT_WMAV3;
1671 GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
1675 if (gst_structure_get_int (structure, "depth", &depth))
1676 audiocontext->bitdepth = depth;
1677 } else if (!strcmp (mimetype, "audio/x-alaw")
1678 || !strcmp (mimetype, "audio/x-mulaw")) {
1679 audiocontext->bitdepth = 8;
1680 if (!strcmp (mimetype, "audio/x-alaw"))
1681 format = GST_RIFF_WAVE_FORMAT_ALAW;
1683 format = GST_RIFF_WAVE_FORMAT_MULAW;
1685 block_align = channels;
1686 bitrate = block_align * samplerate;
1688 g_assert (format != 0);
1690 codec_priv_size = WAVEFORMATEX_SIZE;
1692 codec_priv_size += gst_buffer_get_size (buf);
1694 /* serialize waveformatex structure */
1695 codec_priv = g_malloc0 (codec_priv_size);
1696 GST_WRITE_UINT16_LE (codec_priv, format);
1697 GST_WRITE_UINT16_LE (codec_priv + 2, channels);
1698 GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
1699 GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
1700 GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
1701 GST_WRITE_UINT16_LE (codec_priv + 14, 0);
1703 GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
1705 GST_WRITE_UINT16_LE (codec_priv + 16, 0);
1707 /* process codec private/initialization data, if any */
1709 gst_buffer_extract (buf, 0,
1710 (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
1713 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_ACM);
1714 context->codec_priv = (gpointer) codec_priv;
1715 context->codec_priv_size = codec_priv_size;
1723 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1724 GST_PAD_NAME (pad), caps);
1731 * gst_matroska_mux_subtitle_pad_setcaps:
1732 * @pad: Pad which got the caps.
1735 * Setcaps function for subtitle sink pad.
1737 * Returns: #TRUE on success.
1740 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
1743 * Consider this as boilerplate code for now. There is
1744 * no single subtitle creation element in GStreamer,
1745 * neither do I know how subtitling works at all. */
1747 /* There is now (at least) one such alement (kateenc), and I'm going
1748 to handle it here and claim it works when it can be piped back
1749 through GStreamer and VLC */
1751 GstMatroskaTrackContext *context = NULL;
1752 GstMatroskaTrackSubtitleContext *scontext;
1753 GstMatroskaMux *mux;
1754 GstMatroskaPad *collect_pad;
1755 const gchar *mimetype;
1756 GstStructure *structure;
1758 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1761 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1762 g_assert (collect_pad);
1763 context = collect_pad->track;
1765 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
1766 scontext = (GstMatroskaTrackSubtitleContext *) context;
1768 structure = gst_caps_get_structure (caps, 0);
1769 mimetype = gst_structure_get_name (structure);
1772 scontext->check_utf8 = 1;
1773 scontext->invalid_utf8 = 0;
1774 context->default_duration = 0;
1776 /* TODO: - other format than Kate */
1778 if (!strcmp (mimetype, "subtitle/x-kate")) {
1779 const GValue *streamheader;
1781 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
1783 if (context->codec_priv != NULL) {
1784 g_free (context->codec_priv);
1785 context->codec_priv = NULL;
1786 context->codec_priv_size = 0;
1789 streamheader = gst_structure_get_value (structure, "streamheader");
1790 if (!kate_streamheader_to_codecdata (streamheader, context)) {
1791 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1792 ("kate stream headers missing or malformed"));
1803 * gst_matroska_mux_request_new_pad:
1804 * @element: #GstMatroskaMux.
1805 * @templ: #GstPadTemplate.
1806 * @pad_name: New pad name.
1808 * Request pad function for sink templates.
1810 * Returns: New #GstPad.
1813 gst_matroska_mux_request_new_pad (GstElement * element,
1814 GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
1816 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
1817 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
1818 GstMatroskaPad *collect_pad;
1819 GstPad *newpad = NULL;
1821 const gchar *pad_name = NULL;
1822 GstMatroskaCapsFunc capsfunc = NULL;
1823 GstMatroskaTrackContext *context = NULL;
1826 if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
1827 /* don't mix named and unnamed pads, if the pad already exists we fail when
1828 * trying to add it */
1829 if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
1830 pad_name = req_name;
1832 name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
1835 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
1836 context = (GstMatroskaTrackContext *)
1837 g_new0 (GstMatroskaTrackAudioContext, 1);
1838 context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
1839 context->name = g_strdup ("Audio");
1840 } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
1841 /* don't mix named and unnamed pads, if the pad already exists we fail when
1842 * trying to add it */
1843 if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
1844 pad_name = req_name;
1846 name = g_strdup_printf ("video_%u", mux->num_v_streams++);
1849 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
1850 context = (GstMatroskaTrackContext *)
1851 g_new0 (GstMatroskaTrackVideoContext, 1);
1852 context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
1853 context->name = g_strdup ("Video");
1854 } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
1855 /* don't mix named and unnamed pads, if the pad already exists we fail when
1856 * trying to add it */
1857 if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
1858 pad_name = req_name;
1860 name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
1863 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
1864 context = (GstMatroskaTrackContext *)
1865 g_new0 (GstMatroskaTrackSubtitleContext, 1);
1866 context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
1867 context->name = g_strdup ("Subtitle");
1869 GST_WARNING_OBJECT (mux, "This is not our template!");
1873 newpad = gst_pad_new_from_template (templ, pad_name);
1875 collect_pad = (GstMatroskaPad *)
1876 gst_collect_pads_add_pad (mux->collect, newpad,
1877 sizeof (GstMatroskaPad),
1878 (GstCollectDataDestroyNotify) gst_matroska_pad_free);
1880 collect_pad->track = context;
1881 gst_matroska_pad_reset (collect_pad, FALSE);
1883 /* FIXME: hacked way to override/extend the event function of
1884 * GstCollectPads; because it sets its own event function giving the
1885 * element no access to events.
1886 * TODO GstCollectPads should really give its 'users' a clean chance to
1887 * properly handle events that are not meant for collectpads itself.
1888 * Perhaps a callback or so, though rejected (?) in #340060.
1889 * This would allow (clean) transcoding of info from demuxer/streams
1890 * to another muxer */
1891 mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
1892 gst_pad_set_event_function (newpad,
1893 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event));
1895 collect_pad->capsfunc = capsfunc;
1896 gst_pad_set_active (newpad, TRUE);
1897 if (!gst_element_add_pad (element, newpad))
1898 goto pad_add_failed;
1902 GST_DEBUG_OBJECT (newpad, "Added new request pad");
1909 GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
1910 gst_object_unref (newpad);
1916 * gst_matroska_mux_release_pad:
1917 * @element: #GstMatroskaMux.
1918 * @pad: Pad to release.
1920 * Release a previously requested pad.
1923 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
1925 GstMatroskaMux *mux;
1928 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1930 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
1931 GstCollectData *cdata = (GstCollectData *) walk->data;
1932 GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
1934 if (cdata->pad == pad) {
1935 GstClockTime min_dur; /* observed minimum duration */
1937 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
1938 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
1939 min_dur = GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
1940 if (collect_pad->duration < min_dur)
1941 collect_pad->duration = min_dur;
1944 if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
1945 mux->duration < collect_pad->duration)
1946 mux->duration = collect_pad->duration;
1952 gst_collect_pads_remove_pad (mux->collect, pad);
1953 if (gst_element_remove_pad (element, pad))
1959 * gst_matroska_mux_track_header:
1960 * @mux: #GstMatroskaMux
1961 * @context: Tack context.
1963 * Write a track header.
1966 gst_matroska_mux_track_header (GstMatroskaMux * mux,
1967 GstMatroskaTrackContext * context)
1969 GstEbmlWrite *ebml = mux->ebml_write;
1972 /* TODO: check if everything necessary is written and check default values */
1974 /* track type goes before the type-specific stuff */
1975 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
1976 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
1978 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID,
1979 gst_matroska_mux_create_uid ());
1980 if (context->default_duration) {
1981 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
1982 context->default_duration);
1984 if (context->language) {
1985 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
1989 /* type-specific stuff */
1990 switch (context->type) {
1991 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
1992 GstMatroskaTrackVideoContext *videocontext =
1993 (GstMatroskaTrackVideoContext *) context;
1995 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
1996 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
1997 videocontext->pixel_width);
1998 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
1999 videocontext->pixel_height);
2000 if (videocontext->display_width && videocontext->display_height) {
2001 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2002 videocontext->display_width);
2003 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2004 videocontext->display_height);
2006 if (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED)
2007 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2008 if (videocontext->fourcc) {
2009 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2011 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2012 (gpointer) & fcc_le, 4);
2014 gst_ebml_write_master_finish (ebml, master);
2019 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2020 GstMatroskaTrackAudioContext *audiocontext =
2021 (GstMatroskaTrackAudioContext *) context;
2023 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2024 if (audiocontext->samplerate != 8000)
2025 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2026 audiocontext->samplerate);
2027 if (audiocontext->channels != 1)
2028 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2029 audiocontext->channels);
2030 if (audiocontext->bitdepth) {
2031 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2032 audiocontext->bitdepth);
2034 gst_ebml_write_master_finish (ebml, master);
2040 /* doesn't need type-specific data */
2044 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2045 if (context->codec_priv)
2046 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2047 context->codec_priv, context->codec_priv_size);
2048 /* FIXME: until we have a nice way of getting the codecname
2049 * out of the caps, I'm not going to enable this. Too much
2050 * (useless, double, boring) work... */
2051 /* TODO: Use value from tags if any */
2052 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2053 context->codec_name); */
2054 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2059 * gst_matroska_mux_start:
2060 * @mux: #GstMatroskaMux
2062 * Start a new matroska file (write headers etc...)
2065 gst_matroska_mux_start (GstMatroskaMux * mux)
2067 GstEbmlWrite *ebml = mux->ebml_write;
2068 const gchar *doctype;
2069 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
2070 GST_MATROSKA_ID_TRACKS,
2071 GST_MATROSKA_ID_CUES,
2072 GST_MATROSKA_ID_TAGS,
2075 guint64 master, child;
2079 GstClockTime duration = 0;
2080 guint32 segment_uid[4];
2081 GTimeVal time = { 0, 0 };
2083 if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2084 ebml->caps = gst_caps_new_empty_simple ("video/webm");
2086 ebml->caps = gst_caps_new_empty_simple ("video/x-matroska");
2088 /* we start with a EBML header */
2089 doctype = mux->doctype;
2090 GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
2091 doctype, mux->doctype_version);
2092 gst_ebml_write_header (ebml, doctype, mux->doctype_version);
2094 /* the rest of the header is cached */
2095 gst_ebml_write_set_cache (ebml, 0x1000);
2097 /* start a segment */
2099 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
2100 mux->segment_master = ebml->pos;
2102 if (!mux->streamable) {
2103 /* seekhead (table of contents) - we set the positions later */
2104 mux->seekhead_pos = ebml->pos;
2105 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
2106 for (i = 0; seekhead_id[i] != 0; i++) {
2107 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
2108 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
2109 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
2110 gst_ebml_write_master_finish (ebml, child);
2112 gst_ebml_write_master_finish (ebml, master);
2115 if (mux->streamable) {
2116 const GstTagList *tags;
2119 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2121 if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2122 guint64 master_tags, master_tag;
2124 GST_DEBUG ("Writing tags");
2126 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2127 mux->tags_pos = ebml->pos;
2128 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2129 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2130 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2131 gst_ebml_write_master_finish (ebml, master_tag);
2132 gst_ebml_write_master_finish (ebml, master_tags);
2137 mux->info_pos = ebml->pos;
2138 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
2139 for (i = 0; i < 4; i++) {
2140 segment_uid[i] = g_random_int ();
2142 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
2143 (guint8 *) segment_uid, 16);
2144 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
2145 mux->duration_pos = ebml->pos;
2147 if (!mux->streamable) {
2148 for (collected = mux->collect->data; collected;
2149 collected = g_slist_next (collected)) {
2150 GstMatroskaPad *collect_pad;
2152 gint64 trackduration;
2154 collect_pad = (GstMatroskaPad *) collected->data;
2155 thepad = collect_pad->collect.pad;
2157 /* Query the total length of the track. */
2158 GST_DEBUG_OBJECT (thepad, "querying peer duration");
2159 if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
2160 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
2161 GST_TIME_ARGS (trackduration));
2162 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
2163 duration = (GstClockTime) trackduration;
2167 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2168 gst_guint64_to_gdouble (duration) /
2169 gst_guint64_to_gdouble (mux->time_scale));
2171 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
2172 "GStreamer plugin version " PACKAGE_VERSION);
2173 if (mux->writing_app && mux->writing_app[0]) {
2174 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
2176 g_get_current_time (&time);
2177 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
2178 gst_ebml_write_master_finish (ebml, master);
2181 mux->tracks_pos = ebml->pos;
2182 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
2184 for (collected = mux->collect->data; collected;
2185 collected = g_slist_next (collected)) {
2186 GstMatroskaPad *collect_pad;
2189 collect_pad = (GstMatroskaPad *) collected->data;
2190 thepad = collect_pad->collect.pad;
2192 if (gst_pad_is_linked (thepad) && gst_pad_is_active (thepad) &&
2193 collect_pad->track->codec_id != 0) {
2194 collect_pad->track->num = tracknum++;
2195 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
2196 gst_matroska_mux_track_header (mux, collect_pad->track);
2197 gst_ebml_write_master_finish (ebml, child);
2198 /* some remaing pad/track setup */
2199 collect_pad->default_duration_scaled =
2200 gst_util_uint64_scale (collect_pad->track->default_duration,
2201 1, mux->time_scale);
2204 gst_ebml_write_master_finish (ebml, master);
2206 /* lastly, flush the cache */
2207 gst_ebml_write_flush_cache (ebml, FALSE, 0);
2211 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
2214 /* TODO: more sensible tag mappings */
2217 const gchar *matroska_tagname;
2218 const gchar *gstreamer_tagname;
2222 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
2223 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
2224 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
2225 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
2226 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
2227 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
2228 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
2229 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
2230 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
2231 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
2232 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
2233 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
2234 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
2235 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
2236 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
2238 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
2240 guint64 simpletag_master;
2242 for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) {
2243 const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
2244 const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
2246 if (strcmp (tagname_gst, tag) == 0) {
2247 GValue src = { 0, };
2250 if (!gst_tag_list_copy_value (&src, list, tag))
2252 if ((dest = gst_value_serialize (&src))) {
2254 simpletag_master = gst_ebml_write_master_start (ebml,
2255 GST_MATROSKA_ID_SIMPLETAG);
2256 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
2257 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
2258 gst_ebml_write_master_finish (ebml, simpletag_master);
2261 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
2263 g_value_unset (&src);
2271 * gst_matroska_mux_finish:
2272 * @mux: #GstMatroskaMux
2274 * Finish a new matroska file (write index etc...)
2277 gst_matroska_mux_finish (GstMatroskaMux * mux)
2279 GstEbmlWrite *ebml = mux->ebml_write;
2281 guint64 duration = 0;
2283 const GstTagList *tags;
2285 /* finish last cluster */
2287 gst_ebml_write_master_finish (ebml, mux->cluster);
2291 if (mux->index != NULL) {
2293 guint64 master, pointentry_master, trackpos_master;
2295 mux->cues_pos = ebml->pos;
2296 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
2297 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
2299 for (n = 0; n < mux->num_indexes; n++) {
2300 GstMatroskaIndex *idx = &mux->index[n];
2302 pointentry_master = gst_ebml_write_master_start (ebml,
2303 GST_MATROSKA_ID_POINTENTRY);
2304 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
2305 idx->time / mux->time_scale);
2306 trackpos_master = gst_ebml_write_master_start (ebml,
2307 GST_MATROSKA_ID_CUETRACKPOSITIONS);
2308 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
2309 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
2310 idx->pos - mux->segment_master);
2311 gst_ebml_write_master_finish (ebml, trackpos_master);
2312 gst_ebml_write_master_finish (ebml, pointentry_master);
2315 gst_ebml_write_master_finish (ebml, master);
2316 gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
2320 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2322 if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2323 guint64 master_tags, master_tag;
2325 GST_DEBUG ("Writing tags");
2327 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2328 mux->tags_pos = ebml->pos;
2329 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2330 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2331 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2332 gst_ebml_write_master_finish (ebml, master_tag);
2333 gst_ebml_write_master_finish (ebml, master_tags);
2336 /* update seekhead. We know that:
2337 * - a seekhead contains 4 entries.
2338 * - order of entries is as above.
2339 * - a seekhead has a 4-byte header + 8-byte length
2340 * - each entry is 2-byte master, 2-byte ID pointer,
2341 * 2-byte length pointer, all 8/1-byte length, 4-
2342 * byte ID and 8-byte length pointer, where the
2343 * length pointer starts at 20.
2344 * - all entries are local to the segment (so pos - segment_master).
2345 * - so each entry is at 12 + 20 + num * 28. */
2346 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
2347 mux->info_pos - mux->segment_master);
2348 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
2349 mux->tracks_pos - mux->segment_master);
2350 if (mux->index != NULL) {
2351 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
2352 mux->cues_pos - mux->segment_master);
2355 guint64 my_pos = ebml->pos;
2357 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
2358 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2359 gst_ebml_write_seek (ebml, my_pos);
2362 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
2363 mux->tags_pos - mux->segment_master);
2366 guint64 my_pos = ebml->pos;
2368 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
2369 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2370 gst_ebml_write_seek (ebml, my_pos);
2373 /* update duration */
2374 /* first get the overall duration */
2375 /* a released track may have left a duration in here */
2376 duration = mux->duration;
2377 for (collected = mux->collect->data; collected;
2378 collected = g_slist_next (collected)) {
2379 GstMatroskaPad *collect_pad;
2380 GstClockTime min_duration; /* observed minimum duration */
2382 collect_pad = (GstMatroskaPad *) collected->data;
2384 GST_DEBUG_OBJECT (mux,
2385 "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
2386 " end ts %" GST_TIME_FORMAT, collect_pad,
2387 GST_TIME_ARGS (collect_pad->start_ts),
2388 GST_TIME_ARGS (collect_pad->end_ts));
2390 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2391 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2393 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2394 if (collect_pad->duration < min_duration)
2395 collect_pad->duration = min_duration;
2396 GST_DEBUG_OBJECT (collect_pad,
2397 "final track duration: %" GST_TIME_FORMAT,
2398 GST_TIME_ARGS (collect_pad->duration));
2401 if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
2402 duration < collect_pad->duration)
2403 duration = collect_pad->duration;
2405 if (duration != 0) {
2406 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
2407 GST_TIME_ARGS (duration));
2408 pos = mux->ebml_write->pos;
2409 gst_ebml_write_seek (ebml, mux->duration_pos);
2410 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2411 gst_guint64_to_gdouble (duration) /
2412 gst_guint64_to_gdouble (mux->time_scale));
2413 gst_ebml_write_seek (ebml, pos);
2416 guint64 my_pos = ebml->pos;
2418 gst_ebml_write_seek (ebml, mux->duration_pos);
2419 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
2420 gst_ebml_write_seek (ebml, my_pos);
2422 GST_DEBUG_OBJECT (mux, "finishing segment");
2423 /* finish segment - this also writes element length */
2424 gst_ebml_write_master_finish (ebml, mux->segment_pos);
2429 * gst_matroska_mux_best_pad:
2430 * @mux: #GstMatroskaMux
2431 * @popped: True if at least one buffer was popped from #GstCollectPads
2433 * Find a pad with the oldest data
2434 * (data from this pad should be written first).
2436 * Returns: Selected pad.
2438 static GstMatroskaPad *
2439 gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
2442 GstMatroskaPad *best = NULL;
2445 for (collected = mux->collect->data; collected;
2446 collected = g_slist_next (collected)) {
2447 GstMatroskaPad *collect_pad;
2449 collect_pad = (GstMatroskaPad *) collected->data;
2450 /* fetch a new buffer if needed */
2451 if (collect_pad->buffer == NULL) {
2452 collect_pad->buffer = gst_collect_pads_pop (mux->collect,
2453 (GstCollectData *) collect_pad);
2455 if (collect_pad->buffer != NULL) {
2459 /* convert to running time */
2460 time = GST_BUFFER_TIMESTAMP (collect_pad->buffer);
2461 /* invalid should pass */
2462 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
2463 time = gst_segment_to_running_time (&collect_pad->collect.segment,
2464 GST_FORMAT_TIME, time);
2465 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
2466 GST_DEBUG_OBJECT (mux, "clipping buffer on pad %s outside segment",
2467 GST_PAD_NAME (collect_pad->collect.pad));
2468 gst_buffer_unref (collect_pad->buffer);
2469 collect_pad->buffer = NULL;
2472 GST_LOG_OBJECT (mux, "buffer ts %" GST_TIME_FORMAT " -> %"
2473 GST_TIME_FORMAT " running time",
2474 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (collect_pad->buffer)),
2475 GST_TIME_ARGS (time));
2476 collect_pad->buffer =
2477 gst_buffer_make_writable (collect_pad->buffer);
2478 GST_BUFFER_TIMESTAMP (collect_pad->buffer) = time;
2484 /* if we have a buffer check if it is better then the current best one */
2485 if (collect_pad->buffer != NULL) {
2486 if (best == NULL || !GST_BUFFER_TIMESTAMP_IS_VALID (collect_pad->buffer)
2487 || (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)
2488 && GST_BUFFER_TIMESTAMP (collect_pad->buffer) <
2489 GST_BUFFER_TIMESTAMP (best->buffer))) {
2499 * gst_matroska_mux_buffer_header:
2500 * @track: Track context.
2501 * @relative_timestamp: relative timestamp of the buffer
2502 * @flags: Buffer flags.
2504 * Create a buffer containing buffer header.
2506 * Returns: New buffer.
2509 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
2510 gint16 relative_timestamp, int flags)
2513 guint8 *data = g_malloc (4);
2515 hdr = gst_buffer_new_wrapped (data, 4);
2516 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
2517 data[0] = track->num | 0x80;
2518 /* time relative to clustertime */
2519 GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
2527 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
2528 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
2529 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
2532 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
2533 GstMatroskaPad * collect_pad, GstBuffer * buf)
2535 GstMatroskaTrackVideoContext *ctx =
2536 (GstMatroskaTrackVideoContext *) collect_pad->track;
2537 guint8 *buf_data, *data;
2540 guint32 next_parse_offset;
2541 GstBuffer *ret = NULL;
2542 gboolean is_muxing_unit = FALSE;
2544 buf_data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
2548 gst_buffer_unmap (buf, buf_data, -1);
2549 gst_buffer_unref (buf);
2553 /* Check if this buffer contains a picture or end-of-sequence packet */
2554 while (size >= 13) {
2555 if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
2556 gst_buffer_unmap (buf, buf_data, -1);
2557 gst_buffer_unref (buf);
2561 parse_code = GST_READ_UINT8 (data + 4);
2562 if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
2563 if (ctx->dirac_unit) {
2564 gst_buffer_unref (ctx->dirac_unit);
2565 ctx->dirac_unit = NULL;
2567 } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
2568 parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
2569 is_muxing_unit = TRUE;
2573 next_parse_offset = GST_READ_UINT32_BE (data + 5);
2575 if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
2578 data += next_parse_offset;
2579 size -= next_parse_offset;
2582 if (ctx->dirac_unit)
2583 ctx->dirac_unit = gst_buffer_join (ctx->dirac_unit, gst_buffer_ref (buf));
2585 ctx->dirac_unit = gst_buffer_ref (buf);
2587 gst_buffer_unmap (buf, buf_data, -1);
2589 if (is_muxing_unit) {
2590 ret = gst_buffer_make_writable (ctx->dirac_unit);
2591 ctx->dirac_unit = NULL;
2592 gst_buffer_copy_into (ret, buf,
2593 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2594 gst_buffer_unref (buf);
2596 gst_buffer_unref (buf);
2604 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
2608 GValue streamheader = { 0 };
2609 GValue bufval = { 0 };
2610 GstBuffer *streamheader_buffer;
2611 GstEbmlWrite *ebml = mux->ebml_write;
2613 streamheader_buffer = gst_ebml_stop_streamheader (ebml);
2614 if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
2615 caps = gst_caps_new_empty_simple ("video/webm");
2617 caps = gst_caps_new_empty_simple ("video/x-matroska");
2619 s = gst_caps_get_structure (caps, 0);
2620 g_value_init (&streamheader, GST_TYPE_ARRAY);
2621 g_value_init (&bufval, GST_TYPE_BUFFER);
2622 GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_IN_CAPS);
2623 gst_value_set_buffer (&bufval, streamheader_buffer);
2624 gst_value_array_append_value (&streamheader, &bufval);
2625 g_value_unset (&bufval);
2626 gst_structure_set_value (s, "streamheader", &streamheader);
2627 g_value_unset (&streamheader);
2628 gst_caps_replace (&ebml->caps, caps);
2629 gst_buffer_unref (streamheader_buffer);
2630 gst_caps_unref (caps);
2634 * gst_matroska_mux_write_data:
2635 * @mux: #GstMatroskaMux
2636 * @collect_pad: #GstMatroskaPad with the data
2638 * Write collected data (called from gst_matroska_mux_collected).
2640 * Returns: Result of the gst_pad_push issued to write the data.
2642 static GstFlowReturn
2643 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
2645 GstEbmlWrite *ebml = mux->ebml_write;
2646 GstBuffer *buf, *hdr;
2648 gboolean write_duration;
2649 gint16 relative_timestamp;
2650 gint64 relative_timestamp64;
2651 guint64 block_duration;
2652 gboolean is_video_keyframe = FALSE;
2655 buf = collect_pad->buffer;
2656 collect_pad->buffer = NULL;
2658 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
2659 if (collect_pad->track->xiph_headers_to_skip > 0) {
2660 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
2661 gst_buffer_unref (buf);
2662 --collect_pad->track->xiph_headers_to_skip;
2666 /* for dirac we have to queue up everything up to a picture unit */
2667 if (collect_pad->track->codec_id != NULL &&
2668 strcmp (collect_pad->track->codec_id,
2669 GST_MATROSKA_CODEC_ID_VIDEO_DIRAC) == 0) {
2670 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
2675 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
2676 * this would wreak havoc with time stored in matroska file */
2677 /* TODO: maybe calculate a timestamp by using the previous timestamp
2678 * and default duration */
2679 if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2680 GST_WARNING_OBJECT (collect_pad->collect.pad,
2681 "Invalid buffer timestamp; dropping buffer");
2682 gst_buffer_unref (buf);
2686 /* set the timestamp for outgoing buffers */
2687 ebml->timestamp = GST_BUFFER_TIMESTAMP (buf);
2689 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
2690 !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
2691 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
2692 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2693 is_video_keyframe = TRUE;
2697 /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
2698 * or when we may be reaching the limit of the relative timestamp */
2699 if (mux->cluster_time +
2700 mux->max_cluster_duration < GST_BUFFER_TIMESTAMP (buf)
2701 || is_video_keyframe || mux->force_key_unit_event) {
2702 if (!mux->streamable)
2703 gst_ebml_write_master_finish (ebml, mux->cluster);
2705 /* Forward the GstForceKeyUnit event after finishing the cluster */
2706 if (mux->force_key_unit_event) {
2707 gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
2708 mux->force_key_unit_event = NULL;
2711 mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
2712 mux->cluster_pos = ebml->pos;
2713 gst_ebml_write_set_cache (ebml, 0x20);
2715 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2716 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2717 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2719 GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
2720 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1,
2722 gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2723 mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2724 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
2725 mux->prev_cluster_size);
2730 mux->cluster_pos = ebml->pos;
2731 gst_ebml_write_set_cache (ebml, 0x20);
2732 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2733 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2734 gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 1, mux->time_scale));
2735 gst_ebml_write_flush_cache (ebml, TRUE, GST_BUFFER_TIMESTAMP (buf));
2736 mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2739 /* update duration of this track */
2740 if (GST_BUFFER_DURATION_IS_VALID (buf))
2741 collect_pad->duration += GST_BUFFER_DURATION (buf);
2743 /* We currently write index entries for all video tracks or for the audio
2744 * track in a single-track audio file. This could be improved by keeping the
2745 * index only for the *first* video track. */
2747 /* TODO: index is useful for every track, should contain the number of
2748 * the block in the cluster which contains the timestamp, should also work
2749 * for files with multiple audio tracks.
2751 if (!mux->streamable &&
2752 (is_video_keyframe ||
2753 ((collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
2754 (mux->num_streams == 1)))) {
2757 if (mux->min_index_interval != 0) {
2758 for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
2759 if (mux->index[last_idx].track == collect_pad->track->num)
2764 if (last_idx < 0 || mux->min_index_interval == 0 ||
2765 (GST_CLOCK_DIFF (mux->index[last_idx].time, GST_BUFFER_TIMESTAMP (buf))
2766 >= mux->min_index_interval)) {
2767 GstMatroskaIndex *idx;
2769 if (mux->num_indexes % 32 == 0) {
2770 mux->index = g_renew (GstMatroskaIndex, mux->index,
2771 mux->num_indexes + 32);
2773 idx = &mux->index[mux->num_indexes++];
2775 idx->pos = mux->cluster_pos;
2776 idx->time = GST_BUFFER_TIMESTAMP (buf);
2777 idx->track = collect_pad->track->num;
2781 /* Check if the duration differs from the default duration. */
2782 write_duration = FALSE;
2784 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
2785 block_duration = gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
2786 1, mux->time_scale);
2788 /* small difference should be ok. */
2789 if (block_duration > collect_pad->default_duration_scaled + 1 ||
2790 block_duration < collect_pad->default_duration_scaled - 1) {
2791 write_duration = TRUE;
2795 /* write the block, for doctype v2 use SimpleBlock if possible
2796 * one slice (*breath*).
2797 * FIXME: Need to do correct lacing! */
2798 relative_timestamp64 = GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time;
2799 if (relative_timestamp64 >= 0) {
2800 /* round the timestamp */
2801 relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
2803 /* round the timestamp */
2804 relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
2806 relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
2808 if (mux->doctype_version > 1 && !write_duration) {
2810 GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : 0x80;
2813 gst_matroska_mux_create_buffer_header (collect_pad->track,
2814 relative_timestamp, flags);
2815 gst_ebml_write_set_cache (ebml, 0x40);
2816 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
2817 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
2818 gst_ebml_write_buffer (ebml, hdr);
2819 gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
2820 gst_ebml_write_buffer (ebml, buf);
2822 return gst_ebml_last_write_result (ebml);
2824 gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
2825 /* write and call order slightly unnatural,
2826 * but avoids seek and minizes pushing */
2827 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
2829 gst_matroska_mux_create_buffer_header (collect_pad->track,
2830 relative_timestamp, 0);
2832 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
2833 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
2834 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
2835 gst_ebml_write_buffer (ebml, hdr);
2836 gst_ebml_write_master_finish_full (ebml, blockgroup,
2837 gst_buffer_get_size (buf));
2838 gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
2839 gst_ebml_write_buffer (ebml, buf);
2841 return gst_ebml_last_write_result (ebml);
2847 * gst_matroska_mux_collected:
2848 * @pads: #GstCollectPads
2849 * @uuser_data: #GstMatroskaMux
2851 * Collectpads callback.
2853 * Returns: #GstFlowReturn
2855 static GstFlowReturn
2856 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
2858 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
2859 GstEbmlWrite *ebml = mux->ebml_write;
2860 GstMatroskaPad *best;
2862 GstFlowReturn ret = GST_FLOW_OK;
2864 GST_DEBUG_OBJECT (mux, "Collected pads");
2866 /* start with a header */
2867 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
2868 if (mux->collect->data == NULL) {
2869 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2870 ("No input streams configured"));
2871 return GST_FLOW_ERROR;
2873 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
2874 gst_ebml_start_streamheader (ebml);
2875 gst_matroska_mux_start (mux);
2876 gst_matroska_mux_stop_streamheader (mux);
2877 mux->state = GST_MATROSKA_MUX_STATE_DATA;
2881 /* which stream to write from? */
2882 best = gst_matroska_mux_best_pad (mux, &popped);
2884 /* if there is no best pad, we have reached EOS */
2886 /* buffer popped, but none returned means it was clipped */
2889 GST_DEBUG_OBJECT (mux, "No best pad finishing...");
2890 if (!mux->streamable) {
2891 gst_matroska_mux_finish (mux);
2893 GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
2895 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
2896 ret = GST_FLOW_UNEXPECTED;
2899 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
2900 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
2901 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (best->buffer)),
2902 GST_TIME_ARGS (GST_BUFFER_DURATION (best->buffer)));
2904 /* make note of first and last encountered timestamps, so we can calculate
2905 * the actual duration later when we send an updated header on eos */
2906 if (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)) {
2907 GstClockTime start_ts = GST_BUFFER_TIMESTAMP (best->buffer);
2908 GstClockTime end_ts = start_ts;
2910 if (GST_BUFFER_DURATION_IS_VALID (best->buffer))
2911 end_ts += GST_BUFFER_DURATION (best->buffer);
2912 else if (best->track->default_duration)
2913 end_ts += best->track->default_duration;
2915 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
2916 best->end_ts = end_ts;
2918 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
2919 start_ts < best->start_ts))
2920 best->start_ts = start_ts;
2923 /* write one buffer */
2924 ret = gst_matroska_mux_write_data (mux, best);
2925 } while (ret == GST_FLOW_OK && !popped);
2932 * gst_matroska_mux_change_state:
2933 * @element: #GstMatroskaMux
2934 * @transition: State change transition.
2936 * Change the muxer state.
2938 * Returns: #GstStateChangeReturn
2940 static GstStateChangeReturn
2941 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
2943 GstStateChangeReturn ret;
2944 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
2946 switch (transition) {
2947 case GST_STATE_CHANGE_NULL_TO_READY:
2949 case GST_STATE_CHANGE_READY_TO_PAUSED:
2950 gst_collect_pads_start (mux->collect);
2952 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2954 case GST_STATE_CHANGE_PAUSED_TO_READY:
2955 gst_collect_pads_stop (mux->collect);
2961 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2963 switch (transition) {
2964 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2966 case GST_STATE_CHANGE_PAUSED_TO_READY:
2967 gst_matroska_mux_reset (GST_ELEMENT (mux));
2969 case GST_STATE_CHANGE_READY_TO_NULL:
2979 gst_matroska_mux_set_property (GObject * object,
2980 guint prop_id, const GValue * value, GParamSpec * pspec)
2982 GstMatroskaMux *mux;
2984 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
2985 mux = GST_MATROSKA_MUX (object);
2988 case ARG_WRITING_APP:
2989 if (!g_value_get_string (value)) {
2990 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
2993 g_free (mux->writing_app);
2994 mux->writing_app = g_value_dup_string (value);
2996 case ARG_DOCTYPE_VERSION:
2997 mux->doctype_version = g_value_get_int (value);
2999 case ARG_MIN_INDEX_INTERVAL:
3000 mux->min_index_interval = g_value_get_int64 (value);
3002 case ARG_STREAMABLE:
3003 mux->streamable = g_value_get_boolean (value);
3006 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3012 gst_matroska_mux_get_property (GObject * object,
3013 guint prop_id, GValue * value, GParamSpec * pspec)
3015 GstMatroskaMux *mux;
3017 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
3018 mux = GST_MATROSKA_MUX (object);
3021 case ARG_WRITING_APP:
3022 g_value_set_string (value, mux->writing_app);
3024 case ARG_DOCTYPE_VERSION:
3025 g_value_set_int (value, mux->doctype_version);
3027 case ARG_MIN_INDEX_INTERVAL:
3028 g_value_set_int64 (value, mux->min_index_interval);
3030 case ARG_STREAMABLE:
3031 g_value_set_boolean (value, mux->streamable);
3034 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);