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