1 /* GStreamer Matroska muxer/demuxer
2 * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3 * (c) 2005 Michal Benes <michal.benes@xeris.cz>
4 * (c) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * (c) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
7 * matroska-mux.c: matroska file/stream muxer
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
25 /* TODO: - check everywhere that we don't write invalid values
26 * - make sure timestamps are correctly scaled everywhere
30 * SECTION:element-matroskamux
33 * matroskamux muxes different input streams into a Matroska file.
35 * ## Example launch line
37 * gst-launch-1.0 -v filesrc location=/path/to/mp3 ! mpegaudioparse ! matroskamux name=mux ! filesink location=test.mkv filesrc location=/path/to/theora.ogg ! oggdemux ! theoraparse ! mux.
38 * ]| This pipeline muxes an MP3 file and a Ogg Theora video into a Matroska file.
40 * gst-launch-1.0 -v audiotestsrc num-buffers=100 ! audioconvert ! vorbisenc ! matroskamux ! filesink location=test.mka
41 * ]| This pipeline muxes a 440Hz sine wave encoded with the Vorbis codec into a Matroska file.
53 #include <gst/audio/audio.h>
54 #include <gst/riff/riff-media.h>
55 #include <gst/tag/tag.h>
56 #include <gst/pbutils/codec-utils.h>
58 #include "gstmatroskaelements.h"
59 #include "matroska-mux.h"
60 #include "matroska-ids.h"
62 #define GST_MATROSKA_MUX_CHAPLANG "und"
64 GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
65 #define GST_CAT_DEFAULT matroskamux_debug
72 PROP_MIN_INDEX_INTERVAL,
75 PROP_MIN_CLUSTER_DURATION,
76 PROP_MAX_CLUSTER_DURATION,
79 PROP_CLUSTER_TIMESTAMP_OFFSET,
82 #define DEFAULT_DOCTYPE_VERSION 2
83 #define DEFAULT_WRITING_APP "GStreamer Matroska muxer"
84 #define DEFAULT_MIN_INDEX_INTERVAL 0
85 #define DEFAULT_STREAMABLE FALSE
86 #define DEFAULT_TIMECODESCALE GST_MSECOND
87 #define DEFAULT_MIN_CLUSTER_DURATION 500 * GST_MSECOND
88 #define DEFAULT_MAX_CLUSTER_DURATION 65535 * GST_MSECOND
89 #define DEFAULT_OFFSET_TO_ZERO FALSE
90 #define DEFAULT_CLUSTER_TIMESTAMP_OFFSET 0
92 /* WAVEFORMATEX is gst_riff_strf_auds + an extra guint16 extension size */
93 #define WAVEFORMATEX_SIZE (2 + sizeof (gst_riff_strf_auds))
95 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
98 GST_STATIC_CAPS ("video/x-matroska; video/x-matroska-3d; audio/x-matroska")
101 #define COMMON_VIDEO_CAPS \
102 "width = (int) [ 1, MAX ], " \
103 "height = (int) [ 1, MAX ] "
106 * * require codec data, etc as needed
109 static GstStaticPadTemplate videosink_templ =
110 GST_STATIC_PAD_TEMPLATE ("video_%u",
113 GST_STATIC_CAPS ("video/mpeg, "
114 "mpegversion = (int) { 1, 2, 4 }, "
115 "systemstream = (boolean) false, "
116 COMMON_VIDEO_CAPS "; "
117 "video/x-h264, stream-format = (string) { avc, avc3 }, alignment=au, "
118 COMMON_VIDEO_CAPS "; "
119 "video/x-h265, stream-format = (string) { hvc1, hev1 }, alignment=au, "
120 COMMON_VIDEO_CAPS "; "
122 COMMON_VIDEO_CAPS "; "
124 COMMON_VIDEO_CAPS "; "
126 COMMON_VIDEO_CAPS "; "
128 COMMON_VIDEO_CAPS "; "
130 COMMON_VIDEO_CAPS "; "
132 COMMON_VIDEO_CAPS "; "
135 COMMON_VIDEO_CAPS "; "
136 "video/x-pn-realvideo, "
137 "rmversion = (int) [1, 4], "
138 COMMON_VIDEO_CAPS "; "
140 COMMON_VIDEO_CAPS "; "
142 COMMON_VIDEO_CAPS "; "
144 "format = (string) { YUY2, I420, YV12, UYVY, AYUV, GRAY8, BGR, RGB }, "
145 COMMON_VIDEO_CAPS "; "
147 COMMON_VIDEO_CAPS "; "
148 "video/x-wmv, " "wmvversion = (int) [ 1, 3 ], " COMMON_VIDEO_CAPS "; "
149 "video/x-av1, " COMMON_VIDEO_CAPS ";"
150 "video/x-ffv, ffversion = (int) 1, " COMMON_VIDEO_CAPS)
153 #define COMMON_AUDIO_CAPS \
154 "channels = (int) [ 1, MAX ], " \
155 "rate = (int) [ 1, MAX ]"
158 * * require codec data, etc as needed
160 static GstStaticPadTemplate audiosink_templ =
161 GST_STATIC_PAD_TEMPLATE ("audio_%u",
164 GST_STATIC_CAPS ("audio/mpeg, "
165 "mpegversion = (int) 1, "
166 "layer = (int) [ 1, 3 ], "
167 COMMON_AUDIO_CAPS "; "
169 "mpegversion = (int) { 2, 4 }, "
170 "stream-format = (string) raw, "
171 COMMON_AUDIO_CAPS "; "
173 COMMON_AUDIO_CAPS "; "
175 COMMON_AUDIO_CAPS "; "
177 COMMON_AUDIO_CAPS "; "
179 COMMON_AUDIO_CAPS "; "
181 COMMON_AUDIO_CAPS "; "
184 COMMON_AUDIO_CAPS "; "
186 "format = (string) { U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }, "
187 "layout = (string) interleaved, "
188 COMMON_AUDIO_CAPS ";"
190 "width = (int) { 8, 16, 24 }, "
191 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
192 "audio/x-pn-realaudio, "
193 "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS "; "
194 "audio/x-wma, " "wmaversion = (int) [ 1, 3 ], "
195 "block_align = (int) [ 0, 65535 ], bitrate = (int) [ 0, 524288 ], "
196 COMMON_AUDIO_CAPS ";"
198 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
200 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
202 "layout = (string)dvi, "
203 "block_align = (int)[64, 8192], "
204 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
206 "channels = (int)1," "rate = (int)16000; "
208 "layout = (string)g726, " "channels = (int)1," "rate = (int)8000; ")
211 static GstStaticPadTemplate subtitlesink_templ =
212 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
215 GST_STATIC_CAPS ("subtitle/x-kate; "
216 "text/x-raw, format=utf8; application/x-ssa; application/x-ass; "
217 "application/x-usf; subpicture/x-dvd; "
218 "application/x-subtitle-unknown")
221 static gpointer parent_class; /* NULL */
223 /* Matroska muxer destructor */
224 static void gst_matroska_mux_class_init (GstMatroskaMuxClass * klass);
225 static void gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class);
226 static void gst_matroska_mux_finalize (GObject * object);
228 /* Pads collected callback */
229 static GstFlowReturn gst_matroska_mux_handle_buffer (GstCollectPads * pads,
230 GstCollectData * data, GstBuffer * buf, gpointer user_data);
231 static gboolean gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
232 GstCollectData * data, GstEvent * event, gpointer user_data);
235 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
236 GstObject * parent, GstEvent * event);
237 static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
238 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
239 static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
241 /* gst internal change state handler */
242 static GstStateChangeReturn
243 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
245 /* gobject bla bla */
246 static void gst_matroska_mux_set_property (GObject * object,
247 guint prop_id, const GValue * value, GParamSpec * pspec);
248 static void gst_matroska_mux_get_property (GObject * object,
249 guint prop_id, GValue * value, GParamSpec * pspec);
252 static void gst_matroska_mux_reset (GstElement * element);
255 static guint64 gst_matroska_mux_create_uid (GstMatroskaMux * mux);
257 static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
258 GstMatroskaTrackContext * context);
259 static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
260 GstMatroskaTrackContext * context);
261 static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
262 GstMatroskaTrackContext * context);
263 static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
264 GstMatroskaTrackContext * context);
265 static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
266 GstMatroskaTrackContext * context);
268 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
270 static gboolean gst_matroska_mux_tag_list_is_empty (const GstTagList * list);
271 static void gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux);
272 static gboolean gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux);
274 /* Cannot use boilerplate macros here because we need the full init function
275 * signature with the additional class argument, so we use the right template
276 * for the sink caps */
278 gst_matroska_mux_get_type (void)
280 static GType object_type; /* 0 */
282 if (object_type == 0) {
283 static const GTypeInfo object_info = {
284 sizeof (GstMatroskaMuxClass),
285 NULL, /* base_init */
286 NULL, /* base_finalize */
287 (GClassInitFunc) gst_matroska_mux_class_init,
288 NULL, /* class_finalize */
289 NULL, /* class_data */
290 sizeof (GstMatroskaMux),
292 (GInstanceInitFunc) gst_matroska_mux_init
294 const GInterfaceInfo iface_info = { NULL };
296 object_type = g_type_register_static (GST_TYPE_ELEMENT,
297 "GstMatroskaMux", &object_info, (GTypeFlags) 0);
299 g_type_add_interface_static (object_type, GST_TYPE_TAG_SETTER, &iface_info);
300 g_type_add_interface_static (object_type, GST_TYPE_TOC_SETTER, &iface_info);
306 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (matroskamux, "matroskamux",
307 GST_RANK_PRIMARY, GST_TYPE_MATROSKA_MUX, matroska_element_init (plugin));
310 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
312 GObjectClass *gobject_class;
313 GstElementClass *gstelement_class;
315 gobject_class = (GObjectClass *) klass;
316 gstelement_class = (GstElementClass *) klass;
318 gst_element_class_add_static_pad_template (gstelement_class,
320 gst_element_class_add_static_pad_template (gstelement_class,
322 gst_element_class_add_static_pad_template (gstelement_class,
323 &subtitlesink_templ);
324 gst_element_class_add_static_pad_template (gstelement_class, &src_templ);
325 gst_element_class_set_static_metadata (gstelement_class, "Matroska muxer",
327 "Muxes video/audio/subtitle streams into a matroska stream",
328 "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
330 GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
333 gobject_class->finalize = gst_matroska_mux_finalize;
335 gobject_class->get_property = gst_matroska_mux_get_property;
336 gobject_class->set_property = gst_matroska_mux_set_property;
338 g_object_class_install_property (gobject_class, PROP_WRITING_APP,
339 g_param_spec_string ("writing-app", "Writing application.",
340 "The name the application that creates the matroska file.",
341 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
342 g_object_class_install_property (gobject_class, PROP_DOCTYPE_VERSION,
343 g_param_spec_int ("version", "DocType version",
344 "This parameter determines what Matroska features can be used.",
345 1, 2, DEFAULT_DOCTYPE_VERSION,
346 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
347 g_object_class_install_property (gobject_class, PROP_MIN_INDEX_INTERVAL,
348 g_param_spec_int64 ("min-index-interval", "Minimum time between index "
349 "entries", "An index entry is created every so many nanoseconds.",
350 0, G_MAXINT64, DEFAULT_MIN_INDEX_INTERVAL,
351 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
352 g_object_class_install_property (gobject_class, PROP_STREAMABLE,
353 g_param_spec_boolean ("streamable", "Determines whether output should "
354 "be streamable", "If set to true, the output should be as if it is "
355 "to be streamed and hence no indexes written or duration written.",
356 DEFAULT_STREAMABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
357 g_object_class_install_property (gobject_class, PROP_TIMECODESCALE,
358 g_param_spec_int64 ("timecodescale", "Timecode Scale",
359 "TimecodeScale used to calculate the Raw Timecode of a Block", 1,
360 GST_SECOND, DEFAULT_TIMECODESCALE,
361 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
362 g_object_class_install_property (gobject_class, PROP_MIN_CLUSTER_DURATION,
363 g_param_spec_int64 ("min-cluster-duration", "Minimum cluster duration",
364 "Desired cluster duration as nanoseconds. A new cluster will be "
365 "created irrespective of this property if a force key unit event "
366 "is received. 0 means create a new cluster for each video keyframe "
367 "or for each audio buffer in audio only streams.", 0,
368 G_MAXINT64, DEFAULT_MIN_CLUSTER_DURATION,
369 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
370 g_object_class_install_property (gobject_class, PROP_MAX_CLUSTER_DURATION,
371 g_param_spec_int64 ("max-cluster-duration", "Maximum cluster duration",
372 "A new cluster will be created if its duration exceeds this value. "
373 "0 means no maximum duration.", 0,
374 G_MAXINT64, DEFAULT_MAX_CLUSTER_DURATION,
375 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
376 g_object_class_install_property (gobject_class, PROP_OFFSET_TO_ZERO,
377 g_param_spec_boolean ("offset-to-zero", "Offset To Zero",
378 "Offsets all streams so that the " "earliest stream starts at 0.",
379 DEFAULT_OFFSET_TO_ZERO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
380 g_object_class_install_property (gobject_class, PROP_CREATION_TIME,
381 g_param_spec_boxed ("creation-time", "Creation Time",
382 "Date and time of creation. This will be used for the DateUTC field."
383 " NULL means that the current time will be used.",
384 G_TYPE_DATE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
387 * GstMatroskaMux:cluster-timestamp-offset:
389 * An offset to add to all clusters/blocks (in nanoseconds)
393 g_object_class_install_property (gobject_class, PROP_CLUSTER_TIMESTAMP_OFFSET,
394 g_param_spec_uint64 ("cluster-timestamp-offset",
395 "Cluster timestamp offset",
396 "An offset to add to all clusters/blocks (in nanoseconds)", 0,
397 G_MAXUINT64, DEFAULT_CLUSTER_TIMESTAMP_OFFSET,
398 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
400 gstelement_class->change_state =
401 GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
402 gstelement_class->request_new_pad =
403 GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
404 gstelement_class->release_pad =
405 GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
407 parent_class = g_type_class_peek_parent (klass);
411 * Start of pad option handler code
413 #define DEFAULT_PAD_FRAME_DURATION TRUE
418 PROP_PAD_FRAME_DURATION
424 gboolean frame_duration;
425 gboolean frame_duration_user;
428 typedef GstPadClass GstMatroskamuxPadClass;
430 GType gst_matroskamux_pad_get_type (void);
431 G_DEFINE_TYPE (GstMatroskamuxPad, gst_matroskamux_pad, GST_TYPE_PAD);
433 #define GST_TYPE_MATROSKAMUX_PAD (gst_matroskamux_pad_get_type())
434 #define GST_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_MATROSKAMUX_PAD,GstMatroskamuxPad))
435 #define GST_MATROSKAMUX_PAD_CAST(pad) ((GstMatroskamuxPad *) pad)
436 #define GST_IS_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_MATROSKAMUX_PAD))
439 gst_matroskamux_pad_get_property (GObject * object, guint prop_id,
440 GValue * value, GParamSpec * pspec)
442 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
445 case PROP_PAD_FRAME_DURATION:
446 g_value_set_boolean (value, pad->frame_duration);
449 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
455 gst_matroskamux_pad_set_property (GObject * object, guint prop_id,
456 const GValue * value, GParamSpec * pspec)
458 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
461 case PROP_PAD_FRAME_DURATION:
462 pad->frame_duration = g_value_get_boolean (value);
463 pad->frame_duration_user = TRUE;
466 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
472 gst_matroskamux_pad_class_init (GstMatroskamuxPadClass * klass)
474 GObjectClass *gobject_class = (GObjectClass *) klass;
476 gobject_class->set_property = gst_matroskamux_pad_set_property;
477 gobject_class->get_property = gst_matroskamux_pad_get_property;
479 g_object_class_install_property (gobject_class, PROP_PAD_FRAME_DURATION,
480 g_param_spec_boolean ("frame-duration", "Frame duration",
481 "Default frame duration", DEFAULT_PAD_FRAME_DURATION,
482 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
486 gst_matroskamux_pad_init (GstMatroskamuxPad * pad)
488 pad->frame_duration = DEFAULT_PAD_FRAME_DURATION;
489 pad->frame_duration_user = FALSE;
493 * End of pad option handler code
497 gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class)
499 GstPadTemplate *templ;
502 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
503 mux->srcpad = gst_pad_new_from_template (templ, "src");
505 gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
506 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
507 gst_pad_use_fixed_caps (mux->srcpad);
509 mux->collect = gst_collect_pads_new ();
510 gst_collect_pads_set_clip_function (mux->collect,
511 GST_DEBUG_FUNCPTR (gst_collect_pads_clip_running_time), mux);
512 gst_collect_pads_set_buffer_function (mux->collect,
513 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_buffer), mux);
514 gst_collect_pads_set_event_function (mux->collect,
515 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event), mux);
517 mux->ebml_write = gst_ebml_write_new (mux->srcpad);
518 mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
520 /* property defaults */
521 mux->doctype_version = DEFAULT_DOCTYPE_VERSION;
522 mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
523 mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
524 mux->ebml_write->streamable = DEFAULT_STREAMABLE;
525 mux->time_scale = DEFAULT_TIMECODESCALE;
526 mux->min_cluster_duration = DEFAULT_MIN_CLUSTER_DURATION;
527 mux->max_cluster_duration = DEFAULT_MAX_CLUSTER_DURATION;
528 mux->cluster_timestamp_offset = DEFAULT_CLUSTER_TIMESTAMP_OFFSET;
530 /* initialize internal variables */
532 mux->num_streams = 0;
533 mux->num_a_streams = 0;
534 mux->num_t_streams = 0;
535 mux->num_v_streams = 0;
536 mux->internal_toc = NULL;
538 /* initialize remaining variables */
539 gst_matroska_mux_reset (GST_ELEMENT (mux));
544 * gst_matroska_mux_finalize:
545 * @object: #GstMatroskaMux that should be finalized.
547 * Finalize matroska muxer.
550 gst_matroska_mux_finalize (GObject * object)
552 GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
554 gst_event_replace (&mux->force_key_unit_event, NULL);
556 gst_object_unref (mux->collect);
557 gst_object_unref (mux->ebml_write);
558 g_free (mux->writing_app);
559 g_clear_pointer (&mux->creation_time, g_date_time_unref);
561 if (mux->internal_toc) {
562 gst_toc_unref (mux->internal_toc);
563 mux->internal_toc = NULL;
566 G_OBJECT_CLASS (parent_class)->finalize (object);
571 * gst_matroska_mux_create_uid:
572 * @mux: #GstMatroskaMux to generate UID for.
574 * Generate new track UID.
576 * Returns: New track UID.
579 gst_matroska_mux_create_uid (GstMatroskaMux * mux)
581 return (((guint64) g_random_int ()) << 32) | g_random_int ();
586 * gst_matroska_pad_reset:
587 * @collect_pad: the #GstMatroskaPad
589 * Reset and/or release resources of a matroska collect pad.
592 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
595 GstMatroskaTrackType type = 0;
597 /* free track information */
598 if (collect_pad->track != NULL) {
599 /* retrieve for optional later use */
600 name = collect_pad->track->name;
601 type = collect_pad->track->type;
602 /* extra for video */
603 if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
604 GstMatroskaTrackVideoContext *ctx =
605 (GstMatroskaTrackVideoContext *) collect_pad->track;
607 if (ctx->dirac_unit) {
608 gst_buffer_unref (ctx->dirac_unit);
609 ctx->dirac_unit = NULL;
612 g_free (collect_pad->track->codec_id);
613 g_free (collect_pad->track->codec_name);
615 g_free (collect_pad->track->name);
616 g_free (collect_pad->track->language);
617 g_free (collect_pad->track->codec_priv);
618 g_free (collect_pad->track);
619 collect_pad->track = NULL;
620 if (collect_pad->tags) {
621 gst_tag_list_unref (collect_pad->tags);
622 collect_pad->tags = NULL;
626 if (!full && type != 0) {
627 GstMatroskaTrackContext *context;
629 /* create a fresh context */
631 case GST_MATROSKA_TRACK_TYPE_VIDEO:
632 context = (GstMatroskaTrackContext *)
633 g_new0 (GstMatroskaTrackVideoContext, 1);
635 case GST_MATROSKA_TRACK_TYPE_AUDIO:
636 context = (GstMatroskaTrackContext *)
637 g_new0 (GstMatroskaTrackAudioContext, 1);
639 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
640 context = (GstMatroskaTrackContext *)
641 g_new0 (GstMatroskaTrackSubtitleContext, 1);
644 g_assert_not_reached ();
648 context->type = type;
649 context->name = name;
650 context->uid = gst_matroska_mux_create_uid (collect_pad->mux);
651 /* TODO: check default values for the context */
652 context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
653 collect_pad->track = context;
654 collect_pad->start_ts = GST_CLOCK_TIME_NONE;
655 collect_pad->end_ts = GST_CLOCK_TIME_NONE;
656 collect_pad->tags = gst_tag_list_new_empty ();
657 gst_tag_list_set_scope (collect_pad->tags, GST_TAG_SCOPE_STREAM);
662 * gst_matroska_pad_free:
663 * @collect_pad: the #GstMatroskaPad
665 * Release resources of a matroska collect pad.
668 gst_matroska_pad_free (GstPad * collect_pad)
670 gst_matroska_pad_reset ((GstMatroskaPad *) collect_pad, TRUE);
675 * gst_matroska_mux_reset:
676 * @element: #GstMatroskaMux that should be reset.
678 * Reset matroska muxer back to initial state.
681 gst_matroska_mux_reset (GstElement * element)
683 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
686 /* reset EBML write */
687 gst_ebml_write_reset (mux->ebml_write);
690 mux->state = GST_MATROSKA_MUX_STATE_START;
692 /* clean up existing streams */
694 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
695 GstMatroskaPad *collect_pad;
697 collect_pad = (GstMatroskaPad *) walk->data;
699 /* reset collect pad to pristine state */
700 gst_matroska_pad_reset (collect_pad, FALSE);
704 mux->num_indexes = 0;
713 mux->cluster_time = 0;
714 mux->cluster_pos = 0;
715 mux->prev_cluster_size = 0;
718 gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
723 gst_toc_setter_reset (GST_TOC_SETTER (mux));
724 if (mux->internal_toc) {
725 gst_toc_unref (mux->internal_toc);
726 mux->internal_toc = NULL;
729 mux->chapters_pos = 0;
733 * gst_matroska_mux_handle_src_event:
734 * @pad: Pad which received the event.
735 * @event: Received event.
737 * handle events - copied from oggmux without understanding
739 * Returns: %TRUE on success.
742 gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
747 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
751 /* disable seeking for now */
757 return gst_pad_event_default (pad, parent, event);
762 gst_matroska_mux_free_codec_priv (GstMatroskaTrackContext * context)
764 if (context->codec_priv != NULL) {
765 g_free (context->codec_priv);
766 context->codec_priv = NULL;
767 context->codec_priv_size = 0;
772 gst_matroska_mux_build_vobsub_private (GstMatroskaTrackContext * context,
782 /* produce comma-separated list in hex format */
783 for (i = 0; i < 16; ++i) {
785 /* replicate vobsub's slightly off RGB conversion calculation */
786 y = (((col >> 16) & 0xff) - 16) * 255 / 219;
787 u = ((col >> 8) & 0xff) - 128;
788 v = (col & 0xff) - 128;
789 r = CLAMP (1.0 * y + 1.4022 * u, 0, 255);
790 g = CLAMP (1.0 * y - 0.3456 * u - 0.7145 * v, 0, 255);
791 b = CLAMP (1.0 * y + 1.7710 * v, 0, 255);
792 clutv[i] = g_strdup_printf ("%02x%02x%02x", r, g, b);
795 sclut = g_strjoinv (",", clutv);
797 /* build codec private; only palette for now */
798 gst_matroska_mux_free_codec_priv (context);
799 context->codec_priv = (guint8 *) g_strdup_printf ("palette: %s", sclut);
800 /* include terminating 0 */
801 context->codec_priv_size = strlen ((gchar *) context->codec_priv) + 1;
803 for (i = 0; i < 16; ++i) {
810 * gst_matroska_mux_handle_sink_event:
811 * @pad: Pad which received the event.
812 * @event: Received event.
814 * handle events - informational ones like tags
816 * Returns: %TRUE on success.
819 gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
820 GstCollectData * data, GstEvent * event, gpointer user_data)
822 GstMatroskaPad *collect_pad;
823 GstMatroskaTrackContext *context;
829 mux = GST_MATROSKA_MUX (user_data);
830 collect_pad = (GstMatroskaPad *) data;
832 context = collect_pad->track;
835 switch (GST_EVENT_TYPE (event)) {
836 case GST_EVENT_CAPS:{
839 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
840 gst_event_parse_caps (event, &caps);
842 ret = collect_pad->capsfunc (pad, caps);
843 gst_event_unref (event);
850 GST_DEBUG_OBJECT (mux, "received tag event");
851 gst_event_parse_tag (event, &list);
853 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
854 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
855 const gchar *lang_code;
857 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
859 GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
860 g_free (context->language);
861 context->language = g_strdup (lang_code);
863 GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
868 /* FIXME: what about stream-specific tags? */
869 if (gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL) {
870 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
871 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
873 gst_tag_list_insert (collect_pad->tags, list, GST_TAG_MERGE_REPLACE);
876 gst_event_unref (event);
877 /* handled this, don't want collectpads to forward it downstream */
883 GstToc *toc, *old_toc;
885 if (mux->chapters_pos > 0)
888 GST_DEBUG_OBJECT (mux, "received toc event");
889 gst_event_parse_toc (event, &toc, NULL);
892 old_toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
893 if (old_toc != NULL) {
895 GST_INFO_OBJECT (pad, "Replacing TOC with a new one");
896 gst_toc_unref (old_toc);
899 gst_toc_setter_set_toc (GST_TOC_SETTER (mux), toc);
903 gst_event_unref (event);
904 /* handled this, don't want collectpads to forward it downstream */
908 case GST_EVENT_CUSTOM_DOWNSTREAM:
909 case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY:{
910 const GstStructure *structure;
912 structure = gst_event_get_structure (event);
913 if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
914 gst_event_replace (&mux->force_key_unit_event, NULL);
915 mux->force_key_unit_event = event;
917 } else if (gst_structure_has_name (structure, "application/x-gst-dvd") &&
918 !strcmp ("dvd-spu-clut-change",
919 gst_structure_get_string (structure, "event"))) {
924 GST_DEBUG_OBJECT (pad, "New DVD colour table received");
925 if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
926 GST_DEBUG_OBJECT (pad, "... discarding");
929 /* first transform event data into table form */
930 for (i = 0; i < 16; i++) {
931 g_snprintf (name, sizeof (name), "clut%02d", i);
932 if (!gst_structure_get_int (structure, name, &value)) {
933 GST_ERROR_OBJECT (mux, "dvd-spu-clut-change event did not "
934 "contain %s field", name);
940 /* transform into private data for stream; text form */
941 gst_matroska_mux_build_vobsub_private (context, clut);
951 return gst_collect_pads_event_default (pads, data, event, FALSE);
957 gst_matroska_mux_set_codec_id (GstMatroskaTrackContext * context,
960 g_assert (context && id);
961 g_free (context->codec_id);
962 context->codec_id = g_strdup (id);
966 check_field (GQuark field_id, const GValue * value, gpointer user_data)
968 GstStructure *structure = (GstStructure *) user_data;
969 const gchar *name = gst_structure_get_name (structure);
971 if ((g_strcmp0 (name, "video/x-h264") == 0 &&
972 !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
973 "avc3")) || (g_strcmp0 (name, "video/x-h265") == 0
974 && !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
977 /* While in theory, matroska only supports avc1 / hvc1, and doesn't support codec_data
978 * changes, in practice most decoders will use in-band SPS / PPS (avc3 / hev1), if the
979 * input stream is avc3 / hev1 we let the new codec_data slide to support "smart" encoding.
981 * We don't warn here as we already warned elsewhere.
983 if (field_id == g_quark_from_static_string ("codec_data")) {
985 } else if (field_id == g_quark_from_static_string ("tier")) {
987 } else if (field_id == g_quark_from_static_string ("profile")) {
989 } else if (field_id == g_quark_from_static_string ("level")) {
998 check_new_caps (GstCaps * old_caps, GstCaps * new_caps)
1000 GstStructure *old_s, *new_s;
1003 old_caps = gst_caps_copy (old_caps);
1004 new_caps = gst_caps_copy (new_caps);
1006 new_s = gst_caps_get_structure (new_caps, 0);
1007 old_s = gst_caps_get_structure (old_caps, 0);
1009 gst_structure_filter_and_map_in_place (new_s,
1010 (GstStructureFilterMapFunc) check_field, new_s);
1011 gst_structure_filter_and_map_in_place (old_s,
1012 (GstStructureFilterMapFunc) check_field, old_s);
1014 ret = gst_caps_is_subset (new_caps, old_caps);
1016 gst_caps_unref (new_caps);
1017 gst_caps_unref (old_caps);
1023 * gst_matroska_mux_video_pad_setcaps:
1024 * @pad: Pad which got the caps.
1027 * Setcaps function for video sink pad.
1029 * Returns: %TRUE on success.
1032 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
1034 GstMatroskaTrackContext *context = NULL;
1035 GstMatroskaTrackVideoContext *videocontext;
1036 GstMatroskaMux *mux;
1037 GstMatroskaPad *collect_pad;
1038 GstStructure *structure;
1039 const gchar *mimetype;
1040 const gchar *interlace_mode, *s;
1041 const GValue *value = NULL;
1042 GstBuffer *codec_buf = NULL;
1043 gint width, height, pixel_width, pixel_height;
1045 guint multiview_flags;
1048 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1050 if ((old_caps = gst_pad_get_current_caps (pad))) {
1051 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1052 && !check_new_caps (old_caps, caps)) {
1053 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1054 ("Caps changes are not supported by Matroska\nCurrent: `%"
1055 GST_PTR_FORMAT "`\nNew: `%" GST_PTR_FORMAT "`", old_caps, caps));
1056 gst_caps_unref (old_caps);
1059 gst_caps_unref (old_caps);
1060 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
1061 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1062 ("Caps on pad %" GST_PTR_FORMAT
1063 " arrived late. Headers were already written", pad));
1068 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1069 g_assert (collect_pad);
1070 context = collect_pad->track;
1072 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
1073 videocontext = (GstMatroskaTrackVideoContext *) context;
1075 /* gst -> matroska ID'ing */
1076 structure = gst_caps_get_structure (caps, 0);
1078 mimetype = gst_structure_get_name (structure);
1080 interlace_mode = gst_structure_get_string (structure, "interlace-mode");
1081 if (interlace_mode != NULL) {
1082 if (strcmp (interlace_mode, "progressive") == 0)
1083 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE;
1085 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_INTERLACED;
1087 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_UNKNOWN;
1090 if (!strcmp (mimetype, "video/x-theora")) {
1091 /* we'll extract the details later from the theora identification header */
1095 /* get general properties */
1096 /* spec says it is mandatory */
1097 if (!gst_structure_get_int (structure, "width", &width) ||
1098 !gst_structure_get_int (structure, "height", &height))
1101 videocontext->pixel_width = width;
1102 videocontext->pixel_height = height;
1104 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
1105 && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
1107 context->default_duration =
1108 gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
1109 GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
1110 GST_TIME_ARGS (context->default_duration));
1112 context->default_duration = 0;
1114 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
1115 &pixel_width, &pixel_height)) {
1116 if (pixel_width > pixel_height) {
1117 videocontext->display_width = width * pixel_width / pixel_height;
1118 videocontext->display_height = height;
1119 } else if (pixel_width < pixel_height) {
1120 videocontext->display_width = width;
1121 videocontext->display_height = height * pixel_height / pixel_width;
1123 videocontext->display_width = 0;
1124 videocontext->display_height = 0;
1127 videocontext->display_width = 0;
1128 videocontext->display_height = 0;
1131 if ((s = gst_structure_get_string (structure, "colorimetry"))) {
1132 if (!gst_video_colorimetry_from_string (&videocontext->colorimetry, s)) {
1133 GST_WARNING_OBJECT (pad, "Could not parse colorimetry %s", s);
1137 if ((s = gst_structure_get_string (structure, "mastering-display-info"))) {
1138 if (!gst_video_mastering_display_info_from_string
1139 (&videocontext->mastering_display_info, s)) {
1140 GST_WARNING_OBJECT (pad, "Could not parse mastering-display-metadata %s",
1143 videocontext->mastering_display_info_present = TRUE;
1147 if ((s = gst_structure_get_string (structure, "content-light-level"))) {
1148 if (!gst_video_content_light_level_from_string
1149 (&videocontext->content_light_level, s))
1150 GST_WARNING_OBJECT (pad, "Could not parse content-light-level %s", s);
1153 /* Collect stereoscopic info, if any */
1154 if ((s = gst_structure_get_string (structure, "multiview-mode")))
1155 videocontext->multiview_mode =
1156 gst_video_multiview_mode_from_caps_string (s);
1157 gst_structure_get_flagset (structure, "multiview-flags", &multiview_flags,
1159 videocontext->multiview_flags = multiview_flags;
1164 videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
1165 videocontext->fourcc = 0;
1167 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1168 * data and other settings
1172 /* extract codec_data, may turn out needed */
1173 value = gst_structure_get_value (structure, "codec_data");
1175 codec_buf = (GstBuffer *) gst_value_get_buffer (value);
1178 if (!strcmp (mimetype, "video/x-raw")) {
1180 gst_matroska_mux_set_codec_id (context,
1181 GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
1182 fstr = gst_structure_get_string (structure, "format");
1184 if (strlen (fstr) == 4)
1185 videocontext->fourcc = GST_STR_FOURCC (fstr);
1186 else if (!strcmp (fstr, "GRAY8"))
1187 videocontext->fourcc = GST_MAKE_FOURCC ('Y', '8', '0', '0');
1188 else if (!strcmp (fstr, "BGR"))
1189 videocontext->fourcc = GST_MAKE_FOURCC ('B', 'G', 'R', 24);
1190 else if (!strcmp (fstr, "RGB"))
1191 videocontext->fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', 24);
1193 } else if (!strcmp (mimetype, "video/x-huffyuv") /* MS/VfW compatibility cases */
1194 ||!strcmp (mimetype, "video/x-divx")
1195 || !strcmp (mimetype, "video/x-dv")
1196 || !strcmp (mimetype, "video/x-h263")
1197 || !strcmp (mimetype, "video/x-msmpeg")
1198 || !strcmp (mimetype, "video/x-wmv")
1199 || !strcmp (mimetype, "image/jpeg")) {
1200 gst_riff_strf_vids *bih;
1201 gint size = sizeof (gst_riff_strf_vids);
1204 if (!strcmp (mimetype, "video/x-huffyuv"))
1205 fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
1206 else if (!strcmp (mimetype, "video/x-dv"))
1207 fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
1208 else if (!strcmp (mimetype, "video/x-h263"))
1209 fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
1210 else if (!strcmp (mimetype, "video/x-divx")) {
1213 gst_structure_get_int (structure, "divxversion", &divxversion);
1214 switch (divxversion) {
1216 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
1219 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
1222 fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
1225 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1228 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
1229 switch (msmpegversion) {
1231 fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
1234 fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
1240 } else if (!strcmp (mimetype, "video/x-wmv")) {
1244 fstr = gst_structure_get_string (structure, "format");
1245 if (fstr && strlen (fstr) == 4) {
1246 fourcc = GST_STR_FOURCC (fstr);
1247 } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
1248 if (wmvversion == 2) {
1249 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
1250 } else if (wmvversion == 1) {
1251 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
1252 } else if (wmvversion == 3) {
1253 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
1256 } else if (!strcmp (mimetype, "image/jpeg")) {
1257 fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
1263 bih = g_new0 (gst_riff_strf_vids, 1);
1264 GST_WRITE_UINT32_LE (&bih->size, size);
1265 GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
1266 GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
1267 GST_WRITE_UINT32_LE (&bih->compression, fourcc);
1268 GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
1269 GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
1270 GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
1271 videocontext->pixel_height * 3);
1273 /* process codec private/initialization data, if any */
1275 size += gst_buffer_get_size (codec_buf);
1276 bih = g_realloc (bih, size);
1277 GST_WRITE_UINT32_LE (&bih->size, size);
1278 gst_buffer_extract (codec_buf, 0,
1279 (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
1282 gst_matroska_mux_set_codec_id (context,
1283 GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
1284 gst_matroska_mux_free_codec_priv (context);
1285 context->codec_priv = (gpointer) bih;
1286 context->codec_priv_size = size;
1287 context->dts_only = TRUE;
1288 } else if (!strcmp (mimetype, "video/x-h264")) {
1289 gst_matroska_mux_set_codec_id (context,
1290 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
1291 gst_matroska_mux_free_codec_priv (context);
1293 if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1295 GST_WARNING_OBJECT (mux,
1296 "avc3 is not officially supported, only use this format for smart encoding");
1299 /* Create avcC header */
1300 if (codec_buf != NULL) {
1301 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1302 context->codec_priv = g_malloc0 (context->codec_priv_size);
1303 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1305 } else if (!strcmp (mimetype, "video/x-h265")) {
1306 gst_matroska_mux_set_codec_id (context,
1307 GST_MATROSKA_CODEC_ID_VIDEO_MPEGH_HEVC);
1308 gst_matroska_mux_free_codec_priv (context);
1310 if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1312 GST_WARNING_OBJECT (mux,
1313 "hev1 is not officially supported, only use this format for smart encoding");
1316 /* Create hvcC header */
1317 if (codec_buf != NULL) {
1318 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1319 context->codec_priv = g_malloc0 (context->codec_priv_size);
1320 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1322 } else if (!strcmp (mimetype, "video/x-theora")) {
1323 const GValue *streamheader;
1325 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
1327 gst_matroska_mux_free_codec_priv (context);
1329 streamheader = gst_structure_get_value (structure, "streamheader");
1330 if (!theora_streamheader_to_codecdata (streamheader, context)) {
1331 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1332 ("theora stream headers missing or malformed"));
1335 } else if (!strcmp (mimetype, "video/x-dirac")) {
1336 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
1337 } else if (!strcmp (mimetype, "video/x-vp8")) {
1338 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP8);
1339 } else if (!strcmp (mimetype, "video/x-vp9")) {
1340 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP9);
1341 } else if (!strcmp (mimetype, "video/x-av1")) {
1342 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_AV1);
1343 gst_matroska_mux_free_codec_priv (context);
1344 /* Create av1C header */
1345 if (codec_buf != NULL)
1346 gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1347 &context->codec_priv, &context->codec_priv_size);
1348 } else if (!strcmp (mimetype, "video/x-ffv")) {
1349 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_FFV1);
1350 gst_matroska_mux_free_codec_priv (context);
1351 if (codec_buf != NULL)
1352 gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1353 &context->codec_priv, &context->codec_priv_size);
1354 } else if (!strcmp (mimetype, "video/mpeg")) {
1357 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1358 switch (mpegversion) {
1360 gst_matroska_mux_set_codec_id (context,
1361 GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
1364 gst_matroska_mux_set_codec_id (context,
1365 GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
1368 gst_matroska_mux_set_codec_id (context,
1369 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
1375 /* global headers may be in codec data */
1376 if (codec_buf != NULL) {
1377 gst_matroska_mux_free_codec_priv (context);
1378 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1379 context->codec_priv = g_malloc0 (context->codec_priv_size);
1380 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1382 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1384 /* can only make it here if preceding case verified it was version 3 */
1385 gst_matroska_mux_set_codec_id (context,
1386 GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
1387 } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
1389 const GValue *mdpr_data;
1391 gst_structure_get_int (structure, "rmversion", &rmversion);
1392 switch (rmversion) {
1394 gst_matroska_mux_set_codec_id (context,
1395 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
1398 gst_matroska_mux_set_codec_id (context,
1399 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
1402 gst_matroska_mux_set_codec_id (context,
1403 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
1406 gst_matroska_mux_set_codec_id (context,
1407 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
1413 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1414 if (mdpr_data != NULL) {
1415 guint8 *priv_data = NULL;
1416 guint priv_data_size = 0;
1418 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1420 priv_data_size = gst_buffer_get_size (codec_data_buf);
1421 priv_data = g_malloc0 (priv_data_size);
1423 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1425 gst_matroska_mux_free_codec_priv (context);
1426 context->codec_priv = priv_data;
1427 context->codec_priv_size = priv_data_size;
1429 } else if (strcmp (mimetype, "video/x-prores") == 0) {
1430 const gchar *variant;
1432 gst_matroska_mux_free_codec_priv (context);
1434 variant = gst_structure_get_string (structure, "format");
1435 if (!variant || !g_strcmp0 (variant, "standard"))
1436 context->codec_priv = g_strdup ("apcn");
1437 else if (!g_strcmp0 (variant, "hq"))
1438 context->codec_priv = g_strdup ("apch");
1439 else if (!g_strcmp0 (variant, "lt"))
1440 context->codec_priv = g_strdup ("apcs");
1441 else if (!g_strcmp0 (variant, "proxy"))
1442 context->codec_priv = g_strdup ("apco");
1443 else if (!g_strcmp0 (variant, "4444"))
1444 context->codec_priv = g_strdup ("ap4h");
1446 GST_WARNING_OBJECT (mux, "Unhandled prores format: %s", variant);
1451 context->codec_priv_size = sizeof (guint32);
1452 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_PRORES);
1460 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1461 GST_PAD_NAME (pad), caps);
1466 /* N > 0 to expect a particular number of headers, negative if the
1467 number of headers is variable */
1469 xiphN_streamheader_to_codecdata (const GValue * streamheader,
1470 GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
1472 GstBuffer **buf = NULL;
1475 guint bufi, i, offset, priv_data_size;
1477 if (streamheader == NULL)
1478 goto no_stream_headers;
1480 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1483 bufarr = g_value_peek_pointer (streamheader);
1484 if (bufarr->len <= 0 || bufarr->len > 255) /* at least one header, and count stored in a byte */
1486 if (N > 0 && bufarr->len != N)
1489 context->xiph_headers_to_skip = bufarr->len;
1491 buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1492 for (i = 0; i < bufarr->len; i++) {
1493 GValue *bufval = &g_array_index (bufarr, GValue, i);
1495 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1497 goto wrong_content_type;
1500 buf[i] = g_value_peek_pointer (bufval);
1504 if (bufarr->len > 0) {
1505 for (i = 0; i < bufarr->len - 1; i++) {
1506 priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
1510 for (i = 0; i < bufarr->len; ++i) {
1511 priv_data_size += gst_buffer_get_size (buf[i]);
1514 priv_data = g_malloc0 (priv_data_size);
1516 priv_data[0] = bufarr->len - 1;
1519 if (bufarr->len > 0) {
1520 for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1521 for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
1522 priv_data[offset++] = 0xff;
1524 priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
1528 for (i = 0; i < bufarr->len; ++i) {
1529 gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
1530 offset += gst_buffer_get_size (buf[i]);
1533 gst_matroska_mux_free_codec_priv (context);
1534 context->codec_priv = priv_data;
1535 context->codec_priv_size = priv_data_size;
1538 *p_buf0 = gst_buffer_ref (buf[0]);
1547 GST_WARNING ("required streamheaders missing in sink caps!");
1552 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1553 G_VALUE_TYPE_NAME (streamheader));
1558 GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1563 GST_WARNING ("streamheaders array does not contain GstBuffers");
1569 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1570 GstMatroskaTrackContext * context)
1572 GstBuffer *buf0 = NULL;
1574 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1577 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
1578 GST_WARNING ("First vorbis header too small, ignoring");
1580 if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
1581 GstMatroskaTrackAudioContext *audiocontext;
1585 gst_buffer_map (buf0, &map, GST_MAP_READ);
1586 hdr = map.data + 1 + 6 + 4;
1587 audiocontext = (GstMatroskaTrackAudioContext *) context;
1588 audiocontext->channels = GST_READ_UINT8 (hdr);
1589 audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1590 gst_buffer_unmap (buf0, &map);
1595 gst_buffer_unref (buf0);
1601 theora_streamheader_to_codecdata (const GValue * streamheader,
1602 GstMatroskaTrackContext * context)
1604 GstBuffer *buf0 = NULL;
1606 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1609 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
1610 GST_WARNING ("First theora header too small, ignoring");
1611 } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
1612 GST_WARNING ("First header not a theora identification header, ignoring");
1614 GstMatroskaTrackVideoContext *videocontext;
1615 guint fps_num, fps_denom, par_num, par_denom;
1619 gst_buffer_map (buf0, &map, GST_MAP_READ);
1620 hdr = map.data + 1 + 6 + 3 + 2 + 2;
1622 videocontext = (GstMatroskaTrackVideoContext *) context;
1623 videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1624 videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1625 hdr += 3 + 3 + 1 + 1;
1626 fps_num = GST_READ_UINT32_BE (hdr);
1627 fps_denom = GST_READ_UINT32_BE (hdr + 4);
1628 context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1629 fps_denom, fps_num);
1631 par_num = GST_READ_UINT32_BE (hdr) >> 8;
1632 par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1633 if (par_num > 0 && par_denom > 0) {
1634 if (par_num > par_denom) {
1635 videocontext->display_width =
1636 videocontext->pixel_width * par_num / par_denom;
1637 videocontext->display_height = videocontext->pixel_height;
1638 } else if (par_num < par_denom) {
1639 videocontext->display_width = videocontext->pixel_width;
1640 videocontext->display_height =
1641 videocontext->pixel_height * par_denom / par_num;
1643 videocontext->display_width = 0;
1644 videocontext->display_height = 0;
1647 videocontext->display_width = 0;
1648 videocontext->display_height = 0;
1651 gst_buffer_unmap (buf0, &map);
1655 gst_buffer_unref (buf0);
1661 kate_streamheader_to_codecdata (const GValue * streamheader,
1662 GstMatroskaTrackContext * context)
1664 GstBuffer *buf0 = NULL;
1666 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1669 if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) { /* Kate ID header is 64 bytes */
1670 GST_WARNING ("First kate header too small, ignoring");
1671 } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
1672 GST_WARNING ("First header not a kate identification header, ignoring");
1676 gst_buffer_unref (buf0);
1682 flac_streamheader_to_codecdata (const GValue * streamheader,
1683 GstMatroskaTrackContext * context)
1690 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1691 GST_WARNING ("No or invalid streamheader field in the caps");
1695 bufarr = g_value_peek_pointer (streamheader);
1696 if (bufarr->len < 2) {
1697 GST_WARNING ("Too few headers in streamheader field");
1701 context->xiph_headers_to_skip = bufarr->len + 1;
1703 bufval = &g_array_index (bufarr, GValue, 0);
1704 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1705 GST_WARNING ("streamheaders array does not contain GstBuffers");
1709 buffer = g_value_peek_pointer (bufval);
1711 /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1712 if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
1713 || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
1714 || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
1715 GST_WARNING ("Invalid streamheader for FLAC");
1719 gst_matroska_mux_free_codec_priv (context);
1720 context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
1721 context->codec_priv = g_malloc (context->codec_priv_size);
1722 gst_buffer_extract (buffer, 9, context->codec_priv, -1);
1724 for (i = 1; i < bufarr->len; i++) {
1726 bufval = &g_array_index (bufarr, GValue, i);
1728 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1729 gst_matroska_mux_free_codec_priv (context);
1730 GST_WARNING ("streamheaders array does not contain GstBuffers");
1734 buffer = g_value_peek_pointer (bufval);
1736 old_size = context->codec_priv_size;
1737 context->codec_priv_size += gst_buffer_get_size (buffer);
1739 context->codec_priv = g_realloc (context->codec_priv,
1740 context->codec_priv_size);
1741 gst_buffer_extract (buffer, 0,
1742 (guint8 *) context->codec_priv + old_size, -1);
1749 speex_streamheader_to_codecdata (const GValue * streamheader,
1750 GstMatroskaTrackContext * context)
1757 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1758 GST_WARNING ("No or invalid streamheader field in the caps");
1762 bufarr = g_value_peek_pointer (streamheader);
1763 if (bufarr->len != 2) {
1764 GST_WARNING ("Too few headers in streamheader field");
1768 context->xiph_headers_to_skip = bufarr->len + 1;
1770 bufval = &g_array_index (bufarr, GValue, 0);
1771 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1772 GST_WARNING ("streamheaders array does not contain GstBuffers");
1776 buffer = g_value_peek_pointer (bufval);
1778 if (gst_buffer_get_size (buffer) < 80
1779 || gst_buffer_memcmp (buffer, 0, "Speex ", 8) != 0) {
1780 GST_WARNING ("Invalid streamheader for Speex");
1784 gst_matroska_mux_free_codec_priv (context);
1785 context->codec_priv_size = gst_buffer_get_size (buffer);
1786 context->codec_priv = g_malloc (context->codec_priv_size);
1787 gst_buffer_extract (buffer, 0, context->codec_priv, -1);
1789 bufval = &g_array_index (bufarr, GValue, 1);
1791 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1792 gst_matroska_mux_free_codec_priv (context);
1793 GST_WARNING ("streamheaders array does not contain GstBuffers");
1797 buffer = g_value_peek_pointer (bufval);
1799 old_size = context->codec_priv_size;
1800 context->codec_priv_size += gst_buffer_get_size (buffer);
1801 context->codec_priv = g_realloc (context->codec_priv,
1802 context->codec_priv_size);
1803 gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
1809 opus_streamheader_to_codecdata (const GValue * streamheader,
1810 GstMatroskaTrackContext * context)
1816 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1819 bufarr = g_value_peek_pointer (streamheader);
1820 if (bufarr->len != 1 && bufarr->len != 2) /* one header, and count stored in a byte */
1823 /* Opus headers are not in-band */
1824 context->xiph_headers_to_skip = 0;
1826 bufval = &g_array_index (bufarr, GValue, 0);
1827 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1828 goto wrong_content_type;
1830 buf = g_value_peek_pointer (bufval);
1832 gst_matroska_mux_free_codec_priv (context);
1834 context->codec_priv_size = gst_buffer_get_size (buf);
1835 context->codec_priv = g_malloc0 (context->codec_priv_size);
1836 gst_buffer_extract (buf, 0, context->codec_priv, -1);
1838 context->codec_delay =
1839 GST_READ_UINT16_LE ((guint8 *) context->codec_priv + 10);
1840 context->codec_delay =
1841 gst_util_uint64_scale_round (context->codec_delay, GST_SECOND, 48000);
1842 context->seek_preroll = 80 * GST_MSECOND;
1849 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1850 G_VALUE_TYPE_NAME (streamheader));
1855 GST_WARNING ("got %u streamheaders, not 1 or 2 as expected", bufarr->len);
1860 GST_WARNING ("streamheaders array does not contain GstBuffers");
1866 opus_make_codecdata (GstMatroskaTrackContext * context, GstCaps * caps)
1870 guint8 channel_mapping_family;
1871 guint8 stream_count, coupled_count, channel_mapping[256];
1875 /* Opus headers are not in-band */
1876 context->xiph_headers_to_skip = 0;
1878 context->codec_delay = 0;
1879 context->seek_preroll = 80 * GST_MSECOND;
1881 if (!gst_codec_utils_opus_parse_caps (caps, &rate, &channels,
1882 &channel_mapping_family, &stream_count, &coupled_count,
1884 GST_WARNING ("Failed to parse caps for Opus");
1889 gst_codec_utils_opus_create_header (rate, channels,
1890 channel_mapping_family, stream_count, coupled_count, channel_mapping, 0,
1893 GST_WARNING ("Failed to create Opus header from caps");
1897 gst_buffer_map (buffer, &map, GST_MAP_READ);
1898 context->codec_priv_size = map.size;
1899 context->codec_priv = g_malloc (context->codec_priv_size);
1900 memcpy (context->codec_priv, map.data, map.size);
1901 gst_buffer_unmap (buffer, &map);
1902 gst_buffer_unref (buffer);
1908 * gst_matroska_mux_audio_pad_setcaps:
1909 * @pad: Pad which got the caps.
1912 * Setcaps function for audio sink pad.
1914 * Returns: %TRUE on success.
1917 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1919 GstMatroskaTrackContext *context = NULL;
1920 GstMatroskaTrackAudioContext *audiocontext;
1921 GstMatroskaMux *mux;
1922 GstMatroskaPad *collect_pad;
1923 const gchar *mimetype;
1924 gint samplerate = 0, channels = 0;
1925 GstStructure *structure;
1926 const GValue *codec_data = NULL;
1927 GstBuffer *buf = NULL;
1928 const gchar *stream_format = NULL;
1931 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1933 if ((old_caps = gst_pad_get_current_caps (pad))) {
1934 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1935 && !gst_caps_is_equal (caps, old_caps)) {
1936 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1937 ("Caps changes are not supported by Matroska"));
1938 gst_caps_unref (old_caps);
1941 gst_caps_unref (old_caps);
1942 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
1943 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1944 ("Caps on pad %" GST_PTR_FORMAT
1945 " arrived late. Headers were already written", pad));
1950 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1951 g_assert (collect_pad);
1952 context = collect_pad->track;
1954 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
1955 audiocontext = (GstMatroskaTrackAudioContext *) context;
1957 structure = gst_caps_get_structure (caps, 0);
1958 mimetype = gst_structure_get_name (structure);
1961 gst_structure_get_int (structure, "rate", &samplerate);
1962 gst_structure_get_int (structure, "channels", &channels);
1964 audiocontext->samplerate = samplerate;
1965 audiocontext->channels = channels;
1966 audiocontext->bitdepth = 0;
1967 context->default_duration = 0;
1969 codec_data = gst_structure_get_value (structure, "codec_data");
1971 buf = gst_value_get_buffer (codec_data);
1973 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1974 * data and other settings
1978 if (!strcmp (mimetype, "audio/mpeg")) {
1979 gint mpegversion = 0;
1981 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1982 switch (mpegversion) {
1988 gst_structure_get_int (structure, "layer", &layer);
1990 if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
1991 GST_WARNING_OBJECT (mux,
1992 "Unable to determine MPEG audio version, assuming 1");
1998 else if (layer == 2)
2000 else if (version == 2)
2005 context->default_duration =
2006 gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
2010 gst_matroska_mux_set_codec_id (context,
2011 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
2014 gst_matroska_mux_set_codec_id (context,
2015 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
2018 gst_matroska_mux_set_codec_id (context,
2019 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
2028 stream_format = gst_structure_get_string (structure, "stream-format");
2029 /* check this is raw aac */
2030 if (stream_format) {
2031 if (strcmp (stream_format, "raw") != 0) {
2032 GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
2036 GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
2041 gst_matroska_mux_set_codec_id (context,
2042 GST_MATROSKA_CODEC_ID_AUDIO_AAC);
2043 context->codec_priv_size = gst_buffer_get_size (buf);
2044 context->codec_priv = g_malloc (context->codec_priv_size);
2045 gst_buffer_extract (buf, 0, context->codec_priv,
2046 context->codec_priv_size);
2048 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
2055 } else if (!strcmp (mimetype, "audio/x-raw")) {
2058 gst_audio_info_init (&info);
2059 if (!gst_audio_info_from_caps (&info, caps)) {
2060 GST_DEBUG_OBJECT (mux,
2061 "broken caps, rejected by gst_audio_info_from_caps");
2065 switch (GST_AUDIO_INFO_FORMAT (&info)) {
2066 case GST_AUDIO_FORMAT_U8:
2067 case GST_AUDIO_FORMAT_S16BE:
2068 case GST_AUDIO_FORMAT_S16LE:
2069 case GST_AUDIO_FORMAT_S24BE:
2070 case GST_AUDIO_FORMAT_S24LE:
2071 case GST_AUDIO_FORMAT_S32BE:
2072 case GST_AUDIO_FORMAT_S32LE:
2073 if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
2074 GST_DEBUG_OBJECT (mux, "width must be same as depth!");
2077 if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
2078 gst_matroska_mux_set_codec_id (context,
2079 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
2081 gst_matroska_mux_set_codec_id (context,
2082 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
2084 case GST_AUDIO_FORMAT_F32LE:
2085 case GST_AUDIO_FORMAT_F64LE:
2086 gst_matroska_mux_set_codec_id (context,
2087 GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
2091 GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
2095 audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
2096 } else if (!strcmp (mimetype, "audio/x-vorbis")) {
2097 const GValue *streamheader;
2099 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
2101 gst_matroska_mux_free_codec_priv (context);
2103 streamheader = gst_structure_get_value (structure, "streamheader");
2104 if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
2105 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2106 ("vorbis stream headers missing or malformed"));
2109 } else if (!strcmp (mimetype, "audio/x-flac")) {
2110 const GValue *streamheader;
2112 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
2114 gst_matroska_mux_free_codec_priv (context);
2116 streamheader = gst_structure_get_value (structure, "streamheader");
2117 if (!flac_streamheader_to_codecdata (streamheader, context)) {
2118 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2119 ("flac stream headers missing or malformed"));
2122 } else if (!strcmp (mimetype, "audio/x-speex")) {
2123 const GValue *streamheader;
2125 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
2126 gst_matroska_mux_free_codec_priv (context);
2128 streamheader = gst_structure_get_value (structure, "streamheader");
2129 if (!speex_streamheader_to_codecdata (streamheader, context)) {
2130 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2131 ("speex stream headers missing or malformed"));
2134 } else if (!strcmp (mimetype, "audio/x-opus")) {
2135 const GValue *streamheader;
2137 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_OPUS);
2139 streamheader = gst_structure_get_value (structure, "streamheader");
2141 gst_matroska_mux_free_codec_priv (context);
2142 if (!opus_streamheader_to_codecdata (streamheader, context)) {
2143 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2144 ("opus stream headers missing or malformed"));
2148 /* no streamheader, but we need to have one, so we make one up
2150 gst_matroska_mux_free_codec_priv (context);
2151 if (!opus_make_codecdata (context, caps)) {
2152 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2153 ("opus stream headers missing or malformed"));
2157 } else if (!strcmp (mimetype, "audio/x-ac3")) {
2158 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_AC3);
2159 } else if (!strcmp (mimetype, "audio/x-eac3")) {
2160 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
2161 } else if (!strcmp (mimetype, "audio/x-dts")) {
2162 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_DTS);
2163 } else if (!strcmp (mimetype, "audio/x-tta")) {
2166 /* TTA frame duration */
2167 context->default_duration = 1.04489795918367346939 * GST_SECOND;
2169 gst_structure_get_int (structure, "width", &width);
2170 audiocontext->bitdepth = width;
2171 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_TTA);
2173 } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
2175 const GValue *mdpr_data;
2177 gst_structure_get_int (structure, "raversion", &raversion);
2178 switch (raversion) {
2180 gst_matroska_mux_set_codec_id (context,
2181 GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
2184 gst_matroska_mux_set_codec_id (context,
2185 GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
2188 gst_matroska_mux_set_codec_id (context,
2189 GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
2195 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
2196 if (mdpr_data != NULL) {
2197 guint8 *priv_data = NULL;
2198 guint priv_data_size = 0;
2200 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
2202 priv_data_size = gst_buffer_get_size (codec_data_buf);
2203 priv_data = g_malloc0 (priv_data_size);
2205 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
2207 gst_matroska_mux_free_codec_priv (context);
2209 context->codec_priv = priv_data;
2210 context->codec_priv_size = priv_data_size;
2213 } else if (!strcmp (mimetype, "audio/x-wma")
2214 || !strcmp (mimetype, "audio/x-alaw")
2215 || !strcmp (mimetype, "audio/x-mulaw")
2216 || !strcmp (mimetype, "audio/x-adpcm")
2217 || !strcmp (mimetype, "audio/G722")) {
2219 guint codec_priv_size;
2221 gint block_align = 0;
2224 if (samplerate == 0 || channels == 0) {
2225 GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
2229 if (!strcmp (mimetype, "audio/x-wma")) {
2233 if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
2234 || !gst_structure_get_int (structure, "block_align", &block_align)
2235 || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
2236 GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
2241 switch (wmaversion) {
2243 format = GST_RIFF_WAVE_FORMAT_WMAV1;
2246 format = GST_RIFF_WAVE_FORMAT_WMAV2;
2249 format = GST_RIFF_WAVE_FORMAT_WMAV3;
2252 GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
2256 if (gst_structure_get_int (structure, "depth", &depth))
2257 audiocontext->bitdepth = depth;
2258 } else if (!strcmp (mimetype, "audio/x-alaw")
2259 || !strcmp (mimetype, "audio/x-mulaw")) {
2260 audiocontext->bitdepth = 8;
2261 if (!strcmp (mimetype, "audio/x-alaw"))
2262 format = GST_RIFF_WAVE_FORMAT_ALAW;
2264 format = GST_RIFF_WAVE_FORMAT_MULAW;
2266 block_align = channels;
2267 bitrate = block_align * samplerate;
2268 } else if (!strcmp (mimetype, "audio/x-adpcm")) {
2271 layout = gst_structure_get_string (structure, "layout");
2273 GST_WARNING_OBJECT (mux, "Missing layout on adpcm caps");
2277 if (!gst_structure_get_int (structure, "block_align", &block_align)) {
2278 GST_WARNING_OBJECT (mux, "Missing block_align on adpcm caps");
2282 if (!strcmp (layout, "dvi")) {
2283 format = GST_RIFF_WAVE_FORMAT_DVI_ADPCM;
2284 } else if (!strcmp (layout, "g726")) {
2285 format = GST_RIFF_WAVE_FORMAT_ITU_G726_ADPCM;
2286 if (!gst_structure_get_int (structure, "bitrate", &bitrate)) {
2287 GST_WARNING_OBJECT (mux, "Missing bitrate on adpcm g726 caps");
2291 GST_WARNING_OBJECT (mux, "Unknown layout on adpcm caps");
2295 } else if (!strcmp (mimetype, "audio/G722")) {
2296 format = GST_RIFF_WAVE_FORMAT_ADPCM_G722;
2298 g_assert (format != 0);
2300 codec_priv_size = WAVEFORMATEX_SIZE;
2302 codec_priv_size += gst_buffer_get_size (buf);
2304 /* serialize waveformatex structure */
2305 codec_priv = g_malloc0 (codec_priv_size);
2306 GST_WRITE_UINT16_LE (codec_priv, format);
2307 GST_WRITE_UINT16_LE (codec_priv + 2, channels);
2308 GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
2309 GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
2310 GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
2311 GST_WRITE_UINT16_LE (codec_priv + 14, 0);
2313 GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
2315 GST_WRITE_UINT16_LE (codec_priv + 16, 0);
2317 /* process codec private/initialization data, if any */
2319 gst_buffer_extract (buf, 0,
2320 (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
2323 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
2324 gst_matroska_mux_free_codec_priv (context);
2325 context->codec_priv = (gpointer) codec_priv;
2326 context->codec_priv_size = codec_priv_size;
2334 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2335 GST_PAD_NAME (pad), caps);
2340 /* we probably don't have the data at start,
2341 * so have to reserve (a maximum) space to write this at the end.
2342 * bit spacy, but some formats can hold quite some */
2343 #define SUBTITLE_MAX_CODEC_PRIVATE 2048 /* must be > 128 */
2346 * gst_matroska_mux_subtitle_pad_setcaps:
2347 * @pad: Pad which got the caps.
2350 * Setcaps function for subtitle sink pad.
2352 * Returns: %TRUE on success.
2355 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
2357 /* There is now (at least) one such alement (kateenc), and I'm going
2358 to handle it here and claim it works when it can be piped back
2359 through GStreamer and VLC */
2361 GstMatroskaTrackContext *context = NULL;
2362 GstMatroskaTrackSubtitleContext *scontext;
2363 GstMatroskaMux *mux;
2364 GstMatroskaPad *collect_pad;
2365 GstCollectData *data;
2366 const gchar *mimetype;
2367 GstStructure *structure;
2368 const GValue *value = NULL;
2369 GstBuffer *buf = NULL;
2370 gboolean ret = TRUE;
2373 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2375 if ((old_caps = gst_pad_get_current_caps (pad))) {
2376 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
2377 && !gst_caps_is_equal (caps, old_caps)) {
2378 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2379 ("Caps changes are not supported by Matroska"));
2380 gst_caps_unref (old_caps);
2383 gst_caps_unref (old_caps);
2384 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
2385 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2386 ("Caps on pad %" GST_PTR_FORMAT
2387 " arrived late. Headers were already written", pad));
2392 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
2393 g_assert (collect_pad);
2394 data = (GstCollectData *) (collect_pad);
2396 context = collect_pad->track;
2398 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
2399 scontext = (GstMatroskaTrackSubtitleContext *) context;
2401 structure = gst_caps_get_structure (caps, 0);
2402 mimetype = gst_structure_get_name (structure);
2405 scontext->check_utf8 = 1;
2406 scontext->invalid_utf8 = 0;
2407 context->default_duration = 0;
2409 if (!strcmp (mimetype, "subtitle/x-kate")) {
2410 const GValue *streamheader;
2412 gst_matroska_mux_set_codec_id (context,
2413 GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
2415 gst_matroska_mux_free_codec_priv (context);
2417 streamheader = gst_structure_get_value (structure, "streamheader");
2418 if (!kate_streamheader_to_codecdata (streamheader, context)) {
2419 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2420 ("kate stream headers missing or malformed"));
2424 } else if (!strcmp (mimetype, "text/x-raw")) {
2425 gst_matroska_mux_set_codec_id (context,
2426 GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
2427 } else if (!strcmp (mimetype, "application/x-ssa")) {
2428 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
2429 } else if (!strcmp (mimetype, "application/x-ass")) {
2430 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
2431 } else if (!strcmp (mimetype, "application/x-usf")) {
2432 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
2433 } else if (!strcmp (mimetype, "subpicture/x-dvd")) {
2434 gst_matroska_mux_set_codec_id (context,
2435 GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
2441 /* maybe some private data, e.g. vobsub */
2442 value = gst_structure_get_value (structure, "codec_data");
2444 buf = gst_value_get_buffer (value);
2447 guint8 *priv_data = NULL;
2449 gst_buffer_map (buf, &map, GST_MAP_READ);
2451 if (map.size > SUBTITLE_MAX_CODEC_PRIVATE) {
2452 GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
2453 " exceeded maximum (%d); discarding", pad,
2454 SUBTITLE_MAX_CODEC_PRIVATE);
2455 gst_buffer_unmap (buf, &map);
2459 gst_matroska_mux_free_codec_priv (context);
2461 priv_data = g_malloc0 (map.size);
2462 memcpy (priv_data, map.data, map.size);
2463 context->codec_priv = priv_data;
2464 context->codec_priv_size = map.size;
2465 gst_buffer_unmap (buf, &map);
2468 GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %" G_GSIZE_FORMAT,
2469 GST_STR_NULL (context->codec_id), context->codec_priv_size);
2471 /* This pad is sparse. Now that we have caps on it, we can tell collectpads
2472 * not to actually wait for data when muxing */
2473 GST_COLLECT_PADS_STREAM_LOCK (mux->collect);
2474 GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED);
2475 gst_collect_pads_set_waiting (mux->collect, data, FALSE);
2476 GST_COLLECT_PADS_STREAM_UNLOCK (mux->collect);
2485 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2486 GST_PAD_NAME (pad), caps);
2493 * gst_matroska_mux_request_new_pad:
2494 * @element: #GstMatroskaMux.
2495 * @templ: #GstPadTemplate.
2496 * @pad_name: New pad name.
2498 * Request pad function for sink templates.
2500 * Returns: New #GstPad.
2503 gst_matroska_mux_request_new_pad (GstElement * element,
2504 GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
2506 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
2507 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
2508 GstMatroskaPad *collect_pad;
2509 GstMatroskamuxPad *newpad;
2511 const gchar *pad_name = NULL;
2512 GstMatroskaCapsFunc capsfunc = NULL;
2513 GstMatroskaTrackContext *context = NULL;
2515 const gchar *id = NULL;
2517 if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
2518 /* don't mix named and unnamed pads, if the pad already exists we fail when
2519 * trying to add it */
2520 if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
2521 pad_name = req_name;
2523 name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
2526 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
2527 context = (GstMatroskaTrackContext *)
2528 g_new0 (GstMatroskaTrackAudioContext, 1);
2529 context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
2530 context->name = g_strdup ("Audio");
2531 } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
2532 /* don't mix named and unnamed pads, if the pad already exists we fail when
2533 * trying to add it */
2534 if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
2535 pad_name = req_name;
2537 name = g_strdup_printf ("video_%u", mux->num_v_streams++);
2540 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
2541 context = (GstMatroskaTrackContext *)
2542 g_new0 (GstMatroskaTrackVideoContext, 1);
2543 context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
2544 context->name = g_strdup ("Video");
2545 } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
2546 /* don't mix named and unnamed pads, if the pad already exists we fail when
2547 * trying to add it */
2548 if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
2549 pad_name = req_name;
2551 name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
2554 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
2555 context = (GstMatroskaTrackContext *)
2556 g_new0 (GstMatroskaTrackSubtitleContext, 1);
2557 context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
2558 context->name = g_strdup ("Subtitle");
2559 /* setcaps may only provide proper one a lot later */
2560 id = "S_SUB_UNKNOWN";
2562 GST_WARNING_OBJECT (mux, "This is not our template!");
2566 newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
2567 "name", pad_name, "direction", templ->direction, "template", templ, NULL);
2569 gst_matroskamux_pad_init (newpad);
2570 collect_pad = (GstMatroskaPad *)
2571 gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad),
2572 sizeof (GstMatroskaPad),
2573 (GstCollectDataDestroyNotify) gst_matroska_pad_free, TRUE);
2575 collect_pad->mux = mux;
2576 collect_pad->track = context;
2577 gst_matroska_pad_reset (collect_pad, FALSE);
2579 gst_matroska_mux_set_codec_id (collect_pad->track, id);
2580 collect_pad->track->dts_only = FALSE;
2582 collect_pad->capsfunc = capsfunc;
2583 gst_pad_set_active (GST_PAD (newpad), TRUE);
2584 if (!gst_element_add_pad (element, GST_PAD (newpad)))
2585 goto pad_add_failed;
2591 GST_DEBUG_OBJECT (newpad, "Added new request pad");
2593 return GST_PAD (newpad);
2598 GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
2600 gst_object_unref (newpad);
2606 * gst_matroska_mux_release_pad:
2607 * @element: #GstMatroskaMux.
2608 * @pad: Pad to release.
2610 * Release a previously requested pad.
2613 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
2615 GstMatroskaMux *mux;
2618 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2620 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
2621 GstCollectData *cdata = (GstCollectData *) walk->data;
2622 GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
2624 if (cdata->pad == pad) {
2626 * observed duration, this will remain GST_CLOCK_TIME_NONE
2627 * only if the pad is reset
2629 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
2631 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2632 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2633 collected_duration =
2634 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2637 if (GST_CLOCK_TIME_IS_VALID (collected_duration)
2638 && mux->duration < collected_duration)
2639 mux->duration = collected_duration;
2645 gst_collect_pads_remove_pad (mux->collect, pad);
2646 if (gst_element_remove_pad (element, pad))
2651 gst_matroska_mux_write_mastering_metadata (GstMatroskaMux * mux,
2652 GstMatroskaTrackVideoContext * videocontext)
2654 GstEbmlWrite *ebml = mux->ebml_write;
2656 GstVideoMasteringDisplayInfo *minfo = &videocontext->mastering_display_info;
2658 const gdouble chroma_scale = 50000;
2659 const gdouble luma_scale = 50000;
2661 if (!videocontext->mastering_display_info_present)
2665 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_MASTERINGMETADATA);
2667 value = (gdouble) minfo->display_primaries[0].x / chroma_scale;
2668 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYX, value);
2670 value = (gdouble) minfo->display_primaries[0].y / chroma_scale;
2671 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYY, value);
2673 value = (gdouble) minfo->display_primaries[1].x / chroma_scale;
2674 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYX, value);
2676 value = (gdouble) minfo->display_primaries[1].y / chroma_scale;
2677 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYY, value);
2679 value = (gdouble) minfo->display_primaries[2].x / chroma_scale;
2680 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYX, value);
2682 value = (gdouble) minfo->display_primaries[2].y / chroma_scale;
2683 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYY, value);
2685 value = (gdouble) minfo->white_point.x / chroma_scale;
2686 gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYX, value);
2688 value = (gdouble) minfo->white_point.y / chroma_scale;
2689 gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY, value);
2691 value = (gdouble) minfo->max_display_mastering_luminance / luma_scale;
2692 gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMAX, value);
2694 value = (gdouble) minfo->min_display_mastering_luminance / luma_scale;
2695 gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMIN, value);
2697 gst_ebml_write_master_finish (ebml, master);
2702 gst_matroska_mux_write_colour (GstMatroskaMux * mux,
2703 GstMatroskaTrackVideoContext * videocontext)
2705 GstEbmlWrite *ebml = mux->ebml_write;
2707 guint matrix_id = 0;
2709 guint transfer_id = 0;
2710 guint primaries_id = 0;
2712 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_VIDEOCOLOUR);
2714 switch (videocontext->colorimetry.range) {
2715 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
2718 case GST_VIDEO_COLOR_RANGE_16_235:
2721 case GST_VIDEO_COLOR_RANGE_0_255:
2725 matrix_id = gst_video_color_matrix_to_iso (videocontext->colorimetry.matrix);
2727 gst_video_transfer_function_to_iso (videocontext->colorimetry.transfer);
2729 gst_video_color_primaries_to_iso (videocontext->colorimetry.primaries);
2731 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEORANGE, range_id);
2732 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOMATRIXCOEFFICIENTS,
2734 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS,
2736 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPRIMARIES, primaries_id);
2737 if (videocontext->content_light_level.max_content_light_level &&
2738 videocontext->content_light_level.max_frame_average_light_level) {
2739 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXCLL,
2740 videocontext->content_light_level.max_content_light_level);
2741 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXFALL,
2742 videocontext->content_light_level.max_frame_average_light_level);
2745 gst_matroska_mux_write_mastering_metadata (mux, videocontext);
2746 gst_ebml_write_master_finish (ebml, master);
2750 * gst_matroska_mux_track_header:
2751 * @mux: #GstMatroskaMux
2752 * @context: Tack context.
2754 * Write a track header.
2757 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2758 GstMatroskaTrackContext * context)
2760 GstEbmlWrite *ebml = mux->ebml_write;
2763 /* TODO: check if everything necessary is written and check default values */
2765 /* track type goes before the type-specific stuff */
2766 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2767 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2769 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, context->uid);
2770 if (context->default_duration) {
2771 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2772 context->default_duration);
2774 if (context->language) {
2775 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2779 /* FIXME: until we have a nice way of getting the codecname
2780 * out of the caps, I'm not going to enable this. Too much
2781 * (useless, double, boring) work... */
2782 /* TODO: Use value from tags if any */
2783 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2784 context->codec_name); */
2785 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2787 /* type-specific stuff */
2788 switch (context->type) {
2789 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2790 GstMatroskaTrackVideoContext *videocontext =
2791 (GstMatroskaTrackVideoContext *) context;
2793 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2794 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2795 videocontext->pixel_width);
2796 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2797 videocontext->pixel_height);
2798 if (videocontext->display_width && videocontext->display_height) {
2799 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2800 videocontext->display_width);
2801 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2802 videocontext->display_height);
2804 switch (videocontext->interlace_mode) {
2805 case GST_MATROSKA_INTERLACE_MODE_INTERLACED:
2806 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2808 case GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE:
2809 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 2);
2815 if (videocontext->fourcc) {
2816 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2818 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2819 (gpointer) & fcc_le, 4);
2821 gst_matroska_mux_write_colour (mux, videocontext);
2822 if (videocontext->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
2823 guint64 stereo_mode = 0;
2825 switch (videocontext->multiview_mode) {
2826 case GST_VIDEO_MULTIVIEW_MODE_MONO:
2828 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
2829 if (videocontext->multiview_flags &
2830 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2831 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_RL;
2833 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_LR;
2835 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
2836 if (videocontext->multiview_flags &
2837 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2838 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_RL;
2840 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_LR;
2842 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
2843 if (videocontext->multiview_flags &
2844 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2845 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_RL;
2847 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_LR;
2849 case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
2850 if (videocontext->multiview_flags &
2851 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2852 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_RL;
2854 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_LR;
2855 /* FIXME: In frame-by-frame mode, left/right frame buffers need to be
2856 * laced within one block. See http://www.matroska.org/technical/specs/index.html#StereoMode */
2857 GST_FIXME_OBJECT (mux,
2858 "Frame-by-frame stereoscopic mode not fully implemented");
2861 GST_WARNING_OBJECT (mux,
2862 "Multiview mode %d not supported in Matroska/WebM",
2863 videocontext->multiview_mode);
2867 if (stereo_mode != 0)
2868 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOSTEREOMODE,
2871 gst_ebml_write_master_finish (ebml, master);
2876 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2877 GstMatroskaTrackAudioContext *audiocontext =
2878 (GstMatroskaTrackAudioContext *) context;
2880 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2881 if (audiocontext->samplerate != 8000)
2882 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2883 audiocontext->samplerate);
2884 if (audiocontext->channels != 1)
2885 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2886 audiocontext->channels);
2887 if (audiocontext->bitdepth) {
2888 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2889 audiocontext->bitdepth);
2892 gst_ebml_write_master_finish (ebml, master);
2897 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
2901 /* doesn't need type-specific data */
2905 GST_DEBUG_OBJECT (mux, "Wrote track header. Codec %s", context->codec_id);
2907 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2908 if (context->codec_priv)
2909 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2910 context->codec_priv, context->codec_priv_size);
2912 if (context->seek_preroll) {
2913 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPREROLL,
2914 context->seek_preroll);
2917 if (context->codec_delay) {
2918 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CODECDELAY,
2919 context->codec_delay);
2924 gst_matroska_mux_write_chapter_title (const gchar * title, GstEbmlWrite * ebml)
2926 guint64 title_master;
2929 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERDISPLAY);
2931 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPSTRING, title);
2932 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CHAPLANGUAGE,
2933 GST_MATROSKA_MUX_CHAPLANG);
2935 gst_ebml_write_master_finish (ebml, title_master);
2938 static GstTocEntry *
2939 gst_matroska_mux_write_chapter (GstMatroskaMux * mux, GstTocEntry * edition,
2940 GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters,
2941 guint64 * master_edition)
2943 guint64 master_chapteratom;
2950 GstTocEntry *internal_chapter, *internal_nested;
2953 if (G_UNLIKELY (master_chapters != NULL && *master_chapters == 0))
2955 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERS);
2957 if (G_UNLIKELY (master_edition != NULL && *master_edition == 0)) {
2958 /* create uid for the parent */
2960 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_EDITIONENTRY);
2962 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONUID,
2963 g_ascii_strtoull (gst_toc_entry_get_uid (edition), NULL, 10));
2964 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGHIDDEN, 0);
2965 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGDEFAULT, 0);
2966 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGORDERED, 0);
2969 gst_toc_entry_get_start_stop_times (entry, &start, &stop);
2970 tags = gst_toc_entry_get_tags (entry);
2972 tags = gst_tag_list_copy (tags);
2975 /* build internal chapter */
2976 uid = gst_matroska_mux_create_uid (mux);
2977 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT, uid);
2978 internal_chapter = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, s_uid);
2980 /* Write the chapter entry */
2981 master_chapteratom =
2982 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERATOM);
2984 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERUID, uid);
2985 /* Store the user provided UID in the ChapterStringUID */
2986 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPTERSTRINGUID,
2987 gst_toc_entry_get_uid (entry));
2988 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTART, start);
2989 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTOP, stop);
2990 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGHIDDEN, 0);
2991 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGENABLED, 1);
2993 /* write current ChapterDisplays before the nested chapters */
2994 if (G_LIKELY (tags != NULL)) {
2995 count = gst_tag_list_get_tag_size (tags, GST_TAG_TITLE);
2997 for (i = 0; i < count; ++i) {
2998 gst_tag_list_get_string_index (tags, GST_TAG_TITLE, i, &title);
2999 /* FIXME: handle ChapterLanguage entries */
3000 gst_matroska_mux_write_chapter_title (title, ebml);
3004 /* remove title tag */
3005 if (G_LIKELY (count > 0))
3006 gst_tag_list_remove_tag (tags, GST_TAG_TITLE);
3008 gst_toc_entry_set_tags (internal_chapter, tags);
3011 /* Write nested chapters */
3012 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3014 internal_nested = gst_matroska_mux_write_chapter (mux, NULL, cur->data,
3017 gst_toc_entry_append_sub_entry (internal_chapter, internal_nested);
3020 gst_ebml_write_master_finish (ebml, master_chapteratom);
3022 return internal_chapter;
3025 static GstTocEntry *
3026 gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
3027 GstTocEntry * edition, GList * chapters, GstEbmlWrite * ebml,
3028 guint64 * master_chapters)
3030 guint64 master_edition = 0;
3033 GstTocEntry *internal_edition, *internal_chapter;
3034 GstTagList *tags = NULL;
3036 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT,
3037 gst_matroska_mux_create_uid (mux));
3039 if (edition != NULL) {
3040 /* Edition entry defined, get its tags */
3041 tags = gst_toc_entry_get_tags (edition);
3043 tags = gst_tag_list_copy (tags);
3047 internal_edition = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, s_uid);
3049 gst_toc_entry_set_tags (internal_edition, tags);
3052 for (cur = g_list_first (chapters); cur != NULL; cur = cur->next) {
3053 internal_chapter = gst_matroska_mux_write_chapter (mux, internal_edition,
3054 cur->data, ebml, master_chapters, &master_edition);
3056 gst_toc_entry_append_sub_entry (internal_edition, internal_chapter);
3059 if (G_LIKELY (master_edition != 0))
3060 gst_ebml_write_master_finish (ebml, master_edition);
3062 return internal_edition;
3066 * gst_matroska_mux_start:
3067 * @mux: #GstMatroskaMux
3069 * Start a new matroska file (write headers etc...)
3072 gst_matroska_mux_start (GstMatroskaMux * mux, GstMatroskaPad * first_pad,
3073 GstBuffer * first_pad_buf)
3075 GstEbmlWrite *ebml = mux->ebml_write;
3076 const gchar *doctype;
3077 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
3078 GST_MATROSKA_ID_TRACKS,
3079 GST_MATROSKA_ID_CHAPTERS,
3080 GST_MATROSKA_ID_CUES,
3081 GST_MATROSKA_ID_TAGS,
3084 const gchar *media_type;
3085 gboolean audio_only;
3086 guint64 master, child;
3090 GstClockTime earliest_time = GST_CLOCK_TIME_NONE;
3091 GstClockTime duration = 0;
3092 guint32 segment_uid[4];
3097 /* if not streaming, check if downstream is seekable */
3098 if (!mux->ebml_write->streamable) {
3102 query = gst_query_new_seeking (GST_FORMAT_BYTES);
3103 if (gst_pad_peer_query (mux->srcpad, query)) {
3104 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3105 GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
3107 /* assume seeking is not supported if query not handled downstream */
3108 GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
3112 mux->ebml_write->streamable = TRUE;
3113 g_object_notify (G_OBJECT (mux), "streamable");
3114 GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
3115 "streamable=false. Will ignore that and create streamable output "
3118 gst_query_unref (query);
3121 /* stream-start (FIXME: create id based on input ids) */
3122 g_snprintf (s_id, sizeof (s_id), "matroskamux-%08x", g_random_int ());
3123 gst_pad_push_event (mux->srcpad, gst_event_new_stream_start (s_id));
3126 audio_only = mux->num_v_streams == 0 && mux->num_a_streams > 0;
3128 media_type = (audio_only) ? "audio/webm" : "video/webm";
3130 media_type = (audio_only) ? "audio/x-matroska" : "video/x-matroska";
3132 ebml->caps = gst_caps_new_empty_simple (media_type);
3133 gst_pad_set_caps (mux->srcpad, ebml->caps);
3134 /* we start with a EBML header */
3135 doctype = mux->doctype;
3136 GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
3137 doctype, mux->doctype_version);
3138 gst_ebml_write_header (ebml, doctype, mux->doctype_version);
3140 /* the rest of the header is cached */
3141 gst_ebml_write_set_cache (ebml, 0x1000);
3143 /* start a segment */
3145 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
3146 mux->segment_master = ebml->pos;
3148 if (!mux->ebml_write->streamable) {
3149 /* seekhead (table of contents) - we set the positions later */
3150 mux->seekhead_pos = ebml->pos;
3151 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
3152 for (i = 0; seekhead_id[i] != 0; i++) {
3153 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
3154 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
3155 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
3156 gst_ebml_write_master_finish (ebml, child);
3158 gst_ebml_write_master_finish (ebml, master);
3161 if (mux->ebml_write->streamable) {
3162 const GstTagList *tags;
3163 gboolean has_main_tags;
3166 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3167 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3169 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux)) {
3170 guint64 master_tags, master_tag;
3172 GST_DEBUG_OBJECT (mux, "Writing tags");
3174 mux->tags_pos = ebml->pos;
3175 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3176 if (has_main_tags) {
3177 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3178 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3179 gst_ebml_write_master_finish (ebml, master_tag);
3181 gst_matroska_mux_write_streams_tags (mux);
3182 gst_ebml_write_master_finish (ebml, master_tags);
3187 mux->info_pos = ebml->pos;
3188 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
3190 /* WebM does not support SegmentUID field on SegmentInfo */
3191 if (!mux->is_webm) {
3192 for (i = 0; i < 4; i++) {
3193 segment_uid[i] = g_random_int ();
3195 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
3196 (guint8 *) segment_uid, 16);
3199 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
3200 mux->duration_pos = ebml->pos;
3202 if (!mux->ebml_write->streamable) {
3203 for (collected = mux->collect->data; collected;
3204 collected = g_slist_next (collected)) {
3205 GstMatroskaPad *collect_pad;
3207 gint64 trackduration;
3209 collect_pad = (GstMatroskaPad *) collected->data;
3210 thepad = collect_pad->collect.pad;
3212 /* Query the total length of the track. */
3213 GST_DEBUG_OBJECT (thepad, "querying peer duration");
3214 if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
3215 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
3216 GST_TIME_ARGS (trackduration));
3217 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
3218 duration = (GstClockTime) trackduration;
3222 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3223 gst_guint64_to_gdouble (duration) /
3224 gst_guint64_to_gdouble (mux->time_scale));
3226 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
3227 "GStreamer matroskamux version " PACKAGE_VERSION);
3228 if (mux->writing_app && mux->writing_app[0]) {
3229 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
3231 if (mux->creation_time != NULL) {
3232 time = g_date_time_to_unix (mux->creation_time) * GST_SECOND;
3233 time += g_date_time_get_microsecond (mux->creation_time) * GST_USECOND;
3235 time = g_get_real_time () * GST_USECOND;
3237 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time);
3238 gst_ebml_write_master_finish (ebml, master);
3241 mux->tracks_pos = ebml->pos;
3242 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
3244 for (collected = mux->collect->data; collected;
3245 collected = g_slist_next (collected)) {
3246 GstMatroskaPad *collect_pad;
3249 collect_pad = (GstMatroskaPad *) collected->data;
3251 /* This will cause an error at a later time */
3252 if (collect_pad->track->codec_id == NULL)
3255 /* Find the smallest timestamp so we can offset all streams by this to
3257 if (mux->offset_to_zero) {
3260 if (collect_pad == first_pad)
3261 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3263 buf = gst_collect_pads_peek (mux->collect, collected->data);
3266 ts = gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
3268 if (earliest_time == GST_CLOCK_TIME_NONE)
3270 else if (ts != GST_CLOCK_TIME_NONE && ts < earliest_time)
3275 gst_buffer_unref (buf);
3278 /* For audio tracks, use the first buffers duration as the default
3279 * duration if we didn't get any better idea from the caps event already
3281 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO &&
3282 collect_pad->track->default_duration == 0) {
3283 if (collect_pad == first_pad)
3284 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3286 buf = gst_collect_pads_peek (mux->collect, collected->data);
3288 if (buf && GST_BUFFER_DURATION_IS_VALID (buf))
3289 collect_pad->track->default_duration =
3290 GST_BUFFER_DURATION (buf) + collect_pad->track->codec_delay;
3292 gst_buffer_unref (buf);
3295 collect_pad->track->num = tracknum++;
3296 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
3297 gst_matroska_mux_track_header (mux, collect_pad->track);
3298 gst_ebml_write_master_finish (ebml, child);
3299 /* some remaining pad/track setup */
3300 collect_pad->default_duration_scaled =
3301 gst_util_uint64_scale (collect_pad->track->default_duration,
3302 1, mux->time_scale);
3304 gst_ebml_write_master_finish (ebml, master);
3306 mux->earliest_time = earliest_time == GST_CLOCK_TIME_NONE ? 0 : earliest_time;
3309 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3310 if (toc != NULL && !mux->ebml_write->streamable) {
3311 guint64 master_chapters = 0;
3312 GstTocEntry *internal_edition;
3313 GList *cur, *chapters;
3315 GST_DEBUG ("Writing chapters");
3317 /* There are two UIDs for Chapters:
3318 * - The ChapterUID is a mandatory unsigned integer which internally
3319 * refers to a given chapter. Except for the title & language which use
3320 * dedicated fields, this UID can also be used to add tags to the Chapter.
3321 * The tags come in a separate section of the container.
3322 * - The ChapterStringUID is an optional UTF-8 string which also uniquely
3323 * refers to a chapter but from an external perspective. It can act as a
3324 * "WebVTT cue identifier" which "can be used to reference a specific cue,
3325 * for example from script or CSS".
3327 * The ChapterUID will be generated and checked for unicity, while the
3328 * ChapterStringUID will receive the user defined UID.
3330 * In order to be able to refer to chapters from the tags section,
3331 * we must maintain an internal Toc tree with the generated ChapterUID
3332 * (see gst_matroska_mux_write_toc_entry_tags) */
3334 /* Check whether we have editions or chapters at the root level. */
3335 cur = gst_toc_get_entries (toc);
3337 mux->chapters_pos = ebml->pos;
3339 mux->internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
3341 if (gst_toc_entry_get_entry_type (cur->data) ==
3342 GST_TOC_ENTRY_TYPE_EDITION) {
3343 /* Editions at the root level */
3344 for (; cur != NULL; cur = cur->next) {
3345 chapters = gst_toc_entry_get_sub_entries (cur->data);
3346 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3347 cur->data, chapters, ebml, &master_chapters);
3348 gst_toc_append_entry (mux->internal_toc, internal_edition);
3351 /* Chapters at the root level */
3352 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3353 NULL, cur, ebml, &master_chapters);
3354 gst_toc_append_entry (mux->internal_toc, internal_edition);
3357 /* close master element if any edition was written */
3358 if (G_LIKELY (master_chapters != 0))
3359 gst_ebml_write_master_finish (ebml, master_chapters);
3363 /* lastly, flush the cache */
3364 gst_ebml_write_flush_cache (ebml, FALSE, 0);
3367 gst_toc_unref (toc);
3370 /* TODO: more sensible tag mappings */
3373 const gchar *matroska_tagname;
3374 const gchar *gstreamer_tagname;
3376 gst_matroska_tag_conv[] = {
3378 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
3379 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
3380 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
3381 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
3382 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
3383 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
3384 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
3385 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
3386 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
3387 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
3388 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
3389 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
3390 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
3391 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
3392 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
3395 /* Every stagefright implementation on android up to and including 6.0.1 is using
3396 libwebm with bug in matroska parsing, where it will choke on empty tag elements;
3397 so before outputting tags and tag elements we better make sure that there are
3398 actually tags we are going to write */
3400 gst_matroska_mux_tag_list_is_empty (const GstTagList * list)
3403 for (i = 0; i < gst_tag_list_n_tags (list); i++) {
3404 const gchar *tag = gst_tag_list_nth_tag_name (list, i);
3406 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3407 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3408 if (strcmp (tagname_gst, tag) == 0) {
3409 GValue src = { 0, };
3412 if (!gst_tag_list_copy_value (&src, list, tag))
3414 dest = gst_value_serialize (&src);
3416 g_value_unset (&src);
3428 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
3431 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
3433 guint64 simpletag_master;
3435 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3436 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3437 const gchar *tagname_mkv = gst_matroska_tag_conv[i].matroska_tagname;
3439 if (strcmp (tagname_gst, tag) == 0) {
3440 GValue src = { 0, };
3443 if (!gst_tag_list_copy_value (&src, list, tag))
3445 if ((dest = gst_value_serialize (&src))) {
3447 simpletag_master = gst_ebml_write_master_start (ebml,
3448 GST_MATROSKA_ID_SIMPLETAG);
3449 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
3450 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
3451 gst_ebml_write_master_finish (ebml, simpletag_master);
3454 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
3456 g_value_unset (&src);
3463 gst_matroska_mux_write_stream_tags (GstMatroskaMux * mux, GstMatroskaPad * mpad)
3465 guint64 master_tag, master_targets;
3468 ebml = mux->ebml_write;
3470 if (G_UNLIKELY (mpad->tags == NULL
3471 || gst_matroska_mux_tag_list_is_empty (mpad->tags)))
3474 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3475 master_targets = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3477 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETTRACKUID, mpad->track->uid);
3479 gst_ebml_write_master_finish (ebml, master_targets);
3480 gst_tag_list_foreach (mpad->tags, gst_matroska_mux_write_simple_tag, ebml);
3481 gst_ebml_write_master_finish (ebml, master_tag);
3485 gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux)
3489 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3490 GstMatroskaPad *collect_pad;
3492 collect_pad = (GstMatroskaPad *) walk->data;
3494 gst_matroska_mux_write_stream_tags (mux, collect_pad);
3499 gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux)
3503 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3504 GstMatroskaPad *collect_pad;
3506 collect_pad = (GstMatroskaPad *) walk->data;
3507 if (!gst_matroska_mux_tag_list_is_empty (collect_pad->tags))
3514 gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
3515 const GstTocEntry * entry, guint64 * master_tags, gboolean * has_tags)
3517 guint64 master_tag, master_targets;
3520 const GstTagList *tags;
3522 ebml = mux->ebml_write;
3524 tags = gst_toc_entry_get_tags (entry);
3525 if (G_UNLIKELY (tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags))) {
3528 if (*master_tags == 0) {
3529 mux->tags_pos = ebml->pos;
3530 *master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3533 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3535 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3537 if (gst_toc_entry_get_entry_type (entry) == GST_TOC_ENTRY_TYPE_EDITION)
3538 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETEDITIONUID,
3539 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3541 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETCHAPTERUID,
3542 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3544 gst_ebml_write_master_finish (ebml, master_targets);
3545 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3546 gst_ebml_write_master_finish (ebml, master_tag);
3549 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3551 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, master_tags,
3557 * gst_matroska_mux_finish:
3558 * @mux: #GstMatroskaMux
3560 * Finish a new matroska file (write index etc...)
3563 gst_matroska_mux_finish (GstMatroskaMux * mux)
3565 GstEbmlWrite *ebml = mux->ebml_write;
3567 guint64 duration = 0;
3569 const GstTagList *tags, *toc_tags;
3571 gboolean has_main_tags, toc_has_tags = FALSE;
3574 /* finish last cluster */
3576 gst_ebml_write_master_finish (ebml, mux->cluster);
3580 if (mux->index != NULL) {
3582 guint64 master, pointentry_master, trackpos_master;
3584 mux->cues_pos = ebml->pos;
3585 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
3586 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
3588 for (n = 0; n < mux->num_indexes; n++) {
3589 GstMatroskaIndex *idx = &mux->index[n];
3591 pointentry_master = gst_ebml_write_master_start (ebml,
3592 GST_MATROSKA_ID_POINTENTRY);
3593 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
3594 idx->time / mux->time_scale);
3595 trackpos_master = gst_ebml_write_master_start (ebml,
3596 GST_MATROSKA_ID_CUETRACKPOSITIONS);
3597 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
3598 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
3599 idx->pos - mux->segment_master);
3600 gst_ebml_write_master_finish (ebml, trackpos_master);
3601 gst_ebml_write_master_finish (ebml, pointentry_master);
3604 gst_ebml_write_master_finish (ebml, master);
3605 gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
3609 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3610 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3611 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3613 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux) || toc != NULL) {
3614 guint64 master_tags = 0, master_tag;
3616 GST_DEBUG_OBJECT (mux, "Writing tags");
3618 if (has_main_tags) {
3619 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
3620 mux->tags_pos = ebml->pos;
3621 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3622 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3625 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3626 if (mux->internal_toc != NULL) {
3627 toc_tags = gst_toc_get_tags (mux->internal_toc);
3628 toc_has_tags = (toc_tags != NULL);
3629 gst_tag_list_foreach (toc_tags, gst_matroska_mux_write_simple_tag,
3633 gst_ebml_write_master_finish (ebml, master_tag);
3636 if (mux->internal_toc != NULL) {
3637 for (cur = gst_toc_get_entries (mux->internal_toc); cur != NULL;
3639 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, &master_tags,
3644 if (master_tags == 0 && gst_matroska_mux_streams_have_tags (mux)) {
3645 mux->tags_pos = ebml->pos;
3646 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3648 gst_matroska_mux_write_streams_tags (mux);
3650 if (master_tags != 0)
3651 gst_ebml_write_master_finish (ebml, master_tags);
3654 /* update seekhead. We know that:
3655 * - a seekhead contains 5 entries.
3656 * - order of entries is as above.
3657 * - a seekhead has a 4-byte header + 8-byte length
3658 * - each entry is 2-byte master, 2-byte ID pointer,
3659 * 2-byte length pointer, all 8/1-byte length, 4-
3660 * byte ID and 8-byte length pointer, where the
3661 * length pointer starts at 20.
3662 * - all entries are local to the segment (so pos - segment_master).
3663 * - so each entry is at 12 + 20 + num * 28. */
3664 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
3665 mux->info_pos - mux->segment_master);
3666 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
3667 mux->tracks_pos - mux->segment_master);
3668 if (toc != NULL && mux->chapters_pos > 0) {
3669 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
3670 mux->chapters_pos - mux->segment_master);
3673 guint64 my_pos = ebml->pos;
3675 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
3676 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3677 gst_ebml_write_seek (ebml, my_pos);
3679 if (mux->index != NULL) {
3680 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
3681 mux->cues_pos - mux->segment_master);
3684 guint64 my_pos = ebml->pos;
3686 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
3687 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3688 gst_ebml_write_seek (ebml, my_pos);
3691 if (mux->tags_pos != 0 || toc_has_tags) {
3692 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 144,
3693 mux->tags_pos - mux->segment_master);
3696 guint64 my_pos = ebml->pos;
3698 gst_ebml_write_seek (ebml, mux->seekhead_pos + 124);
3699 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3700 gst_ebml_write_seek (ebml, my_pos);
3704 gst_toc_unref (toc);
3708 * - first get the overall duration
3709 * (a released track may have left a duration in here)
3710 * - write some track header data for subtitles
3712 duration = mux->duration;
3714 for (collected = mux->collect->data; collected;
3715 collected = g_slist_next (collected)) {
3716 GstMatroskaPad *collect_pad;
3718 * observed duration, this will never remain GST_CLOCK_TIME_NONE
3719 * since this means buffer without timestamps that is not possible
3721 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
3723 collect_pad = (GstMatroskaPad *) collected->data;
3725 GST_DEBUG_OBJECT (mux,
3726 "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
3727 " end ts %" GST_TIME_FORMAT, collect_pad,
3728 GST_TIME_ARGS (collect_pad->start_ts),
3729 GST_TIME_ARGS (collect_pad->end_ts));
3731 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
3732 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
3733 collected_duration =
3734 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
3735 GST_DEBUG_OBJECT (collect_pad->collect.pad,
3736 "final track duration: %" GST_TIME_FORMAT,
3737 GST_TIME_ARGS (collected_duration));
3739 GST_WARNING_OBJECT (collect_pad->collect.pad,
3740 "unable to get final track duration");
3742 if (GST_CLOCK_TIME_IS_VALID (collected_duration) &&
3743 duration < collected_duration)
3744 duration = collected_duration;
3748 /* seek back (optional, but do anyway) */
3749 gst_ebml_write_seek (ebml, pos);
3751 /* update duration */
3752 if (duration != 0) {
3753 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
3754 GST_TIME_ARGS (duration));
3755 pos = mux->ebml_write->pos;
3756 gst_ebml_write_seek (ebml, mux->duration_pos);
3757 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3758 gst_guint64_to_gdouble (duration) /
3759 gst_guint64_to_gdouble (mux->time_scale));
3760 gst_ebml_write_seek (ebml, pos);
3763 guint64 my_pos = ebml->pos;
3765 gst_ebml_write_seek (ebml, mux->duration_pos);
3766 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
3767 gst_ebml_write_seek (ebml, my_pos);
3769 GST_DEBUG_OBJECT (mux, "finishing segment");
3770 /* finish segment - this also writes element length */
3771 gst_ebml_write_master_finish (ebml, mux->segment_pos);
3775 * gst_matroska_mux_buffer_header:
3776 * @track: Track context.
3777 * @relative_timestamp: relative timestamp of the buffer
3778 * @flags: Buffer flags.
3780 * Create a buffer containing buffer header.
3782 * Returns: New buffer.
3785 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
3786 gint16 relative_timestamp, int flags)
3789 guint8 *data = g_malloc (4);
3791 hdr = gst_buffer_new_wrapped (data, 4);
3792 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
3793 data[0] = track->num | 0x80;
3794 /* time relative to clustertime */
3795 GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
3803 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
3804 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
3805 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
3808 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
3809 GstMatroskaPad * collect_pad, GstBuffer * buf)
3811 GstMatroskaTrackVideoContext *ctx =
3812 (GstMatroskaTrackVideoContext *) collect_pad->track;
3817 guint32 next_parse_offset;
3818 GstBuffer *ret = NULL;
3819 gboolean is_muxing_unit = FALSE;
3821 gst_buffer_map (buf, &map, GST_MAP_READ);
3826 gst_buffer_unmap (buf, &map);
3827 gst_buffer_unref (buf);
3831 /* Check if this buffer contains a picture or end-of-sequence packet */
3832 while (size >= 13) {
3833 if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
3834 gst_buffer_unmap (buf, &map);
3835 gst_buffer_unref (buf);
3839 parse_code = GST_READ_UINT8 (data + 4);
3840 if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
3841 if (ctx->dirac_unit) {
3842 gst_buffer_unref (ctx->dirac_unit);
3843 ctx->dirac_unit = NULL;
3845 } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
3846 parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
3847 is_muxing_unit = TRUE;
3851 next_parse_offset = GST_READ_UINT32_BE (data + 5);
3853 if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
3856 data += next_parse_offset;
3857 size -= next_parse_offset;
3860 if (ctx->dirac_unit)
3861 ctx->dirac_unit = gst_buffer_append (ctx->dirac_unit, gst_buffer_ref (buf));
3863 ctx->dirac_unit = gst_buffer_ref (buf);
3865 gst_buffer_unmap (buf, &map);
3867 if (is_muxing_unit) {
3868 ret = gst_buffer_make_writable (ctx->dirac_unit);
3869 ctx->dirac_unit = NULL;
3870 gst_buffer_copy_into (ret, buf,
3871 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
3872 gst_buffer_unref (buf);
3874 gst_buffer_unref (buf);
3882 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
3886 GValue streamheader = { 0 };
3887 GValue bufval = { 0 };
3888 GstBuffer *streamheader_buffer;
3889 GstEbmlWrite *ebml = mux->ebml_write;
3891 streamheader_buffer = gst_ebml_stop_streamheader (ebml);
3892 caps = gst_caps_copy (mux->ebml_write->caps);
3893 s = gst_caps_get_structure (caps, 0);
3894 g_value_init (&streamheader, GST_TYPE_ARRAY);
3895 g_value_init (&bufval, GST_TYPE_BUFFER);
3896 GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_HEADER);
3897 gst_value_set_buffer (&bufval, streamheader_buffer);
3898 gst_value_array_append_value (&streamheader, &bufval);
3899 g_value_unset (&bufval);
3900 gst_structure_set_value (s, "streamheader", &streamheader);
3901 g_value_unset (&streamheader);
3902 gst_caps_replace (&ebml->caps, caps);
3903 gst_buffer_unref (streamheader_buffer);
3904 gst_pad_set_caps (mux->srcpad, caps);
3905 gst_caps_unref (caps);
3909 * gst_matroska_mux_write_data:
3910 * @mux: #GstMatroskaMux
3911 * @collect_pad: #GstMatroskaPad with the data
3913 * Write collected data (called from gst_matroska_mux_collected).
3915 * Returns: Result of the gst_pad_push issued to write the data.
3917 static GstFlowReturn
3918 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
3921 GstEbmlWrite *ebml = mux->ebml_write;
3924 gboolean write_duration;
3925 guint64 cluster_time_scaled;
3926 gint16 relative_timestamp;
3927 gint64 relative_timestamp64;
3928 guint64 block_duration, duration_diff = 0;
3929 gboolean is_video_keyframe = FALSE;
3930 gboolean is_video_invisible = FALSE;
3931 gboolean is_audio_only = FALSE;
3932 gboolean is_min_duration_reached = FALSE;
3933 gboolean is_max_duration_exceeded = FALSE;
3934 GstMatroskamuxPad *pad;
3936 GstClockTime buffer_timestamp;
3937 GstAudioClippingMeta *cmeta = NULL;
3940 pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
3942 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
3943 if (collect_pad->track->xiph_headers_to_skip > 0) {
3944 --collect_pad->track->xiph_headers_to_skip;
3945 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER)) {
3946 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
3947 gst_buffer_unref (buf);
3952 /* for dirac we have to queue up everything up to a picture unit */
3953 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC)) {
3954 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
3957 } else if (!strcmp (collect_pad->track->codec_id,
3958 GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) {
3959 /* Remove the 'Frame container atom' header' */
3960 buf = gst_buffer_make_writable (buf);
3961 gst_buffer_resize (buf, 8, gst_buffer_get_size (buf) - 8);
3965 gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
3966 if (buffer_timestamp >= mux->earliest_time) {
3967 buffer_timestamp -= mux->earliest_time;
3969 buffer_timestamp = 0;
3972 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
3973 * this would wreak havoc with time stored in matroska file */
3974 /* TODO: maybe calculate a timestamp by using the previous timestamp
3975 * and default duration */
3976 if (!GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
3977 GST_WARNING_OBJECT (collect_pad->collect.pad,
3978 "Invalid buffer timestamp; dropping buffer");
3979 gst_buffer_unref (buf);
3983 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
3984 && collect_pad->track->codec_delay) {
3985 /* All timestamps should include the codec delay */
3986 if (buffer_timestamp > collect_pad->track->codec_delay) {
3987 buffer_timestamp += collect_pad->track->codec_delay;
3989 buffer_timestamp = 0;
3990 duration_diff = collect_pad->track->codec_delay - buffer_timestamp;
3994 /* set the timestamp for outgoing buffers */
3995 ebml->timestamp = buffer_timestamp;
3997 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
3998 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
3999 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
4000 GST_TIME_ARGS (buffer_timestamp));
4001 is_video_keyframe = TRUE;
4002 } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DECODE_ONLY) &&
4003 (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP8)
4004 || !strcmp (collect_pad->track->codec_id,
4005 GST_MATROSKA_CODEC_ID_VIDEO_VP9))) {
4006 GST_LOG_OBJECT (mux,
4007 "have VP8 video invisible frame, " "ts=%" GST_TIME_FORMAT,
4008 GST_TIME_ARGS (buffer_timestamp));
4009 is_video_invisible = TRUE;
4013 /* From this point on we use the buffer_timestamp to do cluster and other
4014 * related arithmetic, so apply the timestamp offset if we have one */
4015 buffer_timestamp += mux->cluster_timestamp_offset;
4017 is_audio_only = (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
4018 (mux->num_streams == 1);
4019 is_min_duration_reached = (mux->min_cluster_duration == 0
4020 || (buffer_timestamp > mux->cluster_time
4021 && (buffer_timestamp - mux->cluster_time) >=
4022 mux->min_cluster_duration));
4023 is_max_duration_exceeded = (mux->max_cluster_duration > 0
4024 && buffer_timestamp > mux->cluster_time
4025 && (buffer_timestamp - mux->cluster_time) >=
4026 MIN (G_MAXINT16 * mux->time_scale, mux->max_cluster_duration));
4029 /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
4030 * or when we may be reaching the limit of the relative timestamp */
4031 if (is_max_duration_exceeded || (is_video_keyframe
4032 && is_min_duration_reached) || mux->force_key_unit_event
4033 || (is_audio_only && is_min_duration_reached)) {
4034 if (!mux->ebml_write->streamable)
4035 gst_ebml_write_master_finish (ebml, mux->cluster);
4037 /* Forward the GstForceKeyUnit event after finishing the cluster */
4038 if (mux->force_key_unit_event) {
4039 gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
4040 mux->force_key_unit_event = NULL;
4042 cluster_time_scaled =
4043 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4045 mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
4046 mux->cluster_pos = ebml->pos;
4047 gst_ebml_write_set_cache (ebml, 0x20);
4049 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4050 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4051 cluster_time_scaled);
4052 GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
4053 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
4054 gst_ebml_write_flush_cache (ebml, is_video_keyframe
4055 || is_audio_only, buffer_timestamp);
4056 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
4057 mux->prev_cluster_size);
4058 /* cluster_time needs to be identical in value to what's stored in the
4059 * matroska so we need to have it with the same precision as what's
4060 * possible with the set timecodescale rather than just using the
4062 * If this is not done the rounding of relative_timestamp will be
4063 * incorrect and possibly making the timestamps get out of order if tw
4064 * buffers arrive at the same millisecond (assuming default timecodescale
4067 gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4071 cluster_time_scaled =
4072 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4073 mux->cluster_pos = ebml->pos;
4074 gst_ebml_write_set_cache (ebml, 0x20);
4075 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4076 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4077 cluster_time_scaled);
4078 gst_ebml_write_flush_cache (ebml, TRUE, buffer_timestamp);
4079 /* cluster_time needs to be identical in value to what's stored in the
4080 * matroska so we need to have it with the same precision as what's
4081 * possible with the set timecodescale rather than just using the
4083 * If this is not done the rounding of relative_timestamp will be
4084 * incorrect and possibly making the timestamps get out of order if tw
4085 * buffers arrive at the same millisecond (assuming default timecodescale
4088 gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4091 /* We currently write index entries for all video tracks or for the audio
4092 * track in a single-track audio file. This could be improved by keeping the
4093 * index only for the *first* video track. */
4095 /* TODO: index is useful for every track, should contain the number of
4096 * the block in the cluster which contains the timestamp, should also work
4097 * for files with multiple audio tracks.
4099 if (!mux->ebml_write->streamable && (is_video_keyframe || is_audio_only)) {
4102 if (mux->min_index_interval != 0) {
4103 for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
4104 if (mux->index[last_idx].track == collect_pad->track->num)
4109 if (last_idx < 0 || mux->min_index_interval == 0 ||
4110 (GST_CLOCK_DIFF (mux->index[last_idx].time, buffer_timestamp)
4111 >= mux->min_index_interval)) {
4112 GstMatroskaIndex *idx;
4114 if (mux->num_indexes % 32 == 0) {
4115 mux->index = g_renew (GstMatroskaIndex, mux->index,
4116 mux->num_indexes + 32);
4118 idx = &mux->index[mux->num_indexes++];
4120 idx->pos = mux->cluster_pos;
4121 idx->time = buffer_timestamp;
4122 idx->track = collect_pad->track->num;
4126 /* Check if the duration differs from the default duration. */
4127 write_duration = FALSE;
4129 if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
4130 block_duration = GST_BUFFER_DURATION (buf) + duration_diff;
4131 block_duration = gst_util_uint64_scale (block_duration, 1, mux->time_scale);
4133 /* small difference should be ok. */
4134 if (block_duration > collect_pad->default_duration_scaled + 1 ||
4135 block_duration < collect_pad->default_duration_scaled - 1) {
4136 write_duration = TRUE;
4140 /* write the block, for doctype v2 use SimpleBlock if possible
4141 * one slice (*breath*).
4142 * FIXME: Need to do correct lacing! */
4143 relative_timestamp64 = buffer_timestamp - mux->cluster_time;
4144 if (relative_timestamp64 >= 0) {
4145 /* round the timestamp */
4146 relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
4147 relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
4150 /* round the timestamp */
4151 relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
4152 relative_timestamp =
4153 -((gint16) gst_util_uint64_scale (-relative_timestamp64, 1,
4157 if (is_video_invisible)
4160 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
4161 cmeta = gst_buffer_get_audio_clipping_meta (buf);
4162 g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);
4164 /* Start clipping is done via header and CodecDelay */
4165 if (cmeta && !cmeta->end)
4169 if (mux->doctype_version > 1 && !write_duration && !cmeta) {
4170 if (is_video_keyframe)
4174 gst_matroska_mux_create_buffer_header (collect_pad->track,
4175 relative_timestamp, flags);
4176 gst_ebml_write_set_cache (ebml, 0x40);
4177 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
4178 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4179 gst_ebml_write_buffer (ebml, hdr);
4180 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4181 gst_ebml_write_buffer (ebml, buf);
4183 return gst_ebml_last_write_result (ebml);
4185 gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
4186 /* write and call order slightly unnatural,
4187 * but avoids seek and minizes pushing */
4188 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
4190 gst_matroska_mux_create_buffer_header (collect_pad->track,
4191 relative_timestamp, flags);
4193 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
4195 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4197 /* Start clipping is done via header and CodecDelay */
4200 gst_util_uint64_scale_round (cmeta->end, GST_SECOND, 48000);
4201 gst_ebml_write_sint (ebml, GST_MATROSKA_ID_DISCARDPADDING, end);
4205 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
4206 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4207 gst_ebml_write_buffer (ebml, hdr);
4208 gst_ebml_write_master_finish_full (ebml, blockgroup,
4209 gst_buffer_get_size (buf));
4210 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4211 gst_ebml_write_buffer (ebml, buf);
4213 return gst_ebml_last_write_result (ebml);
4218 * gst_matroska_mux_handle_buffer:
4219 * @pads: #GstCollectPads
4220 * @uuser_data: #GstMatroskaMux
4222 * Collectpads callback.
4224 * Returns: #GstFlowReturn
4226 static GstFlowReturn
4227 gst_matroska_mux_handle_buffer (GstCollectPads * pads, GstCollectData * data,
4228 GstBuffer * buf, gpointer user_data)
4230 GstClockTime buffer_timestamp;
4231 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
4232 GstEbmlWrite *ebml = mux->ebml_write;
4233 GstMatroskaPad *best = (GstMatroskaPad *) data;
4234 GstFlowReturn ret = GST_FLOW_OK;
4235 GST_DEBUG_OBJECT (mux, "Collected pads");
4237 /* start with a header */
4238 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
4239 if (mux->collect->data == NULL) {
4240 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
4241 ("No input streams configured"));
4242 return GST_FLOW_ERROR;
4244 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
4245 gst_ebml_start_streamheader (ebml);
4246 gst_matroska_mux_start (mux, best, buf);
4247 gst_matroska_mux_stop_streamheader (mux);
4248 mux->state = GST_MATROSKA_MUX_STATE_DATA;
4251 /* if there is no best pad, we have reached EOS */
4253 GST_DEBUG_OBJECT (mux, "No best pad. Finishing...");
4254 if (!mux->ebml_write->streamable) {
4255 gst_matroska_mux_finish (mux);
4257 GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
4259 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
4264 if (best->track->codec_id == NULL) {
4265 GST_ERROR_OBJECT (best->collect.pad, "No codec-id for pad");
4266 ret = GST_FLOW_NOT_NEGOTIATED;
4270 /* if we have a best stream, should also have a buffer */
4273 buffer_timestamp = gst_matroska_track_get_buffer_timestamp (best->track, buf);
4274 if (buffer_timestamp >= mux->earliest_time) {
4275 buffer_timestamp -= mux->earliest_time;
4277 GST_ERROR_OBJECT (mux,
4278 "PTS before first PTS (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")",
4279 GST_TIME_ARGS (buffer_timestamp), GST_TIME_ARGS (mux->earliest_time));
4280 buffer_timestamp = 0;
4283 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
4284 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
4285 GST_TIME_ARGS (buffer_timestamp),
4286 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
4288 /* make note of first and last encountered timestamps, so we can calculate
4289 * the actual duration later when we send an updated header on eos */
4290 if (GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
4291 GstClockTime start_ts = buffer_timestamp;
4292 GstClockTime end_ts = start_ts;
4294 if (GST_BUFFER_DURATION_IS_VALID (buf))
4295 end_ts += GST_BUFFER_DURATION (buf);
4296 else if (best->track->default_duration)
4297 end_ts += best->track->default_duration;
4299 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
4300 best->end_ts = end_ts;
4302 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
4303 start_ts < best->start_ts))
4304 best->start_ts = start_ts;
4307 /* write one buffer */
4308 ret = gst_matroska_mux_write_data (mux, best, buf);
4316 * gst_matroska_mux_change_state:
4317 * @element: #GstMatroskaMux
4318 * @transition: State change transition.
4320 * Change the muxer state.
4322 * Returns: #GstStateChangeReturn
4324 static GstStateChangeReturn
4325 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
4327 GstStateChangeReturn ret;
4328 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
4330 switch (transition) {
4331 case GST_STATE_CHANGE_NULL_TO_READY:
4333 case GST_STATE_CHANGE_READY_TO_PAUSED:
4334 gst_collect_pads_start (mux->collect);
4336 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4338 case GST_STATE_CHANGE_PAUSED_TO_READY:
4339 gst_collect_pads_stop (mux->collect);
4345 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4347 switch (transition) {
4348 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4350 case GST_STATE_CHANGE_PAUSED_TO_READY:
4351 gst_matroska_mux_reset (GST_ELEMENT (mux));
4353 case GST_STATE_CHANGE_READY_TO_NULL:
4363 gst_matroska_mux_set_property (GObject * object,
4364 guint prop_id, const GValue * value, GParamSpec * pspec)
4366 GstMatroskaMux *mux;
4368 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4369 mux = GST_MATROSKA_MUX (object);
4372 case PROP_WRITING_APP:
4373 if (!g_value_get_string (value)) {
4374 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
4377 g_free (mux->writing_app);
4378 mux->writing_app = g_value_dup_string (value);
4380 case PROP_DOCTYPE_VERSION:
4381 mux->doctype_version = g_value_get_int (value);
4383 case PROP_MIN_INDEX_INTERVAL:
4384 mux->min_index_interval = g_value_get_int64 (value);
4386 case PROP_STREAMABLE:
4387 mux->ebml_write->streamable = g_value_get_boolean (value);
4389 case PROP_TIMECODESCALE:
4390 mux->time_scale = g_value_get_int64 (value);
4392 case PROP_MIN_CLUSTER_DURATION:
4393 mux->min_cluster_duration = g_value_get_int64 (value);
4395 case PROP_MAX_CLUSTER_DURATION:
4396 mux->max_cluster_duration = g_value_get_int64 (value);
4398 case PROP_OFFSET_TO_ZERO:
4399 mux->offset_to_zero = g_value_get_boolean (value);
4401 case PROP_CREATION_TIME:
4402 g_clear_pointer (&mux->creation_time, g_date_time_unref);
4403 mux->creation_time = g_value_dup_boxed (value);
4405 case PROP_CLUSTER_TIMESTAMP_OFFSET:
4406 mux->cluster_timestamp_offset = g_value_get_uint64 (value);
4409 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4415 gst_matroska_mux_get_property (GObject * object,
4416 guint prop_id, GValue * value, GParamSpec * pspec)
4418 GstMatroskaMux *mux;
4420 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4421 mux = GST_MATROSKA_MUX (object);
4424 case PROP_WRITING_APP:
4425 g_value_set_string (value, mux->writing_app);
4427 case PROP_DOCTYPE_VERSION:
4428 g_value_set_int (value, mux->doctype_version);
4430 case PROP_MIN_INDEX_INTERVAL:
4431 g_value_set_int64 (value, mux->min_index_interval);
4433 case PROP_STREAMABLE:
4434 g_value_set_boolean (value, mux->ebml_write->streamable);
4436 case PROP_TIMECODESCALE:
4437 g_value_set_int64 (value, mux->time_scale);
4439 case PROP_MIN_CLUSTER_DURATION:
4440 g_value_set_int64 (value, mux->min_cluster_duration);
4442 case PROP_MAX_CLUSTER_DURATION:
4443 g_value_set_int64 (value, mux->max_cluster_duration);
4445 case PROP_OFFSET_TO_ZERO:
4446 g_value_set_boolean (value, mux->offset_to_zero);
4448 case PROP_CREATION_TIME:
4449 g_value_set_boxed (value, mux->creation_time);
4451 case PROP_CLUSTER_TIMESTAMP_OFFSET:
4452 g_value_set_uint64 (value, mux->cluster_timestamp_offset);
4455 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);