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>
5 * (c) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
7 * matroska-mux.c: matroska file/stream muxer
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
25 /* TODO: - check everywhere that we don't write invalid values
26 * - make sure timestamps are correctly scaled everywhere
30 * SECTION:element-matroskamux
32 * matroskamux muxes different input streams into a Matroska file.
35 * <title>Example launch line</title>
37 * gst-launch-1.0 -v filesrc location=/path/to/mp3 ! mpegaudioparse ! matroskamux name=mux ! filesink location=test.mkv filesrc location=/path/to/theora.ogg ! oggdemux ! theoraparse ! mux.
38 * ]| This pipeline muxes an MP3 file and a Ogg Theora video into a Matroska file.
40 * gst-launch-1.0 -v audiotestsrc num-buffers=100 ! audioconvert ! vorbisenc ! matroskamux ! filesink location=test.mka
41 * ]| This pipeline muxes a 440Hz sine wave encoded with the Vorbis codec into a Matroska file.
53 #include <gst/audio/audio.h>
54 #include <gst/riff/riff-media.h>
55 #include <gst/tag/tag.h>
56 #include <gst/pbutils/codec-utils.h>
58 #include "matroska-mux.h"
59 #include "matroska-ids.h"
61 #define GST_MATROSKA_MUX_CHAPLANG "und"
63 GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
64 #define GST_CAT_DEFAULT matroskamux_debug
71 PROP_MIN_INDEX_INTERVAL,
74 PROP_MIN_CLUSTER_DURATION,
75 PROP_MAX_CLUSTER_DURATION
78 #define DEFAULT_DOCTYPE_VERSION 2
79 #define DEFAULT_WRITING_APP "GStreamer Matroska muxer"
80 #define DEFAULT_MIN_INDEX_INTERVAL 0
81 #define DEFAULT_STREAMABLE FALSE
82 #define DEFAULT_TIMECODESCALE GST_MSECOND
83 #define DEFAULT_MIN_CLUSTER_DURATION 500 * GST_MSECOND
84 #define DEFAULT_MAX_CLUSTER_DURATION 65535 * GST_MSECOND
86 /* WAVEFORMATEX is gst_riff_strf_auds + an extra guint16 extension size */
87 #define WAVEFORMATEX_SIZE (2 + sizeof (gst_riff_strf_auds))
89 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
92 GST_STATIC_CAPS ("video/x-matroska; video/x-matroska-3d; audio/x-matroska")
95 #define COMMON_VIDEO_CAPS \
96 "width = (int) [ 16, MAX ], " \
97 "height = (int) [ 16, MAX ] "
100 * * require codec data, etc as needed
103 static GstStaticPadTemplate videosink_templ =
104 GST_STATIC_PAD_TEMPLATE ("video_%u",
107 GST_STATIC_CAPS ("video/mpeg, "
108 "mpegversion = (int) { 1, 2, 4 }, "
109 "systemstream = (boolean) false, "
110 COMMON_VIDEO_CAPS "; "
111 "video/x-h264, stream-format=avc, alignment=au, "
112 COMMON_VIDEO_CAPS "; "
113 "video/x-h265, stream-format=hvc1, alignment=au, "
114 COMMON_VIDEO_CAPS "; "
116 COMMON_VIDEO_CAPS "; "
118 COMMON_VIDEO_CAPS "; "
120 COMMON_VIDEO_CAPS "; "
122 COMMON_VIDEO_CAPS "; "
124 COMMON_VIDEO_CAPS "; "
126 COMMON_VIDEO_CAPS "; "
129 COMMON_VIDEO_CAPS "; "
130 "video/x-pn-realvideo, "
131 "rmversion = (int) [1, 4], "
132 COMMON_VIDEO_CAPS "; "
134 COMMON_VIDEO_CAPS "; "
136 COMMON_VIDEO_CAPS "; "
138 "format = (string) { YUY2, I420, YV12, UYVY, AYUV, GRAY8, BGR, RGB }, "
139 COMMON_VIDEO_CAPS "; "
141 COMMON_VIDEO_CAPS "; "
142 "video/x-wmv, " "wmvversion = (int) [ 1, 3 ], " COMMON_VIDEO_CAPS "; "
143 "video/x-av1, " COMMON_VIDEO_CAPS)
146 #define COMMON_AUDIO_CAPS \
147 "channels = (int) [ 1, MAX ], " \
148 "rate = (int) [ 1, MAX ]"
151 * * require codec data, etc as needed
153 static GstStaticPadTemplate audiosink_templ =
154 GST_STATIC_PAD_TEMPLATE ("audio_%u",
157 GST_STATIC_CAPS ("audio/mpeg, "
158 "mpegversion = (int) 1, "
159 "layer = (int) [ 1, 3 ], "
160 COMMON_AUDIO_CAPS "; "
162 "mpegversion = (int) { 2, 4 }, "
163 "stream-format = (string) raw, "
164 COMMON_AUDIO_CAPS "; "
166 COMMON_AUDIO_CAPS "; "
168 COMMON_AUDIO_CAPS "; "
170 COMMON_AUDIO_CAPS "; "
172 COMMON_AUDIO_CAPS "; "
174 COMMON_AUDIO_CAPS "; "
177 COMMON_AUDIO_CAPS "; "
179 "format = (string) { U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }, "
180 "layout = (string) interleaved, "
181 COMMON_AUDIO_CAPS ";"
183 "width = (int) { 8, 16, 24 }, "
184 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
185 "audio/x-pn-realaudio, "
186 "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS "; "
187 "audio/x-wma, " "wmaversion = (int) [ 1, 3 ], "
188 "block_align = (int) [ 0, 65535 ], bitrate = (int) [ 0, 524288 ], "
189 COMMON_AUDIO_CAPS ";"
191 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
193 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
195 "layout = (string)dvi, "
196 "block_align = (int)[64, 8192], "
197 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
199 "channels = (int)1," "rate = (int)16000; "
201 "layout = (string)g726, " "channels = (int)1," "rate = (int)8000; ")
204 static GstStaticPadTemplate subtitlesink_templ =
205 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
208 GST_STATIC_CAPS ("subtitle/x-kate; "
209 "text/x-raw, format=utf8; application/x-ssa; application/x-ass; "
210 "application/x-usf; subpicture/x-dvd; "
211 "application/x-subtitle-unknown")
214 static gpointer parent_class; /* NULL */
216 /* Matroska muxer destructor */
217 static void gst_matroska_mux_class_init (GstMatroskaMuxClass * klass);
218 static void gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class);
219 static void gst_matroska_mux_finalize (GObject * object);
221 /* Pads collected callback */
222 static GstFlowReturn gst_matroska_mux_handle_buffer (GstCollectPads * pads,
223 GstCollectData * data, GstBuffer * buf, gpointer user_data);
224 static gboolean gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
225 GstCollectData * data, GstEvent * event, gpointer user_data);
228 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
229 GstObject * parent, GstEvent * event);
230 static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
231 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
232 static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
234 /* gst internal change state handler */
235 static GstStateChangeReturn
236 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
238 /* gobject bla bla */
239 static void gst_matroska_mux_set_property (GObject * object,
240 guint prop_id, const GValue * value, GParamSpec * pspec);
241 static void gst_matroska_mux_get_property (GObject * object,
242 guint prop_id, GValue * value, GParamSpec * pspec);
245 static void gst_matroska_mux_reset (GstElement * element);
248 static guint64 gst_matroska_mux_create_uid (GstMatroskaMux * mux);
250 static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
251 GstMatroskaTrackContext * context);
252 static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
253 GstMatroskaTrackContext * context);
254 static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
255 GstMatroskaTrackContext * context);
256 static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
257 GstMatroskaTrackContext * context);
258 static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
259 GstMatroskaTrackContext * context);
261 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
263 static gboolean gst_matroska_mux_tag_list_is_empty (const GstTagList * list);
264 static void gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux);
265 static gboolean gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux);
267 /* Cannot use boilerplate macros here because we need the full init function
268 * signature with the additional class argument, so we use the right template
269 * for the sink caps */
271 gst_matroska_mux_get_type (void)
273 static GType object_type; /* 0 */
275 if (object_type == 0) {
276 static const GTypeInfo object_info = {
277 sizeof (GstMatroskaMuxClass),
278 NULL, /* base_init */
279 NULL, /* base_finalize */
280 (GClassInitFunc) gst_matroska_mux_class_init,
281 NULL, /* class_finalize */
282 NULL, /* class_data */
283 sizeof (GstMatroskaMux),
285 (GInstanceInitFunc) gst_matroska_mux_init
287 const GInterfaceInfo iface_info = { NULL };
289 object_type = g_type_register_static (GST_TYPE_ELEMENT,
290 "GstMatroskaMux", &object_info, (GTypeFlags) 0);
292 g_type_add_interface_static (object_type, GST_TYPE_TAG_SETTER, &iface_info);
293 g_type_add_interface_static (object_type, GST_TYPE_TOC_SETTER, &iface_info);
300 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
302 GObjectClass *gobject_class;
303 GstElementClass *gstelement_class;
305 gobject_class = (GObjectClass *) klass;
306 gstelement_class = (GstElementClass *) klass;
308 gst_element_class_add_static_pad_template (gstelement_class,
310 gst_element_class_add_static_pad_template (gstelement_class,
312 gst_element_class_add_static_pad_template (gstelement_class,
313 &subtitlesink_templ);
314 gst_element_class_add_static_pad_template (gstelement_class, &src_templ);
315 gst_element_class_set_static_metadata (gstelement_class, "Matroska muxer",
317 "Muxes video/audio/subtitle streams into a matroska stream",
318 "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
320 GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
323 gobject_class->finalize = gst_matroska_mux_finalize;
325 gobject_class->get_property = gst_matroska_mux_get_property;
326 gobject_class->set_property = gst_matroska_mux_set_property;
328 g_object_class_install_property (gobject_class, PROP_WRITING_APP,
329 g_param_spec_string ("writing-app", "Writing application.",
330 "The name the application that creates the matroska file.",
331 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
332 g_object_class_install_property (gobject_class, PROP_DOCTYPE_VERSION,
333 g_param_spec_int ("version", "DocType version",
334 "This parameter determines what Matroska features can be used.",
335 1, 2, DEFAULT_DOCTYPE_VERSION,
336 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
337 g_object_class_install_property (gobject_class, PROP_MIN_INDEX_INTERVAL,
338 g_param_spec_int64 ("min-index-interval", "Minimum time between index "
339 "entries", "An index entry is created every so many nanoseconds.",
340 0, G_MAXINT64, DEFAULT_MIN_INDEX_INTERVAL,
341 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
342 g_object_class_install_property (gobject_class, PROP_STREAMABLE,
343 g_param_spec_boolean ("streamable", "Determines whether output should "
344 "be streamable", "If set to true, the output should be as if it is "
345 "to be streamed and hence no indexes written or duration written.",
346 DEFAULT_STREAMABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
347 g_object_class_install_property (gobject_class, PROP_TIMECODESCALE,
348 g_param_spec_int64 ("timecodescale", "Timecode Scale",
349 "TimecodeScale used to calculate the Raw Timecode of a Block", 1,
350 GST_SECOND, DEFAULT_TIMECODESCALE,
351 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
352 g_object_class_install_property (gobject_class, PROP_MIN_CLUSTER_DURATION,
353 g_param_spec_int64 ("min-cluster-duration", "Minimum cluster duration",
354 "Desidered cluster duration as nanoseconds. A new cluster will be "
355 "created irrespective of this property if a force key unit event "
356 "is received. 0 means create a new cluster for each video keyframe "
357 "or for each audio buffer in audio only streams.", 0,
358 G_MAXINT64, DEFAULT_MIN_CLUSTER_DURATION,
359 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
360 g_object_class_install_property (gobject_class, PROP_MAX_CLUSTER_DURATION,
361 g_param_spec_int64 ("max-cluster-duration", "Maximum cluster duration",
362 "A new cluster will be created if its duration exceeds this value. "
363 "0 means no maximum duration.", 0,
364 G_MAXINT64, DEFAULT_MAX_CLUSTER_DURATION,
365 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
367 gstelement_class->change_state =
368 GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
369 gstelement_class->request_new_pad =
370 GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
371 gstelement_class->release_pad =
372 GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
374 parent_class = g_type_class_peek_parent (klass);
378 * Start of pad option handler code
380 #define DEFAULT_PAD_FRAME_DURATION TRUE
385 PROP_PAD_FRAME_DURATION
391 gboolean frame_duration;
392 gboolean frame_duration_user;
395 typedef GstPadClass GstMatroskamuxPadClass;
397 GType gst_matroskamux_pad_get_type (void);
398 G_DEFINE_TYPE (GstMatroskamuxPad, gst_matroskamux_pad, GST_TYPE_PAD);
400 #define GST_TYPE_MATROSKAMUX_PAD (gst_matroskamux_pad_get_type())
401 #define GST_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_MATROSKAMUX_PAD,GstMatroskamuxPad))
402 #define GST_MATROSKAMUX_PAD_CAST(pad) ((GstMatroskamuxPad *) pad)
403 #define GST_IS_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_MATROSKAMUX_PAD))
406 gst_matroskamux_pad_get_property (GObject * object, guint prop_id,
407 GValue * value, GParamSpec * pspec)
409 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
412 case PROP_PAD_FRAME_DURATION:
413 g_value_set_boolean (value, pad->frame_duration);
416 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
422 gst_matroskamux_pad_set_property (GObject * object, guint prop_id,
423 const GValue * value, GParamSpec * pspec)
425 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
428 case PROP_PAD_FRAME_DURATION:
429 pad->frame_duration = g_value_get_boolean (value);
430 pad->frame_duration_user = TRUE;
433 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
439 gst_matroskamux_pad_class_init (GstMatroskamuxPadClass * klass)
441 GObjectClass *gobject_class = (GObjectClass *) klass;
443 gobject_class->set_property = gst_matroskamux_pad_set_property;
444 gobject_class->get_property = gst_matroskamux_pad_get_property;
446 g_object_class_install_property (gobject_class, PROP_PAD_FRAME_DURATION,
447 g_param_spec_boolean ("frame-duration", "Frame duration",
448 "Default frame duration", DEFAULT_PAD_FRAME_DURATION,
449 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
453 gst_matroskamux_pad_init (GstMatroskamuxPad * pad)
455 pad->frame_duration = DEFAULT_PAD_FRAME_DURATION;
456 pad->frame_duration_user = FALSE;
460 * End of pad option handler code
464 gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class)
466 GstPadTemplate *templ;
469 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
470 mux->srcpad = gst_pad_new_from_template (templ, "src");
472 gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
473 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
474 gst_pad_use_fixed_caps (mux->srcpad);
476 mux->collect = gst_collect_pads_new ();
477 gst_collect_pads_set_clip_function (mux->collect,
478 GST_DEBUG_FUNCPTR (gst_collect_pads_clip_running_time), mux);
479 gst_collect_pads_set_buffer_function (mux->collect,
480 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_buffer), mux);
481 gst_collect_pads_set_event_function (mux->collect,
482 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event), mux);
484 mux->ebml_write = gst_ebml_write_new (mux->srcpad);
485 mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
487 /* property defaults */
488 mux->doctype_version = DEFAULT_DOCTYPE_VERSION;
489 mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
490 mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
491 mux->ebml_write->streamable = DEFAULT_STREAMABLE;
492 mux->time_scale = DEFAULT_TIMECODESCALE;
493 mux->min_cluster_duration = DEFAULT_MIN_CLUSTER_DURATION;
494 mux->max_cluster_duration = DEFAULT_MAX_CLUSTER_DURATION;
496 /* initialize internal variables */
498 mux->num_streams = 0;
499 mux->num_a_streams = 0;
500 mux->num_t_streams = 0;
501 mux->num_v_streams = 0;
502 mux->internal_toc = NULL;
504 /* initialize remaining variables */
505 gst_matroska_mux_reset (GST_ELEMENT (mux));
510 * gst_matroska_mux_finalize:
511 * @object: #GstMatroskaMux that should be finalized.
513 * Finalize matroska muxer.
516 gst_matroska_mux_finalize (GObject * object)
518 GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
520 gst_event_replace (&mux->force_key_unit_event, NULL);
522 gst_object_unref (mux->collect);
523 gst_object_unref (mux->ebml_write);
524 g_free (mux->writing_app);
526 if (mux->internal_toc) {
527 gst_toc_unref (mux->internal_toc);
528 mux->internal_toc = NULL;
531 G_OBJECT_CLASS (parent_class)->finalize (object);
536 * gst_matroska_mux_create_uid:
537 * @mux: #GstMatroskaMux to generate UID for.
539 * Generate new track UID.
541 * Returns: New track UID.
544 gst_matroska_mux_create_uid (GstMatroskaMux * mux)
546 return (((guint64) g_random_int ()) << 32) | g_random_int ();
551 * gst_matroska_pad_reset:
552 * @collect_pad: the #GstMatroskaPad
554 * Reset and/or release resources of a matroska collect pad.
557 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
560 GstMatroskaTrackType type = 0;
562 /* free track information */
563 if (collect_pad->track != NULL) {
564 /* retrieve for optional later use */
565 name = collect_pad->track->name;
566 type = collect_pad->track->type;
567 /* extra for video */
568 if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
569 GstMatroskaTrackVideoContext *ctx =
570 (GstMatroskaTrackVideoContext *) collect_pad->track;
572 if (ctx->dirac_unit) {
573 gst_buffer_unref (ctx->dirac_unit);
574 ctx->dirac_unit = NULL;
577 g_free (collect_pad->track->codec_id);
578 g_free (collect_pad->track->codec_name);
580 g_free (collect_pad->track->name);
581 g_free (collect_pad->track->language);
582 g_free (collect_pad->track->codec_priv);
583 g_free (collect_pad->track);
584 collect_pad->track = NULL;
585 if (collect_pad->tags) {
586 gst_tag_list_unref (collect_pad->tags);
587 collect_pad->tags = NULL;
591 if (!full && type != 0) {
592 GstMatroskaTrackContext *context;
594 /* create a fresh context */
596 case GST_MATROSKA_TRACK_TYPE_VIDEO:
597 context = (GstMatroskaTrackContext *)
598 g_new0 (GstMatroskaTrackVideoContext, 1);
600 case GST_MATROSKA_TRACK_TYPE_AUDIO:
601 context = (GstMatroskaTrackContext *)
602 g_new0 (GstMatroskaTrackAudioContext, 1);
604 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
605 context = (GstMatroskaTrackContext *)
606 g_new0 (GstMatroskaTrackSubtitleContext, 1);
609 g_assert_not_reached ();
613 context->type = type;
614 context->name = name;
615 context->uid = gst_matroska_mux_create_uid (collect_pad->mux);
616 /* TODO: check default values for the context */
617 context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
618 collect_pad->track = context;
619 collect_pad->start_ts = GST_CLOCK_TIME_NONE;
620 collect_pad->end_ts = GST_CLOCK_TIME_NONE;
621 collect_pad->tags = gst_tag_list_new_empty ();
622 gst_tag_list_set_scope (collect_pad->tags, GST_TAG_SCOPE_STREAM);
627 * gst_matroska_pad_free:
628 * @collect_pad: the #GstMatroskaPad
630 * Release resources of a matroska collect pad.
633 gst_matroska_pad_free (GstPad * collect_pad)
635 gst_matroska_pad_reset ((GstMatroskaPad *) collect_pad, TRUE);
640 * gst_matroska_mux_reset:
641 * @element: #GstMatroskaMux that should be reseted.
643 * Reset matroska muxer back to initial state.
646 gst_matroska_mux_reset (GstElement * element)
648 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
651 /* reset EBML write */
652 gst_ebml_write_reset (mux->ebml_write);
655 mux->state = GST_MATROSKA_MUX_STATE_START;
657 /* clean up existing streams */
659 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
660 GstMatroskaPad *collect_pad;
662 collect_pad = (GstMatroskaPad *) walk->data;
664 /* reset collect pad to pristine state */
665 gst_matroska_pad_reset (collect_pad, FALSE);
669 mux->num_indexes = 0;
678 mux->cluster_time = 0;
679 mux->cluster_pos = 0;
680 mux->prev_cluster_size = 0;
683 gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
688 gst_toc_setter_reset (GST_TOC_SETTER (mux));
689 if (mux->internal_toc) {
690 gst_toc_unref (mux->internal_toc);
691 mux->internal_toc = NULL;
694 mux->chapters_pos = 0;
698 * gst_matroska_mux_handle_src_event:
699 * @pad: Pad which received the event.
700 * @event: Received event.
702 * handle events - copied from oggmux without understanding
704 * Returns: %TRUE on success.
707 gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
712 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
716 /* disable seeking for now */
722 return gst_pad_event_default (pad, parent, event);
727 gst_matroska_mux_free_codec_priv (GstMatroskaTrackContext * context)
729 if (context->codec_priv != NULL) {
730 g_free (context->codec_priv);
731 context->codec_priv = NULL;
732 context->codec_priv_size = 0;
737 gst_matroska_mux_build_vobsub_private (GstMatroskaTrackContext * context,
747 /* produce comma-separated list in hex format */
748 for (i = 0; i < 16; ++i) {
750 /* replicate vobsub's slightly off RGB conversion calculation */
751 y = (((col >> 16) & 0xff) - 16) * 255 / 219;
752 u = ((col >> 8) & 0xff) - 128;
753 v = (col & 0xff) - 128;
754 r = CLAMP (1.0 * y + 1.4022 * u, 0, 255);
755 g = CLAMP (1.0 * y - 0.3456 * u - 0.7145 * v, 0, 255);
756 b = CLAMP (1.0 * y + 1.7710 * v, 0, 255);
757 clutv[i] = g_strdup_printf ("%02x%02x%02x", r, g, b);
760 sclut = g_strjoinv (",", clutv);
762 /* build codec private; only palette for now */
763 gst_matroska_mux_free_codec_priv (context);
764 context->codec_priv = (guint8 *) g_strdup_printf ("palette: %s", sclut);
765 /* include terminating 0 */
766 context->codec_priv_size = strlen ((gchar *) context->codec_priv) + 1;
768 for (i = 0; i < 16; ++i) {
775 * gst_matroska_mux_handle_sink_event:
776 * @pad: Pad which received the event.
777 * @event: Received event.
779 * handle events - informational ones like tags
781 * Returns: %TRUE on success.
784 gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
785 GstCollectData * data, GstEvent * event, gpointer user_data)
787 GstMatroskaPad *collect_pad;
788 GstMatroskaTrackContext *context;
794 mux = GST_MATROSKA_MUX (user_data);
795 collect_pad = (GstMatroskaPad *) data;
797 context = collect_pad->track;
800 switch (GST_EVENT_TYPE (event)) {
801 case GST_EVENT_CAPS:{
804 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
805 gst_event_parse_caps (event, &caps);
807 ret = collect_pad->capsfunc (pad, caps);
808 gst_event_unref (event);
815 GST_DEBUG_OBJECT (mux, "received tag event");
816 gst_event_parse_tag (event, &list);
818 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
819 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
820 const gchar *lang_code;
822 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
824 GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
825 g_free (context->language);
826 context->language = g_strdup (lang_code);
828 GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
833 /* FIXME: what about stream-specific tags? */
834 if (gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL) {
835 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
836 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
838 gst_tag_list_insert (collect_pad->tags, list, GST_TAG_MERGE_REPLACE);
841 gst_event_unref (event);
842 /* handled this, don't want collectpads to forward it downstream */
848 GstToc *toc, *old_toc;
850 if (mux->chapters_pos > 0)
853 GST_DEBUG_OBJECT (mux, "received toc event");
854 gst_event_parse_toc (event, &toc, NULL);
857 old_toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
858 if (old_toc != NULL) {
860 GST_INFO_OBJECT (pad, "Replacing TOC with a new one");
861 gst_toc_unref (old_toc);
864 gst_toc_setter_set_toc (GST_TOC_SETTER (mux), toc);
868 gst_event_unref (event);
869 /* handled this, don't want collectpads to forward it downstream */
873 case GST_EVENT_CUSTOM_DOWNSTREAM:
874 case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY:{
875 const GstStructure *structure;
877 structure = gst_event_get_structure (event);
878 if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
879 gst_event_replace (&mux->force_key_unit_event, NULL);
880 mux->force_key_unit_event = event;
882 } else if (gst_structure_has_name (structure, "application/x-gst-dvd") &&
883 !strcmp ("dvd-spu-clut-change",
884 gst_structure_get_string (structure, "event"))) {
889 GST_DEBUG_OBJECT (pad, "New DVD colour table received");
890 if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
891 GST_DEBUG_OBJECT (pad, "... discarding");
894 /* first transform event data into table form */
895 for (i = 0; i < 16; i++) {
896 g_snprintf (name, sizeof (name), "clut%02d", i);
897 if (!gst_structure_get_int (structure, name, &value)) {
898 GST_ERROR_OBJECT (mux, "dvd-spu-clut-change event did not "
899 "contain %s field", name);
905 /* transform into private data for stream; text form */
906 gst_matroska_mux_build_vobsub_private (context, clut);
916 return gst_collect_pads_event_default (pads, data, event, FALSE);
922 gst_matroska_mux_set_codec_id (GstMatroskaTrackContext * context,
925 g_assert (context && id);
926 g_free (context->codec_id);
927 context->codec_id = g_strdup (id);
931 * gst_matroska_mux_video_pad_setcaps:
932 * @pad: Pad which got the caps.
935 * Setcaps function for video sink pad.
937 * Returns: %TRUE on success.
940 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
942 GstMatroskaTrackContext *context = NULL;
943 GstMatroskaTrackVideoContext *videocontext;
945 GstMatroskaPad *collect_pad;
946 GstStructure *structure;
947 const gchar *mimetype;
948 const gchar *interlace_mode, *s;
949 const GValue *value = NULL;
950 GstBuffer *codec_buf = NULL;
951 gint width, height, pixel_width, pixel_height;
953 guint multiview_flags;
956 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
958 if ((old_caps = gst_pad_get_current_caps (pad))) {
959 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
960 && !gst_caps_is_equal (caps, old_caps)) {
961 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
962 ("Caps changed are not supported by Matroska"));
963 gst_caps_unref (old_caps);
966 gst_caps_unref (old_caps);
970 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
971 g_assert (collect_pad);
972 context = collect_pad->track;
974 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
975 videocontext = (GstMatroskaTrackVideoContext *) context;
977 /* gst -> matroska ID'ing */
978 structure = gst_caps_get_structure (caps, 0);
980 mimetype = gst_structure_get_name (structure);
982 interlace_mode = gst_structure_get_string (structure, "interlace-mode");
983 if (interlace_mode != NULL) {
984 if (strcmp (interlace_mode, "progressive") == 0)
985 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE;
987 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_INTERLACED;
989 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_UNKNOWN;
992 if (!strcmp (mimetype, "video/x-theora")) {
993 /* we'll extract the details later from the theora identification header */
997 /* get general properties */
998 /* spec says it is mandatory */
999 if (!gst_structure_get_int (structure, "width", &width) ||
1000 !gst_structure_get_int (structure, "height", &height))
1003 videocontext->pixel_width = width;
1004 videocontext->pixel_height = height;
1006 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
1007 && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
1009 context->default_duration =
1010 gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
1011 GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
1012 GST_TIME_ARGS (context->default_duration));
1014 context->default_duration = 0;
1016 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
1017 &pixel_width, &pixel_height)) {
1018 if (pixel_width > pixel_height) {
1019 videocontext->display_width = width * pixel_width / pixel_height;
1020 videocontext->display_height = height;
1021 } else if (pixel_width < pixel_height) {
1022 videocontext->display_width = width;
1023 videocontext->display_height = height * pixel_height / pixel_width;
1025 videocontext->display_width = 0;
1026 videocontext->display_height = 0;
1029 videocontext->display_width = 0;
1030 videocontext->display_height = 0;
1033 if ((s = gst_structure_get_string (structure, "colorimetry"))) {
1034 if (!gst_video_colorimetry_from_string (&videocontext->colorimetry, s)) {
1035 GST_WARNING_OBJECT (pad, "Could not parse colorimetry %s", s);
1039 /* Collect stereoscopic info, if any */
1040 if ((s = gst_structure_get_string (structure, "multiview-mode")))
1041 videocontext->multiview_mode =
1042 gst_video_multiview_mode_from_caps_string (s);
1043 gst_structure_get_flagset (structure, "multiview-flags", &multiview_flags,
1045 videocontext->multiview_flags = multiview_flags;
1050 videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
1051 videocontext->fourcc = 0;
1053 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1054 * data and other settings
1058 /* extract codec_data, may turn out needed */
1059 value = gst_structure_get_value (structure, "codec_data");
1061 codec_buf = (GstBuffer *) gst_value_get_buffer (value);
1064 if (!strcmp (mimetype, "video/x-raw")) {
1066 gst_matroska_mux_set_codec_id (context,
1067 GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
1068 fstr = gst_structure_get_string (structure, "format");
1070 if (strlen (fstr) == 4)
1071 videocontext->fourcc = GST_STR_FOURCC (fstr);
1072 else if (!strcmp (fstr, "GRAY8"))
1073 videocontext->fourcc = GST_MAKE_FOURCC ('Y', '8', '0', '0');
1074 else if (!strcmp (fstr, "BGR"))
1075 videocontext->fourcc = GST_MAKE_FOURCC ('B', 'G', 'R', 24);
1076 else if (!strcmp (fstr, "RGB"))
1077 videocontext->fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', 24);
1079 } else if (!strcmp (mimetype, "video/x-huffyuv") /* MS/VfW compatibility cases */
1080 ||!strcmp (mimetype, "video/x-divx")
1081 || !strcmp (mimetype, "video/x-dv")
1082 || !strcmp (mimetype, "video/x-h263")
1083 || !strcmp (mimetype, "video/x-msmpeg")
1084 || !strcmp (mimetype, "video/x-wmv")
1085 || !strcmp (mimetype, "image/jpeg")) {
1086 gst_riff_strf_vids *bih;
1087 gint size = sizeof (gst_riff_strf_vids);
1090 if (!strcmp (mimetype, "video/x-huffyuv"))
1091 fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
1092 else if (!strcmp (mimetype, "video/x-dv"))
1093 fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
1094 else if (!strcmp (mimetype, "video/x-h263"))
1095 fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
1096 else if (!strcmp (mimetype, "video/x-divx")) {
1099 gst_structure_get_int (structure, "divxversion", &divxversion);
1100 switch (divxversion) {
1102 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
1105 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
1108 fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
1111 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1114 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
1115 switch (msmpegversion) {
1117 fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
1120 fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
1126 } else if (!strcmp (mimetype, "video/x-wmv")) {
1130 fstr = gst_structure_get_string (structure, "format");
1131 if (fstr && strlen (fstr) == 4) {
1132 fourcc = GST_STR_FOURCC (fstr);
1133 } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
1134 if (wmvversion == 2) {
1135 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
1136 } else if (wmvversion == 1) {
1137 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
1138 } else if (wmvversion == 3) {
1139 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
1142 } else if (!strcmp (mimetype, "image/jpeg")) {
1143 fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
1149 bih = g_new0 (gst_riff_strf_vids, 1);
1150 GST_WRITE_UINT32_LE (&bih->size, size);
1151 GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
1152 GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
1153 GST_WRITE_UINT32_LE (&bih->compression, fourcc);
1154 GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
1155 GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
1156 GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
1157 videocontext->pixel_height * 3);
1159 /* process codec private/initialization data, if any */
1161 size += gst_buffer_get_size (codec_buf);
1162 bih = g_realloc (bih, size);
1163 GST_WRITE_UINT32_LE (&bih->size, size);
1164 gst_buffer_extract (codec_buf, 0,
1165 (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
1168 gst_matroska_mux_set_codec_id (context,
1169 GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
1170 gst_matroska_mux_free_codec_priv (context);
1171 context->codec_priv = (gpointer) bih;
1172 context->codec_priv_size = size;
1173 context->dts_only = TRUE;
1174 } else if (!strcmp (mimetype, "video/x-h264")) {
1175 gst_matroska_mux_set_codec_id (context,
1176 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
1177 gst_matroska_mux_free_codec_priv (context);
1178 /* Create avcC header */
1179 if (codec_buf != NULL) {
1180 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1181 context->codec_priv = g_malloc0 (context->codec_priv_size);
1182 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1184 } else if (!strcmp (mimetype, "video/x-h265")) {
1185 gst_matroska_mux_set_codec_id (context,
1186 GST_MATROSKA_CODEC_ID_VIDEO_MPEGH_HEVC);
1187 gst_matroska_mux_free_codec_priv (context);
1188 /* Create hvcC header */
1189 if (codec_buf != NULL) {
1190 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1191 context->codec_priv = g_malloc0 (context->codec_priv_size);
1192 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1194 } else if (!strcmp (mimetype, "video/x-theora")) {
1195 const GValue *streamheader;
1197 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
1199 gst_matroska_mux_free_codec_priv (context);
1201 streamheader = gst_structure_get_value (structure, "streamheader");
1202 if (!theora_streamheader_to_codecdata (streamheader, context)) {
1203 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1204 ("theora stream headers missing or malformed"));
1207 } else if (!strcmp (mimetype, "video/x-dirac")) {
1208 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
1209 } else if (!strcmp (mimetype, "video/x-vp8")) {
1210 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP8);
1211 } else if (!strcmp (mimetype, "video/x-vp9")) {
1212 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP9);
1213 } else if (!strcmp (mimetype, "video/x-av1")) {
1214 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_AV1);
1215 gst_matroska_mux_free_codec_priv (context);
1216 /* Create av1C header */
1217 if (codec_buf != NULL)
1218 gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1219 &context->codec_priv, &context->codec_priv_size);
1220 } else if (!strcmp (mimetype, "video/mpeg")) {
1223 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1224 switch (mpegversion) {
1226 gst_matroska_mux_set_codec_id (context,
1227 GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
1230 gst_matroska_mux_set_codec_id (context,
1231 GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
1234 gst_matroska_mux_set_codec_id (context,
1235 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
1241 /* global headers may be in codec data */
1242 if (codec_buf != NULL) {
1243 gst_matroska_mux_free_codec_priv (context);
1244 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1245 context->codec_priv = g_malloc0 (context->codec_priv_size);
1246 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1248 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1250 /* can only make it here if preceding case verified it was version 3 */
1251 gst_matroska_mux_set_codec_id (context,
1252 GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
1253 } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
1255 const GValue *mdpr_data;
1257 gst_structure_get_int (structure, "rmversion", &rmversion);
1258 switch (rmversion) {
1260 gst_matroska_mux_set_codec_id (context,
1261 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
1264 gst_matroska_mux_set_codec_id (context,
1265 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
1268 gst_matroska_mux_set_codec_id (context,
1269 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
1272 gst_matroska_mux_set_codec_id (context,
1273 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
1279 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1280 if (mdpr_data != NULL) {
1281 guint8 *priv_data = NULL;
1282 guint priv_data_size = 0;
1284 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1286 priv_data_size = gst_buffer_get_size (codec_data_buf);
1287 priv_data = g_malloc0 (priv_data_size);
1289 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1291 gst_matroska_mux_free_codec_priv (context);
1292 context->codec_priv = priv_data;
1293 context->codec_priv_size = priv_data_size;
1295 } else if (strcmp (mimetype, "video/x-prores") == 0) {
1296 const gchar *variant;
1298 gst_matroska_mux_free_codec_priv (context);
1300 variant = gst_structure_get_string (structure, "format");
1301 if (!variant || !g_strcmp0 (variant, "standard"))
1302 context->codec_priv = g_strdup ("apcn");
1303 else if (!g_strcmp0 (variant, "hq"))
1304 context->codec_priv = g_strdup ("apch");
1305 else if (!g_strcmp0 (variant, "lt"))
1306 context->codec_priv = g_strdup ("apcs");
1307 else if (!g_strcmp0 (variant, "proxy"))
1308 context->codec_priv = g_strdup ("apco");
1309 else if (!g_strcmp0 (variant, "4444"))
1310 context->codec_priv = g_strdup ("ap4h");
1312 GST_WARNING_OBJECT (mux, "Unhandled prores format: %s", variant);
1317 context->codec_priv_size = sizeof (guint32);
1318 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_PRORES);
1326 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1327 GST_PAD_NAME (pad), caps);
1332 /* N > 0 to expect a particular number of headers, negative if the
1333 number of headers is variable */
1335 xiphN_streamheader_to_codecdata (const GValue * streamheader,
1336 GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
1338 GstBuffer **buf = NULL;
1341 guint bufi, i, offset, priv_data_size;
1343 if (streamheader == NULL)
1344 goto no_stream_headers;
1346 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1349 bufarr = g_value_peek_pointer (streamheader);
1350 if (bufarr->len <= 0 || bufarr->len > 255) /* at least one header, and count stored in a byte */
1352 if (N > 0 && bufarr->len != N)
1355 context->xiph_headers_to_skip = bufarr->len;
1357 buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1358 for (i = 0; i < bufarr->len; i++) {
1359 GValue *bufval = &g_array_index (bufarr, GValue, i);
1361 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1363 goto wrong_content_type;
1366 buf[i] = g_value_peek_pointer (bufval);
1370 if (bufarr->len > 0) {
1371 for (i = 0; i < bufarr->len - 1; i++) {
1372 priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
1376 for (i = 0; i < bufarr->len; ++i) {
1377 priv_data_size += gst_buffer_get_size (buf[i]);
1380 priv_data = g_malloc0 (priv_data_size);
1382 priv_data[0] = bufarr->len - 1;
1385 if (bufarr->len > 0) {
1386 for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1387 for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
1388 priv_data[offset++] = 0xff;
1390 priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
1394 for (i = 0; i < bufarr->len; ++i) {
1395 gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
1396 offset += gst_buffer_get_size (buf[i]);
1399 gst_matroska_mux_free_codec_priv (context);
1400 context->codec_priv = priv_data;
1401 context->codec_priv_size = priv_data_size;
1404 *p_buf0 = gst_buffer_ref (buf[0]);
1413 GST_WARNING ("required streamheaders missing in sink caps!");
1418 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1419 G_VALUE_TYPE_NAME (streamheader));
1424 GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1429 GST_WARNING ("streamheaders array does not contain GstBuffers");
1435 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1436 GstMatroskaTrackContext * context)
1438 GstBuffer *buf0 = NULL;
1440 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1443 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
1444 GST_WARNING ("First vorbis header too small, ignoring");
1446 if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
1447 GstMatroskaTrackAudioContext *audiocontext;
1451 gst_buffer_map (buf0, &map, GST_MAP_READ);
1452 hdr = map.data + 1 + 6 + 4;
1453 audiocontext = (GstMatroskaTrackAudioContext *) context;
1454 audiocontext->channels = GST_READ_UINT8 (hdr);
1455 audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1456 gst_buffer_unmap (buf0, &map);
1461 gst_buffer_unref (buf0);
1467 theora_streamheader_to_codecdata (const GValue * streamheader,
1468 GstMatroskaTrackContext * context)
1470 GstBuffer *buf0 = NULL;
1472 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1475 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
1476 GST_WARNING ("First theora header too small, ignoring");
1477 } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
1478 GST_WARNING ("First header not a theora identification header, ignoring");
1480 GstMatroskaTrackVideoContext *videocontext;
1481 guint fps_num, fps_denom, par_num, par_denom;
1485 gst_buffer_map (buf0, &map, GST_MAP_READ);
1486 hdr = map.data + 1 + 6 + 3 + 2 + 2;
1488 videocontext = (GstMatroskaTrackVideoContext *) context;
1489 videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1490 videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1491 hdr += 3 + 3 + 1 + 1;
1492 fps_num = GST_READ_UINT32_BE (hdr);
1493 fps_denom = GST_READ_UINT32_BE (hdr + 4);
1494 context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1495 fps_denom, fps_num);
1497 par_num = GST_READ_UINT32_BE (hdr) >> 8;
1498 par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1499 if (par_num > 0 && par_denom > 0) {
1500 if (par_num > par_denom) {
1501 videocontext->display_width =
1502 videocontext->pixel_width * par_num / par_denom;
1503 videocontext->display_height = videocontext->pixel_height;
1504 } else if (par_num < par_denom) {
1505 videocontext->display_width = videocontext->pixel_width;
1506 videocontext->display_height =
1507 videocontext->pixel_height * par_denom / par_num;
1509 videocontext->display_width = 0;
1510 videocontext->display_height = 0;
1513 videocontext->display_width = 0;
1514 videocontext->display_height = 0;
1517 gst_buffer_unmap (buf0, &map);
1521 gst_buffer_unref (buf0);
1527 kate_streamheader_to_codecdata (const GValue * streamheader,
1528 GstMatroskaTrackContext * context)
1530 GstBuffer *buf0 = NULL;
1532 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1535 if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) { /* Kate ID header is 64 bytes */
1536 GST_WARNING ("First kate header too small, ignoring");
1537 } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
1538 GST_WARNING ("First header not a kate identification header, ignoring");
1542 gst_buffer_unref (buf0);
1548 flac_streamheader_to_codecdata (const GValue * streamheader,
1549 GstMatroskaTrackContext * context)
1556 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1557 GST_WARNING ("No or invalid streamheader field in the caps");
1561 bufarr = g_value_peek_pointer (streamheader);
1562 if (bufarr->len < 2) {
1563 GST_WARNING ("Too few headers in streamheader field");
1567 context->xiph_headers_to_skip = bufarr->len + 1;
1569 bufval = &g_array_index (bufarr, GValue, 0);
1570 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1571 GST_WARNING ("streamheaders array does not contain GstBuffers");
1575 buffer = g_value_peek_pointer (bufval);
1577 /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1578 if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
1579 || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
1580 || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
1581 GST_WARNING ("Invalid streamheader for FLAC");
1585 gst_matroska_mux_free_codec_priv (context);
1586 context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
1587 context->codec_priv = g_malloc (context->codec_priv_size);
1588 gst_buffer_extract (buffer, 9, context->codec_priv, -1);
1590 for (i = 1; i < bufarr->len; i++) {
1592 bufval = &g_array_index (bufarr, GValue, i);
1594 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1595 gst_matroska_mux_free_codec_priv (context);
1596 GST_WARNING ("streamheaders array does not contain GstBuffers");
1600 buffer = g_value_peek_pointer (bufval);
1602 old_size = context->codec_priv_size;
1603 context->codec_priv_size += gst_buffer_get_size (buffer);
1605 context->codec_priv = g_realloc (context->codec_priv,
1606 context->codec_priv_size);
1607 gst_buffer_extract (buffer, 0,
1608 (guint8 *) context->codec_priv + old_size, -1);
1615 speex_streamheader_to_codecdata (const GValue * streamheader,
1616 GstMatroskaTrackContext * context)
1623 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1624 GST_WARNING ("No or invalid streamheader field in the caps");
1628 bufarr = g_value_peek_pointer (streamheader);
1629 if (bufarr->len != 2) {
1630 GST_WARNING ("Too few headers in streamheader field");
1634 context->xiph_headers_to_skip = bufarr->len + 1;
1636 bufval = &g_array_index (bufarr, GValue, 0);
1637 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1638 GST_WARNING ("streamheaders array does not contain GstBuffers");
1642 buffer = g_value_peek_pointer (bufval);
1644 if (gst_buffer_get_size (buffer) < 80
1645 || gst_buffer_memcmp (buffer, 0, "Speex ", 8) != 0) {
1646 GST_WARNING ("Invalid streamheader for Speex");
1650 gst_matroska_mux_free_codec_priv (context);
1651 context->codec_priv_size = gst_buffer_get_size (buffer);
1652 context->codec_priv = g_malloc (context->codec_priv_size);
1653 gst_buffer_extract (buffer, 0, context->codec_priv, -1);
1655 bufval = &g_array_index (bufarr, GValue, 1);
1657 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1658 gst_matroska_mux_free_codec_priv (context);
1659 GST_WARNING ("streamheaders array does not contain GstBuffers");
1663 buffer = g_value_peek_pointer (bufval);
1665 old_size = context->codec_priv_size;
1666 context->codec_priv_size += gst_buffer_get_size (buffer);
1667 context->codec_priv = g_realloc (context->codec_priv,
1668 context->codec_priv_size);
1669 gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
1675 opus_streamheader_to_codecdata (const GValue * streamheader,
1676 GstMatroskaTrackContext * context)
1682 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1685 bufarr = g_value_peek_pointer (streamheader);
1686 if (bufarr->len != 1 && bufarr->len != 2) /* one header, and count stored in a byte */
1689 /* Opus headers are not in-band */
1690 context->xiph_headers_to_skip = 0;
1692 bufval = &g_array_index (bufarr, GValue, 0);
1693 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1694 goto wrong_content_type;
1696 buf = g_value_peek_pointer (bufval);
1698 gst_matroska_mux_free_codec_priv (context);
1700 context->codec_priv_size = gst_buffer_get_size (buf);
1701 context->codec_priv = g_malloc0 (context->codec_priv_size);
1702 gst_buffer_extract (buf, 0, context->codec_priv, -1);
1704 context->codec_delay =
1705 GST_READ_UINT16_LE ((guint8 *) context->codec_priv + 10);
1706 context->codec_delay =
1707 gst_util_uint64_scale_round (context->codec_delay, GST_SECOND, 48000);
1708 context->seek_preroll = 80 * GST_MSECOND;
1715 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1716 G_VALUE_TYPE_NAME (streamheader));
1721 GST_WARNING ("got %u streamheaders, not 1 or 2 as expected", bufarr->len);
1726 GST_WARNING ("streamheaders array does not contain GstBuffers");
1732 opus_make_codecdata (GstMatroskaTrackContext * context, GstCaps * caps)
1736 guint8 channel_mapping_family;
1737 guint8 stream_count, coupled_count, channel_mapping[256];
1741 /* Opus headers are not in-band */
1742 context->xiph_headers_to_skip = 0;
1744 context->codec_delay = 0;
1745 context->seek_preroll = 80 * GST_MSECOND;
1747 if (!gst_codec_utils_opus_parse_caps (caps, &rate, &channels,
1748 &channel_mapping_family, &stream_count, &coupled_count,
1750 GST_WARNING ("Failed to parse caps for Opus");
1755 gst_codec_utils_opus_create_header (rate, channels,
1756 channel_mapping_family, stream_count, coupled_count, channel_mapping, 0,
1759 GST_WARNING ("Failed to create Opus header from caps");
1763 gst_buffer_map (buffer, &map, GST_MAP_READ);
1764 context->codec_priv_size = map.size;
1765 context->codec_priv = g_malloc (context->codec_priv_size);
1766 memcpy (context->codec_priv, map.data, map.size);
1767 gst_buffer_unmap (buffer, &map);
1768 gst_buffer_unref (buffer);
1774 * gst_matroska_mux_audio_pad_setcaps:
1775 * @pad: Pad which got the caps.
1778 * Setcaps function for audio sink pad.
1780 * Returns: %TRUE on success.
1783 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1785 GstMatroskaTrackContext *context = NULL;
1786 GstMatroskaTrackAudioContext *audiocontext;
1787 GstMatroskaMux *mux;
1788 GstMatroskaPad *collect_pad;
1789 const gchar *mimetype;
1790 gint samplerate = 0, channels = 0;
1791 GstStructure *structure;
1792 const GValue *codec_data = NULL;
1793 GstBuffer *buf = NULL;
1794 const gchar *stream_format = NULL;
1797 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1799 if ((old_caps = gst_pad_get_current_caps (pad))) {
1800 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1801 && !gst_caps_is_equal (caps, old_caps)) {
1802 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1803 ("Caps changed are not supported by Matroska"));
1804 gst_caps_unref (old_caps);
1807 gst_caps_unref (old_caps);
1811 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1812 g_assert (collect_pad);
1813 context = collect_pad->track;
1815 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
1816 audiocontext = (GstMatroskaTrackAudioContext *) context;
1818 structure = gst_caps_get_structure (caps, 0);
1819 mimetype = gst_structure_get_name (structure);
1822 gst_structure_get_int (structure, "rate", &samplerate);
1823 gst_structure_get_int (structure, "channels", &channels);
1825 audiocontext->samplerate = samplerate;
1826 audiocontext->channels = channels;
1827 audiocontext->bitdepth = 0;
1828 context->default_duration = 0;
1830 codec_data = gst_structure_get_value (structure, "codec_data");
1832 buf = gst_value_get_buffer (codec_data);
1834 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1835 * data and other settings
1839 if (!strcmp (mimetype, "audio/mpeg")) {
1840 gint mpegversion = 0;
1842 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1843 switch (mpegversion) {
1849 gst_structure_get_int (structure, "layer", &layer);
1851 if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
1852 GST_WARNING_OBJECT (mux,
1853 "Unable to determine MPEG audio version, assuming 1");
1859 else if (layer == 2)
1861 else if (version == 2)
1866 context->default_duration =
1867 gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
1871 gst_matroska_mux_set_codec_id (context,
1872 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
1875 gst_matroska_mux_set_codec_id (context,
1876 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
1879 gst_matroska_mux_set_codec_id (context,
1880 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
1889 stream_format = gst_structure_get_string (structure, "stream-format");
1890 /* check this is raw aac */
1891 if (stream_format) {
1892 if (strcmp (stream_format, "raw") != 0) {
1893 GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
1897 GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
1902 gst_matroska_mux_set_codec_id (context,
1903 GST_MATROSKA_CODEC_ID_AUDIO_AAC);
1904 context->codec_priv_size = gst_buffer_get_size (buf);
1905 context->codec_priv = g_malloc (context->codec_priv_size);
1906 gst_buffer_extract (buf, 0, context->codec_priv,
1907 context->codec_priv_size);
1909 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
1916 } else if (!strcmp (mimetype, "audio/x-raw")) {
1919 gst_audio_info_init (&info);
1920 if (!gst_audio_info_from_caps (&info, caps)) {
1921 GST_DEBUG_OBJECT (mux,
1922 "broken caps, rejected by gst_audio_info_from_caps");
1926 switch (GST_AUDIO_INFO_FORMAT (&info)) {
1927 case GST_AUDIO_FORMAT_U8:
1928 case GST_AUDIO_FORMAT_S16BE:
1929 case GST_AUDIO_FORMAT_S16LE:
1930 case GST_AUDIO_FORMAT_S24BE:
1931 case GST_AUDIO_FORMAT_S24LE:
1932 case GST_AUDIO_FORMAT_S32BE:
1933 case GST_AUDIO_FORMAT_S32LE:
1934 if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
1935 GST_DEBUG_OBJECT (mux, "width must be same as depth!");
1938 if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
1939 gst_matroska_mux_set_codec_id (context,
1940 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
1942 gst_matroska_mux_set_codec_id (context,
1943 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
1945 case GST_AUDIO_FORMAT_F32LE:
1946 case GST_AUDIO_FORMAT_F64LE:
1947 gst_matroska_mux_set_codec_id (context,
1948 GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
1952 GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
1956 audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
1957 } else if (!strcmp (mimetype, "audio/x-vorbis")) {
1958 const GValue *streamheader;
1960 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
1962 gst_matroska_mux_free_codec_priv (context);
1964 streamheader = gst_structure_get_value (structure, "streamheader");
1965 if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
1966 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1967 ("vorbis stream headers missing or malformed"));
1970 } else if (!strcmp (mimetype, "audio/x-flac")) {
1971 const GValue *streamheader;
1973 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
1975 gst_matroska_mux_free_codec_priv (context);
1977 streamheader = gst_structure_get_value (structure, "streamheader");
1978 if (!flac_streamheader_to_codecdata (streamheader, context)) {
1979 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1980 ("flac stream headers missing or malformed"));
1983 } else if (!strcmp (mimetype, "audio/x-speex")) {
1984 const GValue *streamheader;
1986 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
1987 gst_matroska_mux_free_codec_priv (context);
1989 streamheader = gst_structure_get_value (structure, "streamheader");
1990 if (!speex_streamheader_to_codecdata (streamheader, context)) {
1991 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1992 ("speex stream headers missing or malformed"));
1995 } else if (!strcmp (mimetype, "audio/x-opus")) {
1996 const GValue *streamheader;
1998 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_OPUS);
2000 streamheader = gst_structure_get_value (structure, "streamheader");
2002 gst_matroska_mux_free_codec_priv (context);
2003 if (!opus_streamheader_to_codecdata (streamheader, context)) {
2004 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2005 ("opus stream headers missing or malformed"));
2009 /* no streamheader, but we need to have one, so we make one up
2011 gst_matroska_mux_free_codec_priv (context);
2012 if (!opus_make_codecdata (context, caps)) {
2013 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2014 ("opus stream headers missing or malformed"));
2018 } else if (!strcmp (mimetype, "audio/x-ac3")) {
2019 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_AC3);
2020 } else if (!strcmp (mimetype, "audio/x-eac3")) {
2021 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
2022 } else if (!strcmp (mimetype, "audio/x-dts")) {
2023 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_DTS);
2024 } else if (!strcmp (mimetype, "audio/x-tta")) {
2027 /* TTA frame duration */
2028 context->default_duration = 1.04489795918367346939 * GST_SECOND;
2030 gst_structure_get_int (structure, "width", &width);
2031 audiocontext->bitdepth = width;
2032 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_TTA);
2034 } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
2036 const GValue *mdpr_data;
2038 gst_structure_get_int (structure, "raversion", &raversion);
2039 switch (raversion) {
2041 gst_matroska_mux_set_codec_id (context,
2042 GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
2045 gst_matroska_mux_set_codec_id (context,
2046 GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
2049 gst_matroska_mux_set_codec_id (context,
2050 GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
2056 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
2057 if (mdpr_data != NULL) {
2058 guint8 *priv_data = NULL;
2059 guint priv_data_size = 0;
2061 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
2063 priv_data_size = gst_buffer_get_size (codec_data_buf);
2064 priv_data = g_malloc0 (priv_data_size);
2066 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
2068 gst_matroska_mux_free_codec_priv (context);
2070 context->codec_priv = priv_data;
2071 context->codec_priv_size = priv_data_size;
2074 } else if (!strcmp (mimetype, "audio/x-wma")
2075 || !strcmp (mimetype, "audio/x-alaw")
2076 || !strcmp (mimetype, "audio/x-mulaw")
2077 || !strcmp (mimetype, "audio/x-adpcm")
2078 || !strcmp (mimetype, "audio/G722")) {
2080 guint codec_priv_size;
2082 gint block_align = 0;
2085 if (samplerate == 0 || channels == 0) {
2086 GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
2090 if (!strcmp (mimetype, "audio/x-wma")) {
2094 if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
2095 || !gst_structure_get_int (structure, "block_align", &block_align)
2096 || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
2097 GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
2102 switch (wmaversion) {
2104 format = GST_RIFF_WAVE_FORMAT_WMAV1;
2107 format = GST_RIFF_WAVE_FORMAT_WMAV2;
2110 format = GST_RIFF_WAVE_FORMAT_WMAV3;
2113 GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
2117 if (gst_structure_get_int (structure, "depth", &depth))
2118 audiocontext->bitdepth = depth;
2119 } else if (!strcmp (mimetype, "audio/x-alaw")
2120 || !strcmp (mimetype, "audio/x-mulaw")) {
2121 audiocontext->bitdepth = 8;
2122 if (!strcmp (mimetype, "audio/x-alaw"))
2123 format = GST_RIFF_WAVE_FORMAT_ALAW;
2125 format = GST_RIFF_WAVE_FORMAT_MULAW;
2127 block_align = channels;
2128 bitrate = block_align * samplerate;
2129 } else if (!strcmp (mimetype, "audio/x-adpcm")) {
2132 layout = gst_structure_get_string (structure, "layout");
2134 GST_WARNING_OBJECT (mux, "Missing layout on adpcm caps");
2138 if (!gst_structure_get_int (structure, "block_align", &block_align)) {
2139 GST_WARNING_OBJECT (mux, "Missing block_align on adpcm caps");
2143 if (!strcmp (layout, "dvi")) {
2144 format = GST_RIFF_WAVE_FORMAT_DVI_ADPCM;
2145 } else if (!strcmp (layout, "g726")) {
2146 format = GST_RIFF_WAVE_FORMAT_ITU_G726_ADPCM;
2147 if (!gst_structure_get_int (structure, "bitrate", &bitrate)) {
2148 GST_WARNING_OBJECT (mux, "Missing bitrate on adpcm g726 caps");
2152 GST_WARNING_OBJECT (mux, "Unknown layout on adpcm caps");
2156 } else if (!strcmp (mimetype, "audio/G722")) {
2157 format = GST_RIFF_WAVE_FORMAT_ADPCM_G722;
2159 g_assert (format != 0);
2161 codec_priv_size = WAVEFORMATEX_SIZE;
2163 codec_priv_size += gst_buffer_get_size (buf);
2165 /* serialize waveformatex structure */
2166 codec_priv = g_malloc0 (codec_priv_size);
2167 GST_WRITE_UINT16_LE (codec_priv, format);
2168 GST_WRITE_UINT16_LE (codec_priv + 2, channels);
2169 GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
2170 GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
2171 GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
2172 GST_WRITE_UINT16_LE (codec_priv + 14, 0);
2174 GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
2176 GST_WRITE_UINT16_LE (codec_priv + 16, 0);
2178 /* process codec private/initialization data, if any */
2180 gst_buffer_extract (buf, 0,
2181 (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
2184 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
2185 gst_matroska_mux_free_codec_priv (context);
2186 context->codec_priv = (gpointer) codec_priv;
2187 context->codec_priv_size = codec_priv_size;
2195 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2196 GST_PAD_NAME (pad), caps);
2201 /* we probably don't have the data at start,
2202 * so have to reserve (a maximum) space to write this at the end.
2203 * bit spacy, but some formats can hold quite some */
2204 #define SUBTITLE_MAX_CODEC_PRIVATE 2048 /* must be > 128 */
2207 * gst_matroska_mux_subtitle_pad_setcaps:
2208 * @pad: Pad which got the caps.
2211 * Setcaps function for subtitle sink pad.
2213 * Returns: %TRUE on success.
2216 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
2218 /* There is now (at least) one such alement (kateenc), and I'm going
2219 to handle it here and claim it works when it can be piped back
2220 through GStreamer and VLC */
2222 GstMatroskaTrackContext *context = NULL;
2223 GstMatroskaTrackSubtitleContext *scontext;
2224 GstMatroskaMux *mux;
2225 GstMatroskaPad *collect_pad;
2226 const gchar *mimetype;
2227 GstStructure *structure;
2228 const GValue *value = NULL;
2229 GstBuffer *buf = NULL;
2230 gboolean ret = TRUE;
2233 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2235 if ((old_caps = gst_pad_get_current_caps (pad))) {
2236 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
2237 && !gst_caps_is_equal (caps, old_caps)) {
2238 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2239 ("Caps changed are not supported by Matroska"));
2240 gst_caps_unref (old_caps);
2243 gst_caps_unref (old_caps);
2247 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
2248 g_assert (collect_pad);
2249 context = collect_pad->track;
2251 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
2252 scontext = (GstMatroskaTrackSubtitleContext *) context;
2254 structure = gst_caps_get_structure (caps, 0);
2255 mimetype = gst_structure_get_name (structure);
2258 scontext->check_utf8 = 1;
2259 scontext->invalid_utf8 = 0;
2260 context->default_duration = 0;
2262 if (!strcmp (mimetype, "subtitle/x-kate")) {
2263 const GValue *streamheader;
2265 gst_matroska_mux_set_codec_id (context,
2266 GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
2268 gst_matroska_mux_free_codec_priv (context);
2270 streamheader = gst_structure_get_value (structure, "streamheader");
2271 if (!kate_streamheader_to_codecdata (streamheader, context)) {
2272 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2273 ("kate stream headers missing or malformed"));
2277 } else if (!strcmp (mimetype, "text/x-raw")) {
2278 gst_matroska_mux_set_codec_id (context,
2279 GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
2280 } else if (!strcmp (mimetype, "application/x-ssa")) {
2281 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
2282 } else if (!strcmp (mimetype, "application/x-ass")) {
2283 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
2284 } else if (!strcmp (mimetype, "application/x-usf")) {
2285 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
2286 } else if (!strcmp (mimetype, "subpicture/x-dvd")) {
2287 gst_matroska_mux_set_codec_id (context,
2288 GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
2294 /* maybe some private data, e.g. vobsub */
2295 value = gst_structure_get_value (structure, "codec_data");
2297 buf = gst_value_get_buffer (value);
2300 guint8 *priv_data = NULL;
2302 gst_buffer_map (buf, &map, GST_MAP_READ);
2304 if (map.size > SUBTITLE_MAX_CODEC_PRIVATE) {
2305 GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
2306 " exceeded maximum (%d); discarding", pad,
2307 SUBTITLE_MAX_CODEC_PRIVATE);
2308 gst_buffer_unmap (buf, &map);
2312 gst_matroska_mux_free_codec_priv (context);
2314 priv_data = g_malloc0 (map.size);
2315 memcpy (priv_data, map.data, map.size);
2316 context->codec_priv = priv_data;
2317 context->codec_priv_size = map.size;
2318 gst_buffer_unmap (buf, &map);
2321 GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %" G_GSIZE_FORMAT,
2322 GST_STR_NULL (context->codec_id), context->codec_priv_size);
2331 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2332 GST_PAD_NAME (pad), caps);
2339 * gst_matroska_mux_request_new_pad:
2340 * @element: #GstMatroskaMux.
2341 * @templ: #GstPadTemplate.
2342 * @pad_name: New pad name.
2344 * Request pad function for sink templates.
2346 * Returns: New #GstPad.
2349 gst_matroska_mux_request_new_pad (GstElement * element,
2350 GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
2352 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
2353 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
2354 GstMatroskaPad *collect_pad;
2355 GstMatroskamuxPad *newpad;
2357 const gchar *pad_name = NULL;
2358 GstMatroskaCapsFunc capsfunc = NULL;
2359 GstMatroskaTrackContext *context = NULL;
2361 gboolean locked = TRUE;
2362 const gchar *id = NULL;
2364 if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
2365 /* don't mix named and unnamed pads, if the pad already exists we fail when
2366 * trying to add it */
2367 if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
2368 pad_name = req_name;
2370 name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
2373 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
2374 context = (GstMatroskaTrackContext *)
2375 g_new0 (GstMatroskaTrackAudioContext, 1);
2376 context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
2377 context->name = g_strdup ("Audio");
2378 } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
2379 /* don't mix named and unnamed pads, if the pad already exists we fail when
2380 * trying to add it */
2381 if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
2382 pad_name = req_name;
2384 name = g_strdup_printf ("video_%u", mux->num_v_streams++);
2387 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
2388 context = (GstMatroskaTrackContext *)
2389 g_new0 (GstMatroskaTrackVideoContext, 1);
2390 context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
2391 context->name = g_strdup ("Video");
2392 } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
2393 /* don't mix named and unnamed pads, if the pad already exists we fail when
2394 * trying to add it */
2395 if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
2396 pad_name = req_name;
2398 name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
2401 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
2402 context = (GstMatroskaTrackContext *)
2403 g_new0 (GstMatroskaTrackSubtitleContext, 1);
2404 context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
2405 context->name = g_strdup ("Subtitle");
2406 /* setcaps may only provide proper one a lot later */
2407 id = "S_SUB_UNKNOWN";
2410 GST_WARNING_OBJECT (mux, "This is not our template!");
2414 newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
2415 "name", pad_name, "direction", templ->direction, "template", templ, NULL);
2417 gst_matroskamux_pad_init (newpad);
2418 collect_pad = (GstMatroskaPad *)
2419 gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad),
2420 sizeof (GstMatroskamuxPad),
2421 (GstCollectDataDestroyNotify) gst_matroska_pad_free, locked);
2423 collect_pad->mux = mux;
2424 collect_pad->track = context;
2425 gst_matroska_pad_reset (collect_pad, FALSE);
2427 gst_matroska_mux_set_codec_id (collect_pad->track, id);
2428 collect_pad->track->dts_only = FALSE;
2430 collect_pad->capsfunc = capsfunc;
2431 gst_pad_set_active (GST_PAD (newpad), TRUE);
2432 if (!gst_element_add_pad (element, GST_PAD (newpad)))
2433 goto pad_add_failed;
2439 GST_DEBUG_OBJECT (newpad, "Added new request pad");
2441 return GST_PAD (newpad);
2446 GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
2448 gst_object_unref (newpad);
2454 * gst_matroska_mux_release_pad:
2455 * @element: #GstMatroskaMux.
2456 * @pad: Pad to release.
2458 * Release a previously requested pad.
2461 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
2463 GstMatroskaMux *mux;
2466 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2468 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
2469 GstCollectData *cdata = (GstCollectData *) walk->data;
2470 GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
2472 if (cdata->pad == pad) {
2474 * observed duration, this will remain GST_CLOCK_TIME_NONE
2475 * only if the pad is resetted
2477 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
2479 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2480 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2481 collected_duration =
2482 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2485 if (GST_CLOCK_TIME_IS_VALID (collected_duration)
2486 && mux->duration < collected_duration)
2487 mux->duration = collected_duration;
2493 gst_collect_pads_remove_pad (mux->collect, pad);
2494 if (gst_element_remove_pad (element, pad))
2499 gst_matroska_mux_write_colour (GstMatroskaMux * mux,
2500 GstMatroskaTrackVideoContext * videocontext)
2502 GstEbmlWrite *ebml = mux->ebml_write;
2504 guint matrix_id = 0;
2506 guint transfer_id = 0;
2507 guint primaries_id = 0;
2509 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_VIDEOCOLOUR);
2511 switch (videocontext->colorimetry.matrix) {
2512 case GST_VIDEO_COLOR_MATRIX_RGB:
2515 case GST_VIDEO_COLOR_MATRIX_BT709:
2518 case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
2521 case GST_VIDEO_COLOR_MATRIX_FCC:
2524 case GST_VIDEO_COLOR_MATRIX_BT601:
2527 case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
2530 case GST_VIDEO_COLOR_MATRIX_BT2020:
2535 switch (videocontext->colorimetry.range) {
2536 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
2539 case GST_VIDEO_COLOR_RANGE_16_235:
2542 case GST_VIDEO_COLOR_RANGE_0_255:
2546 switch (videocontext->colorimetry.transfer) {
2547 case GST_VIDEO_TRANSFER_BT709:
2550 /* FIXME: can't tell what the code should be for these */
2551 case GST_VIDEO_TRANSFER_GAMMA18:
2552 case GST_VIDEO_TRANSFER_GAMMA20:
2553 case GST_VIDEO_TRANSFER_ADOBERGB:
2554 case GST_VIDEO_TRANSFER_UNKNOWN:
2557 /* Adobe RGB transfer is gamma 2.19921875 */
2558 case GST_VIDEO_TRANSFER_GAMMA22:
2561 case GST_VIDEO_TRANSFER_GAMMA28:
2564 case GST_VIDEO_TRANSFER_SMPTE240M:
2567 case GST_VIDEO_TRANSFER_GAMMA10:
2570 case GST_VIDEO_TRANSFER_LOG100:
2573 case GST_VIDEO_TRANSFER_LOG316:
2576 case GST_VIDEO_TRANSFER_SRGB:
2579 case GST_VIDEO_TRANSFER_BT2020_12:
2584 switch (videocontext->colorimetry.primaries) {
2585 case GST_VIDEO_COLOR_PRIMARIES_BT709:
2588 /* FIXME: can't tell what the code should be for this one */
2589 case GST_VIDEO_COLOR_PRIMARIES_ADOBERGB:
2590 case GST_VIDEO_COLOR_PRIMARIES_UNKNOWN:
2593 case GST_VIDEO_COLOR_PRIMARIES_BT470M:
2596 case GST_VIDEO_COLOR_PRIMARIES_BT470BG:
2599 case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
2602 case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
2605 case GST_VIDEO_COLOR_PRIMARIES_FILM:
2608 case GST_VIDEO_COLOR_PRIMARIES_BT2020:
2613 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEORANGE, range_id);
2614 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOMATRIXCOEFFICIENTS,
2616 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS,
2618 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPRIMARIES, primaries_id);
2619 gst_ebml_write_master_finish (ebml, master);
2623 * gst_matroska_mux_track_header:
2624 * @mux: #GstMatroskaMux
2625 * @context: Tack context.
2627 * Write a track header.
2630 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2631 GstMatroskaTrackContext * context)
2633 GstEbmlWrite *ebml = mux->ebml_write;
2636 /* TODO: check if everything necessary is written and check default values */
2638 /* track type goes before the type-specific stuff */
2639 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2640 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2642 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, context->uid);
2643 if (context->default_duration) {
2644 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2645 context->default_duration);
2647 if (context->language) {
2648 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2652 /* FIXME: until we have a nice way of getting the codecname
2653 * out of the caps, I'm not going to enable this. Too much
2654 * (useless, double, boring) work... */
2655 /* TODO: Use value from tags if any */
2656 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2657 context->codec_name); */
2658 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2660 /* type-specific stuff */
2661 switch (context->type) {
2662 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2663 GstMatroskaTrackVideoContext *videocontext =
2664 (GstMatroskaTrackVideoContext *) context;
2666 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2667 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2668 videocontext->pixel_width);
2669 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2670 videocontext->pixel_height);
2671 if (videocontext->display_width && videocontext->display_height) {
2672 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2673 videocontext->display_width);
2674 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2675 videocontext->display_height);
2677 switch (videocontext->interlace_mode) {
2678 case GST_MATROSKA_INTERLACE_MODE_INTERLACED:
2679 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2681 case GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE:
2682 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 2);
2688 if (videocontext->fourcc) {
2689 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2691 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2692 (gpointer) & fcc_le, 4);
2694 gst_matroska_mux_write_colour (mux, videocontext);
2695 if (videocontext->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
2696 guint64 stereo_mode = 0;
2698 switch (videocontext->multiview_mode) {
2699 case GST_VIDEO_MULTIVIEW_MODE_MONO:
2701 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
2702 if (videocontext->multiview_flags &
2703 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2704 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_RL;
2706 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_LR;
2708 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
2709 if (videocontext->multiview_flags &
2710 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2711 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_RL;
2713 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_LR;
2715 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
2716 if (videocontext->multiview_flags &
2717 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2718 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_RL;
2720 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_LR;
2722 case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
2723 if (videocontext->multiview_flags &
2724 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2725 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_RL;
2727 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_LR;
2728 /* FIXME: In frame-by-frame mode, left/right frame buffers need to be
2729 * laced within one block. See http://www.matroska.org/technical/specs/index.html#StereoMode */
2730 GST_FIXME_OBJECT (mux,
2731 "Frame-by-frame stereoscopic mode not fully implemented");
2734 GST_WARNING_OBJECT (mux,
2735 "Multiview mode %d not supported in Matroska/WebM",
2736 videocontext->multiview_mode);
2740 if (stereo_mode != 0)
2741 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOSTEREOMODE,
2744 gst_ebml_write_master_finish (ebml, master);
2749 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2750 GstMatroskaTrackAudioContext *audiocontext =
2751 (GstMatroskaTrackAudioContext *) context;
2753 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2754 if (audiocontext->samplerate != 8000)
2755 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2756 audiocontext->samplerate);
2757 if (audiocontext->channels != 1)
2758 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2759 audiocontext->channels);
2760 if (audiocontext->bitdepth) {
2761 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2762 audiocontext->bitdepth);
2765 gst_ebml_write_master_finish (ebml, master);
2770 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
2774 /* doesn't need type-specific data */
2778 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2779 if (context->codec_priv)
2780 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2781 context->codec_priv, context->codec_priv_size);
2783 if (context->seek_preroll) {
2784 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPREROLL,
2785 context->seek_preroll);
2788 if (context->codec_delay) {
2789 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CODECDELAY,
2790 context->codec_delay);
2795 gst_matroska_mux_write_chapter_title (const gchar * title, GstEbmlWrite * ebml)
2797 guint64 title_master;
2800 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERDISPLAY);
2802 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPSTRING, title);
2803 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CHAPLANGUAGE,
2804 GST_MATROSKA_MUX_CHAPLANG);
2806 gst_ebml_write_master_finish (ebml, title_master);
2809 static GstTocEntry *
2810 gst_matroska_mux_write_chapter (GstMatroskaMux * mux, GstTocEntry * edition,
2811 GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters,
2812 guint64 * master_edition)
2814 guint64 master_chapteratom;
2821 GstTocEntry *internal_chapter, *internal_nested;
2824 if (G_UNLIKELY (master_chapters != NULL && *master_chapters == 0))
2826 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERS);
2828 if (G_UNLIKELY (master_edition != NULL && *master_edition == 0)) {
2829 /* create uid for the parent */
2831 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_EDITIONENTRY);
2833 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONUID,
2834 g_ascii_strtoull (gst_toc_entry_get_uid (edition), NULL, 10));
2835 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGHIDDEN, 0);
2836 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGDEFAULT, 0);
2837 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGORDERED, 0);
2840 gst_toc_entry_get_start_stop_times (entry, &start, &stop);
2841 tags = gst_toc_entry_get_tags (entry);
2843 tags = gst_tag_list_copy (tags);
2846 /* build internal chapter */
2847 uid = gst_matroska_mux_create_uid (mux);
2848 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT, uid);
2849 internal_chapter = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, s_uid);
2851 /* Write the chapter entry */
2852 master_chapteratom =
2853 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERATOM);
2855 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERUID, uid);
2856 /* Store the user provided UID in the ChapterStringUID */
2857 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPTERSTRINGUID,
2858 gst_toc_entry_get_uid (entry));
2859 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTART, start);
2860 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTOP, stop);
2861 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGHIDDEN, 0);
2862 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGENABLED, 1);
2864 /* write current ChapterDisplays before the nested chapters */
2865 if (G_LIKELY (tags != NULL)) {
2866 count = gst_tag_list_get_tag_size (tags, GST_TAG_TITLE);
2868 for (i = 0; i < count; ++i) {
2869 gst_tag_list_get_string_index (tags, GST_TAG_TITLE, i, &title);
2870 /* FIXME: handle ChapterLanguage entries */
2871 gst_matroska_mux_write_chapter_title (title, ebml);
2875 /* remove title tag */
2876 if (G_LIKELY (count > 0))
2877 gst_tag_list_remove_tag (tags, GST_TAG_TITLE);
2879 gst_toc_entry_set_tags (internal_chapter, tags);
2882 /* Write nested chapters */
2883 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
2885 internal_nested = gst_matroska_mux_write_chapter (mux, NULL, cur->data,
2888 gst_toc_entry_append_sub_entry (internal_chapter, internal_nested);
2891 gst_ebml_write_master_finish (ebml, master_chapteratom);
2893 return internal_chapter;
2896 static GstTocEntry *
2897 gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
2898 GstTocEntry * edition, GList * chapters, GstEbmlWrite * ebml,
2899 guint64 * master_chapters)
2901 guint64 master_edition = 0;
2904 GstTocEntry *internal_edition, *internal_chapter;
2905 GstTagList *tags = NULL;
2907 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT,
2908 gst_matroska_mux_create_uid (mux));
2910 if (edition != NULL) {
2911 /* Edition entry defined, get its tags */
2912 tags = gst_toc_entry_get_tags (edition);
2914 tags = gst_tag_list_copy (tags);
2918 internal_edition = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, s_uid);
2920 gst_toc_entry_set_tags (internal_edition, tags);
2923 for (cur = g_list_first (chapters); cur != NULL; cur = cur->next) {
2924 internal_chapter = gst_matroska_mux_write_chapter (mux, internal_edition,
2925 cur->data, ebml, master_chapters, &master_edition);
2927 gst_toc_entry_append_sub_entry (internal_edition, internal_chapter);
2930 if (G_LIKELY (master_edition != 0))
2931 gst_ebml_write_master_finish (ebml, master_edition);
2933 return internal_edition;
2937 * gst_matroska_mux_start:
2938 * @mux: #GstMatroskaMux
2940 * Start a new matroska file (write headers etc...)
2943 gst_matroska_mux_start (GstMatroskaMux * mux, GstMatroskaPad * first_pad,
2944 GstBuffer * first_pad_buf)
2946 GstEbmlWrite *ebml = mux->ebml_write;
2947 const gchar *doctype;
2948 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
2949 GST_MATROSKA_ID_TRACKS,
2950 GST_MATROSKA_ID_CHAPTERS,
2951 GST_MATROSKA_ID_CUES,
2952 GST_MATROSKA_ID_TAGS,
2955 const gchar *media_type;
2956 gboolean audio_only;
2957 guint64 master, child;
2961 GstClockTime duration = 0;
2962 guint32 segment_uid[4];
2963 GTimeVal time = { 0, 0 };
2967 /* if not streaming, check if downstream is seekable */
2968 if (!mux->ebml_write->streamable) {
2972 query = gst_query_new_seeking (GST_FORMAT_BYTES);
2973 if (gst_pad_peer_query (mux->srcpad, query)) {
2974 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
2975 GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
2977 /* assume seeking is not supported if query not handled downstream */
2978 GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
2982 mux->ebml_write->streamable = TRUE;
2983 g_object_notify (G_OBJECT (mux), "streamable");
2984 GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
2985 "streamable=false. Will ignore that and create streamable output "
2988 gst_query_unref (query);
2991 /* stream-start (FIXME: create id based on input ids) */
2992 g_snprintf (s_id, sizeof (s_id), "matroskamux-%08x", g_random_int ());
2993 gst_pad_push_event (mux->srcpad, gst_event_new_stream_start (s_id));
2996 audio_only = mux->num_v_streams == 0 && mux->num_a_streams > 0;
2998 media_type = (audio_only) ? "audio/webm" : "video/webm";
3000 media_type = (audio_only) ? "audio/x-matroska" : "video/x-matroska";
3002 ebml->caps = gst_caps_new_empty_simple (media_type);
3003 gst_pad_set_caps (mux->srcpad, ebml->caps);
3004 /* we start with a EBML header */
3005 doctype = mux->doctype;
3006 GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
3007 doctype, mux->doctype_version);
3008 gst_ebml_write_header (ebml, doctype, mux->doctype_version);
3010 /* the rest of the header is cached */
3011 gst_ebml_write_set_cache (ebml, 0x1000);
3013 /* start a segment */
3015 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
3016 mux->segment_master = ebml->pos;
3018 if (!mux->ebml_write->streamable) {
3019 /* seekhead (table of contents) - we set the positions later */
3020 mux->seekhead_pos = ebml->pos;
3021 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
3022 for (i = 0; seekhead_id[i] != 0; i++) {
3023 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
3024 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
3025 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
3026 gst_ebml_write_master_finish (ebml, child);
3028 gst_ebml_write_master_finish (ebml, master);
3031 if (mux->ebml_write->streamable) {
3032 const GstTagList *tags;
3033 gboolean has_main_tags;
3036 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3037 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3039 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux)) {
3040 guint64 master_tags, master_tag;
3042 GST_DEBUG_OBJECT (mux, "Writing tags");
3044 mux->tags_pos = ebml->pos;
3045 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3046 if (has_main_tags) {
3047 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3048 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3049 gst_ebml_write_master_finish (ebml, master_tag);
3051 gst_matroska_mux_write_streams_tags (mux);
3052 gst_ebml_write_master_finish (ebml, master_tags);
3057 mux->info_pos = ebml->pos;
3058 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
3060 /* WebM does not support SegmentUID field on SegmentInfo */
3061 if (!mux->is_webm) {
3062 for (i = 0; i < 4; i++) {
3063 segment_uid[i] = g_random_int ();
3065 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
3066 (guint8 *) segment_uid, 16);
3069 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
3070 mux->duration_pos = ebml->pos;
3072 if (!mux->ebml_write->streamable) {
3073 for (collected = mux->collect->data; collected;
3074 collected = g_slist_next (collected)) {
3075 GstMatroskaPad *collect_pad;
3077 gint64 trackduration;
3079 collect_pad = (GstMatroskaPad *) collected->data;
3080 thepad = collect_pad->collect.pad;
3082 /* Query the total length of the track. */
3083 GST_DEBUG_OBJECT (thepad, "querying peer duration");
3084 if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
3085 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
3086 GST_TIME_ARGS (trackduration));
3087 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
3088 duration = (GstClockTime) trackduration;
3092 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3093 gst_guint64_to_gdouble (duration) /
3094 gst_guint64_to_gdouble (mux->time_scale));
3096 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
3097 "GStreamer matroskamux version " PACKAGE_VERSION);
3098 if (mux->writing_app && mux->writing_app[0]) {
3099 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
3101 g_get_current_time (&time);
3102 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
3103 gst_ebml_write_master_finish (ebml, master);
3106 mux->tracks_pos = ebml->pos;
3107 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
3109 for (collected = mux->collect->data; collected;
3110 collected = g_slist_next (collected)) {
3111 GstMatroskaPad *collect_pad;
3114 collect_pad = (GstMatroskaPad *) collected->data;
3116 /* This will cause an error at a later time */
3117 if (collect_pad->track->codec_id == NULL)
3120 /* For audio tracks, use the first buffers duration as the default
3121 * duration if we didn't get any better idea from the caps event already
3123 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO &&
3124 collect_pad->track->default_duration == 0) {
3125 if (collect_pad == first_pad)
3126 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3128 buf = gst_collect_pads_peek (mux->collect, collected->data);
3130 if (buf && GST_BUFFER_DURATION_IS_VALID (buf))
3131 collect_pad->track->default_duration =
3132 GST_BUFFER_DURATION (buf) + collect_pad->track->codec_delay;
3134 gst_buffer_unref (buf);
3137 collect_pad->track->num = tracknum++;
3138 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
3139 gst_matroska_mux_track_header (mux, collect_pad->track);
3140 gst_ebml_write_master_finish (ebml, child);
3141 /* some remaining pad/track setup */
3142 collect_pad->default_duration_scaled =
3143 gst_util_uint64_scale (collect_pad->track->default_duration,
3144 1, mux->time_scale);
3146 gst_ebml_write_master_finish (ebml, master);
3149 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3150 if (toc != NULL && !mux->ebml_write->streamable) {
3151 guint64 master_chapters = 0;
3152 GstTocEntry *internal_edition;
3153 GList *cur, *chapters;
3155 GST_DEBUG ("Writing chapters");
3157 /* There are two UIDs for Chapters:
3158 * - The ChapterUID is a mandatory unsigned integer which internally
3159 * refers to a given chapter. Except for the title & language which use
3160 * dedicated fields, this UID can also be used to add tags to the Chapter.
3161 * The tags come in a separate section of the container.
3162 * - The ChapterStringUID is an optional UTF-8 string which also uniquely
3163 * refers to a chapter but from an external perspective. It can act as a
3164 * "WebVTT cue identifier" which "can be used to reference a specific cue,
3165 * for example from script or CSS".
3167 * The ChapterUID will be generated and checked for unicity, while the
3168 * ChapterStringUID will receive the user defined UID.
3170 * In order to be able to refer to chapters from the tags section,
3171 * we must maintain an internal Toc tree with the generated ChapterUID
3172 * (see gst_matroska_mux_write_toc_entry_tags) */
3174 /* Check whether we have editions or chapters at the root level. */
3175 cur = gst_toc_get_entries (toc);
3177 mux->chapters_pos = ebml->pos;
3179 mux->internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
3181 if (gst_toc_entry_get_entry_type (cur->data) ==
3182 GST_TOC_ENTRY_TYPE_EDITION) {
3183 /* Editions at the root level */
3184 for (; cur != NULL; cur = cur->next) {
3185 chapters = gst_toc_entry_get_sub_entries (cur->data);
3186 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3187 cur->data, chapters, ebml, &master_chapters);
3188 gst_toc_append_entry (mux->internal_toc, internal_edition);
3191 /* Chapters at the root level */
3192 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3193 NULL, cur, ebml, &master_chapters);
3194 gst_toc_append_entry (mux->internal_toc, internal_edition);
3197 /* close master element if any edition was written */
3198 if (G_LIKELY (master_chapters != 0))
3199 gst_ebml_write_master_finish (ebml, master_chapters);
3203 /* lastly, flush the cache */
3204 gst_ebml_write_flush_cache (ebml, FALSE, 0);
3207 gst_toc_unref (toc);
3210 /* TODO: more sensible tag mappings */
3213 const gchar *matroska_tagname;
3214 const gchar *gstreamer_tagname;
3216 gst_matroska_tag_conv[] = {
3218 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
3219 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
3220 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
3221 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
3222 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
3223 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
3224 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
3225 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
3226 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
3227 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
3228 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
3229 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
3230 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
3231 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
3232 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
3235 /* Every stagefright implementation on android up to and including 6.0.1 is using
3236 libwebm with bug in matroska parsing, where it will choke on empty tag elements;
3237 so before outputting tags and tag elements we better make sure that there are
3238 actually tags we are going to write */
3240 gst_matroska_mux_tag_list_is_empty (const GstTagList * list)
3243 for (i = 0; i < gst_tag_list_n_tags (list); i++) {
3244 const gchar *tag = gst_tag_list_nth_tag_name (list, i);
3246 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3247 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3248 if (strcmp (tagname_gst, tag) == 0) {
3249 GValue src = { 0, };
3252 if (!gst_tag_list_copy_value (&src, list, tag))
3254 dest = gst_value_serialize (&src);
3256 g_value_unset (&src);
3268 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
3271 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
3273 guint64 simpletag_master;
3275 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3276 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3277 const gchar *tagname_mkv = gst_matroska_tag_conv[i].matroska_tagname;
3279 if (strcmp (tagname_gst, tag) == 0) {
3280 GValue src = { 0, };
3283 if (!gst_tag_list_copy_value (&src, list, tag))
3285 if ((dest = gst_value_serialize (&src))) {
3287 simpletag_master = gst_ebml_write_master_start (ebml,
3288 GST_MATROSKA_ID_SIMPLETAG);
3289 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
3290 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
3291 gst_ebml_write_master_finish (ebml, simpletag_master);
3294 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
3296 g_value_unset (&src);
3303 gst_matroska_mux_write_stream_tags (GstMatroskaMux * mux, GstMatroskaPad * mpad)
3305 guint64 master_tag, master_targets;
3308 ebml = mux->ebml_write;
3310 if (G_UNLIKELY (mpad->tags == NULL
3311 || gst_matroska_mux_tag_list_is_empty (mpad->tags)))
3314 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3315 master_targets = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3317 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETTRACKUID, mpad->track->uid);
3319 gst_ebml_write_master_finish (ebml, master_targets);
3320 gst_tag_list_foreach (mpad->tags, gst_matroska_mux_write_simple_tag, ebml);
3321 gst_ebml_write_master_finish (ebml, master_tag);
3325 gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux)
3329 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3330 GstMatroskaPad *collect_pad;
3332 collect_pad = (GstMatroskaPad *) walk->data;
3334 gst_matroska_mux_write_stream_tags (mux, collect_pad);
3339 gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux)
3343 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3344 GstMatroskaPad *collect_pad;
3346 collect_pad = (GstMatroskaPad *) walk->data;
3347 if (!gst_matroska_mux_tag_list_is_empty (collect_pad->tags))
3354 gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
3355 const GstTocEntry * entry, guint64 * master_tags, gboolean * has_tags)
3357 guint64 master_tag, master_targets;
3360 const GstTagList *tags;
3362 ebml = mux->ebml_write;
3364 tags = gst_toc_entry_get_tags (entry);
3365 if (G_UNLIKELY (tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags))) {
3368 if (*master_tags == 0) {
3369 mux->tags_pos = ebml->pos;
3370 *master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3373 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3375 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3377 if (gst_toc_entry_get_entry_type (entry) == GST_TOC_ENTRY_TYPE_EDITION)
3378 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETEDITIONUID,
3379 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3381 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETCHAPTERUID,
3382 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3384 gst_ebml_write_master_finish (ebml, master_targets);
3385 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3386 gst_ebml_write_master_finish (ebml, master_tag);
3389 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3391 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, master_tags,
3397 * gst_matroska_mux_finish:
3398 * @mux: #GstMatroskaMux
3400 * Finish a new matroska file (write index etc...)
3403 gst_matroska_mux_finish (GstMatroskaMux * mux)
3405 GstEbmlWrite *ebml = mux->ebml_write;
3407 guint64 duration = 0;
3409 const GstTagList *tags, *toc_tags;
3411 gboolean has_main_tags, toc_has_tags = FALSE;
3414 /* finish last cluster */
3416 gst_ebml_write_master_finish (ebml, mux->cluster);
3420 if (mux->index != NULL) {
3422 guint64 master, pointentry_master, trackpos_master;
3424 mux->cues_pos = ebml->pos;
3425 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
3426 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
3428 for (n = 0; n < mux->num_indexes; n++) {
3429 GstMatroskaIndex *idx = &mux->index[n];
3431 pointentry_master = gst_ebml_write_master_start (ebml,
3432 GST_MATROSKA_ID_POINTENTRY);
3433 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
3434 idx->time / mux->time_scale);
3435 trackpos_master = gst_ebml_write_master_start (ebml,
3436 GST_MATROSKA_ID_CUETRACKPOSITIONS);
3437 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
3438 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
3439 idx->pos - mux->segment_master);
3440 gst_ebml_write_master_finish (ebml, trackpos_master);
3441 gst_ebml_write_master_finish (ebml, pointentry_master);
3444 gst_ebml_write_master_finish (ebml, master);
3445 gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
3449 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3450 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3451 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3453 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux) || toc != NULL) {
3454 guint64 master_tags = 0, master_tag;
3456 GST_DEBUG_OBJECT (mux, "Writing tags");
3458 if (has_main_tags) {
3459 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
3460 mux->tags_pos = ebml->pos;
3461 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3462 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3465 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3466 if (mux->internal_toc != NULL) {
3467 toc_tags = gst_toc_get_tags (mux->internal_toc);
3468 toc_has_tags = (toc_tags != NULL);
3469 gst_tag_list_foreach (toc_tags, gst_matroska_mux_write_simple_tag,
3473 gst_ebml_write_master_finish (ebml, master_tag);
3476 if (mux->internal_toc != NULL) {
3477 for (cur = gst_toc_get_entries (mux->internal_toc); cur != NULL;
3479 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, &master_tags,
3484 if (master_tags == 0 && gst_matroska_mux_streams_have_tags (mux)) {
3485 mux->tags_pos = ebml->pos;
3486 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3488 gst_matroska_mux_write_streams_tags (mux);
3490 if (master_tags != 0)
3491 gst_ebml_write_master_finish (ebml, master_tags);
3494 /* update seekhead. We know that:
3495 * - a seekhead contains 5 entries.
3496 * - order of entries is as above.
3497 * - a seekhead has a 4-byte header + 8-byte length
3498 * - each entry is 2-byte master, 2-byte ID pointer,
3499 * 2-byte length pointer, all 8/1-byte length, 4-
3500 * byte ID and 8-byte length pointer, where the
3501 * length pointer starts at 20.
3502 * - all entries are local to the segment (so pos - segment_master).
3503 * - so each entry is at 12 + 20 + num * 28. */
3504 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
3505 mux->info_pos - mux->segment_master);
3506 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
3507 mux->tracks_pos - mux->segment_master);
3508 if (toc != NULL && mux->chapters_pos > 0) {
3509 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
3510 mux->chapters_pos - mux->segment_master);
3513 guint64 my_pos = ebml->pos;
3515 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
3516 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3517 gst_ebml_write_seek (ebml, my_pos);
3519 if (mux->index != NULL) {
3520 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
3521 mux->cues_pos - mux->segment_master);
3524 guint64 my_pos = ebml->pos;
3526 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
3527 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3528 gst_ebml_write_seek (ebml, my_pos);
3531 if (tags != NULL || toc_has_tags) {
3532 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 144,
3533 mux->tags_pos - mux->segment_master);
3536 guint64 my_pos = ebml->pos;
3538 gst_ebml_write_seek (ebml, mux->seekhead_pos + 124);
3539 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3540 gst_ebml_write_seek (ebml, my_pos);
3544 gst_toc_unref (toc);
3548 * - first get the overall duration
3549 * (a released track may have left a duration in here)
3550 * - write some track header data for subtitles
3552 duration = mux->duration;
3554 for (collected = mux->collect->data; collected;
3555 collected = g_slist_next (collected)) {
3556 GstMatroskaPad *collect_pad;
3558 * observed duration, this will never remain GST_CLOCK_TIME_NONE
3559 * since this means buffer without timestamps that is not possibile
3561 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
3563 collect_pad = (GstMatroskaPad *) collected->data;
3565 GST_DEBUG_OBJECT (mux,
3566 "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
3567 " end ts %" GST_TIME_FORMAT, collect_pad,
3568 GST_TIME_ARGS (collect_pad->start_ts),
3569 GST_TIME_ARGS (collect_pad->end_ts));
3571 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
3572 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
3573 collected_duration =
3574 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
3575 GST_DEBUG_OBJECT (collect_pad,
3576 "final track duration: %" GST_TIME_FORMAT,
3577 GST_TIME_ARGS (collected_duration));
3579 GST_WARNING_OBJECT (collect_pad, "unable to get final track duration");
3581 if (GST_CLOCK_TIME_IS_VALID (collected_duration) &&
3582 duration < collected_duration)
3583 duration = collected_duration;
3587 /* seek back (optional, but do anyway) */
3588 gst_ebml_write_seek (ebml, pos);
3590 /* update duration */
3591 if (duration != 0) {
3592 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
3593 GST_TIME_ARGS (duration));
3594 pos = mux->ebml_write->pos;
3595 gst_ebml_write_seek (ebml, mux->duration_pos);
3596 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3597 gst_guint64_to_gdouble (duration) /
3598 gst_guint64_to_gdouble (mux->time_scale));
3599 gst_ebml_write_seek (ebml, pos);
3602 guint64 my_pos = ebml->pos;
3604 gst_ebml_write_seek (ebml, mux->duration_pos);
3605 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
3606 gst_ebml_write_seek (ebml, my_pos);
3608 GST_DEBUG_OBJECT (mux, "finishing segment");
3609 /* finish segment - this also writes element length */
3610 gst_ebml_write_master_finish (ebml, mux->segment_pos);
3614 * gst_matroska_mux_buffer_header:
3615 * @track: Track context.
3616 * @relative_timestamp: relative timestamp of the buffer
3617 * @flags: Buffer flags.
3619 * Create a buffer containing buffer header.
3621 * Returns: New buffer.
3624 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
3625 gint16 relative_timestamp, int flags)
3628 guint8 *data = g_malloc (4);
3630 hdr = gst_buffer_new_wrapped (data, 4);
3631 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
3632 data[0] = track->num | 0x80;
3633 /* time relative to clustertime */
3634 GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
3642 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
3643 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
3644 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
3647 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
3648 GstMatroskaPad * collect_pad, GstBuffer * buf)
3650 GstMatroskaTrackVideoContext *ctx =
3651 (GstMatroskaTrackVideoContext *) collect_pad->track;
3656 guint32 next_parse_offset;
3657 GstBuffer *ret = NULL;
3658 gboolean is_muxing_unit = FALSE;
3660 gst_buffer_map (buf, &map, GST_MAP_READ);
3665 gst_buffer_unmap (buf, &map);
3666 gst_buffer_unref (buf);
3670 /* Check if this buffer contains a picture or end-of-sequence packet */
3671 while (size >= 13) {
3672 if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
3673 gst_buffer_unmap (buf, &map);
3674 gst_buffer_unref (buf);
3678 parse_code = GST_READ_UINT8 (data + 4);
3679 if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
3680 if (ctx->dirac_unit) {
3681 gst_buffer_unref (ctx->dirac_unit);
3682 ctx->dirac_unit = NULL;
3684 } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
3685 parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
3686 is_muxing_unit = TRUE;
3690 next_parse_offset = GST_READ_UINT32_BE (data + 5);
3692 if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
3695 data += next_parse_offset;
3696 size -= next_parse_offset;
3699 if (ctx->dirac_unit)
3700 ctx->dirac_unit = gst_buffer_append (ctx->dirac_unit, gst_buffer_ref (buf));
3702 ctx->dirac_unit = gst_buffer_ref (buf);
3704 gst_buffer_unmap (buf, &map);
3706 if (is_muxing_unit) {
3707 ret = gst_buffer_make_writable (ctx->dirac_unit);
3708 ctx->dirac_unit = NULL;
3709 gst_buffer_copy_into (ret, buf,
3710 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
3711 gst_buffer_unref (buf);
3713 gst_buffer_unref (buf);
3721 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
3725 GValue streamheader = { 0 };
3726 GValue bufval = { 0 };
3727 GstBuffer *streamheader_buffer;
3728 GstEbmlWrite *ebml = mux->ebml_write;
3730 streamheader_buffer = gst_ebml_stop_streamheader (ebml);
3731 caps = gst_caps_copy (mux->ebml_write->caps);
3732 s = gst_caps_get_structure (caps, 0);
3733 g_value_init (&streamheader, GST_TYPE_ARRAY);
3734 g_value_init (&bufval, GST_TYPE_BUFFER);
3735 GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_HEADER);
3736 gst_value_set_buffer (&bufval, streamheader_buffer);
3737 gst_value_array_append_value (&streamheader, &bufval);
3738 g_value_unset (&bufval);
3739 gst_structure_set_value (s, "streamheader", &streamheader);
3740 g_value_unset (&streamheader);
3741 gst_caps_replace (&ebml->caps, caps);
3742 gst_buffer_unref (streamheader_buffer);
3743 gst_pad_set_caps (mux->srcpad, caps);
3744 gst_caps_unref (caps);
3748 * gst_matroska_mux_write_data:
3749 * @mux: #GstMatroskaMux
3750 * @collect_pad: #GstMatroskaPad with the data
3752 * Write collected data (called from gst_matroska_mux_collected).
3754 * Returns: Result of the gst_pad_push issued to write the data.
3756 static GstFlowReturn
3757 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
3760 GstEbmlWrite *ebml = mux->ebml_write;
3763 gboolean write_duration;
3764 gint16 relative_timestamp;
3765 gint64 relative_timestamp64;
3766 guint64 block_duration, duration_diff = 0;
3767 gboolean is_video_keyframe = FALSE;
3768 gboolean is_video_invisible = FALSE;
3769 gboolean is_audio_only = FALSE;
3770 gboolean is_min_duration_reached = FALSE;
3771 gboolean is_max_duration_exceeded = FALSE;
3772 GstMatroskamuxPad *pad;
3774 GstClockTime buffer_timestamp;
3775 GstAudioClippingMeta *cmeta = NULL;
3778 pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
3780 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
3781 if (collect_pad->track->xiph_headers_to_skip > 0) {
3782 --collect_pad->track->xiph_headers_to_skip;
3783 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER)) {
3784 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
3785 gst_buffer_unref (buf);
3790 /* for dirac we have to queue up everything up to a picture unit */
3791 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC)) {
3792 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
3795 } else if (!strcmp (collect_pad->track->codec_id,
3796 GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) {
3797 /* Remove the 'Frame container atom' header' */
3798 buf = gst_buffer_make_writable (buf);
3799 gst_buffer_resize (buf, 8, gst_buffer_get_size (buf) - 8);
3803 gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
3805 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
3806 * this would wreak havoc with time stored in matroska file */
3807 /* TODO: maybe calculate a timestamp by using the previous timestamp
3808 * and default duration */
3809 if (!GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
3810 GST_WARNING_OBJECT (collect_pad->collect.pad,
3811 "Invalid buffer timestamp; dropping buffer");
3812 gst_buffer_unref (buf);
3816 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
3817 && collect_pad->track->codec_delay) {
3818 /* All timestamps should include the codec delay */
3819 if (buffer_timestamp > collect_pad->track->codec_delay) {
3820 buffer_timestamp += collect_pad->track->codec_delay;
3822 buffer_timestamp = 0;
3823 duration_diff = collect_pad->track->codec_delay - buffer_timestamp;
3827 /* set the timestamp for outgoing buffers */
3828 ebml->timestamp = buffer_timestamp;
3830 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
3831 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
3832 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
3833 GST_TIME_ARGS (buffer_timestamp));
3834 is_video_keyframe = TRUE;
3835 } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DECODE_ONLY) &&
3836 (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP8)
3837 || !strcmp (collect_pad->track->codec_id,
3838 GST_MATROSKA_CODEC_ID_VIDEO_VP9))) {
3839 GST_LOG_OBJECT (mux,
3840 "have VP8 video invisible frame, " "ts=%" GST_TIME_FORMAT,
3841 GST_TIME_ARGS (buffer_timestamp));
3842 is_video_invisible = TRUE;
3846 is_audio_only = (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
3847 (mux->num_streams == 1);
3848 is_min_duration_reached = (mux->min_cluster_duration == 0
3849 || (buffer_timestamp > mux->cluster_time
3850 && (buffer_timestamp - mux->cluster_time) >=
3851 mux->min_cluster_duration));
3852 is_max_duration_exceeded = (mux->max_cluster_duration > 0
3853 && buffer_timestamp > mux->cluster_time
3854 && (buffer_timestamp - mux->cluster_time) >=
3855 MIN (G_MAXINT16 * mux->time_scale, mux->max_cluster_duration));
3858 /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
3859 * or when we may be reaching the limit of the relative timestamp */
3860 if (is_max_duration_exceeded || (is_video_keyframe
3861 && is_min_duration_reached) || mux->force_key_unit_event
3862 || (is_audio_only && is_min_duration_reached)) {
3863 if (!mux->ebml_write->streamable)
3864 gst_ebml_write_master_finish (ebml, mux->cluster);
3866 /* Forward the GstForceKeyUnit event after finishing the cluster */
3867 if (mux->force_key_unit_event) {
3868 gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
3869 mux->force_key_unit_event = NULL;
3872 mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
3873 mux->cluster_pos = ebml->pos;
3874 gst_ebml_write_set_cache (ebml, 0x20);
3876 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
3877 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
3878 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
3879 GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
3880 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
3881 gst_ebml_write_flush_cache (ebml, is_video_keyframe
3882 || is_audio_only, buffer_timestamp);
3883 mux->cluster_time = buffer_timestamp;
3884 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
3885 mux->prev_cluster_size);
3890 mux->cluster_pos = ebml->pos;
3891 gst_ebml_write_set_cache (ebml, 0x20);
3892 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
3893 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
3894 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
3895 gst_ebml_write_flush_cache (ebml, TRUE, buffer_timestamp);
3896 mux->cluster_time = buffer_timestamp;
3899 /* We currently write index entries for all video tracks or for the audio
3900 * track in a single-track audio file. This could be improved by keeping the
3901 * index only for the *first* video track. */
3903 /* TODO: index is useful for every track, should contain the number of
3904 * the block in the cluster which contains the timestamp, should also work
3905 * for files with multiple audio tracks.
3907 if (!mux->ebml_write->streamable && (is_video_keyframe || is_audio_only)) {
3910 if (mux->min_index_interval != 0) {
3911 for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
3912 if (mux->index[last_idx].track == collect_pad->track->num)
3917 if (last_idx < 0 || mux->min_index_interval == 0 ||
3918 (GST_CLOCK_DIFF (mux->index[last_idx].time, buffer_timestamp)
3919 >= mux->min_index_interval)) {
3920 GstMatroskaIndex *idx;
3922 if (mux->num_indexes % 32 == 0) {
3923 mux->index = g_renew (GstMatroskaIndex, mux->index,
3924 mux->num_indexes + 32);
3926 idx = &mux->index[mux->num_indexes++];
3928 idx->pos = mux->cluster_pos;
3929 idx->time = buffer_timestamp;
3930 idx->track = collect_pad->track->num;
3934 /* Check if the duration differs from the default duration. */
3935 write_duration = FALSE;
3937 if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
3938 block_duration = GST_BUFFER_DURATION (buf) + duration_diff;
3939 block_duration = gst_util_uint64_scale (block_duration, 1, mux->time_scale);
3941 /* small difference should be ok. */
3942 if (block_duration > collect_pad->default_duration_scaled + 1 ||
3943 block_duration < collect_pad->default_duration_scaled - 1) {
3944 write_duration = TRUE;
3948 /* write the block, for doctype v2 use SimpleBlock if possible
3949 * one slice (*breath*).
3950 * FIXME: Need to do correct lacing! */
3951 relative_timestamp64 = buffer_timestamp - mux->cluster_time;
3952 if (relative_timestamp64 >= 0) {
3953 /* round the timestamp */
3954 relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
3955 relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
3958 /* round the timestamp */
3959 relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
3960 relative_timestamp =
3961 -((gint16) gst_util_uint64_scale (-relative_timestamp64, 1,
3965 if (is_video_invisible)
3968 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
3969 cmeta = gst_buffer_get_audio_clipping_meta (buf);
3970 g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);
3972 /* Start clipping is done via header and CodecDelay */
3973 if (cmeta && !cmeta->end)
3977 if (mux->doctype_version > 1 && !write_duration && !cmeta) {
3978 if (is_video_keyframe)
3982 gst_matroska_mux_create_buffer_header (collect_pad->track,
3983 relative_timestamp, flags);
3984 gst_ebml_write_set_cache (ebml, 0x40);
3985 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
3986 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
3987 gst_ebml_write_buffer (ebml, hdr);
3988 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
3989 gst_ebml_write_buffer (ebml, buf);
3991 return gst_ebml_last_write_result (ebml);
3993 gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
3994 /* write and call order slightly unnatural,
3995 * but avoids seek and minizes pushing */
3996 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
3998 gst_matroska_mux_create_buffer_header (collect_pad->track,
3999 relative_timestamp, flags);
4001 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
4003 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4005 /* Start clipping is done via header and CodecDelay */
4008 gst_util_uint64_scale_round (cmeta->end, GST_SECOND, 48000);
4009 gst_ebml_write_sint (ebml, GST_MATROSKA_ID_DISCARDPADDING, end);
4013 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
4014 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4015 gst_ebml_write_buffer (ebml, hdr);
4016 gst_ebml_write_master_finish_full (ebml, blockgroup,
4017 gst_buffer_get_size (buf));
4018 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4019 gst_ebml_write_buffer (ebml, buf);
4021 return gst_ebml_last_write_result (ebml);
4026 * gst_matroska_mux_handle_buffer:
4027 * @pads: #GstCollectPads
4028 * @uuser_data: #GstMatroskaMux
4030 * Collectpads callback.
4032 * Returns: #GstFlowReturn
4034 static GstFlowReturn
4035 gst_matroska_mux_handle_buffer (GstCollectPads * pads, GstCollectData * data,
4036 GstBuffer * buf, gpointer user_data)
4038 GstClockTime buffer_timestamp;
4039 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
4040 GstEbmlWrite *ebml = mux->ebml_write;
4041 GstMatroskaPad *best = (GstMatroskaPad *) data;
4042 GstFlowReturn ret = GST_FLOW_OK;
4043 GST_DEBUG_OBJECT (mux, "Collected pads");
4045 /* start with a header */
4046 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
4047 if (mux->collect->data == NULL) {
4048 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
4049 ("No input streams configured"));
4050 return GST_FLOW_ERROR;
4052 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
4053 gst_ebml_start_streamheader (ebml);
4054 gst_matroska_mux_start (mux, best, buf);
4055 gst_matroska_mux_stop_streamheader (mux);
4056 mux->state = GST_MATROSKA_MUX_STATE_DATA;
4059 /* if there is no best pad, we have reached EOS */
4061 GST_DEBUG_OBJECT (mux, "No best pad. Finishing...");
4062 if (!mux->ebml_write->streamable) {
4063 gst_matroska_mux_finish (mux);
4065 GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
4067 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
4072 if (best->track->codec_id == NULL) {
4073 GST_ERROR_OBJECT (best->collect.pad, "No codec-id for pad");
4074 ret = GST_FLOW_NOT_NEGOTIATED;
4078 /* if we have a best stream, should also have a buffer */
4081 buffer_timestamp = gst_matroska_track_get_buffer_timestamp (best->track, buf);
4083 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
4084 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
4085 GST_TIME_ARGS (buffer_timestamp),
4086 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
4088 /* make note of first and last encountered timestamps, so we can calculate
4089 * the actual duration later when we send an updated header on eos */
4090 if (GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
4091 GstClockTime start_ts = buffer_timestamp;
4092 GstClockTime end_ts = start_ts;
4094 if (GST_BUFFER_DURATION_IS_VALID (buf))
4095 end_ts += GST_BUFFER_DURATION (buf);
4096 else if (best->track->default_duration)
4097 end_ts += best->track->default_duration;
4099 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
4100 best->end_ts = end_ts;
4102 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
4103 start_ts < best->start_ts))
4104 best->start_ts = start_ts;
4107 /* write one buffer */
4108 ret = gst_matroska_mux_write_data (mux, best, buf);
4116 * gst_matroska_mux_change_state:
4117 * @element: #GstMatroskaMux
4118 * @transition: State change transition.
4120 * Change the muxer state.
4122 * Returns: #GstStateChangeReturn
4124 static GstStateChangeReturn
4125 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
4127 GstStateChangeReturn ret;
4128 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
4130 switch (transition) {
4131 case GST_STATE_CHANGE_NULL_TO_READY:
4133 case GST_STATE_CHANGE_READY_TO_PAUSED:
4134 gst_collect_pads_start (mux->collect);
4136 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4138 case GST_STATE_CHANGE_PAUSED_TO_READY:
4139 gst_collect_pads_stop (mux->collect);
4145 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4147 switch (transition) {
4148 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4150 case GST_STATE_CHANGE_PAUSED_TO_READY:
4151 gst_matroska_mux_reset (GST_ELEMENT (mux));
4153 case GST_STATE_CHANGE_READY_TO_NULL:
4163 gst_matroska_mux_set_property (GObject * object,
4164 guint prop_id, const GValue * value, GParamSpec * pspec)
4166 GstMatroskaMux *mux;
4168 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4169 mux = GST_MATROSKA_MUX (object);
4172 case PROP_WRITING_APP:
4173 if (!g_value_get_string (value)) {
4174 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
4177 g_free (mux->writing_app);
4178 mux->writing_app = g_value_dup_string (value);
4180 case PROP_DOCTYPE_VERSION:
4181 mux->doctype_version = g_value_get_int (value);
4183 case PROP_MIN_INDEX_INTERVAL:
4184 mux->min_index_interval = g_value_get_int64 (value);
4186 case PROP_STREAMABLE:
4187 mux->ebml_write->streamable = g_value_get_boolean (value);
4189 case PROP_TIMECODESCALE:
4190 mux->time_scale = g_value_get_int64 (value);
4192 case PROP_MIN_CLUSTER_DURATION:
4193 mux->min_cluster_duration = g_value_get_int64 (value);
4195 case PROP_MAX_CLUSTER_DURATION:
4196 mux->max_cluster_duration = g_value_get_int64 (value);
4199 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4205 gst_matroska_mux_get_property (GObject * object,
4206 guint prop_id, GValue * value, GParamSpec * pspec)
4208 GstMatroskaMux *mux;
4210 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4211 mux = GST_MATROSKA_MUX (object);
4214 case PROP_WRITING_APP:
4215 g_value_set_string (value, mux->writing_app);
4217 case PROP_DOCTYPE_VERSION:
4218 g_value_set_int (value, mux->doctype_version);
4220 case PROP_MIN_INDEX_INTERVAL:
4221 g_value_set_int64 (value, mux->min_index_interval);
4223 case PROP_STREAMABLE:
4224 g_value_set_boolean (value, mux->ebml_write->streamable);
4226 case PROP_TIMECODESCALE:
4227 g_value_set_int64 (value, mux->time_scale);
4229 case PROP_MIN_CLUSTER_DURATION:
4230 g_value_set_int64 (value, mux->min_cluster_duration);
4232 case PROP_MAX_CLUSTER_DURATION:
4233 g_value_set_int64 (value, mux->max_cluster_duration);
4236 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);