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 /* FIXME: what about stream-specific tags? */
869 if (gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL) {
870 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
871 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
873 gst_tag_list_insert (collect_pad->tags, list, GST_TAG_MERGE_REPLACE);
876 gst_event_unref (event);
877 /* handled this, don't want collectpads to forward it downstream */
883 GstToc *toc, *old_toc;
885 if (mux->chapters_pos > 0)
888 GST_DEBUG_OBJECT (mux, "received toc event");
889 gst_event_parse_toc (event, &toc, NULL);
892 old_toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
893 if (old_toc != NULL) {
895 GST_INFO_OBJECT (pad, "Replacing TOC with a new one");
896 gst_toc_unref (old_toc);
899 gst_toc_setter_set_toc (GST_TOC_SETTER (mux), toc);
903 gst_event_unref (event);
904 /* handled this, don't want collectpads to forward it downstream */
908 case GST_EVENT_CUSTOM_DOWNSTREAM:
909 case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY:{
910 const GstStructure *structure;
912 structure = gst_event_get_structure (event);
913 if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
914 gst_event_replace (&mux->force_key_unit_event, NULL);
915 mux->force_key_unit_event = event;
917 } else if (gst_structure_has_name (structure, "application/x-gst-dvd") &&
918 !strcmp ("dvd-spu-clut-change",
919 gst_structure_get_string (structure, "event"))) {
924 GST_DEBUG_OBJECT (pad, "New DVD colour table received");
925 if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
926 GST_DEBUG_OBJECT (pad, "... discarding");
929 /* first transform event data into table form */
930 for (i = 0; i < 16; i++) {
931 g_snprintf (name, sizeof (name), "clut%02d", i);
932 if (!gst_structure_get_int (structure, name, &value)) {
933 GST_ERROR_OBJECT (mux, "dvd-spu-clut-change event did not "
934 "contain %s field", name);
940 /* transform into private data for stream; text form */
941 gst_matroska_mux_build_vobsub_private (context, clut);
951 return gst_collect_pads_event_default (pads, data, event, FALSE);
957 gst_matroska_mux_set_codec_id (GstMatroskaTrackContext * context,
960 g_assert (context && id);
961 g_free (context->codec_id);
962 context->codec_id = g_strdup (id);
966 check_field (GQuark field_id, const GValue * value, gpointer user_data)
968 GstStructure *structure = (GstStructure *) user_data;
969 const gchar *name = gst_structure_get_name (structure);
971 if ((g_strcmp0 (name, "video/x-h264") == 0 &&
972 !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
973 "avc3")) || (g_strcmp0 (name, "video/x-h265") == 0
974 && !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
977 /* While in theory, matroska only supports avc1 / hvc1, and doesn't support codec_data
978 * changes, in practice most decoders will use in-band SPS / PPS (avc3 / hev1), if the
979 * input stream is avc3 / hev1 we let the new codec_data slide to support "smart" encoding.
981 * We don't warn here as we already warned elsewhere.
983 if (field_id == g_quark_from_static_string ("codec_data")) {
985 } else if (field_id == g_quark_from_static_string ("tier")) {
987 } else if (field_id == g_quark_from_static_string ("profile")) {
989 } else if (field_id == g_quark_from_static_string ("level")) {
992 } else if (gst_structure_has_name (structure, "video/x-vp8")
993 || gst_structure_has_name (structure, "video/x-vp9")) {
994 /* We do not use profile and streamheader for VPX so let it change
996 if (field_id == g_quark_from_static_string ("streamheader"))
998 else if (field_id == g_quark_from_static_string ("profile"))
1002 /* This fields aren't used and are not retained into the bitstream so we can
1004 if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) {
1005 if (field_id == g_quark_from_static_string ("chroma-site"))
1007 else if (field_id == g_quark_from_static_string ("chroma-format"))
1009 else if (field_id == g_quark_from_static_string ("bit-depth-luma"))
1017 check_new_caps (GstCaps * old_caps, GstCaps * new_caps)
1019 GstStructure *old_s, *new_s;
1022 old_caps = gst_caps_copy (old_caps);
1023 new_caps = gst_caps_copy (new_caps);
1025 new_s = gst_caps_get_structure (new_caps, 0);
1026 old_s = gst_caps_get_structure (old_caps, 0);
1028 gst_structure_filter_and_map_in_place (new_s,
1029 (GstStructureFilterMapFunc) check_field, new_s);
1030 gst_structure_filter_and_map_in_place (old_s,
1031 (GstStructureFilterMapFunc) check_field, old_s);
1033 ret = gst_caps_is_subset (new_caps, old_caps);
1035 gst_caps_unref (new_caps);
1036 gst_caps_unref (old_caps);
1042 * gst_matroska_mux_video_pad_setcaps:
1043 * @pad: Pad which got the caps.
1046 * Setcaps function for video sink pad.
1048 * Returns: %TRUE on success.
1051 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
1053 GstMatroskaTrackContext *context = NULL;
1054 GstMatroskaTrackVideoContext *videocontext;
1055 GstMatroskaMux *mux;
1056 GstMatroskaPad *collect_pad;
1057 GstStructure *structure;
1058 const gchar *mimetype;
1059 const gchar *interlace_mode, *s;
1060 const GValue *value = NULL;
1061 GstBuffer *codec_buf = NULL;
1062 gint width, height, pixel_width, pixel_height;
1064 guint multiview_flags;
1067 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1069 if ((old_caps = gst_pad_get_current_caps (pad))) {
1070 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1071 && !check_new_caps (old_caps, caps)) {
1072 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1073 ("Caps changes are not supported by Matroska\nCurrent: `%"
1074 GST_PTR_FORMAT "`\nNew: `%" GST_PTR_FORMAT "`", old_caps, caps));
1075 gst_caps_unref (old_caps);
1078 gst_caps_unref (old_caps);
1079 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
1080 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1081 ("Caps on pad %" GST_PTR_FORMAT
1082 " arrived late. Headers were already written", pad));
1087 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1088 g_assert (collect_pad);
1089 context = collect_pad->track;
1091 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
1092 videocontext = (GstMatroskaTrackVideoContext *) context;
1094 /* gst -> matroska ID'ing */
1095 structure = gst_caps_get_structure (caps, 0);
1097 mimetype = gst_structure_get_name (structure);
1099 interlace_mode = gst_structure_get_string (structure, "interlace-mode");
1100 if (interlace_mode != NULL) {
1101 if (strcmp (interlace_mode, "progressive") == 0)
1102 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE;
1104 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_INTERLACED;
1106 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_UNKNOWN;
1109 if (!strcmp (mimetype, "video/x-theora")) {
1110 /* we'll extract the details later from the theora identification header */
1114 /* get general properties */
1115 /* spec says it is mandatory */
1116 if (!gst_structure_get_int (structure, "width", &width) ||
1117 !gst_structure_get_int (structure, "height", &height))
1120 videocontext->pixel_width = width;
1121 videocontext->pixel_height = height;
1123 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
1124 && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
1126 context->default_duration =
1127 gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
1128 GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
1129 GST_TIME_ARGS (context->default_duration));
1131 context->default_duration = 0;
1133 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
1134 &pixel_width, &pixel_height)) {
1135 if (pixel_width > pixel_height) {
1136 videocontext->display_width = width * pixel_width / pixel_height;
1137 videocontext->display_height = height;
1138 } else if (pixel_width < pixel_height) {
1139 videocontext->display_width = width;
1140 videocontext->display_height = height * pixel_height / pixel_width;
1142 videocontext->display_width = 0;
1143 videocontext->display_height = 0;
1146 videocontext->display_width = 0;
1147 videocontext->display_height = 0;
1150 if ((s = gst_structure_get_string (structure, "colorimetry"))) {
1151 if (!gst_video_colorimetry_from_string (&videocontext->colorimetry, s)) {
1152 GST_WARNING_OBJECT (pad, "Could not parse colorimetry %s", s);
1156 if ((s = gst_structure_get_string (structure, "mastering-display-info"))) {
1157 if (!gst_video_mastering_display_info_from_string
1158 (&videocontext->mastering_display_info, s)) {
1159 GST_WARNING_OBJECT (pad, "Could not parse mastering-display-metadata %s",
1162 videocontext->mastering_display_info_present = TRUE;
1166 if ((s = gst_structure_get_string (structure, "content-light-level"))) {
1167 if (!gst_video_content_light_level_from_string
1168 (&videocontext->content_light_level, s))
1169 GST_WARNING_OBJECT (pad, "Could not parse content-light-level %s", s);
1172 /* Collect stereoscopic info, if any */
1173 if ((s = gst_structure_get_string (structure, "multiview-mode")))
1174 videocontext->multiview_mode =
1175 gst_video_multiview_mode_from_caps_string (s);
1176 gst_structure_get_flagset (structure, "multiview-flags", &multiview_flags,
1178 videocontext->multiview_flags = multiview_flags;
1183 videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
1184 videocontext->fourcc = 0;
1186 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1187 * data and other settings
1191 /* extract codec_data, may turn out needed */
1192 value = gst_structure_get_value (structure, "codec_data");
1194 codec_buf = (GstBuffer *) gst_value_get_buffer (value);
1197 if (!strcmp (mimetype, "video/x-raw")) {
1199 gst_matroska_mux_set_codec_id (context,
1200 GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
1201 fstr = gst_structure_get_string (structure, "format");
1203 if (strlen (fstr) == 4)
1204 videocontext->fourcc = GST_STR_FOURCC (fstr);
1205 else if (!strcmp (fstr, "GRAY8"))
1206 videocontext->fourcc = GST_MAKE_FOURCC ('Y', '8', '0', '0');
1207 else if (!strcmp (fstr, "BGR"))
1208 videocontext->fourcc = GST_MAKE_FOURCC ('B', 'G', 'R', 24);
1209 else if (!strcmp (fstr, "RGB"))
1210 videocontext->fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', 24);
1212 } else if (!strcmp (mimetype, "video/x-huffyuv") /* MS/VfW compatibility cases */
1213 ||!strcmp (mimetype, "video/x-divx")
1214 || !strcmp (mimetype, "video/x-dv")
1215 || !strcmp (mimetype, "video/x-h263")
1216 || !strcmp (mimetype, "video/x-msmpeg")
1217 || !strcmp (mimetype, "video/x-wmv")
1218 || !strcmp (mimetype, "image/jpeg")) {
1219 gst_riff_strf_vids *bih;
1220 gint size = sizeof (gst_riff_strf_vids);
1223 if (!strcmp (mimetype, "video/x-huffyuv"))
1224 fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
1225 else if (!strcmp (mimetype, "video/x-dv"))
1226 fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
1227 else if (!strcmp (mimetype, "video/x-h263"))
1228 fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
1229 else if (!strcmp (mimetype, "video/x-divx")) {
1232 gst_structure_get_int (structure, "divxversion", &divxversion);
1233 switch (divxversion) {
1235 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
1238 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
1241 fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
1244 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1247 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
1248 switch (msmpegversion) {
1250 fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
1253 fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
1259 } else if (!strcmp (mimetype, "video/x-wmv")) {
1263 fstr = gst_structure_get_string (structure, "format");
1264 if (fstr && strlen (fstr) == 4) {
1265 fourcc = GST_STR_FOURCC (fstr);
1266 } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
1267 if (wmvversion == 2) {
1268 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
1269 } else if (wmvversion == 1) {
1270 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
1271 } else if (wmvversion == 3) {
1272 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
1275 } else if (!strcmp (mimetype, "image/jpeg")) {
1276 fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
1282 bih = g_new0 (gst_riff_strf_vids, 1);
1283 GST_WRITE_UINT32_LE (&bih->size, size);
1284 GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
1285 GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
1286 GST_WRITE_UINT32_LE (&bih->compression, fourcc);
1287 GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
1288 GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
1289 GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
1290 videocontext->pixel_height * 3);
1292 /* process codec private/initialization data, if any */
1294 size += gst_buffer_get_size (codec_buf);
1295 bih = g_realloc (bih, size);
1296 GST_WRITE_UINT32_LE (&bih->size, size);
1297 gst_buffer_extract (codec_buf, 0,
1298 (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
1301 gst_matroska_mux_set_codec_id (context,
1302 GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
1303 gst_matroska_mux_free_codec_priv (context);
1304 context->codec_priv = (gpointer) bih;
1305 context->codec_priv_size = size;
1306 context->dts_only = TRUE;
1307 } else if (!strcmp (mimetype, "video/x-h264")) {
1308 gst_matroska_mux_set_codec_id (context,
1309 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
1310 gst_matroska_mux_free_codec_priv (context);
1312 if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1314 GST_WARNING_OBJECT (mux,
1315 "avc3 is not officially supported, only use this format for smart encoding");
1318 /* Create avcC header */
1319 if (codec_buf != NULL) {
1320 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1321 context->codec_priv = g_malloc0 (context->codec_priv_size);
1322 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1324 } else if (!strcmp (mimetype, "video/x-h265")) {
1325 gst_matroska_mux_set_codec_id (context,
1326 GST_MATROSKA_CODEC_ID_VIDEO_MPEGH_HEVC);
1327 gst_matroska_mux_free_codec_priv (context);
1329 if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1331 GST_WARNING_OBJECT (mux,
1332 "hev1 is not officially supported, only use this format for smart encoding");
1335 /* Create hvcC header */
1336 if (codec_buf != NULL) {
1337 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1338 context->codec_priv = g_malloc0 (context->codec_priv_size);
1339 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1341 } else if (!strcmp (mimetype, "video/x-theora")) {
1342 const GValue *streamheader;
1344 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
1346 gst_matroska_mux_free_codec_priv (context);
1348 streamheader = gst_structure_get_value (structure, "streamheader");
1349 if (!theora_streamheader_to_codecdata (streamheader, context)) {
1350 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1351 ("theora stream headers missing or malformed"));
1354 } else if (!strcmp (mimetype, "video/x-dirac")) {
1355 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
1356 } else if (!strcmp (mimetype, "video/x-vp8")) {
1357 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP8);
1358 } else if (!strcmp (mimetype, "video/x-vp9")) {
1359 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP9);
1360 } else if (!strcmp (mimetype, "video/x-av1")) {
1361 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_AV1);
1362 gst_matroska_mux_free_codec_priv (context);
1363 /* Create av1C header */
1364 if (codec_buf != NULL)
1365 gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1366 &context->codec_priv, &context->codec_priv_size);
1367 } else if (!strcmp (mimetype, "video/x-ffv")) {
1368 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_FFV1);
1369 gst_matroska_mux_free_codec_priv (context);
1370 if (codec_buf != NULL)
1371 gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1372 &context->codec_priv, &context->codec_priv_size);
1373 } else if (!strcmp (mimetype, "video/mpeg")) {
1376 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1377 switch (mpegversion) {
1379 gst_matroska_mux_set_codec_id (context,
1380 GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
1383 gst_matroska_mux_set_codec_id (context,
1384 GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
1387 gst_matroska_mux_set_codec_id (context,
1388 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
1394 /* global headers may be in codec data */
1395 if (codec_buf != NULL) {
1396 gst_matroska_mux_free_codec_priv (context);
1397 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1398 context->codec_priv = g_malloc0 (context->codec_priv_size);
1399 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1401 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1403 /* can only make it here if preceding case verified it was version 3 */
1404 gst_matroska_mux_set_codec_id (context,
1405 GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
1406 } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
1408 const GValue *mdpr_data;
1410 gst_structure_get_int (structure, "rmversion", &rmversion);
1411 switch (rmversion) {
1413 gst_matroska_mux_set_codec_id (context,
1414 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
1417 gst_matroska_mux_set_codec_id (context,
1418 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
1421 gst_matroska_mux_set_codec_id (context,
1422 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
1425 gst_matroska_mux_set_codec_id (context,
1426 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
1432 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1433 if (mdpr_data != NULL) {
1434 guint8 *priv_data = NULL;
1435 guint priv_data_size = 0;
1437 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1439 priv_data_size = gst_buffer_get_size (codec_data_buf);
1440 priv_data = g_malloc0 (priv_data_size);
1442 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1444 gst_matroska_mux_free_codec_priv (context);
1445 context->codec_priv = priv_data;
1446 context->codec_priv_size = priv_data_size;
1448 } else if (strcmp (mimetype, "video/x-prores") == 0) {
1449 const gchar *variant;
1451 gst_matroska_mux_free_codec_priv (context);
1453 variant = gst_structure_get_string (structure, "format");
1454 if (!variant || !g_strcmp0 (variant, "standard"))
1455 context->codec_priv = g_strdup ("apcn");
1456 else if (!g_strcmp0 (variant, "hq"))
1457 context->codec_priv = g_strdup ("apch");
1458 else if (!g_strcmp0 (variant, "lt"))
1459 context->codec_priv = g_strdup ("apcs");
1460 else if (!g_strcmp0 (variant, "proxy"))
1461 context->codec_priv = g_strdup ("apco");
1462 else if (!g_strcmp0 (variant, "4444"))
1463 context->codec_priv = g_strdup ("ap4h");
1465 GST_WARNING_OBJECT (mux, "Unhandled prores format: %s", variant);
1470 context->codec_priv_size = sizeof (guint32);
1471 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_PRORES);
1479 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1480 GST_PAD_NAME (pad), caps);
1485 /* N > 0 to expect a particular number of headers, negative if the
1486 number of headers is variable */
1488 xiphN_streamheader_to_codecdata (const GValue * streamheader,
1489 GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
1491 GstBuffer **buf = NULL;
1494 guint bufi, i, offset, priv_data_size;
1496 if (streamheader == NULL)
1497 goto no_stream_headers;
1499 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1502 bufarr = g_value_peek_pointer (streamheader);
1503 if (bufarr->len <= 0 || bufarr->len > 255) /* at least one header, and count stored in a byte */
1505 if (N > 0 && bufarr->len != N)
1508 context->xiph_headers_to_skip = bufarr->len;
1510 buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1511 for (i = 0; i < bufarr->len; i++) {
1512 GValue *bufval = &g_array_index (bufarr, GValue, i);
1514 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1516 goto wrong_content_type;
1519 buf[i] = g_value_peek_pointer (bufval);
1523 if (bufarr->len > 0) {
1524 for (i = 0; i < bufarr->len - 1; i++) {
1525 priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
1529 for (i = 0; i < bufarr->len; ++i) {
1530 priv_data_size += gst_buffer_get_size (buf[i]);
1533 priv_data = g_malloc0 (priv_data_size);
1535 priv_data[0] = bufarr->len - 1;
1538 if (bufarr->len > 0) {
1539 for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1540 for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
1541 priv_data[offset++] = 0xff;
1543 priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
1547 for (i = 0; i < bufarr->len; ++i) {
1548 gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
1549 offset += gst_buffer_get_size (buf[i]);
1552 gst_matroska_mux_free_codec_priv (context);
1553 context->codec_priv = priv_data;
1554 context->codec_priv_size = priv_data_size;
1557 *p_buf0 = gst_buffer_ref (buf[0]);
1566 GST_WARNING ("required streamheaders missing in sink caps!");
1571 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1572 G_VALUE_TYPE_NAME (streamheader));
1577 GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1582 GST_WARNING ("streamheaders array does not contain GstBuffers");
1588 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1589 GstMatroskaTrackContext * context)
1591 GstBuffer *buf0 = NULL;
1593 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1596 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
1597 GST_WARNING ("First vorbis header too small, ignoring");
1599 if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
1600 GstMatroskaTrackAudioContext *audiocontext;
1604 gst_buffer_map (buf0, &map, GST_MAP_READ);
1605 hdr = map.data + 1 + 6 + 4;
1606 audiocontext = (GstMatroskaTrackAudioContext *) context;
1607 audiocontext->channels = GST_READ_UINT8 (hdr);
1608 audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1609 gst_buffer_unmap (buf0, &map);
1614 gst_buffer_unref (buf0);
1620 theora_streamheader_to_codecdata (const GValue * streamheader,
1621 GstMatroskaTrackContext * context)
1623 GstBuffer *buf0 = NULL;
1625 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1628 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
1629 GST_WARNING ("First theora header too small, ignoring");
1630 } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
1631 GST_WARNING ("First header not a theora identification header, ignoring");
1633 GstMatroskaTrackVideoContext *videocontext;
1634 guint fps_num, fps_denom, par_num, par_denom;
1638 gst_buffer_map (buf0, &map, GST_MAP_READ);
1639 hdr = map.data + 1 + 6 + 3 + 2 + 2;
1641 videocontext = (GstMatroskaTrackVideoContext *) context;
1642 videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1643 videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1644 hdr += 3 + 3 + 1 + 1;
1645 fps_num = GST_READ_UINT32_BE (hdr);
1646 fps_denom = GST_READ_UINT32_BE (hdr + 4);
1647 context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1648 fps_denom, fps_num);
1650 par_num = GST_READ_UINT32_BE (hdr) >> 8;
1651 par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1652 if (par_num > 0 && par_denom > 0) {
1653 if (par_num > par_denom) {
1654 videocontext->display_width =
1655 videocontext->pixel_width * par_num / par_denom;
1656 videocontext->display_height = videocontext->pixel_height;
1657 } else if (par_num < par_denom) {
1658 videocontext->display_width = videocontext->pixel_width;
1659 videocontext->display_height =
1660 videocontext->pixel_height * par_denom / par_num;
1662 videocontext->display_width = 0;
1663 videocontext->display_height = 0;
1666 videocontext->display_width = 0;
1667 videocontext->display_height = 0;
1670 gst_buffer_unmap (buf0, &map);
1674 gst_buffer_unref (buf0);
1680 kate_streamheader_to_codecdata (const GValue * streamheader,
1681 GstMatroskaTrackContext * context)
1683 GstBuffer *buf0 = NULL;
1685 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1688 if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) { /* Kate ID header is 64 bytes */
1689 GST_WARNING ("First kate header too small, ignoring");
1690 } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
1691 GST_WARNING ("First header not a kate identification header, ignoring");
1695 gst_buffer_unref (buf0);
1701 flac_streamheader_to_codecdata (const GValue * streamheader,
1702 GstMatroskaTrackContext * context)
1709 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1710 GST_WARNING ("No or invalid streamheader field in the caps");
1714 bufarr = g_value_peek_pointer (streamheader);
1715 if (bufarr->len < 2) {
1716 GST_WARNING ("Too few headers in streamheader field");
1720 context->xiph_headers_to_skip = bufarr->len + 1;
1722 bufval = &g_array_index (bufarr, GValue, 0);
1723 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1724 GST_WARNING ("streamheaders array does not contain GstBuffers");
1728 buffer = g_value_peek_pointer (bufval);
1730 /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1731 if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
1732 || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
1733 || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
1734 GST_WARNING ("Invalid streamheader for FLAC");
1738 gst_matroska_mux_free_codec_priv (context);
1739 context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
1740 context->codec_priv = g_malloc (context->codec_priv_size);
1741 gst_buffer_extract (buffer, 9, context->codec_priv, -1);
1743 for (i = 1; i < bufarr->len; i++) {
1745 bufval = &g_array_index (bufarr, GValue, i);
1747 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1748 gst_matroska_mux_free_codec_priv (context);
1749 GST_WARNING ("streamheaders array does not contain GstBuffers");
1753 buffer = g_value_peek_pointer (bufval);
1755 old_size = context->codec_priv_size;
1756 context->codec_priv_size += gst_buffer_get_size (buffer);
1758 context->codec_priv = g_realloc (context->codec_priv,
1759 context->codec_priv_size);
1760 gst_buffer_extract (buffer, 0,
1761 (guint8 *) context->codec_priv + old_size, -1);
1768 speex_streamheader_to_codecdata (const GValue * streamheader,
1769 GstMatroskaTrackContext * context)
1776 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1777 GST_WARNING ("No or invalid streamheader field in the caps");
1781 bufarr = g_value_peek_pointer (streamheader);
1782 if (bufarr->len != 2) {
1783 GST_WARNING ("Too few headers in streamheader field");
1787 context->xiph_headers_to_skip = bufarr->len + 1;
1789 bufval = &g_array_index (bufarr, GValue, 0);
1790 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1791 GST_WARNING ("streamheaders array does not contain GstBuffers");
1795 buffer = g_value_peek_pointer (bufval);
1797 if (gst_buffer_get_size (buffer) < 80
1798 || gst_buffer_memcmp (buffer, 0, "Speex ", 8) != 0) {
1799 GST_WARNING ("Invalid streamheader for Speex");
1803 gst_matroska_mux_free_codec_priv (context);
1804 context->codec_priv_size = gst_buffer_get_size (buffer);
1805 context->codec_priv = g_malloc (context->codec_priv_size);
1806 gst_buffer_extract (buffer, 0, context->codec_priv, -1);
1808 bufval = &g_array_index (bufarr, GValue, 1);
1810 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1811 gst_matroska_mux_free_codec_priv (context);
1812 GST_WARNING ("streamheaders array does not contain GstBuffers");
1816 buffer = g_value_peek_pointer (bufval);
1818 old_size = context->codec_priv_size;
1819 context->codec_priv_size += gst_buffer_get_size (buffer);
1820 context->codec_priv = g_realloc (context->codec_priv,
1821 context->codec_priv_size);
1822 gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
1828 opus_streamheader_to_codecdata (const GValue * streamheader,
1829 GstMatroskaTrackContext * context)
1835 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1838 bufarr = g_value_peek_pointer (streamheader);
1839 if (bufarr->len != 1 && bufarr->len != 2) /* one header, and count stored in a byte */
1842 /* Opus headers are not in-band */
1843 context->xiph_headers_to_skip = 0;
1845 bufval = &g_array_index (bufarr, GValue, 0);
1846 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1847 goto wrong_content_type;
1849 buf = g_value_peek_pointer (bufval);
1851 gst_matroska_mux_free_codec_priv (context);
1853 context->codec_priv_size = gst_buffer_get_size (buf);
1854 context->codec_priv = g_malloc0 (context->codec_priv_size);
1855 gst_buffer_extract (buf, 0, context->codec_priv, -1);
1857 context->codec_delay =
1858 GST_READ_UINT16_LE ((guint8 *) context->codec_priv + 10);
1859 context->codec_delay =
1860 gst_util_uint64_scale_round (context->codec_delay, GST_SECOND, 48000);
1861 context->seek_preroll = 80 * GST_MSECOND;
1868 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1869 G_VALUE_TYPE_NAME (streamheader));
1874 GST_WARNING ("got %u streamheaders, not 1 or 2 as expected", bufarr->len);
1879 GST_WARNING ("streamheaders array does not contain GstBuffers");
1885 opus_make_codecdata (GstMatroskaTrackContext * context, GstCaps * caps)
1889 guint8 channel_mapping_family;
1890 guint8 stream_count, coupled_count, channel_mapping[256];
1894 /* Opus headers are not in-band */
1895 context->xiph_headers_to_skip = 0;
1897 context->codec_delay = 0;
1898 context->seek_preroll = 80 * GST_MSECOND;
1900 if (!gst_codec_utils_opus_parse_caps (caps, &rate, &channels,
1901 &channel_mapping_family, &stream_count, &coupled_count,
1903 GST_WARNING ("Failed to parse caps for Opus");
1908 gst_codec_utils_opus_create_header (rate, channels,
1909 channel_mapping_family, stream_count, coupled_count, channel_mapping, 0,
1912 GST_WARNING ("Failed to create Opus header from caps");
1916 gst_buffer_map (buffer, &map, GST_MAP_READ);
1917 context->codec_priv_size = map.size;
1918 context->codec_priv = g_malloc (context->codec_priv_size);
1919 memcpy (context->codec_priv, map.data, map.size);
1920 gst_buffer_unmap (buffer, &map);
1921 gst_buffer_unref (buffer);
1927 * gst_matroska_mux_audio_pad_setcaps:
1928 * @pad: Pad which got the caps.
1931 * Setcaps function for audio sink pad.
1933 * Returns: %TRUE on success.
1936 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1938 GstMatroskaTrackContext *context = NULL;
1939 GstMatroskaTrackAudioContext *audiocontext;
1940 GstMatroskaMux *mux;
1941 GstMatroskaPad *collect_pad;
1942 const gchar *mimetype;
1943 gint samplerate = 0, channels = 0;
1944 GstStructure *structure;
1945 const GValue *codec_data = NULL;
1946 GstBuffer *buf = NULL;
1947 const gchar *stream_format = NULL;
1950 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1952 if ((old_caps = gst_pad_get_current_caps (pad))) {
1953 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1954 && !gst_caps_is_equal (caps, old_caps)) {
1955 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1956 ("Caps changes are not supported by Matroska"));
1957 gst_caps_unref (old_caps);
1960 gst_caps_unref (old_caps);
1961 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
1962 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1963 ("Caps on pad %" GST_PTR_FORMAT
1964 " arrived late. Headers were already written", pad));
1969 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1970 g_assert (collect_pad);
1971 context = collect_pad->track;
1973 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
1974 audiocontext = (GstMatroskaTrackAudioContext *) context;
1976 structure = gst_caps_get_structure (caps, 0);
1977 mimetype = gst_structure_get_name (structure);
1980 gst_structure_get_int (structure, "rate", &samplerate);
1981 gst_structure_get_int (structure, "channels", &channels);
1983 audiocontext->samplerate = samplerate;
1984 audiocontext->channels = channels;
1985 audiocontext->bitdepth = 0;
1986 context->default_duration = 0;
1988 codec_data = gst_structure_get_value (structure, "codec_data");
1990 buf = gst_value_get_buffer (codec_data);
1992 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1993 * data and other settings
1997 if (!strcmp (mimetype, "audio/mpeg")) {
1998 gint mpegversion = 0;
2000 gst_structure_get_int (structure, "mpegversion", &mpegversion);
2001 switch (mpegversion) {
2007 gst_structure_get_int (structure, "layer", &layer);
2009 if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
2010 GST_WARNING_OBJECT (mux,
2011 "Unable to determine MPEG audio version, assuming 1");
2017 else if (layer == 2)
2019 else if (version == 2)
2024 context->default_duration =
2025 gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
2029 gst_matroska_mux_set_codec_id (context,
2030 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
2033 gst_matroska_mux_set_codec_id (context,
2034 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
2037 gst_matroska_mux_set_codec_id (context,
2038 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
2047 stream_format = gst_structure_get_string (structure, "stream-format");
2048 /* check this is raw aac */
2049 if (stream_format) {
2050 if (strcmp (stream_format, "raw") != 0) {
2051 GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
2055 GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
2060 gst_matroska_mux_set_codec_id (context,
2061 GST_MATROSKA_CODEC_ID_AUDIO_AAC);
2062 context->codec_priv_size = gst_buffer_get_size (buf);
2063 context->codec_priv = g_malloc (context->codec_priv_size);
2064 gst_buffer_extract (buf, 0, context->codec_priv,
2065 context->codec_priv_size);
2067 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
2074 } else if (!strcmp (mimetype, "audio/x-raw")) {
2077 gst_audio_info_init (&info);
2078 if (!gst_audio_info_from_caps (&info, caps)) {
2079 GST_DEBUG_OBJECT (mux,
2080 "broken caps, rejected by gst_audio_info_from_caps");
2084 switch (GST_AUDIO_INFO_FORMAT (&info)) {
2085 case GST_AUDIO_FORMAT_U8:
2086 case GST_AUDIO_FORMAT_S16BE:
2087 case GST_AUDIO_FORMAT_S16LE:
2088 case GST_AUDIO_FORMAT_S24BE:
2089 case GST_AUDIO_FORMAT_S24LE:
2090 case GST_AUDIO_FORMAT_S32BE:
2091 case GST_AUDIO_FORMAT_S32LE:
2092 if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
2093 GST_DEBUG_OBJECT (mux, "width must be same as depth!");
2096 if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
2097 gst_matroska_mux_set_codec_id (context,
2098 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
2100 gst_matroska_mux_set_codec_id (context,
2101 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
2103 case GST_AUDIO_FORMAT_F32LE:
2104 case GST_AUDIO_FORMAT_F64LE:
2105 gst_matroska_mux_set_codec_id (context,
2106 GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
2110 GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
2114 audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
2115 } else if (!strcmp (mimetype, "audio/x-vorbis")) {
2116 const GValue *streamheader;
2118 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
2120 gst_matroska_mux_free_codec_priv (context);
2122 streamheader = gst_structure_get_value (structure, "streamheader");
2123 if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
2124 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2125 ("vorbis stream headers missing or malformed"));
2128 } else if (!strcmp (mimetype, "audio/x-flac")) {
2129 const GValue *streamheader;
2131 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
2133 gst_matroska_mux_free_codec_priv (context);
2135 streamheader = gst_structure_get_value (structure, "streamheader");
2136 if (!flac_streamheader_to_codecdata (streamheader, context)) {
2137 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2138 ("flac stream headers missing or malformed"));
2141 } else if (!strcmp (mimetype, "audio/x-speex")) {
2142 const GValue *streamheader;
2144 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
2145 gst_matroska_mux_free_codec_priv (context);
2147 streamheader = gst_structure_get_value (structure, "streamheader");
2148 if (!speex_streamheader_to_codecdata (streamheader, context)) {
2149 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2150 ("speex stream headers missing or malformed"));
2153 } else if (!strcmp (mimetype, "audio/x-opus")) {
2154 const GValue *streamheader;
2156 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_OPUS);
2158 streamheader = gst_structure_get_value (structure, "streamheader");
2160 gst_matroska_mux_free_codec_priv (context);
2161 if (!opus_streamheader_to_codecdata (streamheader, context)) {
2162 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2163 ("opus stream headers missing or malformed"));
2167 /* no streamheader, but we need to have one, so we make one up
2169 gst_matroska_mux_free_codec_priv (context);
2170 if (!opus_make_codecdata (context, caps)) {
2171 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2172 ("opus stream headers missing or malformed"));
2176 } else if (!strcmp (mimetype, "audio/x-ac3")) {
2177 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_AC3);
2178 } else if (!strcmp (mimetype, "audio/x-eac3")) {
2179 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
2180 } else if (!strcmp (mimetype, "audio/x-dts")) {
2181 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_DTS);
2182 } else if (!strcmp (mimetype, "audio/x-tta")) {
2185 /* TTA frame duration */
2186 context->default_duration = 1.04489795918367346939 * GST_SECOND;
2188 gst_structure_get_int (structure, "width", &width);
2189 audiocontext->bitdepth = width;
2190 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_TTA);
2192 } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
2194 const GValue *mdpr_data;
2196 gst_structure_get_int (structure, "raversion", &raversion);
2197 switch (raversion) {
2199 gst_matroska_mux_set_codec_id (context,
2200 GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
2203 gst_matroska_mux_set_codec_id (context,
2204 GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
2207 gst_matroska_mux_set_codec_id (context,
2208 GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
2214 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
2215 if (mdpr_data != NULL) {
2216 guint8 *priv_data = NULL;
2217 guint priv_data_size = 0;
2219 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
2221 priv_data_size = gst_buffer_get_size (codec_data_buf);
2222 priv_data = g_malloc0 (priv_data_size);
2224 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
2226 gst_matroska_mux_free_codec_priv (context);
2228 context->codec_priv = priv_data;
2229 context->codec_priv_size = priv_data_size;
2232 } else if (!strcmp (mimetype, "audio/x-wma")
2233 || !strcmp (mimetype, "audio/x-alaw")
2234 || !strcmp (mimetype, "audio/x-mulaw")
2235 || !strcmp (mimetype, "audio/x-adpcm")
2236 || !strcmp (mimetype, "audio/G722")) {
2238 guint codec_priv_size;
2240 gint block_align = 0;
2243 if (samplerate == 0 || channels == 0) {
2244 GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
2248 if (!strcmp (mimetype, "audio/x-wma")) {
2252 if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
2253 || !gst_structure_get_int (structure, "block_align", &block_align)
2254 || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
2255 GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
2260 switch (wmaversion) {
2262 format = GST_RIFF_WAVE_FORMAT_WMAV1;
2265 format = GST_RIFF_WAVE_FORMAT_WMAV2;
2268 format = GST_RIFF_WAVE_FORMAT_WMAV3;
2271 GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
2275 if (gst_structure_get_int (structure, "depth", &depth))
2276 audiocontext->bitdepth = depth;
2277 } else if (!strcmp (mimetype, "audio/x-alaw")
2278 || !strcmp (mimetype, "audio/x-mulaw")) {
2279 audiocontext->bitdepth = 8;
2280 if (!strcmp (mimetype, "audio/x-alaw"))
2281 format = GST_RIFF_WAVE_FORMAT_ALAW;
2283 format = GST_RIFF_WAVE_FORMAT_MULAW;
2285 block_align = channels;
2286 bitrate = block_align * samplerate;
2287 } else if (!strcmp (mimetype, "audio/x-adpcm")) {
2290 layout = gst_structure_get_string (structure, "layout");
2292 GST_WARNING_OBJECT (mux, "Missing layout on adpcm caps");
2296 if (!gst_structure_get_int (structure, "block_align", &block_align)) {
2297 GST_WARNING_OBJECT (mux, "Missing block_align on adpcm caps");
2301 if (!strcmp (layout, "dvi")) {
2302 format = GST_RIFF_WAVE_FORMAT_DVI_ADPCM;
2303 } else if (!strcmp (layout, "g726")) {
2304 format = GST_RIFF_WAVE_FORMAT_ITU_G726_ADPCM;
2305 if (!gst_structure_get_int (structure, "bitrate", &bitrate)) {
2306 GST_WARNING_OBJECT (mux, "Missing bitrate on adpcm g726 caps");
2310 GST_WARNING_OBJECT (mux, "Unknown layout on adpcm caps");
2314 } else if (!strcmp (mimetype, "audio/G722")) {
2315 format = GST_RIFF_WAVE_FORMAT_ADPCM_G722;
2317 g_assert (format != 0);
2319 codec_priv_size = WAVEFORMATEX_SIZE;
2321 codec_priv_size += gst_buffer_get_size (buf);
2323 /* serialize waveformatex structure */
2324 codec_priv = g_malloc0 (codec_priv_size);
2325 GST_WRITE_UINT16_LE (codec_priv, format);
2326 GST_WRITE_UINT16_LE (codec_priv + 2, channels);
2327 GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
2328 GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
2329 GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
2330 GST_WRITE_UINT16_LE (codec_priv + 14, 0);
2332 GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
2334 GST_WRITE_UINT16_LE (codec_priv + 16, 0);
2336 /* process codec private/initialization data, if any */
2338 gst_buffer_extract (buf, 0,
2339 (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
2342 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
2343 gst_matroska_mux_free_codec_priv (context);
2344 context->codec_priv = (gpointer) codec_priv;
2345 context->codec_priv_size = codec_priv_size;
2353 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2354 GST_PAD_NAME (pad), caps);
2359 /* we probably don't have the data at start,
2360 * so have to reserve (a maximum) space to write this at the end.
2361 * bit spacy, but some formats can hold quite some */
2362 #define SUBTITLE_MAX_CODEC_PRIVATE 2048 /* must be > 128 */
2365 * gst_matroska_mux_subtitle_pad_setcaps:
2366 * @pad: Pad which got the caps.
2369 * Setcaps function for subtitle sink pad.
2371 * Returns: %TRUE on success.
2374 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
2376 /* There is now (at least) one such alement (kateenc), and I'm going
2377 to handle it here and claim it works when it can be piped back
2378 through GStreamer and VLC */
2380 GstMatroskaTrackContext *context = NULL;
2381 GstMatroskaTrackSubtitleContext *scontext;
2382 GstMatroskaMux *mux;
2383 GstMatroskaPad *collect_pad;
2384 GstCollectData *data;
2385 const gchar *mimetype;
2386 GstStructure *structure;
2387 const GValue *value = NULL;
2388 GstBuffer *buf = NULL;
2389 gboolean ret = TRUE;
2392 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2394 if ((old_caps = gst_pad_get_current_caps (pad))) {
2395 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
2396 && !gst_caps_is_equal (caps, old_caps)) {
2397 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2398 ("Caps changes are not supported by Matroska"));
2399 gst_caps_unref (old_caps);
2402 gst_caps_unref (old_caps);
2403 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
2404 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2405 ("Caps on pad %" GST_PTR_FORMAT
2406 " arrived late. Headers were already written", pad));
2411 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
2412 g_assert (collect_pad);
2413 data = (GstCollectData *) (collect_pad);
2415 context = collect_pad->track;
2417 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
2418 scontext = (GstMatroskaTrackSubtitleContext *) context;
2420 structure = gst_caps_get_structure (caps, 0);
2421 mimetype = gst_structure_get_name (structure);
2424 scontext->check_utf8 = 1;
2425 scontext->invalid_utf8 = 0;
2426 context->default_duration = 0;
2428 if (!strcmp (mimetype, "subtitle/x-kate")) {
2429 const GValue *streamheader;
2431 gst_matroska_mux_set_codec_id (context,
2432 GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
2434 gst_matroska_mux_free_codec_priv (context);
2436 streamheader = gst_structure_get_value (structure, "streamheader");
2437 if (!kate_streamheader_to_codecdata (streamheader, context)) {
2438 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2439 ("kate stream headers missing or malformed"));
2443 } else if (!strcmp (mimetype, "text/x-raw")) {
2444 gst_matroska_mux_set_codec_id (context,
2445 GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
2446 } else if (!strcmp (mimetype, "application/x-ssa")) {
2447 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
2448 } else if (!strcmp (mimetype, "application/x-ass")) {
2449 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
2450 } else if (!strcmp (mimetype, "application/x-usf")) {
2451 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
2452 } else if (!strcmp (mimetype, "subpicture/x-dvd")) {
2453 gst_matroska_mux_set_codec_id (context,
2454 GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
2460 /* maybe some private data, e.g. vobsub */
2461 value = gst_structure_get_value (structure, "codec_data");
2463 buf = gst_value_get_buffer (value);
2466 guint8 *priv_data = NULL;
2468 gst_buffer_map (buf, &map, GST_MAP_READ);
2470 if (map.size > SUBTITLE_MAX_CODEC_PRIVATE) {
2471 GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
2472 " exceeded maximum (%d); discarding", pad,
2473 SUBTITLE_MAX_CODEC_PRIVATE);
2474 gst_buffer_unmap (buf, &map);
2478 gst_matroska_mux_free_codec_priv (context);
2480 priv_data = g_malloc0 (map.size);
2481 memcpy (priv_data, map.data, map.size);
2482 context->codec_priv = priv_data;
2483 context->codec_priv_size = map.size;
2484 gst_buffer_unmap (buf, &map);
2487 GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %" G_GSIZE_FORMAT,
2488 GST_STR_NULL (context->codec_id), context->codec_priv_size);
2490 /* This pad is sparse. Now that we have caps on it, we can tell collectpads
2491 * not to actually wait for data when muxing */
2492 GST_COLLECT_PADS_STREAM_LOCK (mux->collect);
2493 GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED);
2494 gst_collect_pads_set_waiting (mux->collect, data, FALSE);
2495 GST_COLLECT_PADS_STREAM_UNLOCK (mux->collect);
2504 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2505 GST_PAD_NAME (pad), caps);
2512 * gst_matroska_mux_request_new_pad:
2513 * @element: #GstMatroskaMux.
2514 * @templ: #GstPadTemplate.
2515 * @pad_name: New pad name.
2517 * Request pad function for sink templates.
2519 * Returns: New #GstPad.
2522 gst_matroska_mux_request_new_pad (GstElement * element,
2523 GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
2525 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
2526 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
2527 GstMatroskaPad *collect_pad;
2528 GstMatroskamuxPad *newpad;
2530 const gchar *pad_name = NULL;
2531 GstMatroskaCapsFunc capsfunc = NULL;
2532 GstMatroskaTrackContext *context = NULL;
2534 const gchar *id = NULL;
2536 if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
2537 /* don't mix named and unnamed pads, if the pad already exists we fail when
2538 * trying to add it */
2539 if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
2540 pad_name = req_name;
2542 name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
2545 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
2546 context = (GstMatroskaTrackContext *)
2547 g_new0 (GstMatroskaTrackAudioContext, 1);
2548 context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
2549 context->name = g_strdup ("Audio");
2550 } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
2551 /* don't mix named and unnamed pads, if the pad already exists we fail when
2552 * trying to add it */
2553 if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
2554 pad_name = req_name;
2556 name = g_strdup_printf ("video_%u", mux->num_v_streams++);
2559 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
2560 context = (GstMatroskaTrackContext *)
2561 g_new0 (GstMatroskaTrackVideoContext, 1);
2562 context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
2563 context->name = g_strdup ("Video");
2564 } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
2565 /* don't mix named and unnamed pads, if the pad already exists we fail when
2566 * trying to add it */
2567 if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
2568 pad_name = req_name;
2570 name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
2573 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
2574 context = (GstMatroskaTrackContext *)
2575 g_new0 (GstMatroskaTrackSubtitleContext, 1);
2576 context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
2577 context->name = g_strdup ("Subtitle");
2578 /* setcaps may only provide proper one a lot later */
2579 id = "S_SUB_UNKNOWN";
2581 GST_WARNING_OBJECT (mux, "This is not our template!");
2585 newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
2586 "name", pad_name, "direction", templ->direction, "template", templ, NULL);
2588 gst_matroskamux_pad_init (newpad);
2589 collect_pad = (GstMatroskaPad *)
2590 gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad),
2591 sizeof (GstMatroskaPad),
2592 (GstCollectDataDestroyNotify) gst_matroska_pad_free, TRUE);
2594 collect_pad->mux = mux;
2595 collect_pad->track = context;
2596 gst_matroska_pad_reset (collect_pad, FALSE);
2598 gst_matroska_mux_set_codec_id (collect_pad->track, id);
2599 collect_pad->track->dts_only = FALSE;
2601 collect_pad->capsfunc = capsfunc;
2602 gst_pad_set_active (GST_PAD (newpad), TRUE);
2603 if (!gst_element_add_pad (element, GST_PAD (newpad)))
2604 goto pad_add_failed;
2610 GST_DEBUG_OBJECT (newpad, "Added new request pad");
2612 return GST_PAD (newpad);
2617 GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
2619 gst_object_unref (newpad);
2625 * gst_matroska_mux_release_pad:
2626 * @element: #GstMatroskaMux.
2627 * @pad: Pad to release.
2629 * Release a previously requested pad.
2632 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
2634 GstMatroskaMux *mux;
2637 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2639 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
2640 GstCollectData *cdata = (GstCollectData *) walk->data;
2641 GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
2643 if (cdata->pad == pad) {
2645 * observed duration, this will remain GST_CLOCK_TIME_NONE
2646 * only if the pad is reset
2648 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
2650 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2651 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2652 collected_duration =
2653 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2656 if (GST_CLOCK_TIME_IS_VALID (collected_duration)
2657 && mux->duration < collected_duration)
2658 mux->duration = collected_duration;
2664 gst_collect_pads_remove_pad (mux->collect, pad);
2665 if (gst_element_remove_pad (element, pad))
2670 gst_matroska_mux_write_mastering_metadata (GstMatroskaMux * mux,
2671 GstMatroskaTrackVideoContext * videocontext)
2673 GstEbmlWrite *ebml = mux->ebml_write;
2675 GstVideoMasteringDisplayInfo *minfo = &videocontext->mastering_display_info;
2677 const gdouble chroma_scale = 50000;
2678 const gdouble luma_scale = 50000;
2680 if (!videocontext->mastering_display_info_present)
2684 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_MASTERINGMETADATA);
2686 value = (gdouble) minfo->display_primaries[0].x / chroma_scale;
2687 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYX, value);
2689 value = (gdouble) minfo->display_primaries[0].y / chroma_scale;
2690 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYY, value);
2692 value = (gdouble) minfo->display_primaries[1].x / chroma_scale;
2693 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYX, value);
2695 value = (gdouble) minfo->display_primaries[1].y / chroma_scale;
2696 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYY, value);
2698 value = (gdouble) minfo->display_primaries[2].x / chroma_scale;
2699 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYX, value);
2701 value = (gdouble) minfo->display_primaries[2].y / chroma_scale;
2702 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYY, value);
2704 value = (gdouble) minfo->white_point.x / chroma_scale;
2705 gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYX, value);
2707 value = (gdouble) minfo->white_point.y / chroma_scale;
2708 gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY, value);
2710 value = (gdouble) minfo->max_display_mastering_luminance / luma_scale;
2711 gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMAX, value);
2713 value = (gdouble) minfo->min_display_mastering_luminance / luma_scale;
2714 gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMIN, value);
2716 gst_ebml_write_master_finish (ebml, master);
2721 gst_matroska_mux_write_colour (GstMatroskaMux * mux,
2722 GstMatroskaTrackVideoContext * videocontext)
2724 GstEbmlWrite *ebml = mux->ebml_write;
2726 guint matrix_id = 0;
2728 guint transfer_id = 0;
2729 guint primaries_id = 0;
2731 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_VIDEOCOLOUR);
2733 switch (videocontext->colorimetry.range) {
2734 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
2737 case GST_VIDEO_COLOR_RANGE_16_235:
2740 case GST_VIDEO_COLOR_RANGE_0_255:
2744 matrix_id = gst_video_color_matrix_to_iso (videocontext->colorimetry.matrix);
2746 gst_video_transfer_function_to_iso (videocontext->colorimetry.transfer);
2748 gst_video_color_primaries_to_iso (videocontext->colorimetry.primaries);
2750 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEORANGE, range_id);
2751 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOMATRIXCOEFFICIENTS,
2753 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS,
2755 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPRIMARIES, primaries_id);
2756 if (videocontext->content_light_level.max_content_light_level &&
2757 videocontext->content_light_level.max_frame_average_light_level) {
2758 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXCLL,
2759 videocontext->content_light_level.max_content_light_level);
2760 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXFALL,
2761 videocontext->content_light_level.max_frame_average_light_level);
2764 gst_matroska_mux_write_mastering_metadata (mux, videocontext);
2765 gst_ebml_write_master_finish (ebml, master);
2769 * gst_matroska_mux_track_header:
2770 * @mux: #GstMatroskaMux
2771 * @context: Tack context.
2773 * Write a track header.
2776 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2777 GstMatroskaTrackContext * context)
2779 GstEbmlWrite *ebml = mux->ebml_write;
2782 /* TODO: check if everything necessary is written and check default values */
2784 /* track type goes before the type-specific stuff */
2785 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2786 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2788 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, context->uid);
2789 if (context->default_duration) {
2790 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2791 context->default_duration);
2793 if (context->language) {
2794 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2798 /* FIXME: until we have a nice way of getting the codecname
2799 * out of the caps, I'm not going to enable this. Too much
2800 * (useless, double, boring) work... */
2801 /* TODO: Use value from tags if any */
2802 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2803 context->codec_name); */
2804 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2806 /* type-specific stuff */
2807 switch (context->type) {
2808 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2809 GstMatroskaTrackVideoContext *videocontext =
2810 (GstMatroskaTrackVideoContext *) context;
2812 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2813 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2814 videocontext->pixel_width);
2815 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2816 videocontext->pixel_height);
2817 if (videocontext->display_width && videocontext->display_height) {
2818 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2819 videocontext->display_width);
2820 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2821 videocontext->display_height);
2823 switch (videocontext->interlace_mode) {
2824 case GST_MATROSKA_INTERLACE_MODE_INTERLACED:
2825 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2827 case GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE:
2828 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 2);
2834 if (videocontext->fourcc) {
2835 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2837 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2838 (gpointer) & fcc_le, 4);
2840 gst_matroska_mux_write_colour (mux, videocontext);
2841 if (videocontext->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
2842 guint64 stereo_mode = 0;
2844 switch (videocontext->multiview_mode) {
2845 case GST_VIDEO_MULTIVIEW_MODE_MONO:
2847 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
2848 if (videocontext->multiview_flags &
2849 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2850 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_RL;
2852 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_LR;
2854 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
2855 if (videocontext->multiview_flags &
2856 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2857 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_RL;
2859 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_LR;
2861 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
2862 if (videocontext->multiview_flags &
2863 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2864 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_RL;
2866 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_LR;
2868 case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
2869 if (videocontext->multiview_flags &
2870 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2871 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_RL;
2873 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_LR;
2874 /* FIXME: In frame-by-frame mode, left/right frame buffers need to be
2875 * laced within one block. See http://www.matroska.org/technical/specs/index.html#StereoMode */
2876 GST_FIXME_OBJECT (mux,
2877 "Frame-by-frame stereoscopic mode not fully implemented");
2880 GST_WARNING_OBJECT (mux,
2881 "Multiview mode %d not supported in Matroska/WebM",
2882 videocontext->multiview_mode);
2886 if (stereo_mode != 0)
2887 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOSTEREOMODE,
2890 gst_ebml_write_master_finish (ebml, master);
2895 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2896 GstMatroskaTrackAudioContext *audiocontext =
2897 (GstMatroskaTrackAudioContext *) context;
2899 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2900 if (audiocontext->samplerate != 8000)
2901 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2902 audiocontext->samplerate);
2903 if (audiocontext->channels != 1)
2904 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2905 audiocontext->channels);
2906 if (audiocontext->bitdepth) {
2907 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2908 audiocontext->bitdepth);
2911 gst_ebml_write_master_finish (ebml, master);
2916 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
2920 /* doesn't need type-specific data */
2924 GST_DEBUG_OBJECT (mux, "Wrote track header. Codec %s", context->codec_id);
2926 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2927 if (context->codec_priv)
2928 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2929 context->codec_priv, context->codec_priv_size);
2931 if (context->seek_preroll) {
2932 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPREROLL,
2933 context->seek_preroll);
2936 if (context->codec_delay) {
2937 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CODECDELAY,
2938 context->codec_delay);
2943 gst_matroska_mux_write_chapter_title (const gchar * title, GstEbmlWrite * ebml)
2945 guint64 title_master;
2948 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERDISPLAY);
2950 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPSTRING, title);
2951 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CHAPLANGUAGE,
2952 GST_MATROSKA_MUX_CHAPLANG);
2954 gst_ebml_write_master_finish (ebml, title_master);
2957 static GstTocEntry *
2958 gst_matroska_mux_write_chapter (GstMatroskaMux * mux, GstTocEntry * edition,
2959 GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters,
2960 guint64 * master_edition)
2962 guint64 master_chapteratom;
2969 GstTocEntry *internal_chapter, *internal_nested;
2972 if (G_UNLIKELY (master_chapters != NULL && *master_chapters == 0))
2974 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERS);
2976 if (G_UNLIKELY (master_edition != NULL && *master_edition == 0)) {
2977 /* create uid for the parent */
2979 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_EDITIONENTRY);
2981 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONUID,
2982 g_ascii_strtoull (gst_toc_entry_get_uid (edition), NULL, 10));
2983 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGHIDDEN, 0);
2984 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGDEFAULT, 0);
2985 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGORDERED, 0);
2988 gst_toc_entry_get_start_stop_times (entry, &start, &stop);
2989 tags = gst_toc_entry_get_tags (entry);
2991 tags = gst_tag_list_copy (tags);
2994 /* build internal chapter */
2995 uid = gst_matroska_mux_create_uid (mux);
2996 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT, uid);
2997 internal_chapter = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, s_uid);
2999 /* Write the chapter entry */
3000 master_chapteratom =
3001 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERATOM);
3003 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERUID, uid);
3004 /* Store the user provided UID in the ChapterStringUID */
3005 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPTERSTRINGUID,
3006 gst_toc_entry_get_uid (entry));
3007 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTART, start);
3008 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTOP, stop);
3009 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGHIDDEN, 0);
3010 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGENABLED, 1);
3012 /* write current ChapterDisplays before the nested chapters */
3013 if (G_LIKELY (tags != NULL)) {
3014 count = gst_tag_list_get_tag_size (tags, GST_TAG_TITLE);
3016 for (i = 0; i < count; ++i) {
3017 gst_tag_list_get_string_index (tags, GST_TAG_TITLE, i, &title);
3018 /* FIXME: handle ChapterLanguage entries */
3019 gst_matroska_mux_write_chapter_title (title, ebml);
3023 /* remove title tag */
3024 if (G_LIKELY (count > 0))
3025 gst_tag_list_remove_tag (tags, GST_TAG_TITLE);
3027 gst_toc_entry_set_tags (internal_chapter, tags);
3030 /* Write nested chapters */
3031 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3033 internal_nested = gst_matroska_mux_write_chapter (mux, NULL, cur->data,
3036 gst_toc_entry_append_sub_entry (internal_chapter, internal_nested);
3039 gst_ebml_write_master_finish (ebml, master_chapteratom);
3041 return internal_chapter;
3044 static GstTocEntry *
3045 gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
3046 GstTocEntry * edition, GList * chapters, GstEbmlWrite * ebml,
3047 guint64 * master_chapters)
3049 guint64 master_edition = 0;
3052 GstTocEntry *internal_edition, *internal_chapter;
3053 GstTagList *tags = NULL;
3055 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT,
3056 gst_matroska_mux_create_uid (mux));
3058 if (edition != NULL) {
3059 /* Edition entry defined, get its tags */
3060 tags = gst_toc_entry_get_tags (edition);
3062 tags = gst_tag_list_copy (tags);
3066 internal_edition = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, s_uid);
3068 gst_toc_entry_set_tags (internal_edition, tags);
3071 for (cur = g_list_first (chapters); cur != NULL; cur = cur->next) {
3072 internal_chapter = gst_matroska_mux_write_chapter (mux, internal_edition,
3073 cur->data, ebml, master_chapters, &master_edition);
3075 gst_toc_entry_append_sub_entry (internal_edition, internal_chapter);
3078 if (G_LIKELY (master_edition != 0))
3079 gst_ebml_write_master_finish (ebml, master_edition);
3081 return internal_edition;
3085 * gst_matroska_mux_start:
3086 * @mux: #GstMatroskaMux
3088 * Start a new matroska file (write headers etc...)
3091 gst_matroska_mux_start (GstMatroskaMux * mux, GstMatroskaPad * first_pad,
3092 GstBuffer * first_pad_buf)
3094 GstEbmlWrite *ebml = mux->ebml_write;
3095 const gchar *doctype;
3096 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
3097 GST_MATROSKA_ID_TRACKS,
3098 GST_MATROSKA_ID_CHAPTERS,
3099 GST_MATROSKA_ID_CUES,
3100 GST_MATROSKA_ID_TAGS,
3103 const gchar *media_type;
3104 gboolean audio_only;
3105 guint64 master, child;
3109 GstClockTime earliest_time = GST_CLOCK_TIME_NONE;
3110 GstClockTime duration = 0;
3111 guint32 segment_uid[4];
3116 /* if not streaming, check if downstream is seekable */
3117 if (!mux->ebml_write->streamable) {
3121 query = gst_query_new_seeking (GST_FORMAT_BYTES);
3122 if (gst_pad_peer_query (mux->srcpad, query)) {
3123 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3124 GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
3126 /* assume seeking is not supported if query not handled downstream */
3127 GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
3131 mux->ebml_write->streamable = TRUE;
3132 g_object_notify (G_OBJECT (mux), "streamable");
3133 GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
3134 "streamable=false. Will ignore that and create streamable output "
3137 gst_query_unref (query);
3140 /* stream-start (FIXME: create id based on input ids) */
3141 g_snprintf (s_id, sizeof (s_id), "matroskamux-%08x", g_random_int ());
3142 gst_pad_push_event (mux->srcpad, gst_event_new_stream_start (s_id));
3145 audio_only = mux->num_v_streams == 0 && mux->num_a_streams > 0;
3147 media_type = (audio_only) ? "audio/webm" : "video/webm";
3149 media_type = (audio_only) ? "audio/x-matroska" : "video/x-matroska";
3151 ebml->caps = gst_caps_new_empty_simple (media_type);
3152 gst_pad_set_caps (mux->srcpad, ebml->caps);
3153 /* we start with a EBML header */
3154 doctype = mux->doctype;
3155 GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
3156 doctype, mux->doctype_version);
3157 gst_ebml_write_header (ebml, doctype, mux->doctype_version);
3159 /* the rest of the header is cached */
3160 gst_ebml_write_set_cache (ebml, 0x1000);
3162 /* start a segment */
3164 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
3165 mux->segment_master = ebml->pos;
3167 if (!mux->ebml_write->streamable) {
3168 /* seekhead (table of contents) - we set the positions later */
3169 mux->seekhead_pos = ebml->pos;
3170 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
3171 for (i = 0; seekhead_id[i] != 0; i++) {
3172 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
3173 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
3174 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
3175 gst_ebml_write_master_finish (ebml, child);
3177 gst_ebml_write_master_finish (ebml, master);
3180 if (mux->ebml_write->streamable) {
3181 const GstTagList *tags;
3182 gboolean has_main_tags;
3185 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3186 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3188 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux)) {
3189 guint64 master_tags, master_tag;
3191 GST_DEBUG_OBJECT (mux, "Writing tags");
3193 mux->tags_pos = ebml->pos;
3194 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3195 if (has_main_tags) {
3196 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3197 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3198 gst_ebml_write_master_finish (ebml, master_tag);
3200 gst_matroska_mux_write_streams_tags (mux);
3201 gst_ebml_write_master_finish (ebml, master_tags);
3206 mux->info_pos = ebml->pos;
3207 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
3209 /* WebM does not support SegmentUID field on SegmentInfo */
3210 if (!mux->is_webm) {
3211 for (i = 0; i < 4; i++) {
3212 segment_uid[i] = g_random_int ();
3214 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
3215 (guint8 *) segment_uid, 16);
3218 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
3219 mux->duration_pos = ebml->pos;
3221 if (!mux->ebml_write->streamable) {
3222 for (collected = mux->collect->data; collected;
3223 collected = g_slist_next (collected)) {
3224 GstMatroskaPad *collect_pad;
3226 gint64 trackduration;
3228 collect_pad = (GstMatroskaPad *) collected->data;
3229 thepad = collect_pad->collect.pad;
3231 /* Query the total length of the track. */
3232 GST_DEBUG_OBJECT (thepad, "querying peer duration");
3233 if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
3234 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
3235 GST_TIME_ARGS (trackduration));
3236 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
3237 duration = (GstClockTime) trackduration;
3241 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3242 gst_guint64_to_gdouble (duration) /
3243 gst_guint64_to_gdouble (mux->time_scale));
3245 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
3246 "GStreamer matroskamux version " PACKAGE_VERSION);
3247 if (mux->writing_app && mux->writing_app[0]) {
3248 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
3250 if (mux->creation_time != NULL) {
3251 time = g_date_time_to_unix (mux->creation_time) * GST_SECOND;
3252 time += g_date_time_get_microsecond (mux->creation_time) * GST_USECOND;
3254 time = g_get_real_time () * GST_USECOND;
3256 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time);
3257 gst_ebml_write_master_finish (ebml, master);
3260 mux->tracks_pos = ebml->pos;
3261 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
3263 for (collected = mux->collect->data; collected;
3264 collected = g_slist_next (collected)) {
3265 GstMatroskaPad *collect_pad;
3268 collect_pad = (GstMatroskaPad *) collected->data;
3270 /* This will cause an error at a later time */
3271 if (collect_pad->track->codec_id == NULL)
3274 /* Find the smallest timestamp so we can offset all streams by this to
3276 if (mux->offset_to_zero) {
3279 if (collect_pad == first_pad)
3280 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3282 buf = gst_collect_pads_peek (mux->collect, collected->data);
3285 ts = gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
3287 if (earliest_time == GST_CLOCK_TIME_NONE)
3289 else if (ts != GST_CLOCK_TIME_NONE && ts < earliest_time)
3294 gst_buffer_unref (buf);
3297 /* For audio tracks, use the first buffers duration as the default
3298 * duration if we didn't get any better idea from the caps event already
3300 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO &&
3301 collect_pad->track->default_duration == 0) {
3302 if (collect_pad == first_pad)
3303 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3305 buf = gst_collect_pads_peek (mux->collect, collected->data);
3307 if (buf && GST_BUFFER_DURATION_IS_VALID (buf))
3308 collect_pad->track->default_duration =
3309 GST_BUFFER_DURATION (buf) + collect_pad->track->codec_delay;
3311 gst_buffer_unref (buf);
3314 collect_pad->track->num = tracknum++;
3315 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
3316 gst_matroska_mux_track_header (mux, collect_pad->track);
3317 gst_ebml_write_master_finish (ebml, child);
3318 /* some remaining pad/track setup */
3319 collect_pad->default_duration_scaled =
3320 gst_util_uint64_scale (collect_pad->track->default_duration,
3321 1, mux->time_scale);
3323 gst_ebml_write_master_finish (ebml, master);
3325 mux->earliest_time = earliest_time == GST_CLOCK_TIME_NONE ? 0 : earliest_time;
3328 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3329 if (toc != NULL && !mux->ebml_write->streamable) {
3330 guint64 master_chapters = 0;
3331 GstTocEntry *internal_edition;
3332 GList *cur, *chapters;
3334 GST_DEBUG ("Writing chapters");
3336 /* There are two UIDs for Chapters:
3337 * - The ChapterUID is a mandatory unsigned integer which internally
3338 * refers to a given chapter. Except for the title & language which use
3339 * dedicated fields, this UID can also be used to add tags to the Chapter.
3340 * The tags come in a separate section of the container.
3341 * - The ChapterStringUID is an optional UTF-8 string which also uniquely
3342 * refers to a chapter but from an external perspective. It can act as a
3343 * "WebVTT cue identifier" which "can be used to reference a specific cue,
3344 * for example from script or CSS".
3346 * The ChapterUID will be generated and checked for unicity, while the
3347 * ChapterStringUID will receive the user defined UID.
3349 * In order to be able to refer to chapters from the tags section,
3350 * we must maintain an internal Toc tree with the generated ChapterUID
3351 * (see gst_matroska_mux_write_toc_entry_tags) */
3353 /* Check whether we have editions or chapters at the root level. */
3354 cur = gst_toc_get_entries (toc);
3356 mux->chapters_pos = ebml->pos;
3358 mux->internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
3360 if (gst_toc_entry_get_entry_type (cur->data) ==
3361 GST_TOC_ENTRY_TYPE_EDITION) {
3362 /* Editions at the root level */
3363 for (; cur != NULL; cur = cur->next) {
3364 chapters = gst_toc_entry_get_sub_entries (cur->data);
3365 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3366 cur->data, chapters, ebml, &master_chapters);
3367 gst_toc_append_entry (mux->internal_toc, internal_edition);
3370 /* Chapters at the root level */
3371 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3372 NULL, cur, ebml, &master_chapters);
3373 gst_toc_append_entry (mux->internal_toc, internal_edition);
3376 /* close master element if any edition was written */
3377 if (G_LIKELY (master_chapters != 0))
3378 gst_ebml_write_master_finish (ebml, master_chapters);
3382 /* lastly, flush the cache */
3383 gst_ebml_write_flush_cache (ebml, FALSE, 0);
3386 gst_toc_unref (toc);
3389 /* TODO: more sensible tag mappings */
3392 const gchar *matroska_tagname;
3393 const gchar *gstreamer_tagname;
3395 gst_matroska_tag_conv[] = {
3397 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
3398 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
3399 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
3400 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
3401 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
3402 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
3403 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
3404 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
3405 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
3406 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
3407 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
3408 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
3409 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
3410 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
3411 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
3414 /* Every stagefright implementation on android up to and including 6.0.1 is using
3415 libwebm with bug in matroska parsing, where it will choke on empty tag elements;
3416 so before outputting tags and tag elements we better make sure that there are
3417 actually tags we are going to write */
3419 gst_matroska_mux_tag_list_is_empty (const GstTagList * list)
3422 for (i = 0; i < gst_tag_list_n_tags (list); i++) {
3423 const gchar *tag = gst_tag_list_nth_tag_name (list, i);
3425 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3426 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3427 if (strcmp (tagname_gst, tag) == 0) {
3428 GValue src = { 0, };
3431 if (!gst_tag_list_copy_value (&src, list, tag))
3433 dest = gst_value_serialize (&src);
3435 g_value_unset (&src);
3447 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
3450 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
3452 guint64 simpletag_master;
3454 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3455 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3456 const gchar *tagname_mkv = gst_matroska_tag_conv[i].matroska_tagname;
3458 if (strcmp (tagname_gst, tag) == 0) {
3459 GValue src = { 0, };
3462 if (!gst_tag_list_copy_value (&src, list, tag))
3464 if ((dest = gst_value_serialize (&src))) {
3466 simpletag_master = gst_ebml_write_master_start (ebml,
3467 GST_MATROSKA_ID_SIMPLETAG);
3468 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
3469 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
3470 gst_ebml_write_master_finish (ebml, simpletag_master);
3473 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
3475 g_value_unset (&src);
3482 gst_matroska_mux_write_stream_tags (GstMatroskaMux * mux, GstMatroskaPad * mpad)
3484 guint64 master_tag, master_targets;
3487 ebml = mux->ebml_write;
3489 if (G_UNLIKELY (mpad->tags == NULL
3490 || gst_matroska_mux_tag_list_is_empty (mpad->tags)))
3493 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3494 master_targets = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3496 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETTRACKUID, mpad->track->uid);
3498 gst_ebml_write_master_finish (ebml, master_targets);
3499 gst_tag_list_foreach (mpad->tags, gst_matroska_mux_write_simple_tag, ebml);
3500 gst_ebml_write_master_finish (ebml, master_tag);
3504 gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux)
3508 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3509 GstMatroskaPad *collect_pad;
3511 collect_pad = (GstMatroskaPad *) walk->data;
3513 gst_matroska_mux_write_stream_tags (mux, collect_pad);
3518 gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux)
3522 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3523 GstMatroskaPad *collect_pad;
3525 collect_pad = (GstMatroskaPad *) walk->data;
3526 if (!gst_matroska_mux_tag_list_is_empty (collect_pad->tags))
3533 gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
3534 const GstTocEntry * entry, guint64 * master_tags, gboolean * has_tags)
3536 guint64 master_tag, master_targets;
3539 const GstTagList *tags;
3541 ebml = mux->ebml_write;
3543 tags = gst_toc_entry_get_tags (entry);
3544 if (G_UNLIKELY (tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags))) {
3547 if (*master_tags == 0) {
3548 mux->tags_pos = ebml->pos;
3549 *master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3552 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3554 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3556 if (gst_toc_entry_get_entry_type (entry) == GST_TOC_ENTRY_TYPE_EDITION)
3557 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETEDITIONUID,
3558 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3560 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETCHAPTERUID,
3561 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3563 gst_ebml_write_master_finish (ebml, master_targets);
3564 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3565 gst_ebml_write_master_finish (ebml, master_tag);
3568 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3570 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, master_tags,
3576 * gst_matroska_mux_finish:
3577 * @mux: #GstMatroskaMux
3579 * Finish a new matroska file (write index etc...)
3582 gst_matroska_mux_finish (GstMatroskaMux * mux)
3584 GstEbmlWrite *ebml = mux->ebml_write;
3586 guint64 duration = 0;
3588 const GstTagList *tags, *toc_tags;
3590 gboolean has_main_tags, toc_has_tags = FALSE;
3593 /* finish last cluster */
3595 gst_ebml_write_master_finish (ebml, mux->cluster);
3599 if (mux->index != NULL) {
3601 guint64 master, pointentry_master, trackpos_master;
3603 mux->cues_pos = ebml->pos;
3604 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
3605 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
3607 for (n = 0; n < mux->num_indexes; n++) {
3608 GstMatroskaIndex *idx = &mux->index[n];
3610 pointentry_master = gst_ebml_write_master_start (ebml,
3611 GST_MATROSKA_ID_POINTENTRY);
3612 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
3613 idx->time / mux->time_scale);
3614 trackpos_master = gst_ebml_write_master_start (ebml,
3615 GST_MATROSKA_ID_CUETRACKPOSITIONS);
3616 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
3617 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
3618 idx->pos - mux->segment_master);
3619 gst_ebml_write_master_finish (ebml, trackpos_master);
3620 gst_ebml_write_master_finish (ebml, pointentry_master);
3623 gst_ebml_write_master_finish (ebml, master);
3624 gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
3628 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3629 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3630 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3632 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux) || toc != NULL) {
3633 guint64 master_tags = 0, master_tag;
3635 GST_DEBUG_OBJECT (mux, "Writing tags");
3637 if (has_main_tags) {
3638 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
3639 mux->tags_pos = ebml->pos;
3640 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3641 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3644 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3645 if (mux->internal_toc != NULL) {
3646 toc_tags = gst_toc_get_tags (mux->internal_toc);
3647 toc_has_tags = (toc_tags != NULL);
3648 gst_tag_list_foreach (toc_tags, gst_matroska_mux_write_simple_tag,
3652 gst_ebml_write_master_finish (ebml, master_tag);
3655 if (mux->internal_toc != NULL) {
3656 for (cur = gst_toc_get_entries (mux->internal_toc); cur != NULL;
3658 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, &master_tags,
3663 if (master_tags == 0 && gst_matroska_mux_streams_have_tags (mux)) {
3664 mux->tags_pos = ebml->pos;
3665 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3667 gst_matroska_mux_write_streams_tags (mux);
3669 if (master_tags != 0)
3670 gst_ebml_write_master_finish (ebml, master_tags);
3673 /* update seekhead. We know that:
3674 * - a seekhead contains 5 entries.
3675 * - order of entries is as above.
3676 * - a seekhead has a 4-byte header + 8-byte length
3677 * - each entry is 2-byte master, 2-byte ID pointer,
3678 * 2-byte length pointer, all 8/1-byte length, 4-
3679 * byte ID and 8-byte length pointer, where the
3680 * length pointer starts at 20.
3681 * - all entries are local to the segment (so pos - segment_master).
3682 * - so each entry is at 12 + 20 + num * 28. */
3683 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
3684 mux->info_pos - mux->segment_master);
3685 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
3686 mux->tracks_pos - mux->segment_master);
3687 if (toc != NULL && mux->chapters_pos > 0) {
3688 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
3689 mux->chapters_pos - mux->segment_master);
3692 guint64 my_pos = ebml->pos;
3694 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
3695 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3696 gst_ebml_write_seek (ebml, my_pos);
3698 if (mux->index != NULL) {
3699 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
3700 mux->cues_pos - mux->segment_master);
3703 guint64 my_pos = ebml->pos;
3705 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
3706 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3707 gst_ebml_write_seek (ebml, my_pos);
3710 if (mux->tags_pos != 0 || toc_has_tags) {
3711 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 144,
3712 mux->tags_pos - mux->segment_master);
3715 guint64 my_pos = ebml->pos;
3717 gst_ebml_write_seek (ebml, mux->seekhead_pos + 124);
3718 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3719 gst_ebml_write_seek (ebml, my_pos);
3723 gst_toc_unref (toc);
3727 * - first get the overall duration
3728 * (a released track may have left a duration in here)
3729 * - write some track header data for subtitles
3731 duration = mux->duration;
3733 for (collected = mux->collect->data; collected;
3734 collected = g_slist_next (collected)) {
3735 GstMatroskaPad *collect_pad;
3737 * observed duration, this will never remain GST_CLOCK_TIME_NONE
3738 * since this means buffer without timestamps that is not possible
3740 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
3742 collect_pad = (GstMatroskaPad *) collected->data;
3744 GST_DEBUG_OBJECT (mux,
3745 "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
3746 " end ts %" GST_TIME_FORMAT, collect_pad,
3747 GST_TIME_ARGS (collect_pad->start_ts),
3748 GST_TIME_ARGS (collect_pad->end_ts));
3750 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
3751 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
3752 collected_duration =
3753 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
3754 GST_DEBUG_OBJECT (collect_pad->collect.pad,
3755 "final track duration: %" GST_TIME_FORMAT,
3756 GST_TIME_ARGS (collected_duration));
3758 GST_WARNING_OBJECT (collect_pad->collect.pad,
3759 "unable to get final track duration");
3761 if (GST_CLOCK_TIME_IS_VALID (collected_duration) &&
3762 duration < collected_duration)
3763 duration = collected_duration;
3767 /* seek back (optional, but do anyway) */
3768 gst_ebml_write_seek (ebml, pos);
3770 /* update duration */
3771 if (duration != 0) {
3772 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
3773 GST_TIME_ARGS (duration));
3774 pos = mux->ebml_write->pos;
3775 gst_ebml_write_seek (ebml, mux->duration_pos);
3776 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3777 gst_guint64_to_gdouble (duration) /
3778 gst_guint64_to_gdouble (mux->time_scale));
3779 gst_ebml_write_seek (ebml, pos);
3782 guint64 my_pos = ebml->pos;
3784 gst_ebml_write_seek (ebml, mux->duration_pos);
3785 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
3786 gst_ebml_write_seek (ebml, my_pos);
3788 GST_DEBUG_OBJECT (mux, "finishing segment");
3789 /* finish segment - this also writes element length */
3790 gst_ebml_write_master_finish (ebml, mux->segment_pos);
3794 * gst_matroska_mux_buffer_header:
3795 * @track: Track context.
3796 * @relative_timestamp: relative timestamp of the buffer
3797 * @flags: Buffer flags.
3799 * Create a buffer containing buffer header.
3801 * Returns: New buffer.
3804 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
3805 gint16 relative_timestamp, int flags)
3808 guint8 *data = g_malloc (4);
3810 hdr = gst_buffer_new_wrapped (data, 4);
3811 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
3812 data[0] = track->num | 0x80;
3813 /* time relative to clustertime */
3814 GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
3822 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
3823 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
3824 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
3827 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
3828 GstMatroskaPad * collect_pad, GstBuffer * buf)
3830 GstMatroskaTrackVideoContext *ctx =
3831 (GstMatroskaTrackVideoContext *) collect_pad->track;
3836 guint32 next_parse_offset;
3837 GstBuffer *ret = NULL;
3838 gboolean is_muxing_unit = FALSE;
3840 gst_buffer_map (buf, &map, GST_MAP_READ);
3845 gst_buffer_unmap (buf, &map);
3846 gst_buffer_unref (buf);
3850 /* Check if this buffer contains a picture or end-of-sequence packet */
3851 while (size >= 13) {
3852 if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
3853 gst_buffer_unmap (buf, &map);
3854 gst_buffer_unref (buf);
3858 parse_code = GST_READ_UINT8 (data + 4);
3859 if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
3860 if (ctx->dirac_unit) {
3861 gst_buffer_unref (ctx->dirac_unit);
3862 ctx->dirac_unit = NULL;
3864 } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
3865 parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
3866 is_muxing_unit = TRUE;
3870 next_parse_offset = GST_READ_UINT32_BE (data + 5);
3872 if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
3875 data += next_parse_offset;
3876 size -= next_parse_offset;
3879 if (ctx->dirac_unit)
3880 ctx->dirac_unit = gst_buffer_append (ctx->dirac_unit, gst_buffer_ref (buf));
3882 ctx->dirac_unit = gst_buffer_ref (buf);
3884 gst_buffer_unmap (buf, &map);
3886 if (is_muxing_unit) {
3887 ret = gst_buffer_make_writable (ctx->dirac_unit);
3888 ctx->dirac_unit = NULL;
3889 gst_buffer_copy_into (ret, buf,
3890 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
3891 gst_buffer_unref (buf);
3893 gst_buffer_unref (buf);
3901 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
3905 GValue streamheader = { 0 };
3906 GValue bufval = { 0 };
3907 GstBuffer *streamheader_buffer;
3908 GstEbmlWrite *ebml = mux->ebml_write;
3910 streamheader_buffer = gst_ebml_stop_streamheader (ebml);
3911 caps = gst_caps_copy (mux->ebml_write->caps);
3912 s = gst_caps_get_structure (caps, 0);
3913 g_value_init (&streamheader, GST_TYPE_ARRAY);
3914 g_value_init (&bufval, GST_TYPE_BUFFER);
3915 GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_HEADER);
3916 gst_value_set_buffer (&bufval, streamheader_buffer);
3917 gst_value_array_append_value (&streamheader, &bufval);
3918 g_value_unset (&bufval);
3919 gst_structure_set_value (s, "streamheader", &streamheader);
3920 g_value_unset (&streamheader);
3921 gst_caps_replace (&ebml->caps, caps);
3922 gst_buffer_unref (streamheader_buffer);
3923 gst_pad_set_caps (mux->srcpad, caps);
3924 gst_caps_unref (caps);
3928 * gst_matroska_mux_write_data:
3929 * @mux: #GstMatroskaMux
3930 * @collect_pad: #GstMatroskaPad with the data
3932 * Write collected data (called from gst_matroska_mux_collected).
3934 * Returns: Result of the gst_pad_push issued to write the data.
3936 static GstFlowReturn
3937 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
3940 GstEbmlWrite *ebml = mux->ebml_write;
3943 gboolean write_duration;
3944 guint64 cluster_time_scaled;
3945 gint16 relative_timestamp;
3946 gint64 relative_timestamp64;
3947 guint64 block_duration, duration_diff = 0;
3948 gboolean is_video_keyframe = FALSE;
3949 gboolean is_video_invisible = FALSE;
3950 gboolean is_audio_only = FALSE;
3951 gboolean is_min_duration_reached = FALSE;
3952 gboolean is_max_duration_exceeded = FALSE;
3953 GstMatroskamuxPad *pad;
3955 GstClockTime buffer_timestamp;
3956 GstAudioClippingMeta *cmeta = NULL;
3959 pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
3961 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
3962 if (collect_pad->track->xiph_headers_to_skip > 0) {
3963 --collect_pad->track->xiph_headers_to_skip;
3964 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER)) {
3965 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
3966 gst_buffer_unref (buf);
3971 /* for dirac we have to queue up everything up to a picture unit */
3972 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC)) {
3973 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
3976 } else if (!strcmp (collect_pad->track->codec_id,
3977 GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) {
3978 /* Remove the 'Frame container atom' header' */
3979 buf = gst_buffer_make_writable (buf);
3980 gst_buffer_resize (buf, 8, gst_buffer_get_size (buf) - 8);
3984 gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
3985 if (buffer_timestamp >= mux->earliest_time) {
3986 buffer_timestamp -= mux->earliest_time;
3988 buffer_timestamp = 0;
3991 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
3992 * this would wreak havoc with time stored in matroska file */
3993 /* TODO: maybe calculate a timestamp by using the previous timestamp
3994 * and default duration */
3995 if (!GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
3996 GST_WARNING_OBJECT (collect_pad->collect.pad,
3997 "Invalid buffer timestamp; dropping buffer");
3998 gst_buffer_unref (buf);
4002 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4003 && collect_pad->track->codec_delay) {
4004 /* All timestamps should include the codec delay */
4005 if (buffer_timestamp > collect_pad->track->codec_delay) {
4006 buffer_timestamp += collect_pad->track->codec_delay;
4008 buffer_timestamp = 0;
4009 duration_diff = collect_pad->track->codec_delay - buffer_timestamp;
4013 /* set the timestamp for outgoing buffers */
4014 ebml->timestamp = buffer_timestamp;
4016 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
4017 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
4018 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
4019 GST_TIME_ARGS (buffer_timestamp));
4020 is_video_keyframe = TRUE;
4021 } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DECODE_ONLY) &&
4022 (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP8)
4023 || !strcmp (collect_pad->track->codec_id,
4024 GST_MATROSKA_CODEC_ID_VIDEO_VP9))) {
4025 GST_LOG_OBJECT (mux,
4026 "have VP8 video invisible frame, " "ts=%" GST_TIME_FORMAT,
4027 GST_TIME_ARGS (buffer_timestamp));
4028 is_video_invisible = TRUE;
4032 /* From this point on we use the buffer_timestamp to do cluster and other
4033 * related arithmetic, so apply the timestamp offset if we have one */
4034 buffer_timestamp += mux->cluster_timestamp_offset;
4036 is_audio_only = (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
4037 (mux->num_streams == 1);
4038 is_min_duration_reached = (mux->min_cluster_duration == 0
4039 || (buffer_timestamp > mux->cluster_time
4040 && (buffer_timestamp - mux->cluster_time) >=
4041 mux->min_cluster_duration));
4042 is_max_duration_exceeded = (mux->max_cluster_duration > 0
4043 && buffer_timestamp > mux->cluster_time
4044 && (buffer_timestamp - mux->cluster_time) >=
4045 MIN (G_MAXINT16 * mux->time_scale, mux->max_cluster_duration));
4048 /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
4049 * or when we may be reaching the limit of the relative timestamp */
4050 if (is_max_duration_exceeded || (is_video_keyframe
4051 && is_min_duration_reached) || mux->force_key_unit_event
4052 || (is_audio_only && is_min_duration_reached)) {
4053 if (!mux->ebml_write->streamable)
4054 gst_ebml_write_master_finish (ebml, mux->cluster);
4056 /* Forward the GstForceKeyUnit event after finishing the cluster */
4057 if (mux->force_key_unit_event) {
4058 gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
4059 mux->force_key_unit_event = NULL;
4061 cluster_time_scaled =
4062 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4064 mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
4065 mux->cluster_pos = ebml->pos;
4066 gst_ebml_write_set_cache (ebml, 0x20);
4068 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4069 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4070 cluster_time_scaled);
4071 GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
4072 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
4073 gst_ebml_write_flush_cache (ebml, is_video_keyframe
4074 || is_audio_only, buffer_timestamp);
4075 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
4076 mux->prev_cluster_size);
4077 /* cluster_time needs to be identical in value to what's stored in the
4078 * matroska so we need to have it with the same precision as what's
4079 * possible with the set timecodescale rather than just using the
4081 * If this is not done the rounding of relative_timestamp will be
4082 * incorrect and possibly making the timestamps get out of order if tw
4083 * buffers arrive at the same millisecond (assuming default timecodescale
4086 gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4090 cluster_time_scaled =
4091 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4092 mux->cluster_pos = ebml->pos;
4093 gst_ebml_write_set_cache (ebml, 0x20);
4094 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4095 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4096 cluster_time_scaled);
4097 gst_ebml_write_flush_cache (ebml, TRUE, buffer_timestamp);
4098 /* cluster_time needs to be identical in value to what's stored in the
4099 * matroska so we need to have it with the same precision as what's
4100 * possible with the set timecodescale rather than just using the
4102 * If this is not done the rounding of relative_timestamp will be
4103 * incorrect and possibly making the timestamps get out of order if tw
4104 * buffers arrive at the same millisecond (assuming default timecodescale
4107 gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4110 /* We currently write index entries for all video tracks or for the audio
4111 * track in a single-track audio file. This could be improved by keeping the
4112 * index only for the *first* video track. */
4114 /* TODO: index is useful for every track, should contain the number of
4115 * the block in the cluster which contains the timestamp, should also work
4116 * for files with multiple audio tracks.
4118 if (!mux->ebml_write->streamable && (is_video_keyframe || is_audio_only)) {
4121 if (mux->min_index_interval != 0) {
4122 for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
4123 if (mux->index[last_idx].track == collect_pad->track->num)
4128 if (last_idx < 0 || mux->min_index_interval == 0 ||
4129 (GST_CLOCK_DIFF (mux->index[last_idx].time, buffer_timestamp)
4130 >= mux->min_index_interval)) {
4131 GstMatroskaIndex *idx;
4133 if (mux->num_indexes % 32 == 0) {
4134 mux->index = g_renew (GstMatroskaIndex, mux->index,
4135 mux->num_indexes + 32);
4137 idx = &mux->index[mux->num_indexes++];
4139 idx->pos = mux->cluster_pos;
4140 idx->time = buffer_timestamp;
4141 idx->track = collect_pad->track->num;
4145 /* Check if the duration differs from the default duration. */
4146 write_duration = FALSE;
4148 if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
4149 block_duration = GST_BUFFER_DURATION (buf) + duration_diff;
4150 block_duration = gst_util_uint64_scale (block_duration, 1, mux->time_scale);
4152 /* small difference should be ok. */
4153 if (block_duration > collect_pad->default_duration_scaled + 1 ||
4154 block_duration < collect_pad->default_duration_scaled - 1) {
4155 write_duration = TRUE;
4159 /* write the block, for doctype v2 use SimpleBlock if possible
4160 * one slice (*breath*).
4161 * FIXME: Need to do correct lacing! */
4162 relative_timestamp64 = buffer_timestamp - mux->cluster_time;
4163 if (relative_timestamp64 >= 0) {
4164 /* round the timestamp */
4165 relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
4166 relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
4169 /* round the timestamp */
4170 relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
4171 relative_timestamp =
4172 -((gint16) gst_util_uint64_scale (-relative_timestamp64, 1,
4176 if (is_video_invisible)
4179 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
4180 cmeta = gst_buffer_get_audio_clipping_meta (buf);
4181 g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);
4183 /* Start clipping is done via header and CodecDelay */
4184 if (cmeta && !cmeta->end)
4188 if (mux->doctype_version > 1 && !write_duration && !cmeta) {
4189 if (is_video_keyframe)
4193 gst_matroska_mux_create_buffer_header (collect_pad->track,
4194 relative_timestamp, flags);
4195 gst_ebml_write_set_cache (ebml, 0x40);
4196 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
4197 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4198 gst_ebml_write_buffer (ebml, hdr);
4199 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4200 gst_ebml_write_buffer (ebml, buf);
4202 return gst_ebml_last_write_result (ebml);
4204 gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
4205 /* write and call order slightly unnatural,
4206 * but avoids seek and minizes pushing */
4207 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
4209 gst_matroska_mux_create_buffer_header (collect_pad->track,
4210 relative_timestamp, flags);
4212 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
4214 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4216 /* Start clipping is done via header and CodecDelay */
4219 gst_util_uint64_scale_round (cmeta->end, GST_SECOND, 48000);
4220 gst_ebml_write_sint (ebml, GST_MATROSKA_ID_DISCARDPADDING, end);
4224 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
4225 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4226 gst_ebml_write_buffer (ebml, hdr);
4227 gst_ebml_write_master_finish_full (ebml, blockgroup,
4228 gst_buffer_get_size (buf));
4229 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4230 gst_ebml_write_buffer (ebml, buf);
4232 return gst_ebml_last_write_result (ebml);
4237 * gst_matroska_mux_handle_buffer:
4238 * @pads: #GstCollectPads
4239 * @uuser_data: #GstMatroskaMux
4241 * Collectpads callback.
4243 * Returns: #GstFlowReturn
4245 static GstFlowReturn
4246 gst_matroska_mux_handle_buffer (GstCollectPads * pads, GstCollectData * data,
4247 GstBuffer * buf, gpointer user_data)
4249 GstClockTime buffer_timestamp;
4250 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
4251 GstEbmlWrite *ebml = mux->ebml_write;
4252 GstMatroskaPad *best = (GstMatroskaPad *) data;
4253 GstFlowReturn ret = GST_FLOW_OK;
4254 GST_DEBUG_OBJECT (mux, "Collected pads");
4256 /* start with a header */
4257 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
4258 if (mux->collect->data == NULL) {
4259 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
4260 ("No input streams configured"));
4261 return GST_FLOW_ERROR;
4263 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
4264 gst_ebml_start_streamheader (ebml);
4265 gst_matroska_mux_start (mux, best, buf);
4266 gst_matroska_mux_stop_streamheader (mux);
4267 mux->state = GST_MATROSKA_MUX_STATE_DATA;
4270 /* if there is no best pad, we have reached EOS */
4272 GST_DEBUG_OBJECT (mux, "No best pad. Finishing...");
4273 if (!mux->ebml_write->streamable) {
4274 gst_matroska_mux_finish (mux);
4276 GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
4278 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
4283 if (best->track->codec_id == NULL) {
4284 GST_ERROR_OBJECT (best->collect.pad, "No codec-id for pad");
4285 ret = GST_FLOW_NOT_NEGOTIATED;
4289 /* if we have a best stream, should also have a buffer */
4292 buffer_timestamp = gst_matroska_track_get_buffer_timestamp (best->track, buf);
4293 if (buffer_timestamp >= mux->earliest_time) {
4294 buffer_timestamp -= mux->earliest_time;
4296 GST_ERROR_OBJECT (mux,
4297 "PTS before first PTS (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")",
4298 GST_TIME_ARGS (buffer_timestamp), GST_TIME_ARGS (mux->earliest_time));
4299 buffer_timestamp = 0;
4302 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
4303 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
4304 GST_TIME_ARGS (buffer_timestamp),
4305 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
4307 /* make note of first and last encountered timestamps, so we can calculate
4308 * the actual duration later when we send an updated header on eos */
4309 if (GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
4310 GstClockTime start_ts = buffer_timestamp;
4311 GstClockTime end_ts = start_ts;
4313 if (GST_BUFFER_DURATION_IS_VALID (buf))
4314 end_ts += GST_BUFFER_DURATION (buf);
4315 else if (best->track->default_duration)
4316 end_ts += best->track->default_duration;
4318 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
4319 best->end_ts = end_ts;
4321 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
4322 start_ts < best->start_ts))
4323 best->start_ts = start_ts;
4326 /* write one buffer */
4327 ret = gst_matroska_mux_write_data (mux, best, buf);
4335 * gst_matroska_mux_change_state:
4336 * @element: #GstMatroskaMux
4337 * @transition: State change transition.
4339 * Change the muxer state.
4341 * Returns: #GstStateChangeReturn
4343 static GstStateChangeReturn
4344 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
4346 GstStateChangeReturn ret;
4347 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
4349 switch (transition) {
4350 case GST_STATE_CHANGE_NULL_TO_READY:
4352 case GST_STATE_CHANGE_READY_TO_PAUSED:
4353 gst_collect_pads_start (mux->collect);
4355 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4357 case GST_STATE_CHANGE_PAUSED_TO_READY:
4358 gst_collect_pads_stop (mux->collect);
4364 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4366 switch (transition) {
4367 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4369 case GST_STATE_CHANGE_PAUSED_TO_READY:
4370 gst_matroska_mux_reset (GST_ELEMENT (mux));
4372 case GST_STATE_CHANGE_READY_TO_NULL:
4382 gst_matroska_mux_set_property (GObject * object,
4383 guint prop_id, const GValue * value, GParamSpec * pspec)
4385 GstMatroskaMux *mux;
4387 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4388 mux = GST_MATROSKA_MUX (object);
4391 case PROP_WRITING_APP:
4392 if (!g_value_get_string (value)) {
4393 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
4396 g_free (mux->writing_app);
4397 mux->writing_app = g_value_dup_string (value);
4399 case PROP_DOCTYPE_VERSION:
4400 mux->doctype_version = g_value_get_int (value);
4402 case PROP_MIN_INDEX_INTERVAL:
4403 mux->min_index_interval = g_value_get_int64 (value);
4405 case PROP_STREAMABLE:
4406 mux->ebml_write->streamable = g_value_get_boolean (value);
4408 case PROP_TIMECODESCALE:
4409 mux->time_scale = g_value_get_int64 (value);
4411 case PROP_MIN_CLUSTER_DURATION:
4412 mux->min_cluster_duration = g_value_get_int64 (value);
4414 case PROP_MAX_CLUSTER_DURATION:
4415 mux->max_cluster_duration = g_value_get_int64 (value);
4417 case PROP_OFFSET_TO_ZERO:
4418 mux->offset_to_zero = g_value_get_boolean (value);
4420 case PROP_CREATION_TIME:
4421 g_clear_pointer (&mux->creation_time, g_date_time_unref);
4422 mux->creation_time = g_value_dup_boxed (value);
4424 case PROP_CLUSTER_TIMESTAMP_OFFSET:
4425 mux->cluster_timestamp_offset = g_value_get_uint64 (value);
4428 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4434 gst_matroska_mux_get_property (GObject * object,
4435 guint prop_id, GValue * value, GParamSpec * pspec)
4437 GstMatroskaMux *mux;
4439 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4440 mux = GST_MATROSKA_MUX (object);
4443 case PROP_WRITING_APP:
4444 g_value_set_string (value, mux->writing_app);
4446 case PROP_DOCTYPE_VERSION:
4447 g_value_set_int (value, mux->doctype_version);
4449 case PROP_MIN_INDEX_INTERVAL:
4450 g_value_set_int64 (value, mux->min_index_interval);
4452 case PROP_STREAMABLE:
4453 g_value_set_boolean (value, mux->ebml_write->streamable);
4455 case PROP_TIMECODESCALE:
4456 g_value_set_int64 (value, mux->time_scale);
4458 case PROP_MIN_CLUSTER_DURATION:
4459 g_value_set_int64 (value, mux->min_cluster_duration);
4461 case PROP_MAX_CLUSTER_DURATION:
4462 g_value_set_int64 (value, mux->max_cluster_duration);
4464 case PROP_OFFSET_TO_ZERO:
4465 g_value_set_boolean (value, mux->offset_to_zero);
4467 case PROP_CREATION_TIME:
4468 g_value_set_boxed (value, mux->creation_time);
4470 case PROP_CLUSTER_TIMESTAMP_OFFSET:
4471 g_value_set_uint64 (value, mux->cluster_timestamp_offset);
4474 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);