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