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