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:
2611 case GST_VIDEO_COLOR_PRIMARIES_SMPTEST428:
2614 case GST_VIDEO_COLOR_PRIMARIES_SMPTERP431:
2617 case GST_VIDEO_COLOR_PRIMARIES_SMPTEEG432:
2620 case GST_VIDEO_COLOR_PRIMARIES_EBU3213:
2625 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEORANGE, range_id);
2626 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOMATRIXCOEFFICIENTS,
2628 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS,
2630 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPRIMARIES, primaries_id);
2631 gst_ebml_write_master_finish (ebml, master);
2635 * gst_matroska_mux_track_header:
2636 * @mux: #GstMatroskaMux
2637 * @context: Tack context.
2639 * Write a track header.
2642 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2643 GstMatroskaTrackContext * context)
2645 GstEbmlWrite *ebml = mux->ebml_write;
2648 /* TODO: check if everything necessary is written and check default values */
2650 /* track type goes before the type-specific stuff */
2651 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2652 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2654 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, context->uid);
2655 if (context->default_duration) {
2656 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2657 context->default_duration);
2659 if (context->language) {
2660 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2664 /* FIXME: until we have a nice way of getting the codecname
2665 * out of the caps, I'm not going to enable this. Too much
2666 * (useless, double, boring) work... */
2667 /* TODO: Use value from tags if any */
2668 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2669 context->codec_name); */
2670 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2672 /* type-specific stuff */
2673 switch (context->type) {
2674 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2675 GstMatroskaTrackVideoContext *videocontext =
2676 (GstMatroskaTrackVideoContext *) context;
2678 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2679 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2680 videocontext->pixel_width);
2681 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2682 videocontext->pixel_height);
2683 if (videocontext->display_width && videocontext->display_height) {
2684 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2685 videocontext->display_width);
2686 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2687 videocontext->display_height);
2689 switch (videocontext->interlace_mode) {
2690 case GST_MATROSKA_INTERLACE_MODE_INTERLACED:
2691 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2693 case GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE:
2694 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 2);
2700 if (videocontext->fourcc) {
2701 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2703 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2704 (gpointer) & fcc_le, 4);
2706 gst_matroska_mux_write_colour (mux, videocontext);
2707 if (videocontext->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
2708 guint64 stereo_mode = 0;
2710 switch (videocontext->multiview_mode) {
2711 case GST_VIDEO_MULTIVIEW_MODE_MONO:
2713 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
2714 if (videocontext->multiview_flags &
2715 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2716 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_RL;
2718 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_LR;
2720 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
2721 if (videocontext->multiview_flags &
2722 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2723 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_RL;
2725 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_LR;
2727 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
2728 if (videocontext->multiview_flags &
2729 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2730 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_RL;
2732 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_LR;
2734 case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
2735 if (videocontext->multiview_flags &
2736 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2737 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_RL;
2739 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_LR;
2740 /* FIXME: In frame-by-frame mode, left/right frame buffers need to be
2741 * laced within one block. See http://www.matroska.org/technical/specs/index.html#StereoMode */
2742 GST_FIXME_OBJECT (mux,
2743 "Frame-by-frame stereoscopic mode not fully implemented");
2746 GST_WARNING_OBJECT (mux,
2747 "Multiview mode %d not supported in Matroska/WebM",
2748 videocontext->multiview_mode);
2752 if (stereo_mode != 0)
2753 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOSTEREOMODE,
2756 gst_ebml_write_master_finish (ebml, master);
2761 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2762 GstMatroskaTrackAudioContext *audiocontext =
2763 (GstMatroskaTrackAudioContext *) context;
2765 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2766 if (audiocontext->samplerate != 8000)
2767 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2768 audiocontext->samplerate);
2769 if (audiocontext->channels != 1)
2770 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2771 audiocontext->channels);
2772 if (audiocontext->bitdepth) {
2773 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2774 audiocontext->bitdepth);
2777 gst_ebml_write_master_finish (ebml, master);
2782 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
2786 /* doesn't need type-specific data */
2790 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2791 if (context->codec_priv)
2792 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2793 context->codec_priv, context->codec_priv_size);
2795 if (context->seek_preroll) {
2796 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPREROLL,
2797 context->seek_preroll);
2800 if (context->codec_delay) {
2801 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CODECDELAY,
2802 context->codec_delay);
2807 gst_matroska_mux_write_chapter_title (const gchar * title, GstEbmlWrite * ebml)
2809 guint64 title_master;
2812 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERDISPLAY);
2814 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPSTRING, title);
2815 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CHAPLANGUAGE,
2816 GST_MATROSKA_MUX_CHAPLANG);
2818 gst_ebml_write_master_finish (ebml, title_master);
2821 static GstTocEntry *
2822 gst_matroska_mux_write_chapter (GstMatroskaMux * mux, GstTocEntry * edition,
2823 GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters,
2824 guint64 * master_edition)
2826 guint64 master_chapteratom;
2833 GstTocEntry *internal_chapter, *internal_nested;
2836 if (G_UNLIKELY (master_chapters != NULL && *master_chapters == 0))
2838 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERS);
2840 if (G_UNLIKELY (master_edition != NULL && *master_edition == 0)) {
2841 /* create uid for the parent */
2843 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_EDITIONENTRY);
2845 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONUID,
2846 g_ascii_strtoull (gst_toc_entry_get_uid (edition), NULL, 10));
2847 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGHIDDEN, 0);
2848 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGDEFAULT, 0);
2849 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGORDERED, 0);
2852 gst_toc_entry_get_start_stop_times (entry, &start, &stop);
2853 tags = gst_toc_entry_get_tags (entry);
2855 tags = gst_tag_list_copy (tags);
2858 /* build internal chapter */
2859 uid = gst_matroska_mux_create_uid (mux);
2860 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT, uid);
2861 internal_chapter = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, s_uid);
2863 /* Write the chapter entry */
2864 master_chapteratom =
2865 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERATOM);
2867 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERUID, uid);
2868 /* Store the user provided UID in the ChapterStringUID */
2869 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPTERSTRINGUID,
2870 gst_toc_entry_get_uid (entry));
2871 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTART, start);
2872 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTOP, stop);
2873 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGHIDDEN, 0);
2874 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGENABLED, 1);
2876 /* write current ChapterDisplays before the nested chapters */
2877 if (G_LIKELY (tags != NULL)) {
2878 count = gst_tag_list_get_tag_size (tags, GST_TAG_TITLE);
2880 for (i = 0; i < count; ++i) {
2881 gst_tag_list_get_string_index (tags, GST_TAG_TITLE, i, &title);
2882 /* FIXME: handle ChapterLanguage entries */
2883 gst_matroska_mux_write_chapter_title (title, ebml);
2887 /* remove title tag */
2888 if (G_LIKELY (count > 0))
2889 gst_tag_list_remove_tag (tags, GST_TAG_TITLE);
2891 gst_toc_entry_set_tags (internal_chapter, tags);
2894 /* Write nested chapters */
2895 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
2897 internal_nested = gst_matroska_mux_write_chapter (mux, NULL, cur->data,
2900 gst_toc_entry_append_sub_entry (internal_chapter, internal_nested);
2903 gst_ebml_write_master_finish (ebml, master_chapteratom);
2905 return internal_chapter;
2908 static GstTocEntry *
2909 gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
2910 GstTocEntry * edition, GList * chapters, GstEbmlWrite * ebml,
2911 guint64 * master_chapters)
2913 guint64 master_edition = 0;
2916 GstTocEntry *internal_edition, *internal_chapter;
2917 GstTagList *tags = NULL;
2919 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT,
2920 gst_matroska_mux_create_uid (mux));
2922 if (edition != NULL) {
2923 /* Edition entry defined, get its tags */
2924 tags = gst_toc_entry_get_tags (edition);
2926 tags = gst_tag_list_copy (tags);
2930 internal_edition = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, s_uid);
2932 gst_toc_entry_set_tags (internal_edition, tags);
2935 for (cur = g_list_first (chapters); cur != NULL; cur = cur->next) {
2936 internal_chapter = gst_matroska_mux_write_chapter (mux, internal_edition,
2937 cur->data, ebml, master_chapters, &master_edition);
2939 gst_toc_entry_append_sub_entry (internal_edition, internal_chapter);
2942 if (G_LIKELY (master_edition != 0))
2943 gst_ebml_write_master_finish (ebml, master_edition);
2945 return internal_edition;
2949 * gst_matroska_mux_start:
2950 * @mux: #GstMatroskaMux
2952 * Start a new matroska file (write headers etc...)
2955 gst_matroska_mux_start (GstMatroskaMux * mux, GstMatroskaPad * first_pad,
2956 GstBuffer * first_pad_buf)
2958 GstEbmlWrite *ebml = mux->ebml_write;
2959 const gchar *doctype;
2960 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
2961 GST_MATROSKA_ID_TRACKS,
2962 GST_MATROSKA_ID_CHAPTERS,
2963 GST_MATROSKA_ID_CUES,
2964 GST_MATROSKA_ID_TAGS,
2967 const gchar *media_type;
2968 gboolean audio_only;
2969 guint64 master, child;
2973 GstClockTime duration = 0;
2974 guint32 segment_uid[4];
2975 GTimeVal time = { 0, 0 };
2979 /* if not streaming, check if downstream is seekable */
2980 if (!mux->ebml_write->streamable) {
2984 query = gst_query_new_seeking (GST_FORMAT_BYTES);
2985 if (gst_pad_peer_query (mux->srcpad, query)) {
2986 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
2987 GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
2989 /* assume seeking is not supported if query not handled downstream */
2990 GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
2994 mux->ebml_write->streamable = TRUE;
2995 g_object_notify (G_OBJECT (mux), "streamable");
2996 GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
2997 "streamable=false. Will ignore that and create streamable output "
3000 gst_query_unref (query);
3003 /* stream-start (FIXME: create id based on input ids) */
3004 g_snprintf (s_id, sizeof (s_id), "matroskamux-%08x", g_random_int ());
3005 gst_pad_push_event (mux->srcpad, gst_event_new_stream_start (s_id));
3008 audio_only = mux->num_v_streams == 0 && mux->num_a_streams > 0;
3010 media_type = (audio_only) ? "audio/webm" : "video/webm";
3012 media_type = (audio_only) ? "audio/x-matroska" : "video/x-matroska";
3014 ebml->caps = gst_caps_new_empty_simple (media_type);
3015 gst_pad_set_caps (mux->srcpad, ebml->caps);
3016 /* we start with a EBML header */
3017 doctype = mux->doctype;
3018 GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
3019 doctype, mux->doctype_version);
3020 gst_ebml_write_header (ebml, doctype, mux->doctype_version);
3022 /* the rest of the header is cached */
3023 gst_ebml_write_set_cache (ebml, 0x1000);
3025 /* start a segment */
3027 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
3028 mux->segment_master = ebml->pos;
3030 if (!mux->ebml_write->streamable) {
3031 /* seekhead (table of contents) - we set the positions later */
3032 mux->seekhead_pos = ebml->pos;
3033 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
3034 for (i = 0; seekhead_id[i] != 0; i++) {
3035 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
3036 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
3037 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
3038 gst_ebml_write_master_finish (ebml, child);
3040 gst_ebml_write_master_finish (ebml, master);
3043 if (mux->ebml_write->streamable) {
3044 const GstTagList *tags;
3045 gboolean has_main_tags;
3048 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3049 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3051 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux)) {
3052 guint64 master_tags, master_tag;
3054 GST_DEBUG_OBJECT (mux, "Writing tags");
3056 mux->tags_pos = ebml->pos;
3057 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3058 if (has_main_tags) {
3059 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3060 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3061 gst_ebml_write_master_finish (ebml, master_tag);
3063 gst_matroska_mux_write_streams_tags (mux);
3064 gst_ebml_write_master_finish (ebml, master_tags);
3069 mux->info_pos = ebml->pos;
3070 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
3072 /* WebM does not support SegmentUID field on SegmentInfo */
3073 if (!mux->is_webm) {
3074 for (i = 0; i < 4; i++) {
3075 segment_uid[i] = g_random_int ();
3077 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
3078 (guint8 *) segment_uid, 16);
3081 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
3082 mux->duration_pos = ebml->pos;
3084 if (!mux->ebml_write->streamable) {
3085 for (collected = mux->collect->data; collected;
3086 collected = g_slist_next (collected)) {
3087 GstMatroskaPad *collect_pad;
3089 gint64 trackduration;
3091 collect_pad = (GstMatroskaPad *) collected->data;
3092 thepad = collect_pad->collect.pad;
3094 /* Query the total length of the track. */
3095 GST_DEBUG_OBJECT (thepad, "querying peer duration");
3096 if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
3097 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
3098 GST_TIME_ARGS (trackduration));
3099 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
3100 duration = (GstClockTime) trackduration;
3104 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3105 gst_guint64_to_gdouble (duration) /
3106 gst_guint64_to_gdouble (mux->time_scale));
3108 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
3109 "GStreamer matroskamux version " PACKAGE_VERSION);
3110 if (mux->writing_app && mux->writing_app[0]) {
3111 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
3113 g_get_current_time (&time);
3114 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
3115 gst_ebml_write_master_finish (ebml, master);
3118 mux->tracks_pos = ebml->pos;
3119 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
3121 for (collected = mux->collect->data; collected;
3122 collected = g_slist_next (collected)) {
3123 GstMatroskaPad *collect_pad;
3126 collect_pad = (GstMatroskaPad *) collected->data;
3128 /* This will cause an error at a later time */
3129 if (collect_pad->track->codec_id == NULL)
3132 /* For audio tracks, use the first buffers duration as the default
3133 * duration if we didn't get any better idea from the caps event already
3135 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO &&
3136 collect_pad->track->default_duration == 0) {
3137 if (collect_pad == first_pad)
3138 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3140 buf = gst_collect_pads_peek (mux->collect, collected->data);
3142 if (buf && GST_BUFFER_DURATION_IS_VALID (buf))
3143 collect_pad->track->default_duration =
3144 GST_BUFFER_DURATION (buf) + collect_pad->track->codec_delay;
3146 gst_buffer_unref (buf);
3149 collect_pad->track->num = tracknum++;
3150 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
3151 gst_matroska_mux_track_header (mux, collect_pad->track);
3152 gst_ebml_write_master_finish (ebml, child);
3153 /* some remaining pad/track setup */
3154 collect_pad->default_duration_scaled =
3155 gst_util_uint64_scale (collect_pad->track->default_duration,
3156 1, mux->time_scale);
3158 gst_ebml_write_master_finish (ebml, master);
3161 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3162 if (toc != NULL && !mux->ebml_write->streamable) {
3163 guint64 master_chapters = 0;
3164 GstTocEntry *internal_edition;
3165 GList *cur, *chapters;
3167 GST_DEBUG ("Writing chapters");
3169 /* There are two UIDs for Chapters:
3170 * - The ChapterUID is a mandatory unsigned integer which internally
3171 * refers to a given chapter. Except for the title & language which use
3172 * dedicated fields, this UID can also be used to add tags to the Chapter.
3173 * The tags come in a separate section of the container.
3174 * - The ChapterStringUID is an optional UTF-8 string which also uniquely
3175 * refers to a chapter but from an external perspective. It can act as a
3176 * "WebVTT cue identifier" which "can be used to reference a specific cue,
3177 * for example from script or CSS".
3179 * The ChapterUID will be generated and checked for unicity, while the
3180 * ChapterStringUID will receive the user defined UID.
3182 * In order to be able to refer to chapters from the tags section,
3183 * we must maintain an internal Toc tree with the generated ChapterUID
3184 * (see gst_matroska_mux_write_toc_entry_tags) */
3186 /* Check whether we have editions or chapters at the root level. */
3187 cur = gst_toc_get_entries (toc);
3189 mux->chapters_pos = ebml->pos;
3191 mux->internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
3193 if (gst_toc_entry_get_entry_type (cur->data) ==
3194 GST_TOC_ENTRY_TYPE_EDITION) {
3195 /* Editions at the root level */
3196 for (; cur != NULL; cur = cur->next) {
3197 chapters = gst_toc_entry_get_sub_entries (cur->data);
3198 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3199 cur->data, chapters, ebml, &master_chapters);
3200 gst_toc_append_entry (mux->internal_toc, internal_edition);
3203 /* Chapters at the root level */
3204 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3205 NULL, cur, ebml, &master_chapters);
3206 gst_toc_append_entry (mux->internal_toc, internal_edition);
3209 /* close master element if any edition was written */
3210 if (G_LIKELY (master_chapters != 0))
3211 gst_ebml_write_master_finish (ebml, master_chapters);
3215 /* lastly, flush the cache */
3216 gst_ebml_write_flush_cache (ebml, FALSE, 0);
3219 gst_toc_unref (toc);
3222 /* TODO: more sensible tag mappings */
3225 const gchar *matroska_tagname;
3226 const gchar *gstreamer_tagname;
3228 gst_matroska_tag_conv[] = {
3230 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
3231 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
3232 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
3233 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
3234 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
3235 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
3236 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
3237 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
3238 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
3239 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
3240 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
3241 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
3242 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
3243 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
3244 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
3247 /* Every stagefright implementation on android up to and including 6.0.1 is using
3248 libwebm with bug in matroska parsing, where it will choke on empty tag elements;
3249 so before outputting tags and tag elements we better make sure that there are
3250 actually tags we are going to write */
3252 gst_matroska_mux_tag_list_is_empty (const GstTagList * list)
3255 for (i = 0; i < gst_tag_list_n_tags (list); i++) {
3256 const gchar *tag = gst_tag_list_nth_tag_name (list, i);
3258 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3259 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3260 if (strcmp (tagname_gst, tag) == 0) {
3261 GValue src = { 0, };
3264 if (!gst_tag_list_copy_value (&src, list, tag))
3266 dest = gst_value_serialize (&src);
3268 g_value_unset (&src);
3280 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
3283 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
3285 guint64 simpletag_master;
3287 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3288 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3289 const gchar *tagname_mkv = gst_matroska_tag_conv[i].matroska_tagname;
3291 if (strcmp (tagname_gst, tag) == 0) {
3292 GValue src = { 0, };
3295 if (!gst_tag_list_copy_value (&src, list, tag))
3297 if ((dest = gst_value_serialize (&src))) {
3299 simpletag_master = gst_ebml_write_master_start (ebml,
3300 GST_MATROSKA_ID_SIMPLETAG);
3301 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
3302 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
3303 gst_ebml_write_master_finish (ebml, simpletag_master);
3306 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
3308 g_value_unset (&src);
3315 gst_matroska_mux_write_stream_tags (GstMatroskaMux * mux, GstMatroskaPad * mpad)
3317 guint64 master_tag, master_targets;
3320 ebml = mux->ebml_write;
3322 if (G_UNLIKELY (mpad->tags == NULL
3323 || gst_matroska_mux_tag_list_is_empty (mpad->tags)))
3326 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3327 master_targets = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3329 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETTRACKUID, mpad->track->uid);
3331 gst_ebml_write_master_finish (ebml, master_targets);
3332 gst_tag_list_foreach (mpad->tags, gst_matroska_mux_write_simple_tag, ebml);
3333 gst_ebml_write_master_finish (ebml, master_tag);
3337 gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux)
3341 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3342 GstMatroskaPad *collect_pad;
3344 collect_pad = (GstMatroskaPad *) walk->data;
3346 gst_matroska_mux_write_stream_tags (mux, collect_pad);
3351 gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux)
3355 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3356 GstMatroskaPad *collect_pad;
3358 collect_pad = (GstMatroskaPad *) walk->data;
3359 if (!gst_matroska_mux_tag_list_is_empty (collect_pad->tags))
3366 gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
3367 const GstTocEntry * entry, guint64 * master_tags, gboolean * has_tags)
3369 guint64 master_tag, master_targets;
3372 const GstTagList *tags;
3374 ebml = mux->ebml_write;
3376 tags = gst_toc_entry_get_tags (entry);
3377 if (G_UNLIKELY (tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags))) {
3380 if (*master_tags == 0) {
3381 mux->tags_pos = ebml->pos;
3382 *master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3385 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3387 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3389 if (gst_toc_entry_get_entry_type (entry) == GST_TOC_ENTRY_TYPE_EDITION)
3390 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETEDITIONUID,
3391 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3393 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETCHAPTERUID,
3394 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3396 gst_ebml_write_master_finish (ebml, master_targets);
3397 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3398 gst_ebml_write_master_finish (ebml, master_tag);
3401 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3403 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, master_tags,
3409 * gst_matroska_mux_finish:
3410 * @mux: #GstMatroskaMux
3412 * Finish a new matroska file (write index etc...)
3415 gst_matroska_mux_finish (GstMatroskaMux * mux)
3417 GstEbmlWrite *ebml = mux->ebml_write;
3419 guint64 duration = 0;
3421 const GstTagList *tags, *toc_tags;
3423 gboolean has_main_tags, toc_has_tags = FALSE;
3426 /* finish last cluster */
3428 gst_ebml_write_master_finish (ebml, mux->cluster);
3432 if (mux->index != NULL) {
3434 guint64 master, pointentry_master, trackpos_master;
3436 mux->cues_pos = ebml->pos;
3437 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
3438 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
3440 for (n = 0; n < mux->num_indexes; n++) {
3441 GstMatroskaIndex *idx = &mux->index[n];
3443 pointentry_master = gst_ebml_write_master_start (ebml,
3444 GST_MATROSKA_ID_POINTENTRY);
3445 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
3446 idx->time / mux->time_scale);
3447 trackpos_master = gst_ebml_write_master_start (ebml,
3448 GST_MATROSKA_ID_CUETRACKPOSITIONS);
3449 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
3450 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
3451 idx->pos - mux->segment_master);
3452 gst_ebml_write_master_finish (ebml, trackpos_master);
3453 gst_ebml_write_master_finish (ebml, pointentry_master);
3456 gst_ebml_write_master_finish (ebml, master);
3457 gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
3461 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3462 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3463 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3465 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux) || toc != NULL) {
3466 guint64 master_tags = 0, master_tag;
3468 GST_DEBUG_OBJECT (mux, "Writing tags");
3470 if (has_main_tags) {
3471 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
3472 mux->tags_pos = ebml->pos;
3473 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3474 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3477 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3478 if (mux->internal_toc != NULL) {
3479 toc_tags = gst_toc_get_tags (mux->internal_toc);
3480 toc_has_tags = (toc_tags != NULL);
3481 gst_tag_list_foreach (toc_tags, gst_matroska_mux_write_simple_tag,
3485 gst_ebml_write_master_finish (ebml, master_tag);
3488 if (mux->internal_toc != NULL) {
3489 for (cur = gst_toc_get_entries (mux->internal_toc); cur != NULL;
3491 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, &master_tags,
3496 if (master_tags == 0 && gst_matroska_mux_streams_have_tags (mux)) {
3497 mux->tags_pos = ebml->pos;
3498 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3500 gst_matroska_mux_write_streams_tags (mux);
3502 if (master_tags != 0)
3503 gst_ebml_write_master_finish (ebml, master_tags);
3506 /* update seekhead. We know that:
3507 * - a seekhead contains 5 entries.
3508 * - order of entries is as above.
3509 * - a seekhead has a 4-byte header + 8-byte length
3510 * - each entry is 2-byte master, 2-byte ID pointer,
3511 * 2-byte length pointer, all 8/1-byte length, 4-
3512 * byte ID and 8-byte length pointer, where the
3513 * length pointer starts at 20.
3514 * - all entries are local to the segment (so pos - segment_master).
3515 * - so each entry is at 12 + 20 + num * 28. */
3516 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
3517 mux->info_pos - mux->segment_master);
3518 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
3519 mux->tracks_pos - mux->segment_master);
3520 if (toc != NULL && mux->chapters_pos > 0) {
3521 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
3522 mux->chapters_pos - mux->segment_master);
3525 guint64 my_pos = ebml->pos;
3527 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
3528 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3529 gst_ebml_write_seek (ebml, my_pos);
3531 if (mux->index != NULL) {
3532 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
3533 mux->cues_pos - mux->segment_master);
3536 guint64 my_pos = ebml->pos;
3538 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
3539 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3540 gst_ebml_write_seek (ebml, my_pos);
3543 if (tags != NULL || toc_has_tags) {
3544 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 144,
3545 mux->tags_pos - mux->segment_master);
3548 guint64 my_pos = ebml->pos;
3550 gst_ebml_write_seek (ebml, mux->seekhead_pos + 124);
3551 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3552 gst_ebml_write_seek (ebml, my_pos);
3556 gst_toc_unref (toc);
3560 * - first get the overall duration
3561 * (a released track may have left a duration in here)
3562 * - write some track header data for subtitles
3564 duration = mux->duration;
3566 for (collected = mux->collect->data; collected;
3567 collected = g_slist_next (collected)) {
3568 GstMatroskaPad *collect_pad;
3570 * observed duration, this will never remain GST_CLOCK_TIME_NONE
3571 * since this means buffer without timestamps that is not possibile
3573 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
3575 collect_pad = (GstMatroskaPad *) collected->data;
3577 GST_DEBUG_OBJECT (mux,
3578 "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
3579 " end ts %" GST_TIME_FORMAT, collect_pad,
3580 GST_TIME_ARGS (collect_pad->start_ts),
3581 GST_TIME_ARGS (collect_pad->end_ts));
3583 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
3584 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
3585 collected_duration =
3586 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
3587 GST_DEBUG_OBJECT (collect_pad,
3588 "final track duration: %" GST_TIME_FORMAT,
3589 GST_TIME_ARGS (collected_duration));
3591 GST_WARNING_OBJECT (collect_pad, "unable to get final track duration");
3593 if (GST_CLOCK_TIME_IS_VALID (collected_duration) &&
3594 duration < collected_duration)
3595 duration = collected_duration;
3599 /* seek back (optional, but do anyway) */
3600 gst_ebml_write_seek (ebml, pos);
3602 /* update duration */
3603 if (duration != 0) {
3604 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
3605 GST_TIME_ARGS (duration));
3606 pos = mux->ebml_write->pos;
3607 gst_ebml_write_seek (ebml, mux->duration_pos);
3608 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3609 gst_guint64_to_gdouble (duration) /
3610 gst_guint64_to_gdouble (mux->time_scale));
3611 gst_ebml_write_seek (ebml, pos);
3614 guint64 my_pos = ebml->pos;
3616 gst_ebml_write_seek (ebml, mux->duration_pos);
3617 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
3618 gst_ebml_write_seek (ebml, my_pos);
3620 GST_DEBUG_OBJECT (mux, "finishing segment");
3621 /* finish segment - this also writes element length */
3622 gst_ebml_write_master_finish (ebml, mux->segment_pos);
3626 * gst_matroska_mux_buffer_header:
3627 * @track: Track context.
3628 * @relative_timestamp: relative timestamp of the buffer
3629 * @flags: Buffer flags.
3631 * Create a buffer containing buffer header.
3633 * Returns: New buffer.
3636 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
3637 gint16 relative_timestamp, int flags)
3640 guint8 *data = g_malloc (4);
3642 hdr = gst_buffer_new_wrapped (data, 4);
3643 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
3644 data[0] = track->num | 0x80;
3645 /* time relative to clustertime */
3646 GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
3654 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
3655 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
3656 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
3659 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
3660 GstMatroskaPad * collect_pad, GstBuffer * buf)
3662 GstMatroskaTrackVideoContext *ctx =
3663 (GstMatroskaTrackVideoContext *) collect_pad->track;
3668 guint32 next_parse_offset;
3669 GstBuffer *ret = NULL;
3670 gboolean is_muxing_unit = FALSE;
3672 gst_buffer_map (buf, &map, GST_MAP_READ);
3677 gst_buffer_unmap (buf, &map);
3678 gst_buffer_unref (buf);
3682 /* Check if this buffer contains a picture or end-of-sequence packet */
3683 while (size >= 13) {
3684 if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
3685 gst_buffer_unmap (buf, &map);
3686 gst_buffer_unref (buf);
3690 parse_code = GST_READ_UINT8 (data + 4);
3691 if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
3692 if (ctx->dirac_unit) {
3693 gst_buffer_unref (ctx->dirac_unit);
3694 ctx->dirac_unit = NULL;
3696 } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
3697 parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
3698 is_muxing_unit = TRUE;
3702 next_parse_offset = GST_READ_UINT32_BE (data + 5);
3704 if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
3707 data += next_parse_offset;
3708 size -= next_parse_offset;
3711 if (ctx->dirac_unit)
3712 ctx->dirac_unit = gst_buffer_append (ctx->dirac_unit, gst_buffer_ref (buf));
3714 ctx->dirac_unit = gst_buffer_ref (buf);
3716 gst_buffer_unmap (buf, &map);
3718 if (is_muxing_unit) {
3719 ret = gst_buffer_make_writable (ctx->dirac_unit);
3720 ctx->dirac_unit = NULL;
3721 gst_buffer_copy_into (ret, buf,
3722 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
3723 gst_buffer_unref (buf);
3725 gst_buffer_unref (buf);
3733 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
3737 GValue streamheader = { 0 };
3738 GValue bufval = { 0 };
3739 GstBuffer *streamheader_buffer;
3740 GstEbmlWrite *ebml = mux->ebml_write;
3742 streamheader_buffer = gst_ebml_stop_streamheader (ebml);
3743 caps = gst_caps_copy (mux->ebml_write->caps);
3744 s = gst_caps_get_structure (caps, 0);
3745 g_value_init (&streamheader, GST_TYPE_ARRAY);
3746 g_value_init (&bufval, GST_TYPE_BUFFER);
3747 GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_HEADER);
3748 gst_value_set_buffer (&bufval, streamheader_buffer);
3749 gst_value_array_append_value (&streamheader, &bufval);
3750 g_value_unset (&bufval);
3751 gst_structure_set_value (s, "streamheader", &streamheader);
3752 g_value_unset (&streamheader);
3753 gst_caps_replace (&ebml->caps, caps);
3754 gst_buffer_unref (streamheader_buffer);
3755 gst_pad_set_caps (mux->srcpad, caps);
3756 gst_caps_unref (caps);
3760 * gst_matroska_mux_write_data:
3761 * @mux: #GstMatroskaMux
3762 * @collect_pad: #GstMatroskaPad with the data
3764 * Write collected data (called from gst_matroska_mux_collected).
3766 * Returns: Result of the gst_pad_push issued to write the data.
3768 static GstFlowReturn
3769 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
3772 GstEbmlWrite *ebml = mux->ebml_write;
3775 gboolean write_duration;
3776 gint16 relative_timestamp;
3777 gint64 relative_timestamp64;
3778 guint64 block_duration, duration_diff = 0;
3779 gboolean is_video_keyframe = FALSE;
3780 gboolean is_video_invisible = FALSE;
3781 gboolean is_audio_only = FALSE;
3782 gboolean is_min_duration_reached = FALSE;
3783 gboolean is_max_duration_exceeded = FALSE;
3784 GstMatroskamuxPad *pad;
3786 GstClockTime buffer_timestamp;
3787 GstAudioClippingMeta *cmeta = NULL;
3790 pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
3792 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
3793 if (collect_pad->track->xiph_headers_to_skip > 0) {
3794 --collect_pad->track->xiph_headers_to_skip;
3795 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER)) {
3796 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
3797 gst_buffer_unref (buf);
3802 /* for dirac we have to queue up everything up to a picture unit */
3803 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC)) {
3804 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
3807 } else if (!strcmp (collect_pad->track->codec_id,
3808 GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) {
3809 /* Remove the 'Frame container atom' header' */
3810 buf = gst_buffer_make_writable (buf);
3811 gst_buffer_resize (buf, 8, gst_buffer_get_size (buf) - 8);
3815 gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
3817 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
3818 * this would wreak havoc with time stored in matroska file */
3819 /* TODO: maybe calculate a timestamp by using the previous timestamp
3820 * and default duration */
3821 if (!GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
3822 GST_WARNING_OBJECT (collect_pad->collect.pad,
3823 "Invalid buffer timestamp; dropping buffer");
3824 gst_buffer_unref (buf);
3828 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
3829 && collect_pad->track->codec_delay) {
3830 /* All timestamps should include the codec delay */
3831 if (buffer_timestamp > collect_pad->track->codec_delay) {
3832 buffer_timestamp += collect_pad->track->codec_delay;
3834 buffer_timestamp = 0;
3835 duration_diff = collect_pad->track->codec_delay - buffer_timestamp;
3839 /* set the timestamp for outgoing buffers */
3840 ebml->timestamp = buffer_timestamp;
3842 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
3843 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
3844 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
3845 GST_TIME_ARGS (buffer_timestamp));
3846 is_video_keyframe = TRUE;
3847 } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DECODE_ONLY) &&
3848 (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP8)
3849 || !strcmp (collect_pad->track->codec_id,
3850 GST_MATROSKA_CODEC_ID_VIDEO_VP9))) {
3851 GST_LOG_OBJECT (mux,
3852 "have VP8 video invisible frame, " "ts=%" GST_TIME_FORMAT,
3853 GST_TIME_ARGS (buffer_timestamp));
3854 is_video_invisible = TRUE;
3858 is_audio_only = (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
3859 (mux->num_streams == 1);
3860 is_min_duration_reached = (mux->min_cluster_duration == 0
3861 || (buffer_timestamp > mux->cluster_time
3862 && (buffer_timestamp - mux->cluster_time) >=
3863 mux->min_cluster_duration));
3864 is_max_duration_exceeded = (mux->max_cluster_duration > 0
3865 && buffer_timestamp > mux->cluster_time
3866 && (buffer_timestamp - mux->cluster_time) >=
3867 MIN (G_MAXINT16 * mux->time_scale, mux->max_cluster_duration));
3870 /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
3871 * or when we may be reaching the limit of the relative timestamp */
3872 if (is_max_duration_exceeded || (is_video_keyframe
3873 && is_min_duration_reached) || mux->force_key_unit_event
3874 || (is_audio_only && is_min_duration_reached)) {
3875 if (!mux->ebml_write->streamable)
3876 gst_ebml_write_master_finish (ebml, mux->cluster);
3878 /* Forward the GstForceKeyUnit event after finishing the cluster */
3879 if (mux->force_key_unit_event) {
3880 gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
3881 mux->force_key_unit_event = NULL;
3884 mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
3885 mux->cluster_pos = ebml->pos;
3886 gst_ebml_write_set_cache (ebml, 0x20);
3888 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
3889 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
3890 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
3891 GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
3892 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
3893 gst_ebml_write_flush_cache (ebml, is_video_keyframe
3894 || is_audio_only, buffer_timestamp);
3895 mux->cluster_time = buffer_timestamp;
3896 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
3897 mux->prev_cluster_size);
3902 mux->cluster_pos = ebml->pos;
3903 gst_ebml_write_set_cache (ebml, 0x20);
3904 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
3905 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
3906 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
3907 gst_ebml_write_flush_cache (ebml, TRUE, buffer_timestamp);
3908 mux->cluster_time = buffer_timestamp;
3911 /* We currently write index entries for all video tracks or for the audio
3912 * track in a single-track audio file. This could be improved by keeping the
3913 * index only for the *first* video track. */
3915 /* TODO: index is useful for every track, should contain the number of
3916 * the block in the cluster which contains the timestamp, should also work
3917 * for files with multiple audio tracks.
3919 if (!mux->ebml_write->streamable && (is_video_keyframe || is_audio_only)) {
3922 if (mux->min_index_interval != 0) {
3923 for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
3924 if (mux->index[last_idx].track == collect_pad->track->num)
3929 if (last_idx < 0 || mux->min_index_interval == 0 ||
3930 (GST_CLOCK_DIFF (mux->index[last_idx].time, buffer_timestamp)
3931 >= mux->min_index_interval)) {
3932 GstMatroskaIndex *idx;
3934 if (mux->num_indexes % 32 == 0) {
3935 mux->index = g_renew (GstMatroskaIndex, mux->index,
3936 mux->num_indexes + 32);
3938 idx = &mux->index[mux->num_indexes++];
3940 idx->pos = mux->cluster_pos;
3941 idx->time = buffer_timestamp;
3942 idx->track = collect_pad->track->num;
3946 /* Check if the duration differs from the default duration. */
3947 write_duration = FALSE;
3949 if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
3950 block_duration = GST_BUFFER_DURATION (buf) + duration_diff;
3951 block_duration = gst_util_uint64_scale (block_duration, 1, mux->time_scale);
3953 /* small difference should be ok. */
3954 if (block_duration > collect_pad->default_duration_scaled + 1 ||
3955 block_duration < collect_pad->default_duration_scaled - 1) {
3956 write_duration = TRUE;
3960 /* write the block, for doctype v2 use SimpleBlock if possible
3961 * one slice (*breath*).
3962 * FIXME: Need to do correct lacing! */
3963 relative_timestamp64 = buffer_timestamp - mux->cluster_time;
3964 if (relative_timestamp64 >= 0) {
3965 /* round the timestamp */
3966 relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
3967 relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
3970 /* round the timestamp */
3971 relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
3972 relative_timestamp =
3973 -((gint16) gst_util_uint64_scale (-relative_timestamp64, 1,
3977 if (is_video_invisible)
3980 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
3981 cmeta = gst_buffer_get_audio_clipping_meta (buf);
3982 g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);
3984 /* Start clipping is done via header and CodecDelay */
3985 if (cmeta && !cmeta->end)
3989 if (mux->doctype_version > 1 && !write_duration && !cmeta) {
3990 if (is_video_keyframe)
3994 gst_matroska_mux_create_buffer_header (collect_pad->track,
3995 relative_timestamp, flags);
3996 gst_ebml_write_set_cache (ebml, 0x40);
3997 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
3998 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
3999 gst_ebml_write_buffer (ebml, hdr);
4000 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4001 gst_ebml_write_buffer (ebml, buf);
4003 return gst_ebml_last_write_result (ebml);
4005 gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
4006 /* write and call order slightly unnatural,
4007 * but avoids seek and minizes pushing */
4008 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
4010 gst_matroska_mux_create_buffer_header (collect_pad->track,
4011 relative_timestamp, flags);
4013 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
4015 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4017 /* Start clipping is done via header and CodecDelay */
4020 gst_util_uint64_scale_round (cmeta->end, GST_SECOND, 48000);
4021 gst_ebml_write_sint (ebml, GST_MATROSKA_ID_DISCARDPADDING, end);
4025 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
4026 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4027 gst_ebml_write_buffer (ebml, hdr);
4028 gst_ebml_write_master_finish_full (ebml, blockgroup,
4029 gst_buffer_get_size (buf));
4030 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4031 gst_ebml_write_buffer (ebml, buf);
4033 return gst_ebml_last_write_result (ebml);
4038 * gst_matroska_mux_handle_buffer:
4039 * @pads: #GstCollectPads
4040 * @uuser_data: #GstMatroskaMux
4042 * Collectpads callback.
4044 * Returns: #GstFlowReturn
4046 static GstFlowReturn
4047 gst_matroska_mux_handle_buffer (GstCollectPads * pads, GstCollectData * data,
4048 GstBuffer * buf, gpointer user_data)
4050 GstClockTime buffer_timestamp;
4051 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
4052 GstEbmlWrite *ebml = mux->ebml_write;
4053 GstMatroskaPad *best = (GstMatroskaPad *) data;
4054 GstFlowReturn ret = GST_FLOW_OK;
4055 GST_DEBUG_OBJECT (mux, "Collected pads");
4057 /* start with a header */
4058 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
4059 if (mux->collect->data == NULL) {
4060 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
4061 ("No input streams configured"));
4062 return GST_FLOW_ERROR;
4064 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
4065 gst_ebml_start_streamheader (ebml);
4066 gst_matroska_mux_start (mux, best, buf);
4067 gst_matroska_mux_stop_streamheader (mux);
4068 mux->state = GST_MATROSKA_MUX_STATE_DATA;
4071 /* if there is no best pad, we have reached EOS */
4073 GST_DEBUG_OBJECT (mux, "No best pad. Finishing...");
4074 if (!mux->ebml_write->streamable) {
4075 gst_matroska_mux_finish (mux);
4077 GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
4079 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
4084 if (best->track->codec_id == NULL) {
4085 GST_ERROR_OBJECT (best->collect.pad, "No codec-id for pad");
4086 ret = GST_FLOW_NOT_NEGOTIATED;
4090 /* if we have a best stream, should also have a buffer */
4093 buffer_timestamp = gst_matroska_track_get_buffer_timestamp (best->track, buf);
4095 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
4096 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
4097 GST_TIME_ARGS (buffer_timestamp),
4098 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
4100 /* make note of first and last encountered timestamps, so we can calculate
4101 * the actual duration later when we send an updated header on eos */
4102 if (GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
4103 GstClockTime start_ts = buffer_timestamp;
4104 GstClockTime end_ts = start_ts;
4106 if (GST_BUFFER_DURATION_IS_VALID (buf))
4107 end_ts += GST_BUFFER_DURATION (buf);
4108 else if (best->track->default_duration)
4109 end_ts += best->track->default_duration;
4111 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
4112 best->end_ts = end_ts;
4114 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
4115 start_ts < best->start_ts))
4116 best->start_ts = start_ts;
4119 /* write one buffer */
4120 ret = gst_matroska_mux_write_data (mux, best, buf);
4128 * gst_matroska_mux_change_state:
4129 * @element: #GstMatroskaMux
4130 * @transition: State change transition.
4132 * Change the muxer state.
4134 * Returns: #GstStateChangeReturn
4136 static GstStateChangeReturn
4137 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
4139 GstStateChangeReturn ret;
4140 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
4142 switch (transition) {
4143 case GST_STATE_CHANGE_NULL_TO_READY:
4145 case GST_STATE_CHANGE_READY_TO_PAUSED:
4146 gst_collect_pads_start (mux->collect);
4148 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4150 case GST_STATE_CHANGE_PAUSED_TO_READY:
4151 gst_collect_pads_stop (mux->collect);
4157 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4159 switch (transition) {
4160 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4162 case GST_STATE_CHANGE_PAUSED_TO_READY:
4163 gst_matroska_mux_reset (GST_ELEMENT (mux));
4165 case GST_STATE_CHANGE_READY_TO_NULL:
4175 gst_matroska_mux_set_property (GObject * object,
4176 guint prop_id, const GValue * value, GParamSpec * pspec)
4178 GstMatroskaMux *mux;
4180 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4181 mux = GST_MATROSKA_MUX (object);
4184 case PROP_WRITING_APP:
4185 if (!g_value_get_string (value)) {
4186 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
4189 g_free (mux->writing_app);
4190 mux->writing_app = g_value_dup_string (value);
4192 case PROP_DOCTYPE_VERSION:
4193 mux->doctype_version = g_value_get_int (value);
4195 case PROP_MIN_INDEX_INTERVAL:
4196 mux->min_index_interval = g_value_get_int64 (value);
4198 case PROP_STREAMABLE:
4199 mux->ebml_write->streamable = g_value_get_boolean (value);
4201 case PROP_TIMECODESCALE:
4202 mux->time_scale = g_value_get_int64 (value);
4204 case PROP_MIN_CLUSTER_DURATION:
4205 mux->min_cluster_duration = g_value_get_int64 (value);
4207 case PROP_MAX_CLUSTER_DURATION:
4208 mux->max_cluster_duration = g_value_get_int64 (value);
4211 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4217 gst_matroska_mux_get_property (GObject * object,
4218 guint prop_id, GValue * value, GParamSpec * pspec)
4220 GstMatroskaMux *mux;
4222 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4223 mux = GST_MATROSKA_MUX (object);
4226 case PROP_WRITING_APP:
4227 g_value_set_string (value, mux->writing_app);
4229 case PROP_DOCTYPE_VERSION:
4230 g_value_set_int (value, mux->doctype_version);
4232 case PROP_MIN_INDEX_INTERVAL:
4233 g_value_set_int64 (value, mux->min_index_interval);
4235 case PROP_STREAMABLE:
4236 g_value_set_boolean (value, mux->ebml_write->streamable);
4238 case PROP_TIMECODESCALE:
4239 g_value_set_int64 (value, mux->time_scale);
4241 case PROP_MIN_CLUSTER_DURATION:
4242 g_value_set_int64 (value, mux->min_cluster_duration);
4244 case PROP_MAX_CLUSTER_DURATION:
4245 g_value_set_int64 (value, mux->max_cluster_duration);
4248 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);