Merging gst-rtsp-server
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-good / gst / matroska / matroska-mux.c
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>
6  *
7  * matroska-mux.c: matroska file/stream muxer
8  *
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.
13  *
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.
18  *
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.
23  */
24
25 /* TODO: - check everywhere that we don't write invalid values
26  *       - make sure timestamps are correctly scaled everywhere
27  */
28
29 /**
30  * SECTION:element-matroskamux
31  * @title: matroskamux
32  *
33  * matroskamux muxes different input streams into a Matroska file.
34  *
35  * ## Example launch line
36  * |[
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.
39  * |[
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.
42  *
43  */
44
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
48
49 #include <math.h>
50 #include <stdio.h>
51 #include <string.h>
52
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>
57
58 #include "gstmatroskaelements.h"
59 #include "matroska-mux.h"
60 #include "matroska-ids.h"
61
62 #define GST_MATROSKA_MUX_CHAPLANG "und"
63
64 GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
65 #define GST_CAT_DEFAULT matroskamux_debug
66
67 enum
68 {
69   PROP_0,
70   PROP_WRITING_APP,
71   PROP_DOCTYPE_VERSION,
72   PROP_MIN_INDEX_INTERVAL,
73   PROP_STREAMABLE,
74   PROP_TIMECODESCALE,
75   PROP_MIN_CLUSTER_DURATION,
76   PROP_MAX_CLUSTER_DURATION,
77   PROP_OFFSET_TO_ZERO,
78   PROP_CREATION_TIME,
79   PROP_CLUSTER_TIMESTAMP_OFFSET,
80 };
81
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
91
92 /* WAVEFORMATEX is gst_riff_strf_auds + an extra guint16 extension size */
93 #define WAVEFORMATEX_SIZE  (2 + sizeof (gst_riff_strf_auds))
94
95 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
96     GST_PAD_SRC,
97     GST_PAD_ALWAYS,
98     GST_STATIC_CAPS ("video/x-matroska; video/x-matroska-3d; audio/x-matroska")
99     );
100
101 #define COMMON_VIDEO_CAPS \
102   "width = (int) [ 1, MAX ], " \
103   "height = (int) [ 1, MAX ] "
104
105 /* FIXME:
106  * * require codec data, etc as needed
107  */
108
109 static GstStaticPadTemplate videosink_templ =
110     GST_STATIC_PAD_TEMPLATE ("video_%u",
111     GST_PAD_SINK,
112     GST_PAD_REQUEST,
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 "; "
121         "video/x-divx, "
122         COMMON_VIDEO_CAPS "; "
123         "video/x-huffyuv, "
124         COMMON_VIDEO_CAPS "; "
125         "video/x-dv, "
126         COMMON_VIDEO_CAPS "; "
127         "video/x-h263, "
128         COMMON_VIDEO_CAPS "; "
129         "video/x-msmpeg, "
130         COMMON_VIDEO_CAPS "; "
131         "image/jpeg, "
132         COMMON_VIDEO_CAPS "; "
133         "video/x-theora; "
134         "video/x-dirac, "
135         COMMON_VIDEO_CAPS "; "
136         "video/x-pn-realvideo, "
137         "rmversion = (int) [1, 4], "
138         COMMON_VIDEO_CAPS "; "
139         "video/x-vp8, "
140         COMMON_VIDEO_CAPS "; "
141         "video/x-vp9, "
142         COMMON_VIDEO_CAPS "; "
143         "video/x-raw, "
144         "format = (string) { YUY2, I420, YV12, UYVY, AYUV, GRAY8, BGR, RGB }, "
145         COMMON_VIDEO_CAPS "; "
146         "video/x-prores, "
147         COMMON_VIDEO_CAPS "; "
148         "video/x-wmv, " "wmvversion = (int) [ 1, 3 ], " COMMON_VIDEO_CAPS "; "
149         "video/x-av1, " COMMON_VIDEO_CAPS ";"
150         "video/x-ffv, ffversion = (int) 1, " COMMON_VIDEO_CAPS)
151     );
152
153 #define COMMON_AUDIO_CAPS \
154   "channels = (int) [ 1, MAX ], " \
155   "rate = (int) [ 1, MAX ]"
156
157 /* FIXME:
158  * * require codec data, etc as needed
159  */
160 static GstStaticPadTemplate audiosink_templ =
161     GST_STATIC_PAD_TEMPLATE ("audio_%u",
162     GST_PAD_SINK,
163     GST_PAD_REQUEST,
164     GST_STATIC_CAPS ("audio/mpeg, "
165         "mpegversion = (int) 1, "
166         "layer = (int) [ 1, 3 ], "
167         COMMON_AUDIO_CAPS "; "
168         "audio/mpeg, "
169         "mpegversion = (int) { 2, 4 }, "
170         "stream-format = (string) raw, "
171         COMMON_AUDIO_CAPS "; "
172         "audio/x-ac3, "
173         COMMON_AUDIO_CAPS "; "
174         "audio/x-eac3, "
175         COMMON_AUDIO_CAPS "; "
176         "audio/x-dts, "
177         COMMON_AUDIO_CAPS "; "
178         "audio/x-vorbis, "
179         COMMON_AUDIO_CAPS "; "
180         "audio/x-flac, "
181         COMMON_AUDIO_CAPS "; "
182         "audio/x-opus; "
183         "audio/x-speex, "
184         COMMON_AUDIO_CAPS "; "
185         "audio/x-raw, "
186         "format = (string) { U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }, "
187         "layout = (string) interleaved, "
188         COMMON_AUDIO_CAPS ";"
189         "audio/x-tta, "
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 ";"
197         "audio/x-alaw, "
198         "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
199         "audio/x-mulaw, "
200         "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
201         "audio/x-adpcm, "
202         "layout = (string)dvi, "
203         "block_align = (int)[64, 8192], "
204         "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
205         "audio/G722, "
206         "channels = (int)1," "rate = (int)16000; "
207         "audio/x-adpcm, "
208         "layout = (string)g726, " "channels = (int)1," "rate = (int)8000; ")
209     );
210
211 static GstStaticPadTemplate subtitlesink_templ =
212     GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
213     GST_PAD_SINK,
214     GST_PAD_REQUEST,
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")
219     );
220
221 static gpointer parent_class;   /* NULL */
222
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);
227
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);
233
234 /* pad functions */
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);
240
241 /* gst internal change state handler */
242 static GstStateChangeReturn
243 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
244
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);
250
251 /* reset muxer */
252 static void gst_matroska_mux_reset (GstElement * element);
253
254 /* uid generation */
255 static guint64 gst_matroska_mux_create_uid (GstMatroskaMux * mux);
256
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);
267 static void
268 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
269     gpointer data);
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);
273
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 */
277 GType
278 gst_matroska_mux_get_type (void)
279 {
280   static GType object_type;     /* 0 */
281
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),
291       0,                        /* n_preallocs */
292       (GInstanceInitFunc) gst_matroska_mux_init
293     };
294     const GInterfaceInfo iface_info = { NULL };
295
296     object_type = g_type_register_static (GST_TYPE_ELEMENT,
297         "GstMatroskaMux", &object_info, (GTypeFlags) 0);
298
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);
301   }
302
303   return object_type;
304 }
305
306 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (matroskamux, "matroskamux",
307     GST_RANK_PRIMARY, GST_TYPE_MATROSKA_MUX, matroska_element_init (plugin));
308
309 static void
310 gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
311 {
312   GObjectClass *gobject_class;
313   GstElementClass *gstelement_class;
314
315   gobject_class = (GObjectClass *) klass;
316   gstelement_class = (GstElementClass *) klass;
317
318   gst_element_class_add_static_pad_template (gstelement_class,
319       &videosink_templ);
320   gst_element_class_add_static_pad_template (gstelement_class,
321       &audiosink_templ);
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",
326       "Codec/Muxer",
327       "Muxes video/audio/subtitle streams into a matroska stream",
328       "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
329
330   GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
331       "Matroska muxer");
332
333   gobject_class->finalize = gst_matroska_mux_finalize;
334
335   gobject_class->get_property = gst_matroska_mux_get_property;
336   gobject_class->set_property = gst_matroska_mux_set_property;
337
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));
385
386   /**
387    * GstMatroskaMux:cluster-timestamp-offset:
388    *
389    * An offset to add to all clusters/blocks (in nanoseconds)
390    *
391    * Since: 1.20
392    */
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));
399
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);
406
407   parent_class = g_type_class_peek_parent (klass);
408 }
409
410 /*
411  * Start of pad option handler code
412  */
413 #define DEFAULT_PAD_FRAME_DURATION TRUE
414
415 enum
416 {
417   PROP_PAD_0,
418   PROP_PAD_FRAME_DURATION
419 };
420
421 typedef struct
422 {
423   GstPad parent;
424   gboolean frame_duration;
425   gboolean frame_duration_user;
426 } GstMatroskamuxPad;
427
428 typedef GstPadClass GstMatroskamuxPadClass;
429
430 GType gst_matroskamux_pad_get_type (void);
431 G_DEFINE_TYPE (GstMatroskamuxPad, gst_matroskamux_pad, GST_TYPE_PAD);
432
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))
437
438 static void
439 gst_matroskamux_pad_get_property (GObject * object, guint prop_id,
440     GValue * value, GParamSpec * pspec)
441 {
442   GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
443
444   switch (prop_id) {
445     case PROP_PAD_FRAME_DURATION:
446       g_value_set_boolean (value, pad->frame_duration);
447       break;
448     default:
449       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
450       break;
451   }
452 }
453
454 static void
455 gst_matroskamux_pad_set_property (GObject * object, guint prop_id,
456     const GValue * value, GParamSpec * pspec)
457 {
458   GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
459
460   switch (prop_id) {
461     case PROP_PAD_FRAME_DURATION:
462       pad->frame_duration = g_value_get_boolean (value);
463       pad->frame_duration_user = TRUE;
464       break;
465     default:
466       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
467       break;
468   }
469 }
470
471 static void
472 gst_matroskamux_pad_class_init (GstMatroskamuxPadClass * klass)
473 {
474   GObjectClass *gobject_class = (GObjectClass *) klass;
475
476   gobject_class->set_property = gst_matroskamux_pad_set_property;
477   gobject_class->get_property = gst_matroskamux_pad_get_property;
478
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));
483 }
484
485 static void
486 gst_matroskamux_pad_init (GstMatroskamuxPad * pad)
487 {
488   pad->frame_duration = DEFAULT_PAD_FRAME_DURATION;
489   pad->frame_duration_user = FALSE;
490 }
491
492 /*
493  * End of pad option handler code
494  **/
495
496 static void
497 gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class)
498 {
499   GstPadTemplate *templ;
500
501   templ =
502       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
503   mux->srcpad = gst_pad_new_from_template (templ, "src");
504
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);
508
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);
516
517   mux->ebml_write = gst_ebml_write_new (mux->srcpad);
518   mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
519
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;
529
530   /* initialize internal variables */
531   mux->index = NULL;
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;
537
538   /* initialize remaining variables */
539   gst_matroska_mux_reset (GST_ELEMENT (mux));
540 }
541
542
543 /**
544  * gst_matroska_mux_finalize:
545  * @object: #GstMatroskaMux that should be finalized.
546  *
547  * Finalize matroska muxer.
548  */
549 static void
550 gst_matroska_mux_finalize (GObject * object)
551 {
552   GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
553
554   gst_event_replace (&mux->force_key_unit_event, NULL);
555
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);
560
561   if (mux->internal_toc) {
562     gst_toc_unref (mux->internal_toc);
563     mux->internal_toc = NULL;
564   }
565
566   G_OBJECT_CLASS (parent_class)->finalize (object);
567 }
568
569
570 /**
571  * gst_matroska_mux_create_uid:
572  * @mux: #GstMatroskaMux to generate UID for.
573  *
574  * Generate new track UID.
575  *
576  * Returns: New track UID.
577  */
578 static guint64
579 gst_matroska_mux_create_uid (GstMatroskaMux * mux)
580 {
581   return (((guint64) g_random_int ()) << 32) | g_random_int ();
582 }
583
584
585 /**
586  * gst_matroska_pad_reset:
587  * @collect_pad: the #GstMatroskaPad
588  *
589  * Reset and/or release resources of a matroska collect pad.
590  */
591 static void
592 gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
593 {
594   gchar *name = NULL;
595   GstMatroskaTrackType type = 0;
596
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;
606
607       if (ctx->dirac_unit) {
608         gst_buffer_unref (ctx->dirac_unit);
609         ctx->dirac_unit = NULL;
610       }
611     }
612     g_free (collect_pad->track->codec_id);
613     g_free (collect_pad->track->codec_name);
614     if (full)
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;
623     }
624   }
625
626   if (!full && type != 0) {
627     GstMatroskaTrackContext *context;
628
629     /* create a fresh context */
630     switch (type) {
631       case GST_MATROSKA_TRACK_TYPE_VIDEO:
632         context = (GstMatroskaTrackContext *)
633             g_new0 (GstMatroskaTrackVideoContext, 1);
634         break;
635       case GST_MATROSKA_TRACK_TYPE_AUDIO:
636         context = (GstMatroskaTrackContext *)
637             g_new0 (GstMatroskaTrackAudioContext, 1);
638         break;
639       case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
640         context = (GstMatroskaTrackContext *)
641             g_new0 (GstMatroskaTrackSubtitleContext, 1);
642         break;
643       default:
644         g_assert_not_reached ();
645         return;
646     }
647
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);
658   }
659 }
660
661 /**
662  * gst_matroska_pad_free:
663  * @collect_pad: the #GstMatroskaPad
664  *
665  * Release resources of a matroska collect pad.
666  */
667 static void
668 gst_matroska_pad_free (GstPad * collect_pad)
669 {
670   gst_matroska_pad_reset ((GstMatroskaPad *) collect_pad, TRUE);
671 }
672
673
674 /**
675  * gst_matroska_mux_reset:
676  * @element: #GstMatroskaMux that should be reset.
677  *
678  * Reset matroska muxer back to initial state.
679  */
680 static void
681 gst_matroska_mux_reset (GstElement * element)
682 {
683   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
684   GSList *walk;
685
686   /* reset EBML write */
687   gst_ebml_write_reset (mux->ebml_write);
688
689   /* reset input */
690   mux->state = GST_MATROSKA_MUX_STATE_START;
691
692   /* clean up existing streams */
693
694   for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
695     GstMatroskaPad *collect_pad;
696
697     collect_pad = (GstMatroskaPad *) walk->data;
698
699     /* reset collect pad to pristine state */
700     gst_matroska_pad_reset (collect_pad, FALSE);
701   }
702
703   /* reset indexes */
704   mux->num_indexes = 0;
705   g_free (mux->index);
706   mux->index = NULL;
707
708   /* reset timers */
709   mux->duration = 0;
710
711   /* reset cluster */
712   mux->cluster = 0;
713   mux->cluster_time = 0;
714   mux->cluster_pos = 0;
715   mux->prev_cluster_size = 0;
716
717   /* reset tags */
718   gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
719
720   mux->tags_pos = 0;
721
722   /* reset chapters */
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;
727   }
728
729   mux->chapters_pos = 0;
730 }
731
732 /**
733  * gst_matroska_mux_handle_src_event:
734  * @pad: Pad which received the event.
735  * @event: Received event.
736  *
737  * handle events - copied from oggmux without understanding
738  *
739  * Returns: %TRUE on success.
740  */
741 static gboolean
742 gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
743     GstEvent * event)
744 {
745   GstEventType type;
746
747   type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
748
749   switch (type) {
750     case GST_EVENT_SEEK:
751       /* disable seeking for now */
752       return FALSE;
753     default:
754       break;
755   }
756
757   return gst_pad_event_default (pad, parent, event);
758 }
759
760
761 static void
762 gst_matroska_mux_free_codec_priv (GstMatroskaTrackContext * context)
763 {
764   if (context->codec_priv != NULL) {
765     g_free (context->codec_priv);
766     context->codec_priv = NULL;
767     context->codec_priv_size = 0;
768   }
769 }
770
771 static void
772 gst_matroska_mux_build_vobsub_private (GstMatroskaTrackContext * context,
773     const guint * clut)
774 {
775   gchar *clutv[17];
776   gchar *sclut;
777   gint i;
778   guint32 col;
779   gdouble y, u, v;
780   guint8 r, g, b;
781
782   /* produce comma-separated list in hex format */
783   for (i = 0; i < 16; ++i) {
784     col = clut[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);
793   }
794   clutv[i] = NULL;
795   sclut = g_strjoinv (",", clutv);
796
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;
802   g_free (sclut);
803   for (i = 0; i < 16; ++i) {
804     g_free (clutv[i]);
805   }
806 }
807
808
809 /**
810  * gst_matroska_mux_handle_sink_event:
811  * @pad: Pad which received the event.
812  * @event: Received event.
813  *
814  * handle events - informational ones like tags
815  *
816  * Returns: %TRUE on success.
817  */
818 static gboolean
819 gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
820     GstCollectData * data, GstEvent * event, gpointer user_data)
821 {
822   GstMatroskaPad *collect_pad;
823   GstMatroskaTrackContext *context;
824   GstMatroskaMux *mux;
825   GstPad *pad;
826   GstTagList *list;
827   gboolean ret = TRUE;
828
829   mux = GST_MATROSKA_MUX (user_data);
830   collect_pad = (GstMatroskaPad *) data;
831   pad = data->pad;
832   context = collect_pad->track;
833   g_assert (context);
834
835   switch (GST_EVENT_TYPE (event)) {
836     case GST_EVENT_CAPS:{
837       GstCaps *caps;
838
839       collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
840       gst_event_parse_caps (event, &caps);
841
842       ret = collect_pad->capsfunc (pad, caps);
843       gst_event_unref (event);
844       event = NULL;
845       break;
846     }
847     case GST_EVENT_TAG:{
848       gchar *lang = NULL;
849
850       GST_DEBUG_OBJECT (mux, "received tag event");
851       gst_event_parse_tag (event, &list);
852
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;
856
857         lang_code = gst_tag_get_language_code_iso_639_2B (lang);
858         if (lang_code) {
859           GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
860           g_free (context->language);
861           context->language = g_strdup (lang_code);
862         } else {
863           GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
864         }
865         g_free (lang);
866       }
867
868       /* FIXME: what about stream-specific tags? */
869       if (gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL) {
870         gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
871             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
872       } else {
873         gst_tag_list_insert (collect_pad->tags, list, GST_TAG_MERGE_REPLACE);
874       }
875
876       gst_event_unref (event);
877       /* handled this, don't want collectpads to forward it downstream */
878       event = NULL;
879       ret = TRUE;
880       break;
881     }
882     case GST_EVENT_TOC:{
883       GstToc *toc, *old_toc;
884
885       if (mux->chapters_pos > 0)
886         break;
887
888       GST_DEBUG_OBJECT (mux, "received toc event");
889       gst_event_parse_toc (event, &toc, NULL);
890
891       if (toc != NULL) {
892         old_toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
893         if (old_toc != NULL) {
894           if (old_toc != toc)
895             GST_INFO_OBJECT (pad, "Replacing TOC with a new one");
896           gst_toc_unref (old_toc);
897         }
898
899         gst_toc_setter_set_toc (GST_TOC_SETTER (mux), toc);
900         gst_toc_unref (toc);
901       }
902
903       gst_event_unref (event);
904       /* handled this, don't want collectpads to forward it downstream */
905       event = NULL;
906       break;
907     }
908     case GST_EVENT_CUSTOM_DOWNSTREAM:
909     case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY:{
910       const GstStructure *structure;
911
912       structure = gst_event_get_structure (event);
913       if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
914         gst_event_replace (&mux->force_key_unit_event, NULL);
915         mux->force_key_unit_event = event;
916         event = NULL;
917       } else if (gst_structure_has_name (structure, "application/x-gst-dvd") &&
918           !strcmp ("dvd-spu-clut-change",
919               gst_structure_get_string (structure, "event"))) {
920         gchar name[16];
921         gint i, value;
922         guint clut[16];
923
924         GST_DEBUG_OBJECT (pad, "New DVD colour table received");
925         if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
926           GST_DEBUG_OBJECT (pad, "... discarding");
927           break;
928         }
929         /* first transform event data into table form */
930         for (i = 0; i < 16; i++) {
931           g_snprintf (name, sizeof (name), "clut%02d", i);
932           if (!gst_structure_get_int (structure, name, &value)) {
933             GST_ERROR_OBJECT (mux, "dvd-spu-clut-change event did not "
934                 "contain %s field", name);
935             goto break_hard;
936           }
937           clut[i] = value;
938         }
939
940         /* transform into private data for stream; text form */
941         gst_matroska_mux_build_vobsub_private (context, clut);
942       }
943     }
944       /* fall through */
945     default:
946       break;
947   }
948
949 break_hard:
950   if (event != NULL)
951     return gst_collect_pads_event_default (pads, data, event, FALSE);
952
953   return ret;
954 }
955
956 static void
957 gst_matroska_mux_set_codec_id (GstMatroskaTrackContext * context,
958     const char *id)
959 {
960   g_assert (context && id);
961   g_free (context->codec_id);
962   context->codec_id = g_strdup (id);
963 }
964
965 static gboolean
966 check_field (GQuark field_id, const GValue * value, gpointer user_data)
967 {
968   GstStructure *structure = (GstStructure *) user_data;
969   const gchar *name = gst_structure_get_name (structure);
970
971   if ((g_strcmp0 (name, "video/x-h264") == 0 &&
972           !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
973               "avc3")) || (g_strcmp0 (name, "video/x-h265") == 0
974           && !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
975               "hev1"))
976       ) {
977     /* While in theory, matroska only supports avc1 / hvc1, and doesn't support codec_data
978      * changes, in practice most decoders will use in-band SPS / PPS (avc3 / hev1), if the
979      * input stream is avc3 / hev1 we let the new codec_data slide to support "smart" encoding.
980      *
981      * We don't warn here as we already warned elsewhere.
982      */
983     if (field_id == g_quark_from_static_string ("codec_data")) {
984       return FALSE;
985     } else if (field_id == g_quark_from_static_string ("tier")) {
986       return FALSE;
987     } else if (field_id == g_quark_from_static_string ("profile")) {
988       return FALSE;
989     } else if (field_id == g_quark_from_static_string ("level")) {
990       return FALSE;
991     }
992   }
993
994   return TRUE;
995 }
996
997 static gboolean
998 check_new_caps (GstCaps * old_caps, GstCaps * new_caps)
999 {
1000   GstStructure *old_s, *new_s;
1001   gboolean ret;
1002
1003   old_caps = gst_caps_copy (old_caps);
1004   new_caps = gst_caps_copy (new_caps);
1005
1006   new_s = gst_caps_get_structure (new_caps, 0);
1007   old_s = gst_caps_get_structure (old_caps, 0);
1008
1009   gst_structure_filter_and_map_in_place (new_s,
1010       (GstStructureFilterMapFunc) check_field, new_s);
1011   gst_structure_filter_and_map_in_place (old_s,
1012       (GstStructureFilterMapFunc) check_field, old_s);
1013
1014   ret = gst_caps_is_subset (new_caps, old_caps);
1015
1016   gst_caps_unref (new_caps);
1017   gst_caps_unref (old_caps);
1018
1019   return ret;
1020 }
1021
1022 /**
1023  * gst_matroska_mux_video_pad_setcaps:
1024  * @pad: Pad which got the caps.
1025  * @caps: New caps.
1026  *
1027  * Setcaps function for video sink pad.
1028  *
1029  * Returns: %TRUE on success.
1030  */
1031 static gboolean
1032 gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
1033 {
1034   GstMatroskaTrackContext *context = NULL;
1035   GstMatroskaTrackVideoContext *videocontext;
1036   GstMatroskaMux *mux;
1037   GstMatroskaPad *collect_pad;
1038   GstStructure *structure;
1039   const gchar *mimetype;
1040   const gchar *interlace_mode, *s;
1041   const GValue *value = NULL;
1042   GstBuffer *codec_buf = NULL;
1043   gint width, height, pixel_width, pixel_height;
1044   gint fps_d, fps_n;
1045   guint multiview_flags;
1046   GstCaps *old_caps;
1047
1048   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1049
1050   if ((old_caps = gst_pad_get_current_caps (pad))) {
1051     if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1052         && !check_new_caps (old_caps, caps)) {
1053       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1054           ("Caps changes are not supported by Matroska\nCurrent: `%"
1055               GST_PTR_FORMAT "`\nNew: `%" GST_PTR_FORMAT "`", old_caps, caps));
1056       gst_caps_unref (old_caps);
1057       goto refuse_caps;
1058     }
1059     gst_caps_unref (old_caps);
1060   } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
1061     GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1062         ("Caps on pad %" GST_PTR_FORMAT
1063             " arrived late. Headers were already written", pad));
1064     goto refuse_caps;
1065   }
1066
1067   /* find context */
1068   collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1069   g_assert (collect_pad);
1070   context = collect_pad->track;
1071   g_assert (context);
1072   g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
1073   videocontext = (GstMatroskaTrackVideoContext *) context;
1074
1075   /* gst -> matroska ID'ing */
1076   structure = gst_caps_get_structure (caps, 0);
1077
1078   mimetype = gst_structure_get_name (structure);
1079
1080   interlace_mode = gst_structure_get_string (structure, "interlace-mode");
1081   if (interlace_mode != NULL) {
1082     if (strcmp (interlace_mode, "progressive") == 0)
1083       videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE;
1084     else
1085       videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_INTERLACED;
1086   } else {
1087     videocontext->interlace_mode = GST_MATROSKA_INTERLACE_MODE_UNKNOWN;
1088   }
1089
1090   if (!strcmp (mimetype, "video/x-theora")) {
1091     /* we'll extract the details later from the theora identification header */
1092     goto skip_details;
1093   }
1094
1095   /* get general properties */
1096   /* spec says it is mandatory */
1097   if (!gst_structure_get_int (structure, "width", &width) ||
1098       !gst_structure_get_int (structure, "height", &height))
1099     goto refuse_caps;
1100
1101   videocontext->pixel_width = width;
1102   videocontext->pixel_height = height;
1103
1104   if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
1105       && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
1106       && fps_n > 0) {
1107     context->default_duration =
1108         gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
1109     GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
1110         GST_TIME_ARGS (context->default_duration));
1111   } else {
1112     context->default_duration = 0;
1113   }
1114   if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
1115           &pixel_width, &pixel_height)) {
1116     if (pixel_width > pixel_height) {
1117       videocontext->display_width = width * pixel_width / pixel_height;
1118       videocontext->display_height = height;
1119     } else if (pixel_width < pixel_height) {
1120       videocontext->display_width = width;
1121       videocontext->display_height = height * pixel_height / pixel_width;
1122     } else {
1123       videocontext->display_width = 0;
1124       videocontext->display_height = 0;
1125     }
1126   } else {
1127     videocontext->display_width = 0;
1128     videocontext->display_height = 0;
1129   }
1130
1131   if ((s = gst_structure_get_string (structure, "colorimetry"))) {
1132     if (!gst_video_colorimetry_from_string (&videocontext->colorimetry, s)) {
1133       GST_WARNING_OBJECT (pad, "Could not parse colorimetry %s", s);
1134     }
1135   }
1136
1137   if ((s = gst_structure_get_string (structure, "mastering-display-info"))) {
1138     if (!gst_video_mastering_display_info_from_string
1139         (&videocontext->mastering_display_info, s)) {
1140       GST_WARNING_OBJECT (pad, "Could not parse mastering-display-metadata %s",
1141           s);
1142     } else {
1143       videocontext->mastering_display_info_present = TRUE;
1144     }
1145   }
1146
1147   if ((s = gst_structure_get_string (structure, "content-light-level"))) {
1148     if (!gst_video_content_light_level_from_string
1149         (&videocontext->content_light_level, s))
1150       GST_WARNING_OBJECT (pad, "Could not parse content-light-level %s", s);
1151   }
1152
1153   /* Collect stereoscopic info, if any */
1154   if ((s = gst_structure_get_string (structure, "multiview-mode")))
1155     videocontext->multiview_mode =
1156         gst_video_multiview_mode_from_caps_string (s);
1157   gst_structure_get_flagset (structure, "multiview-flags", &multiview_flags,
1158       NULL);
1159   videocontext->multiview_flags = multiview_flags;
1160
1161
1162 skip_details:
1163
1164   videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
1165   videocontext->fourcc = 0;
1166
1167   /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1168    *         data and other settings
1169    *       - add new formats
1170    */
1171
1172   /* extract codec_data, may turn out needed */
1173   value = gst_structure_get_value (structure, "codec_data");
1174   if (value)
1175     codec_buf = (GstBuffer *) gst_value_get_buffer (value);
1176
1177   /* find type */
1178   if (!strcmp (mimetype, "video/x-raw")) {
1179     const gchar *fstr;
1180     gst_matroska_mux_set_codec_id (context,
1181         GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
1182     fstr = gst_structure_get_string (structure, "format");
1183     if (fstr) {
1184       if (strlen (fstr) == 4)
1185         videocontext->fourcc = GST_STR_FOURCC (fstr);
1186       else if (!strcmp (fstr, "GRAY8"))
1187         videocontext->fourcc = GST_MAKE_FOURCC ('Y', '8', '0', '0');
1188       else if (!strcmp (fstr, "BGR"))
1189         videocontext->fourcc = GST_MAKE_FOURCC ('B', 'G', 'R', 24);
1190       else if (!strcmp (fstr, "RGB"))
1191         videocontext->fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', 24);
1192     }
1193   } else if (!strcmp (mimetype, "video/x-huffyuv")      /* MS/VfW compatibility cases */
1194       ||!strcmp (mimetype, "video/x-divx")
1195       || !strcmp (mimetype, "video/x-dv")
1196       || !strcmp (mimetype, "video/x-h263")
1197       || !strcmp (mimetype, "video/x-msmpeg")
1198       || !strcmp (mimetype, "video/x-wmv")
1199       || !strcmp (mimetype, "image/jpeg")) {
1200     gst_riff_strf_vids *bih;
1201     gint size = sizeof (gst_riff_strf_vids);
1202     guint32 fourcc = 0;
1203
1204     if (!strcmp (mimetype, "video/x-huffyuv"))
1205       fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
1206     else if (!strcmp (mimetype, "video/x-dv"))
1207       fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
1208     else if (!strcmp (mimetype, "video/x-h263"))
1209       fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
1210     else if (!strcmp (mimetype, "video/x-divx")) {
1211       gint divxversion;
1212
1213       gst_structure_get_int (structure, "divxversion", &divxversion);
1214       switch (divxversion) {
1215         case 3:
1216           fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
1217           break;
1218         case 4:
1219           fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
1220           break;
1221         case 5:
1222           fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
1223           break;
1224       }
1225     } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1226       gint msmpegversion;
1227
1228       gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
1229       switch (msmpegversion) {
1230         case 41:
1231           fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
1232           break;
1233         case 42:
1234           fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
1235           break;
1236         case 43:
1237           goto msmpeg43;
1238           break;
1239       }
1240     } else if (!strcmp (mimetype, "video/x-wmv")) {
1241       gint wmvversion;
1242       const gchar *fstr;
1243
1244       fstr = gst_structure_get_string (structure, "format");
1245       if (fstr && strlen (fstr) == 4) {
1246         fourcc = GST_STR_FOURCC (fstr);
1247       } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
1248         if (wmvversion == 2) {
1249           fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
1250         } else if (wmvversion == 1) {
1251           fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
1252         } else if (wmvversion == 3) {
1253           fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
1254         }
1255       }
1256     } else if (!strcmp (mimetype, "image/jpeg")) {
1257       fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
1258     }
1259
1260     if (!fourcc)
1261       goto refuse_caps;
1262
1263     bih = g_new0 (gst_riff_strf_vids, 1);
1264     GST_WRITE_UINT32_LE (&bih->size, size);
1265     GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
1266     GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
1267     GST_WRITE_UINT32_LE (&bih->compression, fourcc);
1268     GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
1269     GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
1270     GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
1271         videocontext->pixel_height * 3);
1272
1273     /* process codec private/initialization data, if any */
1274     if (codec_buf) {
1275       size += gst_buffer_get_size (codec_buf);
1276       bih = g_realloc (bih, size);
1277       GST_WRITE_UINT32_LE (&bih->size, size);
1278       gst_buffer_extract (codec_buf, 0,
1279           (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
1280     }
1281
1282     gst_matroska_mux_set_codec_id (context,
1283         GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
1284     gst_matroska_mux_free_codec_priv (context);
1285     context->codec_priv = (gpointer) bih;
1286     context->codec_priv_size = size;
1287     context->dts_only = TRUE;
1288   } else if (!strcmp (mimetype, "video/x-h264")) {
1289     gst_matroska_mux_set_codec_id (context,
1290         GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
1291     gst_matroska_mux_free_codec_priv (context);
1292
1293     if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1294             "avc3")) {
1295       GST_WARNING_OBJECT (mux,
1296           "avc3 is not officially supported, only use this format for smart encoding");
1297     }
1298
1299     /* Create avcC header */
1300     if (codec_buf != NULL) {
1301       context->codec_priv_size = gst_buffer_get_size (codec_buf);
1302       context->codec_priv = g_malloc0 (context->codec_priv_size);
1303       gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1304     }
1305   } else if (!strcmp (mimetype, "video/x-h265")) {
1306     gst_matroska_mux_set_codec_id (context,
1307         GST_MATROSKA_CODEC_ID_VIDEO_MPEGH_HEVC);
1308     gst_matroska_mux_free_codec_priv (context);
1309
1310     if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
1311             "hev1")) {
1312       GST_WARNING_OBJECT (mux,
1313           "hev1 is not officially supported, only use this format for smart encoding");
1314     }
1315
1316     /* Create hvcC header */
1317     if (codec_buf != NULL) {
1318       context->codec_priv_size = gst_buffer_get_size (codec_buf);
1319       context->codec_priv = g_malloc0 (context->codec_priv_size);
1320       gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1321     }
1322   } else if (!strcmp (mimetype, "video/x-theora")) {
1323     const GValue *streamheader;
1324
1325     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
1326
1327     gst_matroska_mux_free_codec_priv (context);
1328
1329     streamheader = gst_structure_get_value (structure, "streamheader");
1330     if (!theora_streamheader_to_codecdata (streamheader, context)) {
1331       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1332           ("theora stream headers missing or malformed"));
1333       goto refuse_caps;
1334     }
1335   } else if (!strcmp (mimetype, "video/x-dirac")) {
1336     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
1337   } else if (!strcmp (mimetype, "video/x-vp8")) {
1338     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP8);
1339   } else if (!strcmp (mimetype, "video/x-vp9")) {
1340     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP9);
1341   } else if (!strcmp (mimetype, "video/x-av1")) {
1342     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_AV1);
1343     gst_matroska_mux_free_codec_priv (context);
1344     /* Create av1C header */
1345     if (codec_buf != NULL)
1346       gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1347           &context->codec_priv, &context->codec_priv_size);
1348   } else if (!strcmp (mimetype, "video/x-ffv")) {
1349     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_FFV1);
1350     gst_matroska_mux_free_codec_priv (context);
1351     if (codec_buf != NULL)
1352       gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf),
1353           &context->codec_priv, &context->codec_priv_size);
1354   } else if (!strcmp (mimetype, "video/mpeg")) {
1355     gint mpegversion;
1356
1357     gst_structure_get_int (structure, "mpegversion", &mpegversion);
1358     switch (mpegversion) {
1359       case 1:
1360         gst_matroska_mux_set_codec_id (context,
1361             GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
1362         break;
1363       case 2:
1364         gst_matroska_mux_set_codec_id (context,
1365             GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
1366         break;
1367       case 4:
1368         gst_matroska_mux_set_codec_id (context,
1369             GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
1370         break;
1371       default:
1372         goto refuse_caps;
1373     }
1374
1375     /* global headers may be in codec data */
1376     if (codec_buf != NULL) {
1377       gst_matroska_mux_free_codec_priv (context);
1378       context->codec_priv_size = gst_buffer_get_size (codec_buf);
1379       context->codec_priv = g_malloc0 (context->codec_priv_size);
1380       gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
1381     }
1382   } else if (!strcmp (mimetype, "video/x-msmpeg")) {
1383   msmpeg43:
1384     /* can only make it here if preceding case verified it was version 3 */
1385     gst_matroska_mux_set_codec_id (context,
1386         GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
1387   } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
1388     gint rmversion;
1389     const GValue *mdpr_data;
1390
1391     gst_structure_get_int (structure, "rmversion", &rmversion);
1392     switch (rmversion) {
1393       case 1:
1394         gst_matroska_mux_set_codec_id (context,
1395             GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
1396         break;
1397       case 2:
1398         gst_matroska_mux_set_codec_id (context,
1399             GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
1400         break;
1401       case 3:
1402         gst_matroska_mux_set_codec_id (context,
1403             GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
1404         break;
1405       case 4:
1406         gst_matroska_mux_set_codec_id (context,
1407             GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
1408         break;
1409       default:
1410         goto refuse_caps;
1411     }
1412
1413     mdpr_data = gst_structure_get_value (structure, "mdpr_data");
1414     if (mdpr_data != NULL) {
1415       guint8 *priv_data = NULL;
1416       guint priv_data_size = 0;
1417
1418       GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
1419
1420       priv_data_size = gst_buffer_get_size (codec_data_buf);
1421       priv_data = g_malloc0 (priv_data_size);
1422
1423       gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
1424
1425       gst_matroska_mux_free_codec_priv (context);
1426       context->codec_priv = priv_data;
1427       context->codec_priv_size = priv_data_size;
1428     }
1429   } else if (strcmp (mimetype, "video/x-prores") == 0) {
1430     const gchar *variant;
1431
1432     gst_matroska_mux_free_codec_priv (context);
1433
1434     variant = gst_structure_get_string (structure, "format");
1435     if (!variant || !g_strcmp0 (variant, "standard"))
1436       context->codec_priv = g_strdup ("apcn");
1437     else if (!g_strcmp0 (variant, "hq"))
1438       context->codec_priv = g_strdup ("apch");
1439     else if (!g_strcmp0 (variant, "lt"))
1440       context->codec_priv = g_strdup ("apcs");
1441     else if (!g_strcmp0 (variant, "proxy"))
1442       context->codec_priv = g_strdup ("apco");
1443     else if (!g_strcmp0 (variant, "4444"))
1444       context->codec_priv = g_strdup ("ap4h");
1445     else {
1446       GST_WARNING_OBJECT (mux, "Unhandled prores format: %s", variant);
1447
1448       goto refuse_caps;
1449     }
1450
1451     context->codec_priv_size = sizeof (guint32);
1452     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_PRORES);
1453   }
1454
1455   return TRUE;
1456
1457   /* ERRORS */
1458 refuse_caps:
1459   {
1460     GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
1461         GST_PAD_NAME (pad), caps);
1462     return FALSE;
1463   }
1464 }
1465
1466 /* N > 0 to expect a particular number of headers, negative if the
1467    number of headers is variable */
1468 static gboolean
1469 xiphN_streamheader_to_codecdata (const GValue * streamheader,
1470     GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
1471 {
1472   GstBuffer **buf = NULL;
1473   GArray *bufarr;
1474   guint8 *priv_data;
1475   guint bufi, i, offset, priv_data_size;
1476
1477   if (streamheader == NULL)
1478     goto no_stream_headers;
1479
1480   if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1481     goto wrong_type;
1482
1483   bufarr = g_value_peek_pointer (streamheader);
1484   if (bufarr->len <= 0 || bufarr->len > 255)    /* at least one header, and count stored in a byte */
1485     goto wrong_count;
1486   if (N > 0 && bufarr->len != N)
1487     goto wrong_count;
1488
1489   context->xiph_headers_to_skip = bufarr->len;
1490
1491   buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
1492   for (i = 0; i < bufarr->len; i++) {
1493     GValue *bufval = &g_array_index (bufarr, GValue, i);
1494
1495     if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1496       g_free (buf);
1497       goto wrong_content_type;
1498     }
1499
1500     buf[i] = g_value_peek_pointer (bufval);
1501   }
1502
1503   priv_data_size = 1;
1504   if (bufarr->len > 0) {
1505     for (i = 0; i < bufarr->len - 1; i++) {
1506       priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
1507     }
1508   }
1509
1510   for (i = 0; i < bufarr->len; ++i) {
1511     priv_data_size += gst_buffer_get_size (buf[i]);
1512   }
1513
1514   priv_data = g_malloc0 (priv_data_size);
1515
1516   priv_data[0] = bufarr->len - 1;
1517   offset = 1;
1518
1519   if (bufarr->len > 0) {
1520     for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
1521       for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
1522         priv_data[offset++] = 0xff;
1523       }
1524       priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
1525     }
1526   }
1527
1528   for (i = 0; i < bufarr->len; ++i) {
1529     gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
1530     offset += gst_buffer_get_size (buf[i]);
1531   }
1532
1533   gst_matroska_mux_free_codec_priv (context);
1534   context->codec_priv = priv_data;
1535   context->codec_priv_size = priv_data_size;
1536
1537   if (p_buf0)
1538     *p_buf0 = gst_buffer_ref (buf[0]);
1539
1540   g_free (buf);
1541
1542   return TRUE;
1543
1544 /* ERRORS */
1545 no_stream_headers:
1546   {
1547     GST_WARNING ("required streamheaders missing in sink caps!");
1548     return FALSE;
1549   }
1550 wrong_type:
1551   {
1552     GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1553         G_VALUE_TYPE_NAME (streamheader));
1554     return FALSE;
1555   }
1556 wrong_count:
1557   {
1558     GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
1559     return FALSE;
1560   }
1561 wrong_content_type:
1562   {
1563     GST_WARNING ("streamheaders array does not contain GstBuffers");
1564     return FALSE;
1565   }
1566 }
1567
1568 static gboolean
1569 vorbis_streamheader_to_codecdata (const GValue * streamheader,
1570     GstMatroskaTrackContext * context)
1571 {
1572   GstBuffer *buf0 = NULL;
1573
1574   if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1575     return FALSE;
1576
1577   if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
1578     GST_WARNING ("First vorbis header too small, ignoring");
1579   } else {
1580     if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
1581       GstMatroskaTrackAudioContext *audiocontext;
1582       GstMapInfo map;
1583       guint8 *hdr;
1584
1585       gst_buffer_map (buf0, &map, GST_MAP_READ);
1586       hdr = map.data + 1 + 6 + 4;
1587       audiocontext = (GstMatroskaTrackAudioContext *) context;
1588       audiocontext->channels = GST_READ_UINT8 (hdr);
1589       audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
1590       gst_buffer_unmap (buf0, &map);
1591     }
1592   }
1593
1594   if (buf0)
1595     gst_buffer_unref (buf0);
1596
1597   return TRUE;
1598 }
1599
1600 static gboolean
1601 theora_streamheader_to_codecdata (const GValue * streamheader,
1602     GstMatroskaTrackContext * context)
1603 {
1604   GstBuffer *buf0 = NULL;
1605
1606   if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
1607     return FALSE;
1608
1609   if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
1610     GST_WARNING ("First theora header too small, ignoring");
1611   } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
1612     GST_WARNING ("First header not a theora identification header, ignoring");
1613   } else {
1614     GstMatroskaTrackVideoContext *videocontext;
1615     guint fps_num, fps_denom, par_num, par_denom;
1616     GstMapInfo map;
1617     guint8 *hdr;
1618
1619     gst_buffer_map (buf0, &map, GST_MAP_READ);
1620     hdr = map.data + 1 + 6 + 3 + 2 + 2;
1621
1622     videocontext = (GstMatroskaTrackVideoContext *) context;
1623     videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
1624     videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
1625     hdr += 3 + 3 + 1 + 1;
1626     fps_num = GST_READ_UINT32_BE (hdr);
1627     fps_denom = GST_READ_UINT32_BE (hdr + 4);
1628     context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
1629         fps_denom, fps_num);
1630     hdr += 4 + 4;
1631     par_num = GST_READ_UINT32_BE (hdr) >> 8;
1632     par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
1633     if (par_num > 0 && par_denom > 0) {
1634       if (par_num > par_denom) {
1635         videocontext->display_width =
1636             videocontext->pixel_width * par_num / par_denom;
1637         videocontext->display_height = videocontext->pixel_height;
1638       } else if (par_num < par_denom) {
1639         videocontext->display_width = videocontext->pixel_width;
1640         videocontext->display_height =
1641             videocontext->pixel_height * par_denom / par_num;
1642       } else {
1643         videocontext->display_width = 0;
1644         videocontext->display_height = 0;
1645       }
1646     } else {
1647       videocontext->display_width = 0;
1648       videocontext->display_height = 0;
1649     }
1650
1651     gst_buffer_unmap (buf0, &map);
1652   }
1653
1654   if (buf0)
1655     gst_buffer_unref (buf0);
1656
1657   return TRUE;
1658 }
1659
1660 static gboolean
1661 kate_streamheader_to_codecdata (const GValue * streamheader,
1662     GstMatroskaTrackContext * context)
1663 {
1664   GstBuffer *buf0 = NULL;
1665
1666   if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
1667     return FALSE;
1668
1669   if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) {        /* Kate ID header is 64 bytes */
1670     GST_WARNING ("First kate header too small, ignoring");
1671   } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
1672     GST_WARNING ("First header not a kate identification header, ignoring");
1673   }
1674
1675   if (buf0)
1676     gst_buffer_unref (buf0);
1677
1678   return TRUE;
1679 }
1680
1681 static gboolean
1682 flac_streamheader_to_codecdata (const GValue * streamheader,
1683     GstMatroskaTrackContext * context)
1684 {
1685   GArray *bufarr;
1686   gint i;
1687   GValue *bufval;
1688   GstBuffer *buffer;
1689
1690   if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1691     GST_WARNING ("No or invalid streamheader field in the caps");
1692     return FALSE;
1693   }
1694
1695   bufarr = g_value_peek_pointer (streamheader);
1696   if (bufarr->len < 2) {
1697     GST_WARNING ("Too few headers in streamheader field");
1698     return FALSE;
1699   }
1700
1701   context->xiph_headers_to_skip = bufarr->len + 1;
1702
1703   bufval = &g_array_index (bufarr, GValue, 0);
1704   if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1705     GST_WARNING ("streamheaders array does not contain GstBuffers");
1706     return FALSE;
1707   }
1708
1709   buffer = g_value_peek_pointer (bufval);
1710
1711   /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
1712   if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
1713       || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
1714       || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
1715     GST_WARNING ("Invalid streamheader for FLAC");
1716     return FALSE;
1717   }
1718
1719   gst_matroska_mux_free_codec_priv (context);
1720   context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
1721   context->codec_priv = g_malloc (context->codec_priv_size);
1722   gst_buffer_extract (buffer, 9, context->codec_priv, -1);
1723
1724   for (i = 1; i < bufarr->len; i++) {
1725     guint old_size;
1726     bufval = &g_array_index (bufarr, GValue, i);
1727
1728     if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1729       gst_matroska_mux_free_codec_priv (context);
1730       GST_WARNING ("streamheaders array does not contain GstBuffers");
1731       return FALSE;
1732     }
1733
1734     buffer = g_value_peek_pointer (bufval);
1735
1736     old_size = context->codec_priv_size;
1737     context->codec_priv_size += gst_buffer_get_size (buffer);
1738
1739     context->codec_priv = g_realloc (context->codec_priv,
1740         context->codec_priv_size);
1741     gst_buffer_extract (buffer, 0,
1742         (guint8 *) context->codec_priv + old_size, -1);
1743   }
1744
1745   return TRUE;
1746 }
1747
1748 static gboolean
1749 speex_streamheader_to_codecdata (const GValue * streamheader,
1750     GstMatroskaTrackContext * context)
1751 {
1752   GArray *bufarr;
1753   GValue *bufval;
1754   GstBuffer *buffer;
1755   guint old_size;
1756
1757   if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
1758     GST_WARNING ("No or invalid streamheader field in the caps");
1759     return FALSE;
1760   }
1761
1762   bufarr = g_value_peek_pointer (streamheader);
1763   if (bufarr->len != 2) {
1764     GST_WARNING ("Too few headers in streamheader field");
1765     return FALSE;
1766   }
1767
1768   context->xiph_headers_to_skip = bufarr->len + 1;
1769
1770   bufval = &g_array_index (bufarr, GValue, 0);
1771   if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1772     GST_WARNING ("streamheaders array does not contain GstBuffers");
1773     return FALSE;
1774   }
1775
1776   buffer = g_value_peek_pointer (bufval);
1777
1778   if (gst_buffer_get_size (buffer) < 80
1779       || gst_buffer_memcmp (buffer, 0, "Speex   ", 8) != 0) {
1780     GST_WARNING ("Invalid streamheader for Speex");
1781     return FALSE;
1782   }
1783
1784   gst_matroska_mux_free_codec_priv (context);
1785   context->codec_priv_size = gst_buffer_get_size (buffer);
1786   context->codec_priv = g_malloc (context->codec_priv_size);
1787   gst_buffer_extract (buffer, 0, context->codec_priv, -1);
1788
1789   bufval = &g_array_index (bufarr, GValue, 1);
1790
1791   if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1792     gst_matroska_mux_free_codec_priv (context);
1793     GST_WARNING ("streamheaders array does not contain GstBuffers");
1794     return FALSE;
1795   }
1796
1797   buffer = g_value_peek_pointer (bufval);
1798
1799   old_size = context->codec_priv_size;
1800   context->codec_priv_size += gst_buffer_get_size (buffer);
1801   context->codec_priv = g_realloc (context->codec_priv,
1802       context->codec_priv_size);
1803   gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
1804
1805   return TRUE;
1806 }
1807
1808 static gboolean
1809 opus_streamheader_to_codecdata (const GValue * streamheader,
1810     GstMatroskaTrackContext * context)
1811 {
1812   GArray *bufarr;
1813   GValue *bufval;
1814   GstBuffer *buf;
1815
1816   if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
1817     goto wrong_type;
1818
1819   bufarr = g_value_peek_pointer (streamheader);
1820   if (bufarr->len != 1 && bufarr->len != 2)     /* one header, and count stored in a byte */
1821     goto wrong_count;
1822
1823   /* Opus headers are not in-band */
1824   context->xiph_headers_to_skip = 0;
1825
1826   bufval = &g_array_index (bufarr, GValue, 0);
1827   if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
1828     goto wrong_content_type;
1829   }
1830   buf = g_value_peek_pointer (bufval);
1831
1832   gst_matroska_mux_free_codec_priv (context);
1833
1834   context->codec_priv_size = gst_buffer_get_size (buf);
1835   context->codec_priv = g_malloc0 (context->codec_priv_size);
1836   gst_buffer_extract (buf, 0, context->codec_priv, -1);
1837
1838   context->codec_delay =
1839       GST_READ_UINT16_LE ((guint8 *) context->codec_priv + 10);
1840   context->codec_delay =
1841       gst_util_uint64_scale_round (context->codec_delay, GST_SECOND, 48000);
1842   context->seek_preroll = 80 * GST_MSECOND;
1843
1844   return TRUE;
1845
1846 /* ERRORS */
1847 wrong_type:
1848   {
1849     GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
1850         G_VALUE_TYPE_NAME (streamheader));
1851     return FALSE;
1852   }
1853 wrong_count:
1854   {
1855     GST_WARNING ("got %u streamheaders, not 1 or 2 as expected", bufarr->len);
1856     return FALSE;
1857   }
1858 wrong_content_type:
1859   {
1860     GST_WARNING ("streamheaders array does not contain GstBuffers");
1861     return FALSE;
1862   }
1863 }
1864
1865 static gboolean
1866 opus_make_codecdata (GstMatroskaTrackContext * context, GstCaps * caps)
1867 {
1868   guint32 rate;
1869   guint8 channels;
1870   guint8 channel_mapping_family;
1871   guint8 stream_count, coupled_count, channel_mapping[256];
1872   GstBuffer *buffer;
1873   GstMapInfo map;
1874
1875   /* Opus headers are not in-band */
1876   context->xiph_headers_to_skip = 0;
1877
1878   context->codec_delay = 0;
1879   context->seek_preroll = 80 * GST_MSECOND;
1880
1881   if (!gst_codec_utils_opus_parse_caps (caps, &rate, &channels,
1882           &channel_mapping_family, &stream_count, &coupled_count,
1883           channel_mapping)) {
1884     GST_WARNING ("Failed to parse caps for Opus");
1885     return FALSE;
1886   }
1887
1888   buffer =
1889       gst_codec_utils_opus_create_header (rate, channels,
1890       channel_mapping_family, stream_count, coupled_count, channel_mapping, 0,
1891       0);
1892   if (!buffer) {
1893     GST_WARNING ("Failed to create Opus header from caps");
1894     return FALSE;
1895   }
1896
1897   gst_buffer_map (buffer, &map, GST_MAP_READ);
1898   context->codec_priv_size = map.size;
1899   context->codec_priv = g_malloc (context->codec_priv_size);
1900   memcpy (context->codec_priv, map.data, map.size);
1901   gst_buffer_unmap (buffer, &map);
1902   gst_buffer_unref (buffer);
1903
1904   return TRUE;
1905 }
1906
1907 /**
1908  * gst_matroska_mux_audio_pad_setcaps:
1909  * @pad: Pad which got the caps.
1910  * @caps: New caps.
1911  *
1912  * Setcaps function for audio sink pad.
1913  *
1914  * Returns: %TRUE on success.
1915  */
1916 static gboolean
1917 gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
1918 {
1919   GstMatroskaTrackContext *context = NULL;
1920   GstMatroskaTrackAudioContext *audiocontext;
1921   GstMatroskaMux *mux;
1922   GstMatroskaPad *collect_pad;
1923   const gchar *mimetype;
1924   gint samplerate = 0, channels = 0;
1925   GstStructure *structure;
1926   const GValue *codec_data = NULL;
1927   GstBuffer *buf = NULL;
1928   const gchar *stream_format = NULL;
1929   GstCaps *old_caps;
1930
1931   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
1932
1933   if ((old_caps = gst_pad_get_current_caps (pad))) {
1934     if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
1935         && !gst_caps_is_equal (caps, old_caps)) {
1936       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1937           ("Caps changes are not supported by Matroska"));
1938       gst_caps_unref (old_caps);
1939       goto refuse_caps;
1940     }
1941     gst_caps_unref (old_caps);
1942   } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
1943     GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1944         ("Caps on pad %" GST_PTR_FORMAT
1945             " arrived late. Headers were already written", pad));
1946     goto refuse_caps;
1947   }
1948
1949   /* find context */
1950   collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
1951   g_assert (collect_pad);
1952   context = collect_pad->track;
1953   g_assert (context);
1954   g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
1955   audiocontext = (GstMatroskaTrackAudioContext *) context;
1956
1957   structure = gst_caps_get_structure (caps, 0);
1958   mimetype = gst_structure_get_name (structure);
1959
1960   /* general setup */
1961   gst_structure_get_int (structure, "rate", &samplerate);
1962   gst_structure_get_int (structure, "channels", &channels);
1963
1964   audiocontext->samplerate = samplerate;
1965   audiocontext->channels = channels;
1966   audiocontext->bitdepth = 0;
1967   context->default_duration = 0;
1968
1969   codec_data = gst_structure_get_value (structure, "codec_data");
1970   if (codec_data)
1971     buf = gst_value_get_buffer (codec_data);
1972
1973   /* TODO: - check if we handle all codecs by the spec, i.e. codec private
1974    *         data and other settings
1975    *       - add new formats
1976    */
1977
1978   if (!strcmp (mimetype, "audio/mpeg")) {
1979     gint mpegversion = 0;
1980
1981     gst_structure_get_int (structure, "mpegversion", &mpegversion);
1982     switch (mpegversion) {
1983       case 1:{
1984         gint layer;
1985         gint version = 1;
1986         gint spf;
1987
1988         gst_structure_get_int (structure, "layer", &layer);
1989
1990         if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
1991           GST_WARNING_OBJECT (mux,
1992               "Unable to determine MPEG audio version, assuming 1");
1993           version = 1;
1994         }
1995
1996         if (layer == 1)
1997           spf = 384;
1998         else if (layer == 2)
1999           spf = 1152;
2000         else if (version == 2)
2001           spf = 576;
2002         else
2003           spf = 1152;
2004
2005         context->default_duration =
2006             gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
2007
2008         switch (layer) {
2009           case 1:
2010             gst_matroska_mux_set_codec_id (context,
2011                 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
2012             break;
2013           case 2:
2014             gst_matroska_mux_set_codec_id (context,
2015                 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
2016             break;
2017           case 3:
2018             gst_matroska_mux_set_codec_id (context,
2019                 GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
2020             break;
2021           default:
2022             goto refuse_caps;
2023         }
2024         break;
2025       }
2026       case 2:
2027       case 4:
2028         stream_format = gst_structure_get_string (structure, "stream-format");
2029         /* check this is raw aac */
2030         if (stream_format) {
2031           if (strcmp (stream_format, "raw") != 0) {
2032             GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
2033                 stream_format);
2034           }
2035         } else {
2036           GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
2037               "assuming 'raw'");
2038         }
2039
2040         if (buf) {
2041           gst_matroska_mux_set_codec_id (context,
2042               GST_MATROSKA_CODEC_ID_AUDIO_AAC);
2043           context->codec_priv_size = gst_buffer_get_size (buf);
2044           context->codec_priv = g_malloc (context->codec_priv_size);
2045           gst_buffer_extract (buf, 0, context->codec_priv,
2046               context->codec_priv_size);
2047         } else {
2048           GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
2049           goto refuse_caps;
2050         }
2051         break;
2052       default:
2053         goto refuse_caps;
2054     }
2055   } else if (!strcmp (mimetype, "audio/x-raw")) {
2056     GstAudioInfo info;
2057
2058     gst_audio_info_init (&info);
2059     if (!gst_audio_info_from_caps (&info, caps)) {
2060       GST_DEBUG_OBJECT (mux,
2061           "broken caps, rejected by gst_audio_info_from_caps");
2062       goto refuse_caps;
2063     }
2064
2065     switch (GST_AUDIO_INFO_FORMAT (&info)) {
2066       case GST_AUDIO_FORMAT_U8:
2067       case GST_AUDIO_FORMAT_S16BE:
2068       case GST_AUDIO_FORMAT_S16LE:
2069       case GST_AUDIO_FORMAT_S24BE:
2070       case GST_AUDIO_FORMAT_S24LE:
2071       case GST_AUDIO_FORMAT_S32BE:
2072       case GST_AUDIO_FORMAT_S32LE:
2073         if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
2074           GST_DEBUG_OBJECT (mux, "width must be same as depth!");
2075           goto refuse_caps;
2076         }
2077         if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
2078           gst_matroska_mux_set_codec_id (context,
2079               GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
2080         else
2081           gst_matroska_mux_set_codec_id (context,
2082               GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
2083         break;
2084       case GST_AUDIO_FORMAT_F32LE:
2085       case GST_AUDIO_FORMAT_F64LE:
2086         gst_matroska_mux_set_codec_id (context,
2087             GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
2088         break;
2089
2090       default:
2091         GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
2092         goto refuse_caps;
2093     }
2094
2095     audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
2096   } else if (!strcmp (mimetype, "audio/x-vorbis")) {
2097     const GValue *streamheader;
2098
2099     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
2100
2101     gst_matroska_mux_free_codec_priv (context);
2102
2103     streamheader = gst_structure_get_value (structure, "streamheader");
2104     if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
2105       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2106           ("vorbis stream headers missing or malformed"));
2107       goto refuse_caps;
2108     }
2109   } else if (!strcmp (mimetype, "audio/x-flac")) {
2110     const GValue *streamheader;
2111
2112     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
2113
2114     gst_matroska_mux_free_codec_priv (context);
2115
2116     streamheader = gst_structure_get_value (structure, "streamheader");
2117     if (!flac_streamheader_to_codecdata (streamheader, context)) {
2118       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2119           ("flac stream headers missing or malformed"));
2120       goto refuse_caps;
2121     }
2122   } else if (!strcmp (mimetype, "audio/x-speex")) {
2123     const GValue *streamheader;
2124
2125     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
2126     gst_matroska_mux_free_codec_priv (context);
2127
2128     streamheader = gst_structure_get_value (structure, "streamheader");
2129     if (!speex_streamheader_to_codecdata (streamheader, context)) {
2130       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2131           ("speex stream headers missing or malformed"));
2132       goto refuse_caps;
2133     }
2134   } else if (!strcmp (mimetype, "audio/x-opus")) {
2135     const GValue *streamheader;
2136
2137     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_OPUS);
2138
2139     streamheader = gst_structure_get_value (structure, "streamheader");
2140     if (streamheader) {
2141       gst_matroska_mux_free_codec_priv (context);
2142       if (!opus_streamheader_to_codecdata (streamheader, context)) {
2143         GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2144             ("opus stream headers missing or malformed"));
2145         goto refuse_caps;
2146       }
2147     } else {
2148       /* no streamheader, but we need to have one, so we make one up
2149          based on caps */
2150       gst_matroska_mux_free_codec_priv (context);
2151       if (!opus_make_codecdata (context, caps)) {
2152         GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2153             ("opus stream headers missing or malformed"));
2154         goto refuse_caps;
2155       }
2156     }
2157   } else if (!strcmp (mimetype, "audio/x-ac3")) {
2158     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_AC3);
2159   } else if (!strcmp (mimetype, "audio/x-eac3")) {
2160     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
2161   } else if (!strcmp (mimetype, "audio/x-dts")) {
2162     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_DTS);
2163   } else if (!strcmp (mimetype, "audio/x-tta")) {
2164     gint width;
2165
2166     /* TTA frame duration */
2167     context->default_duration = 1.04489795918367346939 * GST_SECOND;
2168
2169     gst_structure_get_int (structure, "width", &width);
2170     audiocontext->bitdepth = width;
2171     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_TTA);
2172
2173   } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
2174     gint raversion;
2175     const GValue *mdpr_data;
2176
2177     gst_structure_get_int (structure, "raversion", &raversion);
2178     switch (raversion) {
2179       case 1:
2180         gst_matroska_mux_set_codec_id (context,
2181             GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
2182         break;
2183       case 2:
2184         gst_matroska_mux_set_codec_id (context,
2185             GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
2186         break;
2187       case 8:
2188         gst_matroska_mux_set_codec_id (context,
2189             GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
2190         break;
2191       default:
2192         goto refuse_caps;
2193     }
2194
2195     mdpr_data = gst_structure_get_value (structure, "mdpr_data");
2196     if (mdpr_data != NULL) {
2197       guint8 *priv_data = NULL;
2198       guint priv_data_size = 0;
2199
2200       GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
2201
2202       priv_data_size = gst_buffer_get_size (codec_data_buf);
2203       priv_data = g_malloc0 (priv_data_size);
2204
2205       gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
2206
2207       gst_matroska_mux_free_codec_priv (context);
2208
2209       context->codec_priv = priv_data;
2210       context->codec_priv_size = priv_data_size;
2211     }
2212
2213   } else if (!strcmp (mimetype, "audio/x-wma")
2214       || !strcmp (mimetype, "audio/x-alaw")
2215       || !strcmp (mimetype, "audio/x-mulaw")
2216       || !strcmp (mimetype, "audio/x-adpcm")
2217       || !strcmp (mimetype, "audio/G722")) {
2218     guint8 *codec_priv;
2219     guint codec_priv_size;
2220     guint16 format = 0;
2221     gint block_align = 0;
2222     gint bitrate = 0;
2223
2224     if (samplerate == 0 || channels == 0) {
2225       GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
2226       goto refuse_caps;
2227     }
2228
2229     if (!strcmp (mimetype, "audio/x-wma")) {
2230       gint wmaversion;
2231       gint depth;
2232
2233       if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
2234           || !gst_structure_get_int (structure, "block_align", &block_align)
2235           || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
2236         GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
2237             " on WMA caps");
2238         goto refuse_caps;
2239       }
2240
2241       switch (wmaversion) {
2242         case 1:
2243           format = GST_RIFF_WAVE_FORMAT_WMAV1;
2244           break;
2245         case 2:
2246           format = GST_RIFF_WAVE_FORMAT_WMAV2;
2247           break;
2248         case 3:
2249           format = GST_RIFF_WAVE_FORMAT_WMAV3;
2250           break;
2251         default:
2252           GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
2253           goto refuse_caps;
2254       }
2255
2256       if (gst_structure_get_int (structure, "depth", &depth))
2257         audiocontext->bitdepth = depth;
2258     } else if (!strcmp (mimetype, "audio/x-alaw")
2259         || !strcmp (mimetype, "audio/x-mulaw")) {
2260       audiocontext->bitdepth = 8;
2261       if (!strcmp (mimetype, "audio/x-alaw"))
2262         format = GST_RIFF_WAVE_FORMAT_ALAW;
2263       else
2264         format = GST_RIFF_WAVE_FORMAT_MULAW;
2265
2266       block_align = channels;
2267       bitrate = block_align * samplerate;
2268     } else if (!strcmp (mimetype, "audio/x-adpcm")) {
2269       const char *layout;
2270
2271       layout = gst_structure_get_string (structure, "layout");
2272       if (!layout) {
2273         GST_WARNING_OBJECT (mux, "Missing layout on adpcm caps");
2274         goto refuse_caps;
2275       }
2276
2277       if (!gst_structure_get_int (structure, "block_align", &block_align)) {
2278         GST_WARNING_OBJECT (mux, "Missing block_align on adpcm caps");
2279         goto refuse_caps;
2280       }
2281
2282       if (!strcmp (layout, "dvi")) {
2283         format = GST_RIFF_WAVE_FORMAT_DVI_ADPCM;
2284       } else if (!strcmp (layout, "g726")) {
2285         format = GST_RIFF_WAVE_FORMAT_ITU_G726_ADPCM;
2286         if (!gst_structure_get_int (structure, "bitrate", &bitrate)) {
2287           GST_WARNING_OBJECT (mux, "Missing bitrate on adpcm g726 caps");
2288           goto refuse_caps;
2289         }
2290       } else {
2291         GST_WARNING_OBJECT (mux, "Unknown layout on adpcm caps");
2292         goto refuse_caps;
2293       }
2294
2295     } else if (!strcmp (mimetype, "audio/G722")) {
2296       format = GST_RIFF_WAVE_FORMAT_ADPCM_G722;
2297     }
2298     g_assert (format != 0);
2299
2300     codec_priv_size = WAVEFORMATEX_SIZE;
2301     if (buf)
2302       codec_priv_size += gst_buffer_get_size (buf);
2303
2304     /* serialize waveformatex structure */
2305     codec_priv = g_malloc0 (codec_priv_size);
2306     GST_WRITE_UINT16_LE (codec_priv, format);
2307     GST_WRITE_UINT16_LE (codec_priv + 2, channels);
2308     GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
2309     GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
2310     GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
2311     GST_WRITE_UINT16_LE (codec_priv + 14, 0);
2312     if (buf)
2313       GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
2314     else
2315       GST_WRITE_UINT16_LE (codec_priv + 16, 0);
2316
2317     /* process codec private/initialization data, if any */
2318     if (buf) {
2319       gst_buffer_extract (buf, 0,
2320           (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
2321     }
2322
2323     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
2324     gst_matroska_mux_free_codec_priv (context);
2325     context->codec_priv = (gpointer) codec_priv;
2326     context->codec_priv_size = codec_priv_size;
2327   }
2328
2329   return TRUE;
2330
2331   /* ERRORS */
2332 refuse_caps:
2333   {
2334     GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2335         GST_PAD_NAME (pad), caps);
2336     return FALSE;
2337   }
2338 }
2339
2340 /* we probably don't have the data at start,
2341  * so have to reserve (a maximum) space to write this at the end.
2342  * bit spacy, but some formats can hold quite some */
2343 #define SUBTITLE_MAX_CODEC_PRIVATE   2048       /* must be > 128 */
2344
2345 /**
2346  * gst_matroska_mux_subtitle_pad_setcaps:
2347  * @pad: Pad which got the caps.
2348  * @caps: New caps.
2349  *
2350  * Setcaps function for subtitle sink pad.
2351  *
2352  * Returns: %TRUE on success.
2353  */
2354 static gboolean
2355 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
2356 {
2357   /* There is now (at least) one such alement (kateenc), and I'm going
2358      to handle it here and claim it works when it can be piped back
2359      through GStreamer and VLC */
2360
2361   GstMatroskaTrackContext *context = NULL;
2362   GstMatroskaTrackSubtitleContext *scontext;
2363   GstMatroskaMux *mux;
2364   GstMatroskaPad *collect_pad;
2365   GstCollectData *data;
2366   const gchar *mimetype;
2367   GstStructure *structure;
2368   const GValue *value = NULL;
2369   GstBuffer *buf = NULL;
2370   gboolean ret = TRUE;
2371   GstCaps *old_caps;
2372
2373   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2374
2375   if ((old_caps = gst_pad_get_current_caps (pad))) {
2376     if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER
2377         && !gst_caps_is_equal (caps, old_caps)) {
2378       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2379           ("Caps changes are not supported by Matroska"));
2380       gst_caps_unref (old_caps);
2381       goto refuse_caps;
2382     }
2383     gst_caps_unref (old_caps);
2384   } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) {
2385     GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2386         ("Caps on pad %" GST_PTR_FORMAT
2387             " arrived late. Headers were already written", pad));
2388     goto refuse_caps;
2389   }
2390
2391   /* find context */
2392   collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
2393   g_assert (collect_pad);
2394   data = (GstCollectData *) (collect_pad);
2395
2396   context = collect_pad->track;
2397   g_assert (context);
2398   g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
2399   scontext = (GstMatroskaTrackSubtitleContext *) context;
2400
2401   structure = gst_caps_get_structure (caps, 0);
2402   mimetype = gst_structure_get_name (structure);
2403
2404   /* general setup */
2405   scontext->check_utf8 = 1;
2406   scontext->invalid_utf8 = 0;
2407   context->default_duration = 0;
2408
2409   if (!strcmp (mimetype, "subtitle/x-kate")) {
2410     const GValue *streamheader;
2411
2412     gst_matroska_mux_set_codec_id (context,
2413         GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
2414
2415     gst_matroska_mux_free_codec_priv (context);
2416
2417     streamheader = gst_structure_get_value (structure, "streamheader");
2418     if (!kate_streamheader_to_codecdata (streamheader, context)) {
2419       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
2420           ("kate stream headers missing or malformed"));
2421       ret = FALSE;
2422       goto exit;
2423     }
2424   } else if (!strcmp (mimetype, "text/x-raw")) {
2425     gst_matroska_mux_set_codec_id (context,
2426         GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
2427   } else if (!strcmp (mimetype, "application/x-ssa")) {
2428     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
2429   } else if (!strcmp (mimetype, "application/x-ass")) {
2430     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
2431   } else if (!strcmp (mimetype, "application/x-usf")) {
2432     gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
2433   } else if (!strcmp (mimetype, "subpicture/x-dvd")) {
2434     gst_matroska_mux_set_codec_id (context,
2435         GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
2436   } else {
2437     ret = FALSE;
2438     goto exit;
2439   }
2440
2441   /* maybe some private data, e.g. vobsub */
2442   value = gst_structure_get_value (structure, "codec_data");
2443   if (value)
2444     buf = gst_value_get_buffer (value);
2445   if (buf != NULL) {
2446     GstMapInfo map;
2447     guint8 *priv_data = NULL;
2448
2449     gst_buffer_map (buf, &map, GST_MAP_READ);
2450
2451     if (map.size > SUBTITLE_MAX_CODEC_PRIVATE) {
2452       GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
2453           " exceeded maximum (%d); discarding", pad,
2454           SUBTITLE_MAX_CODEC_PRIVATE);
2455       gst_buffer_unmap (buf, &map);
2456       return TRUE;
2457     }
2458
2459     gst_matroska_mux_free_codec_priv (context);
2460
2461     priv_data = g_malloc0 (map.size);
2462     memcpy (priv_data, map.data, map.size);
2463     context->codec_priv = priv_data;
2464     context->codec_priv_size = map.size;
2465     gst_buffer_unmap (buf, &map);
2466   }
2467
2468   GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %" G_GSIZE_FORMAT,
2469       GST_STR_NULL (context->codec_id), context->codec_priv_size);
2470
2471   /* This pad is sparse. Now that we have caps on it, we can tell collectpads
2472    * not to actually wait for data when muxing */
2473   GST_COLLECT_PADS_STREAM_LOCK (mux->collect);
2474   GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED);
2475   gst_collect_pads_set_waiting (mux->collect, data, FALSE);
2476   GST_COLLECT_PADS_STREAM_UNLOCK (mux->collect);
2477
2478 exit:
2479
2480   return ret;
2481
2482   /* ERRORS */
2483 refuse_caps:
2484   {
2485     GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
2486         GST_PAD_NAME (pad), caps);
2487     return FALSE;
2488   }
2489 }
2490
2491
2492 /**
2493  * gst_matroska_mux_request_new_pad:
2494  * @element: #GstMatroskaMux.
2495  * @templ: #GstPadTemplate.
2496  * @pad_name: New pad name.
2497  *
2498  * Request pad function for sink templates.
2499  *
2500  * Returns: New #GstPad.
2501  */
2502 static GstPad *
2503 gst_matroska_mux_request_new_pad (GstElement * element,
2504     GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
2505 {
2506   GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
2507   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
2508   GstMatroskaPad *collect_pad;
2509   GstMatroskamuxPad *newpad;
2510   gchar *name = NULL;
2511   const gchar *pad_name = NULL;
2512   GstMatroskaCapsFunc capsfunc = NULL;
2513   GstMatroskaTrackContext *context = NULL;
2514   gint pad_id;
2515   const gchar *id = NULL;
2516
2517   if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
2518     /* don't mix named and unnamed pads, if the pad already exists we fail when
2519      * trying to add it */
2520     if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
2521       pad_name = req_name;
2522     } else {
2523       name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
2524       pad_name = name;
2525     }
2526     capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
2527     context = (GstMatroskaTrackContext *)
2528         g_new0 (GstMatroskaTrackAudioContext, 1);
2529     context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
2530     context->name = g_strdup ("Audio");
2531   } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
2532     /* don't mix named and unnamed pads, if the pad already exists we fail when
2533      * trying to add it */
2534     if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
2535       pad_name = req_name;
2536     } else {
2537       name = g_strdup_printf ("video_%u", mux->num_v_streams++);
2538       pad_name = name;
2539     }
2540     capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
2541     context = (GstMatroskaTrackContext *)
2542         g_new0 (GstMatroskaTrackVideoContext, 1);
2543     context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
2544     context->name = g_strdup ("Video");
2545   } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
2546     /* don't mix named and unnamed pads, if the pad already exists we fail when
2547      * trying to add it */
2548     if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
2549       pad_name = req_name;
2550     } else {
2551       name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
2552       pad_name = name;
2553     }
2554     capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
2555     context = (GstMatroskaTrackContext *)
2556         g_new0 (GstMatroskaTrackSubtitleContext, 1);
2557     context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
2558     context->name = g_strdup ("Subtitle");
2559     /* setcaps may only provide proper one a lot later */
2560     id = "S_SUB_UNKNOWN";
2561   } else {
2562     GST_WARNING_OBJECT (mux, "This is not our template!");
2563     return NULL;
2564   }
2565
2566   newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
2567       "name", pad_name, "direction", templ->direction, "template", templ, NULL);
2568
2569   gst_matroskamux_pad_init (newpad);
2570   collect_pad = (GstMatroskaPad *)
2571       gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad),
2572       sizeof (GstMatroskaPad),
2573       (GstCollectDataDestroyNotify) gst_matroska_pad_free, TRUE);
2574
2575   collect_pad->mux = mux;
2576   collect_pad->track = context;
2577   gst_matroska_pad_reset (collect_pad, FALSE);
2578   if (id)
2579     gst_matroska_mux_set_codec_id (collect_pad->track, id);
2580   collect_pad->track->dts_only = FALSE;
2581
2582   collect_pad->capsfunc = capsfunc;
2583   gst_pad_set_active (GST_PAD (newpad), TRUE);
2584   if (!gst_element_add_pad (element, GST_PAD (newpad)))
2585     goto pad_add_failed;
2586
2587   g_free (name);
2588
2589   mux->num_streams++;
2590
2591   GST_DEBUG_OBJECT (newpad, "Added new request pad");
2592
2593   return GST_PAD (newpad);
2594
2595   /* ERROR cases */
2596 pad_add_failed:
2597   {
2598     GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
2599     g_free (name);
2600     gst_object_unref (newpad);
2601     return NULL;
2602   }
2603 }
2604
2605 /**
2606  * gst_matroska_mux_release_pad:
2607  * @element: #GstMatroskaMux.
2608  * @pad: Pad to release.
2609  *
2610  * Release a previously requested pad.
2611 */
2612 static void
2613 gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
2614 {
2615   GstMatroskaMux *mux;
2616   GSList *walk;
2617
2618   mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
2619
2620   for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
2621     GstCollectData *cdata = (GstCollectData *) walk->data;
2622     GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
2623
2624     if (cdata->pad == pad) {
2625       /*
2626        * observed duration, this will remain GST_CLOCK_TIME_NONE
2627        * only if the pad is reset
2628        */
2629       GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
2630
2631       if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
2632           GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
2633         collected_duration =
2634             GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
2635       }
2636
2637       if (GST_CLOCK_TIME_IS_VALID (collected_duration)
2638           && mux->duration < collected_duration)
2639         mux->duration = collected_duration;
2640
2641       break;
2642     }
2643   }
2644
2645   gst_collect_pads_remove_pad (mux->collect, pad);
2646   if (gst_element_remove_pad (element, pad))
2647     mux->num_streams--;
2648 }
2649
2650 static void
2651 gst_matroska_mux_write_mastering_metadata (GstMatroskaMux * mux,
2652     GstMatroskaTrackVideoContext * videocontext)
2653 {
2654   GstEbmlWrite *ebml = mux->ebml_write;
2655   guint64 master;
2656   GstVideoMasteringDisplayInfo *minfo = &videocontext->mastering_display_info;
2657   gdouble value;
2658   const gdouble chroma_scale = 50000;
2659   const gdouble luma_scale = 50000;
2660
2661   if (!videocontext->mastering_display_info_present)
2662     return;
2663
2664   master =
2665       gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_MASTERINGMETADATA);
2666
2667   value = (gdouble) minfo->display_primaries[0].x / chroma_scale;
2668   gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYX, value);
2669
2670   value = (gdouble) minfo->display_primaries[0].y / chroma_scale;
2671   gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYY, value);
2672
2673   value = (gdouble) minfo->display_primaries[1].x / chroma_scale;
2674   gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYX, value);
2675
2676   value = (gdouble) minfo->display_primaries[1].y / chroma_scale;
2677   gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYY, value);
2678
2679   value = (gdouble) minfo->display_primaries[2].x / chroma_scale;
2680   gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYX, value);
2681
2682   value = (gdouble) minfo->display_primaries[2].y / chroma_scale;
2683   gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYY, value);
2684
2685   value = (gdouble) minfo->white_point.x / chroma_scale;
2686   gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYX, value);
2687
2688   value = (gdouble) minfo->white_point.y / chroma_scale;
2689   gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY, value);
2690
2691   value = (gdouble) minfo->max_display_mastering_luminance / luma_scale;
2692   gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMAX, value);
2693
2694   value = (gdouble) minfo->min_display_mastering_luminance / luma_scale;
2695   gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMIN, value);
2696
2697   gst_ebml_write_master_finish (ebml, master);
2698   return;
2699 }
2700
2701 static void
2702 gst_matroska_mux_write_colour (GstMatroskaMux * mux,
2703     GstMatroskaTrackVideoContext * videocontext)
2704 {
2705   GstEbmlWrite *ebml = mux->ebml_write;
2706   guint64 master;
2707   guint matrix_id = 0;
2708   guint range_id = 0;
2709   guint transfer_id = 0;
2710   guint primaries_id = 0;
2711
2712   master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_VIDEOCOLOUR);
2713
2714   switch (videocontext->colorimetry.range) {
2715     case GST_VIDEO_COLOR_RANGE_UNKNOWN:
2716       range_id = 0;
2717       break;
2718     case GST_VIDEO_COLOR_RANGE_16_235:
2719       range_id = 1;
2720       break;
2721     case GST_VIDEO_COLOR_RANGE_0_255:
2722       range_id = 2;
2723   }
2724
2725   matrix_id = gst_video_color_matrix_to_iso (videocontext->colorimetry.matrix);
2726   transfer_id =
2727       gst_video_transfer_function_to_iso (videocontext->colorimetry.transfer);
2728   primaries_id =
2729       gst_video_color_primaries_to_iso (videocontext->colorimetry.primaries);
2730
2731   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEORANGE, range_id);
2732   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOMATRIXCOEFFICIENTS,
2733       matrix_id);
2734   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS,
2735       transfer_id);
2736   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPRIMARIES, primaries_id);
2737   if (videocontext->content_light_level.max_content_light_level &&
2738       videocontext->content_light_level.max_frame_average_light_level) {
2739     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXCLL,
2740         videocontext->content_light_level.max_content_light_level);
2741     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXFALL,
2742         videocontext->content_light_level.max_frame_average_light_level);
2743   }
2744
2745   gst_matroska_mux_write_mastering_metadata (mux, videocontext);
2746   gst_ebml_write_master_finish (ebml, master);
2747 }
2748
2749 /**
2750  * gst_matroska_mux_track_header:
2751  * @mux: #GstMatroskaMux
2752  * @context: Tack context.
2753  *
2754  * Write a track header.
2755  */
2756 static void
2757 gst_matroska_mux_track_header (GstMatroskaMux * mux,
2758     GstMatroskaTrackContext * context)
2759 {
2760   GstEbmlWrite *ebml = mux->ebml_write;
2761   guint64 master;
2762
2763   /* TODO: check if everything necessary is written and check default values */
2764
2765   /* track type goes before the type-specific stuff */
2766   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
2767   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
2768
2769   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, context->uid);
2770   if (context->default_duration) {
2771     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
2772         context->default_duration);
2773   }
2774   if (context->language) {
2775     gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
2776         context->language);
2777   }
2778
2779   /* FIXME: until we have a nice way of getting the codecname
2780    * out of the caps, I'm not going to enable this. Too much
2781    * (useless, double, boring) work... */
2782   /* TODO: Use value from tags if any */
2783   /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
2784      context->codec_name); */
2785   gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
2786
2787   /* type-specific stuff */
2788   switch (context->type) {
2789     case GST_MATROSKA_TRACK_TYPE_VIDEO:{
2790       GstMatroskaTrackVideoContext *videocontext =
2791           (GstMatroskaTrackVideoContext *) context;
2792
2793       master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
2794       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
2795           videocontext->pixel_width);
2796       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
2797           videocontext->pixel_height);
2798       if (videocontext->display_width && videocontext->display_height) {
2799         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
2800             videocontext->display_width);
2801         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
2802             videocontext->display_height);
2803       }
2804       switch (videocontext->interlace_mode) {
2805         case GST_MATROSKA_INTERLACE_MODE_INTERLACED:
2806           gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
2807           break;
2808         case GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE:
2809           gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 2);
2810           break;
2811         default:
2812           break;
2813       }
2814
2815       if (videocontext->fourcc) {
2816         guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
2817
2818         gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
2819             (gpointer) & fcc_le, 4);
2820       }
2821       gst_matroska_mux_write_colour (mux, videocontext);
2822       if (videocontext->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
2823         guint64 stereo_mode = 0;
2824
2825         switch (videocontext->multiview_mode) {
2826           case GST_VIDEO_MULTIVIEW_MODE_MONO:
2827             break;
2828           case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
2829             if (videocontext->multiview_flags &
2830                 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2831               stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_RL;
2832             else
2833               stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_LR;
2834             break;
2835           case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
2836             if (videocontext->multiview_flags &
2837                 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2838               stereo_mode = GST_MATROSKA_STEREO_MODE_TB_RL;
2839             else
2840               stereo_mode = GST_MATROSKA_STEREO_MODE_TB_LR;
2841             break;
2842           case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
2843             if (videocontext->multiview_flags &
2844                 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2845               stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_RL;
2846             else
2847               stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_LR;
2848             break;
2849           case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
2850             if (videocontext->multiview_flags &
2851                 GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
2852               stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_RL;
2853             else
2854               stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_LR;
2855             /* FIXME: In frame-by-frame mode, left/right frame buffers need to be
2856              * laced within one block. See http://www.matroska.org/technical/specs/index.html#StereoMode */
2857             GST_FIXME_OBJECT (mux,
2858                 "Frame-by-frame stereoscopic mode not fully implemented");
2859             break;
2860           default:
2861             GST_WARNING_OBJECT (mux,
2862                 "Multiview mode %d not supported in Matroska/WebM",
2863                 videocontext->multiview_mode);
2864             break;
2865         }
2866
2867         if (stereo_mode != 0)
2868           gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOSTEREOMODE,
2869               stereo_mode);
2870       }
2871       gst_ebml_write_master_finish (ebml, master);
2872
2873       break;
2874     }
2875
2876     case GST_MATROSKA_TRACK_TYPE_AUDIO:{
2877       GstMatroskaTrackAudioContext *audiocontext =
2878           (GstMatroskaTrackAudioContext *) context;
2879
2880       master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
2881       if (audiocontext->samplerate != 8000)
2882         gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
2883             audiocontext->samplerate);
2884       if (audiocontext->channels != 1)
2885         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
2886             audiocontext->channels);
2887       if (audiocontext->bitdepth) {
2888         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
2889             audiocontext->bitdepth);
2890       }
2891
2892       gst_ebml_write_master_finish (ebml, master);
2893
2894       break;
2895     }
2896
2897     case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
2898       break;
2899     }
2900     default:
2901       /* doesn't need type-specific data */
2902       break;
2903   }
2904
2905   GST_DEBUG_OBJECT (mux, "Wrote track header. Codec %s", context->codec_id);
2906
2907   gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
2908   if (context->codec_priv)
2909     gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
2910         context->codec_priv, context->codec_priv_size);
2911
2912   if (context->seek_preroll) {
2913     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPREROLL,
2914         context->seek_preroll);
2915   }
2916
2917   if (context->codec_delay) {
2918     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CODECDELAY,
2919         context->codec_delay);
2920   }
2921 }
2922
2923 static void
2924 gst_matroska_mux_write_chapter_title (const gchar * title, GstEbmlWrite * ebml)
2925 {
2926   guint64 title_master;
2927
2928   title_master =
2929       gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERDISPLAY);
2930
2931   gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPSTRING, title);
2932   gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CHAPLANGUAGE,
2933       GST_MATROSKA_MUX_CHAPLANG);
2934
2935   gst_ebml_write_master_finish (ebml, title_master);
2936 }
2937
2938 static GstTocEntry *
2939 gst_matroska_mux_write_chapter (GstMatroskaMux * mux, GstTocEntry * edition,
2940     GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters,
2941     guint64 * master_edition)
2942 {
2943   guint64 master_chapteratom;
2944   GList *cur;
2945   guint count, i;
2946   gchar *title;
2947   gint64 start, stop;
2948   guint64 uid;
2949   gchar s_uid[32];
2950   GstTocEntry *internal_chapter, *internal_nested;
2951   GstTagList *tags;
2952
2953   if (G_UNLIKELY (master_chapters != NULL && *master_chapters == 0))
2954     *master_chapters =
2955         gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERS);
2956
2957   if (G_UNLIKELY (master_edition != NULL && *master_edition == 0)) {
2958     /* create uid for the parent */
2959     *master_edition =
2960         gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_EDITIONENTRY);
2961
2962     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONUID,
2963         g_ascii_strtoull (gst_toc_entry_get_uid (edition), NULL, 10));
2964     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGHIDDEN, 0);
2965     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGDEFAULT, 0);
2966     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGORDERED, 0);
2967   }
2968
2969   gst_toc_entry_get_start_stop_times (entry, &start, &stop);
2970   tags = gst_toc_entry_get_tags (entry);
2971   if (tags != NULL) {
2972     tags = gst_tag_list_copy (tags);
2973   }
2974
2975   /* build internal chapter */
2976   uid = gst_matroska_mux_create_uid (mux);
2977   g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT, uid);
2978   internal_chapter = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, s_uid);
2979
2980   /* Write the chapter entry */
2981   master_chapteratom =
2982       gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERATOM);
2983
2984   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERUID, uid);
2985   /* Store the user provided UID in the ChapterStringUID */
2986   gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPTERSTRINGUID,
2987       gst_toc_entry_get_uid (entry));
2988   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTART, start);
2989   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTOP, stop);
2990   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGHIDDEN, 0);
2991   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGENABLED, 1);
2992
2993   /* write current ChapterDisplays before the nested chapters */
2994   if (G_LIKELY (tags != NULL)) {
2995     count = gst_tag_list_get_tag_size (tags, GST_TAG_TITLE);
2996
2997     for (i = 0; i < count; ++i) {
2998       gst_tag_list_get_string_index (tags, GST_TAG_TITLE, i, &title);
2999       /* FIXME: handle ChapterLanguage entries */
3000       gst_matroska_mux_write_chapter_title (title, ebml);
3001       g_free (title);
3002     }
3003
3004     /* remove title tag */
3005     if (G_LIKELY (count > 0))
3006       gst_tag_list_remove_tag (tags, GST_TAG_TITLE);
3007
3008     gst_toc_entry_set_tags (internal_chapter, tags);
3009   }
3010
3011   /* Write nested chapters */
3012   for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3013       cur = cur->next) {
3014     internal_nested = gst_matroska_mux_write_chapter (mux, NULL, cur->data,
3015         ebml, NULL, NULL);
3016
3017     gst_toc_entry_append_sub_entry (internal_chapter, internal_nested);
3018   }
3019
3020   gst_ebml_write_master_finish (ebml, master_chapteratom);
3021
3022   return internal_chapter;
3023 }
3024
3025 static GstTocEntry *
3026 gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
3027     GstTocEntry * edition, GList * chapters, GstEbmlWrite * ebml,
3028     guint64 * master_chapters)
3029 {
3030   guint64 master_edition = 0;
3031   gchar s_uid[32];
3032   GList *cur;
3033   GstTocEntry *internal_edition, *internal_chapter;
3034   GstTagList *tags = NULL;
3035
3036   g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT,
3037       gst_matroska_mux_create_uid (mux));
3038
3039   if (edition != NULL) {
3040     /* Edition entry defined, get its tags */
3041     tags = gst_toc_entry_get_tags (edition);
3042     if (tags != NULL) {
3043       tags = gst_tag_list_copy (tags);
3044     }
3045   }
3046
3047   internal_edition = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, s_uid);
3048   if (tags != NULL) {
3049     gst_toc_entry_set_tags (internal_edition, tags);
3050   }
3051
3052   for (cur = g_list_first (chapters); cur != NULL; cur = cur->next) {
3053     internal_chapter = gst_matroska_mux_write_chapter (mux, internal_edition,
3054         cur->data, ebml, master_chapters, &master_edition);
3055
3056     gst_toc_entry_append_sub_entry (internal_edition, internal_chapter);
3057   }
3058
3059   if (G_LIKELY (master_edition != 0))
3060     gst_ebml_write_master_finish (ebml, master_edition);
3061
3062   return internal_edition;
3063 }
3064
3065 /**
3066  * gst_matroska_mux_start:
3067  * @mux: #GstMatroskaMux
3068  *
3069  * Start a new matroska file (write headers etc...)
3070  */
3071 static void
3072 gst_matroska_mux_start (GstMatroskaMux * mux, GstMatroskaPad * first_pad,
3073     GstBuffer * first_pad_buf)
3074 {
3075   GstEbmlWrite *ebml = mux->ebml_write;
3076   const gchar *doctype;
3077   guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
3078     GST_MATROSKA_ID_TRACKS,
3079     GST_MATROSKA_ID_CHAPTERS,
3080     GST_MATROSKA_ID_CUES,
3081     GST_MATROSKA_ID_TAGS,
3082     0
3083   };
3084   const gchar *media_type;
3085   gboolean audio_only;
3086   guint64 master, child;
3087   GSList *collected;
3088   int i;
3089   guint tracknum = 1;
3090   GstClockTime earliest_time = GST_CLOCK_TIME_NONE;
3091   GstClockTime duration = 0;
3092   guint32 segment_uid[4];
3093   gint64 time;
3094   gchar s_id[32];
3095   GstToc *toc;
3096
3097   /* if not streaming, check if downstream is seekable */
3098   if (!mux->ebml_write->streamable) {
3099     gboolean seekable;
3100     GstQuery *query;
3101
3102     query = gst_query_new_seeking (GST_FORMAT_BYTES);
3103     if (gst_pad_peer_query (mux->srcpad, query)) {
3104       gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3105       GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
3106     } else {
3107       /* assume seeking is not supported if query not handled downstream */
3108       GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
3109       seekable = FALSE;
3110     }
3111     if (!seekable) {
3112       mux->ebml_write->streamable = TRUE;
3113       g_object_notify (G_OBJECT (mux), "streamable");
3114       GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
3115           "streamable=false. Will ignore that and create streamable output "
3116           "instead");
3117     }
3118     gst_query_unref (query);
3119   }
3120
3121   /* stream-start (FIXME: create id based on input ids) */
3122   g_snprintf (s_id, sizeof (s_id), "matroskamux-%08x", g_random_int ());
3123   gst_pad_push_event (mux->srcpad, gst_event_new_stream_start (s_id));
3124
3125   /* output caps */
3126   audio_only = mux->num_v_streams == 0 && mux->num_a_streams > 0;
3127   if (mux->is_webm) {
3128     media_type = (audio_only) ? "audio/webm" : "video/webm";
3129   } else {
3130     media_type = (audio_only) ? "audio/x-matroska" : "video/x-matroska";
3131   }
3132   ebml->caps = gst_caps_new_empty_simple (media_type);
3133   gst_pad_set_caps (mux->srcpad, ebml->caps);
3134   /* we start with a EBML header */
3135   doctype = mux->doctype;
3136   GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
3137       doctype, mux->doctype_version);
3138   gst_ebml_write_header (ebml, doctype, mux->doctype_version);
3139
3140   /* the rest of the header is cached */
3141   gst_ebml_write_set_cache (ebml, 0x1000);
3142
3143   /* start a segment */
3144   mux->segment_pos =
3145       gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
3146   mux->segment_master = ebml->pos;
3147
3148   if (!mux->ebml_write->streamable) {
3149     /* seekhead (table of contents) - we set the positions later */
3150     mux->seekhead_pos = ebml->pos;
3151     master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
3152     for (i = 0; seekhead_id[i] != 0; i++) {
3153       child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
3154       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
3155       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
3156       gst_ebml_write_master_finish (ebml, child);
3157     }
3158     gst_ebml_write_master_finish (ebml, master);
3159   }
3160
3161   if (mux->ebml_write->streamable) {
3162     const GstTagList *tags;
3163     gboolean has_main_tags;
3164
3165     /* tags */
3166     tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3167     has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3168
3169     if (has_main_tags || gst_matroska_mux_streams_have_tags (mux)) {
3170       guint64 master_tags, master_tag;
3171
3172       GST_DEBUG_OBJECT (mux, "Writing tags");
3173
3174       mux->tags_pos = ebml->pos;
3175       master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3176       if (has_main_tags) {
3177         master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3178         gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3179         gst_ebml_write_master_finish (ebml, master_tag);
3180       }
3181       gst_matroska_mux_write_streams_tags (mux);
3182       gst_ebml_write_master_finish (ebml, master_tags);
3183     }
3184   }
3185
3186   /* segment info */
3187   mux->info_pos = ebml->pos;
3188   master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
3189
3190   /* WebM does not support SegmentUID field on SegmentInfo */
3191   if (!mux->is_webm) {
3192     for (i = 0; i < 4; i++) {
3193       segment_uid[i] = g_random_int ();
3194     }
3195     gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
3196         (guint8 *) segment_uid, 16);
3197   }
3198
3199   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
3200   mux->duration_pos = ebml->pos;
3201   /* get duration */
3202   if (!mux->ebml_write->streamable) {
3203     for (collected = mux->collect->data; collected;
3204         collected = g_slist_next (collected)) {
3205       GstMatroskaPad *collect_pad;
3206       GstPad *thepad;
3207       gint64 trackduration;
3208
3209       collect_pad = (GstMatroskaPad *) collected->data;
3210       thepad = collect_pad->collect.pad;
3211
3212       /* Query the total length of the track. */
3213       GST_DEBUG_OBJECT (thepad, "querying peer duration");
3214       if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
3215         GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
3216             GST_TIME_ARGS (trackduration));
3217         if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
3218           duration = (GstClockTime) trackduration;
3219         }
3220       }
3221     }
3222     gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3223         gst_guint64_to_gdouble (duration) /
3224         gst_guint64_to_gdouble (mux->time_scale));
3225   }
3226   gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
3227       "GStreamer matroskamux version " PACKAGE_VERSION);
3228   if (mux->writing_app && mux->writing_app[0]) {
3229     gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
3230   }
3231   if (mux->creation_time != NULL) {
3232     time = g_date_time_to_unix (mux->creation_time) * GST_SECOND;
3233     time += g_date_time_get_microsecond (mux->creation_time) * GST_USECOND;
3234   } else {
3235     time = g_get_real_time () * GST_USECOND;
3236   }
3237   gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time);
3238   gst_ebml_write_master_finish (ebml, master);
3239
3240   /* tracks */
3241   mux->tracks_pos = ebml->pos;
3242   master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
3243
3244   for (collected = mux->collect->data; collected;
3245       collected = g_slist_next (collected)) {
3246     GstMatroskaPad *collect_pad;
3247     GstBuffer *buf;
3248
3249     collect_pad = (GstMatroskaPad *) collected->data;
3250
3251     /* This will cause an error at a later time */
3252     if (collect_pad->track->codec_id == NULL)
3253       continue;
3254
3255     /* Find the smallest timestamp so we can offset all streams by this to
3256      * start at 0 */
3257     if (mux->offset_to_zero) {
3258       GstClockTime ts;
3259
3260       if (collect_pad == first_pad)
3261         buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3262       else
3263         buf = gst_collect_pads_peek (mux->collect, collected->data);
3264
3265       if (buf) {
3266         ts = gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
3267
3268         if (earliest_time == GST_CLOCK_TIME_NONE)
3269           earliest_time = ts;
3270         else if (ts != GST_CLOCK_TIME_NONE && ts < earliest_time)
3271           earliest_time = ts;
3272       }
3273
3274       if (buf)
3275         gst_buffer_unref (buf);
3276     }
3277
3278     /* For audio tracks, use the first buffers duration as the default
3279      * duration if we didn't get any better idea from the caps event already
3280      */
3281     if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO &&
3282         collect_pad->track->default_duration == 0) {
3283       if (collect_pad == first_pad)
3284         buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
3285       else
3286         buf = gst_collect_pads_peek (mux->collect, collected->data);
3287
3288       if (buf && GST_BUFFER_DURATION_IS_VALID (buf))
3289         collect_pad->track->default_duration =
3290             GST_BUFFER_DURATION (buf) + collect_pad->track->codec_delay;
3291       if (buf)
3292         gst_buffer_unref (buf);
3293     }
3294
3295     collect_pad->track->num = tracknum++;
3296     child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
3297     gst_matroska_mux_track_header (mux, collect_pad->track);
3298     gst_ebml_write_master_finish (ebml, child);
3299     /* some remaining pad/track setup */
3300     collect_pad->default_duration_scaled =
3301         gst_util_uint64_scale (collect_pad->track->default_duration,
3302         1, mux->time_scale);
3303   }
3304   gst_ebml_write_master_finish (ebml, master);
3305
3306   mux->earliest_time = earliest_time == GST_CLOCK_TIME_NONE ? 0 : earliest_time;
3307
3308   /* chapters */
3309   toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3310   if (toc != NULL && !mux->ebml_write->streamable) {
3311     guint64 master_chapters = 0;
3312     GstTocEntry *internal_edition;
3313     GList *cur, *chapters;
3314
3315     GST_DEBUG ("Writing chapters");
3316
3317     /* There are two UIDs for Chapters:
3318      * - The ChapterUID is a mandatory unsigned integer which internally
3319      * refers to a given chapter. Except for the title & language which use
3320      * dedicated fields, this UID can also be used to add tags to the Chapter.
3321      * The tags come in a separate section of the container.
3322      * - The ChapterStringUID is an optional UTF-8 string which also uniquely
3323      * refers to a chapter but from an external perspective. It can act as a
3324      * "WebVTT cue identifier" which "can be used to reference a specific cue,
3325      * for example from script or CSS".
3326      *
3327      * The ChapterUID will be generated and checked for unicity, while the
3328      * ChapterStringUID will receive the user defined UID.
3329      *
3330      * In order to be able to refer to chapters from the tags section,
3331      * we must maintain an internal Toc tree with the generated ChapterUID
3332      * (see gst_matroska_mux_write_toc_entry_tags) */
3333
3334     /* Check whether we have editions or chapters at the root level. */
3335     cur = gst_toc_get_entries (toc);
3336     if (cur != NULL) {
3337       mux->chapters_pos = ebml->pos;
3338
3339       mux->internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
3340
3341       if (gst_toc_entry_get_entry_type (cur->data) ==
3342           GST_TOC_ENTRY_TYPE_EDITION) {
3343         /* Editions at the root level */
3344         for (; cur != NULL; cur = cur->next) {
3345           chapters = gst_toc_entry_get_sub_entries (cur->data);
3346           internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3347               cur->data, chapters, ebml, &master_chapters);
3348           gst_toc_append_entry (mux->internal_toc, internal_edition);
3349         }
3350       } else {
3351         /* Chapters at the root level */
3352         internal_edition = gst_matroska_mux_write_chapter_edition (mux,
3353             NULL, cur, ebml, &master_chapters);
3354         gst_toc_append_entry (mux->internal_toc, internal_edition);
3355       }
3356
3357       /* close master element if any edition was written */
3358       if (G_LIKELY (master_chapters != 0))
3359         gst_ebml_write_master_finish (ebml, master_chapters);
3360     }
3361   }
3362
3363   /* lastly, flush the cache */
3364   gst_ebml_write_flush_cache (ebml, FALSE, 0);
3365
3366   if (toc != NULL)
3367     gst_toc_unref (toc);
3368 }
3369
3370 /* TODO: more sensible tag mappings */
3371 static const struct
3372 {
3373   const gchar *matroska_tagname;
3374   const gchar *gstreamer_tagname;
3375 }
3376 gst_matroska_tag_conv[] = {
3377   {
3378   GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
3379   GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
3380   GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
3381   GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
3382   GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
3383   GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
3384   GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
3385   GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
3386   GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
3387   GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
3388   GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
3389   GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
3390   GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
3391   GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
3392   GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
3393 };
3394
3395 /* Every stagefright implementation on android up to and including 6.0.1 is using
3396  libwebm with bug in matroska parsing, where it will choke on empty tag elements;
3397  so before outputting tags and tag elements we better make sure that there are
3398  actually tags we are going to write */
3399 static gboolean
3400 gst_matroska_mux_tag_list_is_empty (const GstTagList * list)
3401 {
3402   int i;
3403   for (i = 0; i < gst_tag_list_n_tags (list); i++) {
3404     const gchar *tag = gst_tag_list_nth_tag_name (list, i);
3405     int i;
3406     for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3407       const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3408       if (strcmp (tagname_gst, tag) == 0) {
3409         GValue src = { 0, };
3410         gchar *dest;
3411
3412         if (!gst_tag_list_copy_value (&src, list, tag))
3413           break;
3414         dest = gst_value_serialize (&src);
3415
3416         g_value_unset (&src);
3417         if (dest) {
3418           g_free (dest);
3419           return FALSE;
3420         }
3421       }
3422     }
3423   }
3424   return TRUE;
3425 }
3426
3427 static void
3428 gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
3429     gpointer data)
3430 {
3431   GstEbmlWrite *ebml = (GstEbmlWrite *) data;
3432   guint i;
3433   guint64 simpletag_master;
3434
3435   for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
3436     const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
3437     const gchar *tagname_mkv = gst_matroska_tag_conv[i].matroska_tagname;
3438
3439     if (strcmp (tagname_gst, tag) == 0) {
3440       GValue src = { 0, };
3441       gchar *dest;
3442
3443       if (!gst_tag_list_copy_value (&src, list, tag))
3444         break;
3445       if ((dest = gst_value_serialize (&src))) {
3446
3447         simpletag_master = gst_ebml_write_master_start (ebml,
3448             GST_MATROSKA_ID_SIMPLETAG);
3449         gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
3450         gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
3451         gst_ebml_write_master_finish (ebml, simpletag_master);
3452         g_free (dest);
3453       } else {
3454         GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
3455       }
3456       g_value_unset (&src);
3457       break;
3458     }
3459   }
3460 }
3461
3462 static void
3463 gst_matroska_mux_write_stream_tags (GstMatroskaMux * mux, GstMatroskaPad * mpad)
3464 {
3465   guint64 master_tag, master_targets;
3466   GstEbmlWrite *ebml;
3467
3468   ebml = mux->ebml_write;
3469
3470   if (G_UNLIKELY (mpad->tags == NULL
3471           || gst_matroska_mux_tag_list_is_empty (mpad->tags)))
3472     return;
3473
3474   master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3475   master_targets = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3476
3477   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETTRACKUID, mpad->track->uid);
3478
3479   gst_ebml_write_master_finish (ebml, master_targets);
3480   gst_tag_list_foreach (mpad->tags, gst_matroska_mux_write_simple_tag, ebml);
3481   gst_ebml_write_master_finish (ebml, master_tag);
3482 }
3483
3484 static void
3485 gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux)
3486 {
3487   GSList *walk;
3488
3489   for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3490     GstMatroskaPad *collect_pad;
3491
3492     collect_pad = (GstMatroskaPad *) walk->data;
3493
3494     gst_matroska_mux_write_stream_tags (mux, collect_pad);
3495   }
3496 }
3497
3498 static gboolean
3499 gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux)
3500 {
3501   GSList *walk;
3502
3503   for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
3504     GstMatroskaPad *collect_pad;
3505
3506     collect_pad = (GstMatroskaPad *) walk->data;
3507     if (!gst_matroska_mux_tag_list_is_empty (collect_pad->tags))
3508       return TRUE;
3509   }
3510   return FALSE;
3511 }
3512
3513 static void
3514 gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
3515     const GstTocEntry * entry, guint64 * master_tags, gboolean * has_tags)
3516 {
3517   guint64 master_tag, master_targets;
3518   GstEbmlWrite *ebml;
3519   GList *cur;
3520   const GstTagList *tags;
3521
3522   ebml = mux->ebml_write;
3523
3524   tags = gst_toc_entry_get_tags (entry);
3525   if (G_UNLIKELY (tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags))) {
3526     *has_tags = TRUE;
3527
3528     if (*master_tags == 0) {
3529       mux->tags_pos = ebml->pos;
3530       *master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3531     }
3532
3533     master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3534     master_targets =
3535         gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
3536
3537     if (gst_toc_entry_get_entry_type (entry) == GST_TOC_ENTRY_TYPE_EDITION)
3538       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETEDITIONUID,
3539           g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3540     else
3541       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETCHAPTERUID,
3542           g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
3543
3544     gst_ebml_write_master_finish (ebml, master_targets);
3545     gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3546     gst_ebml_write_master_finish (ebml, master_tag);
3547   }
3548
3549   for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
3550       cur = cur->next) {
3551     gst_matroska_mux_write_toc_entry_tags (mux, cur->data, master_tags,
3552         has_tags);
3553   }
3554 }
3555
3556 /**
3557  * gst_matroska_mux_finish:
3558  * @mux: #GstMatroskaMux
3559  *
3560  * Finish a new matroska file (write index etc...)
3561  */
3562 static void
3563 gst_matroska_mux_finish (GstMatroskaMux * mux)
3564 {
3565   GstEbmlWrite *ebml = mux->ebml_write;
3566   guint64 pos;
3567   guint64 duration = 0;
3568   GSList *collected;
3569   const GstTagList *tags, *toc_tags;
3570   const GstToc *toc;
3571   gboolean has_main_tags, toc_has_tags = FALSE;
3572   GList *cur;
3573
3574   /* finish last cluster */
3575   if (mux->cluster) {
3576     gst_ebml_write_master_finish (ebml, mux->cluster);
3577   }
3578
3579   /* cues */
3580   if (mux->index != NULL) {
3581     guint n;
3582     guint64 master, pointentry_master, trackpos_master;
3583
3584     mux->cues_pos = ebml->pos;
3585     gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
3586     master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
3587
3588     for (n = 0; n < mux->num_indexes; n++) {
3589       GstMatroskaIndex *idx = &mux->index[n];
3590
3591       pointentry_master = gst_ebml_write_master_start (ebml,
3592           GST_MATROSKA_ID_POINTENTRY);
3593       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
3594           idx->time / mux->time_scale);
3595       trackpos_master = gst_ebml_write_master_start (ebml,
3596           GST_MATROSKA_ID_CUETRACKPOSITIONS);
3597       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
3598       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
3599           idx->pos - mux->segment_master);
3600       gst_ebml_write_master_finish (ebml, trackpos_master);
3601       gst_ebml_write_master_finish (ebml, pointentry_master);
3602     }
3603
3604     gst_ebml_write_master_finish (ebml, master);
3605     gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
3606   }
3607
3608   /* tags */
3609   tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
3610   has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
3611   toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
3612
3613   if (has_main_tags || gst_matroska_mux_streams_have_tags (mux) || toc != NULL) {
3614     guint64 master_tags = 0, master_tag;
3615
3616     GST_DEBUG_OBJECT (mux, "Writing tags");
3617
3618     if (has_main_tags) {
3619       /* TODO: maybe limit via the TARGETS id by looking at the source pad */
3620       mux->tags_pos = ebml->pos;
3621       master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3622       master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
3623
3624       if (tags != NULL)
3625         gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
3626       if (mux->internal_toc != NULL) {
3627         toc_tags = gst_toc_get_tags (mux->internal_toc);
3628         toc_has_tags = (toc_tags != NULL);
3629         gst_tag_list_foreach (toc_tags, gst_matroska_mux_write_simple_tag,
3630             ebml);
3631       }
3632
3633       gst_ebml_write_master_finish (ebml, master_tag);
3634     }
3635
3636     if (mux->internal_toc != NULL) {
3637       for (cur = gst_toc_get_entries (mux->internal_toc); cur != NULL;
3638           cur = cur->next) {
3639         gst_matroska_mux_write_toc_entry_tags (mux, cur->data, &master_tags,
3640             &toc_has_tags);
3641       }
3642     }
3643
3644     if (master_tags == 0 && gst_matroska_mux_streams_have_tags (mux)) {
3645       mux->tags_pos = ebml->pos;
3646       master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
3647     }
3648     gst_matroska_mux_write_streams_tags (mux);
3649
3650     if (master_tags != 0)
3651       gst_ebml_write_master_finish (ebml, master_tags);
3652   }
3653
3654   /* update seekhead. We know that:
3655    * - a seekhead contains 5 entries.
3656    * - order of entries is as above.
3657    * - a seekhead has a 4-byte header + 8-byte length
3658    * - each entry is 2-byte master, 2-byte ID pointer,
3659    *     2-byte length pointer, all 8/1-byte length, 4-
3660    *     byte ID and 8-byte length pointer, where the
3661    *     length pointer starts at 20.
3662    * - all entries are local to the segment (so pos - segment_master).
3663    * - so each entry is at 12 + 20 + num * 28. */
3664   gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
3665       mux->info_pos - mux->segment_master);
3666   gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
3667       mux->tracks_pos - mux->segment_master);
3668   if (toc != NULL && mux->chapters_pos > 0) {
3669     gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
3670         mux->chapters_pos - mux->segment_master);
3671   } else {
3672     /* void'ify */
3673     guint64 my_pos = ebml->pos;
3674
3675     gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
3676     gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3677     gst_ebml_write_seek (ebml, my_pos);
3678   }
3679   if (mux->index != NULL) {
3680     gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
3681         mux->cues_pos - mux->segment_master);
3682   } else {
3683     /* void'ify */
3684     guint64 my_pos = ebml->pos;
3685
3686     gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
3687     gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3688     gst_ebml_write_seek (ebml, my_pos);
3689   }
3690
3691   if (mux->tags_pos != 0 || toc_has_tags) {
3692     gst_ebml_replace_uint (ebml, mux->seekhead_pos + 144,
3693         mux->tags_pos - mux->segment_master);
3694   } else {
3695     /* void'ify */
3696     guint64 my_pos = ebml->pos;
3697
3698     gst_ebml_write_seek (ebml, mux->seekhead_pos + 124);
3699     gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
3700     gst_ebml_write_seek (ebml, my_pos);
3701   }
3702
3703   if (toc != NULL) {
3704     gst_toc_unref (toc);
3705   }
3706
3707   /* loop tracks:
3708    * - first get the overall duration
3709    *   (a released track may have left a duration in here)
3710    * - write some track header data for subtitles
3711    */
3712   duration = mux->duration;
3713   pos = ebml->pos;
3714   for (collected = mux->collect->data; collected;
3715       collected = g_slist_next (collected)) {
3716     GstMatroskaPad *collect_pad;
3717     /*
3718      * observed duration, this will never remain GST_CLOCK_TIME_NONE
3719      * since this means buffer without timestamps that is not possible
3720      */
3721     GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
3722
3723     collect_pad = (GstMatroskaPad *) collected->data;
3724
3725     GST_DEBUG_OBJECT (mux,
3726         "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
3727         " end ts %" GST_TIME_FORMAT, collect_pad,
3728         GST_TIME_ARGS (collect_pad->start_ts),
3729         GST_TIME_ARGS (collect_pad->end_ts));
3730
3731     if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
3732         GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
3733       collected_duration =
3734           GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
3735       GST_DEBUG_OBJECT (collect_pad->collect.pad,
3736           "final track duration: %" GST_TIME_FORMAT,
3737           GST_TIME_ARGS (collected_duration));
3738     } else {
3739       GST_WARNING_OBJECT (collect_pad->collect.pad,
3740           "unable to get final track duration");
3741     }
3742     if (GST_CLOCK_TIME_IS_VALID (collected_duration) &&
3743         duration < collected_duration)
3744       duration = collected_duration;
3745
3746   }
3747
3748   /* seek back (optional, but do anyway) */
3749   gst_ebml_write_seek (ebml, pos);
3750
3751   /* update duration */
3752   if (duration != 0) {
3753     GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
3754         GST_TIME_ARGS (duration));
3755     pos = mux->ebml_write->pos;
3756     gst_ebml_write_seek (ebml, mux->duration_pos);
3757     gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
3758         gst_guint64_to_gdouble (duration) /
3759         gst_guint64_to_gdouble (mux->time_scale));
3760     gst_ebml_write_seek (ebml, pos);
3761   } else {
3762     /* void'ify */
3763     guint64 my_pos = ebml->pos;
3764
3765     gst_ebml_write_seek (ebml, mux->duration_pos);
3766     gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
3767     gst_ebml_write_seek (ebml, my_pos);
3768   }
3769   GST_DEBUG_OBJECT (mux, "finishing segment");
3770   /* finish segment - this also writes element length */
3771   gst_ebml_write_master_finish (ebml, mux->segment_pos);
3772 }
3773
3774 /**
3775  * gst_matroska_mux_buffer_header:
3776  * @track: Track context.
3777  * @relative_timestamp: relative timestamp of the buffer
3778  * @flags: Buffer flags.
3779  *
3780  * Create a buffer containing buffer header.
3781  *
3782  * Returns: New buffer.
3783  */
3784 static GstBuffer *
3785 gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
3786     gint16 relative_timestamp, int flags)
3787 {
3788   GstBuffer *hdr;
3789   guint8 *data = g_malloc (4);
3790
3791   hdr = gst_buffer_new_wrapped (data, 4);
3792   /* track num - FIXME: what if num >= 0x80 (unlikely)? */
3793   data[0] = track->num | 0x80;
3794   /* time relative to clustertime */
3795   GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
3796
3797   /* flags */
3798   data[3] = flags;
3799
3800   return hdr;
3801 }
3802
3803 #define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
3804 #define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
3805 #define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
3806
3807 static GstBuffer *
3808 gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
3809     GstMatroskaPad * collect_pad, GstBuffer * buf)
3810 {
3811   GstMatroskaTrackVideoContext *ctx =
3812       (GstMatroskaTrackVideoContext *) collect_pad->track;
3813   GstMapInfo map;
3814   guint8 *data;
3815   gsize size;
3816   guint8 parse_code;
3817   guint32 next_parse_offset;
3818   GstBuffer *ret = NULL;
3819   gboolean is_muxing_unit = FALSE;
3820
3821   gst_buffer_map (buf, &map, GST_MAP_READ);
3822   data = map.data;
3823   size = map.size;
3824
3825   if (size < 13) {
3826     gst_buffer_unmap (buf, &map);
3827     gst_buffer_unref (buf);
3828     return ret;
3829   }
3830
3831   /* Check if this buffer contains a picture or end-of-sequence packet */
3832   while (size >= 13) {
3833     if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
3834       gst_buffer_unmap (buf, &map);
3835       gst_buffer_unref (buf);
3836       return ret;
3837     }
3838
3839     parse_code = GST_READ_UINT8 (data + 4);
3840     if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
3841       if (ctx->dirac_unit) {
3842         gst_buffer_unref (ctx->dirac_unit);
3843         ctx->dirac_unit = NULL;
3844       }
3845     } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
3846         parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
3847       is_muxing_unit = TRUE;
3848       break;
3849     }
3850
3851     next_parse_offset = GST_READ_UINT32_BE (data + 5);
3852
3853     if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
3854       break;
3855
3856     data += next_parse_offset;
3857     size -= next_parse_offset;
3858   }
3859
3860   if (ctx->dirac_unit)
3861     ctx->dirac_unit = gst_buffer_append (ctx->dirac_unit, gst_buffer_ref (buf));
3862   else
3863     ctx->dirac_unit = gst_buffer_ref (buf);
3864
3865   gst_buffer_unmap (buf, &map);
3866
3867   if (is_muxing_unit) {
3868     ret = gst_buffer_make_writable (ctx->dirac_unit);
3869     ctx->dirac_unit = NULL;
3870     gst_buffer_copy_into (ret, buf,
3871         GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
3872     gst_buffer_unref (buf);
3873   } else {
3874     gst_buffer_unref (buf);
3875     ret = NULL;
3876   }
3877
3878   return ret;
3879 }
3880
3881 static void
3882 gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
3883 {
3884   GstCaps *caps;
3885   GstStructure *s;
3886   GValue streamheader = { 0 };
3887   GValue bufval = { 0 };
3888   GstBuffer *streamheader_buffer;
3889   GstEbmlWrite *ebml = mux->ebml_write;
3890
3891   streamheader_buffer = gst_ebml_stop_streamheader (ebml);
3892   caps = gst_caps_copy (mux->ebml_write->caps);
3893   s = gst_caps_get_structure (caps, 0);
3894   g_value_init (&streamheader, GST_TYPE_ARRAY);
3895   g_value_init (&bufval, GST_TYPE_BUFFER);
3896   GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_HEADER);
3897   gst_value_set_buffer (&bufval, streamheader_buffer);
3898   gst_value_array_append_value (&streamheader, &bufval);
3899   g_value_unset (&bufval);
3900   gst_structure_set_value (s, "streamheader", &streamheader);
3901   g_value_unset (&streamheader);
3902   gst_caps_replace (&ebml->caps, caps);
3903   gst_buffer_unref (streamheader_buffer);
3904   gst_pad_set_caps (mux->srcpad, caps);
3905   gst_caps_unref (caps);
3906 }
3907
3908 /**
3909  * gst_matroska_mux_write_data:
3910  * @mux: #GstMatroskaMux
3911  * @collect_pad: #GstMatroskaPad with the data
3912  *
3913  * Write collected data (called from gst_matroska_mux_collected).
3914  *
3915  * Returns: Result of the gst_pad_push issued to write the data.
3916  */
3917 static GstFlowReturn
3918 gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
3919     GstBuffer * buf)
3920 {
3921   GstEbmlWrite *ebml = mux->ebml_write;
3922   GstBuffer *hdr;
3923   guint64 blockgroup;
3924   gboolean write_duration;
3925   guint64 cluster_time_scaled;
3926   gint16 relative_timestamp;
3927   gint64 relative_timestamp64;
3928   guint64 block_duration, duration_diff = 0;
3929   gboolean is_video_keyframe = FALSE;
3930   gboolean is_video_invisible = FALSE;
3931   gboolean is_audio_only = FALSE;
3932   gboolean is_min_duration_reached = FALSE;
3933   gboolean is_max_duration_exceeded = FALSE;
3934   GstMatroskamuxPad *pad;
3935   gint flags = 0;
3936   GstClockTime buffer_timestamp;
3937   GstAudioClippingMeta *cmeta = NULL;
3938
3939   /* write data */
3940   pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
3941
3942   /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
3943   if (collect_pad->track->xiph_headers_to_skip > 0) {
3944     --collect_pad->track->xiph_headers_to_skip;
3945     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER)) {
3946       GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
3947       gst_buffer_unref (buf);
3948       return GST_FLOW_OK;
3949     }
3950   }
3951
3952   /* for dirac we have to queue up everything up to a picture unit */
3953   if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC)) {
3954     buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
3955     if (!buf)
3956       return GST_FLOW_OK;
3957   } else if (!strcmp (collect_pad->track->codec_id,
3958           GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) {
3959     /* Remove the 'Frame container atom' header' */
3960     buf = gst_buffer_make_writable (buf);
3961     gst_buffer_resize (buf, 8, gst_buffer_get_size (buf) - 8);
3962   }
3963
3964   buffer_timestamp =
3965       gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
3966   if (buffer_timestamp >= mux->earliest_time) {
3967     buffer_timestamp -= mux->earliest_time;
3968   } else {
3969     buffer_timestamp = 0;
3970   }
3971
3972   /* hm, invalid timestamp (due to --to be fixed--- element upstream);
3973    * this would wreak havoc with time stored in matroska file */
3974   /* TODO: maybe calculate a timestamp by using the previous timestamp
3975    * and default duration */
3976   if (!GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
3977     GST_WARNING_OBJECT (collect_pad->collect.pad,
3978         "Invalid buffer timestamp; dropping buffer");
3979     gst_buffer_unref (buf);
3980     return GST_FLOW_OK;
3981   }
3982
3983   if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
3984       && collect_pad->track->codec_delay) {
3985     /* All timestamps should include the codec delay */
3986     if (buffer_timestamp > collect_pad->track->codec_delay) {
3987       buffer_timestamp += collect_pad->track->codec_delay;
3988     } else {
3989       buffer_timestamp = 0;
3990       duration_diff = collect_pad->track->codec_delay - buffer_timestamp;
3991     }
3992   }
3993
3994   /* set the timestamp for outgoing buffers */
3995   ebml->timestamp = buffer_timestamp;
3996
3997   if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
3998     if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
3999       GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
4000           GST_TIME_ARGS (buffer_timestamp));
4001       is_video_keyframe = TRUE;
4002     } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DECODE_ONLY) &&
4003         (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP8)
4004             || !strcmp (collect_pad->track->codec_id,
4005                 GST_MATROSKA_CODEC_ID_VIDEO_VP9))) {
4006       GST_LOG_OBJECT (mux,
4007           "have VP8 video invisible frame, " "ts=%" GST_TIME_FORMAT,
4008           GST_TIME_ARGS (buffer_timestamp));
4009       is_video_invisible = TRUE;
4010     }
4011   }
4012
4013   /* From this point on we use the buffer_timestamp to do cluster and other
4014    * related arithmetic, so apply the timestamp offset if we have one */
4015   buffer_timestamp += mux->cluster_timestamp_offset;
4016
4017   is_audio_only = (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
4018       (mux->num_streams == 1);
4019   is_min_duration_reached = (mux->min_cluster_duration == 0
4020       || (buffer_timestamp > mux->cluster_time
4021           && (buffer_timestamp - mux->cluster_time) >=
4022           mux->min_cluster_duration));
4023   is_max_duration_exceeded = (mux->max_cluster_duration > 0
4024       && buffer_timestamp > mux->cluster_time
4025       && (buffer_timestamp - mux->cluster_time) >=
4026       MIN (G_MAXINT16 * mux->time_scale, mux->max_cluster_duration));
4027
4028   if (mux->cluster) {
4029     /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
4030      * or when we may be reaching the limit of the relative timestamp */
4031     if (is_max_duration_exceeded || (is_video_keyframe
4032             && is_min_duration_reached) || mux->force_key_unit_event
4033         || (is_audio_only && is_min_duration_reached)) {
4034       if (!mux->ebml_write->streamable)
4035         gst_ebml_write_master_finish (ebml, mux->cluster);
4036
4037       /* Forward the GstForceKeyUnit event after finishing the cluster */
4038       if (mux->force_key_unit_event) {
4039         gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
4040         mux->force_key_unit_event = NULL;
4041       }
4042       cluster_time_scaled =
4043           gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4044
4045       mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
4046       mux->cluster_pos = ebml->pos;
4047       gst_ebml_write_set_cache (ebml, 0x20);
4048       mux->cluster =
4049           gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4050       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4051           cluster_time_scaled);
4052       GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
4053           gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
4054       gst_ebml_write_flush_cache (ebml, is_video_keyframe
4055           || is_audio_only, buffer_timestamp);
4056       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
4057           mux->prev_cluster_size);
4058       /* cluster_time needs to be identical in value to what's stored in the
4059        * matroska so we need to have it with the same precision as what's
4060        * possible with the set timecodescale rather than just using the
4061        * buffer_timestamp.
4062        * If this is not done the rounding of relative_timestamp will be
4063        * incorrect and possibly making the timestamps get out of order if tw
4064        * buffers arrive at the same millisecond (assuming default timecodescale
4065        * of 1ms) */
4066       mux->cluster_time =
4067           gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4068     }
4069   } else {
4070     /* first cluster */
4071     cluster_time_scaled =
4072         gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale);
4073     mux->cluster_pos = ebml->pos;
4074     gst_ebml_write_set_cache (ebml, 0x20);
4075     mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
4076     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
4077         cluster_time_scaled);
4078     gst_ebml_write_flush_cache (ebml, TRUE, buffer_timestamp);
4079     /* cluster_time needs to be identical in value to what's stored in the
4080      * matroska so we need to have it with the same precision as what's
4081      * possible with the set timecodescale rather than just using the
4082      * buffer_timestamp.
4083      * If this is not done the rounding of relative_timestamp will be
4084      * incorrect and possibly making the timestamps get out of order if tw
4085      * buffers arrive at the same millisecond (assuming default timecodescale
4086      * of 1ms) */
4087     mux->cluster_time =
4088         gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1);
4089   }
4090
4091   /* We currently write index entries for all video tracks or for the audio
4092    * track in a single-track audio file.  This could be improved by keeping the
4093    * index only for the *first* video track. */
4094
4095   /* TODO: index is useful for every track, should contain the number of
4096    * the block in the cluster which contains the timestamp, should also work
4097    * for files with multiple audio tracks.
4098    */
4099   if (!mux->ebml_write->streamable && (is_video_keyframe || is_audio_only)) {
4100     gint last_idx = -1;
4101
4102     if (mux->min_index_interval != 0) {
4103       for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
4104         if (mux->index[last_idx].track == collect_pad->track->num)
4105           break;
4106       }
4107     }
4108
4109     if (last_idx < 0 || mux->min_index_interval == 0 ||
4110         (GST_CLOCK_DIFF (mux->index[last_idx].time, buffer_timestamp)
4111             >= mux->min_index_interval)) {
4112       GstMatroskaIndex *idx;
4113
4114       if (mux->num_indexes % 32 == 0) {
4115         mux->index = g_renew (GstMatroskaIndex, mux->index,
4116             mux->num_indexes + 32);
4117       }
4118       idx = &mux->index[mux->num_indexes++];
4119
4120       idx->pos = mux->cluster_pos;
4121       idx->time = buffer_timestamp;
4122       idx->track = collect_pad->track->num;
4123     }
4124   }
4125
4126   /* Check if the duration differs from the default duration. */
4127   write_duration = FALSE;
4128   block_duration = 0;
4129   if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
4130     block_duration = GST_BUFFER_DURATION (buf) + duration_diff;
4131     block_duration = gst_util_uint64_scale (block_duration, 1, mux->time_scale);
4132
4133     /* small difference should be ok. */
4134     if (block_duration > collect_pad->default_duration_scaled + 1 ||
4135         block_duration < collect_pad->default_duration_scaled - 1) {
4136       write_duration = TRUE;
4137     }
4138   }
4139
4140   /* write the block, for doctype v2 use SimpleBlock if possible
4141    * one slice (*breath*).
4142    * FIXME: Need to do correct lacing! */
4143   relative_timestamp64 = buffer_timestamp - mux->cluster_time;
4144   if (relative_timestamp64 >= 0) {
4145     /* round the timestamp */
4146     relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
4147     relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
4148         mux->time_scale);
4149   } else {
4150     /* round the timestamp */
4151     relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
4152     relative_timestamp =
4153         -((gint16) gst_util_uint64_scale (-relative_timestamp64, 1,
4154             mux->time_scale));
4155   }
4156
4157   if (is_video_invisible)
4158     flags |= 0x08;
4159
4160   if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
4161     cmeta = gst_buffer_get_audio_clipping_meta (buf);
4162     g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);
4163
4164     /* Start clipping is done via header and CodecDelay */
4165     if (cmeta && !cmeta->end)
4166       cmeta = NULL;
4167   }
4168
4169   if (mux->doctype_version > 1 && !write_duration && !cmeta) {
4170     if (is_video_keyframe)
4171       flags |= 0x80;
4172
4173     hdr =
4174         gst_matroska_mux_create_buffer_header (collect_pad->track,
4175         relative_timestamp, flags);
4176     gst_ebml_write_set_cache (ebml, 0x40);
4177     gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
4178         gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4179     gst_ebml_write_buffer (ebml, hdr);
4180     gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4181     gst_ebml_write_buffer (ebml, buf);
4182
4183     return gst_ebml_last_write_result (ebml);
4184   } else {
4185     gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
4186     /* write and call order slightly unnatural,
4187      * but avoids seek and minizes pushing */
4188     blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
4189     hdr =
4190         gst_matroska_mux_create_buffer_header (collect_pad->track,
4191         relative_timestamp, flags);
4192     if (write_duration)
4193       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
4194
4195     if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
4196         && cmeta) {
4197       /* Start clipping is done via header and CodecDelay */
4198       if (cmeta->end) {
4199         guint64 end =
4200             gst_util_uint64_scale_round (cmeta->end, GST_SECOND, 48000);
4201         gst_ebml_write_sint (ebml, GST_MATROSKA_ID_DISCARDPADDING, end);
4202       }
4203     }
4204
4205     gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
4206         gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
4207     gst_ebml_write_buffer (ebml, hdr);
4208     gst_ebml_write_master_finish_full (ebml, blockgroup,
4209         gst_buffer_get_size (buf));
4210     gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
4211     gst_ebml_write_buffer (ebml, buf);
4212
4213     return gst_ebml_last_write_result (ebml);
4214   }
4215 }
4216
4217 /**
4218  * gst_matroska_mux_handle_buffer:
4219  * @pads: #GstCollectPads
4220  * @uuser_data: #GstMatroskaMux
4221  *
4222  * Collectpads callback.
4223  *
4224  * Returns: #GstFlowReturn
4225  */
4226 static GstFlowReturn
4227 gst_matroska_mux_handle_buffer (GstCollectPads * pads, GstCollectData * data,
4228     GstBuffer * buf, gpointer user_data)
4229 {
4230   GstClockTime buffer_timestamp;
4231   GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
4232   GstEbmlWrite *ebml = mux->ebml_write;
4233   GstMatroskaPad *best = (GstMatroskaPad *) data;
4234   GstFlowReturn ret = GST_FLOW_OK;
4235   GST_DEBUG_OBJECT (mux, "Collected pads");
4236
4237   /* start with a header */
4238   if (mux->state == GST_MATROSKA_MUX_STATE_START) {
4239     if (mux->collect->data == NULL) {
4240       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
4241           ("No input streams configured"));
4242       return GST_FLOW_ERROR;
4243     }
4244     mux->state = GST_MATROSKA_MUX_STATE_HEADER;
4245     gst_ebml_start_streamheader (ebml);
4246     gst_matroska_mux_start (mux, best, buf);
4247     gst_matroska_mux_stop_streamheader (mux);
4248     mux->state = GST_MATROSKA_MUX_STATE_DATA;
4249   }
4250
4251   /* if there is no best pad, we have reached EOS */
4252   if (best == NULL) {
4253     GST_DEBUG_OBJECT (mux, "No best pad. Finishing...");
4254     if (!mux->ebml_write->streamable) {
4255       gst_matroska_mux_finish (mux);
4256     } else {
4257       GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
4258     }
4259     gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
4260     ret = GST_FLOW_EOS;
4261     goto exit;
4262   }
4263
4264   if (best->track->codec_id == NULL) {
4265     GST_ERROR_OBJECT (best->collect.pad, "No codec-id for pad");
4266     ret = GST_FLOW_NOT_NEGOTIATED;
4267     goto exit;
4268   }
4269
4270   /* if we have a best stream, should also have a buffer */
4271   g_assert (buf);
4272
4273   buffer_timestamp = gst_matroska_track_get_buffer_timestamp (best->track, buf);
4274   if (buffer_timestamp >= mux->earliest_time) {
4275     buffer_timestamp -= mux->earliest_time;
4276   } else {
4277     GST_ERROR_OBJECT (mux,
4278         "PTS before first PTS (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")",
4279         GST_TIME_ARGS (buffer_timestamp), GST_TIME_ARGS (mux->earliest_time));
4280     buffer_timestamp = 0;
4281   }
4282
4283   GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
4284       GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
4285       GST_TIME_ARGS (buffer_timestamp),
4286       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
4287
4288   /* make note of first and last encountered timestamps, so we can calculate
4289    * the actual duration later when we send an updated header on eos */
4290   if (GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
4291     GstClockTime start_ts = buffer_timestamp;
4292     GstClockTime end_ts = start_ts;
4293
4294     if (GST_BUFFER_DURATION_IS_VALID (buf))
4295       end_ts += GST_BUFFER_DURATION (buf);
4296     else if (best->track->default_duration)
4297       end_ts += best->track->default_duration;
4298
4299     if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
4300       best->end_ts = end_ts;
4301
4302     if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
4303             start_ts < best->start_ts))
4304       best->start_ts = start_ts;
4305   }
4306
4307   /* write one buffer */
4308   ret = gst_matroska_mux_write_data (mux, best, buf);
4309
4310 exit:
4311   return ret;
4312 }
4313
4314
4315 /**
4316  * gst_matroska_mux_change_state:
4317  * @element: #GstMatroskaMux
4318  * @transition: State change transition.
4319  *
4320  * Change the muxer state.
4321  *
4322  * Returns: #GstStateChangeReturn
4323  */
4324 static GstStateChangeReturn
4325 gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
4326 {
4327   GstStateChangeReturn ret;
4328   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
4329
4330   switch (transition) {
4331     case GST_STATE_CHANGE_NULL_TO_READY:
4332       break;
4333     case GST_STATE_CHANGE_READY_TO_PAUSED:
4334       gst_collect_pads_start (mux->collect);
4335       break;
4336     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4337       break;
4338     case GST_STATE_CHANGE_PAUSED_TO_READY:
4339       gst_collect_pads_stop (mux->collect);
4340       break;
4341     default:
4342       break;
4343   }
4344
4345   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4346
4347   switch (transition) {
4348     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4349       break;
4350     case GST_STATE_CHANGE_PAUSED_TO_READY:
4351       gst_matroska_mux_reset (GST_ELEMENT (mux));
4352       break;
4353     case GST_STATE_CHANGE_READY_TO_NULL:
4354       break;
4355     default:
4356       break;
4357   }
4358
4359   return ret;
4360 }
4361
4362 static void
4363 gst_matroska_mux_set_property (GObject * object,
4364     guint prop_id, const GValue * value, GParamSpec * pspec)
4365 {
4366   GstMatroskaMux *mux;
4367
4368   g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4369   mux = GST_MATROSKA_MUX (object);
4370
4371   switch (prop_id) {
4372     case PROP_WRITING_APP:
4373       if (!g_value_get_string (value)) {
4374         GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
4375         break;
4376       }
4377       g_free (mux->writing_app);
4378       mux->writing_app = g_value_dup_string (value);
4379       break;
4380     case PROP_DOCTYPE_VERSION:
4381       mux->doctype_version = g_value_get_int (value);
4382       break;
4383     case PROP_MIN_INDEX_INTERVAL:
4384       mux->min_index_interval = g_value_get_int64 (value);
4385       break;
4386     case PROP_STREAMABLE:
4387       mux->ebml_write->streamable = g_value_get_boolean (value);
4388       break;
4389     case PROP_TIMECODESCALE:
4390       mux->time_scale = g_value_get_int64 (value);
4391       break;
4392     case PROP_MIN_CLUSTER_DURATION:
4393       mux->min_cluster_duration = g_value_get_int64 (value);
4394       break;
4395     case PROP_MAX_CLUSTER_DURATION:
4396       mux->max_cluster_duration = g_value_get_int64 (value);
4397       break;
4398     case PROP_OFFSET_TO_ZERO:
4399       mux->offset_to_zero = g_value_get_boolean (value);
4400       break;
4401     case PROP_CREATION_TIME:
4402       g_clear_pointer (&mux->creation_time, g_date_time_unref);
4403       mux->creation_time = g_value_dup_boxed (value);
4404       break;
4405     case PROP_CLUSTER_TIMESTAMP_OFFSET:
4406       mux->cluster_timestamp_offset = g_value_get_uint64 (value);
4407       break;
4408     default:
4409       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4410       break;
4411   }
4412 }
4413
4414 static void
4415 gst_matroska_mux_get_property (GObject * object,
4416     guint prop_id, GValue * value, GParamSpec * pspec)
4417 {
4418   GstMatroskaMux *mux;
4419
4420   g_return_if_fail (GST_IS_MATROSKA_MUX (object));
4421   mux = GST_MATROSKA_MUX (object);
4422
4423   switch (prop_id) {
4424     case PROP_WRITING_APP:
4425       g_value_set_string (value, mux->writing_app);
4426       break;
4427     case PROP_DOCTYPE_VERSION:
4428       g_value_set_int (value, mux->doctype_version);
4429       break;
4430     case PROP_MIN_INDEX_INTERVAL:
4431       g_value_set_int64 (value, mux->min_index_interval);
4432       break;
4433     case PROP_STREAMABLE:
4434       g_value_set_boolean (value, mux->ebml_write->streamable);
4435       break;
4436     case PROP_TIMECODESCALE:
4437       g_value_set_int64 (value, mux->time_scale);
4438       break;
4439     case PROP_MIN_CLUSTER_DURATION:
4440       g_value_set_int64 (value, mux->min_cluster_duration);
4441       break;
4442     case PROP_MAX_CLUSTER_DURATION:
4443       g_value_set_int64 (value, mux->max_cluster_duration);
4444       break;
4445     case PROP_OFFSET_TO_ZERO:
4446       g_value_set_boolean (value, mux->offset_to_zero);
4447       break;
4448     case PROP_CREATION_TIME:
4449       g_value_set_boxed (value, mux->creation_time);
4450       break;
4451     case PROP_CLUSTER_TIMESTAMP_OFFSET:
4452       g_value_set_uint64 (value, mux->cluster_timestamp_offset);
4453       break;
4454     default:
4455       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4456       break;
4457   }
4458 }