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, " "alignment = (string) \"tu\", " COMMON_VIDEO_CAPS ";"
150 "video/x-ffv, ffversion = (int) 1, " COMMON_VIDEO_CAPS)
153 #define COMMON_AUDIO_CAPS \
154 "channels = (int) [ 1, MAX ], " \
155 "rate = (int) [ 1, MAX ]"
158 * * require codec data, etc as needed
160 static GstStaticPadTemplate audiosink_templ =
161 GST_STATIC_PAD_TEMPLATE ("audio_%u",
164 GST_STATIC_CAPS ("audio/mpeg, "
165 "mpegversion = (int) 1, "
166 "layer = (int) [ 1, 3 ], "
167 COMMON_AUDIO_CAPS "; "
169 "mpegversion = (int) { 2, 4 }, "
170 "stream-format = (string) raw, "
171 COMMON_AUDIO_CAPS "; "
173 COMMON_AUDIO_CAPS "; "
175 COMMON_AUDIO_CAPS "; "
177 COMMON_AUDIO_CAPS "; "
179 COMMON_AUDIO_CAPS "; "
181 COMMON_AUDIO_CAPS "; "
184 COMMON_AUDIO_CAPS "; "
186 "format = (string) { U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }, "
187 "layout = (string) interleaved, "
188 COMMON_AUDIO_CAPS ";"
190 "width = (int) { 8, 16, 24 }, "
191 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
192 "audio/x-pn-realaudio, "
193 "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS "; "
194 "audio/x-wma, " "wmaversion = (int) [ 1, 3 ], "
195 "block_align = (int) [ 0, 65535 ], bitrate = (int) [ 0, 524288 ], "
196 COMMON_AUDIO_CAPS ";"
198 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
200 "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
202 "layout = (string)dvi, "
203 "block_align = (int)[64, 8192], "
204 "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
206 "channels = (int)1," "rate = (int)16000; "
208 "layout = (string)g726, " "channels = (int)1," "rate = (int)8000; ")
211 static GstStaticPadTemplate subtitlesink_templ =
212 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
215 GST_STATIC_CAPS ("subtitle/x-kate; "
216 "text/x-raw, format=utf8; application/x-ssa; application/x-ass; "
217 "application/x-usf; subpicture/x-dvd; "
218 "application/x-subtitle-unknown")
221 static gpointer parent_class; /* NULL */
223 /* Matroska muxer destructor */
224 static void gst_matroska_mux_class_init (GstMatroskaMuxClass * klass);
225 static void gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class);
226 static void gst_matroska_mux_finalize (GObject * object);
228 /* Pads collected callback */
229 static GstFlowReturn gst_matroska_mux_handle_buffer (GstCollectPads * pads,
230 GstCollectData * data, GstBuffer * buf, gpointer user_data);
231 static gboolean gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
232 GstCollectData * data, GstEvent * event, gpointer user_data);
235 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
236 GstObject * parent, GstEvent * event);
237 static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
238 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
239 static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
241 /* gst internal change state handler */
242 static GstStateChangeReturn
243 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
245 /* gobject bla bla */
246 static void gst_matroska_mux_set_property (GObject * object,
247 guint prop_id, const GValue * value, GParamSpec * pspec);
248 static void gst_matroska_mux_get_property (GObject * object,
249 guint prop_id, GValue * value, GParamSpec * pspec);
252 static void gst_matroska_mux_reset (GstElement * element);
255 static guint64 gst_matroska_mux_create_uid (GstMatroskaMux * mux);
257 static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
258 GstMatroskaTrackContext * context);
259 static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
260 GstMatroskaTrackContext * context);
261 static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
262 GstMatroskaTrackContext * context);
263 static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
264 GstMatroskaTrackContext * context);
265 static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
266 GstMatroskaTrackContext * context);
268 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
270 static gboolean gst_matroska_mux_tag_list_is_empty (const GstTagList * list);
271 static void gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux);
272 static gboolean gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux);
274 /* Cannot use boilerplate macros here because we need the full init function
275 * signature with the additional class argument, so we use the right template
276 * for the sink caps */
278 gst_matroska_mux_get_type (void)
280 static GType object_type; /* 0 */
282 if (object_type == 0) {
283 static const GTypeInfo object_info = {
284 sizeof (GstMatroskaMuxClass),
285 NULL, /* base_init */
286 NULL, /* base_finalize */
287 (GClassInitFunc) gst_matroska_mux_class_init,
288 NULL, /* class_finalize */
289 NULL, /* class_data */
290 sizeof (GstMatroskaMux),
292 (GInstanceInitFunc) gst_matroska_mux_init
294 const GInterfaceInfo iface_info = { NULL };
296 object_type = g_type_register_static (GST_TYPE_ELEMENT,
297 "GstMatroskaMux", &object_info, (GTypeFlags) 0);
299 g_type_add_interface_static (object_type, GST_TYPE_TAG_SETTER, &iface_info);
300 g_type_add_interface_static (object_type, GST_TYPE_TOC_SETTER, &iface_info);
306 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (matroskamux, "matroskamux",
307 GST_RANK_PRIMARY, GST_TYPE_MATROSKA_MUX, matroska_element_init (plugin));
310 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
312 GObjectClass *gobject_class;
313 GstElementClass *gstelement_class;
315 gobject_class = (GObjectClass *) klass;
316 gstelement_class = (GstElementClass *) klass;
318 gst_element_class_add_static_pad_template (gstelement_class,
320 gst_element_class_add_static_pad_template (gstelement_class,
322 gst_element_class_add_static_pad_template (gstelement_class,
323 &subtitlesink_templ);
324 gst_element_class_add_static_pad_template (gstelement_class, &src_templ);
325 gst_element_class_set_static_metadata (gstelement_class, "Matroska muxer",
327 "Muxes video/audio/subtitle streams into a matroska stream",
328 "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
330 GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
333 gobject_class->finalize = gst_matroska_mux_finalize;
335 gobject_class->get_property = gst_matroska_mux_get_property;
336 gobject_class->set_property = gst_matroska_mux_set_property;
338 g_object_class_install_property (gobject_class, PROP_WRITING_APP,
339 g_param_spec_string ("writing-app", "Writing application.",
340 "The name the application that creates the matroska file.",
341 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
342 g_object_class_install_property (gobject_class, PROP_DOCTYPE_VERSION,
343 g_param_spec_int ("version", "DocType version",
344 "This parameter determines what Matroska features can be used.",
345 1, 2, DEFAULT_DOCTYPE_VERSION,
346 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
347 g_object_class_install_property (gobject_class, PROP_MIN_INDEX_INTERVAL,
348 g_param_spec_int64 ("min-index-interval", "Minimum time between index "
349 "entries", "An index entry is created every so many nanoseconds.",
350 0, G_MAXINT64, DEFAULT_MIN_INDEX_INTERVAL,
351 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
352 g_object_class_install_property (gobject_class, PROP_STREAMABLE,
353 g_param_spec_boolean ("streamable", "Determines whether output should "
354 "be streamable", "If set to true, the output should be as if it is "
355 "to be streamed and hence no indexes written or duration written.",
356 DEFAULT_STREAMABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
357 g_object_class_install_property (gobject_class, PROP_TIMECODESCALE,
358 g_param_spec_int64 ("timecodescale", "Timecode Scale",
359 "TimecodeScale used to calculate the Raw Timecode of a Block", 1,
360 GST_SECOND, DEFAULT_TIMECODESCALE,
361 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
362 g_object_class_install_property (gobject_class, PROP_MIN_CLUSTER_DURATION,
363 g_param_spec_int64 ("min-cluster-duration", "Minimum cluster duration",
364 "Desired cluster duration as nanoseconds. A new cluster will be "
365 "created irrespective of this property if a force key unit event "
366 "is received. 0 means create a new cluster for each video keyframe "
367 "or for each audio buffer in audio only streams.", 0,
368 G_MAXINT64, DEFAULT_MIN_CLUSTER_DURATION,
369 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
370 g_object_class_install_property (gobject_class, PROP_MAX_CLUSTER_DURATION,
371 g_param_spec_int64 ("max-cluster-duration", "Maximum cluster duration",
372 "A new cluster will be created if its duration exceeds this value. "
373 "0 means no maximum duration.", 0,
374 G_MAXINT64, DEFAULT_MAX_CLUSTER_DURATION,
375 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
376 g_object_class_install_property (gobject_class, PROP_OFFSET_TO_ZERO,
377 g_param_spec_boolean ("offset-to-zero", "Offset To Zero",
378 "Offsets all streams so that the " "earliest stream starts at 0.",
379 DEFAULT_OFFSET_TO_ZERO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
380 g_object_class_install_property (gobject_class, PROP_CREATION_TIME,
381 g_param_spec_boxed ("creation-time", "Creation Time",
382 "Date and time of creation. This will be used for the DateUTC field."
383 " NULL means that the current time will be used.",
384 G_TYPE_DATE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
387 * GstMatroskaMux:cluster-timestamp-offset:
389 * An offset to add to all clusters/blocks (in nanoseconds)
393 g_object_class_install_property (gobject_class, PROP_CLUSTER_TIMESTAMP_OFFSET,
394 g_param_spec_uint64 ("cluster-timestamp-offset",
395 "Cluster timestamp offset",
396 "An offset to add to all clusters/blocks (in nanoseconds)", 0,
397 G_MAXUINT64, DEFAULT_CLUSTER_TIMESTAMP_OFFSET,
398 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
400 gstelement_class->change_state =
401 GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
402 gstelement_class->request_new_pad =
403 GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
404 gstelement_class->release_pad =
405 GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
407 parent_class = g_type_class_peek_parent (klass);
411 * Start of pad option handler code
413 #define DEFAULT_PAD_FRAME_DURATION TRUE
418 PROP_PAD_FRAME_DURATION
424 gboolean frame_duration;
425 gboolean frame_duration_user;
428 typedef GstPadClass GstMatroskamuxPadClass;
430 GType gst_matroskamux_pad_get_type (void);
431 G_DEFINE_TYPE (GstMatroskamuxPad, gst_matroskamux_pad, GST_TYPE_PAD);
433 #define GST_TYPE_MATROSKAMUX_PAD (gst_matroskamux_pad_get_type())
434 #define GST_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_MATROSKAMUX_PAD,GstMatroskamuxPad))
435 #define GST_MATROSKAMUX_PAD_CAST(pad) ((GstMatroskamuxPad *) pad)
436 #define GST_IS_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_MATROSKAMUX_PAD))
439 gst_matroskamux_pad_get_property (GObject * object, guint prop_id,
440 GValue * value, GParamSpec * pspec)
442 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
445 case PROP_PAD_FRAME_DURATION:
446 g_value_set_boolean (value, pad->frame_duration);
449 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
455 gst_matroskamux_pad_set_property (GObject * object, guint prop_id,
456 const GValue * value, GParamSpec * pspec)
458 GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
461 case PROP_PAD_FRAME_DURATION:
462 pad->frame_duration = g_value_get_boolean (value);
463 pad->frame_duration_user = TRUE;
466 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
472 gst_matroskamux_pad_class_init (GstMatroskamuxPadClass * klass)
474 GObjectClass *gobject_class = (GObjectClass *) klass;
476 gobject_class->set_property = gst_matroskamux_pad_set_property;
477 gobject_class->get_property = gst_matroskamux_pad_get_property;
479 g_object_class_install_property (gobject_class, PROP_PAD_FRAME_DURATION,
480 g_param_spec_boolean ("frame-duration", "Frame duration",
481 "Default frame duration", DEFAULT_PAD_FRAME_DURATION,
482 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
486 gst_matroskamux_pad_init (GstMatroskamuxPad * pad)
488 pad->frame_duration = DEFAULT_PAD_FRAME_DURATION;
489 pad->frame_duration_user = FALSE;
493 * End of pad option handler code
497 gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class)
499 GstPadTemplate *templ;
502 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
503 mux->srcpad = gst_pad_new_from_template (templ, "src");
505 gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
506 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
507 gst_pad_use_fixed_caps (mux->srcpad);
509 mux->collect = gst_collect_pads_new ();
510 gst_collect_pads_set_clip_function (mux->collect,
511 GST_DEBUG_FUNCPTR (gst_collect_pads_clip_running_time), mux);
512 gst_collect_pads_set_buffer_function (mux->collect,
513 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_buffer), mux);
514 gst_collect_pads_set_event_function (mux->collect,
515 GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event), mux);
517 mux->ebml_write = gst_ebml_write_new (mux->srcpad);
518 mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
520 /* property defaults */
521 mux->doctype_version = DEFAULT_DOCTYPE_VERSION;
522 mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
523 mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
524 mux->ebml_write->streamable = DEFAULT_STREAMABLE;
525 mux->time_scale = DEFAULT_TIMECODESCALE;
526 mux->min_cluster_duration = DEFAULT_MIN_CLUSTER_DURATION;
527 mux->max_cluster_duration = DEFAULT_MAX_CLUSTER_DURATION;
528 mux->cluster_timestamp_offset = DEFAULT_CLUSTER_TIMESTAMP_OFFSET;
530 /* initialize internal variables */
532 mux->num_streams = 0;
533 mux->num_a_streams = 0;
534 mux->num_t_streams = 0;
535 mux->num_v_streams = 0;
536 mux->internal_toc = NULL;
538 /* initialize remaining variables */
539 gst_matroska_mux_reset (GST_ELEMENT (mux));
544 * gst_matroska_mux_finalize:
545 * @object: #GstMatroskaMux that should be finalized.
547 * Finalize matroska muxer.
550 gst_matroska_mux_finalize (GObject * object)
552 GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
554 gst_event_replace (&mux->force_key_unit_event, NULL);
556 gst_object_unref (mux->collect);
557 gst_object_unref (mux->ebml_write);
558 g_free (mux->writing_app);
559 g_clear_pointer (&mux->creation_time, g_date_time_unref);
561 if (mux->internal_toc) {
562 gst_toc_unref (mux->internal_toc);
563 mux->internal_toc = NULL;
566 G_OBJECT_CLASS (parent_class)->finalize (object);
571 * gst_matroska_mux_create_uid:
572 * @mux: #GstMatroskaMux to generate UID for.
574 * Generate new track UID.
576 * Returns: New track UID.
579 gst_matroska_mux_create_uid (GstMatroskaMux * mux)
581 return (((guint64) g_random_int ()) << 32) | g_random_int ();
586 * gst_matroska_pad_reset:
587 * @collect_pad: the #GstMatroskaPad
589 * Reset and/or release resources of a matroska collect pad.
592 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
595 GstMatroskaTrackType type = 0;
597 /* free track information */
598 if (collect_pad->track != NULL) {
599 /* retrieve for optional later use */
600 name = collect_pad->track->name;
601 type = collect_pad->track->type;
602 /* extra for video */
603 if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
604 GstMatroskaTrackVideoContext *ctx =
605 (GstMatroskaTrackVideoContext *) collect_pad->track;
607 if (ctx->dirac_unit) {
608 gst_buffer_unref (ctx->dirac_unit);
609 ctx->dirac_unit = NULL;
612 g_free (collect_pad->track->codec_id);
613 g_free (collect_pad->track->codec_name);
615 g_free (collect_pad->track->name);
616 g_free (collect_pad->track->language);
617 g_free (collect_pad->track->codec_priv);
618 g_free (collect_pad->track);
619 collect_pad->track = NULL;
620 if (collect_pad->tags) {
621 gst_tag_list_unref (collect_pad->tags);
622 collect_pad->tags = NULL;
626 if (!full && type != 0) {
627 GstMatroskaTrackContext *context;
629 /* create a fresh context */
631 case GST_MATROSKA_TRACK_TYPE_VIDEO:
632 context = (GstMatroskaTrackContext *)
633 g_new0 (GstMatroskaTrackVideoContext, 1);
635 case GST_MATROSKA_TRACK_TYPE_AUDIO:
636 context = (GstMatroskaTrackContext *)
637 g_new0 (GstMatroskaTrackAudioContext, 1);
639 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
640 context = (GstMatroskaTrackContext *)
641 g_new0 (GstMatroskaTrackSubtitleContext, 1);
644 g_assert_not_reached ();
648 context->type = type;
649 context->name = name;
650 context->uid = gst_matroska_mux_create_uid (collect_pad->mux);
651 /* TODO: check default values for the context */
652 context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
653 collect_pad->track = context;
654 collect_pad->start_ts = GST_CLOCK_TIME_NONE;
655 collect_pad->end_ts = GST_CLOCK_TIME_NONE;
656 collect_pad->tags = gst_tag_list_new_empty ();
657 gst_tag_list_set_scope (collect_pad->tags, GST_TAG_SCOPE_STREAM);
662 * gst_matroska_pad_free:
663 * @collect_pad: the #GstMatroskaPad
665 * Release resources of a matroska collect pad.
668 gst_matroska_pad_free (GstPad * collect_pad)
670 gst_matroska_pad_reset ((GstMatroskaPad *) collect_pad, TRUE);
675 * gst_matroska_mux_reset:
676 * @element: #GstMatroskaMux that should be reset.
678 * Reset matroska muxer back to initial state.
681 gst_matroska_mux_reset (GstElement * element)
683 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
686 /* reset EBML write */
687 gst_ebml_write_reset (mux->ebml_write);
690 mux->state = GST_MATROSKA_MUX_STATE_START;
692 /* clean up existing streams */
694 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
695 GstMatroskaPad *collect_pad;
697 collect_pad = (GstMatroskaPad *) walk->data;
699 /* reset collect pad to pristine state */
700 gst_matroska_pad_reset (collect_pad, FALSE);
704 mux->num_indexes = 0;
713 mux->cluster_time = 0;
714 mux->cluster_pos = 0;
715 mux->prev_cluster_size = 0;
718 gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
723 gst_toc_setter_reset (GST_TOC_SETTER (mux));
724 if (mux->internal_toc) {
725 gst_toc_unref (mux->internal_toc);
726 mux->internal_toc = NULL;
729 mux->chapters_pos = 0;
733 * gst_matroska_mux_handle_src_event:
734 * @pad: Pad which received the event.
735 * @event: Received event.
737 * handle events - copied from oggmux without understanding
739 * Returns: %TRUE on success.
742 gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
747 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
751 /* disable seeking for now */
757 return gst_pad_event_default (pad, parent, event);
762 gst_matroska_mux_free_codec_priv (GstMatroskaTrackContext * context)
764 if (context->codec_priv != NULL) {
765 g_free (context->codec_priv);
766 context->codec_priv = NULL;
767 context->codec_priv_size = 0;
772 gst_matroska_mux_build_vobsub_private (GstMatroskaTrackContext * context,
782 /* produce comma-separated list in hex format */
783 for (i = 0; i < 16; ++i) {
785 /* replicate vobsub's slightly off RGB conversion calculation */
786 y = (((col >> 16) & 0xff) - 16) * 255 / 219;
787 u = ((col >> 8) & 0xff) - 128;
788 v = (col & 0xff) - 128;
789 r = CLAMP (1.0 * y + 1.4022 * u, 0, 255);
790 g = CLAMP (1.0 * y - 0.3456 * u - 0.7145 * v, 0, 255);
791 b = CLAMP (1.0 * y + 1.7710 * v, 0, 255);
792 clutv[i] = g_strdup_printf ("%02x%02x%02x", r, g, b);
795 sclut = g_strjoinv (",", clutv);
797 /* build codec private; only palette for now */
798 gst_matroska_mux_free_codec_priv (context);
799 context->codec_priv = (guint8 *) g_strdup_printf ("palette: %s", sclut);
800 /* include terminating 0 */
801 context->codec_priv_size = strlen ((gchar *) context->codec_priv) + 1;
803 for (i = 0; i < 16; ++i) {
810 * gst_matroska_mux_handle_sink_event:
811 * @pad: Pad which received the event.
812 * @event: Received event.
814 * handle events - informational ones like tags
816 * Returns: %TRUE on success.
819 gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
820 GstCollectData * data, GstEvent * event, gpointer user_data)
822 GstMatroskaPad *collect_pad;
823 GstMatroskaTrackContext *context;
829 mux = GST_MATROSKA_MUX (user_data);
830 collect_pad = (GstMatroskaPad *) data;
832 context = collect_pad->track;
835 switch (GST_EVENT_TYPE (event)) {
836 case GST_EVENT_CAPS:{
839 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
840 gst_event_parse_caps (event, &caps);
842 ret = collect_pad->capsfunc (pad, caps);
843 gst_event_unref (event);
850 GST_DEBUG_OBJECT (mux, "received tag event");
851 gst_event_parse_tag (event, &list);
853 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
854 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
855 const gchar *lang_code;
857 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
859 GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
860 g_free (context->language);
861 context->language = g_strdup (lang_code);
863 GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
868 if (gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL) {
869 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
870 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
874 /* Stream specific tags */
875 gst_tag_list_insert (collect_pad->tags, list, GST_TAG_MERGE_REPLACE);
877 /* If the tags contain a title, update the context name to write it there */
878 if (gst_tag_list_get_string (list, GST_TAG_TITLE, &title)) {
879 GST_INFO_OBJECT (pad, "Setting track name to '%s'", title);
880 g_free (context->name);
881 context->name = g_strdup (title);
886 gst_event_unref (event);
887 /* handled this, don't want collectpads to forward it downstream */
893 GstToc *toc, *old_toc;
895 if (mux->chapters_pos > 0)
898 GST_DEBUG_OBJECT (mux, "received toc event");
899 gst_event_parse_toc (event, &toc, NULL);
902 old_toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
903 if (old_toc != NULL) {
905 GST_INFO_OBJECT (pad, "Replacing TOC with a new one");
906 gst_toc_unref (old_toc);
909 gst_toc_setter_set_toc (GST_TOC_SETTER (mux), toc);
913 gst_event_unref (event);
914 /* handled this, don't want collectpads to forward it downstream */
918 case GST_EVENT_CUSTOM_DOWNSTREAM:
919 case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY:{
920 const GstStructure *structure;
922 structure = gst_event_get_structure (event);
923 if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
924 gst_event_replace (&mux->force_key_unit_event, NULL);
925 mux->force_key_unit_event = event;
927 } else if (gst_structure_has_name (structure, "application/x-gst-dvd") &&
928 !strcmp ("dvd-spu-clut-change",
929 gst_structure_get_string (structure, "event"))) {
934 GST_DEBUG_OBJECT (pad, "New DVD colour table received");
935 if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
936 GST_DEBUG_OBJECT (pad, "... discarding");
939 /* first transform event data into table form */
940 for (i = 0; i < 16; i++) {
941 g_snprintf (name, sizeof (name), "clut%02d", i);
942 if (!gst_structure_get_int (structure, name, &value)) {
943 GST_ERROR_OBJECT (mux, "dvd-spu-clut-change event did not "
944 "contain %s field", name);
950 /* transform into private data for stream; text form */
951 gst_matroska_mux_build_vobsub_private (context, clut);
961 return gst_collect_pads_event_default (pads, data, event, FALSE);
967 gst_matroska_mux_set_codec_id (GstMatroskaTrackContext * context,
970 g_assert (context && id);
971 g_free (context->codec_id);
972 context->codec_id = g_strdup (id);
976 check_field (GQuark field_id, const GValue * value, gpointer user_data)
978 GstStructure *structure = (GstStructure *) user_data;
979 const gchar *name = gst_structure_get_name (structure);
981 if ((g_strcmp0 (name, "video/x-h264") == 0 &&
982 !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
983 "avc3")) || (g_strcmp0 (name, "video/x-h265") == 0
984 && !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
987 /* While in theory, matroska only supports avc1 / hvc1, and doesn't support codec_data
988 * changes, in practice most decoders will use in-band SPS / PPS (avc3 / hev1), if the
989 * input stream is avc3 / hev1 we let the new codec_data slide to support "smart" encoding.
991 * We don't warn here as we already warned elsewhere.
993 if (field_id == g_quark_from_static_string ("codec_data")) {
995 } else if (field_id == g_quark_from_static_string ("tier")) {
997 } else if (field_id == g_quark_from_static_string ("profile")) {
999 } else if (field_id == g_quark_from_static_string ("level")) {
1001 } else if (field_id == g_quark_from_static_string ("width")) {
1003 } else if (field_id == g_quark_from_static_string ("height")) {
1006 } else if (gst_structure_has_name (structure, "video/x-vp8")
1007 || gst_structure_has_name (structure, "video/x-vp9")) {
1008 /* We do not use profile and streamheader for VPX so let it change
1010 if (field_id == g_quark_from_static_string ("streamheader"))
1012 else if (field_id == g_quark_from_static_string ("profile"))
1014 else if (field_id == g_quark_from_static_string ("width"))
1016 else if (field_id == g_quark_from_static_string ("height"))
1020 /* This fields aren't used and are not retained into the bitstream so we can
1022 if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) {
1023 if (field_id == g_quark_from_static_string ("chroma-site"))
1025 else if (field_id == g_quark_from_static_string ("chroma-format"))
1027 else if (field_id == g_quark_from_static_string ("bit-depth-luma"))
1030 /* Remove pixel-aspect-ratio field if it contains 1/1 as that's considered
1031 * equivalent to not having the field but are not considered equivalent
1032 * by the generic caps functions
1034 if (field_id == g_quark_from_static_string ("pixel-aspect-ratio")) {
1035 gint par_n = gst_value_get_fraction_numerator (value);
1036 gint par_d = gst_value_get_fraction_denominator (value);
1038 if (par_n == 1 && par_d == 1)
1042 /* Remove multiview-mode=mono and multiview-flags=0 fields as those are
1043 * equivalent with not having the fields but are not considered equivalent
1044 * by the generic caps functions.
1046 if (field_id == g_quark_from_static_string ("multiview-mode")) {
1047 const gchar *s = g_value_get_string (value);
1049 if (g_strcmp0 (s, "mono") == 0)
1053 if (field_id == g_quark_from_static_string ("multiview-flags")) {
1054 guint multiview_flags = gst_value_get_flagset_flags (value);
1056 if (multiview_flags == 0)
1065 check_new_caps (GstMatroskaTrackVideoContext * videocontext, GstCaps * old_caps,
1068 GstStructure *old_s, *new_s;
1071 old_caps = gst_caps_copy (old_caps);
1072 new_caps = gst_caps_copy (new_caps);
1074 new_s = gst_caps_get_structure (new_caps, 0);
1075 old_s = gst_caps_get_structure (old_caps, 0);
1077 gst_structure_filter_and_map_in_place (new_s,
1078 (GstStructureFilterMapFunc) check_field, new_s);
1079 gst_structure_filter_and_map_in_place (old_s,
1080 (GstStructureFilterMapFunc) check_field, old_s);
1082 ret = gst_caps_is_subset (new_caps, old_caps);
1084 gst_caps_unref (new_caps);
1085 gst_caps_unref (old_caps);
1091 * gst_matroska_mux_video_pad_setcaps:
1092 * @pad: Pad which got the caps.
1095 * Setcaps function for video sink pad.
1097 * Returns: %TRUE on success.
1100 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
1102 GstMatroskaTrackContext *context = NULL;
1103 GstMatroskaTrackVideoContext *videocontext;
1104 GstMatroskaMux *mux;
1105 GstMatroskaPad *collect_pad;
1106 GstStructure *structure;
1107 const gchar *mimetype;
1108 const gchar *interlace_mode, *s;
1109 const GValue *value = NULL;
1110 GstBuffer *codec_buf = NULL;
1111 gint width, height, pixel_width, pixel_height;
1113 guint multiview_flags;
1116 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1119 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1120 g_assert (collect_pad);
1121 context = collect_pad->track;
1123 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
1124 videocontext = (GstMatroskaTrackVideoContext *) context;
1126 if ((old_caps = gst_pad_get_current_caps (pad))) {
1127 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1128 && !check_new_caps (videocontext, old_caps, caps)) {
1129 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1130 ("Caps changes are not supported by Matroska\nCurrent: `%"
1131 GST_PTR_FORMAT "`\nNew: `%" GST_PTR_FORMAT "`", old_caps, caps));
1132 gst_caps_unref (old_caps);
1135 gst_caps_unref (old_caps);
1136 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
1137 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1138 ("Caps on pad %" GST_PTR_FORMAT
1139 " arrived late. Headers were already written", pad));
1143 /* gst -> matroska ID'ing */
1144 structure = gst_caps_get_structure (caps, 0);
1146 mimetype = gst_structure_get_name (structure);
1148 interlace_mode = gst_structure_get_string (structure, "interlace-mode");
1149 if (interlace_mode != NULL) {
1150 if (strcmp (interlace_mode, "progressive") == 0)
1151 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE;
1153 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_INTERLACED;
1155 videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_UNKNOWN;
1158 if (!strcmp (mimetype, "video/x-theora")) {
1159 /* we'll extract the details later from the theora identification header */
1163 /* get general properties */
1164 /* spec says it is mandatory */
1165 if (!gst_structure_get_int (structure, "width", &width) ||
1166 !gst_structure_get_int (structure, "height", &height))
1169 videocontext->pixel_width = width;
1170 videocontext->pixel_height = height;
1172 if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
1173 && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
1175 context->default_duration =
1176 gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
1177 GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
1178 GST_TIME_ARGS (context->default_duration));
1180 context->default_duration = 0;
1182 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
1183 &pixel_width, &pixel_height)) {
1184 if (pixel_width > pixel_height) {
1185 videocontext->display_width = width * pixel_width / pixel_height;
1186 videocontext->display_height = height;
1187 } else if (pixel_width < pixel_height) {
1188 videocontext->display_width = width;
1189 videocontext->display_height = height * pixel_height / pixel_width;
1191 videocontext->display_width = 0;
1192 videocontext->display_height = 0;
1195 videocontext->display_width = 0;
1196 videocontext->display_height = 0;
1199 if ((s = gst_structure_get_string (structure, "colorimetry"))) {
1200 if (!gst_video_colorimetry_from_string (&videocontext->colorimetry, s)) {
1201 GST_WARNING_OBJECT (pad, "Could not parse colorimetry %s", s);
1205 if ((s = gst_structure_get_string (structure, "mastering-display-info"))) {
1206 if (!gst_video_mastering_display_info_from_string
1207 (&videocontext->mastering_display_info, s)) {
1208 GST_WARNING_OBJECT (pad, "Could not parse mastering-display-metadata %s",
1211 videocontext->mastering_display_info_present = TRUE;
1215 if ((s = gst_structure_get_string (structure, "content-light-level"))) {
1216 if (!gst_video_content_light_level_from_string
1217 (&videocontext->content_light_level, s))
1218 GST_WARNING_OBJECT (pad, "Could not parse content-light-level %s", s);
1221 /* Collect stereoscopic info, if any */
1222 if ((s = gst_structure_get_string (structure, "multiview-mode")))
1223 videocontext->multiview_mode =
1224 gst_video_multiview_mode_from_caps_string (s);
1225 gst_structure_get_flagset (structure, "multiview-flags", &multiview_flags,
1227 videocontext->multiview_flags = multiview_flags;
1232 videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
1233 videocontext->fourcc = 0;
1235 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1236 * data and other settings
1240 /* extract codec_data, may turn out needed */
1241 value = gst_structure_get_value (structure, "codec_data");
1243 codec_buf = (GstBuffer *) gst_value_get_buffer (value);
1246 if (!strcmp (mimetype, "video/x-raw")) {
1248 gst_matroska_mux_set_codec_id (context,
1249 GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
1250 fstr = gst_structure_get_string (structure, "format");
1252 if (strlen (fstr) == 4)
1253 videocontext->fourcc = GST_STR_FOURCC (fstr);
1254 else if (!strcmp (fstr, "GRAY8"))
1255 videocontext->fourcc = GST_MAKE_FOURCC ('Y', '8', '0', '0');
1256 else if (!strcmp (fstr, "BGR"))
1257 videocontext->fourcc = GST_MAKE_FOURCC ('B', 'G', 'R', 24);
1258 else if (!strcmp (fstr, "RGB"))
1259 videocontext->fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', 24);
1261 } else if (!strcmp (mimetype, "video/x-huffyuv") /* MS/VfW compatibility cases */
1262 ||!strcmp (mimetype, "video/x-divx")
1263 || !strcmp (mimetype, "video/x-dv")
1264 || !strcmp (mimetype, "video/x-h263")
1265 || !strcmp (mimetype, "video/x-msmpeg")
1266 || !strcmp (mimetype, "video/x-wmv")
1267 || !strcmp (mimetype, "image/jpeg")) {
1268 gst_riff_strf_vids *bih;
1269 gint size = sizeof (gst_riff_strf_vids);
1272 if (!strcmp (mimetype, "video/x-huffyuv"))
1273 fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
1274 else if (!strcmp (mimetype, "video/x-dv"))
1275 fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
1276 else if (!strcmp (mimetype, "video/x-h263"))
1277 fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
1278 else if (!strcmp (mimetype, "video/x-divx")) {
1281 gst_structure_get_int (structure, "divxversion", &divxversion);
1282 switch (divxversion) {
1284 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
1287 fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
1290 fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
1293 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1296 gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
1297 switch (msmpegversion) {
1299 fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
1302 fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
1308 } else if (!strcmp (mimetype, "video/x-wmv")) {
1312 fstr = gst_structure_get_string (structure, "format");
1313 if (fstr && strlen (fstr) == 4) {
1314 fourcc = GST_STR_FOURCC (fstr);
1315 } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
1316 if (wmvversion == 2) {
1317 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
1318 } else if (wmvversion == 1) {
1319 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
1320 } else if (wmvversion == 3) {
1321 fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
1324 } else if (!strcmp (mimetype, "image/jpeg")) {
1325 fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
1331 bih = g_new0 (gst_riff_strf_vids, 1);
1332 GST_WRITE_UINT32_LE (&bih->size, size);
1333 GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
1334 GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
1335 GST_WRITE_UINT32_LE (&bih->compression, fourcc);
1336 GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
1337 GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
1338 GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
1339 videocontext->pixel_height * 3);
1341 /* process codec private/initialization data, if any */
1343 size += gst_buffer_get_size (codec_buf);
1344 bih = g_realloc (bih, size);
1345 GST_WRITE_UINT32_LE (&bih->size, size);
1346 gst_buffer_extract (codec_buf, 0,
1347 (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
1350 gst_matroska_mux_set_codec_id (context,
1351 GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
1352 gst_matroska_mux_free_codec_priv (context);
1353 context->codec_priv = (gpointer) bih;
1354 context->codec_priv_size = size;
1355 context->dts_only = TRUE;
1356 } else if (!strcmp (mimetype, "video/x-h264")) {
1357 gst_matroska_mux_set_codec_id (context,
1358 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
1359 gst_matroska_mux_free_codec_priv (context);
1361 if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1363 GST_WARNING_OBJECT (mux,
1364 "avc3 is not officially supported, only use this format for smart encoding");
1367 /* Create avcC header */
1368 if (codec_buf != NULL) {
1369 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1370 context->codec_priv = g_malloc0 (context->codec_priv_size);
1371 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1373 } else if (!strcmp (mimetype, "video/x-h265")) {
1374 gst_matroska_mux_set_codec_id (context,
1375 GST_MATROSKA_CODEC_ID_VIDEO_MPEGH_HEVC);
1376 gst_matroska_mux_free_codec_priv (context);
1378 if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1380 GST_WARNING_OBJECT (mux,
1381 "hev1 is not officially supported, only use this format for smart encoding");
1384 /* Create hvcC header */
1385 if (codec_buf != NULL) {
1386 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1387 context->codec_priv = g_malloc0 (context->codec_priv_size);
1388 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1390 } else if (!strcmp (mimetype, "video/x-theora")) {
1391 const GValue *streamheader;
1393 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
1395 gst_matroska_mux_free_codec_priv (context);
1397 streamheader = gst_structure_get_value (structure, "streamheader");
1398 if (!theora_streamheader_to_codecdata (streamheader, context)) {
1399 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1400 ("theora stream headers missing or malformed"));
1403 } else if (!strcmp (mimetype, "video/x-dirac")) {
1404 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
1405 } else if (!strcmp (mimetype, "video/x-vp8")) {
1406 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP8);
1407 } else if (!strcmp (mimetype, "video/x-vp9")) {
1408 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP9);
1409 } else if (!strcmp (mimetype, "video/x-av1")) {
1410 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_AV1);
1411 gst_matroska_mux_free_codec_priv (context);
1412 /* Create av1C header */
1413 if (codec_buf != NULL)
1414 gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1415 &context->codec_priv, &context->codec_priv_size);
1416 } else if (!strcmp (mimetype, "video/x-ffv")) {
1417 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_FFV1);
1418 gst_matroska_mux_free_codec_priv (context);
1419 if (codec_buf != NULL)
1420 gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1421 &context->codec_priv, &context->codec_priv_size);
1422 } else if (!strcmp (mimetype, "video/mpeg")) {
1425 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1426 switch (mpegversion) {
1428 gst_matroska_mux_set_codec_id (context,
1429 GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
1432 gst_matroska_mux_set_codec_id (context,
1433 GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
1436 gst_matroska_mux_set_codec_id (context,
1437 GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
1443 /* global headers may be in codec data */
1444 if (codec_buf != NULL) {
1445 gst_matroska_mux_free_codec_priv (context);
1446 context->codec_priv_size = gst_buffer_get_size (codec_buf);
1447 context->codec_priv = g_malloc0 (context->codec_priv_size);
1448 gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1450 } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1452 /* can only make it here if preceding case verified it was version 3 */
1453 gst_matroska_mux_set_codec_id (context,
1454 GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
1455 } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
1457 const GValue *mdpr_data;
1459 gst_structure_get_int (structure, "rmversion", &rmversion);
1460 switch (rmversion) {
1462 gst_matroska_mux_set_codec_id (context,
1463 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
1466 gst_matroska_mux_set_codec_id (context,
1467 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
1470 gst_matroska_mux_set_codec_id (context,
1471 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
1474 gst_matroska_mux_set_codec_id (context,
1475 GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
1481 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1482 if (mdpr_data != NULL) {
1483 guint8 *priv_data = NULL;
1484 guint priv_data_size = 0;
1486 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1488 priv_data_size = gst_buffer_get_size (codec_data_buf);
1489 priv_data = g_malloc0 (priv_data_size);
1491 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1493 gst_matroska_mux_free_codec_priv (context);
1494 context->codec_priv = priv_data;
1495 context->codec_priv_size = priv_data_size;
1497 } else if (strcmp (mimetype, "video/x-prores") == 0) {
1498 const gchar *variant;
1500 gst_matroska_mux_free_codec_priv (context);
1502 variant = gst_structure_get_string (structure, "format");
1503 if (!variant || !g_strcmp0 (variant, "standard"))
1504 context->codec_priv = g_strdup ("apcn");
1505 else if (!g_strcmp0 (variant, "hq"))
1506 context->codec_priv = g_strdup ("apch");
1507 else if (!g_strcmp0 (variant, "lt"))
1508 context->codec_priv = g_strdup ("apcs");
1509 else if (!g_strcmp0 (variant, "proxy"))
1510 context->codec_priv = g_strdup ("apco");
1511 else if (!g_strcmp0 (variant, "4444"))
1512 context->codec_priv = g_strdup ("ap4h");
1514 GST_WARNING_OBJECT (mux, "Unhandled prores format: %s", variant);
1519 context->codec_priv_size = sizeof (guint32);
1520 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_PRORES);
1528 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1529 GST_PAD_NAME (pad), caps);
1534 /* N > 0 to expect a particular number of headers, negative if the
1535 number of headers is variable */
1537 xiphN_streamheader_to_codecdata (const GValue * streamheader,
1538 GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
1540 GstBuffer **buf = NULL;
1543 guint bufi, i, offset, priv_data_size;
1545 if (streamheader == NULL)
1546 goto no_stream_headers;
1548 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1551 bufarr = g_value_peek_pointer (streamheader);
1552 if (bufarr->len <= 0 || bufarr->len > 255) /* at least one header, and count stored in a byte */
1554 if (N > 0 && bufarr->len != N)
1557 context->xiph_headers_to_skip = bufarr->len;
1559 buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1560 for (i = 0; i < bufarr->len; i++) {
1561 GValue *bufval = &g_array_index (bufarr, GValue, i);
1563 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1565 goto wrong_content_type;
1568 buf[i] = g_value_peek_pointer (bufval);
1572 if (bufarr->len > 0) {
1573 for (i = 0; i < bufarr->len - 1; i++) {
1574 priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
1578 for (i = 0; i < bufarr->len; ++i) {
1579 priv_data_size += gst_buffer_get_size (buf[i]);
1582 priv_data = g_malloc0 (priv_data_size);
1584 priv_data[0] = bufarr->len - 1;
1587 if (bufarr->len > 0) {
1588 for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1589 for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
1590 priv_data[offset++] = 0xff;
1592 priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
1596 for (i = 0; i < bufarr->len; ++i) {
1597 gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
1598 offset += gst_buffer_get_size (buf[i]);
1601 gst_matroska_mux_free_codec_priv (context);
1602 context->codec_priv = priv_data;
1603 context->codec_priv_size = priv_data_size;
1606 *p_buf0 = gst_buffer_ref (buf[0]);
1615 GST_WARNING ("required streamheaders missing in sink caps!");
1620 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1621 G_VALUE_TYPE_NAME (streamheader));
1626 GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1631 GST_WARNING ("streamheaders array does not contain GstBuffers");
1637 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1638 GstMatroskaTrackContext * context)
1640 GstBuffer *buf0 = NULL;
1642 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1645 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
1646 GST_WARNING ("First vorbis header too small, ignoring");
1648 if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
1649 GstMatroskaTrackAudioContext *audiocontext;
1653 gst_buffer_map (buf0, &map, GST_MAP_READ);
1654 hdr = map.data + 1 + 6 + 4;
1655 audiocontext = (GstMatroskaTrackAudioContext *) context;
1656 audiocontext->channels = GST_READ_UINT8 (hdr);
1657 audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1658 gst_buffer_unmap (buf0, &map);
1663 gst_buffer_unref (buf0);
1669 theora_streamheader_to_codecdata (const GValue * streamheader,
1670 GstMatroskaTrackContext * context)
1672 GstBuffer *buf0 = NULL;
1674 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1677 if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
1678 GST_WARNING ("First theora header too small, ignoring");
1679 } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
1680 GST_WARNING ("First header not a theora identification header, ignoring");
1682 GstMatroskaTrackVideoContext *videocontext;
1683 guint fps_num, fps_denom, par_num, par_denom;
1687 gst_buffer_map (buf0, &map, GST_MAP_READ);
1688 hdr = map.data + 1 + 6 + 3 + 2 + 2;
1690 videocontext = (GstMatroskaTrackVideoContext *) context;
1691 videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1692 videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1693 hdr += 3 + 3 + 1 + 1;
1694 fps_num = GST_READ_UINT32_BE (hdr);
1695 fps_denom = GST_READ_UINT32_BE (hdr + 4);
1696 context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1697 fps_denom, fps_num);
1699 par_num = GST_READ_UINT32_BE (hdr) >> 8;
1700 par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1701 if (par_num > 0 && par_denom > 0) {
1702 if (par_num > par_denom) {
1703 videocontext->display_width =
1704 videocontext->pixel_width * par_num / par_denom;
1705 videocontext->display_height = videocontext->pixel_height;
1706 } else if (par_num < par_denom) {
1707 videocontext->display_width = videocontext->pixel_width;
1708 videocontext->display_height =
1709 videocontext->pixel_height * par_denom / par_num;
1711 videocontext->display_width = 0;
1712 videocontext->display_height = 0;
1715 videocontext->display_width = 0;
1716 videocontext->display_height = 0;
1719 gst_buffer_unmap (buf0, &map);
1723 gst_buffer_unref (buf0);
1729 kate_streamheader_to_codecdata (const GValue * streamheader,
1730 GstMatroskaTrackContext * context)
1732 GstBuffer *buf0 = NULL;
1734 if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1737 if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) { /* Kate ID header is 64 bytes */
1738 GST_WARNING ("First kate header too small, ignoring");
1739 } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
1740 GST_WARNING ("First header not a kate identification header, ignoring");
1744 gst_buffer_unref (buf0);
1750 flac_streamheader_to_codecdata (const GValue * streamheader,
1751 GstMatroskaTrackContext * context)
1758 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1759 GST_WARNING ("No or invalid streamheader field in the caps");
1763 bufarr = g_value_peek_pointer (streamheader);
1764 if (bufarr->len < 2) {
1765 GST_WARNING ("Too few headers in streamheader field");
1769 context->xiph_headers_to_skip = bufarr->len + 1;
1771 bufval = &g_array_index (bufarr, GValue, 0);
1772 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1773 GST_WARNING ("streamheaders array does not contain GstBuffers");
1777 buffer = g_value_peek_pointer (bufval);
1779 /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1780 if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
1781 || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
1782 || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
1783 GST_WARNING ("Invalid streamheader for FLAC");
1787 gst_matroska_mux_free_codec_priv (context);
1788 context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
1789 context->codec_priv = g_malloc (context->codec_priv_size);
1790 gst_buffer_extract (buffer, 9, context->codec_priv, -1);
1792 for (i = 1; i < bufarr->len; i++) {
1794 bufval = &g_array_index (bufarr, GValue, i);
1796 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1797 gst_matroska_mux_free_codec_priv (context);
1798 GST_WARNING ("streamheaders array does not contain GstBuffers");
1802 buffer = g_value_peek_pointer (bufval);
1804 old_size = context->codec_priv_size;
1805 context->codec_priv_size += gst_buffer_get_size (buffer);
1807 context->codec_priv = g_realloc (context->codec_priv,
1808 context->codec_priv_size);
1809 gst_buffer_extract (buffer, 0,
1810 (guint8 *) context->codec_priv + old_size, -1);
1817 speex_streamheader_to_codecdata (const GValue * streamheader,
1818 GstMatroskaTrackContext * context)
1825 if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1826 GST_WARNING ("No or invalid streamheader field in the caps");
1830 bufarr = g_value_peek_pointer (streamheader);
1831 if (bufarr->len != 2) {
1832 GST_WARNING ("Too few headers in streamheader field");
1836 context->xiph_headers_to_skip = bufarr->len + 1;
1838 bufval = &g_array_index (bufarr, GValue, 0);
1839 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1840 GST_WARNING ("streamheaders array does not contain GstBuffers");
1844 buffer = g_value_peek_pointer (bufval);
1846 if (gst_buffer_get_size (buffer) < 80
1847 || gst_buffer_memcmp (buffer, 0, "Speex ", 8) != 0) {
1848 GST_WARNING ("Invalid streamheader for Speex");
1852 gst_matroska_mux_free_codec_priv (context);
1853 context->codec_priv_size = gst_buffer_get_size (buffer);
1854 context->codec_priv = g_malloc (context->codec_priv_size);
1855 gst_buffer_extract (buffer, 0, context->codec_priv, -1);
1857 bufval = &g_array_index (bufarr, GValue, 1);
1859 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1860 gst_matroska_mux_free_codec_priv (context);
1861 GST_WARNING ("streamheaders array does not contain GstBuffers");
1865 buffer = g_value_peek_pointer (bufval);
1867 old_size = context->codec_priv_size;
1868 context->codec_priv_size += gst_buffer_get_size (buffer);
1869 context->codec_priv = g_realloc (context->codec_priv,
1870 context->codec_priv_size);
1871 gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
1877 opus_streamheader_to_codecdata (const GValue * streamheader,
1878 GstMatroskaTrackContext * context)
1884 if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1887 bufarr = g_value_peek_pointer (streamheader);
1888 if (bufarr->len != 1 && bufarr->len != 2) /* one header, and count stored in a byte */
1891 /* Opus headers are not in-band */
1892 context->xiph_headers_to_skip = 0;
1894 bufval = &g_array_index (bufarr, GValue, 0);
1895 if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1896 goto wrong_content_type;
1898 buf = g_value_peek_pointer (bufval);
1900 gst_matroska_mux_free_codec_priv (context);
1902 context->codec_priv_size = gst_buffer_get_size (buf);
1903 context->codec_priv = g_malloc0 (context->codec_priv_size);
1904 gst_buffer_extract (buf, 0, context->codec_priv, -1);
1906 context->codec_delay =
1907 GST_READ_UINT16_LE ((guint8 *) context->codec_priv + 10);
1908 context->codec_delay =
1909 gst_util_uint64_scale_round (context->codec_delay, GST_SECOND, 48000);
1910 context->seek_preroll = 80 * GST_MSECOND;
1917 GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1918 G_VALUE_TYPE_NAME (streamheader));
1923 GST_WARNING ("got %u streamheaders, not 1 or 2 as expected", bufarr->len);
1928 GST_WARNING ("streamheaders array does not contain GstBuffers");
1934 opus_make_codecdata (GstMatroskaTrackContext * context, GstCaps * caps)
1938 guint8 channel_mapping_family;
1939 guint8 stream_count, coupled_count, channel_mapping[256];
1943 /* Opus headers are not in-band */
1944 context->xiph_headers_to_skip = 0;
1946 context->codec_delay = 0;
1947 context->seek_preroll = 80 * GST_MSECOND;
1949 if (!gst_codec_utils_opus_parse_caps (caps, &rate, &channels,
1950 &channel_mapping_family, &stream_count, &coupled_count,
1952 GST_WARNING ("Failed to parse caps for Opus");
1957 gst_codec_utils_opus_create_header (rate, channels,
1958 channel_mapping_family, stream_count, coupled_count, channel_mapping, 0,
1961 GST_WARNING ("Failed to create Opus header from caps");
1965 gst_buffer_map (buffer, &map, GST_MAP_READ);
1966 context->codec_priv_size = map.size;
1967 context->codec_priv = g_malloc (context->codec_priv_size);
1968 memcpy (context->codec_priv, map.data, map.size);
1969 gst_buffer_unmap (buffer, &map);
1970 gst_buffer_unref (buffer);
1976 * gst_matroska_mux_audio_pad_setcaps:
1977 * @pad: Pad which got the caps.
1980 * Setcaps function for audio sink pad.
1982 * Returns: %TRUE on success.
1985 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1987 GstMatroskaTrackContext *context = NULL;
1988 GstMatroskaTrackAudioContext *audiocontext;
1989 GstMatroskaMux *mux;
1990 GstMatroskaPad *collect_pad;
1991 const gchar *mimetype;
1992 gint samplerate = 0, channels = 0;
1993 GstStructure *structure;
1994 const GValue *codec_data = NULL;
1995 GstBuffer *buf = NULL;
1996 const gchar *stream_format = NULL;
1999 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2001 if ((old_caps = gst_pad_get_current_caps (pad))) {
2002 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
2003 && !gst_caps_is_equal (caps, old_caps)) {
2004 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2005 ("Caps changes are not supported by Matroska"));
2006 gst_caps_unref (old_caps);
2009 gst_caps_unref (old_caps);
2010 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
2011 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2012 ("Caps on pad %" GST_PTR_FORMAT
2013 " arrived late. Headers were already written", pad));
2018 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
2019 g_assert (collect_pad);
2020 context = collect_pad->track;
2022 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
2023 audiocontext = (GstMatroskaTrackAudioContext *) context;
2025 structure = gst_caps_get_structure (caps, 0);
2026 mimetype = gst_structure_get_name (structure);
2029 gst_structure_get_int (structure, "rate", &samplerate);
2030 gst_structure_get_int (structure, "channels", &channels);
2032 audiocontext->samplerate = samplerate;
2033 audiocontext->channels = channels;
2034 audiocontext->bitdepth = 0;
2035 context->default_duration = 0;
2037 codec_data = gst_structure_get_value (structure, "codec_data");
2039 buf = gst_value_get_buffer (codec_data);
2041 /* TODO: - check if we handle all codecs by the spec, i.e. codec private
2042 * data and other settings
2046 if (!strcmp (mimetype, "audio/mpeg")) {
2047 gint mpegversion = 0;
2049 gst_structure_get_int (structure, "mpegversion", &mpegversion);
2050 switch (mpegversion) {
2056 gst_structure_get_int (structure, "layer", &layer);
2058 if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
2059 GST_WARNING_OBJECT (mux,
2060 "Unable to determine MPEG audio version, assuming 1");
2066 else if (layer == 2)
2068 else if (version == 2)
2073 context->default_duration =
2074 gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
2078 gst_matroska_mux_set_codec_id (context,
2079 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
2082 gst_matroska_mux_set_codec_id (context,
2083 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
2086 gst_matroska_mux_set_codec_id (context,
2087 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
2096 stream_format = gst_structure_get_string (structure, "stream-format");
2097 /* check this is raw aac */
2098 if (stream_format) {
2099 if (strcmp (stream_format, "raw") != 0) {
2100 GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
2104 GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
2109 gst_matroska_mux_set_codec_id (context,
2110 GST_MATROSKA_CODEC_ID_AUDIO_AAC);
2111 context->codec_priv_size = gst_buffer_get_size (buf);
2112 context->codec_priv = g_malloc (context->codec_priv_size);
2113 gst_buffer_extract (buf, 0, context->codec_priv,
2114 context->codec_priv_size);
2116 GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
2123 } else if (!strcmp (mimetype, "audio/x-raw")) {
2126 gst_audio_info_init (&info);
2127 if (!gst_audio_info_from_caps (&info, caps)) {
2128 GST_DEBUG_OBJECT (mux,
2129 "broken caps, rejected by gst_audio_info_from_caps");
2133 switch (GST_AUDIO_INFO_FORMAT (&info)) {
2134 case GST_AUDIO_FORMAT_U8:
2135 case GST_AUDIO_FORMAT_S16BE:
2136 case GST_AUDIO_FORMAT_S16LE:
2137 case GST_AUDIO_FORMAT_S24BE:
2138 case GST_AUDIO_FORMAT_S24LE:
2139 case GST_AUDIO_FORMAT_S32BE:
2140 case GST_AUDIO_FORMAT_S32LE:
2141 if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
2142 GST_DEBUG_OBJECT (mux, "width must be same as depth!");
2145 if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
2146 gst_matroska_mux_set_codec_id (context,
2147 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
2149 gst_matroska_mux_set_codec_id (context,
2150 GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
2152 case GST_AUDIO_FORMAT_F32LE:
2153 case GST_AUDIO_FORMAT_F64LE:
2154 gst_matroska_mux_set_codec_id (context,
2155 GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
2159 GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
2163 audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
2164 } else if (!strcmp (mimetype, "audio/x-vorbis")) {
2165 const GValue *streamheader;
2167 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
2169 gst_matroska_mux_free_codec_priv (context);
2171 streamheader = gst_structure_get_value (structure, "streamheader");
2172 if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
2173 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2174 ("vorbis stream headers missing or malformed"));
2177 } else if (!strcmp (mimetype, "audio/x-flac")) {
2178 const GValue *streamheader;
2180 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
2182 gst_matroska_mux_free_codec_priv (context);
2184 streamheader = gst_structure_get_value (structure, "streamheader");
2185 if (!flac_streamheader_to_codecdata (streamheader, context)) {
2186 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2187 ("flac stream headers missing or malformed"));
2190 } else if (!strcmp (mimetype, "audio/x-speex")) {
2191 const GValue *streamheader;
2193 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
2194 gst_matroska_mux_free_codec_priv (context);
2196 streamheader = gst_structure_get_value (structure, "streamheader");
2197 if (!speex_streamheader_to_codecdata (streamheader, context)) {
2198 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2199 ("speex stream headers missing or malformed"));
2202 } else if (!strcmp (mimetype, "audio/x-opus")) {
2203 const GValue *streamheader;
2205 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_OPUS);
2207 streamheader = gst_structure_get_value (structure, "streamheader");
2209 gst_matroska_mux_free_codec_priv (context);
2210 if (!opus_streamheader_to_codecdata (streamheader, context)) {
2211 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2212 ("opus stream headers missing or malformed"));
2216 /* no streamheader, but we need to have one, so we make one up
2218 gst_matroska_mux_free_codec_priv (context);
2219 if (!opus_make_codecdata (context, caps)) {
2220 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2221 ("opus stream headers missing or malformed"));
2225 } else if (!strcmp (mimetype, "audio/x-ac3")) {
2226 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_AC3);
2227 } else if (!strcmp (mimetype, "audio/x-eac3")) {
2228 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
2229 } else if (!strcmp (mimetype, "audio/x-dts")) {
2230 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_DTS);
2231 } else if (!strcmp (mimetype, "audio/x-tta")) {
2234 /* TTA frame duration */
2235 context->default_duration = 1.04489795918367346939 * GST_SECOND;
2237 gst_structure_get_int (structure, "width", &width);
2238 audiocontext->bitdepth = width;
2239 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_TTA);
2241 } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
2243 const GValue *mdpr_data;
2245 gst_structure_get_int (structure, "raversion", &raversion);
2246 switch (raversion) {
2248 gst_matroska_mux_set_codec_id (context,
2249 GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
2252 gst_matroska_mux_set_codec_id (context,
2253 GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
2256 gst_matroska_mux_set_codec_id (context,
2257 GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
2263 mdpr_data = gst_structure_get_value (structure, "mdpr_data");
2264 if (mdpr_data != NULL) {
2265 guint8 *priv_data = NULL;
2266 guint priv_data_size = 0;
2268 GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
2270 priv_data_size = gst_buffer_get_size (codec_data_buf);
2271 priv_data = g_malloc0 (priv_data_size);
2273 gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
2275 gst_matroska_mux_free_codec_priv (context);
2277 context->codec_priv = priv_data;
2278 context->codec_priv_size = priv_data_size;
2281 } else if (!strcmp (mimetype, "audio/x-wma")
2282 || !strcmp (mimetype, "audio/x-alaw")
2283 || !strcmp (mimetype, "audio/x-mulaw")
2284 || !strcmp (mimetype, "audio/x-adpcm")
2285 || !strcmp (mimetype, "audio/G722")) {
2287 guint codec_priv_size;
2289 gint block_align = 0;
2292 if (samplerate == 0 || channels == 0) {
2293 GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
2297 if (!strcmp (mimetype, "audio/x-wma")) {
2301 if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
2302 || !gst_structure_get_int (structure, "block_align", &block_align)
2303 || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
2304 GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
2309 switch (wmaversion) {
2311 format = GST_RIFF_WAVE_FORMAT_WMAV1;
2314 format = GST_RIFF_WAVE_FORMAT_WMAV2;
2317 format = GST_RIFF_WAVE_FORMAT_WMAV3;
2320 GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
2324 if (gst_structure_get_int (structure, "depth", &depth))
2325 audiocontext->bitdepth = depth;
2326 } else if (!strcmp (mimetype, "audio/x-alaw")
2327 || !strcmp (mimetype, "audio/x-mulaw")) {
2328 audiocontext->bitdepth = 8;
2329 if (!strcmp (mimetype, "audio/x-alaw"))
2330 format = GST_RIFF_WAVE_FORMAT_ALAW;
2332 format = GST_RIFF_WAVE_FORMAT_MULAW;
2334 block_align = channels;
2335 bitrate = block_align * samplerate;
2336 } else if (!strcmp (mimetype, "audio/x-adpcm")) {
2339 layout = gst_structure_get_string (structure, "layout");
2341 GST_WARNING_OBJECT (mux, "Missing layout on adpcm caps");
2345 if (!gst_structure_get_int (structure, "block_align", &block_align)) {
2346 GST_WARNING_OBJECT (mux, "Missing block_align on adpcm caps");
2350 if (!strcmp (layout, "dvi")) {
2351 format = GST_RIFF_WAVE_FORMAT_DVI_ADPCM;
2352 } else if (!strcmp (layout, "g726")) {
2353 format = GST_RIFF_WAVE_FORMAT_ITU_G726_ADPCM;
2354 if (!gst_structure_get_int (structure, "bitrate", &bitrate)) {
2355 GST_WARNING_OBJECT (mux, "Missing bitrate on adpcm g726 caps");
2359 GST_WARNING_OBJECT (mux, "Unknown layout on adpcm caps");
2363 } else if (!strcmp (mimetype, "audio/G722")) {
2364 format = GST_RIFF_WAVE_FORMAT_ADPCM_G722;
2366 g_assert (format != 0);
2368 codec_priv_size = WAVEFORMATEX_SIZE;
2370 codec_priv_size += gst_buffer_get_size (buf);
2372 /* serialize waveformatex structure */
2373 codec_priv = g_malloc0 (codec_priv_size);
2374 GST_WRITE_UINT16_LE (codec_priv, format);
2375 GST_WRITE_UINT16_LE (codec_priv + 2, channels);
2376 GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
2377 GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
2378 GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
2379 GST_WRITE_UINT16_LE (codec_priv + 14, 0);
2381 GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
2383 GST_WRITE_UINT16_LE (codec_priv + 16, 0);
2385 /* process codec private/initialization data, if any */
2387 gst_buffer_extract (buf, 0,
2388 (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
2391 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
2392 gst_matroska_mux_free_codec_priv (context);
2393 context->codec_priv = (gpointer) codec_priv;
2394 context->codec_priv_size = codec_priv_size;
2402 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2403 GST_PAD_NAME (pad), caps);
2408 /* we probably don't have the data at start,
2409 * so have to reserve (a maximum) space to write this at the end.
2410 * bit spacy, but some formats can hold quite some */
2411 #define SUBTITLE_MAX_CODEC_PRIVATE 2048 /* must be > 128 */
2414 * gst_matroska_mux_subtitle_pad_setcaps:
2415 * @pad: Pad which got the caps.
2418 * Setcaps function for subtitle sink pad.
2420 * Returns: %TRUE on success.
2423 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
2425 /* There is now (at least) one such alement (kateenc), and I'm going
2426 to handle it here and claim it works when it can be piped back
2427 through GStreamer and VLC */
2429 GstMatroskaTrackContext *context = NULL;
2430 GstMatroskaTrackSubtitleContext *scontext;
2431 GstMatroskaMux *mux;
2432 GstMatroskaPad *collect_pad;
2433 GstCollectData *data;
2434 const gchar *mimetype;
2435 GstStructure *structure;
2436 const GValue *value = NULL;
2437 GstBuffer *buf = NULL;
2438 gboolean ret = TRUE;
2441 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2443 if ((old_caps = gst_pad_get_current_caps (pad))) {
2444 if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
2445 && !gst_caps_is_equal (caps, old_caps)) {
2446 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2447 ("Caps changes are not supported by Matroska"));
2448 gst_caps_unref (old_caps);
2451 gst_caps_unref (old_caps);
2452 } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
2453 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2454 ("Caps on pad %" GST_PTR_FORMAT
2455 " arrived late. Headers were already written", pad));
2460 collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
2461 g_assert (collect_pad);
2462 data = (GstCollectData *) (collect_pad);
2464 context = collect_pad->track;
2466 g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
2467 scontext = (GstMatroskaTrackSubtitleContext *) context;
2469 structure = gst_caps_get_structure (caps, 0);
2470 mimetype = gst_structure_get_name (structure);
2473 scontext->check_utf8 = 1;
2474 scontext->invalid_utf8 = 0;
2475 context->default_duration = 0;
2477 if (!strcmp (mimetype, "subtitle/x-kate")) {
2478 const GValue *streamheader;
2480 gst_matroska_mux_set_codec_id (context,
2481 GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
2483 gst_matroska_mux_free_codec_priv (context);
2485 streamheader = gst_structure_get_value (structure, "streamheader");
2486 if (!kate_streamheader_to_codecdata (streamheader, context)) {
2487 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2488 ("kate stream headers missing or malformed"));
2492 } else if (!strcmp (mimetype, "text/x-raw")) {
2493 gst_matroska_mux_set_codec_id (context,
2494 GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
2495 } else if (!strcmp (mimetype, "application/x-ssa")) {
2496 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
2497 } else if (!strcmp (mimetype, "application/x-ass")) {
2498 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
2499 } else if (!strcmp (mimetype, "application/x-usf")) {
2500 gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
2501 } else if (!strcmp (mimetype, "subpicture/x-dvd")) {
2502 gst_matroska_mux_set_codec_id (context,
2503 GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
2509 /* maybe some private data, e.g. vobsub */
2510 value = gst_structure_get_value (structure, "codec_data");
2512 buf = gst_value_get_buffer (value);
2515 guint8 *priv_data = NULL;
2517 gst_buffer_map (buf, &map, GST_MAP_READ);
2519 if (map.size > SUBTITLE_MAX_CODEC_PRIVATE) {
2520 GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
2521 " exceeded maximum (%d); discarding", pad,
2522 SUBTITLE_MAX_CODEC_PRIVATE);
2523 gst_buffer_unmap (buf, &map);
2527 gst_matroska_mux_free_codec_priv (context);
2529 priv_data = g_malloc0 (map.size);
2530 memcpy (priv_data, map.data, map.size);
2531 context->codec_priv = priv_data;
2532 context->codec_priv_size = map.size;
2533 gst_buffer_unmap (buf, &map);
2536 GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %" G_GSIZE_FORMAT,
2537 GST_STR_NULL (context->codec_id), context->codec_priv_size);
2539 /* This pad is sparse. Now that we have caps on it, we can tell collectpads
2540 * not to actually wait for data when muxing */
2541 GST_COLLECT_PADS_STREAM_LOCK (mux->collect);
2542 GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED);
2543 gst_collect_pads_set_waiting (mux->collect, data, FALSE);
2544 GST_COLLECT_PADS_STREAM_UNLOCK (mux->collect);
2553 GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2554 GST_PAD_NAME (pad), caps);
2561 * gst_matroska_mux_request_new_pad:
2562 * @element: #GstMatroskaMux.
2563 * @templ: #GstPadTemplate.
2564 * @pad_name: New pad name.
2566 * Request pad function for sink templates.
2568 * Returns: New #GstPad.
2571 gst_matroska_mux_request_new_pad (GstElement * element,
2572 GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
2574 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
2575 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
2576 GstMatroskaPad *collect_pad;
2577 GstMatroskamuxPad *newpad;
2579 const gchar *pad_name = NULL;
2580 GstMatroskaCapsFunc capsfunc = NULL;
2581 GstMatroskaTrackContext *context = NULL;
2583 const gchar *id = NULL;
2585 if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
2586 /* don't mix named and unnamed pads, if the pad already exists we fail when
2587 * trying to add it */
2588 if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
2589 pad_name = req_name;
2591 name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
2594 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
2595 context = (GstMatroskaTrackContext *)
2596 g_new0 (GstMatroskaTrackAudioContext, 1);
2597 context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
2598 context->name = g_strdup ("Audio");
2599 } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
2600 /* don't mix named and unnamed pads, if the pad already exists we fail when
2601 * trying to add it */
2602 if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
2603 pad_name = req_name;
2605 name = g_strdup_printf ("video_%u", mux->num_v_streams++);
2608 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
2609 context = (GstMatroskaTrackContext *)
2610 g_new0 (GstMatroskaTrackVideoContext, 1);
2611 context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
2612 context->name = g_strdup ("Video");
2613 } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
2614 /* don't mix named and unnamed pads, if the pad already exists we fail when
2615 * trying to add it */
2616 if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
2617 pad_name = req_name;
2619 name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
2622 capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
2623 context = (GstMatroskaTrackContext *)
2624 g_new0 (GstMatroskaTrackSubtitleContext, 1);
2625 context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
2626 context->name = g_strdup ("Subtitle");
2627 /* setcaps may only provide proper one a lot later */
2628 id = "S_SUB_UNKNOWN";
2630 GST_WARNING_OBJECT (mux, "This is not our template!");
2634 newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
2635 "name", pad_name, "direction", templ->direction, "template", templ, NULL);
2637 gst_matroskamux_pad_init (newpad);
2638 collect_pad = (GstMatroskaPad *)
2639 gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad),
2640 sizeof (GstMatroskaPad),
2641 (GstCollectDataDestroyNotify) gst_matroska_pad_free, TRUE);
2643 collect_pad->mux = mux;
2644 collect_pad->track = context;
2645 gst_matroska_pad_reset (collect_pad, FALSE);
2647 gst_matroska_mux_set_codec_id (collect_pad->track, id);
2648 collect_pad->track->dts_only = FALSE;
2650 collect_pad->capsfunc = capsfunc;
2651 gst_pad_set_active (GST_PAD (newpad), TRUE);
2652 if (!gst_element_add_pad (element, GST_PAD (newpad)))
2653 goto pad_add_failed;
2659 GST_DEBUG_OBJECT (newpad, "Added new request pad");
2661 return GST_PAD (newpad);
2666 GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
2668 gst_object_unref (newpad);
2674 * gst_matroska_mux_release_pad:
2675 * @element: #GstMatroskaMux.
2676 * @pad: Pad to release.
2678 * Release a previously requested pad.
2681 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
2683 GstMatroskaMux *mux;
2686 mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2688 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
2689 GstCollectData *cdata = (GstCollectData *) walk->data;
2690 GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
2692 if (cdata->pad == pad) {
2694 * observed duration, this will remain GST_CLOCK_TIME_NONE
2695 * only if the pad is reset
2697 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
2699 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2700 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2701 collected_duration =
2702 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2705 if (GST_CLOCK_TIME_IS_VALID (collected_duration)
2706 && mux->duration < collected_duration)
2707 mux->duration = collected_duration;
2713 gst_collect_pads_remove_pad (mux->collect, pad);
2714 if (gst_element_remove_pad (element, pad))
2719 gst_matroska_mux_write_mastering_metadata (GstMatroskaMux * mux,
2720 GstMatroskaTrackVideoContext * videocontext)
2722 GstEbmlWrite *ebml = mux->ebml_write;
2724 GstVideoMasteringDisplayInfo *minfo = &videocontext->mastering_display_info;
2726 const gdouble chroma_scale = 50000;
2727 const gdouble luma_scale = 50000;
2729 if (!videocontext->mastering_display_info_present)
2733 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_MASTERINGMETADATA);
2735 value = (gdouble) minfo->display_primaries[0].x / chroma_scale;
2736 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYX, value);
2738 value = (gdouble) minfo->display_primaries[0].y / chroma_scale;
2739 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYY, value);
2741 value = (gdouble) minfo->display_primaries[1].x / chroma_scale;
2742 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYX, value);
2744 value = (gdouble) minfo->display_primaries[1].y / chroma_scale;
2745 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYY, value);
2747 value = (gdouble) minfo->display_primaries[2].x / chroma_scale;
2748 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYX, value);
2750 value = (gdouble) minfo->display_primaries[2].y / chroma_scale;
2751 gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYY, value);
2753 value = (gdouble) minfo->white_point.x / chroma_scale;
2754 gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYX, value);
2756 value = (gdouble) minfo->white_point.y / chroma_scale;
2757 gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY, value);
2759 value = (gdouble) minfo->max_display_mastering_luminance / luma_scale;
2760 gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMAX, value);
2762 value = (gdouble) minfo->min_display_mastering_luminance / luma_scale;
2763 gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMIN, value);
2765 gst_ebml_write_master_finish (ebml, master);
2770 gst_matroska_mux_write_colour (GstMatroskaMux * mux,
2771 GstMatroskaTrackVideoContext * videocontext)
2773 GstEbmlWrite *ebml = mux->ebml_write;
2775 guint matrix_id = 0;
2777 guint transfer_id = 0;
2778 guint primaries_id = 0;
2780 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_VIDEOCOLOUR);
2782 switch (videocontext->colorimetry.range) {
2783 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
2786 case GST_VIDEO_COLOR_RANGE_16_235:
2789 case GST_VIDEO_COLOR_RANGE_0_255:
2793 matrix_id = gst_video_color_matrix_to_iso (videocontext->colorimetry.matrix);
2795 gst_video_transfer_function_to_iso (videocontext->colorimetry.transfer);
2797 gst_video_color_primaries_to_iso (videocontext->colorimetry.primaries);
2799 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEORANGE, range_id);
2800 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOMATRIXCOEFFICIENTS,
2802 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS,
2804 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPRIMARIES, primaries_id);
2805 if (videocontext->content_light_level.max_content_light_level &&
2806 videocontext->content_light_level.max_frame_average_light_level) {
2807 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXCLL,
2808 videocontext->content_light_level.max_content_light_level);
2809 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXFALL,
2810 videocontext->content_light_level.max_frame_average_light_level);
2813 gst_matroska_mux_write_mastering_metadata (mux, videocontext);
2814 gst_ebml_write_master_finish (ebml, master);
2818 * gst_matroska_mux_track_header:
2819 * @mux: #GstMatroskaMux
2820 * @context: Tack context.
2822 * Write a track header.
2825 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2826 GstMatroskaTrackContext * context)
2828 GstEbmlWrite *ebml = mux->ebml_write;
2831 /* TODO: check if everything necessary is written and check default values */
2833 /* track type goes before the type-specific stuff */
2834 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2835 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2837 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, context->uid);
2838 if (context->default_duration) {
2839 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2840 context->default_duration);
2842 if (context->language) {
2843 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2847 /* FIXME: until we have a nice way of getting the codecname
2848 * out of the caps, I'm not going to enable this. Too much
2849 * (useless, double, boring) work... */
2850 /* TODO: Use value from tags if any */
2851 /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2852 context->codec_name); */
2853 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2855 /* type-specific stuff */
2856 switch (context->type) {
2857 case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2858 GstMatroskaTrackVideoContext *videocontext =
2859 (GstMatroskaTrackVideoContext *) context;
2861 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2862 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2863 videocontext->pixel_width);
2864 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2865 videocontext->pixel_height);
2866 if (videocontext->display_width && videocontext->display_height) {
2867 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2868 videocontext->display_width);
2869 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2870 videocontext->display_height);
2872 switch (videocontext->interlace_mode) {
2873 case GST_MATROSKA_INTERLACE_MODE_INTERLACED:
2874 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2876 case GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE:
2877 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 2);
2883 if (videocontext->fourcc) {
2884 guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2886 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2887 (gpointer) & fcc_le, 4);
2889 gst_matroska_mux_write_colour (mux, videocontext);
2890 if (videocontext->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
2891 guint64 stereo_mode = 0;
2893 switch (videocontext->multiview_mode) {
2894 case GST_VIDEO_MULTIVIEW_MODE_MONO:
2896 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
2897 if (videocontext->multiview_flags &
2898 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2899 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_RL;
2901 stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_LR;
2903 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
2904 if (videocontext->multiview_flags &
2905 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2906 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_RL;
2908 stereo_mode = GST_MATROSKA_STEREO_MODE_TB_LR;
2910 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
2911 if (videocontext->multiview_flags &
2912 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2913 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_RL;
2915 stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_LR;
2917 case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
2918 if (videocontext->multiview_flags &
2919 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2920 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_RL;
2922 stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_LR;
2923 /* FIXME: In frame-by-frame mode, left/right frame buffers need to be
2924 * laced within one block. See http://www.matroska.org/technical/specs/index.html#StereoMode */
2925 GST_FIXME_OBJECT (mux,
2926 "Frame-by-frame stereoscopic mode not fully implemented");
2929 GST_WARNING_OBJECT (mux,
2930 "Multiview mode %d not supported in Matroska/WebM",
2931 videocontext->multiview_mode);
2935 if (stereo_mode != 0)
2936 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOSTEREOMODE,
2939 gst_ebml_write_master_finish (ebml, master);
2944 case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2945 GstMatroskaTrackAudioContext *audiocontext =
2946 (GstMatroskaTrackAudioContext *) context;
2948 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2949 if (audiocontext->samplerate != 8000)
2950 gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2951 audiocontext->samplerate);
2952 if (audiocontext->channels != 1)
2953 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2954 audiocontext->channels);
2955 if (audiocontext->bitdepth) {
2956 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2957 audiocontext->bitdepth);
2960 gst_ebml_write_master_finish (ebml, master);
2965 case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
2969 /* doesn't need type-specific data */
2973 GST_DEBUG_OBJECT (mux, "Wrote track header. Codec %s", context->codec_id);
2975 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2976 if (context->codec_priv)
2977 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2978 context->codec_priv, context->codec_priv_size);
2980 if (context->seek_preroll) {
2981 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPREROLL,
2982 context->seek_preroll);
2985 if (context->codec_delay) {
2986 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CODECDELAY,
2987 context->codec_delay);
2992 gst_matroska_mux_write_chapter_title (const gchar * title, GstEbmlWrite * ebml)
2994 guint64 title_master;
2997 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERDISPLAY);
2999 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPSTRING, title);
3000 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CHAPLANGUAGE,
3001 GST_MATROSKA_MUX_CHAPLANG);
3003 gst_ebml_write_master_finish (ebml, title_master);
3006 static GstTocEntry *
3007 gst_matroska_mux_write_chapter (GstMatroskaMux * mux, GstTocEntry * edition,
3008 GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters,
3009 guint64 * master_edition)
3011 guint64 master_chapteratom;
3018 GstTocEntry *internal_chapter, *internal_nested;
3021 if (G_UNLIKELY (master_chapters != NULL && *master_chapters == 0))
3023 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERS);
3025 if (G_UNLIKELY (master_edition != NULL && *master_edition == 0)) {
3026 /* create uid for the parent */
3028 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_EDITIONENTRY);
3030 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONUID,
3031 g_ascii_strtoull (gst_toc_entry_get_uid (edition), NULL, 10));
3032 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGHIDDEN, 0);
3033 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGDEFAULT, 0);
3034 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGORDERED, 0);
3037 gst_toc_entry_get_start_stop_times (entry, &start, &stop);
3038 tags = gst_toc_entry_get_tags (entry);
3040 tags = gst_tag_list_copy (tags);
3043 /* build internal chapter */
3044 uid = gst_matroska_mux_create_uid (mux);
3045 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT, uid);
3046 internal_chapter = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, s_uid);
3048 /* Write the chapter entry */
3049 master_chapteratom =
3050 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERATOM);
3052 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERUID, uid);
3053 /* Store the user provided UID in the ChapterStringUID */
3054 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPTERSTRINGUID,
3055 gst_toc_entry_get_uid (entry));
3056 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTART, start);
3057 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTOP, stop);
3058 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGHIDDEN, 0);
3059 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGENABLED, 1);
3061 /* write current ChapterDisplays before the nested chapters */
3062 if (G_LIKELY (tags != NULL)) {
3063 count = gst_tag_list_get_tag_size (tags, GST_TAG_TITLE);
3065 for (i = 0; i < count; ++i) {
3066 gst_tag_list_get_string_index (tags, GST_TAG_TITLE, i, &title);
3067 /* FIXME: handle ChapterLanguage entries */
3068 gst_matroska_mux_write_chapter_title (title, ebml);
3072 /* remove title tag */
3073 if (G_LIKELY (count > 0))
3074 gst_tag_list_remove_tag (tags, GST_TAG_TITLE);
3076 gst_toc_entry_set_tags (internal_chapter, tags);
3079 /* Write nested chapters */
3080 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3082 internal_nested = gst_matroska_mux_write_chapter (mux, NULL, cur->data,
3085 gst_toc_entry_append_sub_entry (internal_chapter, internal_nested);
3088 gst_ebml_write_master_finish (ebml, master_chapteratom);
3090 return internal_chapter;
3093 static GstTocEntry *
3094 gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
3095 GstTocEntry * edition, GList * chapters, GstEbmlWrite * ebml,
3096 guint64 * master_chapters)
3098 guint64 master_edition = 0;
3101 GstTocEntry *internal_edition, *internal_chapter;
3102 GstTagList *tags = NULL;
3104 g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT,
3105 gst_matroska_mux_create_uid (mux));
3107 if (edition != NULL) {
3108 /* Edition entry defined, get its tags */
3109 tags = gst_toc_entry_get_tags (edition);
3111 tags = gst_tag_list_copy (tags);
3115 internal_edition = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, s_uid);
3117 gst_toc_entry_set_tags (internal_edition, tags);
3120 for (cur = g_list_first (chapters); cur != NULL; cur = cur->next) {
3121 internal_chapter = gst_matroska_mux_write_chapter (mux, internal_edition,
3122 cur->data, ebml, master_chapters, &master_edition);
3124 gst_toc_entry_append_sub_entry (internal_edition, internal_chapter);
3127 if (G_LIKELY (master_edition != 0))
3128 gst_ebml_write_master_finish (ebml, master_edition);
3130 return internal_edition;
3134 * gst_matroska_mux_start:
3135 * @mux: #GstMatroskaMux
3137 * Start a new matroska file (write headers etc...)
3140 gst_matroska_mux_start (GstMatroskaMux * mux, GstMatroskaPad * first_pad,
3141 GstBuffer * first_pad_buf)
3143 GstEbmlWrite *ebml = mux->ebml_write;
3144 const gchar *doctype;
3145 guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
3146 GST_MATROSKA_ID_TRACKS,
3147 GST_MATROSKA_ID_CHAPTERS,
3148 GST_MATROSKA_ID_CUES,
3149 GST_MATROSKA_ID_TAGS,
3152 const gchar *media_type;
3153 gboolean audio_only;
3154 guint64 master, child;
3158 GstClockTime earliest_time = GST_CLOCK_TIME_NONE;
3159 GstClockTime duration = 0;
3160 guint32 segment_uid[4];
3165 /* if not streaming, check if downstream is seekable */
3166 if (!mux->ebml_write->streamable) {
3170 query = gst_query_new_seeking (GST_FORMAT_BYTES);
3171 if (gst_pad_peer_query (mux->srcpad, query)) {
3172 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3173 GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
3175 /* assume seeking is not supported if query not handled downstream */
3176 GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
3180 mux->ebml_write->streamable = TRUE;
3181 g_object_notify (G_OBJECT (mux), "streamable");
3182 GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
3183 "streamable=false. Will ignore that and create streamable output "
3186 gst_query_unref (query);
3189 /* stream-start (FIXME: create id based on input ids) */
3190 g_snprintf (s_id, sizeof (s_id), "matroskamux-%08x", g_random_int ());
3191 gst_pad_push_event (mux->srcpad, gst_event_new_stream_start (s_id));
3194 audio_only = mux->num_v_streams == 0 && mux->num_a_streams > 0;
3196 media_type = (audio_only) ? "audio/webm" : "video/webm";
3198 media_type = (audio_only) ? "audio/x-matroska" : "video/x-matroska";
3200 ebml->caps = gst_caps_new_empty_simple (media_type);
3201 gst_pad_set_caps (mux->srcpad, ebml->caps);
3202 /* we start with a EBML header */
3203 doctype = mux->doctype;
3204 GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
3205 doctype, mux->doctype_version);
3206 gst_ebml_write_header (ebml, doctype, mux->doctype_version);
3208 /* the rest of the header is cached */
3209 gst_ebml_write_set_cache (ebml, 0x1000);
3211 /* start a segment */
3213 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
3214 mux->segment_master = ebml->pos;
3216 if (!mux->ebml_write->streamable) {
3217 /* seekhead (table of contents) - we set the positions later */
3218 mux->seekhead_pos = ebml->pos;
3219 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
3220 for (i = 0; seekhead_id[i] != 0; i++) {
3221 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
3222 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
3223 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
3224 gst_ebml_write_master_finish (ebml, child);
3226 gst_ebml_write_master_finish (ebml, master);
3229 if (mux->ebml_write->streamable) {
3230 const GstTagList *tags;
3231 gboolean has_main_tags;
3234 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3235 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3237 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux)) {
3238 guint64 master_tags, master_tag;
3240 GST_DEBUG_OBJECT (mux, "Writing tags");
3242 mux->tags_pos = ebml->pos;
3243 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3244 if (has_main_tags) {
3245 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3246 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3247 gst_ebml_write_master_finish (ebml, master_tag);
3249 gst_matroska_mux_write_streams_tags (mux);
3250 gst_ebml_write_master_finish (ebml, master_tags);
3255 mux->info_pos = ebml->pos;
3256 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
3258 /* WebM does not support SegmentUID field on SegmentInfo */
3259 if (!mux->is_webm) {
3260 for (i = 0; i < 4; i++) {
3261 segment_uid[i] = g_random_int ();
3263 gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
3264 (guint8 *) segment_uid, 16);
3267 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
3268 mux->duration_pos = ebml->pos;
3270 if (!mux->ebml_write->streamable) {
3271 for (collected = mux->collect->data; collected;
3272 collected = g_slist_next (collected)) {
3273 GstMatroskaPad *collect_pad;
3275 gint64 trackduration;
3277 collect_pad = (GstMatroskaPad *) collected->data;
3278 thepad = collect_pad->collect.pad;
3280 /* Query the total length of the track. */
3281 GST_DEBUG_OBJECT (thepad, "querying peer duration");
3282 if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
3283 GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
3284 GST_TIME_ARGS (trackduration));
3285 if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
3286 duration = (GstClockTime) trackduration;
3290 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3291 gst_guint64_to_gdouble (duration) /
3292 gst_guint64_to_gdouble (mux->time_scale));
3294 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
3295 "GStreamer matroskamux version " PACKAGE_VERSION);
3296 if (mux->writing_app && mux->writing_app[0]) {
3297 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
3299 if (mux->creation_time != NULL) {
3300 time = g_date_time_to_unix (mux->creation_time) * GST_SECOND;
3301 time += g_date_time_get_microsecond (mux->creation_time) * GST_USECOND;
3303 time = g_get_real_time () * GST_USECOND;
3305 gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time);
3306 gst_ebml_write_master_finish (ebml, master);
3309 mux->tracks_pos = ebml->pos;
3310 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
3312 for (collected = mux->collect->data; collected;
3313 collected = g_slist_next (collected)) {
3314 GstMatroskaPad *collect_pad;
3317 collect_pad = (GstMatroskaPad *) collected->data;
3319 /* This will cause an error at a later time */
3320 if (collect_pad->track->codec_id == NULL)
3323 /* Find the smallest timestamp so we can offset all streams by this to
3325 if (mux->offset_to_zero) {
3328 if (collect_pad == first_pad)
3329 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3331 buf = gst_collect_pads_peek (mux->collect, collected->data);
3334 ts = gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
3336 if (earliest_time == GST_CLOCK_TIME_NONE)
3338 else if (ts != GST_CLOCK_TIME_NONE && ts < earliest_time)
3343 gst_buffer_unref (buf);
3346 /* For audio tracks, use the first buffers duration as the default
3347 * duration if we didn't get any better idea from the caps event already
3349 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO &&
3350 collect_pad->track->default_duration == 0) {
3351 if (collect_pad == first_pad)
3352 buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3354 buf = gst_collect_pads_peek (mux->collect, collected->data);
3356 if (buf && GST_BUFFER_DURATION_IS_VALID (buf))
3357 collect_pad->track->default_duration =
3358 GST_BUFFER_DURATION (buf) + collect_pad->track->codec_delay;
3360 gst_buffer_unref (buf);
3363 collect_pad->track->num = tracknum++;
3364 child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
3365 gst_matroska_mux_track_header (mux, collect_pad->track);
3366 gst_ebml_write_master_finish (ebml, child);
3367 /* some remaining pad/track setup */
3368 collect_pad->default_duration_scaled =
3369 gst_util_uint64_scale (collect_pad->track->default_duration,
3370 1, mux->time_scale);
3372 gst_ebml_write_master_finish (ebml, master);
3374 mux->earliest_time = earliest_time == GST_CLOCK_TIME_NONE ? 0 : earliest_time;
3377 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3378 if (toc != NULL && !mux->ebml_write->streamable) {
3379 guint64 master_chapters = 0;
3380 GstTocEntry *internal_edition;
3381 GList *cur, *chapters;
3383 GST_DEBUG ("Writing chapters");
3385 /* There are two UIDs for Chapters:
3386 * - The ChapterUID is a mandatory unsigned integer which internally
3387 * refers to a given chapter. Except for the title & language which use
3388 * dedicated fields, this UID can also be used to add tags to the Chapter.
3389 * The tags come in a separate section of the container.
3390 * - The ChapterStringUID is an optional UTF-8 string which also uniquely
3391 * refers to a chapter but from an external perspective. It can act as a
3392 * "WebVTT cue identifier" which "can be used to reference a specific cue,
3393 * for example from script or CSS".
3395 * The ChapterUID will be generated and checked for unicity, while the
3396 * ChapterStringUID will receive the user defined UID.
3398 * In order to be able to refer to chapters from the tags section,
3399 * we must maintain an internal Toc tree with the generated ChapterUID
3400 * (see gst_matroska_mux_write_toc_entry_tags) */
3402 /* Check whether we have editions or chapters at the root level. */
3403 cur = gst_toc_get_entries (toc);
3405 mux->chapters_pos = ebml->pos;
3407 mux->internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
3409 if (gst_toc_entry_get_entry_type (cur->data) ==
3410 GST_TOC_ENTRY_TYPE_EDITION) {
3411 /* Editions at the root level */
3412 for (; cur != NULL; cur = cur->next) {
3413 chapters = gst_toc_entry_get_sub_entries (cur->data);
3414 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3415 cur->data, chapters, ebml, &master_chapters);
3416 gst_toc_append_entry (mux->internal_toc, internal_edition);
3419 /* Chapters at the root level */
3420 internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3421 NULL, cur, ebml, &master_chapters);
3422 gst_toc_append_entry (mux->internal_toc, internal_edition);
3425 /* close master element if any edition was written */
3426 if (G_LIKELY (master_chapters != 0))
3427 gst_ebml_write_master_finish (ebml, master_chapters);
3431 /* lastly, flush the cache */
3432 gst_ebml_write_flush_cache (ebml, FALSE, 0);
3435 gst_toc_unref (toc);
3438 /* TODO: more sensible tag mappings */
3441 const gchar *matroska_tagname;
3442 const gchar *gstreamer_tagname;
3444 gst_matroska_tag_conv[] = {
3446 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
3447 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
3448 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
3449 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
3450 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
3451 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
3452 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
3453 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
3454 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
3455 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
3456 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
3457 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
3458 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
3459 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
3460 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
3463 /* Every stagefright implementation on android up to and including 6.0.1 is using
3464 libwebm with bug in matroska parsing, where it will choke on empty tag elements;
3465 so before outputting tags and tag elements we better make sure that there are
3466 actually tags we are going to write */
3468 gst_matroska_mux_tag_list_is_empty (const GstTagList * list)
3471 for (i = 0; i < gst_tag_list_n_tags (list); i++) {
3472 const gchar *tag = gst_tag_list_nth_tag_name (list, i);
3474 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3475 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3476 if (strcmp (tagname_gst, tag) == 0) {
3477 GValue src = { 0, };
3480 if (!gst_tag_list_copy_value (&src, list, tag))
3482 dest = gst_value_serialize (&src);
3484 g_value_unset (&src);
3496 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
3499 GstEbmlWrite *ebml = (GstEbmlWrite *) data;
3501 guint64 simpletag_master;
3503 for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3504 const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3505 const gchar *tagname_mkv = gst_matroska_tag_conv[i].matroska_tagname;
3507 if (strcmp (tagname_gst, tag) == 0) {
3508 GValue src = { 0, };
3511 if (!gst_tag_list_copy_value (&src, list, tag))
3513 if ((dest = gst_value_serialize (&src))) {
3515 simpletag_master = gst_ebml_write_master_start (ebml,
3516 GST_MATROSKA_ID_SIMPLETAG);
3517 gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
3518 gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
3519 gst_ebml_write_master_finish (ebml, simpletag_master);
3522 GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
3524 g_value_unset (&src);
3531 gst_matroska_mux_write_stream_tags (GstMatroskaMux * mux, GstMatroskaPad * mpad)
3533 guint64 master_tag, master_targets;
3536 ebml = mux->ebml_write;
3538 if (G_UNLIKELY (mpad->tags == NULL
3539 || gst_matroska_mux_tag_list_is_empty (mpad->tags)))
3542 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3543 master_targets = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3545 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETTRACKUID, mpad->track->uid);
3547 gst_ebml_write_master_finish (ebml, master_targets);
3548 gst_tag_list_foreach (mpad->tags, gst_matroska_mux_write_simple_tag, ebml);
3549 gst_ebml_write_master_finish (ebml, master_tag);
3553 gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux)
3557 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3558 GstMatroskaPad *collect_pad;
3560 collect_pad = (GstMatroskaPad *) walk->data;
3562 gst_matroska_mux_write_stream_tags (mux, collect_pad);
3567 gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux)
3571 for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3572 GstMatroskaPad *collect_pad;
3574 collect_pad = (GstMatroskaPad *) walk->data;
3575 if (!gst_matroska_mux_tag_list_is_empty (collect_pad->tags))
3582 gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
3583 const GstTocEntry * entry, guint64 * master_tags, gboolean * has_tags)
3585 guint64 master_tag, master_targets;
3588 const GstTagList *tags;
3590 ebml = mux->ebml_write;
3592 tags = gst_toc_entry_get_tags (entry);
3593 if (G_UNLIKELY (tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags))) {
3596 if (*master_tags == 0) {
3597 mux->tags_pos = ebml->pos;
3598 *master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3601 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3603 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3605 if (gst_toc_entry_get_entry_type (entry) == GST_TOC_ENTRY_TYPE_EDITION)
3606 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETEDITIONUID,
3607 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3609 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETCHAPTERUID,
3610 g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3612 gst_ebml_write_master_finish (ebml, master_targets);
3613 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3614 gst_ebml_write_master_finish (ebml, master_tag);
3617 for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3619 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, master_tags,
3625 * gst_matroska_mux_finish:
3626 * @mux: #GstMatroskaMux
3628 * Finish a new matroska file (write index etc...)
3631 gst_matroska_mux_finish (GstMatroskaMux * mux)
3633 GstEbmlWrite *ebml = mux->ebml_write;
3635 guint64 duration = 0;
3637 const GstTagList *tags, *toc_tags;
3639 gboolean has_main_tags, toc_has_tags = FALSE;
3642 /* finish last cluster */
3644 gst_ebml_write_master_finish (ebml, mux->cluster);
3648 if (mux->index != NULL) {
3650 guint64 master, pointentry_master, trackpos_master;
3652 mux->cues_pos = ebml->pos;
3653 gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
3654 master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
3656 for (n = 0; n < mux->num_indexes; n++) {
3657 GstMatroskaIndex *idx = &mux->index[n];
3659 pointentry_master = gst_ebml_write_master_start (ebml,
3660 GST_MATROSKA_ID_POINTENTRY);
3661 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
3662 idx->time / mux->time_scale);
3663 trackpos_master = gst_ebml_write_master_start (ebml,
3664 GST_MATROSKA_ID_CUETRACKPOSITIONS);
3665 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
3666 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
3667 idx->pos - mux->segment_master);
3668 gst_ebml_write_master_finish (ebml, trackpos_master);
3669 gst_ebml_write_master_finish (ebml, pointentry_master);
3672 gst_ebml_write_master_finish (ebml, master);
3673 gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
3677 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3678 has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3679 toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3681 if (has_main_tags || gst_matroska_mux_streams_have_tags (mux) || toc != NULL) {
3682 guint64 master_tags = 0, master_tag;
3684 GST_DEBUG_OBJECT (mux, "Writing tags");
3686 if (has_main_tags) {
3687 /* TODO: maybe limit via the TARGETS id by looking at the source pad */
3688 mux->tags_pos = ebml->pos;
3689 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3690 master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3693 gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3694 if (mux->internal_toc != NULL) {
3695 toc_tags = gst_toc_get_tags (mux->internal_toc);
3696 toc_has_tags = (toc_tags != NULL);
3697 gst_tag_list_foreach (toc_tags, gst_matroska_mux_write_simple_tag,
3701 gst_ebml_write_master_finish (ebml, master_tag);
3704 if (mux->internal_toc != NULL) {
3705 for (cur = gst_toc_get_entries (mux->internal_toc); cur != NULL;
3707 gst_matroska_mux_write_toc_entry_tags (mux, cur->data, &master_tags,
3712 if (master_tags == 0 && gst_matroska_mux_streams_have_tags (mux)) {
3713 mux->tags_pos = ebml->pos;
3714 master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3716 gst_matroska_mux_write_streams_tags (mux);
3718 if (master_tags != 0)
3719 gst_ebml_write_master_finish (ebml, master_tags);
3722 /* update seekhead. We know that:
3723 * - a seekhead contains 5 entries.
3724 * - order of entries is as above.
3725 * - a seekhead has a 4-byte header + 8-byte length
3726 * - each entry is 2-byte master, 2-byte ID pointer,
3727 * 2-byte length pointer, all 8/1-byte length, 4-
3728 * byte ID and 8-byte length pointer, where the
3729 * length pointer starts at 20.
3730 * - all entries are local to the segment (so pos - segment_master).
3731 * - so each entry is at 12 + 20 + num * 28. */
3732 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
3733 mux->info_pos - mux->segment_master);
3734 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
3735 mux->tracks_pos - mux->segment_master);
3736 if (toc != NULL && mux->chapters_pos > 0) {
3737 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
3738 mux->chapters_pos - mux->segment_master);
3741 guint64 my_pos = ebml->pos;
3743 gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
3744 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3745 gst_ebml_write_seek (ebml, my_pos);
3747 if (mux->index != NULL) {
3748 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
3749 mux->cues_pos - mux->segment_master);
3752 guint64 my_pos = ebml->pos;
3754 gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
3755 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3756 gst_ebml_write_seek (ebml, my_pos);
3759 if (mux->tags_pos != 0 || toc_has_tags) {
3760 gst_ebml_replace_uint (ebml, mux->seekhead_pos + 144,
3761 mux->tags_pos - mux->segment_master);
3764 guint64 my_pos = ebml->pos;
3766 gst_ebml_write_seek (ebml, mux->seekhead_pos + 124);
3767 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3768 gst_ebml_write_seek (ebml, my_pos);
3772 gst_toc_unref (toc);
3776 * - first get the overall duration
3777 * (a released track may have left a duration in here)
3778 * - write some track header data for subtitles
3780 duration = mux->duration;
3782 for (collected = mux->collect->data; collected;
3783 collected = g_slist_next (collected)) {
3784 GstMatroskaPad *collect_pad;
3786 * observed duration, this will never remain GST_CLOCK_TIME_NONE
3787 * since this means buffer without timestamps that is not possible
3789 GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
3791 collect_pad = (GstMatroskaPad *) collected->data;
3793 GST_DEBUG_OBJECT (mux,
3794 "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
3795 " end ts %" GST_TIME_FORMAT, collect_pad,
3796 GST_TIME_ARGS (collect_pad->start_ts),
3797 GST_TIME_ARGS (collect_pad->end_ts));
3799 if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
3800 GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
3801 collected_duration =
3802 GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
3803 GST_DEBUG_OBJECT (collect_pad->collect.pad,
3804 "final track duration: %" GST_TIME_FORMAT,
3805 GST_TIME_ARGS (collected_duration));
3807 GST_WARNING_OBJECT (collect_pad->collect.pad,
3808 "unable to get final track duration");
3810 if (GST_CLOCK_TIME_IS_VALID (collected_duration) &&
3811 duration < collected_duration)
3812 duration = collected_duration;
3816 /* seek back (optional, but do anyway) */
3817 gst_ebml_write_seek (ebml, pos);
3819 /* update duration */
3820 if (duration != 0) {
3821 GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
3822 GST_TIME_ARGS (duration));
3823 pos = mux->ebml_write->pos;
3824 gst_ebml_write_seek (ebml, mux->duration_pos);
3825 gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3826 gst_guint64_to_gdouble (duration) /
3827 gst_guint64_to_gdouble (mux->time_scale));
3828 gst_ebml_write_seek (ebml, pos);
3831 guint64 my_pos = ebml->pos;
3833 gst_ebml_write_seek (ebml, mux->duration_pos);
3834 gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
3835 gst_ebml_write_seek (ebml, my_pos);
3837 GST_DEBUG_OBJECT (mux, "finishing segment");
3838 /* finish segment - this also writes element length */
3839 gst_ebml_write_master_finish (ebml, mux->segment_pos);
3843 * gst_matroska_mux_buffer_header:
3844 * @track: Track context.
3845 * @relative_timestamp: relative timestamp of the buffer
3846 * @flags: Buffer flags.
3848 * Create a buffer containing buffer header.
3850 * Returns: New buffer.
3853 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
3854 gint16 relative_timestamp, int flags)
3857 guint8 *data = g_malloc (4);
3859 hdr = gst_buffer_new_wrapped (data, 4);
3860 /* track num - FIXME: what if num >= 0x80 (unlikely)? */
3861 data[0] = track->num | 0x80;
3862 /* time relative to clustertime */
3863 GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
3871 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
3872 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
3873 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
3876 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
3877 GstMatroskaPad * collect_pad, GstBuffer * buf)
3879 GstMatroskaTrackVideoContext *ctx =
3880 (GstMatroskaTrackVideoContext *) collect_pad->track;
3885 guint32 next_parse_offset;
3886 GstBuffer *ret = NULL;
3887 gboolean is_muxing_unit = FALSE;
3889 gst_buffer_map (buf, &map, GST_MAP_READ);
3894 gst_buffer_unmap (buf, &map);
3895 gst_buffer_unref (buf);
3899 /* Check if this buffer contains a picture or end-of-sequence packet */
3900 while (size >= 13) {
3901 if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
3902 gst_buffer_unmap (buf, &map);
3903 gst_buffer_unref (buf);
3907 parse_code = GST_READ_UINT8 (data + 4);
3908 if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
3909 if (ctx->dirac_unit) {
3910 gst_buffer_unref (ctx->dirac_unit);
3911 ctx->dirac_unit = NULL;
3913 } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
3914 parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
3915 is_muxing_unit = TRUE;
3919 next_parse_offset = GST_READ_UINT32_BE (data + 5);
3921 if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
3924 data += next_parse_offset;
3925 size -= next_parse_offset;
3928 if (ctx->dirac_unit)
3929 ctx->dirac_unit = gst_buffer_append (ctx->dirac_unit, gst_buffer_ref (buf));
3931 ctx->dirac_unit = gst_buffer_ref (buf);
3933 gst_buffer_unmap (buf, &map);
3935 if (is_muxing_unit) {
3936 ret = gst_buffer_make_writable (ctx->dirac_unit);
3937 ctx->dirac_unit = NULL;
3938 gst_buffer_copy_into (ret, buf,
3939 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
3940 gst_buffer_unref (buf);
3942 gst_buffer_unref (buf);
3950 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
3954 GValue streamheader = { 0 };
3955 GValue bufval = { 0 };
3956 GstBuffer *streamheader_buffer;
3957 GstEbmlWrite *ebml = mux->ebml_write;
3959 streamheader_buffer = gst_ebml_stop_streamheader (ebml);
3960 caps = gst_caps_copy (mux->ebml_write->caps);
3961 s = gst_caps_get_structure (caps, 0);
3962 g_value_init (&streamheader, GST_TYPE_ARRAY);
3963 g_value_init (&bufval, GST_TYPE_BUFFER);
3964 GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_HEADER);
3965 gst_value_set_buffer (&bufval, streamheader_buffer);
3966 gst_value_array_append_value (&streamheader, &bufval);
3967 g_value_unset (&bufval);
3968 gst_structure_set_value (s, "streamheader", &streamheader);
3969 g_value_unset (&streamheader);
3970 gst_caps_replace (&ebml->caps, caps);
3971 gst_buffer_unref (streamheader_buffer);
3972 gst_pad_set_caps (mux->srcpad, caps);
3973 gst_caps_unref (caps);
3977 * gst_matroska_mux_write_data:
3978 * @mux: #GstMatroskaMux
3979 * @collect_pad: #GstMatroskaPad with the data
3981 * Write collected data (called from gst_matroska_mux_collected).
3983 * Returns: Result of the gst_pad_push issued to write the data.
3985 static GstFlowReturn
3986 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
3989 GstEbmlWrite *ebml = mux->ebml_write;
3992 gboolean write_duration;
3993 guint64 cluster_time_scaled;
3994 gint16 relative_timestamp;
3995 gint64 relative_timestamp64;
3996 guint64 block_duration, duration_diff = 0;
3997 gboolean is_video_keyframe = FALSE;
3998 gboolean is_video_invisible = FALSE;
3999 gboolean is_audio_only = FALSE;
4000 gboolean is_min_duration_reached = FALSE;
4001 gboolean is_max_duration_exceeded = FALSE;
4002 GstMatroskamuxPad *pad;
4004 GstClockTime buffer_timestamp;
4005 GstAudioClippingMeta *cmeta = NULL;
4008 pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
4010 /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
4011 if (collect_pad->track->xiph_headers_to_skip > 0) {
4012 --collect_pad->track->xiph_headers_to_skip;
4013 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER)) {
4014 GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
4015 gst_buffer_unref (buf);
4020 /* for dirac we have to queue up everything up to a picture unit */
4021 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC)) {
4022 buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
4025 } else if (!strcmp (collect_pad->track->codec_id,
4026 GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) {
4027 /* Remove the 'Frame container atom' header' */
4028 buf = gst_buffer_make_writable (buf);
4029 gst_buffer_resize (buf, 8, gst_buffer_get_size (buf) - 8);
4033 gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
4034 if (buffer_timestamp >= mux->earliest_time) {
4035 buffer_timestamp -= mux->earliest_time;
4037 buffer_timestamp = 0;
4040 /* hm, invalid timestamp (due to --to be fixed--- element upstream);
4041 * this would wreak havoc with time stored in matroska file */
4042 /* TODO: maybe calculate a timestamp by using the previous timestamp
4043 * and default duration */
4044 if (!GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
4045 GST_WARNING_OBJECT (collect_pad->collect.pad,
4046 "Invalid buffer timestamp; dropping buffer");
4047 gst_buffer_unref (buf);
4051 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4052 && collect_pad->track->codec_delay) {
4053 /* All timestamps should include the codec delay */
4054 if (buffer_timestamp > collect_pad->track->codec_delay) {
4055 buffer_timestamp += collect_pad->track->codec_delay;
4057 buffer_timestamp = 0;
4058 duration_diff = collect_pad->track->codec_delay - buffer_timestamp;
4062 /* set the timestamp for outgoing buffers */
4063 ebml->timestamp = buffer_timestamp;
4065 if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
4066 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
4067 GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
4068 GST_TIME_ARGS (buffer_timestamp));
4069 is_video_keyframe = TRUE;
4070 } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DECODE_ONLY) &&
4071 (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP8)
4072 || !strcmp (collect_pad->track->codec_id,
4073 GST_MATROSKA_CODEC_ID_VIDEO_VP9))) {
4074 GST_LOG_OBJECT (mux,
4075 "have VP8 video invisible frame, " "ts=%" GST_TIME_FORMAT,
4076 GST_TIME_ARGS (buffer_timestamp));
4077 is_video_invisible = TRUE;
4081 /* From this point on we use the buffer_timestamp to do cluster and other
4082 * related arithmetic, so apply the timestamp offset if we have one */
4083 buffer_timestamp += mux->cluster_timestamp_offset;
4085 is_audio_only = (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
4086 (mux->num_streams == 1);
4087 is_min_duration_reached = (mux->min_cluster_duration == 0
4088 || (buffer_timestamp > mux->cluster_time
4089 && (buffer_timestamp - mux->cluster_time) >=
4090 mux->min_cluster_duration));
4091 is_max_duration_exceeded = (mux->max_cluster_duration > 0
4092 && buffer_timestamp > mux->cluster_time
4093 && (buffer_timestamp - mux->cluster_time) >=
4094 MIN (G_MAXINT16 * mux->time_scale, mux->max_cluster_duration));
4097 /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
4098 * or when we may be reaching the limit of the relative timestamp */
4099 if (is_max_duration_exceeded || (is_video_keyframe
4100 && is_min_duration_reached) || mux->force_key_unit_event
4101 || (is_audio_only && is_min_duration_reached)) {
4102 if (!mux->ebml_write->streamable)
4103 gst_ebml_write_master_finish (ebml, mux->cluster);
4105 /* Forward the GstForceKeyUnit event after finishing the cluster */
4106 if (mux->force_key_unit_event) {
4107 gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
4108 mux->force_key_unit_event = NULL;
4110 cluster_time_scaled =
4111 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4113 mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
4114 mux->cluster_pos = ebml->pos;
4115 gst_ebml_write_set_cache (ebml, 0x20);
4117 gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4118 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4119 cluster_time_scaled);
4120 GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
4121 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
4122 gst_ebml_write_flush_cache (ebml, is_video_keyframe
4123 || is_audio_only, buffer_timestamp);
4124 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
4125 mux->prev_cluster_size);
4126 /* cluster_time needs to be identical in value to what's stored in the
4127 * matroska so we need to have it with the same precision as what's
4128 * possible with the set timecodescale rather than just using the
4130 * If this is not done the rounding of relative_timestamp will be
4131 * incorrect and possibly making the timestamps get out of order if tw
4132 * buffers arrive at the same millisecond (assuming default timecodescale
4135 gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4139 cluster_time_scaled =
4140 gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4141 mux->cluster_pos = ebml->pos;
4142 gst_ebml_write_set_cache (ebml, 0x20);
4143 mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4144 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4145 cluster_time_scaled);
4146 gst_ebml_write_flush_cache (ebml, TRUE, buffer_timestamp);
4147 /* cluster_time needs to be identical in value to what's stored in the
4148 * matroska so we need to have it with the same precision as what's
4149 * possible with the set timecodescale rather than just using the
4151 * If this is not done the rounding of relative_timestamp will be
4152 * incorrect and possibly making the timestamps get out of order if tw
4153 * buffers arrive at the same millisecond (assuming default timecodescale
4156 gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4159 /* We currently write index entries for all video tracks or for the audio
4160 * track in a single-track audio file. This could be improved by keeping the
4161 * index only for the *first* video track. */
4163 /* TODO: index is useful for every track, should contain the number of
4164 * the block in the cluster which contains the timestamp, should also work
4165 * for files with multiple audio tracks.
4167 if (!mux->ebml_write->streamable && (is_video_keyframe || is_audio_only)) {
4170 if (mux->min_index_interval != 0) {
4171 for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
4172 if (mux->index[last_idx].track == collect_pad->track->num)
4177 if (last_idx < 0 || mux->min_index_interval == 0 ||
4178 (GST_CLOCK_DIFF (mux->index[last_idx].time, buffer_timestamp)
4179 >= mux->min_index_interval)) {
4180 GstMatroskaIndex *idx;
4182 if (mux->num_indexes % 32 == 0) {
4183 mux->index = g_renew (GstMatroskaIndex, mux->index,
4184 mux->num_indexes + 32);
4186 idx = &mux->index[mux->num_indexes++];
4188 idx->pos = mux->cluster_pos;
4189 idx->time = buffer_timestamp;
4190 idx->track = collect_pad->track->num;
4194 /* Check if the duration differs from the default duration. */
4195 write_duration = FALSE;
4197 if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
4198 block_duration = GST_BUFFER_DURATION (buf) + duration_diff;
4199 block_duration = gst_util_uint64_scale (block_duration, 1, mux->time_scale);
4201 /* small difference should be ok. */
4202 if (block_duration > collect_pad->default_duration_scaled + 1 ||
4203 block_duration < collect_pad->default_duration_scaled - 1) {
4204 write_duration = TRUE;
4208 /* write the block, for doctype v2 use SimpleBlock if possible
4209 * one slice (*breath*).
4210 * FIXME: Need to do correct lacing! */
4211 relative_timestamp64 = buffer_timestamp - mux->cluster_time;
4212 if (relative_timestamp64 >= 0) {
4213 /* round the timestamp */
4214 relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
4215 relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
4218 /* round the timestamp */
4219 relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
4220 relative_timestamp =
4221 -((gint16) gst_util_uint64_scale (-relative_timestamp64, 1,
4225 if (is_video_invisible)
4228 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
4229 cmeta = gst_buffer_get_audio_clipping_meta (buf);
4230 g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);
4232 /* Start clipping is done via header and CodecDelay */
4233 if (cmeta && !cmeta->end)
4237 if (mux->doctype_version > 1 && !write_duration && !cmeta) {
4238 if (is_video_keyframe)
4242 gst_matroska_mux_create_buffer_header (collect_pad->track,
4243 relative_timestamp, flags);
4244 gst_ebml_write_set_cache (ebml, 0x40);
4245 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
4246 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4247 gst_ebml_write_buffer (ebml, hdr);
4248 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4249 gst_ebml_write_buffer (ebml, buf);
4251 return gst_ebml_last_write_result (ebml);
4253 gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
4254 /* write and call order slightly unnatural,
4255 * but avoids seek and minizes pushing */
4256 blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
4258 gst_matroska_mux_create_buffer_header (collect_pad->track,
4259 relative_timestamp, flags);
4261 gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
4263 if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4265 /* Start clipping is done via header and CodecDelay */
4268 gst_util_uint64_scale_round (cmeta->end, GST_SECOND, 48000);
4269 gst_ebml_write_sint (ebml, GST_MATROSKA_ID_DISCARDPADDING, end);
4273 gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
4274 gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4275 gst_ebml_write_buffer (ebml, hdr);
4276 gst_ebml_write_master_finish_full (ebml, blockgroup,
4277 gst_buffer_get_size (buf));
4278 gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4279 gst_ebml_write_buffer (ebml, buf);
4281 return gst_ebml_last_write_result (ebml);
4286 * gst_matroska_mux_handle_buffer:
4287 * @pads: #GstCollectPads
4288 * @uuser_data: #GstMatroskaMux
4290 * Collectpads callback.
4292 * Returns: #GstFlowReturn
4294 static GstFlowReturn
4295 gst_matroska_mux_handle_buffer (GstCollectPads * pads, GstCollectData * data,
4296 GstBuffer * buf, gpointer user_data)
4298 GstClockTime buffer_timestamp;
4299 GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
4300 GstEbmlWrite *ebml = mux->ebml_write;
4301 GstMatroskaPad *best = (GstMatroskaPad *) data;
4302 GstFlowReturn ret = GST_FLOW_OK;
4303 GST_DEBUG_OBJECT (mux, "Collected pads");
4305 /* start with a header */
4306 if (mux->state == GST_MATROSKA_MUX_STATE_START) {
4307 if (mux->collect->data == NULL) {
4308 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
4309 ("No input streams configured"));
4310 return GST_FLOW_ERROR;
4312 mux->state = GST_MATROSKA_MUX_STATE_HEADER;
4313 gst_ebml_start_streamheader (ebml);
4314 gst_matroska_mux_start (mux, best, buf);
4315 gst_matroska_mux_stop_streamheader (mux);
4316 mux->state = GST_MATROSKA_MUX_STATE_DATA;
4319 /* if there is no best pad, we have reached EOS */
4321 GST_DEBUG_OBJECT (mux, "No best pad. Finishing...");
4322 if (!mux->ebml_write->streamable) {
4323 gst_matroska_mux_finish (mux);
4325 GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
4327 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
4332 if (best->track->codec_id == NULL) {
4333 GST_ERROR_OBJECT (best->collect.pad, "No codec-id for pad");
4334 ret = GST_FLOW_NOT_NEGOTIATED;
4338 /* if we have a best stream, should also have a buffer */
4341 buffer_timestamp = gst_matroska_track_get_buffer_timestamp (best->track, buf);
4342 if (buffer_timestamp >= mux->earliest_time) {
4343 buffer_timestamp -= mux->earliest_time;
4345 GST_ERROR_OBJECT (mux,
4346 "PTS before first PTS (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")",
4347 GST_TIME_ARGS (buffer_timestamp), GST_TIME_ARGS (mux->earliest_time));
4348 buffer_timestamp = 0;
4351 GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
4352 GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
4353 GST_TIME_ARGS (buffer_timestamp),
4354 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
4356 /* make note of first and last encountered timestamps, so we can calculate
4357 * the actual duration later when we send an updated header on eos */
4358 if (GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
4359 GstClockTime start_ts = buffer_timestamp;
4360 GstClockTime end_ts = start_ts;
4362 if (GST_BUFFER_DURATION_IS_VALID (buf))
4363 end_ts += GST_BUFFER_DURATION (buf);
4364 else if (best->track->default_duration)
4365 end_ts += best->track->default_duration;
4367 if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
4368 best->end_ts = end_ts;
4370 if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
4371 start_ts < best->start_ts))
4372 best->start_ts = start_ts;
4375 /* write one buffer */
4376 ret = gst_matroska_mux_write_data (mux, best, buf);
4384 * gst_matroska_mux_change_state:
4385 * @element: #GstMatroskaMux
4386 * @transition: State change transition.
4388 * Change the muxer state.
4390 * Returns: #GstStateChangeReturn
4392 static GstStateChangeReturn
4393 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
4395 GstStateChangeReturn ret;
4396 GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
4398 switch (transition) {
4399 case GST_STATE_CHANGE_NULL_TO_READY:
4401 case GST_STATE_CHANGE_READY_TO_PAUSED:
4402 gst_collect_pads_start (mux->collect);
4404 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4406 case GST_STATE_CHANGE_PAUSED_TO_READY:
4407 gst_collect_pads_stop (mux->collect);
4413 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4415 switch (transition) {
4416 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4418 case GST_STATE_CHANGE_PAUSED_TO_READY:
4419 gst_matroska_mux_reset (GST_ELEMENT (mux));
4421 case GST_STATE_CHANGE_READY_TO_NULL:
4431 gst_matroska_mux_set_property (GObject * object,
4432 guint prop_id, const GValue * value, GParamSpec * pspec)
4434 GstMatroskaMux *mux;
4436 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4437 mux = GST_MATROSKA_MUX (object);
4440 case PROP_WRITING_APP:
4441 if (!g_value_get_string (value)) {
4442 GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
4445 g_free (mux->writing_app);
4446 mux->writing_app = g_value_dup_string (value);
4448 case PROP_DOCTYPE_VERSION:
4449 mux->doctype_version = g_value_get_int (value);
4451 case PROP_MIN_INDEX_INTERVAL:
4452 mux->min_index_interval = g_value_get_int64 (value);
4454 case PROP_STREAMABLE:
4455 mux->ebml_write->streamable = g_value_get_boolean (value);
4457 case PROP_TIMECODESCALE:
4458 mux->time_scale = g_value_get_int64 (value);
4460 case PROP_MIN_CLUSTER_DURATION:
4461 mux->min_cluster_duration = g_value_get_int64 (value);
4463 case PROP_MAX_CLUSTER_DURATION:
4464 mux->max_cluster_duration = g_value_get_int64 (value);
4466 case PROP_OFFSET_TO_ZERO:
4467 mux->offset_to_zero = g_value_get_boolean (value);
4469 case PROP_CREATION_TIME:
4470 g_clear_pointer (&mux->creation_time, g_date_time_unref);
4471 mux->creation_time = g_value_dup_boxed (value);
4473 case PROP_CLUSTER_TIMESTAMP_OFFSET:
4474 mux->cluster_timestamp_offset = g_value_get_uint64 (value);
4477 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4483 gst_matroska_mux_get_property (GObject * object,
4484 guint prop_id, GValue * value, GParamSpec * pspec)
4486 GstMatroskaMux *mux;
4488 g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4489 mux = GST_MATROSKA_MUX (object);
4492 case PROP_WRITING_APP:
4493 g_value_set_string (value, mux->writing_app);
4495 case PROP_DOCTYPE_VERSION:
4496 g_value_set_int (value, mux->doctype_version);
4498 case PROP_MIN_INDEX_INTERVAL:
4499 g_value_set_int64 (value, mux->min_index_interval);
4501 case PROP_STREAMABLE:
4502 g_value_set_boolean (value, mux->ebml_write->streamable);
4504 case PROP_TIMECODESCALE:
4505 g_value_set_int64 (value, mux->time_scale);
4507 case PROP_MIN_CLUSTER_DURATION:
4508 g_value_set_int64 (value, mux->min_cluster_duration);
4510 case PROP_MAX_CLUSTER_DURATION:
4511 g_value_set_int64 (value, mux->max_cluster_duration);
4513 case PROP_OFFSET_TO_ZERO:
4514 g_value_set_boolean (value, mux->offset_to_zero);
4516 case PROP_CREATION_TIME:
4517 g_value_set_boxed (value, mux->creation_time);
4519 case PROP_CLUSTER_TIMESTAMP_OFFSET:
4520 g_value_set_uint64 (value, mux->cluster_timestamp_offset);
4523 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);