a80be303b1381ff4efd72ba4f630bf1be6438da0
[platform/upstream/gst-plugins-good.git] / gst / matroska / matroska-mux.c
1 /* GStreamer Matroska muxer/demuxer
2  * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * matroska-mux.c: matroska file/stream muxer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <math.h>
27 #include <string.h>
28
29 #include "matroska-mux.h"
30 #include "matroska-ids.h"
31
32 enum {
33   /* FILL ME */
34   LAST_SIGNAL
35 };
36
37 enum {
38   ARG_0,
39   ARG_METADATA,
40   /* FILL ME */
41 };
42
43 static GstStaticPadTemplate src_templ =
44 GST_STATIC_PAD_TEMPLATE (
45   "src",
46   GST_PAD_SRC,
47   GST_PAD_ALWAYS,
48   GST_STATIC_CAPS ("video/x-matroska")
49 );
50
51 #define COMMON_VIDEO_CAPS \
52   "width = (int) [ 16, 4096 ], " \
53   "height = (int) [ 16, 4096 ], " \
54   "framerate = (double) [ 0, MAX ]"
55
56 static GstStaticPadTemplate videosink_templ =
57 GST_STATIC_PAD_TEMPLATE (
58   "video_%d",
59   GST_PAD_SINK,
60   GST_PAD_REQUEST,
61   GST_STATIC_CAPS (
62     "video/mpeg, "
63       "mpegversion = (int) { 1, 2, 4 }, "
64       "systemstream = (boolean) false, "
65       COMMON_VIDEO_CAPS "; "
66     "video/x-divx, "
67       COMMON_VIDEO_CAPS "; "
68     "video/x-xvid, "
69       COMMON_VIDEO_CAPS "; "
70     "video/x-msmpeg, "
71       COMMON_VIDEO_CAPS "; "
72     "video/x-jpeg, "
73       COMMON_VIDEO_CAPS "; "
74     "video/x-raw-yuv, "
75       "format = (fourcc) { YUY2, I420 }, "
76       COMMON_VIDEO_CAPS
77   )
78 );
79
80 #define COMMON_AUDIO_CAPS \
81   "channels = (int) [ 1, 8 ], " \
82   "rate = (int) [ 8000, 96000 ]"
83
84 /* FIXME:
85  * * audio/x-raw-float: endianness needs defining.
86  * * audio/x-vorbis: private data setup needs work.
87  */
88 static GstStaticPadTemplate audiosink_templ =
89 GST_STATIC_PAD_TEMPLATE (
90   "audio_%d",
91   GST_PAD_SINK,
92   GST_PAD_REQUEST,
93   GST_STATIC_CAPS (
94     "audio/mpeg, "
95       "mpegversion = (int) 1, "
96       "layer = (int) [ 1, 3 ], "
97       COMMON_AUDIO_CAPS "; "
98     "audio/mpeg, "
99       "mpegversion = (int) { 2, 4 }, "
100       COMMON_AUDIO_CAPS "; "
101     "audio/x-ac3, "
102       COMMON_AUDIO_CAPS "; "
103     "audio/x-raw-int, "
104       "width = (int) { 8, 16, 24 }, "
105       "depth = (int) { 8, 16, 24 }, "
106       "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
107       "signed = (boolean) { true, false }, "
108       COMMON_AUDIO_CAPS
109   )
110 );
111
112 static GstStaticPadTemplate subtitlesink_templ =
113 GST_STATIC_PAD_TEMPLATE (
114   "subtitle_%d",
115   GST_PAD_SINK,
116   GST_PAD_REQUEST,
117   GST_STATIC_CAPS_ANY
118 );
119
120 /* gobject magic foo */
121 static void     gst_matroska_mux_base_init          (GstMatroskaMuxClass *klass);
122 static void     gst_matroska_mux_class_init         (GstMatroskaMuxClass *klass);
123 static void     gst_matroska_mux_init               (GstMatroskaMux *mux);
124
125 /* element functions */
126 static void     gst_matroska_mux_loop               (GstElement  *element);
127
128 /* pad functions */
129 static GstPad * gst_matroska_mux_request_new_pad    (GstElement *element,
130                                                      GstPadTemplate *templ,
131                                                      const gchar *name);
132
133 /* gst internal change state handler */
134 static GstElementStateReturn
135                 gst_matroska_mux_change_state       (GstElement  *element);
136
137 /* gobject bla bla */
138 static void     gst_matroska_mux_set_property       (GObject     *object,
139                                                      guint        prop_id,      
140                                                      const GValue *value,
141                                                      GParamSpec  *pspec);
142 static void     gst_matroska_mux_get_property       (GObject     *object,
143                                                      guint        prop_id,      
144                                                      GValue      *value,
145                                                      GParamSpec  *pspec);
146
147 /* reset muxer */
148 static void     gst_matroska_mux_reset              (GstElement  *element);
149
150 static GstEbmlWriteClass *parent_class = NULL;
151 /*static guint gst_matroska_mux_signals[LAST_SIGNAL] = { 0 };*/
152
153 GType
154 gst_matroska_mux_get_type (void) 
155 {
156   static GType gst_matroska_mux_type = 0;
157
158   if (!gst_matroska_mux_type) {
159     static const GTypeInfo gst_matroska_mux_info = {
160       sizeof (GstMatroskaMuxClass),      
161       (GBaseInitFunc) gst_matroska_mux_base_init,
162       NULL,
163       (GClassInitFunc) gst_matroska_mux_class_init,
164       NULL,
165       NULL,
166       sizeof (GstMatroskaMux),
167       0,
168       (GInstanceInitFunc) gst_matroska_mux_init,
169     };
170
171     gst_matroska_mux_type =
172         g_type_register_static (GST_TYPE_EBML_WRITE,
173                                 "GstMatroskaMmux",
174                                 &gst_matroska_mux_info, 0);
175   }
176
177   return gst_matroska_mux_type;
178 }
179
180 static void
181 gst_matroska_mux_base_init (GstMatroskaMuxClass *klass)
182 {
183   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
184   static GstElementDetails gst_matroska_mux_details = {
185     "Matroska muxer",
186     "Codec/Muxer",
187     "Muxes video/audio/subtitle streams into a matroska stream",
188     "Ronald Bultje <rbultje@ronald.bitfreak.net>"
189   };
190
191   gst_element_class_add_pad_template (element_class,
192                 gst_static_pad_template_get (&videosink_templ));
193   gst_element_class_add_pad_template (element_class,
194                 gst_static_pad_template_get (&audiosink_templ));
195   gst_element_class_add_pad_template (element_class,
196                 gst_static_pad_template_get (&subtitlesink_templ));
197   gst_element_class_add_pad_template (element_class,
198                 gst_static_pad_template_get (&src_templ));
199   gst_element_class_set_details (element_class,
200                 &gst_matroska_mux_details);
201 }
202
203 static void
204 gst_matroska_mux_class_init (GstMatroskaMuxClass *klass) 
205 {
206   GObjectClass *gobject_class;
207   GstElementClass *gstelement_class;
208
209   gobject_class = (GObjectClass *) klass;
210   gstelement_class = (GstElementClass *) klass;
211
212   g_object_class_install_property (gobject_class, ARG_METADATA,
213     g_param_spec_boxed ("metadata", "Metadata", "Metadata",
214                         GST_TYPE_CAPS, G_PARAM_READWRITE));
215
216   parent_class = g_type_class_ref (GST_TYPE_EBML_WRITE);
217
218   gobject_class->get_property = gst_matroska_mux_get_property;
219   gobject_class->set_property = gst_matroska_mux_set_property;
220
221   gstelement_class->change_state = gst_matroska_mux_change_state;
222   gstelement_class->request_new_pad = gst_matroska_mux_request_new_pad;
223 }
224
225 static void 
226 gst_matroska_mux_init (GstMatroskaMux *mux) 
227 {
228   GstElementClass *klass = GST_ELEMENT_GET_CLASS (mux);
229   gint i;
230
231   mux->srcpad = gst_pad_new_from_template (
232         gst_element_class_get_pad_template (klass, "src"), "src");
233   gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
234   GST_EBML_WRITE (mux)->srcpad = mux->srcpad;
235
236   gst_element_set_loop_function (GST_ELEMENT (mux),
237                                  gst_matroska_mux_loop);
238
239   /* initial stream no. */
240   for (i = 0; i < GST_MATROSKA_MUX_MAX_STREAMS; i++) {
241     mux->sink[i].buffer = NULL;
242     mux->sink[i].track = NULL;
243   }
244   mux->index = NULL;
245
246   /* finish off */
247   gst_matroska_mux_reset (GST_ELEMENT (mux));
248 }
249
250 static void
251 gst_matroska_mux_reset (GstElement *element)
252 {
253   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
254   guint i;
255
256   /* reset input */
257   mux->state = GST_MATROSKA_MUX_STATE_START;
258
259   /* clean up existing streams */
260   for (i = 0; i < GST_MATROSKA_MUX_MAX_STREAMS; i++) {
261     if (mux->sink[i].track != NULL) {
262       if (mux->sink[i].track->pad != NULL) {
263         gst_element_remove_pad (GST_ELEMENT (mux), mux->sink[i].track->pad);
264       }
265       g_free (mux->sink[i].track->codec_id);
266       g_free (mux->sink[i].track->codec_name);
267       g_free (mux->sink[i].track->name);
268       g_free (mux->sink[i].track->language);
269       g_free (mux->sink[i].track->codec_priv);
270       g_free (mux->sink[i].track);
271       mux->sink[i].track = NULL;
272     }
273     if (mux->sink[i].buffer != NULL) {
274       gst_buffer_unref (mux->sink[i].buffer);
275       mux->sink[i].buffer = NULL;
276     }
277     mux->sink[i].eos = FALSE;
278   }
279   mux->num_streams = 0;
280   mux->num_a_streams = 0;
281   mux->num_t_streams = 0;
282   mux->num_v_streams = 0;
283
284   /* reset media info  (to default) */
285   gst_caps_replace (&mux->metadata,
286       gst_caps_new_simple ("application/x-gst-metadata",
287         "application", G_TYPE_STRING, "",
288         "date",        G_TYPE_STRING, "", NULL));
289
290   /* reset indexes */
291   mux->num_indexes = 0;
292   g_free (mux->index);
293   mux->index = NULL;
294
295   /* reset timers */
296   mux->time_scale = 1000000;
297   mux->duration = 0;
298 }
299
300 static GstPadLinkReturn
301 gst_matroska_mux_video_pad_link (GstPad  *pad, const GstCaps *caps)
302 {
303   GstMatroskaTrackContext *context = NULL;
304   GstMatroskaTrackVideoContext *videocontext;
305   GstMatroskaMux *mux = GST_MATROSKA_MUX (gst_pad_get_parent (pad));
306   const gchar *mimetype;
307   gint width, height, pixel_width, pixel_height, i;
308   gdouble framerate;
309   GstStructure *structure;
310   gboolean ret;
311
312   /* find context */
313   for (i = 0; i < mux->num_streams; i++) {
314     if (mux->sink[i].track && mux->sink[i].track->pad &&
315         mux->sink[i].track->pad == pad) {
316       context = mux->sink[i].track;
317       break;
318     }
319   }
320   g_assert (i < mux->num_streams);
321   g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
322   videocontext = (GstMatroskaTrackVideoContext *) context;
323
324   /* gst -> matroska ID'ing */
325   structure = gst_caps_get_structure (caps, 0);
326
327   mimetype = gst_structure_get_name (structure);
328
329   /* get general properties */
330   gst_structure_get_int (structure, "width", &width);
331   gst_structure_get_int (structure, "height", &height);
332   gst_structure_get_double (structure, "framerate", &framerate);
333
334   videocontext->pixel_width = width;
335   videocontext->pixel_height = height;
336   context->default_duration = GST_SECOND / framerate;
337
338   ret = gst_structure_get_int (structure, "pixel_width", &pixel_width);
339   ret &= gst_structure_get_int (structure, "pixel_height", &pixel_height);
340   if (ret) {
341     if (pixel_width > pixel_height) {
342       videocontext->display_width = width * pixel_width / pixel_height;
343       videocontext->display_height = height;
344     } else if (pixel_width < pixel_height) {
345       videocontext->display_width = width;
346       videocontext->display_height = height * pixel_height / pixel_width;
347     } else {
348       videocontext->display_width = 0;
349       videocontext->display_height = 0;
350     }
351   } else {
352     videocontext->display_width = 0;
353     videocontext->display_height = 0;
354   }
355
356   videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
357   videocontext->eye_mode = GST_MATROSKA_EYE_MODE_MONO;
358   videocontext->fourcc = 0;
359
360   /* find type */
361   if (!strcmp (mimetype, "video/x-raw-yuv")) {
362     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
363     gst_structure_get_fourcc (structure, "format", &videocontext->fourcc);
364
365     return GST_PAD_LINK_OK;
366   } else if (!strcmp (mimetype, "video/x-jpeg")) {
367     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
368
369     return GST_PAD_LINK_OK;
370   } else if (!strcmp (mimetype, "video/x-divx")) {
371     gint divxversion;
372
373     gst_structure_get_int (structure, "divxversion", &divxversion);
374     switch (divxversion) {
375       case 3:
376         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
377         break;
378       case 4:
379         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_SP);
380         break;
381       case 5:
382         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
383         break;
384     }
385
386     return GST_PAD_LINK_OK;
387   } else if (!strcmp (mimetype, "video/x-xvid")) {
388     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
389
390     return GST_PAD_LINK_OK;
391   } else if (!strcmp (mimetype, "video/mpeg")) {
392     gint mpegversion;
393
394     gst_structure_get_int (structure, "mpegversion", &mpegversion);
395     switch (mpegversion) {
396       case 1:
397         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
398         break;
399       case 2:
400         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
401         break;
402       case 3:
403         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
404         break;
405     }
406
407     return GST_PAD_LINK_OK;
408   } else if (!strcmp (mimetype, "video/x-msmpeg")) {
409     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
410
411     return GST_PAD_LINK_OK;
412   }
413
414   return GST_PAD_LINK_REFUSED;
415 }
416
417 static GstPadLinkReturn
418 gst_matroska_mux_audio_pad_link (GstPad  *pad,
419                                  const GstCaps *caps)
420 {
421   GstMatroskaTrackContext *context = NULL;
422   GstMatroskaTrackAudioContext *audiocontext;
423   GstMatroskaMux *mux = GST_MATROSKA_MUX (gst_pad_get_parent (pad));
424   const gchar *mimetype;
425   gint samplerate, channels, i;
426   GstStructure *structure;
427
428   /* find context */
429   for (i = 0; i < mux->num_streams; i++) {
430     if (mux->sink[i].track && mux->sink[i].track->pad &&
431         mux->sink[i].track->pad == pad) {
432       context = mux->sink[i].track;
433       break;
434     }
435   }
436   g_assert (i < mux->num_streams);
437   g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
438   audiocontext = (GstMatroskaTrackAudioContext *) context;
439
440   structure = gst_caps_get_structure (caps, 0);
441   mimetype = gst_structure_get_name (structure);
442
443   /* general setup */
444   gst_structure_get_int (structure, "rate", &samplerate);
445   gst_structure_get_int (structure, "channels", &channels);
446
447   audiocontext->samplerate = samplerate;
448   audiocontext->channels = channels;
449   audiocontext->bitdepth = 0;
450
451   if (!strcmp (mimetype, "audio/mpeg")) {
452     gint mpegversion = 0;
453
454     gst_structure_get_int (structure, "mpegversion", &mpegversion);
455     switch (mpegversion) {
456       case 1: {
457         gint layer;
458
459         gst_structure_get_int (structure, "layer", &layer);
460         switch (layer) {
461           case 1:
462             context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
463             break;
464           case 2:
465             context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
466             break;
467           case 3:
468             context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
469             break;
470         }
471         break;
472       }
473       case 2:
474         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG2
475                                       "MAIN");
476         break;
477       case 4:
478         context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG4
479                                       "MAIN");
480         break;
481     }
482
483     return GST_PAD_LINK_OK;
484   } else if (!strcmp (mimetype, "audio/x-raw-int")) {
485     gint endianness, width, depth;
486     gboolean signedness;
487
488     gst_structure_get_int (structure, "endianness", &endianness);
489     gst_structure_get_int (structure, "width", &width);
490     gst_structure_get_int (structure, "depth", &depth);
491     gst_structure_get_int (structure, "signed", &signedness);
492     if (width != depth ||
493         (width == 8 && signedness) || (width == 16 && !signedness))
494       return GST_PAD_LINK_REFUSED;
495
496     audiocontext->bitdepth = depth;
497     if (endianness == G_BIG_ENDIAN)
498       context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
499     else
500       context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
501
502     return GST_PAD_LINK_OK;
503   } else if (!strcmp (mimetype, "audio/x-raw-float")) {
504     /* FIXME: endianness is undefined */
505   } else if (!strcmp (mimetype, "audio/x-vorbis")) {
506     /* FIXME: private data setup needs work */
507   } else if (!strcmp (mimetype, "audio/x-ac3")) {
508     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AC3);
509
510     return GST_PAD_LINK_OK;
511   }
512
513   return GST_PAD_LINK_REFUSED;
514 }
515
516 static GstPadLinkReturn
517 gst_matroska_mux_subtitle_pad_link (GstPad  *pad,
518                                     const GstCaps *caps)
519 {
520   /* Consider this as boilerplate code for now. There is
521    * no single subtitle creation element in GStreamer,
522    * neither do I know how subtitling works at all. */
523
524   return GST_PAD_LINK_REFUSED;
525 }
526
527 static GstPad *
528 gst_matroska_mux_request_new_pad (GstElement     *element,
529                                   GstPadTemplate *templ,
530                                   const gchar    *pad_name)
531 {
532   GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
533   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
534   GstPad *pad = NULL;
535   gchar *name = NULL;
536   GstPadLinkFunction linkfunc = NULL;
537   GstMatroskaTrackContext *context = NULL;
538
539   if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
540     name = g_strdup_printf ("audio_%d", mux->num_a_streams++);
541     linkfunc = gst_matroska_mux_audio_pad_link;
542     context = (GstMatroskaTrackContext *)
543                 g_new0 (GstMatroskaTrackAudioContext, 1);
544     context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
545     context->name = g_strdup ("Audio");
546   } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
547     name = g_strdup_printf ("video_%d", mux->num_v_streams++);
548     linkfunc = gst_matroska_mux_video_pad_link;
549     context = (GstMatroskaTrackContext *)
550                 g_new0 (GstMatroskaTrackVideoContext, 1);
551     context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
552     context->name = g_strdup ("Video");
553   } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%d")) {
554     name = g_strdup_printf ("subtitle_%d", mux->num_t_streams++);
555     linkfunc = gst_matroska_mux_subtitle_pad_link;
556     context = (GstMatroskaTrackContext *)
557                 g_new0 (GstMatroskaTrackSubtitleContext, 1);
558     context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
559     context->name = g_strdup ("Subtitle");
560   } else {
561     g_warning ("matroskamux: this is not our template!");
562     return NULL;
563   }
564
565   pad = gst_pad_new_from_template (templ, name);
566   g_free (name);
567   gst_element_add_pad (element, pad);
568   gst_pad_set_link_function (pad, linkfunc);
569   context->index = mux->num_streams++;
570   mux->sink[context->index].track = context;
571   context->pad = pad;
572   context->flags = GST_MATROSKA_TRACK_ENABLED |
573                    GST_MATROSKA_TRACK_DEFAULT;
574   
575   return pad;
576 }
577
578 static void
579 gst_matroska_mux_track_header (GstMatroskaMux          *mux,
580                                GstMatroskaTrackContext *context)
581 {
582   GstEbmlWrite *ebml = GST_EBML_WRITE (mux);
583   guint64 master;
584
585   /* track type goes before the type-specific stuff */
586   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
587   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
588
589   /* type-specific stuff */
590   switch (context->type) {
591     case GST_MATROSKA_TRACK_TYPE_VIDEO: {
592       GstMatroskaTrackVideoContext *videocontext =
593         (GstMatroskaTrackVideoContext *) context;
594
595       /* framerate, but not in the video part */
596       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
597                            context->default_duration);
598
599       master = gst_ebml_write_master_start (ebml,
600                                 GST_MATROSKA_ID_TRACKVIDEO);
601       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
602                            videocontext->pixel_width);
603       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
604                            videocontext->pixel_height);
605       if (videocontext->display_width && videocontext->display_height) {
606         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
607                              videocontext->display_width);
608         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
609                              videocontext->display_height);
610       }
611       if (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED)
612         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
613       if (videocontext->fourcc) {
614         guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
615         gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
616                                (gpointer) &fcc_le, 4);
617       }
618       gst_ebml_write_master_finish (ebml, master);
619
620       break;
621     }
622
623     case GST_MATROSKA_TRACK_TYPE_AUDIO: {
624       GstMatroskaTrackAudioContext *audiocontext =
625         (GstMatroskaTrackAudioContext *) context;
626
627       master = gst_ebml_write_master_start (ebml,
628                                 GST_MATROSKA_ID_TRACKAUDIO);
629       if (audiocontext->samplerate != 8000)
630         gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
631                               audiocontext->samplerate);
632       if (audiocontext->channels != 1)
633         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
634                              audiocontext->channels);
635       if (audiocontext->bitdepth) {
636         gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
637                              audiocontext->bitdepth);
638       }
639       gst_ebml_write_master_finish (ebml, master);
640
641       break;
642     }
643
644     default:
645       /* doesn't need type-specific data */
646       break;
647   }
648
649   gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID,
650                         context->codec_id);
651   if (context->codec_priv)
652     gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
653                            context->codec_priv, context->codec_priv_size);
654   /* FIXME: until we have a nice way of getting the codecname
655    * out of the caps, I'm not going to enable this. Too much
656    * (useless, double, boring) work... */
657   /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
658                        context->codec_name);*/
659   gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME,
660                        context->name);
661 }
662
663 static void
664 gst_matroska_mux_start (GstMatroskaMux *mux)
665 {
666   GstEbmlWrite *ebml = GST_EBML_WRITE (mux);
667   guint32 seekhead_id[] = { GST_MATROSKA_ID_INFO,
668                             GST_MATROSKA_ID_TRACKS,
669                             GST_MATROSKA_ID_CUES,
670 #if 0
671                             GST_MATROSKA_ID_TAGS,
672 #endif
673                             0 };
674   guint64 master, child;
675   gint i;
676   guint tracknum = 1;
677
678   /* we start with a EBML header */
679   gst_ebml_write_header (ebml, "matroska", 1);
680
681   /* start a segment */
682   mux->segment_pos = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
683   mux->segment_master = ebml->pos;
684
685   /* the rest of the header is cached */
686   gst_ebml_write_set_cache (ebml, 0x1000);
687
688   /* seekhead (table of contents) - we set the positions later */
689   mux->seekhead_pos = ebml->pos;
690   master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
691   for (i = 0; seekhead_id[i] != 0; i++) {
692     child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
693     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
694     gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
695     gst_ebml_write_master_finish (ebml, child);
696   }
697   gst_ebml_write_master_finish (ebml, master);
698
699   /* segment info */
700   mux->info_pos = ebml->pos;
701   master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_INFO);
702   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
703   mux->duration_pos = ebml->pos;
704   gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION, 0);
705   gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP, "GStreamer");
706   if (mux->metadata &&
707       gst_structure_has_field (gst_caps_get_structure(mux->metadata,0),
708         "application")) {
709     const gchar *app;
710
711     app = gst_structure_get_string (gst_caps_get_structure(mux->metadata, 0),
712         "application");
713     if (app && app[0]) {
714       gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, app);
715     }
716   }
717   /* FIXME: how do I get this? Automatic? Via tags? */
718   /*gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, 0);*/
719   gst_ebml_write_master_finish (ebml, master);
720
721   /* tracks */
722   mux->tracks_pos = ebml->pos;
723   master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
724   for (i = 0; i < mux->num_streams; i++) {
725     if (GST_PAD_IS_USABLE (mux->sink[i].track->pad)) {
726       mux->sink[i].track->num = tracknum++;
727       child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
728       gst_matroska_mux_track_header (mux, mux->sink[i].track);
729       gst_ebml_write_master_finish (ebml, child);
730     }
731   }
732   gst_ebml_write_master_finish (ebml, master);
733
734   /* lastly, flush the cache */
735   gst_ebml_write_flush_cache (ebml);
736 }
737
738 static void
739 gst_matroska_mux_finish (GstMatroskaMux *mux)
740 {
741   GstEbmlWrite *ebml = GST_EBML_WRITE (mux);
742   guint64 pos;
743
744   /* cues */
745   if (mux->index != NULL) {
746     guint n;
747     guint64 master, pointentry_master, trackpos_master;
748
749     mux->cues_pos = ebml->pos;
750     gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
751     master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
752
753     for (n = 0; n < mux->num_indexes; n++) {
754       GstMatroskaIndex *idx = &mux->index[n];
755
756       pointentry_master = gst_ebml_write_master_start (ebml,
757                                         GST_MATROSKA_ID_POINTENTRY);
758       gst_ebml_write_date (ebml, GST_MATROSKA_ID_CUETIME,
759                            idx->time / mux->time_scale);
760       trackpos_master = gst_ebml_write_master_start (ebml,
761                                         GST_MATROSKA_ID_CUETRACKPOSITION);
762       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
763       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
764                            idx->pos - mux->segment_master);
765       gst_ebml_write_master_finish (ebml, trackpos_master);
766       gst_ebml_write_master_finish (ebml, pointentry_master);
767     }
768
769     gst_ebml_write_master_finish (ebml, master);
770     gst_ebml_write_flush_cache (ebml);
771   }
772
773   /* FIXME: tags */
774
775   /* update seekhead. We know that:
776    * - a seekhead contains 4 entries.
777    * - order of entries is as above.
778    * - a seekhead has a 4-byte header + 8-byte length
779    * - each entry is 2-byte master, 2-byte ID pointer,
780    *     2-byte length pointer, all 8/1-byte length, 4-
781    *     byte ID and 8-byte length pointer, where the
782    *     length pointer starts at 20.
783    * - all entries are local to the segment (so pos - segment_master).
784    * - so each entry is at 12 + 20 + num * 28. */
785   gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
786                          mux->info_pos - mux->segment_master);
787   gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
788                          mux->tracks_pos - mux->segment_master);
789   if (mux->index != NULL) {
790     gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
791                            mux->cues_pos - mux->segment_master);
792   } else {
793     /* void'ify */
794     guint64 my_pos = ebml->pos;
795     gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
796     gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
797     gst_ebml_write_seek (ebml, my_pos);
798   }
799 #if 0
800   gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
801                          mux->tags_pos - mux->segment_master);
802 #endif
803
804   /* update duration */
805   pos = GST_EBML_WRITE (mux)->pos;
806   gst_ebml_write_seek (ebml, mux->duration_pos);
807   gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
808                         mux->duration / mux->time_scale);
809   gst_ebml_write_seek (ebml, pos);
810
811   /* finish segment - this also writes element length */
812   gst_ebml_write_master_finish (ebml, mux->segment_pos);
813 }
814
815 static gint
816 gst_matroska_mux_prepare_data (GstMatroskaMux *mux)
817 {
818   gint i, first = -1;
819
820   for (i = 0; i < mux->num_streams; i++) {
821     while (!mux->sink[i].eos && !mux->sink[i].buffer &&
822            mux->sink[i].track->num > 0 &&
823            GST_PAD_IS_USABLE (mux->sink[i].track->pad)) {
824       GstData *data;
825
826       data = gst_pad_pull (mux->sink[i].track->pad);
827       if (GST_IS_EVENT (data)) {
828         if (GST_EVENT_TYPE (GST_EVENT (data)) == GST_EVENT_EOS)
829           mux->sink[i].eos = TRUE;
830         gst_event_unref (GST_EVENT (data));
831       } else {
832         mux->sink[i].buffer = GST_BUFFER (data);
833       }
834     }
835
836     if (mux->sink[i].buffer) {
837       if (first < 0 || GST_BUFFER_TIMESTAMP (mux->sink[i].buffer) <
838                          GST_BUFFER_TIMESTAMP (mux->sink[first].buffer))
839         first = i;
840     }
841   }
842
843   return first;
844 }
845
846 static void
847 gst_matroska_mux_write_data (GstMatroskaMux *mux)
848 {
849   GstEbmlWrite *ebml = GST_EBML_WRITE (mux);
850   GstBuffer *buf, *hdr;
851   gint i;
852   guint64 cluster, blockgroup;
853
854   /* which stream-num to write from? */
855   if ((i = gst_matroska_mux_prepare_data (mux)) < 0) {
856     GstEvent *event = gst_event_new (GST_EVENT_EOS);
857
858     gst_matroska_mux_finish (mux);
859     gst_pad_push (mux->srcpad, GST_DATA (event));
860     gst_element_set_eos (GST_ELEMENT (mux));
861
862     return;
863   }
864
865   /* write data */
866   buf = mux->sink[i].buffer;
867   mux->sink[i].buffer = NULL;
868
869   /* We currently write an index entry for each keyframe in a
870    * video track. This can be largely improved, such as doing
871    * one for each keyframe or each second (for all-keyframe
872    * streams), only the *first* video track or the audio track
873    * if we have no video tracks. But that'll come later... */
874   if (mux->sink[i].track->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
875       GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_KEY_UNIT)) {
876     GstMatroskaIndex *idx;
877
878     if (mux->num_indexes % 32 == 0) {
879       mux->index = g_renew (GstMatroskaIndex, mux->index,
880                             mux->num_indexes + 32);
881     }
882     idx = &mux->index[mux->num_indexes++];
883
884     idx->pos   = ebml->pos;
885     idx->time  = GST_BUFFER_TIMESTAMP (buf);
886     idx->track = mux->sink[i].track->num;
887   }
888
889   /* write one cluster with one blockgroup with one block with
890    * one slice (*breath*).
891    * FIXME: lacing, multiple frames/cluster, etc. */
892   cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
893   gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
894                        GST_BUFFER_TIMESTAMP (buf) / mux->time_scale);
895   blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
896   gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
897                                 GST_BUFFER_SIZE (buf) + 4);
898   hdr = gst_buffer_new_and_alloc (4);
899   /* track num - FIXME: what if num >= 0x80 (unlikely)? */
900   GST_BUFFER_DATA (hdr)[0] = mux->sink[i].track->num | 0x80;
901   /* time relative to clustertime - we don't use this yet */
902   * (guint16 *) &GST_BUFFER_DATA (hdr)[1] = GUINT16_TO_BE (0);
903   /* flags - no lacing (yet) */
904   GST_BUFFER_DATA (hdr)[3] = 0;
905   gst_ebml_write_buffer (ebml, hdr);
906   gst_ebml_write_buffer (ebml, buf);
907   gst_ebml_write_master_finish (ebml, blockgroup);
908   gst_ebml_write_master_finish (ebml, cluster);
909 }
910
911 static void
912 gst_matroska_mux_loop (GstElement *element)
913 {
914   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
915
916   /* start with a header */
917   if (mux->state == GST_MATROSKA_MUX_STATE_START) {
918     mux->state = GST_MATROSKA_MUX_STATE_HEADER;
919     gst_matroska_mux_start (mux);
920     mux->state = GST_MATROSKA_MUX_STATE_DATA;
921   }
922
923   /* do one single buffer */
924   gst_matroska_mux_write_data (mux);
925 }
926
927 static GstElementStateReturn
928 gst_matroska_mux_change_state (GstElement *element)
929 {
930   GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
931
932   switch (GST_STATE_TRANSITION (element)) {
933     case GST_STATE_PAUSED_TO_READY:
934       gst_matroska_mux_reset (GST_ELEMENT (mux));
935       break;
936     default:
937       break;
938   }
939
940   if (((GstElementClass *) parent_class)->change_state)
941     return ((GstElementClass *) parent_class)->change_state (element);
942
943   return GST_STATE_SUCCESS;
944 }
945
946 static void
947 gst_matroska_mux_set_property (GObject      *object,
948                                guint         prop_id,   
949                                const GValue *value,
950                                GParamSpec   *pspec)
951 {
952   GstMatroskaMux *mux;
953
954   g_return_if_fail (GST_IS_MATROSKA_MUX (object));
955   mux = GST_MATROSKA_MUX (object);
956
957   switch (prop_id) {
958     case ARG_METADATA:
959       gst_caps_replace (&mux->metadata,
960                         g_value_get_boxed (value));
961       break;
962     default:
963       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
964       break;
965   }
966 }
967
968 static void
969 gst_matroska_mux_get_property (GObject    *object,
970                                guint       prop_id,     
971                                GValue     *value,
972                                GParamSpec *pspec)
973 {
974   GstMatroskaMux *mux;
975
976   g_return_if_fail (GST_IS_MATROSKA_MUX (object));
977   mux = GST_MATROSKA_MUX (object);
978
979   switch (prop_id) {
980     case ARG_METADATA:
981       g_value_set_boxed (value, mux->metadata);
982       break;
983     default:
984       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
985       break;
986   }
987 }
988
989 gboolean
990 gst_matroska_mux_plugin_init (GstPlugin *plugin)
991 {
992   return gst_element_register (plugin, "matroskamux",
993                                GST_RANK_NONE,
994                                GST_TYPE_MATROSKA_MUX);
995 }