1 /* GStreamer Matroska muxer/demuxer
2 * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3 * (c) 2005 Michal Benes <michal.benes@xeris.cz>
4 * (c) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * (c) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
7 * matroska-mux.c: matroska file/stream muxer
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
25 /* TODO: - check everywhere that we don't write invalid values
26 * - make sure timestamps are correctly scaled everywhere
30 * SECTION:element-matroskamux
33 * matroskamux muxes different input streams into a Matroska file.
35 * ## Example launch line
37 * gst-launch-1.0 -v filesrc location=/path/to/mp3 ! mpegaudioparse ! matroskamux name=mux ! filesink location=test.mkv filesrc location=/path/to/theora.ogg ! oggdemux ! theoraparse ! mux.
38 * ]| This pipeline muxes an MP3 file and a Ogg Theora video into a Matroska file.
40 * gst-launch-1.0 -v audiotestsrc num-buffers=100 ! audioconvert ! vorbisenc ! matroskamux ! filesink location=test.mka
41 * ]| This pipeline muxes a 440Hz sine wave encoded with the Vorbis codec into a Matroska file.
53 #include <gst/audio/audio.h>
54 #include <gst/riff/riff-media.h>
55 #include <gst/tag/tag.h>
56 #include <gst/pbutils/codec-utils.h>
58 #include "gstmatroskaelements.h"
59 #include "matroska-mux.h"
60 #include "matroska-ids.h"
62 #define GST_MATROSKA_MUX_CHAPLANG "und"
64 GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
65 #define GST_CAT_DEFAULT matroskamux_debug
72 PROP_MIN_INDEX_INTERVAL,
75 PROP_MIN_CLUSTER_DURATION,
76 PROP_MAX_CLUSTER_DURATION,
79 PROP_CLUSTER_TIMESTAMP_OFFSET,
82 #define DEFAULT_DOCTYPE_VERSION 2
83 #define DEFAULT_WRITING_APP "GStreamer Matroska muxer"
84 #define DEFAULT_MIN_INDEX_INTERVAL 0
85 #define DEFAULT_STREAMABLE FALSE
86 #define DEFAULT_TIMECODESCALE GST_MSECOND
87 #define DEFAULT_MIN_CLUSTER_DURATION 500 * GST_MSECOND
88 #define DEFAULT_MAX_CLUSTER_DURATION 65535 * GST_MSECOND
89 #define DEFAULT_OFFSET_TO_ZERO FALSE
90 #define DEFAULT_CLUSTER_TIMESTAMP_OFFSET 0
92 /* WAVEFORMATEX is gst_riff_strf_auds + an extra guint16 extension size */
93 #define WAVEFORMATEX_SIZE (2 + sizeof (gst_riff_strf_auds))
95 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
98 GST_STATIC_CAPS ("video/x-matroska; video/x-matroska-3d; audio/x-matroska")
101 #define COMMON_VIDEO_CAPS \
102 "width = (int) [ 1, MAX ], " \
103 "height = (int) [ 1, MAX ] "
106 * * require codec data, etc as needed
109 static GstStaticPadTemplate videosink_templ =
110 GST_STATIC_PAD_TEMPLATE ("video_%u",
113 GST_STATIC_CAPS ("video/mpeg, "
114 "mpegversion = (int) { 1, 2, 4 }, "
115 "systemstream = (boolean) false, "
116 COMMON_VIDEO_CAPS "; "
117 "video/x-h264, stream-format = (string) { avc, avc3 }, alignment=au, "
118 COMMON_VIDEO_CAPS "; "
119 "video/x-h265, stream-format = (string) { hvc1, hev1 }, alignment=au, "
120 COMMON_VIDEO_CAPS "; "
122 COMMON_VIDEO_CAPS "; "
124 COMMON_VIDEO_CAPS "; "
126 COMMON_VIDEO_CAPS "; "
128 COMMON_VIDEO_CAPS "; "
130 COMMON_VIDEO_CAPS "; "
132 COMMON_VIDEO_CAPS "; "
135 COMMON_VIDEO_CAPS "; "
136 "video/x-pn-realvideo, "
137 "rmversion = (int) [1, 4], "
138 COMMON_VIDEO_CAPS "; "
140 COMMON_VIDEO_CAPS "; "
142 COMMON_VIDEO_CAPS "; "
144 "format = (string) { YUY2, I420, YV12, UYVY, AYUV, GRAY8, BGR, RGB }, "
145 COMMON_VIDEO_CAPS "; "
147 COMMON_VIDEO_CAPS "; "
148 "video/x-wmv, " "wmvversion = (int) [ 1, 3 ], " COMMON_VIDEO_CAPS "; "
149 "video/x-av1, " COMMON_VIDEO_CAPS ";"
150 "video/x-ffv, ffversion = (int) 1, " COMMON_VIDEO_CAPS)
153 #define COMMON_AUDIO_CAPS \
154 "channels = (int) [ 1, MAX ], " \
155 "rate = (int) [ 1, MAX ]"
158 * * require codec data, etc as needed
160 static GstStaticPadTemplate audiosink_templ =
161 GST_STATIC_PAD_TEMPLATE ("audio_%u",
164 GST_STATIC_CAPS ("audio/mpeg, "
165 "mpegversion = (int) 1, "
166 "layer = (int) [ 1, 3 ], "
167 COMMON_AUDIO_CAPS "; "
169 "mpegversion = (int) { 2, 4 }, "
170 "stream-format = (string) raw, "
171 COMMON_AUDIO_CAPS "; "
173 COMMON_AUDIO_CAPS "; "
175 COMMON_AUDIO_CAPS "; "
177 COMMON_AUDIO_CAPS "; "
179 COMMON_AUDIO_CAPS "; "
181 COMMON_AUDIO_CAPS "; "
184 COMMON_AUDIO_CAPS "; "
186 "format = (string) { U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }, "
187 "layout = (string) interleaved, "
188 COMMON_AUDIO_CAPS ";"
190 "width = (int) { 8, 16, 24 }, "
191 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
192 "audio/x-pn-realaudio, "
193 "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS "; "
194 "audio/x-wma, " "wmaversion = (int) [ 1, 3 ], "
195 "block_align = (int) [ 0, 65535 ], bitrate = (int) [ 0, 524288 ], "
196 COMMON_AUDIO_CAPS ";"
198 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
200 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
202 "layout = (string)dvi, "
203 "block_align = (int)[64, 8192], "
204 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
206 "channels = (int)1," "rate = (int)16000; "
208 "layout = (string)g726, " "channels = (int)1," "rate = (int)8000; ")
211 static GstStaticPadTemplate subtitlesink_templ =
212 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
215 GST_STATIC_CAPS ("subtitle/x-kate; "
216 "text/x-raw, format=utf8; application/x-ssa; application/x-ass; "
217 "application/x-usf; subpicture/x-dvd; "
218 "application/x-subtitle-unknown")
221 static gpointer parent_class; /* NULL */
223 /* Matroska muxer destructor */
224 static void gst_matroska_mux_class_init (GstMatroskaMuxClass * klass);
225 static void gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class);
226 static void gst_matroska_mux_finalize (GObject * object);
228 /* Pads collected callback */
229 static GstFlowReturn gst_matroska_mux_handle_buffer (GstCollectPads * pads,
230 GstCollectData * data, GstBuffer * buf, gpointer user_data);
231 static gboolean gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
232 GstCollectData * data, GstEvent * event, gpointer user_data);
235 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
236 GstObject * parent, GstEvent * event);
237 static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
238 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
239 static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
241 /* gst internal change state handler */
242 static GstStateChangeReturn
243 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
245 /* gobject bla bla */
246 static void gst_matroska_mux_set_property (GObject * object,
247 guint prop_id, const GValue * value, GParamSpec * pspec);
248 static void gst_matroska_mux_get_property (GObject * object,
249 guint prop_id, GValue * value, GParamSpec * pspec);
252 static void gst_matroska_mux_reset (GstElement * element);
255 static guint64 gst_matroska_mux_create_uid (GstMatroskaMux * mux);
257 static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
258 GstMatroskaTrackContext * context);
259 static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
260 GstMatroskaTrackContext * context);
261 static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
262 GstMatroskaTrackContext * context);
263 static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
264 GstMatroskaTrackContext * context);
265 static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
266 GstMatroskaTrackContext * context);
268 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
270 static gboolean gst_matroska_mux_tag_list_is_empty (const GstTagList * list);
271 static void gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux);
272 static gboolean gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux);
274 /* Cannot use boilerplate macros here because we need the full init function
275 * signature with the additional class argument, so we use the right template
276 * for the sink caps */
278 gst_matroska_mux_get_type (void)
280 static GType object_type; /* 0 */
282 if (object_type == 0) {
283 static const GTypeInfo object_info = {
284 sizeof (GstMatroskaMuxClass),
285 NULL, /* base_init */
286 NULL, /* base_finalize */
287 (GClassInitFunc) gst_matroska_mux_class_init,
288 NULL, /* class_finalize */
289 NULL, /* class_data */
290 sizeof (GstMatroskaMux),
292 (GInstanceInitFunc) gst_matroska_mux_init
294 const GInterfaceInfo iface_info = { NULL };
296 object_type = g_type_register_static (GST_TYPE_ELEMENT,
297 "GstMatroskaMux", &object_info, (GTypeFlags) 0);
299 g_type_add_interface_static (object_type, GST_TYPE_TAG_SETTER, &iface_info);
300 g_type_add_interface_static (object_type, GST_TYPE_TOC_SETTER, &iface_info);
306 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (matroskamux, "matroskamux",
307 GST_RANK_PRIMARY, GST_TYPE_MATROSKA_MUX, matroska_element_init (plugin));
310 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
312 GObjectClass *gobject_class;
313 GstElementClass *gstelement_class;
315 gobject_class = (GObjectClass *) klass;
316 gstelement_class = (GstElementClass *) klass;
318 gst_element_class_add_static_pad_template (gstelement_class,
320 gst_element_class_add_static_pad_template (gstelement_class,
322 gst_element_class_add_static_pad_template (gstelement_class,
323 &subtitlesink_templ);
324 gst_element_class_add_static_pad_template (gstelement_class, &src_templ);
325 gst_element_class_set_static_metadata (gstelement_class, "Matroska muxer",
327 "Muxes video/audio/subtitle streams into a matroska stream",
328 "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
330 GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
333 gobject_class->finalize = gst_matroska_mux_finalize;
335 gobject_class->get_property = gst_matroska_mux_get_property;
336 gobject_class->set_property = gst_matroska_mux_set_property;
338 g_object_class_install_property (gobject_class, PROP_WRITING_APP,
339 g_param_spec_string ("writing-app", "Writing application.",
340 "The name the application that creates the matroska file.",
341 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
342 g_object_class_install_property (gobject_class, PROP_DOCTYPE_VERSION,
343 g_param_spec_int ("version", "DocType version",
344 "This parameter determines what Matroska features can be used.",
345 1, 2, DEFAULT_DOCTYPE_VERSION,
346 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
347 g_object_class_install_property (gobject_class, PROP_MIN_INDEX_INTERVAL,
348 g_param_spec_int64 ("min-index-interval", "Minimum time between index "
349 "entries", "An index entry is created every so many nanoseconds.",
350 0, G_MAXINT64, DEFAULT_MIN_INDEX_INTERVAL,
351 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
352 g_object_class_install_property (gobject_class, PROP_STREAMABLE,
353 g_param_spec_boolean ("streamable", "Determines whether output should "
354 "be streamable", "If set to true, the output should be as if it is "
355 "to be streamed and hence no indexes written or duration written.",
356 DEFAULT_STREAMABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
357 g_object_class_install_property (gobject_class, PROP_TIMECODESCALE,
358 g_param_spec_int64 ("timecodescale", "Timecode Scale",
359 "TimecodeScale used to calculate the Raw Timecode of a Block", 1,
360 GST_SECOND, DEFAULT_TIMECODESCALE,
361 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
362 g_object_class_install_property (gobject_class, PROP_MIN_CLUSTER_DURATION,
363 g_param_spec_int64 ("min-cluster-duration", "Minimum cluster duration",
364 "Desired cluster duration as nanoseconds. A new cluster will be "
365 "created irrespective of this property if a force key unit event "
366 "is received. 0 means create a new cluster for each video keyframe "
367 "or for each audio buffer in audio only streams.", 0,
368 G_MAXINT64, DEFAULT_MIN_CLUSTER_DURATION,
369 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
370 g_object_class_install_property (gobject_class, PROP_MAX_CLUSTER_DURATION,
371 g_param_spec_int64 ("max-cluster-duration", "Maximum cluster duration",
372 "A new cluster will be created if its duration exceeds this value. "
373 "0 means no maximum duration.", 0,
374 G_MAXINT64, DEFAULT_MAX_CLUSTER_DURATION,
375 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
376 g_object_class_install_property (gobject_class, PROP_OFFSET_TO_ZERO,
377 g_param_spec_boolean ("offset-to-zero", "Offset To Zero",
378 "Offsets all streams so that the " "earliest stream starts at 0.",
379 DEFAULT_OFFSET_TO_ZERO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
380 g_object_class_install_property (gobject_class, PROP_CREATION_TIME,
381 g_param_spec_boxed ("creation-time", "Creation Time",
382 "Date and time of creation. This will be used for the DateUTC field."
383 " NULL means that the current time will be used.",
384 G_TYPE_DATE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
387 * GstMatroskaMux:cluster-timestamp-offset:
389 * An offset to add to all clusters/blocks (in nanoseconds)
393 g_object_class_install_property (gobject_class, PROP_CLUSTER_TIMESTAMP_OFFSET,
394 g_param_spec_uint64 ("cluster-timestamp-offset",
395 "Cluster timestamp offset",
396 "An offset to add to all clusters/blocks (in nanoseconds)", 0,
397 G_MAXUINT64, DEFAULT_CLUSTER_TIMESTAMP_OFFSET,
398 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
400 gstelement_class->change_state =
401 GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
402 gstelement_class->request_new_pad =
403 GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
404 gstelement_class->release_pad =
405 GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
407 parent_class = g_type_class_peek_parent (klass);
411 * Start of pad option handler code
413 #define DEFAULT_PAD_FRAME_DURATION TRUE
418 PROP_PAD_FRAME_DURATION
424 gboolean frame_duration;
425 gboolean frame_duration_user;
428 typedef GstPadClass GstMatroskamuxPadClass;
430 GType gst_matroskamux_pad_get_type (void);
431 G_DEFINE_TYPE (GstMatroskamuxPad, gst_matroskamux_pad, GST_TYPE_PAD);
433 #define GST_TYPE_MATROSKAMUX_PAD (gst_matroskamux_pad_get_type())
434 #define GST_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_MATROSKAMUX_PAD,GstMatroskamuxPad))
435 #define GST_MATROSKAMUX_PAD_CAST(pad) ((GstMatroskamuxPad *) pad)
436 #define GST_IS_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_MATROSKAMUX_PAD))
439 gst_matroskamux_pad_get_property (GObject * object, guint prop_id,
440 GValue * value, GParamSpec * pspec)
442 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
445 case PROP_PAD_FRAME_DURATION:
446 g_value_set_boolean (value, pad->frame_duration);
449 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
455 gst_matroskamux_pad_set_property (GObject * object, guint prop_id,
456 const GValue * value, GParamSpec * pspec)
458 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
461 case PROP_PAD_FRAME_DURATION:
462 pad->frame_duration = g_value_get_boolean (value);
463 pad->frame_duration_user = TRUE;
466 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
472 gst_matroskamux_pad_class_init (GstMatroskamuxPadClass * klass)
474 GObjectClass *gobject_class = (GObjectClass *) klass;
476 gobject_class->set_property = gst_matroskamux_pad_set_property;
477 gobject_class->get_property = gst_matroskamux_pad_get_property;
479 g_object_class_install_property (gobject_class, PROP_PAD_FRAME_DURATION,
480 g_param_spec_boolean ("frame-duration", "Frame duration",
481 "Default frame duration", DEFAULT_PAD_FRAME_DURATION,
482 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
486 gst_matroskamux_pad_init (GstMatroskamuxPad * pad)
488 pad->frame_duration = DEFAULT_PAD_FRAME_DURATION;
489 pad->frame_duration_user = FALSE;
493 * End of pad option handler code
497 gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class)
499 GstPadTemplate *templ;
502 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
503 mux->srcpad = gst_pad_new_from_template (templ, "src");
505 gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
506 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
507 gst_pad_use_fixed_caps (mux->srcpad);
509 mux->collect = gst_collect_pads_new ();
510 gst_collect_pads_set_clip_function (mux->collect,
511 GST_DEBUG_FUNCPTR (gst_collect_pads_clip_running_time), mux);
512 gst_collect_pads_set_buffer_function (mux->collect,
513 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_buffer), mux);
514 gst_collect_pads_set_event_function (mux->collect,
515 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event), mux);
517 mux->ebml_write = gst_ebml_write_new (mux->srcpad);
518 mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
520 /* property defaults */
521 mux->doctype_version = DEFAULT_DOCTYPE_VERSION;
522 mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
523 mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
524 mux->ebml_write->streamable = DEFAULT_STREAMABLE;
525 mux->time_scale = DEFAULT_TIMECODESCALE;
526 mux->min_cluster_duration = DEFAULT_MIN_CLUSTER_DURATION;
527 mux->max_cluster_duration = DEFAULT_MAX_CLUSTER_DURATION;
528 mux->cluster_timestamp_offset = DEFAULT_CLUSTER_TIMESTAMP_OFFSET;
530 /* initialize internal variables */
532 mux->num_streams = 0;
533 mux->num_a_streams = 0;
534 mux->num_t_streams = 0;
535 mux->num_v_streams = 0;
536 mux->internal_toc = NULL;
538 /* initialize remaining variables */
539 gst_matroska_mux_reset (GST_ELEMENT (mux));
544 * gst_matroska_mux_finalize:
545 * @object: #GstMatroskaMux that should be finalized.
547 * Finalize matroska muxer.
550 gst_matroska_mux_finalize (GObject * object)
552 GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
554 gst_event_replace (&mux->force_key_unit_event, NULL);
556 gst_object_unref (mux->collect);
557 gst_object_unref (mux->ebml_write);
558 g_free (mux->writing_app);
559 g_clear_pointer (&mux->creation_time, g_date_time_unref);
561 if (mux->internal_toc) {
562 gst_toc_unref (mux->internal_toc);
563 mux->internal_toc = NULL;
566 G_OBJECT_CLASS (parent_class)->finalize (object);
571 * gst_matroska_mux_create_uid:
572 * @mux: #GstMatroskaMux to generate UID for.
574 * Generate new track UID.
576 * Returns: New track UID.
579 gst_matroska_mux_create_uid (GstMatroskaMux * mux)
581 return (((guint64) g_random_int ()) << 32) | g_random_int ();
586 * gst_matroska_pad_reset:
587 * @collect_pad: the #GstMatroskaPad
589 * Reset and/or release resources of a matroska collect pad.
592 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
595 GstMatroskaTrackType type = 0;
597 /* free track information */
598 if (collect_pad->track != NULL) {
599 /* retrieve for optional later use */
600 name = collect_pad->track->name;
601 type = collect_pad->track->type;
602 /* extra for video */
603 if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
604 GstMatroskaTrackVideoContext *ctx =
605 (GstMatroskaTrackVideoContext *) collect_pad->track;
607 if (ctx->dirac_unit) {
608 gst_buffer_unref (ctx->dirac_unit);
609 ctx->dirac_unit = NULL;
612 g_free (collect_pad->track->codec_id);
613 g_free (collect_pad->track->codec_name);
615 g_free (collect_pad->track->name);
616 g_free (collect_pad->track->language);
617 g_free (collect_pad->track->codec_priv);
618 g_free (collect_pad->track);
619 collect_pad->track = NULL;
620 if (collect_pad->tags) {
621 gst_tag_list_unref (collect_pad->tags);
622 collect_pad->tags = NULL;
626 if (!full && type != 0) {
627 GstMatroskaTrackContext *context;
629 /* create a fresh context */
631 case GST_MATROSKA_TRACK_TYPE_VIDEO:
632 context = (GstMatroskaTrackContext *)
633 g_new0 (GstMatroskaTrackVideoContext, 1);
635 case GST_MATROSKA_TRACK_TYPE_AUDIO:
636 context = (GstMatroskaTrackContext *)
637 g_new0 (GstMatroskaTrackAudioContext, 1);
639 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
640 context = (GstMatroskaTrackContext *)
641 g_new0 (GstMatroskaTrackSubtitleContext, 1);
644 g_assert_not_reached ();
648 context->type = type;
649 context->name = name;
650 context->uid = gst_matroska_mux_create_uid (collect_pad->mux);
651 /* TODO: check default values for the context */
652 context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
653 collect_pad->track = context;
654 collect_pad->start_ts = GST_CLOCK_TIME_NONE;
655 collect_pad->end_ts = GST_CLOCK_TIME_NONE;
656 collect_pad->tags = gst_tag_list_new_empty ();
657 gst_tag_list_set_scope (collect_pad->tags, GST_TAG_SCOPE_STREAM);
662 * gst_matroska_pad_free:
663 * @collect_pad: the #GstMatroskaPad
665 * Release resources of a matroska collect pad.
668 gst_matroska_pad_free (GstPad * collect_pad)
670 gst_matroska_pad_reset ((GstMatroskaPad *) collect_pad, TRUE);
675 * gst_matroska_mux_reset:
676 * @element: #GstMatroskaMux that should be reset.
678 * Reset matroska muxer back to initial state.
681 gst_matroska_mux_reset (GstElement * element)
683 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
686 /* reset EBML write */
687 gst_ebml_write_reset (mux->ebml_write);
690 mux->state = GST_MATROSKA_MUX_STATE_START;
692 /* clean up existing streams */
694 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
695 GstMatroskaPad *collect_pad;
697 collect_pad = (GstMatroskaPad *) walk->data;
699 /* reset collect pad to pristine state */
700 gst_matroska_pad_reset (collect_pad, FALSE);
704 mux->num_indexes = 0;
713 mux->cluster_time = 0;
714 mux->cluster_pos = 0;
715 mux->prev_cluster_size = 0;
718 gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
723 gst_toc_setter_reset (GST_TOC_SETTER (mux));
724 if (mux->internal_toc) {
725 gst_toc_unref (mux->internal_toc);
726 mux->internal_toc = NULL;
729 mux->chapters_pos = 0;
733 * gst_matroska_mux_handle_src_event:
734 * @pad: Pad which received the event.
735 * @event: Received event.
737 * handle events - copied from oggmux without understanding
739 * Returns: %TRUE on success.
742 gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
747 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
751 /* disable seeking for now */
757 return gst_pad_event_default (pad, parent, event);
762 gst_matroska_mux_free_codec_priv (GstMatroskaTrackContext * context)
764 if (context->codec_priv != NULL) {
765 g_free (context->codec_priv);
766 context->codec_priv = NULL;
767 context->codec_priv_size = 0;
772 gst_matroska_mux_build_vobsub_private (GstMatroskaTrackContext * context,
782 /* produce comma-separated list in hex format */
783 for (i = 0; i < 16; ++i) {
785 /* replicate vobsub's slightly off RGB conversion calculation */
786 y = (((col >> 16) & 0xff) - 16) * 255 / 219;
787 u = ((col >> 8) & 0xff) - 128;
788 v = (col & 0xff) - 128;
789 r = CLAMP (1.0 * y + 1.4022 * u, 0, 255);
790 g = CLAMP (1.0 * y - 0.3456 * u - 0.7145 * v, 0, 255);
791 b = CLAMP (1.0 * y + 1.7710 * v, 0, 255);
792 clutv[i] = g_strdup_printf ("%02x%02x%02x", r, g, b);
795 sclut = g_strjoinv (",", clutv);
797 /* build codec private; only palette for now */
798 gst_matroska_mux_free_codec_priv (context);
799 context->codec_priv = (guint8 *) g_strdup_printf ("palette: %s", sclut);
800 /* include terminating 0 */
801 context->codec_priv_size = strlen ((gchar *) context->codec_priv) + 1;
803 for (i = 0; i < 16; ++i) {
810 * gst_matroska_mux_handle_sink_event:
811 * @pad: Pad which received the event.
812 * @event: Received event.
814 * handle events - informational ones like tags
816 * Returns: %TRUE on success.
819 gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
820 GstCollectData * data, GstEvent * event, gpointer user_data)
822 GstMatroskaPad *collect_pad;
823 GstMatroskaTrackContext *context;
829 mux = GST_MATROSKA_MUX (user_data);
830 collect_pad = (GstMatroskaPad *) data;
832 context = collect_pad->track;
835 switch (GST_EVENT_TYPE (event)) {
836 case GST_EVENT_CAPS:{
839 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
840 gst_event_parse_caps (event, &caps);
842 ret = collect_pad->capsfunc (pad, caps);
843 gst_event_unref (event);
850 GST_DEBUG_OBJECT (mux, "received tag event");
851 gst_event_parse_tag (event, &list);
853 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
854 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
855 const gchar *lang_code;
857 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
859 GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
860 g_free (context->language);
861 context->language = g_strdup (lang_code);
863 GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
868 if (gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL) {
869 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
870 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
874 /* Stream specific tags */
875 gst_tag_list_insert (collect_pad->tags, list, GST_TAG_MERGE_REPLACE);
877 /* If the tags contain a title, update the context name to write it there */
878 if (gst_tag_list_get_string (list, GST_TAG_TITLE, &title)) {
879 GST_INFO_OBJECT (pad, "Setting track name to '%s'", title);
880 g_free (context->name);
881 context->name = g_strdup (title);
886 gst_event_unref (event);
887 /* handled this, don't want collectpads to forward it downstream */
893 GstToc *toc, *old_toc;
895 if (mux->chapters_pos > 0)
898 GST_DEBUG_OBJECT (mux, "received toc event");
899 gst_event_parse_toc (event, &toc, NULL);
902 old_toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
903 if (old_toc != NULL) {
905 GST_INFO_OBJECT (pad, "Replacing TOC with a new one");
906 gst_toc_unref (old_toc);
909 gst_toc_setter_set_toc (GST_TOC_SETTER (mux), toc);
913 gst_event_unref (event);
914 /* handled this, don't want collectpads to forward it downstream */
918 case GST_EVENT_CUSTOM_DOWNSTREAM:
919 case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY:{
920 const GstStructure *structure;
922 structure = gst_event_get_structure (event);
923 if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
924 gst_event_replace (&mux->force_key_unit_event, NULL);
925 mux->force_key_unit_event = event;
927 } else if (gst_structure_has_name (structure, "application/x-gst-dvd") &&
928 !strcmp ("dvd-spu-clut-change",
929 gst_structure_get_string (structure, "event"))) {
934 GST_DEBUG_OBJECT (pad, "New DVD colour table received");
935 if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
936 GST_DEBUG_OBJECT (pad, "... discarding");
939 /* first transform event data into table form */
940 for (i = 0; i < 16; i++) {
941 g_snprintf (name, sizeof (name), "clut%02d", i);
942 if (!gst_structure_get_int (structure, name, &value)) {
943 GST_ERROR_OBJECT (mux, "dvd-spu-clut-change event did not "
944 "contain %s field", name);
950 /* transform into private data for stream; text form */
951 gst_matroska_mux_build_vobsub_private (context, clut);
961 return gst_collect_pads_event_default (pads, data, event, FALSE);
967 gst_matroska_mux_set_codec_id (GstMatroskaTrackContext * context,
970 g_assert (context && id);
971 g_free (context->codec_id);
972 context->codec_id = g_strdup (id);
976 check_field (GQuark field_id, const GValue * value, gpointer user_data)
978 GstStructure *structure = (GstStructure *) user_data;
979 const gchar *name = gst_structure_get_name (structure);
981 if ((g_strcmp0 (name, "video/x-h264") == 0 &&
982 !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
983 "avc3")) || (g_strcmp0 (name, "video/x-h265") == 0
984 && !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
987 /* While in theory, matroska only supports avc1 / hvc1, and doesn't support codec_data
988 * changes, in practice most decoders will use in-band SPS / PPS (avc3 / hev1), if the
989 * input stream is avc3 / hev1 we let the new codec_data slide to support "smart" encoding.
991 * We don't warn here as we already warned elsewhere.
993 if (field_id == g_quark_from_static_string ("codec_data")) {
995 } else if (field_id == g_quark_from_static_string ("tier")) {
997 } else if (field_id == g_quark_from_static_string ("profile")) {
999 } else if (field_id == g_quark_from_static_string ("level")) {
1002 } else if (gst_structure_has_name (structure, "video/x-vp8")
1003 || gst_structure_has_name (structure, "video/x-vp9")) {
1004 /* We do not use profile and streamheader for VPX so let it change
1006 if (field_id == g_quark_from_static_string ("streamheader"))
1008 else if (field_id == g_quark_from_static_string ("profile"))
1012 /* This fields aren't used and are not retained into the bitstream so we can
1014 if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) {
1015 if (field_id == g_quark_from_static_string ("chroma-site"))
1017 else if (field_id == g_quark_from_static_string ("chroma-format"))
1019 else if (field_id == g_quark_from_static_string ("bit-depth-luma"))
1022 /* Remove multiview-mode=mono and multiview-flags=0 fields as those are
1023 * equivalent with not having the fields but are not considered equivalent
1024 * by the generic caps functions.
1026 if (field_id == g_quark_from_static_string ("multiview-mode")) {
1027 const gchar *s = g_value_get_string (value);
1029 if (g_strcmp0 (s, "mono") == 0)
1033 if (field_id == g_quark_from_static_string ("multiview-flags")) {
1034 guint multiview_flags = gst_value_get_flagset_flags (value);
1036 if (multiview_flags == 0)
1045 check_new_caps (GstMatroskaTrackVideoContext * videocontext, GstCaps * old_caps,
1048 GstStructure *old_s, *new_s;
1051 old_caps = gst_caps_copy (old_caps);
1052 new_caps = gst_caps_copy (new_caps);
1054 new_s = gst_caps_get_structure (new_caps, 0);
1055 old_s = gst_caps_get_structure (old_caps, 0);
1057 gst_structure_filter_and_map_in_place (new_s,
1058 (GstStructureFilterMapFunc) check_field, new_s);
1059 gst_structure_filter_and_map_in_place (old_s,
1060 (GstStructureFilterMapFunc) check_field, old_s);
1062 ret = gst_caps_is_subset (new_caps, old_caps);
1064 gst_caps_unref (new_caps);
1065 gst_caps_unref (old_caps);
1071 * gst_matroska_mux_video_pad_setcaps:
1072 * @pad: Pad which got the caps.
1075 * Setcaps function for video sink pad.
1077 * Returns: %TRUE on success.
1080 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
1082 GstMatroskaTrackContext *context = NULL;
1083 GstMatroskaTrackVideoContext *videocontext;
1084 GstMatroskaMux *mux;
1085 GstMatroskaPad *collect_pad;
1086 GstStructure *structure;
1087 const gchar *mimetype;
1088 const gchar *interlace_mode, *s;
1089 const GValue *value = NULL;
1090 GstBuffer *codec_buf = NULL;
1091 gint width, height, pixel_width, pixel_height;
1093 guint multiview_flags;
1096 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1099 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1100 g_assert (collect_pad);
1101 context = collect_pad->track;
1103 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
1104 videocontext = (GstMatroskaTrackVideoContext *) context;
1106 if ((old_caps = gst_pad_get_current_caps (pad))) {
1107 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1108 && !check_new_caps (videocontext, old_caps, caps)) {
1109 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1110 ("Caps changes are not supported by Matroska\nCurrent: `%"
1111 GST_PTR_FORMAT "`\nNew: `%" GST_PTR_FORMAT "`", old_caps, caps));
1112 gst_caps_unref (old_caps);
1115 gst_caps_unref (old_caps);
1116 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
1117 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1118 ("Caps on pad %" GST_PTR_FORMAT
1119 " arrived late. Headers were already written", pad));
1123 /* gst -> matroska ID'ing */
1124 structure = gst_caps_get_structure (caps, 0);
1126 mimetype = gst_structure_get_name (structure);
1128 interlace_mode = gst_structure_get_string (structure, "interlace-mode");
1129 if (interlace_mode != NULL) {
1130 if (strcmp (interlace_mode, "progressive") == 0)
1131 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE;
1133 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_INTERLACED;
1135 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_UNKNOWN;
1138 if (!strcmp (mimetype, "video/x-theora")) {
1139 /* we'll extract the details later from the theora identification header */
1143 /* get general properties */
1144 /* spec says it is mandatory */
1145 if (!gst_structure_get_int (structure, "width", &width) ||
1146 !gst_structure_get_int (structure, "height", &height))
1149 videocontext->pixel_width = width;
1150 videocontext->pixel_height = height;
1152 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
1153 && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
1155 context->default_duration =
1156 gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
1157 GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
1158 GST_TIME_ARGS (context->default_duration));
1160 context->default_duration = 0;
1162 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
1163 &pixel_width, &pixel_height)) {
1164 if (pixel_width > pixel_height) {
1165 videocontext->display_width = width * pixel_width / pixel_height;
1166 videocontext->display_height = height;
1167 } else if (pixel_width < pixel_height) {
1168 videocontext->display_width = width;
1169 videocontext->display_height = height * pixel_height / pixel_width;
1171 videocontext->display_width = 0;
1172 videocontext->display_height = 0;
1175 videocontext->display_width = 0;
1176 videocontext->display_height = 0;
1179 if ((s = gst_structure_get_string (structure, "colorimetry"))) {
1180 if (!gst_video_colorimetry_from_string (&videocontext->colorimetry, s)) {
1181 GST_WARNING_OBJECT (pad, "Could not parse colorimetry %s", s);
1185 if ((s = gst_structure_get_string (structure, "mastering-display-info"))) {
1186 if (!gst_video_mastering_display_info_from_string
1187 (&videocontext->mastering_display_info, s)) {
1188 GST_WARNING_OBJECT (pad, "Could not parse mastering-display-metadata %s",
1191 videocontext->mastering_display_info_present = TRUE;
1195 if ((s = gst_structure_get_string (structure, "content-light-level"))) {
1196 if (!gst_video_content_light_level_from_string
1197 (&videocontext->content_light_level, s))
1198 GST_WARNING_OBJECT (pad, "Could not parse content-light-level %s", s);
1201 /* Collect stereoscopic info, if any */
1202 if ((s = gst_structure_get_string (structure, "multiview-mode")))
1203 videocontext->multiview_mode =
1204 gst_video_multiview_mode_from_caps_string (s);
1205 gst_structure_get_flagset (structure, "multiview-flags", &multiview_flags,
1207 videocontext->multiview_flags = multiview_flags;
1212 videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
1213 videocontext->fourcc = 0;
1215 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1216 * data and other settings
1220 /* extract codec_data, may turn out needed */
1221 value = gst_structure_get_value (structure, "codec_data");
1223 codec_buf = (GstBuffer *) gst_value_get_buffer (value);
1226 if (!strcmp (mimetype, "video/x-raw")) {
1228 gst_matroska_mux_set_codec_id (context,
1229 GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
1230 fstr = gst_structure_get_string (structure, "format");
1232 if (strlen (fstr) == 4)
1233 videocontext->fourcc = GST_STR_FOURCC (fstr);
1234 else if (!strcmp (fstr, "GRAY8"))
1235 videocontext->fourcc = GST_MAKE_FOURCC ('Y', '8', '0', '0');
1236 else if (!strcmp (fstr, "BGR"))
1237 videocontext->fourcc = GST_MAKE_FOURCC ('B', 'G', 'R', 24);
1238 else if (!strcmp (fstr, "RGB"))
1239 videocontext->fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', 24);
1241 } else if (!strcmp (mimetype, "video/x-huffyuv") /* MS/VfW compatibility cases */
1242 ||!strcmp (mimetype, "video/x-divx")
1243 || !strcmp (mimetype, "video/x-dv")
1244 || !strcmp (mimetype, "video/x-h263")
1245 || !strcmp (mimetype, "video/x-msmpeg")
1246 || !strcmp (mimetype, "video/x-wmv")
1247 || !strcmp (mimetype, "image/jpeg")) {
1248 gst_riff_strf_vids *bih;
1249 gint size = sizeof (gst_riff_strf_vids);
1252 if (!strcmp (mimetype, "video/x-huffyuv"))
1253 fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
1254 else if (!strcmp (mimetype, "video/x-dv"))
1255 fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
1256 else if (!strcmp (mimetype, "video/x-h263"))
1257 fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
1258 else if (!strcmp (mimetype, "video/x-divx")) {
1261 gst_structure_get_int (structure, "divxversion", &divxversion);
1262 switch (divxversion) {
1264 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
1267 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
1270 fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
1273 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1276 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
1277 switch (msmpegversion) {
1279 fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
1282 fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
1288 } else if (!strcmp (mimetype, "video/x-wmv")) {
1292 fstr = gst_structure_get_string (structure, "format");
1293 if (fstr && strlen (fstr) == 4) {
1294 fourcc = GST_STR_FOURCC (fstr);
1295 } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
1296 if (wmvversion == 2) {
1297 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
1298 } else if (wmvversion == 1) {
1299 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
1300 } else if (wmvversion == 3) {
1301 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
1304 } else if (!strcmp (mimetype, "image/jpeg")) {
1305 fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
1311 bih = g_new0 (gst_riff_strf_vids, 1);
1312 GST_WRITE_UINT32_LE (&bih->size, size);
1313 GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
1314 GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
1315 GST_WRITE_UINT32_LE (&bih->compression, fourcc);
1316 GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
1317 GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
1318 GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
1319 videocontext->pixel_height * 3);
1321 /* process codec private/initialization data, if any */
1323 size += gst_buffer_get_size (codec_buf);
1324 bih = g_realloc (bih, size);
1325 GST_WRITE_UINT32_LE (&bih->size, size);
1326 gst_buffer_extract (codec_buf, 0,
1327 (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
1330 gst_matroska_mux_set_codec_id (context,
1331 GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
1332 gst_matroska_mux_free_codec_priv (context);
1333 context->codec_priv = (gpointer) bih;
1334 context->codec_priv_size = size;
1335 context->dts_only = TRUE;
1336 } else if (!strcmp (mimetype, "video/x-h264")) {
1337 gst_matroska_mux_set_codec_id (context,
1338 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
1339 gst_matroska_mux_free_codec_priv (context);
1341 if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1343 GST_WARNING_OBJECT (mux,
1344 "avc3 is not officially supported, only use this format for smart encoding");
1347 /* Create avcC header */
1348 if (codec_buf != NULL) {
1349 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1350 context->codec_priv = g_malloc0 (context->codec_priv_size);
1351 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1353 } else if (!strcmp (mimetype, "video/x-h265")) {
1354 gst_matroska_mux_set_codec_id (context,
1355 GST_MATROSKA_CODEC_ID_VIDEO_MPEGH_HEVC);
1356 gst_matroska_mux_free_codec_priv (context);
1358 if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1360 GST_WARNING_OBJECT (mux,
1361 "hev1 is not officially supported, only use this format for smart encoding");
1364 /* Create hvcC header */
1365 if (codec_buf != NULL) {
1366 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1367 context->codec_priv = g_malloc0 (context->codec_priv_size);
1368 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1370 } else if (!strcmp (mimetype, "video/x-theora")) {
1371 const GValue *streamheader;
1373 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
1375 gst_matroska_mux_free_codec_priv (context);
1377 streamheader = gst_structure_get_value (structure, "streamheader");
1378 if (!theora_streamheader_to_codecdata (streamheader, context)) {
1379 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1380 ("theora stream headers missing or malformed"));
1383 } else if (!strcmp (mimetype, "video/x-dirac")) {
1384 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
1385 } else if (!strcmp (mimetype, "video/x-vp8")) {
1386 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP8);
1387 } else if (!strcmp (mimetype, "video/x-vp9")) {
1388 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP9);
1389 } else if (!strcmp (mimetype, "video/x-av1")) {
1390 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_AV1);
1391 gst_matroska_mux_free_codec_priv (context);
1392 /* Create av1C header */
1393 if (codec_buf != NULL)
1394 gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1395 &context->codec_priv, &context->codec_priv_size);
1396 } else if (!strcmp (mimetype, "video/x-ffv")) {
1397 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_FFV1);
1398 gst_matroska_mux_free_codec_priv (context);
1399 if (codec_buf != NULL)
1400 gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1401 &context->codec_priv, &context->codec_priv_size);
1402 } else if (!strcmp (mimetype, "video/mpeg")) {
1405 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1406 switch (mpegversion) {
1408 gst_matroska_mux_set_codec_id (context,
1409 GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
1412 gst_matroska_mux_set_codec_id (context,
1413 GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
1416 gst_matroska_mux_set_codec_id (context,
1417 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
1423 /* global headers may be in codec data */
1424 if (codec_buf != NULL) {
1425 gst_matroska_mux_free_codec_priv (context);
1426 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1427 context->codec_priv = g_malloc0 (context->codec_priv_size);
1428 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1430 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1432 /* can only make it here if preceding case verified it was version 3 */
1433 gst_matroska_mux_set_codec_id (context,
1434 GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
1435 } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
1437 const GValue *mdpr_data;
1439 gst_structure_get_int (structure, "rmversion", &rmversion);
1440 switch (rmversion) {
1442 gst_matroska_mux_set_codec_id (context,
1443 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
1446 gst_matroska_mux_set_codec_id (context,
1447 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
1450 gst_matroska_mux_set_codec_id (context,
1451 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
1454 gst_matroska_mux_set_codec_id (context,
1455 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
1461 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1462 if (mdpr_data != NULL) {
1463 guint8 *priv_data = NULL;
1464 guint priv_data_size = 0;
1466 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1468 priv_data_size = gst_buffer_get_size (codec_data_buf);
1469 priv_data = g_malloc0 (priv_data_size);
1471 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1473 gst_matroska_mux_free_codec_priv (context);
1474 context->codec_priv = priv_data;
1475 context->codec_priv_size = priv_data_size;
1477 } else if (strcmp (mimetype, "video/x-prores") == 0) {
1478 const gchar *variant;
1480 gst_matroska_mux_free_codec_priv (context);
1482 variant = gst_structure_get_string (structure, "format");
1483 if (!variant || !g_strcmp0 (variant, "standard"))
1484 context->codec_priv = g_strdup ("apcn");
1485 else if (!g_strcmp0 (variant, "hq"))
1486 context->codec_priv = g_strdup ("apch");
1487 else if (!g_strcmp0 (variant, "lt"))
1488 context->codec_priv = g_strdup ("apcs");
1489 else if (!g_strcmp0 (variant, "proxy"))
1490 context->codec_priv = g_strdup ("apco");
1491 else if (!g_strcmp0 (variant, "4444"))
1492 context->codec_priv = g_strdup ("ap4h");
1494 GST_WARNING_OBJECT (mux, "Unhandled prores format: %s", variant);
1499 context->codec_priv_size = sizeof (guint32);
1500 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_PRORES);
1508 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1509 GST_PAD_NAME (pad), caps);
1514 /* N > 0 to expect a particular number of headers, negative if the
1515 number of headers is variable */
1517 xiphN_streamheader_to_codecdata (const GValue * streamheader,
1518 GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
1520 GstBuffer **buf = NULL;
1523 guint bufi, i, offset, priv_data_size;
1525 if (streamheader == NULL)
1526 goto no_stream_headers;
1528 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1531 bufarr = g_value_peek_pointer (streamheader);
1532 if (bufarr->len <= 0 || bufarr->len > 255) /* at least one header, and count stored in a byte */
1534 if (N > 0 && bufarr->len != N)
1537 context->xiph_headers_to_skip = bufarr->len;
1539 buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1540 for (i = 0; i < bufarr->len; i++) {
1541 GValue *bufval = &g_array_index (bufarr, GValue, i);
1543 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1545 goto wrong_content_type;
1548 buf[i] = g_value_peek_pointer (bufval);
1552 if (bufarr->len > 0) {
1553 for (i = 0; i < bufarr->len - 1; i++) {
1554 priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
1558 for (i = 0; i < bufarr->len; ++i) {
1559 priv_data_size += gst_buffer_get_size (buf[i]);
1562 priv_data = g_malloc0 (priv_data_size);
1564 priv_data[0] = bufarr->len - 1;
1567 if (bufarr->len > 0) {
1568 for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1569 for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
1570 priv_data[offset++] = 0xff;
1572 priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
1576 for (i = 0; i < bufarr->len; ++i) {
1577 gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
1578 offset += gst_buffer_get_size (buf[i]);
1581 gst_matroska_mux_free_codec_priv (context);
1582 context->codec_priv = priv_data;
1583 context->codec_priv_size = priv_data_size;
1586 *p_buf0 = gst_buffer_ref (buf[0]);
1595 GST_WARNING ("required streamheaders missing in sink caps!");
1600 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1601 G_VALUE_TYPE_NAME (streamheader));
1606 GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1611 GST_WARNING ("streamheaders array does not contain GstBuffers");
1617 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1618 GstMatroskaTrackContext * context)
1620 GstBuffer *buf0 = NULL;
1622 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1625 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
1626 GST_WARNING ("First vorbis header too small, ignoring");
1628 if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
1629 GstMatroskaTrackAudioContext *audiocontext;
1633 gst_buffer_map (buf0, &map, GST_MAP_READ);
1634 hdr = map.data + 1 + 6 + 4;
1635 audiocontext = (GstMatroskaTrackAudioContext *) context;
1636 audiocontext->channels = GST_READ_UINT8 (hdr);
1637 audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1638 gst_buffer_unmap (buf0, &map);
1643 gst_buffer_unref (buf0);
1649 theora_streamheader_to_codecdata (const GValue * streamheader,
1650 GstMatroskaTrackContext * context)
1652 GstBuffer *buf0 = NULL;
1654 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1657 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
1658 GST_WARNING ("First theora header too small, ignoring");
1659 } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
1660 GST_WARNING ("First header not a theora identification header, ignoring");
1662 GstMatroskaTrackVideoContext *videocontext;
1663 guint fps_num, fps_denom, par_num, par_denom;
1667 gst_buffer_map (buf0, &map, GST_MAP_READ);
1668 hdr = map.data + 1 + 6 + 3 + 2 + 2;
1670 videocontext = (GstMatroskaTrackVideoContext *) context;
1671 videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1672 videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1673 hdr += 3 + 3 + 1 + 1;
1674 fps_num = GST_READ_UINT32_BE (hdr);
1675 fps_denom = GST_READ_UINT32_BE (hdr + 4);
1676 context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1677 fps_denom, fps_num);
1679 par_num = GST_READ_UINT32_BE (hdr) >> 8;
1680 par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1681 if (par_num > 0 && par_denom > 0) {
1682 if (par_num > par_denom) {
1683 videocontext->display_width =
1684 videocontext->pixel_width * par_num / par_denom;
1685 videocontext->display_height = videocontext->pixel_height;
1686 } else if (par_num < par_denom) {
1687 videocontext->display_width = videocontext->pixel_width;
1688 videocontext->display_height =
1689 videocontext->pixel_height * par_denom / par_num;
1691 videocontext->display_width = 0;
1692 videocontext->display_height = 0;
1695 videocontext->display_width = 0;
1696 videocontext->display_height = 0;
1699 gst_buffer_unmap (buf0, &map);
1703 gst_buffer_unref (buf0);
1709 kate_streamheader_to_codecdata (const GValue * streamheader,
1710 GstMatroskaTrackContext * context)
1712 GstBuffer *buf0 = NULL;
1714 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1717 if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) { /* Kate ID header is 64 bytes */
1718 GST_WARNING ("First kate header too small, ignoring");
1719 } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
1720 GST_WARNING ("First header not a kate identification header, ignoring");
1724 gst_buffer_unref (buf0);
1730 flac_streamheader_to_codecdata (const GValue * streamheader,
1731 GstMatroskaTrackContext * context)
1738 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1739 GST_WARNING ("No or invalid streamheader field in the caps");
1743 bufarr = g_value_peek_pointer (streamheader);
1744 if (bufarr->len < 2) {
1745 GST_WARNING ("Too few headers in streamheader field");
1749 context->xiph_headers_to_skip = bufarr->len + 1;
1751 bufval = &g_array_index (bufarr, GValue, 0);
1752 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1753 GST_WARNING ("streamheaders array does not contain GstBuffers");
1757 buffer = g_value_peek_pointer (bufval);
1759 /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1760 if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
1761 || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
1762 || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
1763 GST_WARNING ("Invalid streamheader for FLAC");
1767 gst_matroska_mux_free_codec_priv (context);
1768 context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
1769 context->codec_priv = g_malloc (context->codec_priv_size);
1770 gst_buffer_extract (buffer, 9, context->codec_priv, -1);
1772 for (i = 1; i < bufarr->len; i++) {
1774 bufval = &g_array_index (bufarr, GValue, i);
1776 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1777 gst_matroska_mux_free_codec_priv (context);
1778 GST_WARNING ("streamheaders array does not contain GstBuffers");
1782 buffer = g_value_peek_pointer (bufval);
1784 old_size = context->codec_priv_size;
1785 context->codec_priv_size += gst_buffer_get_size (buffer);
1787 context->codec_priv = g_realloc (context->codec_priv,
1788 context->codec_priv_size);
1789 gst_buffer_extract (buffer, 0,
1790 (guint8 *) context->codec_priv + old_size, -1);
1797 speex_streamheader_to_codecdata (const GValue * streamheader,
1798 GstMatroskaTrackContext * context)
1805 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1806 GST_WARNING ("No or invalid streamheader field in the caps");
1810 bufarr = g_value_peek_pointer (streamheader);
1811 if (bufarr->len != 2) {
1812 GST_WARNING ("Too few headers in streamheader field");
1816 context->xiph_headers_to_skip = bufarr->len + 1;
1818 bufval = &g_array_index (bufarr, GValue, 0);
1819 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1820 GST_WARNING ("streamheaders array does not contain GstBuffers");
1824 buffer = g_value_peek_pointer (bufval);
1826 if (gst_buffer_get_size (buffer) < 80
1827 || gst_buffer_memcmp (buffer, 0, "Speex ", 8) != 0) {
1828 GST_WARNING ("Invalid streamheader for Speex");
1832 gst_matroska_mux_free_codec_priv (context);
1833 context->codec_priv_size = gst_buffer_get_size (buffer);
1834 context->codec_priv = g_malloc (context->codec_priv_size);
1835 gst_buffer_extract (buffer, 0, context->codec_priv, -1);
1837 bufval = &g_array_index (bufarr, GValue, 1);
1839 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1840 gst_matroska_mux_free_codec_priv (context);
1841 GST_WARNING ("streamheaders array does not contain GstBuffers");
1845 buffer = g_value_peek_pointer (bufval);
1847 old_size = context->codec_priv_size;
1848 context->codec_priv_size += gst_buffer_get_size (buffer);
1849 context->codec_priv = g_realloc (context->codec_priv,
1850 context->codec_priv_size);
1851 gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
1857 opus_streamheader_to_codecdata (const GValue * streamheader,
1858 GstMatroskaTrackContext * context)
1864 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1867 bufarr = g_value_peek_pointer (streamheader);
1868 if (bufarr->len != 1 && bufarr->len != 2) /* one header, and count stored in a byte */
1871 /* Opus headers are not in-band */
1872 context->xiph_headers_to_skip = 0;
1874 bufval = &g_array_index (bufarr, GValue, 0);
1875 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1876 goto wrong_content_type;
1878 buf = g_value_peek_pointer (bufval);
1880 gst_matroska_mux_free_codec_priv (context);
1882 context->codec_priv_size = gst_buffer_get_size (buf);
1883 context->codec_priv = g_malloc0 (context->codec_priv_size);
1884 gst_buffer_extract (buf, 0, context->codec_priv, -1);
1886 context->codec_delay =
1887 GST_READ_UINT16_LE ((guint8 *) context->codec_priv + 10);
1888 context->codec_delay =
1889 gst_util_uint64_scale_round (context->codec_delay, GST_SECOND, 48000);
1890 context->seek_preroll = 80 * GST_MSECOND;
1897 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1898 G_VALUE_TYPE_NAME (streamheader));
1903 GST_WARNING ("got %u streamheaders, not 1 or 2 as expected", bufarr->len);
1908 GST_WARNING ("streamheaders array does not contain GstBuffers");
1914 opus_make_codecdata (GstMatroskaTrackContext * context, GstCaps * caps)
1918 guint8 channel_mapping_family;
1919 guint8 stream_count, coupled_count, channel_mapping[256];
1923 /* Opus headers are not in-band */
1924 context->xiph_headers_to_skip = 0;
1926 context->codec_delay = 0;
1927 context->seek_preroll = 80 * GST_MSECOND;
1929 if (!gst_codec_utils_opus_parse_caps (caps, &rate, &channels,
1930 &channel_mapping_family, &stream_count, &coupled_count,
1932 GST_WARNING ("Failed to parse caps for Opus");
1937 gst_codec_utils_opus_create_header (rate, channels,
1938 channel_mapping_family, stream_count, coupled_count, channel_mapping, 0,
1941 GST_WARNING ("Failed to create Opus header from caps");
1945 gst_buffer_map (buffer, &map, GST_MAP_READ);
1946 context->codec_priv_size = map.size;
1947 context->codec_priv = g_malloc (context->codec_priv_size);
1948 memcpy (context->codec_priv, map.data, map.size);
1949 gst_buffer_unmap (buffer, &map);
1950 gst_buffer_unref (buffer);
1956 * gst_matroska_mux_audio_pad_setcaps:
1957 * @pad: Pad which got the caps.
1960 * Setcaps function for audio sink pad.
1962 * Returns: %TRUE on success.
1965 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1967 GstMatroskaTrackContext *context = NULL;
1968 GstMatroskaTrackAudioContext *audiocontext;
1969 GstMatroskaMux *mux;
1970 GstMatroskaPad *collect_pad;
1971 const gchar *mimetype;
1972 gint samplerate = 0, channels = 0;
1973 GstStructure *structure;
1974 const GValue *codec_data = NULL;
1975 GstBuffer *buf = NULL;
1976 const gchar *stream_format = NULL;
1979 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1981 if ((old_caps = gst_pad_get_current_caps (pad))) {
1982 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1983 && !gst_caps_is_equal (caps, old_caps)) {
1984 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1985 ("Caps changes are not supported by Matroska"));
1986 gst_caps_unref (old_caps);
1989 gst_caps_unref (old_caps);
1990 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
1991 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1992 ("Caps on pad %" GST_PTR_FORMAT
1993 " arrived late. Headers were already written", pad));
1998 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1999 g_assert (collect_pad);
2000 context = collect_pad->track;
2002 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
2003 audiocontext = (GstMatroskaTrackAudioContext *) context;
2005 structure = gst_caps_get_structure (caps, 0);
2006 mimetype = gst_structure_get_name (structure);
2009 gst_structure_get_int (structure, "rate", &samplerate);
2010 gst_structure_get_int (structure, "channels", &channels);
2012 audiocontext->samplerate = samplerate;
2013 audiocontext->channels = channels;
2014 audiocontext->bitdepth = 0;
2015 context->default_duration = 0;
2017 codec_data = gst_structure_get_value (structure, "codec_data");
2019 buf = gst_value_get_buffer (codec_data);
2021 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
2022 * data and other settings
2026 if (!strcmp (mimetype, "audio/mpeg")) {
2027 gint mpegversion = 0;
2029 gst_structure_get_int (structure, "mpegversion", &mpegversion);
2030 switch (mpegversion) {
2036 gst_structure_get_int (structure, "layer", &layer);
2038 if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
2039 GST_WARNING_OBJECT (mux,
2040 "Unable to determine MPEG audio version, assuming 1");
2046 else if (layer == 2)
2048 else if (version == 2)
2053 context->default_duration =
2054 gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
2058 gst_matroska_mux_set_codec_id (context,
2059 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
2062 gst_matroska_mux_set_codec_id (context,
2063 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
2066 gst_matroska_mux_set_codec_id (context,
2067 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
2076 stream_format = gst_structure_get_string (structure, "stream-format");
2077 /* check this is raw aac */
2078 if (stream_format) {
2079 if (strcmp (stream_format, "raw") != 0) {
2080 GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
2084 GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
2089 gst_matroska_mux_set_codec_id (context,
2090 GST_MATROSKA_CODEC_ID_AUDIO_AAC);
2091 context->codec_priv_size = gst_buffer_get_size (buf);
2092 context->codec_priv = g_malloc (context->codec_priv_size);
2093 gst_buffer_extract (buf, 0, context->codec_priv,
2094 context->codec_priv_size);
2096 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
2103 } else if (!strcmp (mimetype, "audio/x-raw")) {
2106 gst_audio_info_init (&info);
2107 if (!gst_audio_info_from_caps (&info, caps)) {
2108 GST_DEBUG_OBJECT (mux,
2109 "broken caps, rejected by gst_audio_info_from_caps");
2113 switch (GST_AUDIO_INFO_FORMAT (&info)) {
2114 case GST_AUDIO_FORMAT_U8:
2115 case GST_AUDIO_FORMAT_S16BE:
2116 case GST_AUDIO_FORMAT_S16LE:
2117 case GST_AUDIO_FORMAT_S24BE:
2118 case GST_AUDIO_FORMAT_S24LE:
2119 case GST_AUDIO_FORMAT_S32BE:
2120 case GST_AUDIO_FORMAT_S32LE:
2121 if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
2122 GST_DEBUG_OBJECT (mux, "width must be same as depth!");
2125 if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
2126 gst_matroska_mux_set_codec_id (context,
2127 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
2129 gst_matroska_mux_set_codec_id (context,
2130 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
2132 case GST_AUDIO_FORMAT_F32LE:
2133 case GST_AUDIO_FORMAT_F64LE:
2134 gst_matroska_mux_set_codec_id (context,
2135 GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
2139 GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
2143 audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
2144 } else if (!strcmp (mimetype, "audio/x-vorbis")) {
2145 const GValue *streamheader;
2147 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
2149 gst_matroska_mux_free_codec_priv (context);
2151 streamheader = gst_structure_get_value (structure, "streamheader");
2152 if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
2153 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2154 ("vorbis stream headers missing or malformed"));
2157 } else if (!strcmp (mimetype, "audio/x-flac")) {
2158 const GValue *streamheader;
2160 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
2162 gst_matroska_mux_free_codec_priv (context);
2164 streamheader = gst_structure_get_value (structure, "streamheader");
2165 if (!flac_streamheader_to_codecdata (streamheader, context)) {
2166 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2167 ("flac stream headers missing or malformed"));
2170 } else if (!strcmp (mimetype, "audio/x-speex")) {
2171 const GValue *streamheader;
2173 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
2174 gst_matroska_mux_free_codec_priv (context);
2176 streamheader = gst_structure_get_value (structure, "streamheader");
2177 if (!speex_streamheader_to_codecdata (streamheader, context)) {
2178 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2179 ("speex stream headers missing or malformed"));
2182 } else if (!strcmp (mimetype, "audio/x-opus")) {
2183 const GValue *streamheader;
2185 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_OPUS);
2187 streamheader = gst_structure_get_value (structure, "streamheader");
2189 gst_matroska_mux_free_codec_priv (context);
2190 if (!opus_streamheader_to_codecdata (streamheader, context)) {
2191 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2192 ("opus stream headers missing or malformed"));
2196 /* no streamheader, but we need to have one, so we make one up
2198 gst_matroska_mux_free_codec_priv (context);
2199 if (!opus_make_codecdata (context, caps)) {
2200 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2201 ("opus stream headers missing or malformed"));
2205 } else if (!strcmp (mimetype, "audio/x-ac3")) {
2206 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_AC3);
2207 } else if (!strcmp (mimetype, "audio/x-eac3")) {
2208 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
2209 } else if (!strcmp (mimetype, "audio/x-dts")) {
2210 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_DTS);
2211 } else if (!strcmp (mimetype, "audio/x-tta")) {
2214 /* TTA frame duration */
2215 context->default_duration = 1.04489795918367346939 * GST_SECOND;
2217 gst_structure_get_int (structure, "width", &width);
2218 audiocontext->bitdepth = width;
2219 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_TTA);
2221 } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
2223 const GValue *mdpr_data;
2225 gst_structure_get_int (structure, "raversion", &raversion);
2226 switch (raversion) {
2228 gst_matroska_mux_set_codec_id (context,
2229 GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
2232 gst_matroska_mux_set_codec_id (context,
2233 GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
2236 gst_matroska_mux_set_codec_id (context,
2237 GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
2243 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
2244 if (mdpr_data != NULL) {
2245 guint8 *priv_data = NULL;
2246 guint priv_data_size = 0;
2248 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
2250 priv_data_size = gst_buffer_get_size (codec_data_buf);
2251 priv_data = g_malloc0 (priv_data_size);
2253 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
2255 gst_matroska_mux_free_codec_priv (context);
2257 context->codec_priv = priv_data;
2258 context->codec_priv_size = priv_data_size;
2261 } else if (!strcmp (mimetype, "audio/x-wma")
2262 || !strcmp (mimetype, "audio/x-alaw")
2263 || !strcmp (mimetype, "audio/x-mulaw")
2264 || !strcmp (mimetype, "audio/x-adpcm")
2265 || !strcmp (mimetype, "audio/G722")) {
2267 guint codec_priv_size;
2269 gint block_align = 0;
2272 if (samplerate == 0 || channels == 0) {
2273 GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
2277 if (!strcmp (mimetype, "audio/x-wma")) {
2281 if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
2282 || !gst_structure_get_int (structure, "block_align", &block_align)
2283 || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
2284 GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
2289 switch (wmaversion) {
2291 format = GST_RIFF_WAVE_FORMAT_WMAV1;
2294 format = GST_RIFF_WAVE_FORMAT_WMAV2;
2297 format = GST_RIFF_WAVE_FORMAT_WMAV3;
2300 GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
2304 if (gst_structure_get_int (structure, "depth", &depth))
2305 audiocontext->bitdepth = depth;
2306 } else if (!strcmp (mimetype, "audio/x-alaw")
2307 || !strcmp (mimetype, "audio/x-mulaw")) {
2308 audiocontext->bitdepth = 8;
2309 if (!strcmp (mimetype, "audio/x-alaw"))
2310 format = GST_RIFF_WAVE_FORMAT_ALAW;
2312 format = GST_RIFF_WAVE_FORMAT_MULAW;
2314 block_align = channels;
2315 bitrate = block_align * samplerate;
2316 } else if (!strcmp (mimetype, "audio/x-adpcm")) {
2319 layout = gst_structure_get_string (structure, "layout");
2321 GST_WARNING_OBJECT (mux, "Missing layout on adpcm caps");
2325 if (!gst_structure_get_int (structure, "block_align", &block_align)) {
2326 GST_WARNING_OBJECT (mux, "Missing block_align on adpcm caps");
2330 if (!strcmp (layout, "dvi")) {
2331 format = GST_RIFF_WAVE_FORMAT_DVI_ADPCM;
2332 } else if (!strcmp (layout, "g726")) {
2333 format = GST_RIFF_WAVE_FORMAT_ITU_G726_ADPCM;
2334 if (!gst_structure_get_int (structure, "bitrate", &bitrate)) {
2335 GST_WARNING_OBJECT (mux, "Missing bitrate on adpcm g726 caps");
2339 GST_WARNING_OBJECT (mux, "Unknown layout on adpcm caps");
2343 } else if (!strcmp (mimetype, "audio/G722")) {
2344 format = GST_RIFF_WAVE_FORMAT_ADPCM_G722;
2346 g_assert (format != 0);
2348 codec_priv_size = WAVEFORMATEX_SIZE;
2350 codec_priv_size += gst_buffer_get_size (buf);
2352 /* serialize waveformatex structure */
2353 codec_priv = g_malloc0 (codec_priv_size);
2354 GST_WRITE_UINT16_LE (codec_priv, format);
2355 GST_WRITE_UINT16_LE (codec_priv + 2, channels);
2356 GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
2357 GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
2358 GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
2359 GST_WRITE_UINT16_LE (codec_priv + 14, 0);
2361 GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
2363 GST_WRITE_UINT16_LE (codec_priv + 16, 0);
2365 /* process codec private/initialization data, if any */
2367 gst_buffer_extract (buf, 0,
2368 (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
2371 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
2372 gst_matroska_mux_free_codec_priv (context);
2373 context->codec_priv = (gpointer) codec_priv;
2374 context->codec_priv_size = codec_priv_size;
2382 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2383 GST_PAD_NAME (pad), caps);
2388 /* we probably don't have the data at start,
2389 * so have to reserve (a maximum) space to write this at the end.
2390 * bit spacy, but some formats can hold quite some */
2391 #define SUBTITLE_MAX_CODEC_PRIVATE 2048 /* must be > 128 */
2394 * gst_matroska_mux_subtitle_pad_setcaps:
2395 * @pad: Pad which got the caps.
2398 * Setcaps function for subtitle sink pad.
2400 * Returns: %TRUE on success.
2403 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
2405 /* There is now (at least) one such alement (kateenc), and I'm going
2406 to handle it here and claim it works when it can be piped back
2407 through GStreamer and VLC */
2409 GstMatroskaTrackContext *context = NULL;
2410 GstMatroskaTrackSubtitleContext *scontext;
2411 GstMatroskaMux *mux;
2412 GstMatroskaPad *collect_pad;
2413 GstCollectData *data;
2414 const gchar *mimetype;
2415 GstStructure *structure;
2416 const GValue *value = NULL;
2417 GstBuffer *buf = NULL;
2418 gboolean ret = TRUE;
2421 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2423 if ((old_caps = gst_pad_get_current_caps (pad))) {
2424 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
2425 && !gst_caps_is_equal (caps, old_caps)) {
2426 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2427 ("Caps changes are not supported by Matroska"));
2428 gst_caps_unref (old_caps);
2431 gst_caps_unref (old_caps);
2432 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
2433 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2434 ("Caps on pad %" GST_PTR_FORMAT
2435 " arrived late. Headers were already written", pad));
2440 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
2441 g_assert (collect_pad);
2442 data = (GstCollectData *) (collect_pad);
2444 context = collect_pad->track;
2446 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
2447 scontext = (GstMatroskaTrackSubtitleContext *) context;
2449 structure = gst_caps_get_structure (caps, 0);
2450 mimetype = gst_structure_get_name (structure);
2453 scontext->check_utf8 = 1;
2454 scontext->invalid_utf8 = 0;
2455 context->default_duration = 0;
2457 if (!strcmp (mimetype, "subtitle/x-kate")) {
2458 const GValue *streamheader;
2460 gst_matroska_mux_set_codec_id (context,
2461 GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
2463 gst_matroska_mux_free_codec_priv (context);
2465 streamheader = gst_structure_get_value (structure, "streamheader");
2466 if (!kate_streamheader_to_codecdata (streamheader, context)) {
2467 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2468 ("kate stream headers missing or malformed"));
2472 } else if (!strcmp (mimetype, "text/x-raw")) {
2473 gst_matroska_mux_set_codec_id (context,
2474 GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
2475 } else if (!strcmp (mimetype, "application/x-ssa")) {
2476 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
2477 } else if (!strcmp (mimetype, "application/x-ass")) {
2478 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
2479 } else if (!strcmp (mimetype, "application/x-usf")) {
2480 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
2481 } else if (!strcmp (mimetype, "subpicture/x-dvd")) {
2482 gst_matroska_mux_set_codec_id (context,
2483 GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
2489 /* maybe some private data, e.g. vobsub */
2490 value = gst_structure_get_value (structure, "codec_data");
2492 buf = gst_value_get_buffer (value);
2495 guint8 *priv_data = NULL;
2497 gst_buffer_map (buf, &map, GST_MAP_READ);
2499 if (map.size > SUBTITLE_MAX_CODEC_PRIVATE) {
2500 GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
2501 " exceeded maximum (%d); discarding", pad,
2502 SUBTITLE_MAX_CODEC_PRIVATE);
2503 gst_buffer_unmap (buf, &map);
2507 gst_matroska_mux_free_codec_priv (context);
2509 priv_data = g_malloc0 (map.size);
2510 memcpy (priv_data, map.data, map.size);
2511 context->codec_priv = priv_data;
2512 context->codec_priv_size = map.size;
2513 gst_buffer_unmap (buf, &map);
2516 GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %" G_GSIZE_FORMAT,
2517 GST_STR_NULL (context->codec_id), context->codec_priv_size);
2519 /* This pad is sparse. Now that we have caps on it, we can tell collectpads
2520 * not to actually wait for data when muxing */
2521 GST_COLLECT_PADS_STREAM_LOCK (mux->collect);
2522 GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED);
2523 gst_collect_pads_set_waiting (mux->collect, data, FALSE);
2524 GST_COLLECT_PADS_STREAM_UNLOCK (mux->collect);
2533 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2534 GST_PAD_NAME (pad), caps);
2541 * gst_matroska_mux_request_new_pad:
2542 * @element: #GstMatroskaMux.
2543 * @templ: #GstPadTemplate.
2544 * @pad_name: New pad name.
2546 * Request pad function for sink templates.
2548 * Returns: New #GstPad.
2551 gst_matroska_mux_request_new_pad (GstElement * element,
2552 GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
2554 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
2555 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
2556 GstMatroskaPad *collect_pad;
2557 GstMatroskamuxPad *newpad;
2559 const gchar *pad_name = NULL;
2560 GstMatroskaCapsFunc capsfunc = NULL;
2561 GstMatroskaTrackContext *context = NULL;
2563 const gchar *id = NULL;
2565 if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
2566 /* don't mix named and unnamed pads, if the pad already exists we fail when
2567 * trying to add it */
2568 if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
2569 pad_name = req_name;
2571 name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
2574 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
2575 context = (GstMatroskaTrackContext *)
2576 g_new0 (GstMatroskaTrackAudioContext, 1);
2577 context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
2578 context->name = g_strdup ("Audio");
2579 } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
2580 /* don't mix named and unnamed pads, if the pad already exists we fail when
2581 * trying to add it */
2582 if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
2583 pad_name = req_name;
2585 name = g_strdup_printf ("video_%u", mux->num_v_streams++);
2588 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
2589 context = (GstMatroskaTrackContext *)
2590 g_new0 (GstMatroskaTrackVideoContext, 1);
2591 context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
2592 context->name = g_strdup ("Video");
2593 } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
2594 /* don't mix named and unnamed pads, if the pad already exists we fail when
2595 * trying to add it */
2596 if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
2597 pad_name = req_name;
2599 name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
2602 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
2603 context = (GstMatroskaTrackContext *)
2604 g_new0 (GstMatroskaTrackSubtitleContext, 1);
2605 context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
2606 context->name = g_strdup ("Subtitle");
2607 /* setcaps may only provide proper one a lot later */
2608 id = "S_SUB_UNKNOWN";
2610 GST_WARNING_OBJECT (mux, "This is not our template!");
2614 newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
2615 "name", pad_name, "direction", templ->direction, "template", templ, NULL);
2617 gst_matroskamux_pad_init (newpad);
2618 collect_pad = (GstMatroskaPad *)
2619 gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad),
2620 sizeof (GstMatroskaPad),
2621 (GstCollectDataDestroyNotify) gst_matroska_pad_free, TRUE);
2623 collect_pad->mux = mux;
2624 collect_pad->track = context;
2625 gst_matroska_pad_reset (collect_pad, FALSE);
2627 gst_matroska_mux_set_codec_id (collect_pad->track, id);
2628 collect_pad->track->dts_only = FALSE;
2630 collect_pad->capsfunc = capsfunc;
2631 gst_pad_set_active (GST_PAD (newpad), TRUE);
2632 if (!gst_element_add_pad (element, GST_PAD (newpad)))
2633 goto pad_add_failed;
2639 GST_DEBUG_OBJECT (newpad, "Added new request pad");
2641 return GST_PAD (newpad);
2646 GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
2648 gst_object_unref (newpad);
2654 * gst_matroska_mux_release_pad:
2655 * @element: #GstMatroskaMux.
2656 * @pad: Pad to release.
2658 * Release a previously requested pad.
2661 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
2663 GstMatroskaMux *mux;
2666 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2668 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
2669 GstCollectData *cdata = (GstCollectData *) walk->data;
2670 GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
2672 if (cdata->pad == pad) {
2674 * observed duration, this will remain GST_CLOCK_TIME_NONE
2675 * only if the pad is reset
2677 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
2679 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2680 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2681 collected_duration =
2682 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2685 if (GST_CLOCK_TIME_IS_VALID (collected_duration)
2686 && mux->duration < collected_duration)
2687 mux->duration = collected_duration;
2693 gst_collect_pads_remove_pad (mux->collect, pad);
2694 if (gst_element_remove_pad (element, pad))
2699 gst_matroska_mux_write_mastering_metadata (GstMatroskaMux * mux,
2700 GstMatroskaTrackVideoContext * videocontext)
2702 GstEbmlWrite *ebml = mux->ebml_write;
2704 GstVideoMasteringDisplayInfo *minfo = &videocontext->mastering_display_info;
2706 const gdouble chroma_scale = 50000;
2707 const gdouble luma_scale = 50000;
2709 if (!videocontext->mastering_display_info_present)
2713 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_MASTERINGMETADATA);
2715 value = (gdouble) minfo->display_primaries[0].x / chroma_scale;
2716 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYX, value);
2718 value = (gdouble) minfo->display_primaries[0].y / chroma_scale;
2719 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYY, value);
2721 value = (gdouble) minfo->display_primaries[1].x / chroma_scale;
2722 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYX, value);
2724 value = (gdouble) minfo->display_primaries[1].y / chroma_scale;
2725 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYY, value);
2727 value = (gdouble) minfo->display_primaries[2].x / chroma_scale;
2728 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYX, value);
2730 value = (gdouble) minfo->display_primaries[2].y / chroma_scale;
2731 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYY, value);
2733 value = (gdouble) minfo->white_point.x / chroma_scale;
2734 gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYX, value);
2736 value = (gdouble) minfo->white_point.y / chroma_scale;
2737 gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY, value);
2739 value = (gdouble) minfo->max_display_mastering_luminance / luma_scale;
2740 gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMAX, value);
2742 value = (gdouble) minfo->min_display_mastering_luminance / luma_scale;
2743 gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMIN, value);
2745 gst_ebml_write_master_finish (ebml, master);
2750 gst_matroska_mux_write_colour (GstMatroskaMux * mux,
2751 GstMatroskaTrackVideoContext * videocontext)
2753 GstEbmlWrite *ebml = mux->ebml_write;
2755 guint matrix_id = 0;
2757 guint transfer_id = 0;
2758 guint primaries_id = 0;
2760 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_VIDEOCOLOUR);
2762 switch (videocontext->colorimetry.range) {
2763 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
2766 case GST_VIDEO_COLOR_RANGE_16_235:
2769 case GST_VIDEO_COLOR_RANGE_0_255:
2773 matrix_id = gst_video_color_matrix_to_iso (videocontext->colorimetry.matrix);
2775 gst_video_transfer_function_to_iso (videocontext->colorimetry.transfer);
2777 gst_video_color_primaries_to_iso (videocontext->colorimetry.primaries);
2779 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEORANGE, range_id);
2780 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOMATRIXCOEFFICIENTS,
2782 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS,
2784 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPRIMARIES, primaries_id);
2785 if (videocontext->content_light_level.max_content_light_level &&
2786 videocontext->content_light_level.max_frame_average_light_level) {
2787 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXCLL,
2788 videocontext->content_light_level.max_content_light_level);
2789 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXFALL,
2790 videocontext->content_light_level.max_frame_average_light_level);
2793 gst_matroska_mux_write_mastering_metadata (mux, videocontext);
2794 gst_ebml_write_master_finish (ebml, master);
2798 * gst_matroska_mux_track_header:
2799 * @mux: #GstMatroskaMux
2800 * @context: Tack context.
2802 * Write a track header.
2805 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2806 GstMatroskaTrackContext * context)
2808 GstEbmlWrite *ebml = mux->ebml_write;
2811 /* TODO: check if everything necessary is written and check default values */
2813 /* track type goes before the type-specific stuff */
2814 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2815 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2817 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, context->uid);
2818 if (context->default_duration) {
2819 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2820 context->default_duration);
2822 if (context->language) {
2823 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2827 /* FIXME: until we have a nice way of getting the codecname
2828 * out of the caps, I'm not going to enable this. Too much
2829 * (useless, double, boring) work... */
2830 /* TODO: Use value from tags if any */
2831 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2832 context->codec_name); */
2833 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2835 /* type-specific stuff */
2836 switch (context->type) {
2837 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2838 GstMatroskaTrackVideoContext *videocontext =
2839 (GstMatroskaTrackVideoContext *) context;
2841 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2842 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2843 videocontext->pixel_width);
2844 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2845 videocontext->pixel_height);
2846 if (videocontext->display_width && videocontext->display_height) {
2847 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2848 videocontext->display_width);
2849 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2850 videocontext->display_height);
2852 switch (videocontext->interlace_mode) {
2853 case GST_MATROSKA_INTERLACE_MODE_INTERLACED:
2854 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2856 case GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE:
2857 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 2);
2863 if (videocontext->fourcc) {
2864 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2866 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2867 (gpointer) & fcc_le, 4);
2869 gst_matroska_mux_write_colour (mux, videocontext);
2870 if (videocontext->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
2871 guint64 stereo_mode = 0;
2873 switch (videocontext->multiview_mode) {
2874 case GST_VIDEO_MULTIVIEW_MODE_MONO:
2876 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
2877 if (videocontext->multiview_flags &
2878 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2879 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_RL;
2881 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_LR;
2883 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
2884 if (videocontext->multiview_flags &
2885 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2886 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_RL;
2888 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_LR;
2890 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
2891 if (videocontext->multiview_flags &
2892 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2893 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_RL;
2895 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_LR;
2897 case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
2898 if (videocontext->multiview_flags &
2899 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2900 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_RL;
2902 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_LR;
2903 /* FIXME: In frame-by-frame mode, left/right frame buffers need to be
2904 * laced within one block. See http://www.matroska.org/technical/specs/index.html#StereoMode */
2905 GST_FIXME_OBJECT (mux,
2906 "Frame-by-frame stereoscopic mode not fully implemented");
2909 GST_WARNING_OBJECT (mux,
2910 "Multiview mode %d not supported in Matroska/WebM",
2911 videocontext->multiview_mode);
2915 if (stereo_mode != 0)
2916 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOSTEREOMODE,
2919 gst_ebml_write_master_finish (ebml, master);
2924 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2925 GstMatroskaTrackAudioContext *audiocontext =
2926 (GstMatroskaTrackAudioContext *) context;
2928 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2929 if (audiocontext->samplerate != 8000)
2930 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2931 audiocontext->samplerate);
2932 if (audiocontext->channels != 1)
2933 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2934 audiocontext->channels);
2935 if (audiocontext->bitdepth) {
2936 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2937 audiocontext->bitdepth);
2940 gst_ebml_write_master_finish (ebml, master);
2945 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
2949 /* doesn't need type-specific data */
2953 GST_DEBUG_OBJECT (mux, "Wrote track header. Codec %s", context->codec_id);
2955 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2956 if (context->codec_priv)
2957 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2958 context->codec_priv, context->codec_priv_size);
2960 if (context->seek_preroll) {
2961 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPREROLL,
2962 context->seek_preroll);
2965 if (context->codec_delay) {
2966 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CODECDELAY,
2967 context->codec_delay);
2972 gst_matroska_mux_write_chapter_title (const gchar * title, GstEbmlWrite * ebml)
2974 guint64 title_master;
2977 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERDISPLAY);
2979 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPSTRING, title);
2980 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CHAPLANGUAGE,
2981 GST_MATROSKA_MUX_CHAPLANG);
2983 gst_ebml_write_master_finish (ebml, title_master);
2986 static GstTocEntry *
2987 gst_matroska_mux_write_chapter (GstMatroskaMux * mux, GstTocEntry * edition,
2988 GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters,
2989 guint64 * master_edition)
2991 guint64 master_chapteratom;
2998 GstTocEntry *internal_chapter, *internal_nested;
3001 if (G_UNLIKELY (master_chapters != NULL && *master_chapters == 0))
3003 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERS);
3005 if (G_UNLIKELY (master_edition != NULL && *master_edition == 0)) {
3006 /* create uid for the parent */
3008 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_EDITIONENTRY);
3010 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONUID,
3011 g_ascii_strtoull (gst_toc_entry_get_uid (edition), NULL, 10));
3012 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGHIDDEN, 0);
3013 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGDEFAULT, 0);
3014 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGORDERED, 0);
3017 gst_toc_entry_get_start_stop_times (entry, &start, &stop);
3018 tags = gst_toc_entry_get_tags (entry);
3020 tags = gst_tag_list_copy (tags);
3023 /* build internal chapter */
3024 uid = gst_matroska_mux_create_uid (mux);
3025 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT, uid);
3026 internal_chapter = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, s_uid);
3028 /* Write the chapter entry */
3029 master_chapteratom =
3030 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERATOM);
3032 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERUID, uid);
3033 /* Store the user provided UID in the ChapterStringUID */
3034 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPTERSTRINGUID,
3035 gst_toc_entry_get_uid (entry));
3036 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTART, start);
3037 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTOP, stop);
3038 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGHIDDEN, 0);
3039 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGENABLED, 1);
3041 /* write current ChapterDisplays before the nested chapters */
3042 if (G_LIKELY (tags != NULL)) {
3043 count = gst_tag_list_get_tag_size (tags, GST_TAG_TITLE);
3045 for (i = 0; i < count; ++i) {
3046 gst_tag_list_get_string_index (tags, GST_TAG_TITLE, i, &title);
3047 /* FIXME: handle ChapterLanguage entries */
3048 gst_matroska_mux_write_chapter_title (title, ebml);
3052 /* remove title tag */
3053 if (G_LIKELY (count > 0))
3054 gst_tag_list_remove_tag (tags, GST_TAG_TITLE);
3056 gst_toc_entry_set_tags (internal_chapter, tags);
3059 /* Write nested chapters */
3060 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3062 internal_nested = gst_matroska_mux_write_chapter (mux, NULL, cur->data,
3065 gst_toc_entry_append_sub_entry (internal_chapter, internal_nested);
3068 gst_ebml_write_master_finish (ebml, master_chapteratom);
3070 return internal_chapter;
3073 static GstTocEntry *
3074 gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
3075 GstTocEntry * edition, GList * chapters, GstEbmlWrite * ebml,
3076 guint64 * master_chapters)
3078 guint64 master_edition = 0;
3081 GstTocEntry *internal_edition, *internal_chapter;
3082 GstTagList *tags = NULL;
3084 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT,
3085 gst_matroska_mux_create_uid (mux));
3087 if (edition != NULL) {
3088 /* Edition entry defined, get its tags */
3089 tags = gst_toc_entry_get_tags (edition);
3091 tags = gst_tag_list_copy (tags);
3095 internal_edition = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, s_uid);
3097 gst_toc_entry_set_tags (internal_edition, tags);
3100 for (cur = g_list_first (chapters); cur != NULL; cur = cur->next) {
3101 internal_chapter = gst_matroska_mux_write_chapter (mux, internal_edition,
3102 cur->data, ebml, master_chapters, &master_edition);
3104 gst_toc_entry_append_sub_entry (internal_edition, internal_chapter);
3107 if (G_LIKELY (master_edition != 0))
3108 gst_ebml_write_master_finish (ebml, master_edition);
3110 return internal_edition;
3114 * gst_matroska_mux_start:
3115 * @mux: #GstMatroskaMux
3117 * Start a new matroska file (write headers etc...)
3120 gst_matroska_mux_start (GstMatroskaMux * mux, GstMatroskaPad * first_pad,
3121 GstBuffer * first_pad_buf)
3123 GstEbmlWrite *ebml = mux->ebml_write;
3124 const gchar *doctype;
3125 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
3126 GST_MATROSKA_ID_TRACKS,
3127 GST_MATROSKA_ID_CHAPTERS,
3128 GST_MATROSKA_ID_CUES,
3129 GST_MATROSKA_ID_TAGS,
3132 const gchar *media_type;
3133 gboolean audio_only;
3134 guint64 master, child;
3138 GstClockTime earliest_time = GST_CLOCK_TIME_NONE;
3139 GstClockTime duration = 0;
3140 guint32 segment_uid[4];
3145 /* if not streaming, check if downstream is seekable */
3146 if (!mux->ebml_write->streamable) {
3150 query = gst_query_new_seeking (GST_FORMAT_BYTES);
3151 if (gst_pad_peer_query (mux->srcpad, query)) {
3152 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3153 GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
3155 /* assume seeking is not supported if query not handled downstream */
3156 GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
3160 mux->ebml_write->streamable = TRUE;
3161 g_object_notify (G_OBJECT (mux), "streamable");
3162 GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
3163 "streamable=false. Will ignore that and create streamable output "
3166 gst_query_unref (query);
3169 /* stream-start (FIXME: create id based on input ids) */
3170 g_snprintf (s_id, sizeof (s_id), "matroskamux-%08x", g_random_int ());
3171 gst_pad_push_event (mux->srcpad, gst_event_new_stream_start (s_id));
3174 audio_only = mux->num_v_streams == 0 && mux->num_a_streams > 0;
3176 media_type = (audio_only) ? "audio/webm" : "video/webm";
3178 media_type = (audio_only) ? "audio/x-matroska" : "video/x-matroska";
3180 ebml->caps = gst_caps_new_empty_simple (media_type);
3181 gst_pad_set_caps (mux->srcpad, ebml->caps);
3182 /* we start with a EBML header */
3183 doctype = mux->doctype;
3184 GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
3185 doctype, mux->doctype_version);
3186 gst_ebml_write_header (ebml, doctype, mux->doctype_version);
3188 /* the rest of the header is cached */
3189 gst_ebml_write_set_cache (ebml, 0x1000);
3191 /* start a segment */
3193 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
3194 mux->segment_master = ebml->pos;
3196 if (!mux->ebml_write->streamable) {
3197 /* seekhead (table of contents) - we set the positions later */
3198 mux->seekhead_pos = ebml->pos;
3199 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
3200 for (i = 0; seekhead_id[i] != 0; i++) {
3201 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
3202 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
3203 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
3204 gst_ebml_write_master_finish (ebml, child);
3206 gst_ebml_write_master_finish (ebml, master);
3209 if (mux->ebml_write->streamable) {
3210 const GstTagList *tags;
3211 gboolean has_main_tags;
3214 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3215 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3217 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux)) {
3218 guint64 master_tags, master_tag;
3220 GST_DEBUG_OBJECT (mux, "Writing tags");
3222 mux->tags_pos = ebml->pos;
3223 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3224 if (has_main_tags) {
3225 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3226 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3227 gst_ebml_write_master_finish (ebml, master_tag);
3229 gst_matroska_mux_write_streams_tags (mux);
3230 gst_ebml_write_master_finish (ebml, master_tags);
3235 mux->info_pos = ebml->pos;
3236 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
3238 /* WebM does not support SegmentUID field on SegmentInfo */
3239 if (!mux->is_webm) {
3240 for (i = 0; i < 4; i++) {
3241 segment_uid[i] = g_random_int ();
3243 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
3244 (guint8 *) segment_uid, 16);
3247 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
3248 mux->duration_pos = ebml->pos;
3250 if (!mux->ebml_write->streamable) {
3251 for (collected = mux->collect->data; collected;
3252 collected = g_slist_next (collected)) {
3253 GstMatroskaPad *collect_pad;
3255 gint64 trackduration;
3257 collect_pad = (GstMatroskaPad *) collected->data;
3258 thepad = collect_pad->collect.pad;
3260 /* Query the total length of the track. */
3261 GST_DEBUG_OBJECT (thepad, "querying peer duration");
3262 if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
3263 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
3264 GST_TIME_ARGS (trackduration));
3265 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
3266 duration = (GstClockTime) trackduration;
3270 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3271 gst_guint64_to_gdouble (duration) /
3272 gst_guint64_to_gdouble (mux->time_scale));
3274 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
3275 "GStreamer matroskamux version " PACKAGE_VERSION);
3276 if (mux->writing_app && mux->writing_app[0]) {
3277 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
3279 if (mux->creation_time != NULL) {
3280 time = g_date_time_to_unix (mux->creation_time) * GST_SECOND;
3281 time += g_date_time_get_microsecond (mux->creation_time) * GST_USECOND;
3283 time = g_get_real_time () * GST_USECOND;
3285 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time);
3286 gst_ebml_write_master_finish (ebml, master);
3289 mux->tracks_pos = ebml->pos;
3290 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
3292 for (collected = mux->collect->data; collected;
3293 collected = g_slist_next (collected)) {
3294 GstMatroskaPad *collect_pad;
3297 collect_pad = (GstMatroskaPad *) collected->data;
3299 /* This will cause an error at a later time */
3300 if (collect_pad->track->codec_id == NULL)
3303 /* Find the smallest timestamp so we can offset all streams by this to
3305 if (mux->offset_to_zero) {
3308 if (collect_pad == first_pad)
3309 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3311 buf = gst_collect_pads_peek (mux->collect, collected->data);
3314 ts = gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
3316 if (earliest_time == GST_CLOCK_TIME_NONE)
3318 else if (ts != GST_CLOCK_TIME_NONE && ts < earliest_time)
3323 gst_buffer_unref (buf);
3326 /* For audio tracks, use the first buffers duration as the default
3327 * duration if we didn't get any better idea from the caps event already
3329 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO &&
3330 collect_pad->track->default_duration == 0) {
3331 if (collect_pad == first_pad)
3332 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3334 buf = gst_collect_pads_peek (mux->collect, collected->data);
3336 if (buf && GST_BUFFER_DURATION_IS_VALID (buf))
3337 collect_pad->track->default_duration =
3338 GST_BUFFER_DURATION (buf) + collect_pad->track->codec_delay;
3340 gst_buffer_unref (buf);
3343 collect_pad->track->num = tracknum++;
3344 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
3345 gst_matroska_mux_track_header (mux, collect_pad->track);
3346 gst_ebml_write_master_finish (ebml, child);
3347 /* some remaining pad/track setup */
3348 collect_pad->default_duration_scaled =
3349 gst_util_uint64_scale (collect_pad->track->default_duration,
3350 1, mux->time_scale);
3352 gst_ebml_write_master_finish (ebml, master);
3354 mux->earliest_time = earliest_time == GST_CLOCK_TIME_NONE ? 0 : earliest_time;
3357 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3358 if (toc != NULL && !mux->ebml_write->streamable) {
3359 guint64 master_chapters = 0;
3360 GstTocEntry *internal_edition;
3361 GList *cur, *chapters;
3363 GST_DEBUG ("Writing chapters");
3365 /* There are two UIDs for Chapters:
3366 * - The ChapterUID is a mandatory unsigned integer which internally
3367 * refers to a given chapter. Except for the title & language which use
3368 * dedicated fields, this UID can also be used to add tags to the Chapter.
3369 * The tags come in a separate section of the container.
3370 * - The ChapterStringUID is an optional UTF-8 string which also uniquely
3371 * refers to a chapter but from an external perspective. It can act as a
3372 * "WebVTT cue identifier" which "can be used to reference a specific cue,
3373 * for example from script or CSS".
3375 * The ChapterUID will be generated and checked for unicity, while the
3376 * ChapterStringUID will receive the user defined UID.
3378 * In order to be able to refer to chapters from the tags section,
3379 * we must maintain an internal Toc tree with the generated ChapterUID
3380 * (see gst_matroska_mux_write_toc_entry_tags) */
3382 /* Check whether we have editions or chapters at the root level. */
3383 cur = gst_toc_get_entries (toc);
3385 mux->chapters_pos = ebml->pos;
3387 mux->internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
3389 if (gst_toc_entry_get_entry_type (cur->data) ==
3390 GST_TOC_ENTRY_TYPE_EDITION) {
3391 /* Editions at the root level */
3392 for (; cur != NULL; cur = cur->next) {
3393 chapters = gst_toc_entry_get_sub_entries (cur->data);
3394 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3395 cur->data, chapters, ebml, &master_chapters);
3396 gst_toc_append_entry (mux->internal_toc, internal_edition);
3399 /* Chapters at the root level */
3400 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3401 NULL, cur, ebml, &master_chapters);
3402 gst_toc_append_entry (mux->internal_toc, internal_edition);
3405 /* close master element if any edition was written */
3406 if (G_LIKELY (master_chapters != 0))
3407 gst_ebml_write_master_finish (ebml, master_chapters);
3411 /* lastly, flush the cache */
3412 gst_ebml_write_flush_cache (ebml, FALSE, 0);
3415 gst_toc_unref (toc);
3418 /* TODO: more sensible tag mappings */
3421 const gchar *matroska_tagname;
3422 const gchar *gstreamer_tagname;
3424 gst_matroska_tag_conv[] = {
3426 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
3427 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
3428 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
3429 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
3430 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
3431 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
3432 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
3433 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
3434 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
3435 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
3436 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
3437 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
3438 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
3439 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
3440 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
3443 /* Every stagefright implementation on android up to and including 6.0.1 is using
3444 libwebm with bug in matroska parsing, where it will choke on empty tag elements;
3445 so before outputting tags and tag elements we better make sure that there are
3446 actually tags we are going to write */
3448 gst_matroska_mux_tag_list_is_empty (const GstTagList * list)
3451 for (i = 0; i < gst_tag_list_n_tags (list); i++) {
3452 const gchar *tag = gst_tag_list_nth_tag_name (list, i);
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 if (strcmp (tagname_gst, tag) == 0) {
3457 GValue src = { 0, };
3460 if (!gst_tag_list_copy_value (&src, list, tag))
3462 dest = gst_value_serialize (&src);
3464 g_value_unset (&src);
3476 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
3479 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
3481 guint64 simpletag_master;
3483 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3484 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3485 const gchar *tagname_mkv = gst_matroska_tag_conv[i].matroska_tagname;
3487 if (strcmp (tagname_gst, tag) == 0) {
3488 GValue src = { 0, };
3491 if (!gst_tag_list_copy_value (&src, list, tag))
3493 if ((dest = gst_value_serialize (&src))) {
3495 simpletag_master = gst_ebml_write_master_start (ebml,
3496 GST_MATROSKA_ID_SIMPLETAG);
3497 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
3498 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
3499 gst_ebml_write_master_finish (ebml, simpletag_master);
3502 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
3504 g_value_unset (&src);
3511 gst_matroska_mux_write_stream_tags (GstMatroskaMux * mux, GstMatroskaPad * mpad)
3513 guint64 master_tag, master_targets;
3516 ebml = mux->ebml_write;
3518 if (G_UNLIKELY (mpad->tags == NULL
3519 || gst_matroska_mux_tag_list_is_empty (mpad->tags)))
3522 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3523 master_targets = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3525 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETTRACKUID, mpad->track->uid);
3527 gst_ebml_write_master_finish (ebml, master_targets);
3528 gst_tag_list_foreach (mpad->tags, gst_matroska_mux_write_simple_tag, ebml);
3529 gst_ebml_write_master_finish (ebml, master_tag);
3533 gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux)
3537 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3538 GstMatroskaPad *collect_pad;
3540 collect_pad = (GstMatroskaPad *) walk->data;
3542 gst_matroska_mux_write_stream_tags (mux, collect_pad);
3547 gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux)
3551 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3552 GstMatroskaPad *collect_pad;
3554 collect_pad = (GstMatroskaPad *) walk->data;
3555 if (!gst_matroska_mux_tag_list_is_empty (collect_pad->tags))
3562 gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
3563 const GstTocEntry * entry, guint64 * master_tags, gboolean * has_tags)
3565 guint64 master_tag, master_targets;
3568 const GstTagList *tags;
3570 ebml = mux->ebml_write;
3572 tags = gst_toc_entry_get_tags (entry);
3573 if (G_UNLIKELY (tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags))) {
3576 if (*master_tags == 0) {
3577 mux->tags_pos = ebml->pos;
3578 *master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3581 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3583 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3585 if (gst_toc_entry_get_entry_type (entry) == GST_TOC_ENTRY_TYPE_EDITION)
3586 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETEDITIONUID,
3587 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3589 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETCHAPTERUID,
3590 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3592 gst_ebml_write_master_finish (ebml, master_targets);
3593 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3594 gst_ebml_write_master_finish (ebml, master_tag);
3597 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3599 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, master_tags,
3605 * gst_matroska_mux_finish:
3606 * @mux: #GstMatroskaMux
3608 * Finish a new matroska file (write index etc...)
3611 gst_matroska_mux_finish (GstMatroskaMux * mux)
3613 GstEbmlWrite *ebml = mux->ebml_write;
3615 guint64 duration = 0;
3617 const GstTagList *tags, *toc_tags;
3619 gboolean has_main_tags, toc_has_tags = FALSE;
3622 /* finish last cluster */
3624 gst_ebml_write_master_finish (ebml, mux->cluster);
3628 if (mux->index != NULL) {
3630 guint64 master, pointentry_master, trackpos_master;
3632 mux->cues_pos = ebml->pos;
3633 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
3634 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
3636 for (n = 0; n < mux->num_indexes; n++) {
3637 GstMatroskaIndex *idx = &mux->index[n];
3639 pointentry_master = gst_ebml_write_master_start (ebml,
3640 GST_MATROSKA_ID_POINTENTRY);
3641 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
3642 idx->time / mux->time_scale);
3643 trackpos_master = gst_ebml_write_master_start (ebml,
3644 GST_MATROSKA_ID_CUETRACKPOSITIONS);
3645 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
3646 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
3647 idx->pos - mux->segment_master);
3648 gst_ebml_write_master_finish (ebml, trackpos_master);
3649 gst_ebml_write_master_finish (ebml, pointentry_master);
3652 gst_ebml_write_master_finish (ebml, master);
3653 gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
3657 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3658 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3659 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3661 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux) || toc != NULL) {
3662 guint64 master_tags = 0, master_tag;
3664 GST_DEBUG_OBJECT (mux, "Writing tags");
3666 if (has_main_tags) {
3667 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
3668 mux->tags_pos = ebml->pos;
3669 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3670 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3673 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3674 if (mux->internal_toc != NULL) {
3675 toc_tags = gst_toc_get_tags (mux->internal_toc);
3676 toc_has_tags = (toc_tags != NULL);
3677 gst_tag_list_foreach (toc_tags, gst_matroska_mux_write_simple_tag,
3681 gst_ebml_write_master_finish (ebml, master_tag);
3684 if (mux->internal_toc != NULL) {
3685 for (cur = gst_toc_get_entries (mux->internal_toc); cur != NULL;
3687 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, &master_tags,
3692 if (master_tags == 0 && gst_matroska_mux_streams_have_tags (mux)) {
3693 mux->tags_pos = ebml->pos;
3694 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3696 gst_matroska_mux_write_streams_tags (mux);
3698 if (master_tags != 0)
3699 gst_ebml_write_master_finish (ebml, master_tags);
3702 /* update seekhead. We know that:
3703 * - a seekhead contains 5 entries.
3704 * - order of entries is as above.
3705 * - a seekhead has a 4-byte header + 8-byte length
3706 * - each entry is 2-byte master, 2-byte ID pointer,
3707 * 2-byte length pointer, all 8/1-byte length, 4-
3708 * byte ID and 8-byte length pointer, where the
3709 * length pointer starts at 20.
3710 * - all entries are local to the segment (so pos - segment_master).
3711 * - so each entry is at 12 + 20 + num * 28. */
3712 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
3713 mux->info_pos - mux->segment_master);
3714 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
3715 mux->tracks_pos - mux->segment_master);
3716 if (toc != NULL && mux->chapters_pos > 0) {
3717 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
3718 mux->chapters_pos - mux->segment_master);
3721 guint64 my_pos = ebml->pos;
3723 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
3724 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3725 gst_ebml_write_seek (ebml, my_pos);
3727 if (mux->index != NULL) {
3728 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
3729 mux->cues_pos - mux->segment_master);
3732 guint64 my_pos = ebml->pos;
3734 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
3735 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3736 gst_ebml_write_seek (ebml, my_pos);
3739 if (mux->tags_pos != 0 || toc_has_tags) {
3740 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 144,
3741 mux->tags_pos - mux->segment_master);
3744 guint64 my_pos = ebml->pos;
3746 gst_ebml_write_seek (ebml, mux->seekhead_pos + 124);
3747 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3748 gst_ebml_write_seek (ebml, my_pos);
3752 gst_toc_unref (toc);
3756 * - first get the overall duration
3757 * (a released track may have left a duration in here)
3758 * - write some track header data for subtitles
3760 duration = mux->duration;
3762 for (collected = mux->collect->data; collected;
3763 collected = g_slist_next (collected)) {
3764 GstMatroskaPad *collect_pad;
3766 * observed duration, this will never remain GST_CLOCK_TIME_NONE
3767 * since this means buffer without timestamps that is not possible
3769 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
3771 collect_pad = (GstMatroskaPad *) collected->data;
3773 GST_DEBUG_OBJECT (mux,
3774 "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
3775 " end ts %" GST_TIME_FORMAT, collect_pad,
3776 GST_TIME_ARGS (collect_pad->start_ts),
3777 GST_TIME_ARGS (collect_pad->end_ts));
3779 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
3780 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
3781 collected_duration =
3782 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
3783 GST_DEBUG_OBJECT (collect_pad->collect.pad,
3784 "final track duration: %" GST_TIME_FORMAT,
3785 GST_TIME_ARGS (collected_duration));
3787 GST_WARNING_OBJECT (collect_pad->collect.pad,
3788 "unable to get final track duration");
3790 if (GST_CLOCK_TIME_IS_VALID (collected_duration) &&
3791 duration < collected_duration)
3792 duration = collected_duration;
3796 /* seek back (optional, but do anyway) */
3797 gst_ebml_write_seek (ebml, pos);
3799 /* update duration */
3800 if (duration != 0) {
3801 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
3802 GST_TIME_ARGS (duration));
3803 pos = mux->ebml_write->pos;
3804 gst_ebml_write_seek (ebml, mux->duration_pos);
3805 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3806 gst_guint64_to_gdouble (duration) /
3807 gst_guint64_to_gdouble (mux->time_scale));
3808 gst_ebml_write_seek (ebml, pos);
3811 guint64 my_pos = ebml->pos;
3813 gst_ebml_write_seek (ebml, mux->duration_pos);
3814 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
3815 gst_ebml_write_seek (ebml, my_pos);
3817 GST_DEBUG_OBJECT (mux, "finishing segment");
3818 /* finish segment - this also writes element length */
3819 gst_ebml_write_master_finish (ebml, mux->segment_pos);
3823 * gst_matroska_mux_buffer_header:
3824 * @track: Track context.
3825 * @relative_timestamp: relative timestamp of the buffer
3826 * @flags: Buffer flags.
3828 * Create a buffer containing buffer header.
3830 * Returns: New buffer.
3833 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
3834 gint16 relative_timestamp, int flags)
3837 guint8 *data = g_malloc (4);
3839 hdr = gst_buffer_new_wrapped (data, 4);
3840 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
3841 data[0] = track->num | 0x80;
3842 /* time relative to clustertime */
3843 GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
3851 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
3852 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
3853 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
3856 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
3857 GstMatroskaPad * collect_pad, GstBuffer * buf)
3859 GstMatroskaTrackVideoContext *ctx =
3860 (GstMatroskaTrackVideoContext *) collect_pad->track;
3865 guint32 next_parse_offset;
3866 GstBuffer *ret = NULL;
3867 gboolean is_muxing_unit = FALSE;
3869 gst_buffer_map (buf, &map, GST_MAP_READ);
3874 gst_buffer_unmap (buf, &map);
3875 gst_buffer_unref (buf);
3879 /* Check if this buffer contains a picture or end-of-sequence packet */
3880 while (size >= 13) {
3881 if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
3882 gst_buffer_unmap (buf, &map);
3883 gst_buffer_unref (buf);
3887 parse_code = GST_READ_UINT8 (data + 4);
3888 if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
3889 if (ctx->dirac_unit) {
3890 gst_buffer_unref (ctx->dirac_unit);
3891 ctx->dirac_unit = NULL;
3893 } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
3894 parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
3895 is_muxing_unit = TRUE;
3899 next_parse_offset = GST_READ_UINT32_BE (data + 5);
3901 if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
3904 data += next_parse_offset;
3905 size -= next_parse_offset;
3908 if (ctx->dirac_unit)
3909 ctx->dirac_unit = gst_buffer_append (ctx->dirac_unit, gst_buffer_ref (buf));
3911 ctx->dirac_unit = gst_buffer_ref (buf);
3913 gst_buffer_unmap (buf, &map);
3915 if (is_muxing_unit) {
3916 ret = gst_buffer_make_writable (ctx->dirac_unit);
3917 ctx->dirac_unit = NULL;
3918 gst_buffer_copy_into (ret, buf,
3919 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
3920 gst_buffer_unref (buf);
3922 gst_buffer_unref (buf);
3930 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
3934 GValue streamheader = { 0 };
3935 GValue bufval = { 0 };
3936 GstBuffer *streamheader_buffer;
3937 GstEbmlWrite *ebml = mux->ebml_write;
3939 streamheader_buffer = gst_ebml_stop_streamheader (ebml);
3940 caps = gst_caps_copy (mux->ebml_write->caps);
3941 s = gst_caps_get_structure (caps, 0);
3942 g_value_init (&streamheader, GST_TYPE_ARRAY);
3943 g_value_init (&bufval, GST_TYPE_BUFFER);
3944 GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_HEADER);
3945 gst_value_set_buffer (&bufval, streamheader_buffer);
3946 gst_value_array_append_value (&streamheader, &bufval);
3947 g_value_unset (&bufval);
3948 gst_structure_set_value (s, "streamheader", &streamheader);
3949 g_value_unset (&streamheader);
3950 gst_caps_replace (&ebml->caps, caps);
3951 gst_buffer_unref (streamheader_buffer);
3952 gst_pad_set_caps (mux->srcpad, caps);
3953 gst_caps_unref (caps);
3957 * gst_matroska_mux_write_data:
3958 * @mux: #GstMatroskaMux
3959 * @collect_pad: #GstMatroskaPad with the data
3961 * Write collected data (called from gst_matroska_mux_collected).
3963 * Returns: Result of the gst_pad_push issued to write the data.
3965 static GstFlowReturn
3966 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
3969 GstEbmlWrite *ebml = mux->ebml_write;
3972 gboolean write_duration;
3973 guint64 cluster_time_scaled;
3974 gint16 relative_timestamp;
3975 gint64 relative_timestamp64;
3976 guint64 block_duration, duration_diff = 0;
3977 gboolean is_video_keyframe = FALSE;
3978 gboolean is_video_invisible = FALSE;
3979 gboolean is_audio_only = FALSE;
3980 gboolean is_min_duration_reached = FALSE;
3981 gboolean is_max_duration_exceeded = FALSE;
3982 GstMatroskamuxPad *pad;
3984 GstClockTime buffer_timestamp;
3985 GstAudioClippingMeta *cmeta = NULL;
3988 pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
3990 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
3991 if (collect_pad->track->xiph_headers_to_skip > 0) {
3992 --collect_pad->track->xiph_headers_to_skip;
3993 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER)) {
3994 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
3995 gst_buffer_unref (buf);
4000 /* for dirac we have to queue up everything up to a picture unit */
4001 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC)) {
4002 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
4005 } else if (!strcmp (collect_pad->track->codec_id,
4006 GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) {
4007 /* Remove the 'Frame container atom' header' */
4008 buf = gst_buffer_make_writable (buf);
4009 gst_buffer_resize (buf, 8, gst_buffer_get_size (buf) - 8);
4013 gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
4014 if (buffer_timestamp >= mux->earliest_time) {
4015 buffer_timestamp -= mux->earliest_time;
4017 buffer_timestamp = 0;
4020 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
4021 * this would wreak havoc with time stored in matroska file */
4022 /* TODO: maybe calculate a timestamp by using the previous timestamp
4023 * and default duration */
4024 if (!GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
4025 GST_WARNING_OBJECT (collect_pad->collect.pad,
4026 "Invalid buffer timestamp; dropping buffer");
4027 gst_buffer_unref (buf);
4031 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4032 && collect_pad->track->codec_delay) {
4033 /* All timestamps should include the codec delay */
4034 if (buffer_timestamp > collect_pad->track->codec_delay) {
4035 buffer_timestamp += collect_pad->track->codec_delay;
4037 buffer_timestamp = 0;
4038 duration_diff = collect_pad->track->codec_delay - buffer_timestamp;
4042 /* set the timestamp for outgoing buffers */
4043 ebml->timestamp = buffer_timestamp;
4045 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
4046 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
4047 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
4048 GST_TIME_ARGS (buffer_timestamp));
4049 is_video_keyframe = TRUE;
4050 } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DECODE_ONLY) &&
4051 (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP8)
4052 || !strcmp (collect_pad->track->codec_id,
4053 GST_MATROSKA_CODEC_ID_VIDEO_VP9))) {
4054 GST_LOG_OBJECT (mux,
4055 "have VP8 video invisible frame, " "ts=%" GST_TIME_FORMAT,
4056 GST_TIME_ARGS (buffer_timestamp));
4057 is_video_invisible = TRUE;
4061 /* From this point on we use the buffer_timestamp to do cluster and other
4062 * related arithmetic, so apply the timestamp offset if we have one */
4063 buffer_timestamp += mux->cluster_timestamp_offset;
4065 is_audio_only = (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
4066 (mux->num_streams == 1);
4067 is_min_duration_reached = (mux->min_cluster_duration == 0
4068 || (buffer_timestamp > mux->cluster_time
4069 && (buffer_timestamp - mux->cluster_time) >=
4070 mux->min_cluster_duration));
4071 is_max_duration_exceeded = (mux->max_cluster_duration > 0
4072 && buffer_timestamp > mux->cluster_time
4073 && (buffer_timestamp - mux->cluster_time) >=
4074 MIN (G_MAXINT16 * mux->time_scale, mux->max_cluster_duration));
4077 /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
4078 * or when we may be reaching the limit of the relative timestamp */
4079 if (is_max_duration_exceeded || (is_video_keyframe
4080 && is_min_duration_reached) || mux->force_key_unit_event
4081 || (is_audio_only && is_min_duration_reached)) {
4082 if (!mux->ebml_write->streamable)
4083 gst_ebml_write_master_finish (ebml, mux->cluster);
4085 /* Forward the GstForceKeyUnit event after finishing the cluster */
4086 if (mux->force_key_unit_event) {
4087 gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
4088 mux->force_key_unit_event = NULL;
4090 cluster_time_scaled =
4091 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4093 mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
4094 mux->cluster_pos = ebml->pos;
4095 gst_ebml_write_set_cache (ebml, 0x20);
4097 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4098 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4099 cluster_time_scaled);
4100 GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
4101 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
4102 gst_ebml_write_flush_cache (ebml, is_video_keyframe
4103 || is_audio_only, buffer_timestamp);
4104 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
4105 mux->prev_cluster_size);
4106 /* cluster_time needs to be identical in value to what's stored in the
4107 * matroska so we need to have it with the same precision as what's
4108 * possible with the set timecodescale rather than just using the
4110 * If this is not done the rounding of relative_timestamp will be
4111 * incorrect and possibly making the timestamps get out of order if tw
4112 * buffers arrive at the same millisecond (assuming default timecodescale
4115 gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4119 cluster_time_scaled =
4120 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4121 mux->cluster_pos = ebml->pos;
4122 gst_ebml_write_set_cache (ebml, 0x20);
4123 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4124 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4125 cluster_time_scaled);
4126 gst_ebml_write_flush_cache (ebml, TRUE, buffer_timestamp);
4127 /* cluster_time needs to be identical in value to what's stored in the
4128 * matroska so we need to have it with the same precision as what's
4129 * possible with the set timecodescale rather than just using the
4131 * If this is not done the rounding of relative_timestamp will be
4132 * incorrect and possibly making the timestamps get out of order if tw
4133 * buffers arrive at the same millisecond (assuming default timecodescale
4136 gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4139 /* We currently write index entries for all video tracks or for the audio
4140 * track in a single-track audio file. This could be improved by keeping the
4141 * index only for the *first* video track. */
4143 /* TODO: index is useful for every track, should contain the number of
4144 * the block in the cluster which contains the timestamp, should also work
4145 * for files with multiple audio tracks.
4147 if (!mux->ebml_write->streamable && (is_video_keyframe || is_audio_only)) {
4150 if (mux->min_index_interval != 0) {
4151 for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
4152 if (mux->index[last_idx].track == collect_pad->track->num)
4157 if (last_idx < 0 || mux->min_index_interval == 0 ||
4158 (GST_CLOCK_DIFF (mux->index[last_idx].time, buffer_timestamp)
4159 >= mux->min_index_interval)) {
4160 GstMatroskaIndex *idx;
4162 if (mux->num_indexes % 32 == 0) {
4163 mux->index = g_renew (GstMatroskaIndex, mux->index,
4164 mux->num_indexes + 32);
4166 idx = &mux->index[mux->num_indexes++];
4168 idx->pos = mux->cluster_pos;
4169 idx->time = buffer_timestamp;
4170 idx->track = collect_pad->track->num;
4174 /* Check if the duration differs from the default duration. */
4175 write_duration = FALSE;
4177 if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
4178 block_duration = GST_BUFFER_DURATION (buf) + duration_diff;
4179 block_duration = gst_util_uint64_scale (block_duration, 1, mux->time_scale);
4181 /* small difference should be ok. */
4182 if (block_duration > collect_pad->default_duration_scaled + 1 ||
4183 block_duration < collect_pad->default_duration_scaled - 1) {
4184 write_duration = TRUE;
4188 /* write the block, for doctype v2 use SimpleBlock if possible
4189 * one slice (*breath*).
4190 * FIXME: Need to do correct lacing! */
4191 relative_timestamp64 = buffer_timestamp - mux->cluster_time;
4192 if (relative_timestamp64 >= 0) {
4193 /* round the timestamp */
4194 relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
4195 relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
4198 /* round the timestamp */
4199 relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
4200 relative_timestamp =
4201 -((gint16) gst_util_uint64_scale (-relative_timestamp64, 1,
4205 if (is_video_invisible)
4208 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
4209 cmeta = gst_buffer_get_audio_clipping_meta (buf);
4210 g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);
4212 /* Start clipping is done via header and CodecDelay */
4213 if (cmeta && !cmeta->end)
4217 if (mux->doctype_version > 1 && !write_duration && !cmeta) {
4218 if (is_video_keyframe)
4222 gst_matroska_mux_create_buffer_header (collect_pad->track,
4223 relative_timestamp, flags);
4224 gst_ebml_write_set_cache (ebml, 0x40);
4225 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
4226 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4227 gst_ebml_write_buffer (ebml, hdr);
4228 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4229 gst_ebml_write_buffer (ebml, buf);
4231 return gst_ebml_last_write_result (ebml);
4233 gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
4234 /* write and call order slightly unnatural,
4235 * but avoids seek and minizes pushing */
4236 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
4238 gst_matroska_mux_create_buffer_header (collect_pad->track,
4239 relative_timestamp, flags);
4241 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
4243 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4245 /* Start clipping is done via header and CodecDelay */
4248 gst_util_uint64_scale_round (cmeta->end, GST_SECOND, 48000);
4249 gst_ebml_write_sint (ebml, GST_MATROSKA_ID_DISCARDPADDING, end);
4253 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
4254 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4255 gst_ebml_write_buffer (ebml, hdr);
4256 gst_ebml_write_master_finish_full (ebml, blockgroup,
4257 gst_buffer_get_size (buf));
4258 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4259 gst_ebml_write_buffer (ebml, buf);
4261 return gst_ebml_last_write_result (ebml);
4266 * gst_matroska_mux_handle_buffer:
4267 * @pads: #GstCollectPads
4268 * @uuser_data: #GstMatroskaMux
4270 * Collectpads callback.
4272 * Returns: #GstFlowReturn
4274 static GstFlowReturn
4275 gst_matroska_mux_handle_buffer (GstCollectPads * pads, GstCollectData * data,
4276 GstBuffer * buf, gpointer user_data)
4278 GstClockTime buffer_timestamp;
4279 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
4280 GstEbmlWrite *ebml = mux->ebml_write;
4281 GstMatroskaPad *best = (GstMatroskaPad *) data;
4282 GstFlowReturn ret = GST_FLOW_OK;
4283 GST_DEBUG_OBJECT (mux, "Collected pads");
4285 /* start with a header */
4286 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
4287 if (mux->collect->data == NULL) {
4288 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
4289 ("No input streams configured"));
4290 return GST_FLOW_ERROR;
4292 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
4293 gst_ebml_start_streamheader (ebml);
4294 gst_matroska_mux_start (mux, best, buf);
4295 gst_matroska_mux_stop_streamheader (mux);
4296 mux->state = GST_MATROSKA_MUX_STATE_DATA;
4299 /* if there is no best pad, we have reached EOS */
4301 GST_DEBUG_OBJECT (mux, "No best pad. Finishing...");
4302 if (!mux->ebml_write->streamable) {
4303 gst_matroska_mux_finish (mux);
4305 GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
4307 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
4312 if (best->track->codec_id == NULL) {
4313 GST_ERROR_OBJECT (best->collect.pad, "No codec-id for pad");
4314 ret = GST_FLOW_NOT_NEGOTIATED;
4318 /* if we have a best stream, should also have a buffer */
4321 buffer_timestamp = gst_matroska_track_get_buffer_timestamp (best->track, buf);
4322 if (buffer_timestamp >= mux->earliest_time) {
4323 buffer_timestamp -= mux->earliest_time;
4325 GST_ERROR_OBJECT (mux,
4326 "PTS before first PTS (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")",
4327 GST_TIME_ARGS (buffer_timestamp), GST_TIME_ARGS (mux->earliest_time));
4328 buffer_timestamp = 0;
4331 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
4332 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
4333 GST_TIME_ARGS (buffer_timestamp),
4334 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
4336 /* make note of first and last encountered timestamps, so we can calculate
4337 * the actual duration later when we send an updated header on eos */
4338 if (GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
4339 GstClockTime start_ts = buffer_timestamp;
4340 GstClockTime end_ts = start_ts;
4342 if (GST_BUFFER_DURATION_IS_VALID (buf))
4343 end_ts += GST_BUFFER_DURATION (buf);
4344 else if (best->track->default_duration)
4345 end_ts += best->track->default_duration;
4347 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
4348 best->end_ts = end_ts;
4350 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
4351 start_ts < best->start_ts))
4352 best->start_ts = start_ts;
4355 /* write one buffer */
4356 ret = gst_matroska_mux_write_data (mux, best, buf);
4364 * gst_matroska_mux_change_state:
4365 * @element: #GstMatroskaMux
4366 * @transition: State change transition.
4368 * Change the muxer state.
4370 * Returns: #GstStateChangeReturn
4372 static GstStateChangeReturn
4373 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
4375 GstStateChangeReturn ret;
4376 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
4378 switch (transition) {
4379 case GST_STATE_CHANGE_NULL_TO_READY:
4381 case GST_STATE_CHANGE_READY_TO_PAUSED:
4382 gst_collect_pads_start (mux->collect);
4384 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4386 case GST_STATE_CHANGE_PAUSED_TO_READY:
4387 gst_collect_pads_stop (mux->collect);
4393 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4395 switch (transition) {
4396 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4398 case GST_STATE_CHANGE_PAUSED_TO_READY:
4399 gst_matroska_mux_reset (GST_ELEMENT (mux));
4401 case GST_STATE_CHANGE_READY_TO_NULL:
4411 gst_matroska_mux_set_property (GObject * object,
4412 guint prop_id, const GValue * value, GParamSpec * pspec)
4414 GstMatroskaMux *mux;
4416 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4417 mux = GST_MATROSKA_MUX (object);
4420 case PROP_WRITING_APP:
4421 if (!g_value_get_string (value)) {
4422 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
4425 g_free (mux->writing_app);
4426 mux->writing_app = g_value_dup_string (value);
4428 case PROP_DOCTYPE_VERSION:
4429 mux->doctype_version = g_value_get_int (value);
4431 case PROP_MIN_INDEX_INTERVAL:
4432 mux->min_index_interval = g_value_get_int64 (value);
4434 case PROP_STREAMABLE:
4435 mux->ebml_write->streamable = g_value_get_boolean (value);
4437 case PROP_TIMECODESCALE:
4438 mux->time_scale = g_value_get_int64 (value);
4440 case PROP_MIN_CLUSTER_DURATION:
4441 mux->min_cluster_duration = g_value_get_int64 (value);
4443 case PROP_MAX_CLUSTER_DURATION:
4444 mux->max_cluster_duration = g_value_get_int64 (value);
4446 case PROP_OFFSET_TO_ZERO:
4447 mux->offset_to_zero = g_value_get_boolean (value);
4449 case PROP_CREATION_TIME:
4450 g_clear_pointer (&mux->creation_time, g_date_time_unref);
4451 mux->creation_time = g_value_dup_boxed (value);
4453 case PROP_CLUSTER_TIMESTAMP_OFFSET:
4454 mux->cluster_timestamp_offset = g_value_get_uint64 (value);
4457 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4463 gst_matroska_mux_get_property (GObject * object,
4464 guint prop_id, GValue * value, GParamSpec * pspec)
4466 GstMatroskaMux *mux;
4468 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4469 mux = GST_MATROSKA_MUX (object);
4472 case PROP_WRITING_APP:
4473 g_value_set_string (value, mux->writing_app);
4475 case PROP_DOCTYPE_VERSION:
4476 g_value_set_int (value, mux->doctype_version);
4478 case PROP_MIN_INDEX_INTERVAL:
4479 g_value_set_int64 (value, mux->min_index_interval);
4481 case PROP_STREAMABLE:
4482 g_value_set_boolean (value, mux->ebml_write->streamable);
4484 case PROP_TIMECODESCALE:
4485 g_value_set_int64 (value, mux->time_scale);
4487 case PROP_MIN_CLUSTER_DURATION:
4488 g_value_set_int64 (value, mux->min_cluster_duration);
4490 case PROP_MAX_CLUSTER_DURATION:
4491 g_value_set_int64 (value, mux->max_cluster_duration);
4493 case PROP_OFFSET_TO_ZERO:
4494 g_value_set_boolean (value, mux->offset_to_zero);
4496 case PROP_CREATION_TIME:
4497 g_value_set_boxed (value, mux->creation_time);
4499 case PROP_CLUSTER_TIMESTAMP_OFFSET:
4500 g_value_set_uint64 (value, mux->cluster_timestamp_offset);
4503 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);