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
33 * matroskamux muxes different input streams into a Matroska file.
35 * ## Example launch line
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 "gstmatroskaelements.h"
59 #include "matroska-mux.h"
60 #include "matroska-ids.h"
62 #define GST_MATROSKA_MUX_CHAPLANG "und"
64 GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
65 #define GST_CAT_DEFAULT matroskamux_debug
72 PROP_MIN_INDEX_INTERVAL,
75 PROP_MIN_CLUSTER_DURATION,
76 PROP_MAX_CLUSTER_DURATION,
79 PROP_CLUSTER_TIMESTAMP_OFFSET,
82 #define DEFAULT_DOCTYPE_VERSION 2
83 #define DEFAULT_WRITING_APP "GStreamer Matroska muxer"
84 #define DEFAULT_MIN_INDEX_INTERVAL 0
85 #define DEFAULT_STREAMABLE FALSE
86 #define DEFAULT_TIMECODESCALE GST_MSECOND
87 #define DEFAULT_MIN_CLUSTER_DURATION 500 * GST_MSECOND
88 #define DEFAULT_MAX_CLUSTER_DURATION 65535 * GST_MSECOND
89 #define DEFAULT_OFFSET_TO_ZERO FALSE
90 #define DEFAULT_CLUSTER_TIMESTAMP_OFFSET 0
92 /* WAVEFORMATEX is gst_riff_strf_auds + an extra guint16 extension size */
93 #define WAVEFORMATEX_SIZE (2 + sizeof (gst_riff_strf_auds))
95 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
98 GST_STATIC_CAPS ("video/x-matroska; video/x-matroska-3d; audio/x-matroska")
101 #define COMMON_VIDEO_CAPS \
102 "width = (int) [ 1, MAX ], " \
103 "height = (int) [ 1, MAX ] "
106 * * require codec data, etc as needed
109 static GstStaticPadTemplate videosink_templ =
110 GST_STATIC_PAD_TEMPLATE ("video_%u",
113 GST_STATIC_CAPS ("video/mpeg, "
114 "mpegversion = (int) { 1, 2, 4 }, "
115 "systemstream = (boolean) false, "
116 COMMON_VIDEO_CAPS "; "
117 "video/x-h264, stream-format = (string) { avc, avc3 }, alignment=au, "
118 COMMON_VIDEO_CAPS "; "
119 "video/x-h265, stream-format = (string) { hvc1, hev1 }, alignment=au, "
120 COMMON_VIDEO_CAPS "; "
122 COMMON_VIDEO_CAPS "; "
124 COMMON_VIDEO_CAPS "; "
126 COMMON_VIDEO_CAPS "; "
128 COMMON_VIDEO_CAPS "; "
130 COMMON_VIDEO_CAPS "; "
132 COMMON_VIDEO_CAPS "; "
135 COMMON_VIDEO_CAPS "; "
136 "video/x-pn-realvideo, "
137 "rmversion = (int) [1, 4], "
138 COMMON_VIDEO_CAPS "; "
140 COMMON_VIDEO_CAPS "; "
142 COMMON_VIDEO_CAPS "; "
144 "format = (string) { YUY2, I420, YV12, UYVY, AYUV, GRAY8, BGR, RGB }, "
145 COMMON_VIDEO_CAPS "; "
147 COMMON_VIDEO_CAPS "; "
148 "video/x-wmv, " "wmvversion = (int) [ 1, 3 ], " COMMON_VIDEO_CAPS "; "
149 "video/x-av1, " COMMON_VIDEO_CAPS ";"
150 "video/x-ffv, ffversion = (int) 1, " COMMON_VIDEO_CAPS)
153 #define COMMON_AUDIO_CAPS \
154 "channels = (int) [ 1, MAX ], " \
155 "rate = (int) [ 1, MAX ]"
158 * * require codec data, etc as needed
160 static GstStaticPadTemplate audiosink_templ =
161 GST_STATIC_PAD_TEMPLATE ("audio_%u",
164 GST_STATIC_CAPS ("audio/mpeg, "
165 "mpegversion = (int) 1, "
166 "layer = (int) [ 1, 3 ], "
167 COMMON_AUDIO_CAPS "; "
169 "mpegversion = (int) { 2, 4 }, "
170 "stream-format = (string) raw, "
171 COMMON_AUDIO_CAPS "; "
173 COMMON_AUDIO_CAPS "; "
175 COMMON_AUDIO_CAPS "; "
177 COMMON_AUDIO_CAPS "; "
179 COMMON_AUDIO_CAPS "; "
181 COMMON_AUDIO_CAPS "; "
184 COMMON_AUDIO_CAPS "; "
186 "format = (string) { U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }, "
187 "layout = (string) interleaved, "
188 COMMON_AUDIO_CAPS ";"
190 "width = (int) { 8, 16, 24 }, "
191 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
192 "audio/x-pn-realaudio, "
193 "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS "; "
194 "audio/x-wma, " "wmaversion = (int) [ 1, 3 ], "
195 "block_align = (int) [ 0, 65535 ], bitrate = (int) [ 0, 524288 ], "
196 COMMON_AUDIO_CAPS ";"
198 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
200 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
202 "layout = (string)dvi, "
203 "block_align = (int)[64, 8192], "
204 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
206 "channels = (int)1," "rate = (int)16000; "
208 "layout = (string)g726, " "channels = (int)1," "rate = (int)8000; ")
211 static GstStaticPadTemplate subtitlesink_templ =
212 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
215 GST_STATIC_CAPS ("subtitle/x-kate; "
216 "text/x-raw, format=utf8; application/x-ssa; application/x-ass; "
217 "application/x-usf; subpicture/x-dvd; "
218 "application/x-subtitle-unknown")
221 static gpointer parent_class; /* NULL */
223 /* Matroska muxer destructor */
224 static void gst_matroska_mux_class_init (GstMatroskaMuxClass * klass);
225 static void gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class);
226 static void gst_matroska_mux_finalize (GObject * object);
228 /* Pads collected callback */
229 static GstFlowReturn gst_matroska_mux_handle_buffer (GstCollectPads * pads,
230 GstCollectData * data, GstBuffer * buf, gpointer user_data);
231 static gboolean gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
232 GstCollectData * data, GstEvent * event, gpointer user_data);
235 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
236 GstObject * parent, GstEvent * event);
237 static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
238 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
239 static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
241 /* gst internal change state handler */
242 static GstStateChangeReturn
243 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
245 /* gobject bla bla */
246 static void gst_matroska_mux_set_property (GObject * object,
247 guint prop_id, const GValue * value, GParamSpec * pspec);
248 static void gst_matroska_mux_get_property (GObject * object,
249 guint prop_id, GValue * value, GParamSpec * pspec);
252 static void gst_matroska_mux_reset (GstElement * element);
255 static guint64 gst_matroska_mux_create_uid (GstMatroskaMux * mux);
257 static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
258 GstMatroskaTrackContext * context);
259 static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
260 GstMatroskaTrackContext * context);
261 static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
262 GstMatroskaTrackContext * context);
263 static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
264 GstMatroskaTrackContext * context);
265 static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
266 GstMatroskaTrackContext * context);
268 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
270 static gboolean gst_matroska_mux_tag_list_is_empty (const GstTagList * list);
271 static void gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux);
272 static gboolean gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux);
274 /* Cannot use boilerplate macros here because we need the full init function
275 * signature with the additional class argument, so we use the right template
276 * for the sink caps */
278 gst_matroska_mux_get_type (void)
280 static GType object_type; /* 0 */
282 if (object_type == 0) {
283 static const GTypeInfo object_info = {
284 sizeof (GstMatroskaMuxClass),
285 NULL, /* base_init */
286 NULL, /* base_finalize */
287 (GClassInitFunc) gst_matroska_mux_class_init,
288 NULL, /* class_finalize */
289 NULL, /* class_data */
290 sizeof (GstMatroskaMux),
292 (GInstanceInitFunc) gst_matroska_mux_init
294 const GInterfaceInfo iface_info = { NULL };
296 object_type = g_type_register_static (GST_TYPE_ELEMENT,
297 "GstMatroskaMux", &object_info, (GTypeFlags) 0);
299 g_type_add_interface_static (object_type, GST_TYPE_TAG_SETTER, &iface_info);
300 g_type_add_interface_static (object_type, GST_TYPE_TOC_SETTER, &iface_info);
306 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (matroskamux, "matroskamux",
307 GST_RANK_PRIMARY, GST_TYPE_MATROSKA_MUX, matroska_element_init (plugin));
310 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
312 GObjectClass *gobject_class;
313 GstElementClass *gstelement_class;
315 gobject_class = (GObjectClass *) klass;
316 gstelement_class = (GstElementClass *) klass;
318 gst_element_class_add_static_pad_template (gstelement_class,
320 gst_element_class_add_static_pad_template (gstelement_class,
322 gst_element_class_add_static_pad_template (gstelement_class,
323 &subtitlesink_templ);
324 gst_element_class_add_static_pad_template (gstelement_class, &src_templ);
325 gst_element_class_set_static_metadata (gstelement_class, "Matroska muxer",
327 "Muxes video/audio/subtitle streams into a matroska stream",
328 "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
330 GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
333 gobject_class->finalize = gst_matroska_mux_finalize;
335 gobject_class->get_property = gst_matroska_mux_get_property;
336 gobject_class->set_property = gst_matroska_mux_set_property;
338 g_object_class_install_property (gobject_class, PROP_WRITING_APP,
339 g_param_spec_string ("writing-app", "Writing application.",
340 "The name the application that creates the matroska file.",
341 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
342 g_object_class_install_property (gobject_class, PROP_DOCTYPE_VERSION,
343 g_param_spec_int ("version", "DocType version",
344 "This parameter determines what Matroska features can be used.",
345 1, 2, DEFAULT_DOCTYPE_VERSION,
346 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
347 g_object_class_install_property (gobject_class, PROP_MIN_INDEX_INTERVAL,
348 g_param_spec_int64 ("min-index-interval", "Minimum time between index "
349 "entries", "An index entry is created every so many nanoseconds.",
350 0, G_MAXINT64, DEFAULT_MIN_INDEX_INTERVAL,
351 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
352 g_object_class_install_property (gobject_class, PROP_STREAMABLE,
353 g_param_spec_boolean ("streamable", "Determines whether output should "
354 "be streamable", "If set to true, the output should be as if it is "
355 "to be streamed and hence no indexes written or duration written.",
356 DEFAULT_STREAMABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
357 g_object_class_install_property (gobject_class, PROP_TIMECODESCALE,
358 g_param_spec_int64 ("timecodescale", "Timecode Scale",
359 "TimecodeScale used to calculate the Raw Timecode of a Block", 1,
360 GST_SECOND, DEFAULT_TIMECODESCALE,
361 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
362 g_object_class_install_property (gobject_class, PROP_MIN_CLUSTER_DURATION,
363 g_param_spec_int64 ("min-cluster-duration", "Minimum cluster duration",
364 "Desired cluster duration as nanoseconds. A new cluster will be "
365 "created irrespective of this property if a force key unit event "
366 "is received. 0 means create a new cluster for each video keyframe "
367 "or for each audio buffer in audio only streams.", 0,
368 G_MAXINT64, DEFAULT_MIN_CLUSTER_DURATION,
369 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
370 g_object_class_install_property (gobject_class, PROP_MAX_CLUSTER_DURATION,
371 g_param_spec_int64 ("max-cluster-duration", "Maximum cluster duration",
372 "A new cluster will be created if its duration exceeds this value. "
373 "0 means no maximum duration.", 0,
374 G_MAXINT64, DEFAULT_MAX_CLUSTER_DURATION,
375 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
376 g_object_class_install_property (gobject_class, PROP_OFFSET_TO_ZERO,
377 g_param_spec_boolean ("offset-to-zero", "Offset To Zero",
378 "Offsets all streams so that the " "earliest stream starts at 0.",
379 DEFAULT_OFFSET_TO_ZERO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
380 g_object_class_install_property (gobject_class, PROP_CREATION_TIME,
381 g_param_spec_boxed ("creation-time", "Creation Time",
382 "Date and time of creation. This will be used for the DateUTC field."
383 " NULL means that the current time will be used.",
384 G_TYPE_DATE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
387 * GstMatroskaMux:cluster-timestamp-offset:
389 * An offset to add to all clusters/blocks (in nanoseconds)
393 g_object_class_install_property (gobject_class, PROP_CLUSTER_TIMESTAMP_OFFSET,
394 g_param_spec_uint64 ("cluster-timestamp-offset",
395 "Cluster timestamp offset",
396 "An offset to add to all clusters/blocks (in nanoseconds)", 0,
397 G_MAXUINT64, DEFAULT_CLUSTER_TIMESTAMP_OFFSET,
398 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
400 gstelement_class->change_state =
401 GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
402 gstelement_class->request_new_pad =
403 GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
404 gstelement_class->release_pad =
405 GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
407 parent_class = g_type_class_peek_parent (klass);
411 * Start of pad option handler code
413 #define DEFAULT_PAD_FRAME_DURATION TRUE
418 PROP_PAD_FRAME_DURATION
424 gboolean frame_duration;
425 gboolean frame_duration_user;
428 typedef GstPadClass GstMatroskamuxPadClass;
430 GType gst_matroskamux_pad_get_type (void);
431 G_DEFINE_TYPE (GstMatroskamuxPad, gst_matroskamux_pad, GST_TYPE_PAD);
433 #define GST_TYPE_MATROSKAMUX_PAD (gst_matroskamux_pad_get_type())
434 #define GST_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_MATROSKAMUX_PAD,GstMatroskamuxPad))
435 #define GST_MATROSKAMUX_PAD_CAST(pad) ((GstMatroskamuxPad *) pad)
436 #define GST_IS_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_MATROSKAMUX_PAD))
439 gst_matroskamux_pad_get_property (GObject * object, guint prop_id,
440 GValue * value, GParamSpec * pspec)
442 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
445 case PROP_PAD_FRAME_DURATION:
446 g_value_set_boolean (value, pad->frame_duration);
449 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
455 gst_matroskamux_pad_set_property (GObject * object, guint prop_id,
456 const GValue * value, GParamSpec * pspec)
458 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
461 case PROP_PAD_FRAME_DURATION:
462 pad->frame_duration = g_value_get_boolean (value);
463 pad->frame_duration_user = TRUE;
466 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
472 gst_matroskamux_pad_class_init (GstMatroskamuxPadClass * klass)
474 GObjectClass *gobject_class = (GObjectClass *) klass;
476 gobject_class->set_property = gst_matroskamux_pad_set_property;
477 gobject_class->get_property = gst_matroskamux_pad_get_property;
479 g_object_class_install_property (gobject_class, PROP_PAD_FRAME_DURATION,
480 g_param_spec_boolean ("frame-duration", "Frame duration",
481 "Default frame duration", DEFAULT_PAD_FRAME_DURATION,
482 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
486 gst_matroskamux_pad_init (GstMatroskamuxPad * pad)
488 pad->frame_duration = DEFAULT_PAD_FRAME_DURATION;
489 pad->frame_duration_user = FALSE;
493 * End of pad option handler code
497 gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class)
499 GstPadTemplate *templ;
502 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
503 mux->srcpad = gst_pad_new_from_template (templ, "src");
505 gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
506 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
507 gst_pad_use_fixed_caps (mux->srcpad);
509 mux->collect = gst_collect_pads_new ();
510 gst_collect_pads_set_clip_function (mux->collect,
511 GST_DEBUG_FUNCPTR (gst_collect_pads_clip_running_time), mux);
512 gst_collect_pads_set_buffer_function (mux->collect,
513 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_buffer), mux);
514 gst_collect_pads_set_event_function (mux->collect,
515 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event), mux);
517 mux->ebml_write = gst_ebml_write_new (mux->srcpad);
518 mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
520 /* property defaults */
521 mux->doctype_version = DEFAULT_DOCTYPE_VERSION;
522 mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
523 mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
524 mux->ebml_write->streamable = DEFAULT_STREAMABLE;
525 mux->time_scale = DEFAULT_TIMECODESCALE;
526 mux->min_cluster_duration = DEFAULT_MIN_CLUSTER_DURATION;
527 mux->max_cluster_duration = DEFAULT_MAX_CLUSTER_DURATION;
528 mux->cluster_timestamp_offset = DEFAULT_CLUSTER_TIMESTAMP_OFFSET;
530 /* initialize internal variables */
532 mux->num_streams = 0;
533 mux->num_a_streams = 0;
534 mux->num_t_streams = 0;
535 mux->num_v_streams = 0;
536 mux->internal_toc = NULL;
538 /* initialize remaining variables */
539 gst_matroska_mux_reset (GST_ELEMENT (mux));
544 * gst_matroska_mux_finalize:
545 * @object: #GstMatroskaMux that should be finalized.
547 * Finalize matroska muxer.
550 gst_matroska_mux_finalize (GObject * object)
552 GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
554 gst_event_replace (&mux->force_key_unit_event, NULL);
556 gst_object_unref (mux->collect);
557 gst_object_unref (mux->ebml_write);
558 g_free (mux->writing_app);
559 g_clear_pointer (&mux->creation_time, g_date_time_unref);
561 if (mux->internal_toc) {
562 gst_toc_unref (mux->internal_toc);
563 mux->internal_toc = NULL;
566 G_OBJECT_CLASS (parent_class)->finalize (object);
571 * gst_matroska_mux_create_uid:
572 * @mux: #GstMatroskaMux to generate UID for.
574 * Generate new track UID.
576 * Returns: New track UID.
579 gst_matroska_mux_create_uid (GstMatroskaMux * mux)
581 return (((guint64) g_random_int ()) << 32) | g_random_int ();
586 * gst_matroska_pad_reset:
587 * @collect_pad: the #GstMatroskaPad
589 * Reset and/or release resources of a matroska collect pad.
592 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
595 GstMatroskaTrackType type = 0;
597 /* free track information */
598 if (collect_pad->track != NULL) {
599 /* retrieve for optional later use */
600 name = collect_pad->track->name;
601 type = collect_pad->track->type;
602 /* extra for video */
603 if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
604 GstMatroskaTrackVideoContext *ctx =
605 (GstMatroskaTrackVideoContext *) collect_pad->track;
607 if (ctx->dirac_unit) {
608 gst_buffer_unref (ctx->dirac_unit);
609 ctx->dirac_unit = NULL;
612 g_free (collect_pad->track->codec_id);
613 g_free (collect_pad->track->codec_name);
615 g_free (collect_pad->track->name);
616 g_free (collect_pad->track->language);
617 g_free (collect_pad->track->codec_priv);
618 g_free (collect_pad->track);
619 collect_pad->track = NULL;
620 if (collect_pad->tags) {
621 gst_tag_list_unref (collect_pad->tags);
622 collect_pad->tags = NULL;
626 if (!full && type != 0) {
627 GstMatroskaTrackContext *context;
629 /* create a fresh context */
631 case GST_MATROSKA_TRACK_TYPE_VIDEO:
632 context = (GstMatroskaTrackContext *)
633 g_new0 (GstMatroskaTrackVideoContext, 1);
635 case GST_MATROSKA_TRACK_TYPE_AUDIO:
636 context = (GstMatroskaTrackContext *)
637 g_new0 (GstMatroskaTrackAudioContext, 1);
639 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
640 context = (GstMatroskaTrackContext *)
641 g_new0 (GstMatroskaTrackSubtitleContext, 1);
644 g_assert_not_reached ();
648 context->type = type;
649 context->name = name;
650 context->uid = gst_matroska_mux_create_uid (collect_pad->mux);
651 /* TODO: check default values for the context */
652 context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
653 collect_pad->track = context;
654 collect_pad->start_ts = GST_CLOCK_TIME_NONE;
655 collect_pad->end_ts = GST_CLOCK_TIME_NONE;
656 collect_pad->tags = gst_tag_list_new_empty ();
657 gst_tag_list_set_scope (collect_pad->tags, GST_TAG_SCOPE_STREAM);
662 * gst_matroska_pad_free:
663 * @collect_pad: the #GstMatroskaPad
665 * Release resources of a matroska collect pad.
668 gst_matroska_pad_free (GstPad * collect_pad)
670 gst_matroska_pad_reset ((GstMatroskaPad *) collect_pad, TRUE);
675 * gst_matroska_mux_reset:
676 * @element: #GstMatroskaMux that should be reset.
678 * Reset matroska muxer back to initial state.
681 gst_matroska_mux_reset (GstElement * element)
683 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
686 /* reset EBML write */
687 gst_ebml_write_reset (mux->ebml_write);
690 mux->state = GST_MATROSKA_MUX_STATE_START;
692 /* clean up existing streams */
694 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
695 GstMatroskaPad *collect_pad;
697 collect_pad = (GstMatroskaPad *) walk->data;
699 /* reset collect pad to pristine state */
700 gst_matroska_pad_reset (collect_pad, FALSE);
704 mux->num_indexes = 0;
713 mux->cluster_time = 0;
714 mux->cluster_pos = 0;
715 mux->prev_cluster_size = 0;
718 gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
723 gst_toc_setter_reset (GST_TOC_SETTER (mux));
724 if (mux->internal_toc) {
725 gst_toc_unref (mux->internal_toc);
726 mux->internal_toc = NULL;
729 mux->chapters_pos = 0;
733 * gst_matroska_mux_handle_src_event:
734 * @pad: Pad which received the event.
735 * @event: Received event.
737 * handle events - copied from oggmux without understanding
739 * Returns: %TRUE on success.
742 gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
747 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
751 /* disable seeking for now */
757 return gst_pad_event_default (pad, parent, event);
762 gst_matroska_mux_free_codec_priv (GstMatroskaTrackContext * context)
764 if (context->codec_priv != NULL) {
765 g_free (context->codec_priv);
766 context->codec_priv = NULL;
767 context->codec_priv_size = 0;
772 gst_matroska_mux_build_vobsub_private (GstMatroskaTrackContext * context,
782 /* produce comma-separated list in hex format */
783 for (i = 0; i < 16; ++i) {
785 /* replicate vobsub's slightly off RGB conversion calculation */
786 y = (((col >> 16) & 0xff) - 16) * 255 / 219;
787 u = ((col >> 8) & 0xff) - 128;
788 v = (col & 0xff) - 128;
789 r = CLAMP (1.0 * y + 1.4022 * u, 0, 255);
790 g = CLAMP (1.0 * y - 0.3456 * u - 0.7145 * v, 0, 255);
791 b = CLAMP (1.0 * y + 1.7710 * v, 0, 255);
792 clutv[i] = g_strdup_printf ("%02x%02x%02x", r, g, b);
795 sclut = g_strjoinv (",", clutv);
797 /* build codec private; only palette for now */
798 gst_matroska_mux_free_codec_priv (context);
799 context->codec_priv = (guint8 *) g_strdup_printf ("palette: %s", sclut);
800 /* include terminating 0 */
801 context->codec_priv_size = strlen ((gchar *) context->codec_priv) + 1;
803 for (i = 0; i < 16; ++i) {
810 * gst_matroska_mux_handle_sink_event:
811 * @pad: Pad which received the event.
812 * @event: Received event.
814 * handle events - informational ones like tags
816 * Returns: %TRUE on success.
819 gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
820 GstCollectData * data, GstEvent * event, gpointer user_data)
822 GstMatroskaPad *collect_pad;
823 GstMatroskaTrackContext *context;
829 mux = GST_MATROSKA_MUX (user_data);
830 collect_pad = (GstMatroskaPad *) data;
832 context = collect_pad->track;
835 switch (GST_EVENT_TYPE (event)) {
836 case GST_EVENT_CAPS:{
839 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
840 gst_event_parse_caps (event, &caps);
842 ret = collect_pad->capsfunc (pad, caps);
843 gst_event_unref (event);
850 GST_DEBUG_OBJECT (mux, "received tag event");
851 gst_event_parse_tag (event, &list);
853 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
854 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
855 const gchar *lang_code;
857 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
859 GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
860 g_free (context->language);
861 context->language = g_strdup (lang_code);
863 GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
868 if (gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL) {
869 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
870 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
874 /* Stream specific tags */
875 gst_tag_list_insert (collect_pad->tags, list, GST_TAG_MERGE_REPLACE);
877 /* If the tags contain a title, update the context name to write it there */
878 if (gst_tag_list_get_string (list, GST_TAG_TITLE, &title)) {
879 GST_INFO_OBJECT (pad, "Setting track name to '%s'", title);
880 g_free (context->name);
881 context->name = g_strdup (title);
886 gst_event_unref (event);
887 /* handled this, don't want collectpads to forward it downstream */
893 GstToc *toc, *old_toc;
895 if (mux->chapters_pos > 0)
898 GST_DEBUG_OBJECT (mux, "received toc event");
899 gst_event_parse_toc (event, &toc, NULL);
902 old_toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
903 if (old_toc != NULL) {
905 GST_INFO_OBJECT (pad, "Replacing TOC with a new one");
906 gst_toc_unref (old_toc);
909 gst_toc_setter_set_toc (GST_TOC_SETTER (mux), toc);
913 gst_event_unref (event);
914 /* handled this, don't want collectpads to forward it downstream */
918 case GST_EVENT_CUSTOM_DOWNSTREAM:
919 case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY:{
920 const GstStructure *structure;
922 structure = gst_event_get_structure (event);
923 if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
924 gst_event_replace (&mux->force_key_unit_event, NULL);
925 mux->force_key_unit_event = event;
927 } else if (gst_structure_has_name (structure, "application/x-gst-dvd") &&
928 !strcmp ("dvd-spu-clut-change",
929 gst_structure_get_string (structure, "event"))) {
934 GST_DEBUG_OBJECT (pad, "New DVD colour table received");
935 if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
936 GST_DEBUG_OBJECT (pad, "... discarding");
939 /* first transform event data into table form */
940 for (i = 0; i < 16; i++) {
941 g_snprintf (name, sizeof (name), "clut%02d", i);
942 if (!gst_structure_get_int (structure, name, &value)) {
943 GST_ERROR_OBJECT (mux, "dvd-spu-clut-change event did not "
944 "contain %s field", name);
950 /* transform into private data for stream; text form */
951 gst_matroska_mux_build_vobsub_private (context, clut);
961 return gst_collect_pads_event_default (pads, data, event, FALSE);
967 gst_matroska_mux_set_codec_id (GstMatroskaTrackContext * context,
970 g_assert (context && id);
971 g_free (context->codec_id);
972 context->codec_id = g_strdup (id);
976 check_field (GQuark field_id, const GValue * value, gpointer user_data)
978 GstStructure *structure = (GstStructure *) user_data;
979 const gchar *name = gst_structure_get_name (structure);
981 if ((g_strcmp0 (name, "video/x-h264") == 0 &&
982 !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
983 "avc3")) || (g_strcmp0 (name, "video/x-h265") == 0
984 && !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
987 /* While in theory, matroska only supports avc1 / hvc1, and doesn't support codec_data
988 * changes, in practice most decoders will use in-band SPS / PPS (avc3 / hev1), if the
989 * input stream is avc3 / hev1 we let the new codec_data slide to support "smart" encoding.
991 * We don't warn here as we already warned elsewhere.
993 if (field_id == g_quark_from_static_string ("codec_data")) {
995 } else if (field_id == g_quark_from_static_string ("tier")) {
997 } else if (field_id == g_quark_from_static_string ("profile")) {
999 } else if (field_id == g_quark_from_static_string ("level")) {
1001 } else if (field_id == g_quark_from_static_string ("width")) {
1003 } else if (field_id == g_quark_from_static_string ("height")) {
1006 } else if (gst_structure_has_name (structure, "video/x-vp8")
1007 || gst_structure_has_name (structure, "video/x-vp9")) {
1008 /* We do not use profile and streamheader for VPX so let it change
1010 if (field_id == g_quark_from_static_string ("streamheader"))
1012 else if (field_id == g_quark_from_static_string ("profile"))
1016 /* This fields aren't used and are not retained into the bitstream so we can
1018 if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) {
1019 if (field_id == g_quark_from_static_string ("chroma-site"))
1021 else if (field_id == g_quark_from_static_string ("chroma-format"))
1023 else if (field_id == g_quark_from_static_string ("bit-depth-luma"))
1026 /* Remove pixel-aspect-ratio field if it contains 1/1 as that's considered
1027 * equivalent to not having the field but are not considered equivalent
1028 * by the generic caps functions
1030 if (field_id == g_quark_from_static_string ("pixel-aspect-ratio")) {
1031 gint par_n = gst_value_get_fraction_numerator (value);
1032 gint par_d = gst_value_get_fraction_denominator (value);
1034 if (par_n == 1 && par_d == 1)
1038 /* Remove multiview-mode=mono and multiview-flags=0 fields as those are
1039 * equivalent with not having the fields but are not considered equivalent
1040 * by the generic caps functions.
1042 if (field_id == g_quark_from_static_string ("multiview-mode")) {
1043 const gchar *s = g_value_get_string (value);
1045 if (g_strcmp0 (s, "mono") == 0)
1049 if (field_id == g_quark_from_static_string ("multiview-flags")) {
1050 guint multiview_flags = gst_value_get_flagset_flags (value);
1052 if (multiview_flags == 0)
1061 check_new_caps (GstMatroskaTrackVideoContext * videocontext, GstCaps * old_caps,
1064 GstStructure *old_s, *new_s;
1067 old_caps = gst_caps_copy (old_caps);
1068 new_caps = gst_caps_copy (new_caps);
1070 new_s = gst_caps_get_structure (new_caps, 0);
1071 old_s = gst_caps_get_structure (old_caps, 0);
1073 gst_structure_filter_and_map_in_place (new_s,
1074 (GstStructureFilterMapFunc) check_field, new_s);
1075 gst_structure_filter_and_map_in_place (old_s,
1076 (GstStructureFilterMapFunc) check_field, old_s);
1078 ret = gst_caps_is_subset (new_caps, old_caps);
1080 gst_caps_unref (new_caps);
1081 gst_caps_unref (old_caps);
1087 * gst_matroska_mux_video_pad_setcaps:
1088 * @pad: Pad which got the caps.
1091 * Setcaps function for video sink pad.
1093 * Returns: %TRUE on success.
1096 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
1098 GstMatroskaTrackContext *context = NULL;
1099 GstMatroskaTrackVideoContext *videocontext;
1100 GstMatroskaMux *mux;
1101 GstMatroskaPad *collect_pad;
1102 GstStructure *structure;
1103 const gchar *mimetype;
1104 const gchar *interlace_mode, *s;
1105 const GValue *value = NULL;
1106 GstBuffer *codec_buf = NULL;
1107 gint width, height, pixel_width, pixel_height;
1109 guint multiview_flags;
1112 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1115 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1116 g_assert (collect_pad);
1117 context = collect_pad->track;
1119 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
1120 videocontext = (GstMatroskaTrackVideoContext *) context;
1122 if ((old_caps = gst_pad_get_current_caps (pad))) {
1123 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1124 && !check_new_caps (videocontext, old_caps, caps)) {
1125 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1126 ("Caps changes are not supported by Matroska\nCurrent: `%"
1127 GST_PTR_FORMAT "`\nNew: `%" GST_PTR_FORMAT "`", old_caps, caps));
1128 gst_caps_unref (old_caps);
1131 gst_caps_unref (old_caps);
1132 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
1133 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1134 ("Caps on pad %" GST_PTR_FORMAT
1135 " arrived late. Headers were already written", pad));
1139 /* gst -> matroska ID'ing */
1140 structure = gst_caps_get_structure (caps, 0);
1142 mimetype = gst_structure_get_name (structure);
1144 interlace_mode = gst_structure_get_string (structure, "interlace-mode");
1145 if (interlace_mode != NULL) {
1146 if (strcmp (interlace_mode, "progressive") == 0)
1147 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE;
1149 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_INTERLACED;
1151 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_UNKNOWN;
1154 if (!strcmp (mimetype, "video/x-theora")) {
1155 /* we'll extract the details later from the theora identification header */
1159 /* get general properties */
1160 /* spec says it is mandatory */
1161 if (!gst_structure_get_int (structure, "width", &width) ||
1162 !gst_structure_get_int (structure, "height", &height))
1165 videocontext->pixel_width = width;
1166 videocontext->pixel_height = height;
1168 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
1169 && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
1171 context->default_duration =
1172 gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
1173 GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
1174 GST_TIME_ARGS (context->default_duration));
1176 context->default_duration = 0;
1178 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
1179 &pixel_width, &pixel_height)) {
1180 if (pixel_width > pixel_height) {
1181 videocontext->display_width = width * pixel_width / pixel_height;
1182 videocontext->display_height = height;
1183 } else if (pixel_width < pixel_height) {
1184 videocontext->display_width = width;
1185 videocontext->display_height = height * pixel_height / pixel_width;
1187 videocontext->display_width = 0;
1188 videocontext->display_height = 0;
1191 videocontext->display_width = 0;
1192 videocontext->display_height = 0;
1195 if ((s = gst_structure_get_string (structure, "colorimetry"))) {
1196 if (!gst_video_colorimetry_from_string (&videocontext->colorimetry, s)) {
1197 GST_WARNING_OBJECT (pad, "Could not parse colorimetry %s", s);
1201 if ((s = gst_structure_get_string (structure, "mastering-display-info"))) {
1202 if (!gst_video_mastering_display_info_from_string
1203 (&videocontext->mastering_display_info, s)) {
1204 GST_WARNING_OBJECT (pad, "Could not parse mastering-display-metadata %s",
1207 videocontext->mastering_display_info_present = TRUE;
1211 if ((s = gst_structure_get_string (structure, "content-light-level"))) {
1212 if (!gst_video_content_light_level_from_string
1213 (&videocontext->content_light_level, s))
1214 GST_WARNING_OBJECT (pad, "Could not parse content-light-level %s", s);
1217 /* Collect stereoscopic info, if any */
1218 if ((s = gst_structure_get_string (structure, "multiview-mode")))
1219 videocontext->multiview_mode =
1220 gst_video_multiview_mode_from_caps_string (s);
1221 gst_structure_get_flagset (structure, "multiview-flags", &multiview_flags,
1223 videocontext->multiview_flags = multiview_flags;
1228 videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
1229 videocontext->fourcc = 0;
1231 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1232 * data and other settings
1236 /* extract codec_data, may turn out needed */
1237 value = gst_structure_get_value (structure, "codec_data");
1239 codec_buf = (GstBuffer *) gst_value_get_buffer (value);
1242 if (!strcmp (mimetype, "video/x-raw")) {
1244 gst_matroska_mux_set_codec_id (context,
1245 GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
1246 fstr = gst_structure_get_string (structure, "format");
1248 if (strlen (fstr) == 4)
1249 videocontext->fourcc = GST_STR_FOURCC (fstr);
1250 else if (!strcmp (fstr, "GRAY8"))
1251 videocontext->fourcc = GST_MAKE_FOURCC ('Y', '8', '0', '0');
1252 else if (!strcmp (fstr, "BGR"))
1253 videocontext->fourcc = GST_MAKE_FOURCC ('B', 'G', 'R', 24);
1254 else if (!strcmp (fstr, "RGB"))
1255 videocontext->fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', 24);
1257 } else if (!strcmp (mimetype, "video/x-huffyuv") /* MS/VfW compatibility cases */
1258 ||!strcmp (mimetype, "video/x-divx")
1259 || !strcmp (mimetype, "video/x-dv")
1260 || !strcmp (mimetype, "video/x-h263")
1261 || !strcmp (mimetype, "video/x-msmpeg")
1262 || !strcmp (mimetype, "video/x-wmv")
1263 || !strcmp (mimetype, "image/jpeg")) {
1264 gst_riff_strf_vids *bih;
1265 gint size = sizeof (gst_riff_strf_vids);
1268 if (!strcmp (mimetype, "video/x-huffyuv"))
1269 fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
1270 else if (!strcmp (mimetype, "video/x-dv"))
1271 fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
1272 else if (!strcmp (mimetype, "video/x-h263"))
1273 fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
1274 else if (!strcmp (mimetype, "video/x-divx")) {
1277 gst_structure_get_int (structure, "divxversion", &divxversion);
1278 switch (divxversion) {
1280 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
1283 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
1286 fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
1289 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1292 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
1293 switch (msmpegversion) {
1295 fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
1298 fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
1304 } else if (!strcmp (mimetype, "video/x-wmv")) {
1308 fstr = gst_structure_get_string (structure, "format");
1309 if (fstr && strlen (fstr) == 4) {
1310 fourcc = GST_STR_FOURCC (fstr);
1311 } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
1312 if (wmvversion == 2) {
1313 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
1314 } else if (wmvversion == 1) {
1315 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
1316 } else if (wmvversion == 3) {
1317 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
1320 } else if (!strcmp (mimetype, "image/jpeg")) {
1321 fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
1327 bih = g_new0 (gst_riff_strf_vids, 1);
1328 GST_WRITE_UINT32_LE (&bih->size, size);
1329 GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
1330 GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
1331 GST_WRITE_UINT32_LE (&bih->compression, fourcc);
1332 GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
1333 GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
1334 GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
1335 videocontext->pixel_height * 3);
1337 /* process codec private/initialization data, if any */
1339 size += gst_buffer_get_size (codec_buf);
1340 bih = g_realloc (bih, size);
1341 GST_WRITE_UINT32_LE (&bih->size, size);
1342 gst_buffer_extract (codec_buf, 0,
1343 (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
1346 gst_matroska_mux_set_codec_id (context,
1347 GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
1348 gst_matroska_mux_free_codec_priv (context);
1349 context->codec_priv = (gpointer) bih;
1350 context->codec_priv_size = size;
1351 context->dts_only = TRUE;
1352 } else if (!strcmp (mimetype, "video/x-h264")) {
1353 gst_matroska_mux_set_codec_id (context,
1354 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
1355 gst_matroska_mux_free_codec_priv (context);
1357 if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1359 GST_WARNING_OBJECT (mux,
1360 "avc3 is not officially supported, only use this format for smart encoding");
1363 /* Create avcC header */
1364 if (codec_buf != NULL) {
1365 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1366 context->codec_priv = g_malloc0 (context->codec_priv_size);
1367 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1369 } else if (!strcmp (mimetype, "video/x-h265")) {
1370 gst_matroska_mux_set_codec_id (context,
1371 GST_MATROSKA_CODEC_ID_VIDEO_MPEGH_HEVC);
1372 gst_matroska_mux_free_codec_priv (context);
1374 if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1376 GST_WARNING_OBJECT (mux,
1377 "hev1 is not officially supported, only use this format for smart encoding");
1380 /* Create hvcC header */
1381 if (codec_buf != NULL) {
1382 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1383 context->codec_priv = g_malloc0 (context->codec_priv_size);
1384 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1386 } else if (!strcmp (mimetype, "video/x-theora")) {
1387 const GValue *streamheader;
1389 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
1391 gst_matroska_mux_free_codec_priv (context);
1393 streamheader = gst_structure_get_value (structure, "streamheader");
1394 if (!theora_streamheader_to_codecdata (streamheader, context)) {
1395 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1396 ("theora stream headers missing or malformed"));
1399 } else if (!strcmp (mimetype, "video/x-dirac")) {
1400 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
1401 } else if (!strcmp (mimetype, "video/x-vp8")) {
1402 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP8);
1403 } else if (!strcmp (mimetype, "video/x-vp9")) {
1404 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP9);
1405 } else if (!strcmp (mimetype, "video/x-av1")) {
1406 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_AV1);
1407 gst_matroska_mux_free_codec_priv (context);
1408 /* Create av1C header */
1409 if (codec_buf != NULL)
1410 gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1411 &context->codec_priv, &context->codec_priv_size);
1412 } else if (!strcmp (mimetype, "video/x-ffv")) {
1413 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_FFV1);
1414 gst_matroska_mux_free_codec_priv (context);
1415 if (codec_buf != NULL)
1416 gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1417 &context->codec_priv, &context->codec_priv_size);
1418 } else if (!strcmp (mimetype, "video/mpeg")) {
1421 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1422 switch (mpegversion) {
1424 gst_matroska_mux_set_codec_id (context,
1425 GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
1428 gst_matroska_mux_set_codec_id (context,
1429 GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
1432 gst_matroska_mux_set_codec_id (context,
1433 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
1439 /* global headers may be in codec data */
1440 if (codec_buf != NULL) {
1441 gst_matroska_mux_free_codec_priv (context);
1442 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1443 context->codec_priv = g_malloc0 (context->codec_priv_size);
1444 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1446 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1448 /* can only make it here if preceding case verified it was version 3 */
1449 gst_matroska_mux_set_codec_id (context,
1450 GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
1451 } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
1453 const GValue *mdpr_data;
1455 gst_structure_get_int (structure, "rmversion", &rmversion);
1456 switch (rmversion) {
1458 gst_matroska_mux_set_codec_id (context,
1459 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
1462 gst_matroska_mux_set_codec_id (context,
1463 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
1466 gst_matroska_mux_set_codec_id (context,
1467 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
1470 gst_matroska_mux_set_codec_id (context,
1471 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
1477 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1478 if (mdpr_data != NULL) {
1479 guint8 *priv_data = NULL;
1480 guint priv_data_size = 0;
1482 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1484 priv_data_size = gst_buffer_get_size (codec_data_buf);
1485 priv_data = g_malloc0 (priv_data_size);
1487 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1489 gst_matroska_mux_free_codec_priv (context);
1490 context->codec_priv = priv_data;
1491 context->codec_priv_size = priv_data_size;
1493 } else if (strcmp (mimetype, "video/x-prores") == 0) {
1494 const gchar *variant;
1496 gst_matroska_mux_free_codec_priv (context);
1498 variant = gst_structure_get_string (structure, "format");
1499 if (!variant || !g_strcmp0 (variant, "standard"))
1500 context->codec_priv = g_strdup ("apcn");
1501 else if (!g_strcmp0 (variant, "hq"))
1502 context->codec_priv = g_strdup ("apch");
1503 else if (!g_strcmp0 (variant, "lt"))
1504 context->codec_priv = g_strdup ("apcs");
1505 else if (!g_strcmp0 (variant, "proxy"))
1506 context->codec_priv = g_strdup ("apco");
1507 else if (!g_strcmp0 (variant, "4444"))
1508 context->codec_priv = g_strdup ("ap4h");
1510 GST_WARNING_OBJECT (mux, "Unhandled prores format: %s", variant);
1515 context->codec_priv_size = sizeof (guint32);
1516 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_PRORES);
1524 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1525 GST_PAD_NAME (pad), caps);
1530 /* N > 0 to expect a particular number of headers, negative if the
1531 number of headers is variable */
1533 xiphN_streamheader_to_codecdata (const GValue * streamheader,
1534 GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
1536 GstBuffer **buf = NULL;
1539 guint bufi, i, offset, priv_data_size;
1541 if (streamheader == NULL)
1542 goto no_stream_headers;
1544 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1547 bufarr = g_value_peek_pointer (streamheader);
1548 if (bufarr->len <= 0 || bufarr->len > 255) /* at least one header, and count stored in a byte */
1550 if (N > 0 && bufarr->len != N)
1553 context->xiph_headers_to_skip = bufarr->len;
1555 buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1556 for (i = 0; i < bufarr->len; i++) {
1557 GValue *bufval = &g_array_index (bufarr, GValue, i);
1559 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1561 goto wrong_content_type;
1564 buf[i] = g_value_peek_pointer (bufval);
1568 if (bufarr->len > 0) {
1569 for (i = 0; i < bufarr->len - 1; i++) {
1570 priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
1574 for (i = 0; i < bufarr->len; ++i) {
1575 priv_data_size += gst_buffer_get_size (buf[i]);
1578 priv_data = g_malloc0 (priv_data_size);
1580 priv_data[0] = bufarr->len - 1;
1583 if (bufarr->len > 0) {
1584 for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1585 for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
1586 priv_data[offset++] = 0xff;
1588 priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
1592 for (i = 0; i < bufarr->len; ++i) {
1593 gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
1594 offset += gst_buffer_get_size (buf[i]);
1597 gst_matroska_mux_free_codec_priv (context);
1598 context->codec_priv = priv_data;
1599 context->codec_priv_size = priv_data_size;
1602 *p_buf0 = gst_buffer_ref (buf[0]);
1611 GST_WARNING ("required streamheaders missing in sink caps!");
1616 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1617 G_VALUE_TYPE_NAME (streamheader));
1622 GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1627 GST_WARNING ("streamheaders array does not contain GstBuffers");
1633 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1634 GstMatroskaTrackContext * context)
1636 GstBuffer *buf0 = NULL;
1638 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1641 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
1642 GST_WARNING ("First vorbis header too small, ignoring");
1644 if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
1645 GstMatroskaTrackAudioContext *audiocontext;
1649 gst_buffer_map (buf0, &map, GST_MAP_READ);
1650 hdr = map.data + 1 + 6 + 4;
1651 audiocontext = (GstMatroskaTrackAudioContext *) context;
1652 audiocontext->channels = GST_READ_UINT8 (hdr);
1653 audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1654 gst_buffer_unmap (buf0, &map);
1659 gst_buffer_unref (buf0);
1665 theora_streamheader_to_codecdata (const GValue * streamheader,
1666 GstMatroskaTrackContext * context)
1668 GstBuffer *buf0 = NULL;
1670 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1673 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
1674 GST_WARNING ("First theora header too small, ignoring");
1675 } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
1676 GST_WARNING ("First header not a theora identification header, ignoring");
1678 GstMatroskaTrackVideoContext *videocontext;
1679 guint fps_num, fps_denom, par_num, par_denom;
1683 gst_buffer_map (buf0, &map, GST_MAP_READ);
1684 hdr = map.data + 1 + 6 + 3 + 2 + 2;
1686 videocontext = (GstMatroskaTrackVideoContext *) context;
1687 videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1688 videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1689 hdr += 3 + 3 + 1 + 1;
1690 fps_num = GST_READ_UINT32_BE (hdr);
1691 fps_denom = GST_READ_UINT32_BE (hdr + 4);
1692 context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1693 fps_denom, fps_num);
1695 par_num = GST_READ_UINT32_BE (hdr) >> 8;
1696 par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1697 if (par_num > 0 && par_denom > 0) {
1698 if (par_num > par_denom) {
1699 videocontext->display_width =
1700 videocontext->pixel_width * par_num / par_denom;
1701 videocontext->display_height = videocontext->pixel_height;
1702 } else if (par_num < par_denom) {
1703 videocontext->display_width = videocontext->pixel_width;
1704 videocontext->display_height =
1705 videocontext->pixel_height * par_denom / par_num;
1707 videocontext->display_width = 0;
1708 videocontext->display_height = 0;
1711 videocontext->display_width = 0;
1712 videocontext->display_height = 0;
1715 gst_buffer_unmap (buf0, &map);
1719 gst_buffer_unref (buf0);
1725 kate_streamheader_to_codecdata (const GValue * streamheader,
1726 GstMatroskaTrackContext * context)
1728 GstBuffer *buf0 = NULL;
1730 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1733 if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) { /* Kate ID header is 64 bytes */
1734 GST_WARNING ("First kate header too small, ignoring");
1735 } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
1736 GST_WARNING ("First header not a kate identification header, ignoring");
1740 gst_buffer_unref (buf0);
1746 flac_streamheader_to_codecdata (const GValue * streamheader,
1747 GstMatroskaTrackContext * context)
1754 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1755 GST_WARNING ("No or invalid streamheader field in the caps");
1759 bufarr = g_value_peek_pointer (streamheader);
1760 if (bufarr->len < 2) {
1761 GST_WARNING ("Too few headers in streamheader field");
1765 context->xiph_headers_to_skip = bufarr->len + 1;
1767 bufval = &g_array_index (bufarr, GValue, 0);
1768 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1769 GST_WARNING ("streamheaders array does not contain GstBuffers");
1773 buffer = g_value_peek_pointer (bufval);
1775 /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1776 if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
1777 || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
1778 || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
1779 GST_WARNING ("Invalid streamheader for FLAC");
1783 gst_matroska_mux_free_codec_priv (context);
1784 context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
1785 context->codec_priv = g_malloc (context->codec_priv_size);
1786 gst_buffer_extract (buffer, 9, context->codec_priv, -1);
1788 for (i = 1; i < bufarr->len; i++) {
1790 bufval = &g_array_index (bufarr, GValue, i);
1792 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1793 gst_matroska_mux_free_codec_priv (context);
1794 GST_WARNING ("streamheaders array does not contain GstBuffers");
1798 buffer = g_value_peek_pointer (bufval);
1800 old_size = context->codec_priv_size;
1801 context->codec_priv_size += gst_buffer_get_size (buffer);
1803 context->codec_priv = g_realloc (context->codec_priv,
1804 context->codec_priv_size);
1805 gst_buffer_extract (buffer, 0,
1806 (guint8 *) context->codec_priv + old_size, -1);
1813 speex_streamheader_to_codecdata (const GValue * streamheader,
1814 GstMatroskaTrackContext * context)
1821 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1822 GST_WARNING ("No or invalid streamheader field in the caps");
1826 bufarr = g_value_peek_pointer (streamheader);
1827 if (bufarr->len != 2) {
1828 GST_WARNING ("Too few headers in streamheader field");
1832 context->xiph_headers_to_skip = bufarr->len + 1;
1834 bufval = &g_array_index (bufarr, GValue, 0);
1835 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1836 GST_WARNING ("streamheaders array does not contain GstBuffers");
1840 buffer = g_value_peek_pointer (bufval);
1842 if (gst_buffer_get_size (buffer) < 80
1843 || gst_buffer_memcmp (buffer, 0, "Speex ", 8) != 0) {
1844 GST_WARNING ("Invalid streamheader for Speex");
1848 gst_matroska_mux_free_codec_priv (context);
1849 context->codec_priv_size = gst_buffer_get_size (buffer);
1850 context->codec_priv = g_malloc (context->codec_priv_size);
1851 gst_buffer_extract (buffer, 0, context->codec_priv, -1);
1853 bufval = &g_array_index (bufarr, GValue, 1);
1855 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1856 gst_matroska_mux_free_codec_priv (context);
1857 GST_WARNING ("streamheaders array does not contain GstBuffers");
1861 buffer = g_value_peek_pointer (bufval);
1863 old_size = context->codec_priv_size;
1864 context->codec_priv_size += gst_buffer_get_size (buffer);
1865 context->codec_priv = g_realloc (context->codec_priv,
1866 context->codec_priv_size);
1867 gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
1873 opus_streamheader_to_codecdata (const GValue * streamheader,
1874 GstMatroskaTrackContext * context)
1880 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1883 bufarr = g_value_peek_pointer (streamheader);
1884 if (bufarr->len != 1 && bufarr->len != 2) /* one header, and count stored in a byte */
1887 /* Opus headers are not in-band */
1888 context->xiph_headers_to_skip = 0;
1890 bufval = &g_array_index (bufarr, GValue, 0);
1891 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1892 goto wrong_content_type;
1894 buf = g_value_peek_pointer (bufval);
1896 gst_matroska_mux_free_codec_priv (context);
1898 context->codec_priv_size = gst_buffer_get_size (buf);
1899 context->codec_priv = g_malloc0 (context->codec_priv_size);
1900 gst_buffer_extract (buf, 0, context->codec_priv, -1);
1902 context->codec_delay =
1903 GST_READ_UINT16_LE ((guint8 *) context->codec_priv + 10);
1904 context->codec_delay =
1905 gst_util_uint64_scale_round (context->codec_delay, GST_SECOND, 48000);
1906 context->seek_preroll = 80 * GST_MSECOND;
1913 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1914 G_VALUE_TYPE_NAME (streamheader));
1919 GST_WARNING ("got %u streamheaders, not 1 or 2 as expected", bufarr->len);
1924 GST_WARNING ("streamheaders array does not contain GstBuffers");
1930 opus_make_codecdata (GstMatroskaTrackContext * context, GstCaps * caps)
1934 guint8 channel_mapping_family;
1935 guint8 stream_count, coupled_count, channel_mapping[256];
1939 /* Opus headers are not in-band */
1940 context->xiph_headers_to_skip = 0;
1942 context->codec_delay = 0;
1943 context->seek_preroll = 80 * GST_MSECOND;
1945 if (!gst_codec_utils_opus_parse_caps (caps, &rate, &channels,
1946 &channel_mapping_family, &stream_count, &coupled_count,
1948 GST_WARNING ("Failed to parse caps for Opus");
1953 gst_codec_utils_opus_create_header (rate, channels,
1954 channel_mapping_family, stream_count, coupled_count, channel_mapping, 0,
1957 GST_WARNING ("Failed to create Opus header from caps");
1961 gst_buffer_map (buffer, &map, GST_MAP_READ);
1962 context->codec_priv_size = map.size;
1963 context->codec_priv = g_malloc (context->codec_priv_size);
1964 memcpy (context->codec_priv, map.data, map.size);
1965 gst_buffer_unmap (buffer, &map);
1966 gst_buffer_unref (buffer);
1972 * gst_matroska_mux_audio_pad_setcaps:
1973 * @pad: Pad which got the caps.
1976 * Setcaps function for audio sink pad.
1978 * Returns: %TRUE on success.
1981 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1983 GstMatroskaTrackContext *context = NULL;
1984 GstMatroskaTrackAudioContext *audiocontext;
1985 GstMatroskaMux *mux;
1986 GstMatroskaPad *collect_pad;
1987 const gchar *mimetype;
1988 gint samplerate = 0, channels = 0;
1989 GstStructure *structure;
1990 const GValue *codec_data = NULL;
1991 GstBuffer *buf = NULL;
1992 const gchar *stream_format = NULL;
1995 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1997 if ((old_caps = gst_pad_get_current_caps (pad))) {
1998 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1999 && !gst_caps_is_equal (caps, old_caps)) {
2000 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2001 ("Caps changes are not supported by Matroska"));
2002 gst_caps_unref (old_caps);
2005 gst_caps_unref (old_caps);
2006 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
2007 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2008 ("Caps on pad %" GST_PTR_FORMAT
2009 " arrived late. Headers were already written", pad));
2014 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
2015 g_assert (collect_pad);
2016 context = collect_pad->track;
2018 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
2019 audiocontext = (GstMatroskaTrackAudioContext *) context;
2021 structure = gst_caps_get_structure (caps, 0);
2022 mimetype = gst_structure_get_name (structure);
2025 gst_structure_get_int (structure, "rate", &samplerate);
2026 gst_structure_get_int (structure, "channels", &channels);
2028 audiocontext->samplerate = samplerate;
2029 audiocontext->channels = channels;
2030 audiocontext->bitdepth = 0;
2031 context->default_duration = 0;
2033 codec_data = gst_structure_get_value (structure, "codec_data");
2035 buf = gst_value_get_buffer (codec_data);
2037 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
2038 * data and other settings
2042 if (!strcmp (mimetype, "audio/mpeg")) {
2043 gint mpegversion = 0;
2045 gst_structure_get_int (structure, "mpegversion", &mpegversion);
2046 switch (mpegversion) {
2052 gst_structure_get_int (structure, "layer", &layer);
2054 if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
2055 GST_WARNING_OBJECT (mux,
2056 "Unable to determine MPEG audio version, assuming 1");
2062 else if (layer == 2)
2064 else if (version == 2)
2069 context->default_duration =
2070 gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
2074 gst_matroska_mux_set_codec_id (context,
2075 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
2078 gst_matroska_mux_set_codec_id (context,
2079 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
2082 gst_matroska_mux_set_codec_id (context,
2083 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
2092 stream_format = gst_structure_get_string (structure, "stream-format");
2093 /* check this is raw aac */
2094 if (stream_format) {
2095 if (strcmp (stream_format, "raw") != 0) {
2096 GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
2100 GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
2105 gst_matroska_mux_set_codec_id (context,
2106 GST_MATROSKA_CODEC_ID_AUDIO_AAC);
2107 context->codec_priv_size = gst_buffer_get_size (buf);
2108 context->codec_priv = g_malloc (context->codec_priv_size);
2109 gst_buffer_extract (buf, 0, context->codec_priv,
2110 context->codec_priv_size);
2112 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
2119 } else if (!strcmp (mimetype, "audio/x-raw")) {
2122 gst_audio_info_init (&info);
2123 if (!gst_audio_info_from_caps (&info, caps)) {
2124 GST_DEBUG_OBJECT (mux,
2125 "broken caps, rejected by gst_audio_info_from_caps");
2129 switch (GST_AUDIO_INFO_FORMAT (&info)) {
2130 case GST_AUDIO_FORMAT_U8:
2131 case GST_AUDIO_FORMAT_S16BE:
2132 case GST_AUDIO_FORMAT_S16LE:
2133 case GST_AUDIO_FORMAT_S24BE:
2134 case GST_AUDIO_FORMAT_S24LE:
2135 case GST_AUDIO_FORMAT_S32BE:
2136 case GST_AUDIO_FORMAT_S32LE:
2137 if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
2138 GST_DEBUG_OBJECT (mux, "width must be same as depth!");
2141 if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
2142 gst_matroska_mux_set_codec_id (context,
2143 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
2145 gst_matroska_mux_set_codec_id (context,
2146 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
2148 case GST_AUDIO_FORMAT_F32LE:
2149 case GST_AUDIO_FORMAT_F64LE:
2150 gst_matroska_mux_set_codec_id (context,
2151 GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
2155 GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
2159 audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
2160 } else if (!strcmp (mimetype, "audio/x-vorbis")) {
2161 const GValue *streamheader;
2163 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
2165 gst_matroska_mux_free_codec_priv (context);
2167 streamheader = gst_structure_get_value (structure, "streamheader");
2168 if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
2169 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2170 ("vorbis stream headers missing or malformed"));
2173 } else if (!strcmp (mimetype, "audio/x-flac")) {
2174 const GValue *streamheader;
2176 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
2178 gst_matroska_mux_free_codec_priv (context);
2180 streamheader = gst_structure_get_value (structure, "streamheader");
2181 if (!flac_streamheader_to_codecdata (streamheader, context)) {
2182 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2183 ("flac stream headers missing or malformed"));
2186 } else if (!strcmp (mimetype, "audio/x-speex")) {
2187 const GValue *streamheader;
2189 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
2190 gst_matroska_mux_free_codec_priv (context);
2192 streamheader = gst_structure_get_value (structure, "streamheader");
2193 if (!speex_streamheader_to_codecdata (streamheader, context)) {
2194 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2195 ("speex stream headers missing or malformed"));
2198 } else if (!strcmp (mimetype, "audio/x-opus")) {
2199 const GValue *streamheader;
2201 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_OPUS);
2203 streamheader = gst_structure_get_value (structure, "streamheader");
2205 gst_matroska_mux_free_codec_priv (context);
2206 if (!opus_streamheader_to_codecdata (streamheader, context)) {
2207 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2208 ("opus stream headers missing or malformed"));
2212 /* no streamheader, but we need to have one, so we make one up
2214 gst_matroska_mux_free_codec_priv (context);
2215 if (!opus_make_codecdata (context, caps)) {
2216 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2217 ("opus stream headers missing or malformed"));
2221 } else if (!strcmp (mimetype, "audio/x-ac3")) {
2222 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_AC3);
2223 } else if (!strcmp (mimetype, "audio/x-eac3")) {
2224 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
2225 } else if (!strcmp (mimetype, "audio/x-dts")) {
2226 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_DTS);
2227 } else if (!strcmp (mimetype, "audio/x-tta")) {
2230 /* TTA frame duration */
2231 context->default_duration = 1.04489795918367346939 * GST_SECOND;
2233 gst_structure_get_int (structure, "width", &width);
2234 audiocontext->bitdepth = width;
2235 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_TTA);
2237 } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
2239 const GValue *mdpr_data;
2241 gst_structure_get_int (structure, "raversion", &raversion);
2242 switch (raversion) {
2244 gst_matroska_mux_set_codec_id (context,
2245 GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
2248 gst_matroska_mux_set_codec_id (context,
2249 GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
2252 gst_matroska_mux_set_codec_id (context,
2253 GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
2259 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
2260 if (mdpr_data != NULL) {
2261 guint8 *priv_data = NULL;
2262 guint priv_data_size = 0;
2264 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
2266 priv_data_size = gst_buffer_get_size (codec_data_buf);
2267 priv_data = g_malloc0 (priv_data_size);
2269 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
2271 gst_matroska_mux_free_codec_priv (context);
2273 context->codec_priv = priv_data;
2274 context->codec_priv_size = priv_data_size;
2277 } else if (!strcmp (mimetype, "audio/x-wma")
2278 || !strcmp (mimetype, "audio/x-alaw")
2279 || !strcmp (mimetype, "audio/x-mulaw")
2280 || !strcmp (mimetype, "audio/x-adpcm")
2281 || !strcmp (mimetype, "audio/G722")) {
2283 guint codec_priv_size;
2285 gint block_align = 0;
2288 if (samplerate == 0 || channels == 0) {
2289 GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
2293 if (!strcmp (mimetype, "audio/x-wma")) {
2297 if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
2298 || !gst_structure_get_int (structure, "block_align", &block_align)
2299 || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
2300 GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
2305 switch (wmaversion) {
2307 format = GST_RIFF_WAVE_FORMAT_WMAV1;
2310 format = GST_RIFF_WAVE_FORMAT_WMAV2;
2313 format = GST_RIFF_WAVE_FORMAT_WMAV3;
2316 GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
2320 if (gst_structure_get_int (structure, "depth", &depth))
2321 audiocontext->bitdepth = depth;
2322 } else if (!strcmp (mimetype, "audio/x-alaw")
2323 || !strcmp (mimetype, "audio/x-mulaw")) {
2324 audiocontext->bitdepth = 8;
2325 if (!strcmp (mimetype, "audio/x-alaw"))
2326 format = GST_RIFF_WAVE_FORMAT_ALAW;
2328 format = GST_RIFF_WAVE_FORMAT_MULAW;
2330 block_align = channels;
2331 bitrate = block_align * samplerate;
2332 } else if (!strcmp (mimetype, "audio/x-adpcm")) {
2335 layout = gst_structure_get_string (structure, "layout");
2337 GST_WARNING_OBJECT (mux, "Missing layout on adpcm caps");
2341 if (!gst_structure_get_int (structure, "block_align", &block_align)) {
2342 GST_WARNING_OBJECT (mux, "Missing block_align on adpcm caps");
2346 if (!strcmp (layout, "dvi")) {
2347 format = GST_RIFF_WAVE_FORMAT_DVI_ADPCM;
2348 } else if (!strcmp (layout, "g726")) {
2349 format = GST_RIFF_WAVE_FORMAT_ITU_G726_ADPCM;
2350 if (!gst_structure_get_int (structure, "bitrate", &bitrate)) {
2351 GST_WARNING_OBJECT (mux, "Missing bitrate on adpcm g726 caps");
2355 GST_WARNING_OBJECT (mux, "Unknown layout on adpcm caps");
2359 } else if (!strcmp (mimetype, "audio/G722")) {
2360 format = GST_RIFF_WAVE_FORMAT_ADPCM_G722;
2362 g_assert (format != 0);
2364 codec_priv_size = WAVEFORMATEX_SIZE;
2366 codec_priv_size += gst_buffer_get_size (buf);
2368 /* serialize waveformatex structure */
2369 codec_priv = g_malloc0 (codec_priv_size);
2370 GST_WRITE_UINT16_LE (codec_priv, format);
2371 GST_WRITE_UINT16_LE (codec_priv + 2, channels);
2372 GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
2373 GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
2374 GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
2375 GST_WRITE_UINT16_LE (codec_priv + 14, 0);
2377 GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
2379 GST_WRITE_UINT16_LE (codec_priv + 16, 0);
2381 /* process codec private/initialization data, if any */
2383 gst_buffer_extract (buf, 0,
2384 (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
2387 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
2388 gst_matroska_mux_free_codec_priv (context);
2389 context->codec_priv = (gpointer) codec_priv;
2390 context->codec_priv_size = codec_priv_size;
2398 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2399 GST_PAD_NAME (pad), caps);
2404 /* we probably don't have the data at start,
2405 * so have to reserve (a maximum) space to write this at the end.
2406 * bit spacy, but some formats can hold quite some */
2407 #define SUBTITLE_MAX_CODEC_PRIVATE 2048 /* must be > 128 */
2410 * gst_matroska_mux_subtitle_pad_setcaps:
2411 * @pad: Pad which got the caps.
2414 * Setcaps function for subtitle sink pad.
2416 * Returns: %TRUE on success.
2419 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
2421 /* There is now (at least) one such alement (kateenc), and I'm going
2422 to handle it here and claim it works when it can be piped back
2423 through GStreamer and VLC */
2425 GstMatroskaTrackContext *context = NULL;
2426 GstMatroskaTrackSubtitleContext *scontext;
2427 GstMatroskaMux *mux;
2428 GstMatroskaPad *collect_pad;
2429 GstCollectData *data;
2430 const gchar *mimetype;
2431 GstStructure *structure;
2432 const GValue *value = NULL;
2433 GstBuffer *buf = NULL;
2434 gboolean ret = TRUE;
2437 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2439 if ((old_caps = gst_pad_get_current_caps (pad))) {
2440 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
2441 && !gst_caps_is_equal (caps, old_caps)) {
2442 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2443 ("Caps changes are not supported by Matroska"));
2444 gst_caps_unref (old_caps);
2447 gst_caps_unref (old_caps);
2448 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
2449 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2450 ("Caps on pad %" GST_PTR_FORMAT
2451 " arrived late. Headers were already written", pad));
2456 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
2457 g_assert (collect_pad);
2458 data = (GstCollectData *) (collect_pad);
2460 context = collect_pad->track;
2462 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
2463 scontext = (GstMatroskaTrackSubtitleContext *) context;
2465 structure = gst_caps_get_structure (caps, 0);
2466 mimetype = gst_structure_get_name (structure);
2469 scontext->check_utf8 = 1;
2470 scontext->invalid_utf8 = 0;
2471 context->default_duration = 0;
2473 if (!strcmp (mimetype, "subtitle/x-kate")) {
2474 const GValue *streamheader;
2476 gst_matroska_mux_set_codec_id (context,
2477 GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
2479 gst_matroska_mux_free_codec_priv (context);
2481 streamheader = gst_structure_get_value (structure, "streamheader");
2482 if (!kate_streamheader_to_codecdata (streamheader, context)) {
2483 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2484 ("kate stream headers missing or malformed"));
2488 } else if (!strcmp (mimetype, "text/x-raw")) {
2489 gst_matroska_mux_set_codec_id (context,
2490 GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
2491 } else if (!strcmp (mimetype, "application/x-ssa")) {
2492 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
2493 } else if (!strcmp (mimetype, "application/x-ass")) {
2494 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
2495 } else if (!strcmp (mimetype, "application/x-usf")) {
2496 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
2497 } else if (!strcmp (mimetype, "subpicture/x-dvd")) {
2498 gst_matroska_mux_set_codec_id (context,
2499 GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
2505 /* maybe some private data, e.g. vobsub */
2506 value = gst_structure_get_value (structure, "codec_data");
2508 buf = gst_value_get_buffer (value);
2511 guint8 *priv_data = NULL;
2513 gst_buffer_map (buf, &map, GST_MAP_READ);
2515 if (map.size > SUBTITLE_MAX_CODEC_PRIVATE) {
2516 GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
2517 " exceeded maximum (%d); discarding", pad,
2518 SUBTITLE_MAX_CODEC_PRIVATE);
2519 gst_buffer_unmap (buf, &map);
2523 gst_matroska_mux_free_codec_priv (context);
2525 priv_data = g_malloc0 (map.size);
2526 memcpy (priv_data, map.data, map.size);
2527 context->codec_priv = priv_data;
2528 context->codec_priv_size = map.size;
2529 gst_buffer_unmap (buf, &map);
2532 GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %" G_GSIZE_FORMAT,
2533 GST_STR_NULL (context->codec_id), context->codec_priv_size);
2535 /* This pad is sparse. Now that we have caps on it, we can tell collectpads
2536 * not to actually wait for data when muxing */
2537 GST_COLLECT_PADS_STREAM_LOCK (mux->collect);
2538 GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED);
2539 gst_collect_pads_set_waiting (mux->collect, data, FALSE);
2540 GST_COLLECT_PADS_STREAM_UNLOCK (mux->collect);
2549 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2550 GST_PAD_NAME (pad), caps);
2557 * gst_matroska_mux_request_new_pad:
2558 * @element: #GstMatroskaMux.
2559 * @templ: #GstPadTemplate.
2560 * @pad_name: New pad name.
2562 * Request pad function for sink templates.
2564 * Returns: New #GstPad.
2567 gst_matroska_mux_request_new_pad (GstElement * element,
2568 GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
2570 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
2571 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
2572 GstMatroskaPad *collect_pad;
2573 GstMatroskamuxPad *newpad;
2575 const gchar *pad_name = NULL;
2576 GstMatroskaCapsFunc capsfunc = NULL;
2577 GstMatroskaTrackContext *context = NULL;
2579 const gchar *id = NULL;
2581 if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
2582 /* don't mix named and unnamed pads, if the pad already exists we fail when
2583 * trying to add it */
2584 if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
2585 pad_name = req_name;
2587 name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
2590 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
2591 context = (GstMatroskaTrackContext *)
2592 g_new0 (GstMatroskaTrackAudioContext, 1);
2593 context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
2594 context->name = g_strdup ("Audio");
2595 } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
2596 /* don't mix named and unnamed pads, if the pad already exists we fail when
2597 * trying to add it */
2598 if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
2599 pad_name = req_name;
2601 name = g_strdup_printf ("video_%u", mux->num_v_streams++);
2604 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
2605 context = (GstMatroskaTrackContext *)
2606 g_new0 (GstMatroskaTrackVideoContext, 1);
2607 context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
2608 context->name = g_strdup ("Video");
2609 } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
2610 /* don't mix named and unnamed pads, if the pad already exists we fail when
2611 * trying to add it */
2612 if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
2613 pad_name = req_name;
2615 name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
2618 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
2619 context = (GstMatroskaTrackContext *)
2620 g_new0 (GstMatroskaTrackSubtitleContext, 1);
2621 context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
2622 context->name = g_strdup ("Subtitle");
2623 /* setcaps may only provide proper one a lot later */
2624 id = "S_SUB_UNKNOWN";
2626 GST_WARNING_OBJECT (mux, "This is not our template!");
2630 newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
2631 "name", pad_name, "direction", templ->direction, "template", templ, NULL);
2633 gst_matroskamux_pad_init (newpad);
2634 collect_pad = (GstMatroskaPad *)
2635 gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad),
2636 sizeof (GstMatroskaPad),
2637 (GstCollectDataDestroyNotify) gst_matroska_pad_free, TRUE);
2639 collect_pad->mux = mux;
2640 collect_pad->track = context;
2641 gst_matroska_pad_reset (collect_pad, FALSE);
2643 gst_matroska_mux_set_codec_id (collect_pad->track, id);
2644 collect_pad->track->dts_only = FALSE;
2646 collect_pad->capsfunc = capsfunc;
2647 gst_pad_set_active (GST_PAD (newpad), TRUE);
2648 if (!gst_element_add_pad (element, GST_PAD (newpad)))
2649 goto pad_add_failed;
2655 GST_DEBUG_OBJECT (newpad, "Added new request pad");
2657 return GST_PAD (newpad);
2662 GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
2664 gst_object_unref (newpad);
2670 * gst_matroska_mux_release_pad:
2671 * @element: #GstMatroskaMux.
2672 * @pad: Pad to release.
2674 * Release a previously requested pad.
2677 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
2679 GstMatroskaMux *mux;
2682 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2684 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
2685 GstCollectData *cdata = (GstCollectData *) walk->data;
2686 GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
2688 if (cdata->pad == pad) {
2690 * observed duration, this will remain GST_CLOCK_TIME_NONE
2691 * only if the pad is reset
2693 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
2695 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2696 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2697 collected_duration =
2698 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2701 if (GST_CLOCK_TIME_IS_VALID (collected_duration)
2702 && mux->duration < collected_duration)
2703 mux->duration = collected_duration;
2709 gst_collect_pads_remove_pad (mux->collect, pad);
2710 if (gst_element_remove_pad (element, pad))
2715 gst_matroska_mux_write_mastering_metadata (GstMatroskaMux * mux,
2716 GstMatroskaTrackVideoContext * videocontext)
2718 GstEbmlWrite *ebml = mux->ebml_write;
2720 GstVideoMasteringDisplayInfo *minfo = &videocontext->mastering_display_info;
2722 const gdouble chroma_scale = 50000;
2723 const gdouble luma_scale = 50000;
2725 if (!videocontext->mastering_display_info_present)
2729 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_MASTERINGMETADATA);
2731 value = (gdouble) minfo->display_primaries[0].x / chroma_scale;
2732 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYX, value);
2734 value = (gdouble) minfo->display_primaries[0].y / chroma_scale;
2735 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYY, value);
2737 value = (gdouble) minfo->display_primaries[1].x / chroma_scale;
2738 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYX, value);
2740 value = (gdouble) minfo->display_primaries[1].y / chroma_scale;
2741 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYY, value);
2743 value = (gdouble) minfo->display_primaries[2].x / chroma_scale;
2744 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYX, value);
2746 value = (gdouble) minfo->display_primaries[2].y / chroma_scale;
2747 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYY, value);
2749 value = (gdouble) minfo->white_point.x / chroma_scale;
2750 gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYX, value);
2752 value = (gdouble) minfo->white_point.y / chroma_scale;
2753 gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY, value);
2755 value = (gdouble) minfo->max_display_mastering_luminance / luma_scale;
2756 gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMAX, value);
2758 value = (gdouble) minfo->min_display_mastering_luminance / luma_scale;
2759 gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMIN, value);
2761 gst_ebml_write_master_finish (ebml, master);
2766 gst_matroska_mux_write_colour (GstMatroskaMux * mux,
2767 GstMatroskaTrackVideoContext * videocontext)
2769 GstEbmlWrite *ebml = mux->ebml_write;
2771 guint matrix_id = 0;
2773 guint transfer_id = 0;
2774 guint primaries_id = 0;
2776 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_VIDEOCOLOUR);
2778 switch (videocontext->colorimetry.range) {
2779 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
2782 case GST_VIDEO_COLOR_RANGE_16_235:
2785 case GST_VIDEO_COLOR_RANGE_0_255:
2789 matrix_id = gst_video_color_matrix_to_iso (videocontext->colorimetry.matrix);
2791 gst_video_transfer_function_to_iso (videocontext->colorimetry.transfer);
2793 gst_video_color_primaries_to_iso (videocontext->colorimetry.primaries);
2795 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEORANGE, range_id);
2796 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOMATRIXCOEFFICIENTS,
2798 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS,
2800 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPRIMARIES, primaries_id);
2801 if (videocontext->content_light_level.max_content_light_level &&
2802 videocontext->content_light_level.max_frame_average_light_level) {
2803 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXCLL,
2804 videocontext->content_light_level.max_content_light_level);
2805 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXFALL,
2806 videocontext->content_light_level.max_frame_average_light_level);
2809 gst_matroska_mux_write_mastering_metadata (mux, videocontext);
2810 gst_ebml_write_master_finish (ebml, master);
2814 * gst_matroska_mux_track_header:
2815 * @mux: #GstMatroskaMux
2816 * @context: Tack context.
2818 * Write a track header.
2821 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2822 GstMatroskaTrackContext * context)
2824 GstEbmlWrite *ebml = mux->ebml_write;
2827 /* TODO: check if everything necessary is written and check default values */
2829 /* track type goes before the type-specific stuff */
2830 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2831 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2833 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, context->uid);
2834 if (context->default_duration) {
2835 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2836 context->default_duration);
2838 if (context->language) {
2839 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2843 /* FIXME: until we have a nice way of getting the codecname
2844 * out of the caps, I'm not going to enable this. Too much
2845 * (useless, double, boring) work... */
2846 /* TODO: Use value from tags if any */
2847 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2848 context->codec_name); */
2849 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2851 /* type-specific stuff */
2852 switch (context->type) {
2853 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2854 GstMatroskaTrackVideoContext *videocontext =
2855 (GstMatroskaTrackVideoContext *) context;
2857 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2858 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2859 videocontext->pixel_width);
2860 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2861 videocontext->pixel_height);
2862 if (videocontext->display_width && videocontext->display_height) {
2863 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2864 videocontext->display_width);
2865 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2866 videocontext->display_height);
2868 switch (videocontext->interlace_mode) {
2869 case GST_MATROSKA_INTERLACE_MODE_INTERLACED:
2870 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2872 case GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE:
2873 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 2);
2879 if (videocontext->fourcc) {
2880 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2882 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2883 (gpointer) & fcc_le, 4);
2885 gst_matroska_mux_write_colour (mux, videocontext);
2886 if (videocontext->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
2887 guint64 stereo_mode = 0;
2889 switch (videocontext->multiview_mode) {
2890 case GST_VIDEO_MULTIVIEW_MODE_MONO:
2892 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
2893 if (videocontext->multiview_flags &
2894 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2895 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_RL;
2897 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_LR;
2899 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
2900 if (videocontext->multiview_flags &
2901 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2902 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_RL;
2904 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_LR;
2906 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
2907 if (videocontext->multiview_flags &
2908 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2909 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_RL;
2911 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_LR;
2913 case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
2914 if (videocontext->multiview_flags &
2915 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2916 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_RL;
2918 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_LR;
2919 /* FIXME: In frame-by-frame mode, left/right frame buffers need to be
2920 * laced within one block. See http://www.matroska.org/technical/specs/index.html#StereoMode */
2921 GST_FIXME_OBJECT (mux,
2922 "Frame-by-frame stereoscopic mode not fully implemented");
2925 GST_WARNING_OBJECT (mux,
2926 "Multiview mode %d not supported in Matroska/WebM",
2927 videocontext->multiview_mode);
2931 if (stereo_mode != 0)
2932 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOSTEREOMODE,
2935 gst_ebml_write_master_finish (ebml, master);
2940 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2941 GstMatroskaTrackAudioContext *audiocontext =
2942 (GstMatroskaTrackAudioContext *) context;
2944 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2945 if (audiocontext->samplerate != 8000)
2946 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2947 audiocontext->samplerate);
2948 if (audiocontext->channels != 1)
2949 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2950 audiocontext->channels);
2951 if (audiocontext->bitdepth) {
2952 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2953 audiocontext->bitdepth);
2956 gst_ebml_write_master_finish (ebml, master);
2961 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
2965 /* doesn't need type-specific data */
2969 GST_DEBUG_OBJECT (mux, "Wrote track header. Codec %s", context->codec_id);
2971 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2972 if (context->codec_priv)
2973 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2974 context->codec_priv, context->codec_priv_size);
2976 if (context->seek_preroll) {
2977 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPREROLL,
2978 context->seek_preroll);
2981 if (context->codec_delay) {
2982 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CODECDELAY,
2983 context->codec_delay);
2988 gst_matroska_mux_write_chapter_title (const gchar * title, GstEbmlWrite * ebml)
2990 guint64 title_master;
2993 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERDISPLAY);
2995 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPSTRING, title);
2996 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CHAPLANGUAGE,
2997 GST_MATROSKA_MUX_CHAPLANG);
2999 gst_ebml_write_master_finish (ebml, title_master);
3002 static GstTocEntry *
3003 gst_matroska_mux_write_chapter (GstMatroskaMux * mux, GstTocEntry * edition,
3004 GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters,
3005 guint64 * master_edition)
3007 guint64 master_chapteratom;
3014 GstTocEntry *internal_chapter, *internal_nested;
3017 if (G_UNLIKELY (master_chapters != NULL && *master_chapters == 0))
3019 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERS);
3021 if (G_UNLIKELY (master_edition != NULL && *master_edition == 0)) {
3022 /* create uid for the parent */
3024 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_EDITIONENTRY);
3026 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONUID,
3027 g_ascii_strtoull (gst_toc_entry_get_uid (edition), NULL, 10));
3028 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGHIDDEN, 0);
3029 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGDEFAULT, 0);
3030 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGORDERED, 0);
3033 gst_toc_entry_get_start_stop_times (entry, &start, &stop);
3034 tags = gst_toc_entry_get_tags (entry);
3036 tags = gst_tag_list_copy (tags);
3039 /* build internal chapter */
3040 uid = gst_matroska_mux_create_uid (mux);
3041 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT, uid);
3042 internal_chapter = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, s_uid);
3044 /* Write the chapter entry */
3045 master_chapteratom =
3046 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERATOM);
3048 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERUID, uid);
3049 /* Store the user provided UID in the ChapterStringUID */
3050 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPTERSTRINGUID,
3051 gst_toc_entry_get_uid (entry));
3052 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTART, start);
3053 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTOP, stop);
3054 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGHIDDEN, 0);
3055 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGENABLED, 1);
3057 /* write current ChapterDisplays before the nested chapters */
3058 if (G_LIKELY (tags != NULL)) {
3059 count = gst_tag_list_get_tag_size (tags, GST_TAG_TITLE);
3061 for (i = 0; i < count; ++i) {
3062 gst_tag_list_get_string_index (tags, GST_TAG_TITLE, i, &title);
3063 /* FIXME: handle ChapterLanguage entries */
3064 gst_matroska_mux_write_chapter_title (title, ebml);
3068 /* remove title tag */
3069 if (G_LIKELY (count > 0))
3070 gst_tag_list_remove_tag (tags, GST_TAG_TITLE);
3072 gst_toc_entry_set_tags (internal_chapter, tags);
3075 /* Write nested chapters */
3076 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3078 internal_nested = gst_matroska_mux_write_chapter (mux, NULL, cur->data,
3081 gst_toc_entry_append_sub_entry (internal_chapter, internal_nested);
3084 gst_ebml_write_master_finish (ebml, master_chapteratom);
3086 return internal_chapter;
3089 static GstTocEntry *
3090 gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
3091 GstTocEntry * edition, GList * chapters, GstEbmlWrite * ebml,
3092 guint64 * master_chapters)
3094 guint64 master_edition = 0;
3097 GstTocEntry *internal_edition, *internal_chapter;
3098 GstTagList *tags = NULL;
3100 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT,
3101 gst_matroska_mux_create_uid (mux));
3103 if (edition != NULL) {
3104 /* Edition entry defined, get its tags */
3105 tags = gst_toc_entry_get_tags (edition);
3107 tags = gst_tag_list_copy (tags);
3111 internal_edition = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, s_uid);
3113 gst_toc_entry_set_tags (internal_edition, tags);
3116 for (cur = g_list_first (chapters); cur != NULL; cur = cur->next) {
3117 internal_chapter = gst_matroska_mux_write_chapter (mux, internal_edition,
3118 cur->data, ebml, master_chapters, &master_edition);
3120 gst_toc_entry_append_sub_entry (internal_edition, internal_chapter);
3123 if (G_LIKELY (master_edition != 0))
3124 gst_ebml_write_master_finish (ebml, master_edition);
3126 return internal_edition;
3130 * gst_matroska_mux_start:
3131 * @mux: #GstMatroskaMux
3133 * Start a new matroska file (write headers etc...)
3136 gst_matroska_mux_start (GstMatroskaMux * mux, GstMatroskaPad * first_pad,
3137 GstBuffer * first_pad_buf)
3139 GstEbmlWrite *ebml = mux->ebml_write;
3140 const gchar *doctype;
3141 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
3142 GST_MATROSKA_ID_TRACKS,
3143 GST_MATROSKA_ID_CHAPTERS,
3144 GST_MATROSKA_ID_CUES,
3145 GST_MATROSKA_ID_TAGS,
3148 const gchar *media_type;
3149 gboolean audio_only;
3150 guint64 master, child;
3154 GstClockTime earliest_time = GST_CLOCK_TIME_NONE;
3155 GstClockTime duration = 0;
3156 guint32 segment_uid[4];
3161 /* if not streaming, check if downstream is seekable */
3162 if (!mux->ebml_write->streamable) {
3166 query = gst_query_new_seeking (GST_FORMAT_BYTES);
3167 if (gst_pad_peer_query (mux->srcpad, query)) {
3168 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3169 GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
3171 /* assume seeking is not supported if query not handled downstream */
3172 GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
3176 mux->ebml_write->streamable = TRUE;
3177 g_object_notify (G_OBJECT (mux), "streamable");
3178 GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
3179 "streamable=false. Will ignore that and create streamable output "
3182 gst_query_unref (query);
3185 /* stream-start (FIXME: create id based on input ids) */
3186 g_snprintf (s_id, sizeof (s_id), "matroskamux-%08x", g_random_int ());
3187 gst_pad_push_event (mux->srcpad, gst_event_new_stream_start (s_id));
3190 audio_only = mux->num_v_streams == 0 && mux->num_a_streams > 0;
3192 media_type = (audio_only) ? "audio/webm" : "video/webm";
3194 media_type = (audio_only) ? "audio/x-matroska" : "video/x-matroska";
3196 ebml->caps = gst_caps_new_empty_simple (media_type);
3197 gst_pad_set_caps (mux->srcpad, ebml->caps);
3198 /* we start with a EBML header */
3199 doctype = mux->doctype;
3200 GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
3201 doctype, mux->doctype_version);
3202 gst_ebml_write_header (ebml, doctype, mux->doctype_version);
3204 /* the rest of the header is cached */
3205 gst_ebml_write_set_cache (ebml, 0x1000);
3207 /* start a segment */
3209 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
3210 mux->segment_master = ebml->pos;
3212 if (!mux->ebml_write->streamable) {
3213 /* seekhead (table of contents) - we set the positions later */
3214 mux->seekhead_pos = ebml->pos;
3215 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
3216 for (i = 0; seekhead_id[i] != 0; i++) {
3217 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
3218 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
3219 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
3220 gst_ebml_write_master_finish (ebml, child);
3222 gst_ebml_write_master_finish (ebml, master);
3225 if (mux->ebml_write->streamable) {
3226 const GstTagList *tags;
3227 gboolean has_main_tags;
3230 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3231 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3233 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux)) {
3234 guint64 master_tags, master_tag;
3236 GST_DEBUG_OBJECT (mux, "Writing tags");
3238 mux->tags_pos = ebml->pos;
3239 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3240 if (has_main_tags) {
3241 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3242 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3243 gst_ebml_write_master_finish (ebml, master_tag);
3245 gst_matroska_mux_write_streams_tags (mux);
3246 gst_ebml_write_master_finish (ebml, master_tags);
3251 mux->info_pos = ebml->pos;
3252 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
3254 /* WebM does not support SegmentUID field on SegmentInfo */
3255 if (!mux->is_webm) {
3256 for (i = 0; i < 4; i++) {
3257 segment_uid[i] = g_random_int ();
3259 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
3260 (guint8 *) segment_uid, 16);
3263 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
3264 mux->duration_pos = ebml->pos;
3266 if (!mux->ebml_write->streamable) {
3267 for (collected = mux->collect->data; collected;
3268 collected = g_slist_next (collected)) {
3269 GstMatroskaPad *collect_pad;
3271 gint64 trackduration;
3273 collect_pad = (GstMatroskaPad *) collected->data;
3274 thepad = collect_pad->collect.pad;
3276 /* Query the total length of the track. */
3277 GST_DEBUG_OBJECT (thepad, "querying peer duration");
3278 if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
3279 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
3280 GST_TIME_ARGS (trackduration));
3281 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
3282 duration = (GstClockTime) trackduration;
3286 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3287 gst_guint64_to_gdouble (duration) /
3288 gst_guint64_to_gdouble (mux->time_scale));
3290 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
3291 "GStreamer matroskamux version " PACKAGE_VERSION);
3292 if (mux->writing_app && mux->writing_app[0]) {
3293 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
3295 if (mux->creation_time != NULL) {
3296 time = g_date_time_to_unix (mux->creation_time) * GST_SECOND;
3297 time += g_date_time_get_microsecond (mux->creation_time) * GST_USECOND;
3299 time = g_get_real_time () * GST_USECOND;
3301 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time);
3302 gst_ebml_write_master_finish (ebml, master);
3305 mux->tracks_pos = ebml->pos;
3306 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
3308 for (collected = mux->collect->data; collected;
3309 collected = g_slist_next (collected)) {
3310 GstMatroskaPad *collect_pad;
3313 collect_pad = (GstMatroskaPad *) collected->data;
3315 /* This will cause an error at a later time */
3316 if (collect_pad->track->codec_id == NULL)
3319 /* Find the smallest timestamp so we can offset all streams by this to
3321 if (mux->offset_to_zero) {
3324 if (collect_pad == first_pad)
3325 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3327 buf = gst_collect_pads_peek (mux->collect, collected->data);
3330 ts = gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
3332 if (earliest_time == GST_CLOCK_TIME_NONE)
3334 else if (ts != GST_CLOCK_TIME_NONE && ts < earliest_time)
3339 gst_buffer_unref (buf);
3342 /* For audio tracks, use the first buffers duration as the default
3343 * duration if we didn't get any better idea from the caps event already
3345 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO &&
3346 collect_pad->track->default_duration == 0) {
3347 if (collect_pad == first_pad)
3348 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3350 buf = gst_collect_pads_peek (mux->collect, collected->data);
3352 if (buf && GST_BUFFER_DURATION_IS_VALID (buf))
3353 collect_pad->track->default_duration =
3354 GST_BUFFER_DURATION (buf) + collect_pad->track->codec_delay;
3356 gst_buffer_unref (buf);
3359 collect_pad->track->num = tracknum++;
3360 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
3361 gst_matroska_mux_track_header (mux, collect_pad->track);
3362 gst_ebml_write_master_finish (ebml, child);
3363 /* some remaining pad/track setup */
3364 collect_pad->default_duration_scaled =
3365 gst_util_uint64_scale (collect_pad->track->default_duration,
3366 1, mux->time_scale);
3368 gst_ebml_write_master_finish (ebml, master);
3370 mux->earliest_time = earliest_time == GST_CLOCK_TIME_NONE ? 0 : earliest_time;
3373 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3374 if (toc != NULL && !mux->ebml_write->streamable) {
3375 guint64 master_chapters = 0;
3376 GstTocEntry *internal_edition;
3377 GList *cur, *chapters;
3379 GST_DEBUG ("Writing chapters");
3381 /* There are two UIDs for Chapters:
3382 * - The ChapterUID is a mandatory unsigned integer which internally
3383 * refers to a given chapter. Except for the title & language which use
3384 * dedicated fields, this UID can also be used to add tags to the Chapter.
3385 * The tags come in a separate section of the container.
3386 * - The ChapterStringUID is an optional UTF-8 string which also uniquely
3387 * refers to a chapter but from an external perspective. It can act as a
3388 * "WebVTT cue identifier" which "can be used to reference a specific cue,
3389 * for example from script or CSS".
3391 * The ChapterUID will be generated and checked for unicity, while the
3392 * ChapterStringUID will receive the user defined UID.
3394 * In order to be able to refer to chapters from the tags section,
3395 * we must maintain an internal Toc tree with the generated ChapterUID
3396 * (see gst_matroska_mux_write_toc_entry_tags) */
3398 /* Check whether we have editions or chapters at the root level. */
3399 cur = gst_toc_get_entries (toc);
3401 mux->chapters_pos = ebml->pos;
3403 mux->internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
3405 if (gst_toc_entry_get_entry_type (cur->data) ==
3406 GST_TOC_ENTRY_TYPE_EDITION) {
3407 /* Editions at the root level */
3408 for (; cur != NULL; cur = cur->next) {
3409 chapters = gst_toc_entry_get_sub_entries (cur->data);
3410 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3411 cur->data, chapters, ebml, &master_chapters);
3412 gst_toc_append_entry (mux->internal_toc, internal_edition);
3415 /* Chapters at the root level */
3416 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3417 NULL, cur, ebml, &master_chapters);
3418 gst_toc_append_entry (mux->internal_toc, internal_edition);
3421 /* close master element if any edition was written */
3422 if (G_LIKELY (master_chapters != 0))
3423 gst_ebml_write_master_finish (ebml, master_chapters);
3427 /* lastly, flush the cache */
3428 gst_ebml_write_flush_cache (ebml, FALSE, 0);
3431 gst_toc_unref (toc);
3434 /* TODO: more sensible tag mappings */
3437 const gchar *matroska_tagname;
3438 const gchar *gstreamer_tagname;
3440 gst_matroska_tag_conv[] = {
3442 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
3443 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
3444 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
3445 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
3446 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
3447 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
3448 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
3449 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
3450 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
3451 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
3452 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
3453 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
3454 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
3455 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
3456 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
3459 /* Every stagefright implementation on android up to and including 6.0.1 is using
3460 libwebm with bug in matroska parsing, where it will choke on empty tag elements;
3461 so before outputting tags and tag elements we better make sure that there are
3462 actually tags we are going to write */
3464 gst_matroska_mux_tag_list_is_empty (const GstTagList * list)
3467 for (i = 0; i < gst_tag_list_n_tags (list); i++) {
3468 const gchar *tag = gst_tag_list_nth_tag_name (list, i);
3470 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3471 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3472 if (strcmp (tagname_gst, tag) == 0) {
3473 GValue src = { 0, };
3476 if (!gst_tag_list_copy_value (&src, list, tag))
3478 dest = gst_value_serialize (&src);
3480 g_value_unset (&src);
3492 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
3495 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
3497 guint64 simpletag_master;
3499 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3500 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3501 const gchar *tagname_mkv = gst_matroska_tag_conv[i].matroska_tagname;
3503 if (strcmp (tagname_gst, tag) == 0) {
3504 GValue src = { 0, };
3507 if (!gst_tag_list_copy_value (&src, list, tag))
3509 if ((dest = gst_value_serialize (&src))) {
3511 simpletag_master = gst_ebml_write_master_start (ebml,
3512 GST_MATROSKA_ID_SIMPLETAG);
3513 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
3514 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
3515 gst_ebml_write_master_finish (ebml, simpletag_master);
3518 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
3520 g_value_unset (&src);
3527 gst_matroska_mux_write_stream_tags (GstMatroskaMux * mux, GstMatroskaPad * mpad)
3529 guint64 master_tag, master_targets;
3532 ebml = mux->ebml_write;
3534 if (G_UNLIKELY (mpad->tags == NULL
3535 || gst_matroska_mux_tag_list_is_empty (mpad->tags)))
3538 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3539 master_targets = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3541 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETTRACKUID, mpad->track->uid);
3543 gst_ebml_write_master_finish (ebml, master_targets);
3544 gst_tag_list_foreach (mpad->tags, gst_matroska_mux_write_simple_tag, ebml);
3545 gst_ebml_write_master_finish (ebml, master_tag);
3549 gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux)
3553 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3554 GstMatroskaPad *collect_pad;
3556 collect_pad = (GstMatroskaPad *) walk->data;
3558 gst_matroska_mux_write_stream_tags (mux, collect_pad);
3563 gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux)
3567 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3568 GstMatroskaPad *collect_pad;
3570 collect_pad = (GstMatroskaPad *) walk->data;
3571 if (!gst_matroska_mux_tag_list_is_empty (collect_pad->tags))
3578 gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
3579 const GstTocEntry * entry, guint64 * master_tags, gboolean * has_tags)
3581 guint64 master_tag, master_targets;
3584 const GstTagList *tags;
3586 ebml = mux->ebml_write;
3588 tags = gst_toc_entry_get_tags (entry);
3589 if (G_UNLIKELY (tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags))) {
3592 if (*master_tags == 0) {
3593 mux->tags_pos = ebml->pos;
3594 *master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3597 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3599 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3601 if (gst_toc_entry_get_entry_type (entry) == GST_TOC_ENTRY_TYPE_EDITION)
3602 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETEDITIONUID,
3603 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3605 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETCHAPTERUID,
3606 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3608 gst_ebml_write_master_finish (ebml, master_targets);
3609 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3610 gst_ebml_write_master_finish (ebml, master_tag);
3613 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3615 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, master_tags,
3621 * gst_matroska_mux_finish:
3622 * @mux: #GstMatroskaMux
3624 * Finish a new matroska file (write index etc...)
3627 gst_matroska_mux_finish (GstMatroskaMux * mux)
3629 GstEbmlWrite *ebml = mux->ebml_write;
3631 guint64 duration = 0;
3633 const GstTagList *tags, *toc_tags;
3635 gboolean has_main_tags, toc_has_tags = FALSE;
3638 /* finish last cluster */
3640 gst_ebml_write_master_finish (ebml, mux->cluster);
3644 if (mux->index != NULL) {
3646 guint64 master, pointentry_master, trackpos_master;
3648 mux->cues_pos = ebml->pos;
3649 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
3650 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
3652 for (n = 0; n < mux->num_indexes; n++) {
3653 GstMatroskaIndex *idx = &mux->index[n];
3655 pointentry_master = gst_ebml_write_master_start (ebml,
3656 GST_MATROSKA_ID_POINTENTRY);
3657 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
3658 idx->time / mux->time_scale);
3659 trackpos_master = gst_ebml_write_master_start (ebml,
3660 GST_MATROSKA_ID_CUETRACKPOSITIONS);
3661 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
3662 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
3663 idx->pos - mux->segment_master);
3664 gst_ebml_write_master_finish (ebml, trackpos_master);
3665 gst_ebml_write_master_finish (ebml, pointentry_master);
3668 gst_ebml_write_master_finish (ebml, master);
3669 gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
3673 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3674 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3675 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3677 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux) || toc != NULL) {
3678 guint64 master_tags = 0, master_tag;
3680 GST_DEBUG_OBJECT (mux, "Writing tags");
3682 if (has_main_tags) {
3683 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
3684 mux->tags_pos = ebml->pos;
3685 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3686 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3689 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3690 if (mux->internal_toc != NULL) {
3691 toc_tags = gst_toc_get_tags (mux->internal_toc);
3692 toc_has_tags = (toc_tags != NULL);
3693 gst_tag_list_foreach (toc_tags, gst_matroska_mux_write_simple_tag,
3697 gst_ebml_write_master_finish (ebml, master_tag);
3700 if (mux->internal_toc != NULL) {
3701 for (cur = gst_toc_get_entries (mux->internal_toc); cur != NULL;
3703 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, &master_tags,
3708 if (master_tags == 0 && gst_matroska_mux_streams_have_tags (mux)) {
3709 mux->tags_pos = ebml->pos;
3710 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3712 gst_matroska_mux_write_streams_tags (mux);
3714 if (master_tags != 0)
3715 gst_ebml_write_master_finish (ebml, master_tags);
3718 /* update seekhead. We know that:
3719 * - a seekhead contains 5 entries.
3720 * - order of entries is as above.
3721 * - a seekhead has a 4-byte header + 8-byte length
3722 * - each entry is 2-byte master, 2-byte ID pointer,
3723 * 2-byte length pointer, all 8/1-byte length, 4-
3724 * byte ID and 8-byte length pointer, where the
3725 * length pointer starts at 20.
3726 * - all entries are local to the segment (so pos - segment_master).
3727 * - so each entry is at 12 + 20 + num * 28. */
3728 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
3729 mux->info_pos - mux->segment_master);
3730 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
3731 mux->tracks_pos - mux->segment_master);
3732 if (toc != NULL && mux->chapters_pos > 0) {
3733 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
3734 mux->chapters_pos - mux->segment_master);
3737 guint64 my_pos = ebml->pos;
3739 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
3740 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3741 gst_ebml_write_seek (ebml, my_pos);
3743 if (mux->index != NULL) {
3744 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
3745 mux->cues_pos - mux->segment_master);
3748 guint64 my_pos = ebml->pos;
3750 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
3751 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3752 gst_ebml_write_seek (ebml, my_pos);
3755 if (mux->tags_pos != 0 || toc_has_tags) {
3756 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 144,
3757 mux->tags_pos - mux->segment_master);
3760 guint64 my_pos = ebml->pos;
3762 gst_ebml_write_seek (ebml, mux->seekhead_pos + 124);
3763 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3764 gst_ebml_write_seek (ebml, my_pos);
3768 gst_toc_unref (toc);
3772 * - first get the overall duration
3773 * (a released track may have left a duration in here)
3774 * - write some track header data for subtitles
3776 duration = mux->duration;
3778 for (collected = mux->collect->data; collected;
3779 collected = g_slist_next (collected)) {
3780 GstMatroskaPad *collect_pad;
3782 * observed duration, this will never remain GST_CLOCK_TIME_NONE
3783 * since this means buffer without timestamps that is not possible
3785 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
3787 collect_pad = (GstMatroskaPad *) collected->data;
3789 GST_DEBUG_OBJECT (mux,
3790 "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
3791 " end ts %" GST_TIME_FORMAT, collect_pad,
3792 GST_TIME_ARGS (collect_pad->start_ts),
3793 GST_TIME_ARGS (collect_pad->end_ts));
3795 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
3796 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
3797 collected_duration =
3798 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
3799 GST_DEBUG_OBJECT (collect_pad->collect.pad,
3800 "final track duration: %" GST_TIME_FORMAT,
3801 GST_TIME_ARGS (collected_duration));
3803 GST_WARNING_OBJECT (collect_pad->collect.pad,
3804 "unable to get final track duration");
3806 if (GST_CLOCK_TIME_IS_VALID (collected_duration) &&
3807 duration < collected_duration)
3808 duration = collected_duration;
3812 /* seek back (optional, but do anyway) */
3813 gst_ebml_write_seek (ebml, pos);
3815 /* update duration */
3816 if (duration != 0) {
3817 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
3818 GST_TIME_ARGS (duration));
3819 pos = mux->ebml_write->pos;
3820 gst_ebml_write_seek (ebml, mux->duration_pos);
3821 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3822 gst_guint64_to_gdouble (duration) /
3823 gst_guint64_to_gdouble (mux->time_scale));
3824 gst_ebml_write_seek (ebml, pos);
3827 guint64 my_pos = ebml->pos;
3829 gst_ebml_write_seek (ebml, mux->duration_pos);
3830 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
3831 gst_ebml_write_seek (ebml, my_pos);
3833 GST_DEBUG_OBJECT (mux, "finishing segment");
3834 /* finish segment - this also writes element length */
3835 gst_ebml_write_master_finish (ebml, mux->segment_pos);
3839 * gst_matroska_mux_buffer_header:
3840 * @track: Track context.
3841 * @relative_timestamp: relative timestamp of the buffer
3842 * @flags: Buffer flags.
3844 * Create a buffer containing buffer header.
3846 * Returns: New buffer.
3849 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
3850 gint16 relative_timestamp, int flags)
3853 guint8 *data = g_malloc (4);
3855 hdr = gst_buffer_new_wrapped (data, 4);
3856 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
3857 data[0] = track->num | 0x80;
3858 /* time relative to clustertime */
3859 GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
3867 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
3868 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
3869 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
3872 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
3873 GstMatroskaPad * collect_pad, GstBuffer * buf)
3875 GstMatroskaTrackVideoContext *ctx =
3876 (GstMatroskaTrackVideoContext *) collect_pad->track;
3881 guint32 next_parse_offset;
3882 GstBuffer *ret = NULL;
3883 gboolean is_muxing_unit = FALSE;
3885 gst_buffer_map (buf, &map, GST_MAP_READ);
3890 gst_buffer_unmap (buf, &map);
3891 gst_buffer_unref (buf);
3895 /* Check if this buffer contains a picture or end-of-sequence packet */
3896 while (size >= 13) {
3897 if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
3898 gst_buffer_unmap (buf, &map);
3899 gst_buffer_unref (buf);
3903 parse_code = GST_READ_UINT8 (data + 4);
3904 if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
3905 if (ctx->dirac_unit) {
3906 gst_buffer_unref (ctx->dirac_unit);
3907 ctx->dirac_unit = NULL;
3909 } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
3910 parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
3911 is_muxing_unit = TRUE;
3915 next_parse_offset = GST_READ_UINT32_BE (data + 5);
3917 if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
3920 data += next_parse_offset;
3921 size -= next_parse_offset;
3924 if (ctx->dirac_unit)
3925 ctx->dirac_unit = gst_buffer_append (ctx->dirac_unit, gst_buffer_ref (buf));
3927 ctx->dirac_unit = gst_buffer_ref (buf);
3929 gst_buffer_unmap (buf, &map);
3931 if (is_muxing_unit) {
3932 ret = gst_buffer_make_writable (ctx->dirac_unit);
3933 ctx->dirac_unit = NULL;
3934 gst_buffer_copy_into (ret, buf,
3935 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
3936 gst_buffer_unref (buf);
3938 gst_buffer_unref (buf);
3946 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
3950 GValue streamheader = { 0 };
3951 GValue bufval = { 0 };
3952 GstBuffer *streamheader_buffer;
3953 GstEbmlWrite *ebml = mux->ebml_write;
3955 streamheader_buffer = gst_ebml_stop_streamheader (ebml);
3956 caps = gst_caps_copy (mux->ebml_write->caps);
3957 s = gst_caps_get_structure (caps, 0);
3958 g_value_init (&streamheader, GST_TYPE_ARRAY);
3959 g_value_init (&bufval, GST_TYPE_BUFFER);
3960 GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_HEADER);
3961 gst_value_set_buffer (&bufval, streamheader_buffer);
3962 gst_value_array_append_value (&streamheader, &bufval);
3963 g_value_unset (&bufval);
3964 gst_structure_set_value (s, "streamheader", &streamheader);
3965 g_value_unset (&streamheader);
3966 gst_caps_replace (&ebml->caps, caps);
3967 gst_buffer_unref (streamheader_buffer);
3968 gst_pad_set_caps (mux->srcpad, caps);
3969 gst_caps_unref (caps);
3973 * gst_matroska_mux_write_data:
3974 * @mux: #GstMatroskaMux
3975 * @collect_pad: #GstMatroskaPad with the data
3977 * Write collected data (called from gst_matroska_mux_collected).
3979 * Returns: Result of the gst_pad_push issued to write the data.
3981 static GstFlowReturn
3982 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
3985 GstEbmlWrite *ebml = mux->ebml_write;
3988 gboolean write_duration;
3989 guint64 cluster_time_scaled;
3990 gint16 relative_timestamp;
3991 gint64 relative_timestamp64;
3992 guint64 block_duration, duration_diff = 0;
3993 gboolean is_video_keyframe = FALSE;
3994 gboolean is_video_invisible = FALSE;
3995 gboolean is_audio_only = FALSE;
3996 gboolean is_min_duration_reached = FALSE;
3997 gboolean is_max_duration_exceeded = FALSE;
3998 GstMatroskamuxPad *pad;
4000 GstClockTime buffer_timestamp;
4001 GstAudioClippingMeta *cmeta = NULL;
4004 pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
4006 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
4007 if (collect_pad->track->xiph_headers_to_skip > 0) {
4008 --collect_pad->track->xiph_headers_to_skip;
4009 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER)) {
4010 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
4011 gst_buffer_unref (buf);
4016 /* for dirac we have to queue up everything up to a picture unit */
4017 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC)) {
4018 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
4021 } else if (!strcmp (collect_pad->track->codec_id,
4022 GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) {
4023 /* Remove the 'Frame container atom' header' */
4024 buf = gst_buffer_make_writable (buf);
4025 gst_buffer_resize (buf, 8, gst_buffer_get_size (buf) - 8);
4029 gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
4030 if (buffer_timestamp >= mux->earliest_time) {
4031 buffer_timestamp -= mux->earliest_time;
4033 buffer_timestamp = 0;
4036 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
4037 * this would wreak havoc with time stored in matroska file */
4038 /* TODO: maybe calculate a timestamp by using the previous timestamp
4039 * and default duration */
4040 if (!GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
4041 GST_WARNING_OBJECT (collect_pad->collect.pad,
4042 "Invalid buffer timestamp; dropping buffer");
4043 gst_buffer_unref (buf);
4047 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4048 && collect_pad->track->codec_delay) {
4049 /* All timestamps should include the codec delay */
4050 if (buffer_timestamp > collect_pad->track->codec_delay) {
4051 buffer_timestamp += collect_pad->track->codec_delay;
4053 buffer_timestamp = 0;
4054 duration_diff = collect_pad->track->codec_delay - buffer_timestamp;
4058 /* set the timestamp for outgoing buffers */
4059 ebml->timestamp = buffer_timestamp;
4061 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
4062 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
4063 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
4064 GST_TIME_ARGS (buffer_timestamp));
4065 is_video_keyframe = TRUE;
4066 } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DECODE_ONLY) &&
4067 (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP8)
4068 || !strcmp (collect_pad->track->codec_id,
4069 GST_MATROSKA_CODEC_ID_VIDEO_VP9))) {
4070 GST_LOG_OBJECT (mux,
4071 "have VP8 video invisible frame, " "ts=%" GST_TIME_FORMAT,
4072 GST_TIME_ARGS (buffer_timestamp));
4073 is_video_invisible = TRUE;
4077 /* From this point on we use the buffer_timestamp to do cluster and other
4078 * related arithmetic, so apply the timestamp offset if we have one */
4079 buffer_timestamp += mux->cluster_timestamp_offset;
4081 is_audio_only = (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
4082 (mux->num_streams == 1);
4083 is_min_duration_reached = (mux->min_cluster_duration == 0
4084 || (buffer_timestamp > mux->cluster_time
4085 && (buffer_timestamp - mux->cluster_time) >=
4086 mux->min_cluster_duration));
4087 is_max_duration_exceeded = (mux->max_cluster_duration > 0
4088 && buffer_timestamp > mux->cluster_time
4089 && (buffer_timestamp - mux->cluster_time) >=
4090 MIN (G_MAXINT16 * mux->time_scale, mux->max_cluster_duration));
4093 /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
4094 * or when we may be reaching the limit of the relative timestamp */
4095 if (is_max_duration_exceeded || (is_video_keyframe
4096 && is_min_duration_reached) || mux->force_key_unit_event
4097 || (is_audio_only && is_min_duration_reached)) {
4098 if (!mux->ebml_write->streamable)
4099 gst_ebml_write_master_finish (ebml, mux->cluster);
4101 /* Forward the GstForceKeyUnit event after finishing the cluster */
4102 if (mux->force_key_unit_event) {
4103 gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
4104 mux->force_key_unit_event = NULL;
4106 cluster_time_scaled =
4107 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4109 mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
4110 mux->cluster_pos = ebml->pos;
4111 gst_ebml_write_set_cache (ebml, 0x20);
4113 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4114 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4115 cluster_time_scaled);
4116 GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
4117 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
4118 gst_ebml_write_flush_cache (ebml, is_video_keyframe
4119 || is_audio_only, buffer_timestamp);
4120 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
4121 mux->prev_cluster_size);
4122 /* cluster_time needs to be identical in value to what's stored in the
4123 * matroska so we need to have it with the same precision as what's
4124 * possible with the set timecodescale rather than just using the
4126 * If this is not done the rounding of relative_timestamp will be
4127 * incorrect and possibly making the timestamps get out of order if tw
4128 * buffers arrive at the same millisecond (assuming default timecodescale
4131 gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4135 cluster_time_scaled =
4136 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4137 mux->cluster_pos = ebml->pos;
4138 gst_ebml_write_set_cache (ebml, 0x20);
4139 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4140 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4141 cluster_time_scaled);
4142 gst_ebml_write_flush_cache (ebml, TRUE, buffer_timestamp);
4143 /* cluster_time needs to be identical in value to what's stored in the
4144 * matroska so we need to have it with the same precision as what's
4145 * possible with the set timecodescale rather than just using the
4147 * If this is not done the rounding of relative_timestamp will be
4148 * incorrect and possibly making the timestamps get out of order if tw
4149 * buffers arrive at the same millisecond (assuming default timecodescale
4152 gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4155 /* We currently write index entries for all video tracks or for the audio
4156 * track in a single-track audio file. This could be improved by keeping the
4157 * index only for the *first* video track. */
4159 /* TODO: index is useful for every track, should contain the number of
4160 * the block in the cluster which contains the timestamp, should also work
4161 * for files with multiple audio tracks.
4163 if (!mux->ebml_write->streamable && (is_video_keyframe || is_audio_only)) {
4166 if (mux->min_index_interval != 0) {
4167 for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
4168 if (mux->index[last_idx].track == collect_pad->track->num)
4173 if (last_idx < 0 || mux->min_index_interval == 0 ||
4174 (GST_CLOCK_DIFF (mux->index[last_idx].time, buffer_timestamp)
4175 >= mux->min_index_interval)) {
4176 GstMatroskaIndex *idx;
4178 if (mux->num_indexes % 32 == 0) {
4179 mux->index = g_renew (GstMatroskaIndex, mux->index,
4180 mux->num_indexes + 32);
4182 idx = &mux->index[mux->num_indexes++];
4184 idx->pos = mux->cluster_pos;
4185 idx->time = buffer_timestamp;
4186 idx->track = collect_pad->track->num;
4190 /* Check if the duration differs from the default duration. */
4191 write_duration = FALSE;
4193 if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
4194 block_duration = GST_BUFFER_DURATION (buf) + duration_diff;
4195 block_duration = gst_util_uint64_scale (block_duration, 1, mux->time_scale);
4197 /* small difference should be ok. */
4198 if (block_duration > collect_pad->default_duration_scaled + 1 ||
4199 block_duration < collect_pad->default_duration_scaled - 1) {
4200 write_duration = TRUE;
4204 /* write the block, for doctype v2 use SimpleBlock if possible
4205 * one slice (*breath*).
4206 * FIXME: Need to do correct lacing! */
4207 relative_timestamp64 = buffer_timestamp - mux->cluster_time;
4208 if (relative_timestamp64 >= 0) {
4209 /* round the timestamp */
4210 relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
4211 relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
4214 /* round the timestamp */
4215 relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
4216 relative_timestamp =
4217 -((gint16) gst_util_uint64_scale (-relative_timestamp64, 1,
4221 if (is_video_invisible)
4224 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
4225 cmeta = gst_buffer_get_audio_clipping_meta (buf);
4226 g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);
4228 /* Start clipping is done via header and CodecDelay */
4229 if (cmeta && !cmeta->end)
4233 if (mux->doctype_version > 1 && !write_duration && !cmeta) {
4234 if (is_video_keyframe)
4238 gst_matroska_mux_create_buffer_header (collect_pad->track,
4239 relative_timestamp, flags);
4240 gst_ebml_write_set_cache (ebml, 0x40);
4241 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
4242 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4243 gst_ebml_write_buffer (ebml, hdr);
4244 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4245 gst_ebml_write_buffer (ebml, buf);
4247 return gst_ebml_last_write_result (ebml);
4249 gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
4250 /* write and call order slightly unnatural,
4251 * but avoids seek and minizes pushing */
4252 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
4254 gst_matroska_mux_create_buffer_header (collect_pad->track,
4255 relative_timestamp, flags);
4257 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
4259 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4261 /* Start clipping is done via header and CodecDelay */
4264 gst_util_uint64_scale_round (cmeta->end, GST_SECOND, 48000);
4265 gst_ebml_write_sint (ebml, GST_MATROSKA_ID_DISCARDPADDING, end);
4269 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
4270 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4271 gst_ebml_write_buffer (ebml, hdr);
4272 gst_ebml_write_master_finish_full (ebml, blockgroup,
4273 gst_buffer_get_size (buf));
4274 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4275 gst_ebml_write_buffer (ebml, buf);
4277 return gst_ebml_last_write_result (ebml);
4282 * gst_matroska_mux_handle_buffer:
4283 * @pads: #GstCollectPads
4284 * @uuser_data: #GstMatroskaMux
4286 * Collectpads callback.
4288 * Returns: #GstFlowReturn
4290 static GstFlowReturn
4291 gst_matroska_mux_handle_buffer (GstCollectPads * pads, GstCollectData * data,
4292 GstBuffer * buf, gpointer user_data)
4294 GstClockTime buffer_timestamp;
4295 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
4296 GstEbmlWrite *ebml = mux->ebml_write;
4297 GstMatroskaPad *best = (GstMatroskaPad *) data;
4298 GstFlowReturn ret = GST_FLOW_OK;
4299 GST_DEBUG_OBJECT (mux, "Collected pads");
4301 /* start with a header */
4302 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
4303 if (mux->collect->data == NULL) {
4304 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
4305 ("No input streams configured"));
4306 return GST_FLOW_ERROR;
4308 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
4309 gst_ebml_start_streamheader (ebml);
4310 gst_matroska_mux_start (mux, best, buf);
4311 gst_matroska_mux_stop_streamheader (mux);
4312 mux->state = GST_MATROSKA_MUX_STATE_DATA;
4315 /* if there is no best pad, we have reached EOS */
4317 GST_DEBUG_OBJECT (mux, "No best pad. Finishing...");
4318 if (!mux->ebml_write->streamable) {
4319 gst_matroska_mux_finish (mux);
4321 GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
4323 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
4328 if (best->track->codec_id == NULL) {
4329 GST_ERROR_OBJECT (best->collect.pad, "No codec-id for pad");
4330 ret = GST_FLOW_NOT_NEGOTIATED;
4334 /* if we have a best stream, should also have a buffer */
4337 buffer_timestamp = gst_matroska_track_get_buffer_timestamp (best->track, buf);
4338 if (buffer_timestamp >= mux->earliest_time) {
4339 buffer_timestamp -= mux->earliest_time;
4341 GST_ERROR_OBJECT (mux,
4342 "PTS before first PTS (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")",
4343 GST_TIME_ARGS (buffer_timestamp), GST_TIME_ARGS (mux->earliest_time));
4344 buffer_timestamp = 0;
4347 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
4348 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
4349 GST_TIME_ARGS (buffer_timestamp),
4350 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
4352 /* make note of first and last encountered timestamps, so we can calculate
4353 * the actual duration later when we send an updated header on eos */
4354 if (GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
4355 GstClockTime start_ts = buffer_timestamp;
4356 GstClockTime end_ts = start_ts;
4358 if (GST_BUFFER_DURATION_IS_VALID (buf))
4359 end_ts += GST_BUFFER_DURATION (buf);
4360 else if (best->track->default_duration)
4361 end_ts += best->track->default_duration;
4363 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
4364 best->end_ts = end_ts;
4366 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
4367 start_ts < best->start_ts))
4368 best->start_ts = start_ts;
4371 /* write one buffer */
4372 ret = gst_matroska_mux_write_data (mux, best, buf);
4380 * gst_matroska_mux_change_state:
4381 * @element: #GstMatroskaMux
4382 * @transition: State change transition.
4384 * Change the muxer state.
4386 * Returns: #GstStateChangeReturn
4388 static GstStateChangeReturn
4389 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
4391 GstStateChangeReturn ret;
4392 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
4394 switch (transition) {
4395 case GST_STATE_CHANGE_NULL_TO_READY:
4397 case GST_STATE_CHANGE_READY_TO_PAUSED:
4398 gst_collect_pads_start (mux->collect);
4400 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4402 case GST_STATE_CHANGE_PAUSED_TO_READY:
4403 gst_collect_pads_stop (mux->collect);
4409 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4411 switch (transition) {
4412 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4414 case GST_STATE_CHANGE_PAUSED_TO_READY:
4415 gst_matroska_mux_reset (GST_ELEMENT (mux));
4417 case GST_STATE_CHANGE_READY_TO_NULL:
4427 gst_matroska_mux_set_property (GObject * object,
4428 guint prop_id, const GValue * value, GParamSpec * pspec)
4430 GstMatroskaMux *mux;
4432 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4433 mux = GST_MATROSKA_MUX (object);
4436 case PROP_WRITING_APP:
4437 if (!g_value_get_string (value)) {
4438 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
4441 g_free (mux->writing_app);
4442 mux->writing_app = g_value_dup_string (value);
4444 case PROP_DOCTYPE_VERSION:
4445 mux->doctype_version = g_value_get_int (value);
4447 case PROP_MIN_INDEX_INTERVAL:
4448 mux->min_index_interval = g_value_get_int64 (value);
4450 case PROP_STREAMABLE:
4451 mux->ebml_write->streamable = g_value_get_boolean (value);
4453 case PROP_TIMECODESCALE:
4454 mux->time_scale = g_value_get_int64 (value);
4456 case PROP_MIN_CLUSTER_DURATION:
4457 mux->min_cluster_duration = g_value_get_int64 (value);
4459 case PROP_MAX_CLUSTER_DURATION:
4460 mux->max_cluster_duration = g_value_get_int64 (value);
4462 case PROP_OFFSET_TO_ZERO:
4463 mux->offset_to_zero = g_value_get_boolean (value);
4465 case PROP_CREATION_TIME:
4466 g_clear_pointer (&mux->creation_time, g_date_time_unref);
4467 mux->creation_time = g_value_dup_boxed (value);
4469 case PROP_CLUSTER_TIMESTAMP_OFFSET:
4470 mux->cluster_timestamp_offset = g_value_get_uint64 (value);
4473 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4479 gst_matroska_mux_get_property (GObject * object,
4480 guint prop_id, GValue * value, GParamSpec * pspec)
4482 GstMatroskaMux *mux;
4484 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4485 mux = GST_MATROSKA_MUX (object);
4488 case PROP_WRITING_APP:
4489 g_value_set_string (value, mux->writing_app);
4491 case PROP_DOCTYPE_VERSION:
4492 g_value_set_int (value, mux->doctype_version);
4494 case PROP_MIN_INDEX_INTERVAL:
4495 g_value_set_int64 (value, mux->min_index_interval);
4497 case PROP_STREAMABLE:
4498 g_value_set_boolean (value, mux->ebml_write->streamable);
4500 case PROP_TIMECODESCALE:
4501 g_value_set_int64 (value, mux->time_scale);
4503 case PROP_MIN_CLUSTER_DURATION:
4504 g_value_set_int64 (value, mux->min_cluster_duration);
4506 case PROP_MAX_CLUSTER_DURATION:
4507 g_value_set_int64 (value, mux->max_cluster_duration);
4509 case PROP_OFFSET_TO_ZERO:
4510 g_value_set_boolean (value, mux->offset_to_zero);
4512 case PROP_CREATION_TIME:
4513 g_value_set_boxed (value, mux->creation_time);
4515 case PROP_CLUSTER_TIMESTAMP_OFFSET:
4516 g_value_set_uint64 (value, mux->cluster_timestamp_offset);
4519 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);