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.
51 #include "matroska-mux.h"
52 #include "matroska-ids.h"
54 GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
55 #define GST_CAT_DEFAULT matroskamux_debug
64 #define DEFAULT_MATROSKA_VERSION 1
65 #define DEFAULT_WRITING_APP "GStreamer Matroska muxer"
67 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
70 GST_STATIC_CAPS ("video/x-matroska")
73 #define COMMON_VIDEO_CAPS \
74 "width = (int) [ 16, 4096 ], " \
75 "height = (int) [ 16, 4096 ], " \
76 "framerate = (fraction) [ 0, MAX ]"
78 #define COMMON_VIDEO_CAPS_NO_FRAMERATE \
79 "width = (int) [ 16, 4096 ], " \
80 "height = (int) [ 16, 4096 ] "
83 * * require codec data, etc as needed
86 static GstStaticPadTemplate videosink_templ =
87 GST_STATIC_PAD_TEMPLATE ("video_%d",
90 GST_STATIC_CAPS ("video/mpeg, "
91 "mpegversion = (int) { 1, 2, 4 }, "
92 "systemstream = (boolean) false, "
93 COMMON_VIDEO_CAPS "; "
95 COMMON_VIDEO_CAPS "; "
97 COMMON_VIDEO_CAPS "; "
99 COMMON_VIDEO_CAPS "; "
101 COMMON_VIDEO_CAPS "; "
103 COMMON_VIDEO_CAPS "; "
105 COMMON_VIDEO_CAPS "; "
107 COMMON_VIDEO_CAPS "; "
109 COMMON_VIDEO_CAPS_NO_FRAMERATE "; "
112 COMMON_VIDEO_CAPS "; "
113 "video/x-pn-realvideo, "
114 "rmversion = (int) [1, 4], "
115 COMMON_VIDEO_CAPS "; "
117 "format = (fourcc) { YUY2, I420, YV12, UYVY, AYUV }, "
121 #define COMMON_AUDIO_CAPS \
122 "channels = (int) [ 1, MAX ], " \
123 "rate = (int) [ 1, MAX ]"
126 * * require codec data, etc as needed
128 static GstStaticPadTemplate audiosink_templ =
129 GST_STATIC_PAD_TEMPLATE ("audio_%d",
132 GST_STATIC_CAPS ("audio/mpeg, "
133 "mpegversion = (int) 1, "
134 "layer = (int) [ 1, 3 ], "
135 COMMON_AUDIO_CAPS "; "
137 "mpegversion = (int) { 2, 4 }, "
138 COMMON_AUDIO_CAPS "; "
140 COMMON_AUDIO_CAPS "; "
142 COMMON_AUDIO_CAPS "; "
144 COMMON_AUDIO_CAPS "; "
146 COMMON_AUDIO_CAPS "; "
150 "signed = (boolean) false, "
151 COMMON_AUDIO_CAPS ";"
155 "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
156 "signed = (boolean) true, "
157 COMMON_AUDIO_CAPS ";"
161 "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
162 "signed = (boolean) true, "
163 COMMON_AUDIO_CAPS ";"
167 "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
168 "signed = (boolean) true, "
169 COMMON_AUDIO_CAPS ";"
170 "audio/x-raw-float, "
171 "width = (int) [ 32, 64 ], "
172 "endianness = (int) LITTLE_ENDIAN, "
173 COMMON_AUDIO_CAPS ";"
175 "width = (int) { 8, 16, 24 }, "
176 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
177 "audio/x-pn-realaudio, "
178 "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS ";")
181 static GstStaticPadTemplate subtitlesink_templ =
182 GST_STATIC_PAD_TEMPLATE ("subtitle_%d",
185 GST_STATIC_CAPS_ANY);
187 static GArray *used_uids;
188 G_LOCK_DEFINE_STATIC (used_uids);
190 static void gst_matroska_mux_add_interfaces (GType type);
192 GST_BOILERPLATE_FULL (GstMatroskaMux, gst_matroska_mux, GstElement,
193 GST_TYPE_ELEMENT, gst_matroska_mux_add_interfaces);
195 /* Matroska muxer destructor */
196 static void gst_matroska_mux_finalize (GObject * object);
198 /* Pads collected callback */
200 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data);
203 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
205 static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
206 GstPadTemplate * templ, const gchar * name);
207 static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
209 /* gst internal change state handler */
210 static GstStateChangeReturn
211 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
213 /* gobject bla bla */
214 static void gst_matroska_mux_set_property (GObject * object,
215 guint prop_id, const GValue * value, GParamSpec * pspec);
216 static void gst_matroska_mux_get_property (GObject * object,
217 guint prop_id, GValue * value, GParamSpec * pspec);
220 static void gst_matroska_mux_reset (GstElement * element);
223 static guint64 gst_matroska_mux_create_uid ();
225 static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
226 GstMatroskaTrackContext * context);
227 static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
228 GstMatroskaTrackContext * context);
229 static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
230 GstMatroskaTrackContext * context);
231 static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
232 GstMatroskaTrackContext * context);
233 static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
234 GstMatroskaTrackContext * context);
237 gst_matroska_mux_add_interfaces (GType type)
239 static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
241 g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
245 gst_matroska_mux_base_init (gpointer g_class)
247 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
249 gst_element_class_add_pad_template (element_class,
250 gst_static_pad_template_get (&videosink_templ));
251 gst_element_class_add_pad_template (element_class,
252 gst_static_pad_template_get (&audiosink_templ));
253 gst_element_class_add_pad_template (element_class,
254 gst_static_pad_template_get (&subtitlesink_templ));
255 gst_element_class_add_pad_template (element_class,
256 gst_static_pad_template_get (&src_templ));
257 gst_element_class_set_details_simple (element_class, "Matroska muxer",
259 "Muxes video/audio/subtitle streams into a matroska stream",
260 "Ronald Bultje <rbultje@ronald.bitfreak.net>");
262 GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
267 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
269 GObjectClass *gobject_class;
270 GstElementClass *gstelement_class;
272 gobject_class = (GObjectClass *) klass;
273 gstelement_class = (GstElementClass *) klass;
275 gobject_class->finalize = gst_matroska_mux_finalize;
277 gobject_class->get_property = gst_matroska_mux_get_property;
278 gobject_class->set_property = gst_matroska_mux_set_property;
280 g_object_class_install_property (gobject_class, ARG_WRITING_APP,
281 g_param_spec_string ("writing-app", "Writing application.",
282 "The name the application that creates the matroska file.",
283 NULL, G_PARAM_READWRITE));
284 g_object_class_install_property (gobject_class, ARG_MATROSKA_VERSION,
285 g_param_spec_int ("version", "Matroska version",
286 "This parameter determines what matroska features can be used.",
287 1, 2, DEFAULT_MATROSKA_VERSION, G_PARAM_READWRITE));
289 gstelement_class->change_state =
290 GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
291 gstelement_class->request_new_pad =
292 GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
293 gstelement_class->release_pad =
294 GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
299 * gst_matroska_mux_init:
300 * @mux: #GstMatroskaMux that should be initialized.
301 * @g_class: Class of the muxer.
303 * Matroska muxer constructor.
306 gst_matroska_mux_init (GstMatroskaMux * mux, GstMatroskaMuxClass * g_class)
308 mux->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
309 gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
310 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
312 mux->collect = gst_collect_pads_new ();
313 gst_collect_pads_set_function (mux->collect,
314 (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_matroska_mux_collected),
317 mux->ebml_write = gst_ebml_write_new (mux->srcpad);
319 /* property defaults */
320 mux->matroska_version = DEFAULT_MATROSKA_VERSION;
321 mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
323 /* initialize internal variables */
325 mux->num_streams = 0;
326 mux->num_a_streams = 0;
327 mux->num_t_streams = 0;
328 mux->num_v_streams = 0;
330 /* initialize remaining variables */
331 gst_matroska_mux_reset (GST_ELEMENT (mux));
336 * gst_matroska_mux_finalize:
337 * @object: #GstMatroskaMux that should be finalized.
339 * Finalize matroska muxer.
342 gst_matroska_mux_finalize (GObject * object)
344 GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
346 gst_object_unref (mux->collect);
347 gst_object_unref (mux->ebml_write);
348 if (mux->writing_app)
349 g_free (mux->writing_app);
351 G_OBJECT_CLASS (parent_class)->finalize (object);
356 * gst_matroska_mux_create_uid:
358 * Generate new unused track UID.
360 * Returns: New track UID.
363 gst_matroska_mux_create_uid (void)
370 used_uids = g_array_sized_new (FALSE, FALSE, sizeof (guint64), 10);
375 uid = (((guint64) g_random_int ()) << 32) | g_random_int ();
376 for (i = 0; i < used_uids->len; i++) {
377 if (g_array_index (used_uids, guint64, i) == uid) {
382 g_array_append_val (used_uids, uid);
385 G_UNLOCK (used_uids);
391 * gst_matroska_pad_reset:
392 * @collect_pad: the #GstMatroskaPad
394 * Reset and/or release resources of a matroska collect pad.
397 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
400 GstMatroskaTrackType type = 0;
402 /* free track information */
403 if (collect_pad->track != NULL) {
404 /* retrieve for optional later use */
405 name = collect_pad->track->name;
406 type = collect_pad->track->type;
407 /* extra for video */
408 if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
409 GstMatroskaTrackVideoContext *ctx =
410 (GstMatroskaTrackVideoContext *) collect_pad->track;
412 if (ctx->dirac_unit) {
413 gst_buffer_unref (ctx->dirac_unit);
414 ctx->dirac_unit = NULL;
417 g_free (collect_pad->track->codec_id);
418 g_free (collect_pad->track->codec_name);
420 g_free (collect_pad->track->name);
421 g_free (collect_pad->track->language);
422 g_free (collect_pad->track->codec_priv);
423 g_free (collect_pad->track);
424 collect_pad->track = NULL;
427 /* free cached buffer */
428 if (collect_pad->buffer != NULL) {
429 gst_buffer_unref (collect_pad->buffer);
430 collect_pad->buffer = NULL;
433 if (!full && type != 0) {
434 GstMatroskaTrackContext *context;
436 /* create a fresh context */
438 case GST_MATROSKA_TRACK_TYPE_VIDEO:
439 context = (GstMatroskaTrackContext *)
440 g_new0 (GstMatroskaTrackVideoContext, 1);
442 case GST_MATROSKA_TRACK_TYPE_AUDIO:
443 context = (GstMatroskaTrackContext *)
444 g_new0 (GstMatroskaTrackAudioContext, 1);
446 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
447 context = (GstMatroskaTrackContext *)
448 g_new0 (GstMatroskaTrackSubtitleContext, 1);
451 g_assert_not_reached ();
455 context->type = type;
456 context->name = name;
457 /* TODO: check default values for the context */
458 context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
459 collect_pad->track = context;
460 collect_pad->buffer = NULL;
461 collect_pad->duration = 0;
462 collect_pad->start_ts = GST_CLOCK_TIME_NONE;
463 collect_pad->end_ts = GST_CLOCK_TIME_NONE;
468 * gst_matroska_pad_free:
469 * @collect_pad: the #GstMatroskaPad
471 * Release resources of a matroska collect pad.
474 gst_matroska_pad_free (GstMatroskaPad * collect_pad)
476 gst_matroska_pad_reset (collect_pad, TRUE);
481 * gst_matroska_mux_reset:
482 * @element: #GstMatroskaMux that should be reseted.
484 * Reset matroska muxer back to initial state.
487 gst_matroska_mux_reset (GstElement * element)
489 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
492 /* reset EBML write */
493 gst_ebml_write_reset (mux->ebml_write);
496 mux->state = GST_MATROSKA_MUX_STATE_START;
498 /* clean up existing streams */
500 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
501 GstMatroskaPad *collect_pad;
503 collect_pad = (GstMatroskaPad *) walk->data;
505 /* reset collect pad to pristine state */
506 gst_matroska_pad_reset (collect_pad, FALSE);
510 mux->num_indexes = 0;
515 mux->time_scale = GST_MSECOND;
520 mux->cluster_time = 0;
521 mux->cluster_pos = 0;
524 gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
528 * gst_matroska_mux_handle_src_event:
529 * @pad: Pad which received the event.
530 * @event: Received event.
532 * handle events - copied from oggmux without understanding
534 * Returns: #TRUE on success.
537 gst_matroska_mux_handle_src_event (GstPad * pad, GstEvent * event)
541 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
545 /* disable seeking for now */
551 return gst_pad_event_default (pad, event);
555 * gst_matroska_mux_handle_sink_event:
556 * @pad: Pad which received the event.
557 * @event: Received event.
559 * handle events - informational ones like tags
561 * Returns: #TRUE on success.
564 gst_matroska_mux_handle_sink_event (GstPad * pad, GstEvent * event)
566 GstMatroskaTrackContext *context;
567 GstMatroskaPad *collect_pad;
572 mux = GST_MATROSKA_MUX (gst_pad_get_parent (pad));
574 switch (GST_EVENT_TYPE (event)) {
576 GST_DEBUG_OBJECT (mux, "received tag event");
577 gst_event_parse_tag (event, &list);
579 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
580 g_assert (collect_pad);
581 context = collect_pad->track;
584 * strictly speaking, the incoming language code may only be 639-1, so not
585 * 639-2 according to matroska specs, but it will have to do for now */
586 gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &context->language);
588 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
589 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
591 case GST_EVENT_NEWSEGMENT:
592 /* We don't support NEWSEGMENT events */
594 gst_event_unref (event);
600 /* now GstCollectPads can take care of the rest, e.g. EOS */
602 ret = mux->collect_event (pad, event);
603 gst_object_unref (mux);
610 * gst_matroska_mux_video_pad_setcaps:
611 * @pad: Pad which got the caps.
614 * Setcaps function for video sink pad.
616 * Returns: #TRUE on success.
619 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
621 GstMatroskaTrackContext *context = NULL;
622 GstMatroskaTrackVideoContext *videocontext;
624 GstMatroskaPad *collect_pad;
625 GstStructure *structure;
626 const gchar *mimetype;
627 const GValue *value = NULL;
628 const GstBuffer *codec_buf = NULL;
629 gint width, height, pixel_width, pixel_height;
632 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
635 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
636 g_assert (collect_pad);
637 context = collect_pad->track;
639 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
640 videocontext = (GstMatroskaTrackVideoContext *) context;
642 /* gst -> matroska ID'ing */
643 structure = gst_caps_get_structure (caps, 0);
645 mimetype = gst_structure_get_name (structure);
647 if (!strcmp (mimetype, "video/x-theora")) {
648 /* we'll extract the details later from the theora identification header */
652 /* get general properties */
653 gst_structure_get_int (structure, "width", &width);
654 gst_structure_get_int (structure, "height", &height);
655 videocontext->pixel_width = width;
656 videocontext->pixel_height = height;
657 if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
659 context->default_duration =
660 gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
661 GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
662 GST_TIME_ARGS (context->default_duration));
664 context->default_duration = 0;
666 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
667 &pixel_width, &pixel_height)) {
668 if (pixel_width > pixel_height) {
669 videocontext->display_width = width * pixel_width / pixel_height;
670 videocontext->display_height = height;
671 } else if (pixel_width < pixel_height) {
672 videocontext->display_width = width;
673 videocontext->display_height = height * pixel_height / pixel_width;
675 videocontext->display_width = 0;
676 videocontext->display_height = 0;
679 videocontext->display_width = 0;
680 videocontext->display_height = 0;
685 videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
686 videocontext->fourcc = 0;
688 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
689 * data and other settings
693 /* extract codec_data, may turn out needed */
694 value = gst_structure_get_value (structure, "codec_data");
696 codec_buf = gst_value_get_buffer (value);
699 if (!strcmp (mimetype, "video/x-raw-yuv")) {
700 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
701 gst_structure_get_fourcc (structure, "format", &videocontext->fourcc);
704 } else if (!strcmp (mimetype, "image/jpeg")) {
705 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
708 } else if (!strcmp (mimetype, "video/x-xvid") /* MS/VfW compatibility cases */
709 ||!strcmp (mimetype, "video/x-huffyuv")
710 || !strcmp (mimetype, "video/x-divx")
711 || !strcmp (mimetype, "video/x-dv")
712 || !strcmp (mimetype, "video/x-h263")
713 || !strcmp (mimetype, "video/x-msmpeg")) {
714 BITMAPINFOHEADER *bih;
715 gint size = sizeof (BITMAPINFOHEADER);
718 if (!strcmp (mimetype, "video/x-xvid"))
719 fourcc = GST_MAKE_FOURCC ('X', 'V', 'I', 'D');
720 else if (!strcmp (mimetype, "video/x-huffyuv"))
721 fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
722 else if (!strcmp (mimetype, "video/x-dv"))
723 fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
724 else if (!strcmp (mimetype, "video/x-h263"))
725 fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
726 else if (!strcmp (mimetype, "video/x-divx")) {
729 gst_structure_get_int (structure, "divxversion", &divxversion);
730 switch (divxversion) {
732 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
735 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
738 fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
741 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
744 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
745 switch (msmpegversion) {
747 fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
750 fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
761 bih = g_new0 (BITMAPINFOHEADER, 1);
762 GST_WRITE_UINT32_LE (&bih->bi_size, size);
763 GST_WRITE_UINT32_LE (&bih->bi_width, videocontext->pixel_width);
764 GST_WRITE_UINT32_LE (&bih->bi_height, videocontext->pixel_height);
765 GST_WRITE_UINT32_LE (&bih->bi_compression, fourcc);
766 GST_WRITE_UINT16_LE (&bih->bi_planes, (guint16) 1);
767 GST_WRITE_UINT16_LE (&bih->bi_bit_count, (guint16) 24);
768 GST_WRITE_UINT32_LE (&bih->bi_size_image, videocontext->pixel_width *
769 videocontext->pixel_height * 3);
771 /* process codec private/initialization data, if any */
773 size += GST_BUFFER_SIZE (codec_buf);
774 bih = g_realloc (bih, size);
775 GST_WRITE_UINT32_LE (&bih->bi_size, size);
776 memcpy ((guint8 *) bih + sizeof (BITMAPINFOHEADER),
777 GST_BUFFER_DATA (codec_buf), GST_BUFFER_SIZE (codec_buf));
780 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
781 context->codec_priv = (gpointer) bih;
782 context->codec_priv_size = size;
785 } else if (!strcmp (mimetype, "video/x-h264")) {
786 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
788 if (context->codec_priv != NULL) {
789 g_free (context->codec_priv);
790 context->codec_priv = NULL;
791 context->codec_priv_size = 0;
794 /* Create avcC header */
795 if (codec_buf != NULL) {
796 context->codec_priv_size = GST_BUFFER_SIZE (codec_buf);
797 context->codec_priv = g_malloc0 (context->codec_priv_size);
798 memcpy (context->codec_priv, GST_BUFFER_DATA (codec_buf),
799 context->codec_priv_size);
803 } else if (!strcmp (mimetype, "video/x-theora")) {
804 const GValue *streamheader;
806 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
808 if (context->codec_priv != NULL) {
809 g_free (context->codec_priv);
810 context->codec_priv = NULL;
811 context->codec_priv_size = 0;
814 streamheader = gst_structure_get_value (structure, "streamheader");
815 if (!theora_streamheader_to_codecdata (streamheader, context)) {
816 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
817 ("theora stream headers missing or malformed"));
821 } else if (!strcmp (mimetype, "video/x-dirac")) {
822 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
825 } else if (!strcmp (mimetype, "video/mpeg")) {
828 gst_structure_get_int (structure, "mpegversion", &mpegversion);
829 switch (mpegversion) {
831 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
834 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
837 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
843 /* global headers may be in codec data */
844 if (codec_buf != NULL) {
845 context->codec_priv_size = GST_BUFFER_SIZE (codec_buf);
846 context->codec_priv = g_malloc0 (context->codec_priv_size);
847 memcpy (context->codec_priv, GST_BUFFER_DATA (codec_buf),
848 context->codec_priv_size);
852 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
854 /* can only make it here if preceding case verified it was version 3 */
855 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
858 } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
860 const GValue *mdpr_data;
862 gst_structure_get_int (structure, "rmversion", &rmversion);
865 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
868 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
871 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
874 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
880 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
881 if (mdpr_data != NULL) {
882 guint8 *priv_data = NULL;
883 guint priv_data_size = 0;
885 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
887 priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
888 priv_data = g_malloc0 (priv_data_size);
890 memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
892 context->codec_priv = priv_data;
893 context->codec_priv_size = priv_data_size;
902 /* N > 0 to expect a particular number of headers, negative if the
903 number of headers is variable */
905 xiphN_streamheader_to_codecdata (const GValue * streamheader,
906 GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
908 GstBuffer **buf = NULL;
911 guint bufi, i, offset, priv_data_size;
913 if (streamheader == NULL)
914 goto no_stream_headers;
916 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
919 bufarr = g_value_peek_pointer (streamheader);
920 if (bufarr->len <= 0 || bufarr->len > 255) /* at least one header, and count stored in a byte */
922 if (N > 0 && bufarr->len != N)
925 context->xiph_headers_to_skip = bufarr->len;
927 buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
928 for (i = 0; i < bufarr->len; i++) {
929 GValue *bufval = &g_array_index (bufarr, GValue, i);
931 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
933 goto wrong_content_type;
936 buf[i] = g_value_peek_pointer (bufval);
940 if (bufarr->len > 0) {
941 for (i = 0; i < bufarr->len - 1; i++) {
942 priv_data_size += GST_BUFFER_SIZE (buf[i]) / 0xff + 1;
946 for (i = 0; i < bufarr->len; ++i) {
947 priv_data_size += GST_BUFFER_SIZE (buf[i]);
950 priv_data = g_malloc0 (priv_data_size);
952 priv_data[0] = bufarr->len - 1;
955 if (bufarr->len > 0) {
956 for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
957 for (i = 0; i < GST_BUFFER_SIZE (buf[bufi]) / 0xff; ++i) {
958 priv_data[offset++] = 0xff;
960 priv_data[offset++] = GST_BUFFER_SIZE (buf[bufi]) % 0xff;
964 for (i = 0; i < bufarr->len; ++i) {
965 memcpy (priv_data + offset, GST_BUFFER_DATA (buf[i]),
966 GST_BUFFER_SIZE (buf[i]));
967 offset += GST_BUFFER_SIZE (buf[i]);
970 context->codec_priv = priv_data;
971 context->codec_priv_size = priv_data_size;
974 *p_buf0 = gst_buffer_ref (buf[0]);
983 GST_WARNING ("required streamheaders missing in sink caps!");
988 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
989 G_VALUE_TYPE_NAME (streamheader));
994 GST_WARNING ("got %u streamheaders, not 3 as expected", bufarr->len);
999 GST_WARNING ("streamheaders array does not contain GstBuffers");
1004 /* FIXME: after release make all code use xiph3_streamheader_to_codecdata() */
1006 xiph3_streamheader_to_codecdata (const GValue * streamheader,
1007 GstMatroskaTrackContext * context, GstBuffer ** p_buf0)
1012 guint i, offset, priv_data_size;
1014 if (streamheader == NULL)
1015 goto no_stream_headers;
1017 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1020 bufarr = g_value_peek_pointer (streamheader);
1021 if (bufarr->len != 3)
1024 context->xiph_headers_to_skip = bufarr->len;
1026 for (i = 0; i < 3; i++) {
1027 GValue *bufval = &g_array_index (bufarr, GValue, i);
1029 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER)
1030 goto wrong_content_type;
1032 buf[i] = g_value_peek_pointer (bufval);
1036 priv_data_size += GST_BUFFER_SIZE (buf[0]) / 0xff + 1;
1037 priv_data_size += GST_BUFFER_SIZE (buf[1]) / 0xff + 1;
1039 for (i = 0; i < 3; ++i) {
1040 priv_data_size += GST_BUFFER_SIZE (buf[i]);
1043 priv_data = g_malloc0 (priv_data_size);
1048 for (i = 0; i < GST_BUFFER_SIZE (buf[0]) / 0xff; ++i) {
1049 priv_data[offset++] = 0xff;
1051 priv_data[offset++] = GST_BUFFER_SIZE (buf[0]) % 0xff;
1053 for (i = 0; i < GST_BUFFER_SIZE (buf[1]) / 0xff; ++i) {
1054 priv_data[offset++] = 0xff;
1056 priv_data[offset++] = GST_BUFFER_SIZE (buf[1]) % 0xff;
1058 for (i = 0; i < 3; ++i) {
1059 memcpy (priv_data + offset, GST_BUFFER_DATA (buf[i]),
1060 GST_BUFFER_SIZE (buf[i]));
1061 offset += GST_BUFFER_SIZE (buf[i]);
1064 context->codec_priv = priv_data;
1065 context->codec_priv_size = priv_data_size;
1068 *p_buf0 = gst_buffer_ref (buf[0]);
1075 GST_WARNING ("required streamheaders missing in sink caps!");
1080 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1081 G_VALUE_TYPE_NAME (streamheader));
1086 GST_WARNING ("got %u streamheaders, not 3 as expected", bufarr->len);
1091 GST_WARNING ("streamheaders array does not contain GstBuffers");
1097 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1098 GstMatroskaTrackContext * context)
1100 GstBuffer *buf0 = NULL;
1102 /* FIXME: change to use xiphN_streamheader_to_codecdata() after release */
1103 if (!xiph3_streamheader_to_codecdata (streamheader, context, &buf0))
1106 if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 4) {
1107 GST_WARNING ("First vorbis header too small, ignoring");
1109 if (memcmp (GST_BUFFER_DATA (buf0) + 1, "vorbis", 6) == 0) {
1110 GstMatroskaTrackAudioContext *audiocontext;
1113 hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 4;
1114 audiocontext = (GstMatroskaTrackAudioContext *) context;
1115 audiocontext->channels = GST_READ_UINT8 (hdr);
1116 audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1121 gst_buffer_unref (buf0);
1127 theora_streamheader_to_codecdata (const GValue * streamheader,
1128 GstMatroskaTrackContext * context)
1130 GstBuffer *buf0 = NULL;
1132 /* FIXME: change to use xiphN_streamheader_to_codecdata() after release */
1133 if (!xiph3_streamheader_to_codecdata (streamheader, context, &buf0))
1136 if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 26) {
1137 GST_WARNING ("First theora header too small, ignoring");
1138 } else if (memcmp (GST_BUFFER_DATA (buf0), "\200theora\003\002", 9) != 0) {
1139 GST_WARNING ("First header not a theora identification header, ignoring");
1141 GstMatroskaTrackVideoContext *videocontext;
1142 guint fps_num, fps_denom, par_num, par_denom;
1145 hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 3 + 2 + 2;
1147 videocontext = (GstMatroskaTrackVideoContext *) context;
1148 videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1149 videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1150 hdr += 3 + 3 + 1 + 1;
1151 fps_num = GST_READ_UINT32_BE (hdr);
1152 fps_denom = GST_READ_UINT32_BE (hdr + 4);
1153 context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1154 fps_denom, fps_num);
1156 par_num = GST_READ_UINT32_BE (hdr) >> 8;
1157 par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1158 if (par_num > 0 && par_num > 0) {
1159 if (par_num > par_denom) {
1160 videocontext->display_width =
1161 videocontext->pixel_width * par_num / par_denom;
1162 videocontext->display_height = videocontext->pixel_height;
1163 } else if (par_num < par_denom) {
1164 videocontext->display_width = videocontext->pixel_width;
1165 videocontext->display_height =
1166 videocontext->pixel_height * par_denom / par_num;
1168 videocontext->display_width = 0;
1169 videocontext->display_height = 0;
1172 videocontext->display_width = 0;
1173 videocontext->display_height = 0;
1179 gst_buffer_unref (buf0);
1185 kate_streamheader_to_codecdata (const GValue * streamheader,
1186 GstMatroskaTrackContext * context)
1188 GstBuffer *buf0 = NULL;
1190 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1193 if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 64) { /* Kate ID header is 64 bytes */
1194 GST_WARNING ("First kate header too small, ignoring");
1195 } else if (memcmp (GST_BUFFER_DATA (buf0), "\200kate\0\0\0", 8) != 0) {
1196 GST_WARNING ("First header not a kate identification header, ignoring");
1200 gst_buffer_unref (buf0);
1206 flac_streamheader_to_codecdata (const GValue * streamheader,
1207 GstMatroskaTrackContext * context)
1214 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1215 GST_WARNING ("No or invalid streamheader field in the caps");
1219 bufarr = g_value_peek_pointer (streamheader);
1220 if (bufarr->len < 2) {
1221 GST_WARNING ("Too few headers in streamheader field");
1225 context->xiph_headers_to_skip = bufarr->len + 1;
1227 bufval = &g_array_index (bufarr, GValue, 0);
1228 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1229 GST_WARNING ("streamheaders array does not contain GstBuffers");
1233 buffer = g_value_peek_pointer (bufval);
1235 /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1236 if (GST_BUFFER_SIZE (buffer) < 9 + 4 + 4 + 34
1237 || memcmp (GST_BUFFER_DATA (buffer) + 1, "FLAC", 4) != 0
1238 || memcmp (GST_BUFFER_DATA (buffer) + 9, "fLaC", 4) != 0) {
1239 GST_WARNING ("Invalid streamheader for FLAC");
1243 context->codec_priv = g_malloc (GST_BUFFER_SIZE (buffer) - 9);
1244 context->codec_priv_size = GST_BUFFER_SIZE (buffer) - 9;
1245 memcpy (context->codec_priv, GST_BUFFER_DATA (buffer) + 9,
1246 GST_BUFFER_SIZE (buffer) - 9);
1248 for (i = 1; i < bufarr->len; i++) {
1249 bufval = &g_array_index (bufarr, GValue, i);
1251 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1252 g_free (context->codec_priv);
1253 context->codec_priv = NULL;
1254 context->codec_priv_size = 0;
1255 GST_WARNING ("streamheaders array does not contain GstBuffers");
1259 buffer = g_value_peek_pointer (bufval);
1261 context->codec_priv =
1262 g_realloc (context->codec_priv,
1263 context->codec_priv_size + GST_BUFFER_SIZE (buffer));
1264 memcpy ((guint8 *) context->codec_priv + context->codec_priv_size,
1265 GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
1266 context->codec_priv_size =
1267 context->codec_priv_size + GST_BUFFER_SIZE (buffer);
1274 speex_streamheader_to_codecdata (const GValue * streamheader,
1275 GstMatroskaTrackContext * context)
1281 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1282 GST_WARNING ("No or invalid streamheader field in the caps");
1286 bufarr = g_value_peek_pointer (streamheader);
1287 if (bufarr->len != 2) {
1288 GST_WARNING ("Too few headers in streamheader field");
1292 context->xiph_headers_to_skip = bufarr->len + 1;
1294 bufval = &g_array_index (bufarr, GValue, 0);
1295 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1296 GST_WARNING ("streamheaders array does not contain GstBuffers");
1300 buffer = g_value_peek_pointer (bufval);
1302 if (GST_BUFFER_SIZE (buffer) < 80
1303 || memcmp (GST_BUFFER_DATA (buffer), "Speex ", 8) != 0) {
1304 GST_WARNING ("Invalid streamheader for Speex");
1308 context->codec_priv = g_malloc (GST_BUFFER_SIZE (buffer));
1309 context->codec_priv_size = GST_BUFFER_SIZE (buffer);
1310 memcpy (context->codec_priv, GST_BUFFER_DATA (buffer),
1311 GST_BUFFER_SIZE (buffer));
1313 bufval = &g_array_index (bufarr, GValue, 1);
1315 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1316 g_free (context->codec_priv);
1317 context->codec_priv = NULL;
1318 context->codec_priv_size = 0;
1319 GST_WARNING ("streamheaders array does not contain GstBuffers");
1323 buffer = g_value_peek_pointer (bufval);
1325 context->codec_priv =
1326 g_realloc (context->codec_priv,
1327 context->codec_priv_size + GST_BUFFER_SIZE (buffer));
1328 memcpy ((guint8 *) context->codec_priv + context->codec_priv_size,
1329 GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
1330 context->codec_priv_size =
1331 context->codec_priv_size + GST_BUFFER_SIZE (buffer);
1337 aac_codec_data_to_codec_id (const GstBuffer * buf)
1342 /* default to MAIN */
1345 if (GST_BUFFER_SIZE (buf) >= 2) {
1346 profile = GST_READ_UINT8 (GST_BUFFER_DATA (buf));
1364 GST_WARNING ("unknown AAC profile, defaulting to MAIN");
1373 * gst_matroska_mux_audio_pad_setcaps:
1374 * @pad: Pad which got the caps.
1377 * Setcaps function for audio sink pad.
1379 * Returns: #TRUE on success.
1382 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1384 GstMatroskaTrackContext *context = NULL;
1385 GstMatroskaTrackAudioContext *audiocontext;
1386 GstMatroskaMux *mux;
1387 GstMatroskaPad *collect_pad;
1388 const gchar *mimetype;
1389 gint samplerate = 0, channels = 0;
1390 GstStructure *structure;
1392 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1395 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1396 g_assert (collect_pad);
1397 context = collect_pad->track;
1399 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
1400 audiocontext = (GstMatroskaTrackAudioContext *) context;
1402 structure = gst_caps_get_structure (caps, 0);
1403 mimetype = gst_structure_get_name (structure);
1406 gst_structure_get_int (structure, "rate", &samplerate);
1407 gst_structure_get_int (structure, "channels", &channels);
1409 audiocontext->samplerate = samplerate;
1410 audiocontext->channels = channels;
1411 audiocontext->bitdepth = 0;
1412 context->default_duration = 0;
1414 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1415 * data and other settings
1419 if (!strcmp (mimetype, "audio/mpeg")) {
1420 gint mpegversion = 0;
1421 const GValue *codec_data;
1422 const GstBuffer *buf = NULL;
1424 codec_data = gst_structure_get_value (structure, "codec_data");
1426 buf = gst_value_get_buffer (codec_data);
1428 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1429 switch (mpegversion) {
1435 gst_structure_get_int (structure, "layer", &layer);
1437 if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
1438 GST_WARNING_OBJECT (mux,
1439 "Unable to determine MPEG audio version, assuming 1");
1445 else if (layer == 2)
1447 else if (version == 2)
1452 context->default_duration =
1453 gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
1457 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
1460 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
1463 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
1473 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2 "%s",
1474 aac_codec_data_to_codec_id (buf));
1476 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
1483 g_strdup_printf (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4 "%s",
1484 aac_codec_data_to_codec_id (buf));
1486 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
1495 } else if (!strcmp (mimetype, "audio/x-raw-int")) {
1497 gint endianness = G_LITTLE_ENDIAN;
1498 gboolean signedness = TRUE;
1500 if (!gst_structure_get_int (structure, "width", &width) ||
1501 !gst_structure_get_int (structure, "depth", &depth) ||
1502 !gst_structure_get_boolean (structure, "signed", &signedness)) {
1503 GST_DEBUG_OBJECT (mux, "broken caps, width/depth/signed field missing");
1508 !gst_structure_get_int (structure, "endianness", &endianness)) {
1509 GST_DEBUG_OBJECT (mux, "broken caps, no endianness specified");
1513 if (width != depth) {
1514 GST_DEBUG_OBJECT (mux, "width must be same as depth!");
1518 /* FIXME: where is this spec'ed out? (tpm) */
1519 if ((width == 8 && signedness) || (width >= 16 && !signedness)) {
1520 GST_DEBUG_OBJECT (mux, "8-bit PCM must be unsigned, 16-bit PCM signed");
1524 audiocontext->bitdepth = depth;
1525 if (endianness == G_BIG_ENDIAN)
1526 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
1528 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
1531 } else if (!strcmp (mimetype, "audio/x-raw-float")) {
1534 if (!gst_structure_get_int (structure, "width", &width)) {
1535 GST_DEBUG_OBJECT (mux, "broken caps, width field missing");
1539 audiocontext->bitdepth = width;
1540 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
1543 } else if (!strcmp (mimetype, "audio/x-vorbis")) {
1544 const GValue *streamheader;
1546 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
1548 if (context->codec_priv != NULL) {
1549 g_free (context->codec_priv);
1550 context->codec_priv = NULL;
1551 context->codec_priv_size = 0;
1554 streamheader = gst_structure_get_value (structure, "streamheader");
1555 if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
1556 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1557 ("vorbis stream headers missing or malformed"));
1561 } else if (!strcmp (mimetype, "audio/x-flac")) {
1562 const GValue *streamheader;
1564 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
1565 if (context->codec_priv != NULL) {
1566 g_free (context->codec_priv);
1567 context->codec_priv = NULL;
1568 context->codec_priv_size = 0;
1571 streamheader = gst_structure_get_value (structure, "streamheader");
1572 if (!flac_streamheader_to_codecdata (streamheader, context)) {
1573 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1574 ("flac stream headers missing or malformed"));
1578 } else if (!strcmp (mimetype, "audio/x-speex")) {
1579 const GValue *streamheader;
1581 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
1582 if (context->codec_priv != NULL) {
1583 g_free (context->codec_priv);
1584 context->codec_priv = NULL;
1585 context->codec_priv_size = 0;
1588 streamheader = gst_structure_get_value (structure, "streamheader");
1589 if (!speex_streamheader_to_codecdata (streamheader, context)) {
1590 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1591 ("speex stream headers missing or malformed"));
1595 } else if (!strcmp (mimetype, "audio/x-ac3")) {
1596 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AC3);
1599 } else if (!strcmp (mimetype, "audio/x-tta")) {
1602 /* TTA frame duration */
1603 context->default_duration = 1.04489795918367346939 * GST_SECOND;
1605 gst_structure_get_int (structure, "width", &width);
1606 audiocontext->bitdepth = width;
1607 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_TTA);
1610 } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
1612 const GValue *mdpr_data;
1614 gst_structure_get_int (structure, "raversion", &raversion);
1615 switch (raversion) {
1617 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
1620 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
1623 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
1629 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1630 if (mdpr_data != NULL) {
1631 guint8 *priv_data = NULL;
1632 guint priv_data_size = 0;
1634 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1636 priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
1637 priv_data = g_malloc0 (priv_data_size);
1639 memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
1641 context->codec_priv = priv_data;
1642 context->codec_priv_size = priv_data_size;
1653 * gst_matroska_mux_subtitle_pad_setcaps:
1654 * @pad: Pad which got the caps.
1657 * Setcaps function for subtitle sink pad.
1659 * Returns: #TRUE on success.
1662 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
1665 * Consider this as boilerplate code for now. There is
1666 * no single subtitle creation element in GStreamer,
1667 * neither do I know how subtitling works at all. */
1669 /* There is now (at least) one such alement (kateenc), and I'm going
1670 to handle it here and claim it works when it can be piped back
1671 through GStreamer and VLC */
1673 GstMatroskaTrackContext *context = NULL;
1674 GstMatroskaTrackSubtitleContext *scontext;
1675 GstMatroskaMux *mux;
1676 GstMatroskaPad *collect_pad;
1677 const gchar *mimetype;
1678 GstStructure *structure;
1680 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1683 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1684 g_assert (collect_pad);
1685 context = collect_pad->track;
1687 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
1688 scontext = (GstMatroskaTrackSubtitleContext *) context;
1690 structure = gst_caps_get_structure (caps, 0);
1691 mimetype = gst_structure_get_name (structure);
1694 scontext->check_utf8 = 1;
1695 scontext->invalid_utf8 = 0;
1696 context->default_duration = 0;
1698 /* TODO: - other format than Kate */
1700 if (!strcmp (mimetype, "subtitle/x-kate")) {
1701 const GValue *streamheader;
1703 context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
1705 if (context->codec_priv != NULL) {
1706 g_free (context->codec_priv);
1707 context->codec_priv = NULL;
1708 context->codec_priv_size = 0;
1711 streamheader = gst_structure_get_value (structure, "streamheader");
1712 if (!kate_streamheader_to_codecdata (streamheader, context)) {
1713 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1714 ("kate stream headers missing or malformed"));
1725 * gst_matroska_mux_request_new_pad:
1726 * @element: #GstMatroskaMux.
1727 * @templ: #GstPadTemplate.
1728 * @pad_name: New pad name.
1730 * Request pad function for sink templates.
1732 * Returns: New #GstPad.
1735 gst_matroska_mux_request_new_pad (GstElement * element,
1736 GstPadTemplate * templ, const gchar * pad_name)
1738 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
1739 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
1740 GstMatroskaPad *collect_pad;
1741 GstPad *newpad = NULL;
1743 GstPadSetCapsFunction setcapsfunc = NULL;
1744 GstMatroskaTrackContext *context = NULL;
1746 if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
1747 name = g_strdup_printf ("audio_%d", mux->num_a_streams++);
1748 setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
1749 context = (GstMatroskaTrackContext *)
1750 g_new0 (GstMatroskaTrackAudioContext, 1);
1751 context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
1752 context->name = g_strdup ("Audio");
1753 } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
1754 name = g_strdup_printf ("video_%d", mux->num_v_streams++);
1755 setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
1756 context = (GstMatroskaTrackContext *)
1757 g_new0 (GstMatroskaTrackVideoContext, 1);
1758 context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
1759 context->name = g_strdup ("Video");
1760 } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%d")) {
1761 name = g_strdup_printf ("subtitle_%d", mux->num_t_streams++);
1762 setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
1763 context = (GstMatroskaTrackContext *)
1764 g_new0 (GstMatroskaTrackSubtitleContext, 1);
1765 context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
1766 context->name = g_strdup ("Subtitle");
1768 GST_WARNING_OBJECT (mux, "This is not our template!");
1772 newpad = gst_pad_new_from_template (templ, name);
1774 collect_pad = (GstMatroskaPad *)
1775 gst_collect_pads_add_pad_full (mux->collect, newpad,
1776 sizeof (GstMatroskaPad),
1777 (GstCollectDataDestroyNotify) gst_matroska_pad_free);
1779 collect_pad->track = context;
1780 gst_matroska_pad_reset (collect_pad, FALSE);
1782 /* FIXME: hacked way to override/extend the event function of
1783 * GstCollectPads; because it sets its own event function giving the
1784 * element no access to events.
1785 * TODO GstCollectPads should really give its 'users' a clean chance to
1786 * properly handle events that are not meant for collectpads itself.
1787 * Perhaps a callback or so, though rejected (?) in #340060.
1788 * This would allow (clean) transcoding of info from demuxer/streams
1789 * to another muxer */
1790 mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
1791 gst_pad_set_event_function (newpad,
1792 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event));
1794 gst_pad_set_setcaps_function (newpad, setcapsfunc);
1795 gst_pad_set_active (newpad, TRUE);
1796 gst_element_add_pad (element, newpad);
1803 * gst_matroska_mux_release_pad:
1804 * @element: #GstMatroskaMux.
1805 * @pad: Pad to release.
1807 * Release a previously requested pad.
1810 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
1812 GstMatroskaMux *mux;
1815 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1817 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
1818 GstCollectData *cdata = (GstCollectData *) walk->data;
1819 GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
1821 if (cdata->pad == pad) {
1822 GstClockTime min_dur; /* observed minimum duration */
1824 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
1825 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
1826 min_dur = GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
1827 if (collect_pad->duration < min_dur)
1828 collect_pad->duration = min_dur;
1831 if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
1832 mux->duration < collect_pad->duration)
1833 mux->duration = collect_pad->duration;
1839 gst_collect_pads_remove_pad (mux->collect, pad);
1840 if (gst_element_remove_pad (element, pad))
1846 * gst_matroska_mux_track_header:
1847 * @mux: #GstMatroskaMux
1848 * @context: Tack context.
1850 * Write a track header.
1853 gst_matroska_mux_track_header (GstMatroskaMux * mux,
1854 GstMatroskaTrackContext * context)
1856 GstEbmlWrite *ebml = mux->ebml_write;
1859 /* TODO: check if everything necessary is written and check default values */
1861 /* track type goes before the type-specific stuff */
1862 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
1863 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
1865 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID,
1866 gst_matroska_mux_create_uid ());
1867 if (context->default_duration) {
1868 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
1869 context->default_duration);
1871 if (context->language) {
1872 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
1876 /* type-specific stuff */
1877 switch (context->type) {
1878 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
1879 GstMatroskaTrackVideoContext *videocontext =
1880 (GstMatroskaTrackVideoContext *) context;
1882 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
1883 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
1884 videocontext->pixel_width);
1885 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
1886 videocontext->pixel_height);
1887 if (videocontext->display_width && videocontext->display_height) {
1888 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
1889 videocontext->display_width);
1890 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
1891 videocontext->display_height);
1893 if (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED)
1894 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
1895 if (videocontext->fourcc) {
1896 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
1898 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
1899 (gpointer) & fcc_le, 4);
1901 gst_ebml_write_master_finish (ebml, master);
1906 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
1907 GstMatroskaTrackAudioContext *audiocontext =
1908 (GstMatroskaTrackAudioContext *) context;
1910 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
1911 if (audiocontext->samplerate != 8000)
1912 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
1913 audiocontext->samplerate);
1914 if (audiocontext->channels != 1)
1915 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
1916 audiocontext->channels);
1917 if (audiocontext->bitdepth) {
1918 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
1919 audiocontext->bitdepth);
1921 gst_ebml_write_master_finish (ebml, master);
1927 /* doesn't need type-specific data */
1931 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
1932 if (context->codec_priv)
1933 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
1934 context->codec_priv, context->codec_priv_size);
1935 /* FIXME: until we have a nice way of getting the codecname
1936 * out of the caps, I'm not going to enable this. Too much
1937 * (useless, double, boring) work... */
1938 /* TODO: Use value from tags if any */
1939 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
1940 context->codec_name); */
1941 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
1946 * gst_matroska_mux_start:
1947 * @mux: #GstMatroskaMux
1949 * Start a new matroska file (write headers etc...)
1952 gst_matroska_mux_start (GstMatroskaMux * mux)
1954 GstEbmlWrite *ebml = mux->ebml_write;
1955 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
1956 GST_MATROSKA_ID_TRACKS,
1957 GST_MATROSKA_ID_CUES,
1958 GST_MATROSKA_ID_TAGS,
1961 guint64 master, child;
1965 GstClockTime duration = 0;
1966 guint32 segment_uid[4];
1967 GTimeVal time = { 0, 0 };
1969 /* we start with a EBML header */
1970 gst_ebml_write_header (ebml, "matroska", mux->matroska_version);
1972 /* start a segment */
1974 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
1975 mux->segment_master = ebml->pos;
1977 /* the rest of the header is cached */
1978 gst_ebml_write_set_cache (ebml, 0x1000);
1980 /* seekhead (table of contents) - we set the positions later */
1981 mux->seekhead_pos = ebml->pos;
1982 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
1983 for (i = 0; seekhead_id[i] != 0; i++) {
1984 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
1985 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
1986 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
1987 gst_ebml_write_master_finish (ebml, child);
1989 gst_ebml_write_master_finish (ebml, master);
1992 mux->info_pos = ebml->pos;
1993 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
1994 for (i = 0; i < 4; i++) {
1995 segment_uid[i] = g_random_int ();
1997 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
1998 (guint8 *) segment_uid, 16);
1999 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
2000 mux->duration_pos = ebml->pos;
2002 for (collected = mux->collect->data; collected;
2003 collected = g_slist_next (collected)) {
2004 GstMatroskaPad *collect_pad;
2005 GstFormat format = GST_FORMAT_TIME;
2007 gint64 trackduration;
2009 collect_pad = (GstMatroskaPad *) collected->data;
2010 thepad = collect_pad->collect.pad;
2012 /* Query the total length of the track. */
2013 GST_DEBUG_OBJECT (thepad, "querying peer duration");
2014 if (gst_pad_query_peer_duration (thepad, &format, &trackduration)) {
2015 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
2016 GST_TIME_ARGS (trackduration));
2017 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
2018 duration = (GstClockTime) trackduration;
2022 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2023 gst_guint64_to_gdouble (duration) /
2024 gst_guint64_to_gdouble (mux->time_scale));
2026 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
2027 "GStreamer plugin version " PACKAGE_VERSION);
2028 if (mux->writing_app && mux->writing_app[0]) {
2029 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
2031 g_get_current_time (&time);
2032 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
2033 gst_ebml_write_master_finish (ebml, master);
2036 mux->tracks_pos = ebml->pos;
2037 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
2039 for (collected = mux->collect->data; collected;
2040 collected = g_slist_next (collected)) {
2041 GstMatroskaPad *collect_pad;
2044 collect_pad = (GstMatroskaPad *) collected->data;
2045 thepad = collect_pad->collect.pad;
2047 if (gst_pad_is_linked (thepad) && gst_pad_is_active (thepad) &&
2048 collect_pad->track->codec_id != 0) {
2049 collect_pad->track->num = tracknum++;
2050 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
2051 gst_matroska_mux_track_header (mux, collect_pad->track);
2052 gst_ebml_write_master_finish (ebml, child);
2055 gst_ebml_write_master_finish (ebml, master);
2057 /* lastly, flush the cache */
2058 gst_ebml_write_flush_cache (ebml);
2062 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
2065 /* TODO: more sensible tag mappings */
2068 gchar *matroska_tagname;
2069 gchar *gstreamer_tagname;
2073 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
2074 GST_MATROSKA_TAG_ID_AUTHOR, GST_TAG_ARTIST}, {
2075 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
2076 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
2077 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
2078 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
2079 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
2080 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
2081 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
2082 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
2083 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
2084 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
2085 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
2086 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
2087 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
2089 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
2091 guint64 simpletag_master;
2093 for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) {
2094 const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
2095 const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
2097 if (strcmp (tagname_gst, tag) == 0) {
2098 GValue src = { 0, };
2101 if (!gst_tag_list_copy_value (&src, list, tag))
2103 if ((dest = gst_value_serialize (&src))) {
2105 simpletag_master = gst_ebml_write_master_start (ebml,
2106 GST_MATROSKA_ID_SIMPLETAG);
2107 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
2108 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
2109 gst_ebml_write_master_finish (ebml, simpletag_master);
2112 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
2114 g_value_unset (&src);
2122 * gst_matroska_mux_finish:
2123 * @mux: #GstMatroskaMux
2125 * Finish a new matroska file (write index etc...)
2128 gst_matroska_mux_finish (GstMatroskaMux * mux)
2130 GstEbmlWrite *ebml = mux->ebml_write;
2132 guint64 duration = 0;
2134 const GstTagList *tags;
2136 /* finish last cluster */
2138 gst_ebml_write_master_finish (ebml, mux->cluster);
2142 if (mux->index != NULL) {
2144 guint64 master, pointentry_master, trackpos_master;
2146 mux->cues_pos = ebml->pos;
2147 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
2148 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
2150 for (n = 0; n < mux->num_indexes; n++) {
2151 GstMatroskaIndex *idx = &mux->index[n];
2153 pointentry_master = gst_ebml_write_master_start (ebml,
2154 GST_MATROSKA_ID_POINTENTRY);
2155 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
2156 idx->time / mux->time_scale);
2157 trackpos_master = gst_ebml_write_master_start (ebml,
2158 GST_MATROSKA_ID_CUETRACKPOSITIONS);
2159 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
2160 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
2161 idx->pos - mux->segment_master);
2162 gst_ebml_write_master_finish (ebml, trackpos_master);
2163 gst_ebml_write_master_finish (ebml, pointentry_master);
2166 gst_ebml_write_master_finish (ebml, master);
2167 gst_ebml_write_flush_cache (ebml);
2171 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
2173 if (tags != NULL && !gst_tag_list_is_empty (tags)) {
2174 guint64 master_tags, master_tag;
2176 GST_DEBUG ("Writing tags");
2178 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
2179 mux->tags_pos = ebml->pos;
2180 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
2181 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
2182 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
2183 gst_ebml_write_master_finish (ebml, master_tag);
2184 gst_ebml_write_master_finish (ebml, master_tags);
2187 /* update seekhead. We know that:
2188 * - a seekhead contains 4 entries.
2189 * - order of entries is as above.
2190 * - a seekhead has a 4-byte header + 8-byte length
2191 * - each entry is 2-byte master, 2-byte ID pointer,
2192 * 2-byte length pointer, all 8/1-byte length, 4-
2193 * byte ID and 8-byte length pointer, where the
2194 * length pointer starts at 20.
2195 * - all entries are local to the segment (so pos - segment_master).
2196 * - so each entry is at 12 + 20 + num * 28. */
2197 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
2198 mux->info_pos - mux->segment_master);
2199 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
2200 mux->tracks_pos - mux->segment_master);
2201 if (mux->index != NULL) {
2202 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
2203 mux->cues_pos - mux->segment_master);
2206 guint64 my_pos = ebml->pos;
2208 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
2209 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2210 gst_ebml_write_seek (ebml, my_pos);
2213 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
2214 mux->tags_pos - mux->segment_master);
2217 guint64 my_pos = ebml->pos;
2219 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
2220 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
2221 gst_ebml_write_seek (ebml, my_pos);
2224 /* update duration */
2225 /* first get the overall duration */
2226 /* a released track may have left a duration in here */
2227 duration = mux->duration;
2228 for (collected = mux->collect->data; collected;
2229 collected = g_slist_next (collected)) {
2230 GstMatroskaPad *collect_pad;
2231 GstClockTime min_duration; /* observed minimum duration */
2233 collect_pad = (GstMatroskaPad *) collected->data;
2235 GST_DEBUG_OBJECT (mux, "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
2236 " end ts %" GST_TIME_FORMAT, collect_pad,
2237 GST_TIME_ARGS (collect_pad->start_ts),
2238 GST_TIME_ARGS (collect_pad->end_ts));
2240 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2241 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2243 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2244 if (collect_pad->duration < min_duration)
2245 collect_pad->duration = min_duration;
2246 GST_DEBUG_OBJECT (collect_pad, "final track duration: %" GST_TIME_FORMAT,
2247 GST_TIME_ARGS (collect_pad->duration));
2250 if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
2251 duration < collect_pad->duration)
2252 duration = collect_pad->duration;
2254 if (duration != 0) {
2255 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
2256 GST_TIME_ARGS (duration));
2257 pos = mux->ebml_write->pos;
2258 gst_ebml_write_seek (ebml, mux->duration_pos);
2259 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
2260 gst_guint64_to_gdouble (duration) /
2261 gst_guint64_to_gdouble (mux->time_scale));
2262 gst_ebml_write_seek (ebml, pos);
2265 guint64 my_pos = ebml->pos;
2267 gst_ebml_write_seek (ebml, mux->duration_pos);
2268 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
2269 gst_ebml_write_seek (ebml, my_pos);
2272 /* finish segment - this also writes element length */
2273 gst_ebml_write_master_finish (ebml, mux->segment_pos);
2278 * gst_matroska_mux_best_pad:
2279 * @mux: #GstMatroskaMux
2280 * @popped: True if at least one buffer was popped from #GstCollectPads
2282 * Find a pad with the oldest data
2283 * (data from this pad should be written first).
2285 * Returns: Selected pad.
2287 static GstMatroskaPad *
2288 gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
2291 GstMatroskaPad *best = NULL;
2294 for (collected = mux->collect->data; collected;
2295 collected = g_slist_next (collected)) {
2296 GstMatroskaPad *collect_pad;
2298 collect_pad = (GstMatroskaPad *) collected->data;
2299 /* fetch a new buffer if needed */
2300 if (collect_pad->buffer == NULL) {
2301 collect_pad->buffer = gst_collect_pads_pop (mux->collect,
2302 (GstCollectData *) collect_pad);
2304 if (collect_pad->buffer != NULL)
2308 /* if we have a buffer check if it is better then the current best one */
2309 if (collect_pad->buffer != NULL) {
2310 if (best == NULL || !GST_BUFFER_TIMESTAMP_IS_VALID (collect_pad->buffer)
2311 || (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)
2312 && GST_BUFFER_TIMESTAMP (collect_pad->buffer) <
2313 GST_BUFFER_TIMESTAMP (best->buffer))) {
2323 * gst_matroska_mux_buffer_header:
2324 * @track: Track context.
2325 * @relative_timestamp: relative timestamp of the buffer
2326 * @flags: Buffer flags.
2328 * Create a buffer containing buffer header.
2330 * Returns: New buffer.
2333 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
2334 gint16 relative_timestamp, int flags)
2338 hdr = gst_buffer_new_and_alloc (4);
2339 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
2340 GST_BUFFER_DATA (hdr)[0] = track->num | 0x80;
2341 /* time relative to clustertime */
2342 GST_WRITE_UINT16_BE (GST_BUFFER_DATA (hdr) + 1, relative_timestamp);
2345 GST_BUFFER_DATA (hdr)[3] = flags;
2351 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
2352 GstMatroskaPad * collect_pad, GstBuffer * buf)
2354 GstMatroskaTrackVideoContext *ctx =
2355 (GstMatroskaTrackVideoContext *) collect_pad->track;
2356 const guint8 *data = GST_BUFFER_DATA (buf);
2357 guint size = GST_BUFFER_SIZE (buf);
2359 guint32 next_parse_offset;
2360 GstBuffer *ret = NULL;
2361 gboolean is_picture = FALSE;
2363 if (GST_BUFFER_SIZE (buf) < 13) {
2364 gst_buffer_unref (buf);
2368 /* Check if this buffer contains a picture packet */
2369 while (size >= 13) {
2370 if (GST_READ_UINT32_BE (data) != 0x42424344) {
2371 gst_buffer_unref (buf);
2375 parse_code = GST_READ_UINT8 (data + 4);
2376 if (parse_code == 0x00) {
2377 if (ctx->dirac_unit) {
2378 gst_buffer_unref (ctx->dirac_unit);
2379 ctx->dirac_unit = NULL;
2381 } else if (parse_code & 0x08) {
2386 next_parse_offset = GST_READ_UINT32_BE (data + 5);
2388 data += next_parse_offset;
2389 size -= next_parse_offset;
2392 if (ctx->dirac_unit)
2393 ctx->dirac_unit = gst_buffer_join (ctx->dirac_unit, gst_buffer_ref (buf));
2395 ctx->dirac_unit = gst_buffer_ref (buf);
2398 ret = gst_buffer_make_metadata_writable (ctx->dirac_unit);
2399 ctx->dirac_unit = NULL;
2400 gst_buffer_copy_metadata (ret, buf,
2401 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
2402 GST_BUFFER_COPY_CAPS);
2403 gst_buffer_unref (buf);
2405 gst_buffer_unref (buf);
2413 * gst_matroska_mux_write_data:
2414 * @mux: #GstMatroskaMux
2415 * @collect_pad: #GstMatroskaPad with the data
2417 * Write collected data (called from gst_matroska_mux_collected).
2419 * Returns: Result of the gst_pad_push issued to write the data.
2421 static GstFlowReturn
2422 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
2424 GstEbmlWrite *ebml = mux->ebml_write;
2425 GstBuffer *buf, *hdr;
2427 gboolean write_duration;
2428 gint16 relative_timestamp;
2429 gint64 relative_timestamp64;
2430 guint64 block_duration;
2431 gboolean is_video_keyframe = FALSE;
2434 buf = collect_pad->buffer;
2435 collect_pad->buffer = NULL;
2437 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
2438 if (collect_pad->track->xiph_headers_to_skip > 0) {
2439 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
2440 gst_buffer_unref (buf);
2441 --collect_pad->track->xiph_headers_to_skip;
2445 /* for dirac we have to queue up everything up to a picture unit */
2446 if (collect_pad->track->codec_id != NULL &&
2447 strcmp (collect_pad->track->codec_id,
2448 GST_MATROSKA_CODEC_ID_VIDEO_DIRAC) == 0) {
2449 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
2454 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
2455 * this would wreak havoc with time stored in matroska file */
2456 /* TODO: maybe calculate a timestamp by using the previous timestamp
2457 * and default duration */
2458 if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2459 GST_WARNING_OBJECT (collect_pad->collect.pad,
2460 "Invalid buffer timestamp; dropping buffer");
2461 gst_buffer_unref (buf);
2465 /* set the timestamp for outgoing buffers */
2466 ebml->timestamp = GST_BUFFER_TIMESTAMP (buf);
2468 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
2469 !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
2470 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
2471 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2472 is_video_keyframe = TRUE;
2476 /* start a new cluster every two seconds or at keyframe */
2477 if (mux->cluster_time + GST_SECOND * 2 < GST_BUFFER_TIMESTAMP (buf)
2478 || is_video_keyframe) {
2480 gst_ebml_write_master_finish (ebml, mux->cluster);
2481 mux->cluster_pos = ebml->pos;
2483 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2484 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2485 GST_BUFFER_TIMESTAMP (buf) / mux->time_scale);
2486 mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2491 mux->cluster_pos = ebml->pos;
2492 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
2493 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
2494 GST_BUFFER_TIMESTAMP (buf) / mux->time_scale);
2495 mux->cluster_time = GST_BUFFER_TIMESTAMP (buf);
2498 /* update duration of this track */
2499 if (GST_BUFFER_DURATION_IS_VALID (buf))
2500 collect_pad->duration += GST_BUFFER_DURATION (buf);
2502 /* We currently write an index entry for each keyframe in a
2503 * video track or one entry for each cluster in an audio track
2504 * for audio only files. This can be largely improved, such as doing
2505 * one for each keyframe or each second (for all-keyframe
2506 * streams), only the *first* video track. But that'll come later... */
2508 /* TODO: index is useful for every track, should contain the number of
2509 * the block in the cluster which contains the timestamp
2511 if (is_video_keyframe) {
2512 GstMatroskaIndex *idx;
2514 if (mux->num_indexes % 32 == 0) {
2515 mux->index = g_renew (GstMatroskaIndex, mux->index,
2516 mux->num_indexes + 32);
2518 idx = &mux->index[mux->num_indexes++];
2520 idx->pos = mux->cluster_pos;
2521 idx->time = GST_BUFFER_TIMESTAMP (buf);
2522 idx->track = collect_pad->track->num;
2523 } else if ((collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
2524 (mux->num_streams == 1)) {
2525 GstMatroskaIndex *idx;
2527 if (mux->num_indexes % 32 == 0) {
2528 mux->index = g_renew (GstMatroskaIndex, mux->index,
2529 mux->num_indexes + 32);
2531 idx = &mux->index[mux->num_indexes++];
2533 idx->pos = mux->cluster_pos;
2534 idx->time = GST_BUFFER_TIMESTAMP (buf);
2535 idx->track = collect_pad->track->num;
2538 /* Check if the duration differs from the default duration. */
2539 write_duration = FALSE;
2540 block_duration = GST_BUFFER_DURATION (buf);
2541 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
2542 if (block_duration != collect_pad->track->default_duration) {
2543 write_duration = TRUE;
2547 /* write the block, for matroska v2 use SimpleBlock if possible
2548 * one slice (*breath*).
2549 * FIXME: Need to do correct lacing! */
2550 relative_timestamp64 = GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time;
2551 if (relative_timestamp64 >= 0) {
2552 /* round the timestamp */
2553 relative_timestamp64 += mux->time_scale / 2;
2555 /* round the timestamp */
2556 relative_timestamp64 -= mux->time_scale / 2;
2558 relative_timestamp = relative_timestamp64 / (gint64) mux->time_scale;
2559 if (mux->matroska_version > 1 && !write_duration) {
2561 GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : 0x80;
2564 gst_matroska_mux_create_buffer_header (collect_pad->track,
2565 relative_timestamp, flags);
2566 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
2567 GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
2568 gst_ebml_write_buffer (ebml, hdr);
2569 gst_ebml_write_buffer (ebml, buf);
2571 return gst_ebml_last_write_result (ebml);
2573 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
2575 gst_matroska_mux_create_buffer_header (collect_pad->track,
2576 relative_timestamp, 0);
2577 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
2578 GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
2579 gst_ebml_write_buffer (ebml, hdr);
2580 gst_ebml_write_buffer (ebml, buf);
2581 if (write_duration) {
2582 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION,
2583 block_duration / mux->time_scale);
2585 gst_ebml_write_master_finish (ebml, blockgroup);
2586 return gst_ebml_last_write_result (ebml);
2592 * gst_matroska_mux_collected:
2593 * @pads: #GstCollectPads
2594 * @uuser_data: #GstMatroskaMux
2596 * Collectpads callback.
2598 * Returns: #GstFlowReturn
2600 static GstFlowReturn
2601 gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
2603 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
2604 GstMatroskaPad *best;
2608 GST_DEBUG_OBJECT (mux, "Collected pads");
2610 /* start with a header */
2611 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
2612 if (mux->collect->data == NULL) {
2613 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2614 ("No input streams configured"));
2615 return GST_FLOW_ERROR;
2617 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
2618 gst_matroska_mux_start (mux);
2619 mux->state = GST_MATROSKA_MUX_STATE_DATA;
2623 /* which stream to write from? */
2624 best = gst_matroska_mux_best_pad (mux, &popped);
2626 /* if there is no best pad, we have reached EOS */
2628 GST_DEBUG_OBJECT (mux, "No best pad finishing...");
2629 gst_matroska_mux_finish (mux);
2630 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
2631 ret = GST_FLOW_UNEXPECTED;
2634 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
2635 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
2636 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (best->buffer)),
2637 GST_TIME_ARGS (GST_BUFFER_DURATION (best->buffer)));
2639 /* make note of first and last encountered timestamps, so we can calculate
2640 * the actual duration later when we send an updated header on eos */
2641 if (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)) {
2642 GstClockTime start_ts = GST_BUFFER_TIMESTAMP (best->buffer);
2643 GstClockTime end_ts = start_ts;
2645 if (GST_BUFFER_DURATION_IS_VALID (best->buffer))
2646 end_ts += GST_BUFFER_DURATION (best->buffer);
2647 else if (best->track->default_duration)
2648 end_ts += best->track->default_duration;
2650 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
2651 best->end_ts = end_ts;
2653 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
2654 start_ts < best->start_ts))
2655 best->start_ts = start_ts;
2658 /* write one buffer */
2659 ret = gst_matroska_mux_write_data (mux, best);
2660 } while (ret == GST_FLOW_OK && !popped);
2667 * gst_matroska_mux_change_state:
2668 * @element: #GstMatroskaMux
2669 * @transition: State change transition.
2671 * Change the muxer state.
2673 * Returns: #GstStateChangeReturn
2675 static GstStateChangeReturn
2676 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
2678 GstStateChangeReturn ret;
2679 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
2681 switch (transition) {
2682 case GST_STATE_CHANGE_NULL_TO_READY:
2684 case GST_STATE_CHANGE_READY_TO_PAUSED:
2685 gst_collect_pads_start (mux->collect);
2687 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2689 case GST_STATE_CHANGE_PAUSED_TO_READY:
2690 gst_collect_pads_stop (mux->collect);
2696 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2698 switch (transition) {
2699 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2701 case GST_STATE_CHANGE_PAUSED_TO_READY:
2702 gst_matroska_mux_reset (GST_ELEMENT (mux));
2704 case GST_STATE_CHANGE_READY_TO_NULL:
2714 gst_matroska_mux_set_property (GObject * object,
2715 guint prop_id, const GValue * value, GParamSpec * pspec)
2717 GstMatroskaMux *mux;
2719 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
2720 mux = GST_MATROSKA_MUX (object);
2723 case ARG_WRITING_APP:
2724 if (!g_value_get_string (value)) {
2725 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
2728 g_free (mux->writing_app);
2729 mux->writing_app = g_value_dup_string (value);
2731 case ARG_MATROSKA_VERSION:
2732 mux->matroska_version = g_value_get_int (value);
2735 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2741 gst_matroska_mux_get_property (GObject * object,
2742 guint prop_id, GValue * value, GParamSpec * pspec)
2744 GstMatroskaMux *mux;
2746 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
2747 mux = GST_MATROSKA_MUX (object);
2750 case ARG_WRITING_APP:
2751 g_value_set_string (value, mux->writing_app);
2753 case ARG_MATROSKA_VERSION:
2754 g_value_set_int (value, mux->matroska_version);
2757 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2763 gst_matroska_mux_plugin_init (GstPlugin * plugin)
2765 return gst_element_register (plugin, "matroskamux",
2766 GST_RANK_PRIMARY, GST_TYPE_MATROSKA_MUX);