matroska-demux.c 197 KB
Newer Older
1
2
/* GStreamer Matroska muxer/demuxer
 * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3
 * (c) 2006 Tim-Philipp Müller <tim centricular net>
4
 * (c) 2008 Sebastian Dröge <slomo@circular-chaos.org>
5
 * (c) 2011 Debarshi Ray <rishi@gnu.org>
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * matroska-demux.c: matroska file/stream demuxer
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
21
22
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
23
24
 */

25
/* TODO: check CRC32 if present
26
27
28
29
30
31
32
33
 * TODO: there can be a segment after the first segment. Handle like
 *       chained oggs. Fixes #334082
 * TODO: Test samples: http://www.matroska.org/samples/matrix/index.html
 *                     http://samples.mplayerhq.hu/Matroska/
 * TODO: check if demuxing is done correct for all codecs according to spec
 * TODO: seeking with incomplete or without CUE
 */

34
35
36
37
38
39
40
41
/**
 * SECTION:element-matroskademux
 *
 * matroskademux demuxes a Matroska file into the different contained streams.
 *
 * <refsect2>
 * <title>Example launch line</title>
 * |[
42
 * gst-launch-1.0 -v filesrc location=/path/to/mkv ! matroskademux ! vorbisdec ! audioconvert ! audioresample ! autoaudiosink
43
44
45
46
47
 * ]| This pipeline demuxes a Matroska file and outputs the contained Vorbis audio.
 * </refsect2>
 */


48
49
50
51
52
53
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <math.h>
#include <string.h>
54
#include <glib/gprintf.h>
55

56
57
/* For AVI compatibility mode
   and for fourcc stuff */
58
#include <gst/riff/riff-read.h>
59
60
#include <gst/riff/riff-ids.h>
#include <gst/riff/riff-media.h>
61

René Stadler's avatar
René Stadler committed
62
#include <gst/audio/audio.h>
63
#include <gst/tag/tag.h>
64
#include <gst/pbutils/pbutils.h>
65
#include <gst/video/video.h>
66

67
68
69
#include "matroska-demux.h"
#include "matroska-ids.h"

70
GST_DEBUG_CATEGORY_STATIC (matroskademux_debug);
71
72
#define GST_CAT_DEFAULT matroskademux_debug

73
74
#define DEBUG_ELEMENT_START(demux, ebml, element) \
    GST_DEBUG_OBJECT (demux, "Parsing " element " element at offset %" \
75
        G_GUINT64_FORMAT, gst_ebml_read_get_pos (ebml))
76
77

#define DEBUG_ELEMENT_STOP(demux, ebml, element, ret) \
78
79
    GST_DEBUG_OBJECT (demux, "Parsing " element " element " \
        " finished with '%s'", gst_flow_get_name (ret))
80

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
81
82
enum
{
83
84
85
86
  PROP_0,
  PROP_METADATA,
  PROP_STREAMINFO,
  PROP_MAX_GAP_TIME
87
88
};

89
90
#define  DEFAULT_MAX_GAP_TIME      (2 * GST_SECOND)

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
91
92
93
static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
94
95
    GST_STATIC_CAPS ("audio/x-matroska; video/x-matroska; "
        "video/x-matroska-3d; audio/webm; video/webm")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
96
    );
97

98
99
/* TODO: fill in caps! */

100
static GstStaticPadTemplate audio_src_templ =
Wim Taymans's avatar
Wim Taymans committed
101
GST_STATIC_PAD_TEMPLATE ("audio_%u",
102
103
104
105
106
107
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
    GST_STATIC_CAPS ("ANY")
    );

static GstStaticPadTemplate video_src_templ =
Wim Taymans's avatar
Wim Taymans committed
108
GST_STATIC_PAD_TEMPLATE ("video_%u",
109
110
111
112
113
114
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
    GST_STATIC_CAPS ("ANY")
    );

static GstStaticPadTemplate subtitle_src_templ =
Wim Taymans's avatar
Wim Taymans committed
115
    GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
116
117
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
118
    GST_STATIC_CAPS ("text/x-raw, format=pango-markup; application/x-ssa; "
119
        "application/x-ass;application/x-usf; subpicture/x-dvd; "
120
        "subpicture/x-pgs; subtitle/x-kate; " "application/x-subtitle-unknown")
121
122
    );

123
124
static GstFlowReturn gst_matroska_demux_parse_id (GstMatroskaDemux * demux,
    guint32 id, guint64 length, guint needed);
125

126
/* element functions */
127
128
129
static void gst_matroska_demux_loop (GstPad * pad);

static gboolean gst_matroska_demux_element_send_event (GstElement * element,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
130
    GstEvent * event);
131
132
133
static gboolean gst_matroska_demux_element_query (GstElement * element,
    GstQuery * query);

134
/* pad functions */
René Stadler's avatar
René Stadler committed
135
136
137
138
static gboolean gst_matroska_demux_sink_activate (GstPad * sinkpad,
    GstObject * parent);
static gboolean gst_matroska_demux_sink_activate_mode (GstPad * sinkpad,
    GstObject * parent, GstPadMode mode, gboolean active);
139

140
static gboolean gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
141
    GstPad * pad, GstEvent * event);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
142
static gboolean gst_matroska_demux_handle_src_event (GstPad * pad,
René Stadler's avatar
René Stadler committed
143
    GstObject * parent, GstEvent * event);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
144
static gboolean gst_matroska_demux_handle_src_query (GstPad * pad,
René Stadler's avatar
René Stadler committed
145
    GstObject * parent, GstQuery * query);
146

147
static gboolean gst_matroska_demux_handle_sink_event (GstPad * pad,
René Stadler's avatar
René Stadler committed
148
    GstObject * parent, GstEvent * event);
149
static GstFlowReturn gst_matroska_demux_chain (GstPad * pad,
René Stadler's avatar
René Stadler committed
150
    GstObject * object, GstBuffer * buffer);
151

152
153
154
static GstStateChangeReturn
gst_matroska_demux_change_state (GstElement * element,
    GstStateChange transition);
155
#if 0
156
157
158
static void
gst_matroska_demux_set_index (GstElement * element, GstIndex * index);
static GstIndex *gst_matroska_demux_get_index (GstElement * element);
159
#endif
160
161

/* caps functions */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
162
static GstCaps *gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext
163
164
    * videocontext, const gchar * codec_id, guint8 * data, guint size,
    gchar ** codec_name, guint32 * riff_fourcc);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
165
static GstCaps *gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext
166
167
    * audiocontext, const gchar * codec_id, guint8 * data, guint size,
    gchar ** codec_name, guint16 * riff_audio_fmt);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
168
169
170
static GstCaps
    * gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext *
    subtitlecontext, const gchar * codec_id, gpointer data, guint size);
171
172

/* stream methods */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
173
static void gst_matroska_demux_reset (GstElement * element);
174
static gboolean perform_seek_to_offset (GstMatroskaDemux * demux,
175
    gdouble rate, guint64 offset, guint32 seqnum);
176

177
178
179
180
181
182
/* gobject functions */
static void gst_matroska_demux_set_property (GObject * object,
    guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_matroska_demux_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec);

183
GType gst_matroska_demux_get_type (void);
René Stadler's avatar
René Stadler committed
184
185
#define parent_class gst_matroska_demux_parent_class
G_DEFINE_TYPE (GstMatroskaDemux, gst_matroska_demux, GST_TYPE_ELEMENT);
186

187
188
189
190
191
static void
gst_matroska_demux_finalize (GObject * object)
{
  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (object);

192
  gst_matroska_read_common_finalize (&demux->common);
193
  gst_flow_combiner_free (demux->flowcombiner);
194
195
196
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

197
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
198
gst_matroska_demux_class_init (GstMatroskaDemuxClass * klass)
199
{
200
201
  GObjectClass *gobject_class = (GObjectClass *) klass;
  GstElementClass *gstelement_class = (GstElementClass *) klass;
202

203
204
  GST_DEBUG_CATEGORY_INIT (matroskademux_debug, "matroskademux", 0,
      "Matroska demuxer");
205

206
207
  gobject_class->finalize = gst_matroska_demux_finalize;

208
209
210
  gobject_class->get_property = gst_matroska_demux_get_property;
  gobject_class->set_property = gst_matroska_demux_set_property;

211
  g_object_class_install_property (gobject_class, PROP_MAX_GAP_TIME,
212
      g_param_spec_uint64 ("max-gap-time", "Maximum gap time",
René Stadler's avatar
René Stadler committed
213
          "The demuxer sends out segment events for skipping "
214
215
216
          "gaps longer than this (0 = disabled).", 0, G_MAXUINT64,
          DEFAULT_MAX_GAP_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

217
218
219
220
  gstelement_class->change_state =
      GST_DEBUG_FUNCPTR (gst_matroska_demux_change_state);
  gstelement_class->send_event =
      GST_DEBUG_FUNCPTR (gst_matroska_demux_element_send_event);
221
222
  gstelement_class->query =
      GST_DEBUG_FUNCPTR (gst_matroska_demux_element_query);
223
#if 0
224
225
226
227
  gstelement_class->set_index =
      GST_DEBUG_FUNCPTR (gst_matroska_demux_set_index);
  gstelement_class->get_index =
      GST_DEBUG_FUNCPTR (gst_matroska_demux_get_index);
228
#endif
René Stadler's avatar
René Stadler committed
229
230
231
232
233
234
235
236
237
238

  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&video_src_templ));
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&audio_src_templ));
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&subtitle_src_templ));
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&sink_templ));

239
  gst_element_class_set_static_metadata (gstelement_class, "Matroska demuxer",
René Stadler's avatar
René Stadler committed
240
241
      "Codec/Demuxer",
      "Demuxes Matroska/WebM streams into video/audio/subtitles",
242
      "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
243
244
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
245
static void
René Stadler's avatar
René Stadler committed
246
gst_matroska_demux_init (GstMatroskaDemux * demux)
247
{
248
249
250
  demux->common.sinkpad = gst_pad_new_from_static_template (&sink_templ,
      "sink");
  gst_pad_set_activate_function (demux->common.sinkpad,
251
      GST_DEBUG_FUNCPTR (gst_matroska_demux_sink_activate));
René Stadler's avatar
René Stadler committed
252
253
  gst_pad_set_activatemode_function (demux->common.sinkpad,
      GST_DEBUG_FUNCPTR (gst_matroska_demux_sink_activate_mode));
254
  gst_pad_set_chain_function (demux->common.sinkpad,
255
      GST_DEBUG_FUNCPTR (gst_matroska_demux_chain));
256
  gst_pad_set_event_function (demux->common.sinkpad,
257
      GST_DEBUG_FUNCPTR (gst_matroska_demux_handle_sink_event));
258
  gst_element_add_pad (GST_ELEMENT (demux), demux->common.sinkpad);
259

260
261
  /* init defaults for common read context */
  gst_matroska_read_common_init (&demux->common);
262

263
264
265
  /* property defaults */
  demux->max_gap_time = DEFAULT_MAX_GAP_TIME;

Wim Taymans's avatar
Wim Taymans committed
266
267
  GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);

268
269
  demux->flowcombiner = gst_flow_combiner_new ();

270
271
  /* finish off */
  gst_matroska_demux_reset (GST_ELEMENT (demux));
272
273
}

274
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
275
gst_matroska_demux_reset (GstElement * element)
276
277
278
{
  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);

279
280
  GST_DEBUG_OBJECT (demux, "Resetting state");

281
  gst_matroska_read_common_reset (GST_ELEMENT (demux), &demux->common);
282

283
284
285
286
  demux->num_a_streams = 0;
  demux->num_t_streams = 0;
  demux->num_v_streams = 0;

287
288
289
  demux->have_group_id = FALSE;
  demux->group_id = G_MAXUINT;

290
291
  demux->clock = NULL;
  demux->tracks_parsed = FALSE;
292

293
294
295
296
297
  if (demux->clusters) {
    g_array_free (demux->clusters, TRUE);
    demux->clusters = NULL;
  }

298
  g_list_foreach (demux->seek_parsed,
299
      (GFunc) gst_matroska_read_common_free_parsed_el, NULL);
300
301
302
  g_list_free (demux->seek_parsed);
  demux->seek_parsed = NULL;

303
  demux->last_stop_end = GST_CLOCK_TIME_NONE;
304
  demux->seek_block = 0;
305
  demux->stream_start_time = GST_CLOCK_TIME_NONE;
306
  demux->to_time = GST_CLOCK_TIME_NONE;
307
308
  demux->cluster_time = GST_CLOCK_TIME_NONE;
  demux->cluster_offset = 0;
309
  demux->next_cluster_offset = 0;
310
311
  demux->index_offset = 0;
  demux->seekable = FALSE;
René Stadler's avatar
René Stadler committed
312
  demux->need_segment = FALSE;
313
  demux->segment_seqnum = 0;
314
315
  demux->requested_seek_time = GST_CLOCK_TIME_NONE;
  demux->seek_offset = -1;
316
317
318
319
320
  demux->building_index = FALSE;
  if (demux->seek_event) {
    gst_event_unref (demux->seek_event);
    demux->seek_event = NULL;
  }
321

322
323
324
  demux->seek_index = NULL;
  demux->seek_entry = 0;

325
326
327
328
  if (demux->new_segment) {
    gst_event_unref (demux->new_segment);
    demux->new_segment = NULL;
  }
329

330
  demux->invalid_duration = FALSE;
331

332
333
  demux->cached_length = G_MAXUINT64;

334
  gst_flow_combiner_clear (demux->flowcombiner);
335
336
}

337
338
339
static GstBuffer *
gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf)
{
Wim Taymans's avatar
Wim Taymans committed
340
341
342
  GstMapInfo map;
  gpointer data;
  gsize size;
343
344
345

  g_return_val_if_fail (GST_IS_BUFFER (buf), NULL);

346
347
  GST_DEBUG ("decoding buffer %p", buf);

Wim Taymans's avatar
Wim Taymans committed
348
349
350
  gst_buffer_map (buf, &map, GST_MAP_READ);
  data = map.data;
  size = map.size;
René Stadler's avatar
René Stadler committed
351

Wim Taymans's avatar
Wim Taymans committed
352
  g_return_val_if_fail (size > 0, buf);
353
354
355

  if (gst_matroska_decode_data (context->encodings, &data, &size,
          GST_MATROSKA_TRACK_ENCODING_SCOPE_FRAME, FALSE)) {
Wim Taymans's avatar
Wim Taymans committed
356
    gst_buffer_unmap (buf, &map);
357
    gst_buffer_unref (buf);
René Stadler's avatar
René Stadler committed
358
    return gst_buffer_new_wrapped (data, size);
359
  } else {
360
    GST_DEBUG ("decode data failed");
Wim Taymans's avatar
Wim Taymans committed
361
    gst_buffer_unmap (buf, &map);
362
363
364
365
366
    gst_buffer_unref (buf);
    return NULL;
  }
}

367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
static void
gst_matroska_demux_add_stream_headers_to_caps (GstMatroskaDemux * demux,
    GstBufferList * list, GstCaps * caps)
{
  GstStructure *s;
  GValue arr_val = G_VALUE_INIT;
  GValue buf_val = G_VALUE_INIT;
  gint i, num;

  g_assert (gst_caps_is_writable (caps));

  g_value_init (&arr_val, GST_TYPE_ARRAY);
  g_value_init (&buf_val, GST_TYPE_BUFFER);

  num = gst_buffer_list_length (list);
  for (i = 0; i < num; ++i) {
    g_value_set_boxed (&buf_val, gst_buffer_list_get (list, i));
    gst_value_array_append_value (&arr_val, &buf_val);
  }

  s = gst_caps_get_structure (caps, 0);
  gst_structure_take_value (s, "streamheader", &arr_val);
  g_value_unset (&buf_val);
}

392
static GstFlowReturn
393
gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
394
395
396
397
{
  GstElementClass *klass = GST_ELEMENT_GET_CLASS (demux);
  GstMatroskaTrackContext *context;
  GstPadTemplate *templ = NULL;
398
  GstStreamFlags stream_flags;
399
  GstCaps *caps = NULL;
400
  GstTagList *cached_taglist;
401
  gchar *padname = NULL;
402
  GstFlowReturn ret;
403
404
  guint32 id, riff_fourcc = 0;
  guint16 riff_audio_fmt = 0;
405
  GstEvent *stream_start;
406
  gchar *codec = NULL;
407
  gchar *stream_id;
408

409
410
411
412
413
414
415
416
  DEBUG_ELEMENT_START (demux, ebml, "TrackEntry");

  /* start with the master */
  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
    DEBUG_ELEMENT_STOP (demux, ebml, "TrackEntry", ret);
    return ret;
  }

417
418
419
  /* allocate generic... if we know the type, we'll g_renew()
   * with the precise type */
  context = g_new0 (GstMatroskaTrackContext, 1);
420
421
  g_ptr_array_add (demux->common.src, context);
  context->index = demux->common.num_streams;
422
  context->index_writer_id = -1;
423
  context->type = 0;            /* no type yet */
424
  context->default_duration = 0;
425
  context->pos = 0;
426
  context->set_discont = TRUE;
427
428
429
430
  context->timecodescale = 1.0;
  context->flags =
      GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT |
      GST_MATROSKA_TRACK_LACING;
431
432
  context->from_time = GST_CLOCK_TIME_NONE;
  context->from_offset = -1;
433
  context->to_offset = G_MAXINT64;
434
  context->alignment = 1;
435
  context->dts_only = FALSE;
436
  context->intra_only = FALSE;
437
  context->tags = gst_tag_list_new_empty ();
438
439
  demux->common.num_streams++;
  g_assert (demux->common.src->len == demux->common.num_streams);
440

441
  GST_DEBUG_OBJECT (demux, "Stream number %d", context->index);
442
443

  /* try reading the trackentry headers */
444
445
  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
446
      break;
447

448
    switch (id) {
449
        /* track number (unique stream ID) */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
450
      case GST_MATROSKA_ID_TRACKNUMBER:{
451
452
        guint64 num;

453
        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
454
          break;
455

456
        if (num == 0) {
457
458
459
          GST_ERROR_OBJECT (demux, "Invalid TrackNumber 0");
          ret = GST_FLOW_ERROR;
          break;
460
461
        } else if (!gst_matroska_read_common_tracknumber_unique (&demux->common,
                num)) {
462
463
          GST_ERROR_OBJECT (demux, "TrackNumber %" G_GUINT64_FORMAT
              " is not unique", num);
464
465
466
467
          ret = GST_FLOW_ERROR;
          break;
        }

468
        GST_DEBUG_OBJECT (demux, "TrackNumber: %" G_GUINT64_FORMAT, num);
469
470
        context->num = num;
        break;
471
      }
472
        /* track UID (unique identifier) */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
473
      case GST_MATROSKA_ID_TRACKUID:{
474
475
        guint64 num;

476
        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
477
          break;
478

479
        if (num == 0) {
480
          GST_ERROR_OBJECT (demux, "Invalid TrackUID 0");
481
482
483
484
          ret = GST_FLOW_ERROR;
          break;
        }

485
        GST_DEBUG_OBJECT (demux, "TrackUID: %" G_GUINT64_FORMAT, num);
486
487
        context->uid = num;
        break;
488
489
      }

490
        /* track type (video, audio, combined, subtitle, etc.) */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
491
      case GST_MATROSKA_ID_TRACKTYPE:{
492
        guint64 track_type;
493

494
        if ((ret = gst_ebml_read_uint (ebml, &id, &track_type)) != GST_FLOW_OK) {
495
496
          break;
        }
497
498

        if (context->type != 0 && context->type != track_type) {
499
500
          GST_WARNING_OBJECT (demux,
              "More than one tracktype defined in a TrackEntry - skipping");
501
          break;
502
        } else if (track_type < 1 || track_type > 254) {
503
504
          GST_WARNING_OBJECT (demux, "Invalid TrackType %" G_GUINT64_FORMAT,
              track_type);
505
          break;
506
507
        }

508
509
        GST_DEBUG_OBJECT (demux, "TrackType: %" G_GUINT64_FORMAT, track_type);

510
        /* ok, so we're actually going to reallocate this thing */
511
        switch (track_type) {
512
          case GST_MATROSKA_TRACK_TYPE_VIDEO:
513
            gst_matroska_track_init_video_context (&context);
514
515
            break;
          case GST_MATROSKA_TRACK_TYPE_AUDIO:
516
            gst_matroska_track_init_audio_context (&context);
517
518
            break;
          case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
519
            gst_matroska_track_init_subtitle_context (&context);
520
            break;
521
          case GST_MATROSKA_TRACK_TYPE_COMPLEX:
522
          case GST_MATROSKA_TRACK_TYPE_LOGO:
523
          case GST_MATROSKA_TRACK_TYPE_BUTTONS:
524
525
          case GST_MATROSKA_TRACK_TYPE_CONTROL:
          default:
526
527
528
            GST_WARNING_OBJECT (demux,
                "Unknown or unsupported TrackType %" G_GUINT64_FORMAT,
                track_type);
529
530
531
            context->type = 0;
            break;
        }
532
533
        g_ptr_array_index (demux->common.src, demux->common.num_streams - 1)
            = context;
534
        break;
535
536
      }

537
        /* tracktype specific stuff for video */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
538
      case GST_MATROSKA_ID_TRACKVIDEO:{
539
540
        GstMatroskaTrackVideoContext *videocontext;

541
542
        DEBUG_ELEMENT_START (demux, ebml, "TrackVideo");

543
        if (!gst_matroska_track_init_video_context (&context)) {
544
545
          GST_WARNING_OBJECT (demux,
              "TrackVideo element in non-video track - ignoring track");
546
          ret = GST_FLOW_ERROR;
547
          break;
548
        } else if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
549
550
551
          break;
        }
        videocontext = (GstMatroskaTrackVideoContext *) context;
552
553
        g_ptr_array_index (demux->common.src, demux->common.num_streams - 1)
            = context;
554

555
556
557
        while (ret == GST_FLOW_OK &&
            gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
          if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
558
559
560
            break;

          switch (id) {
561
              /* Should be one level up but some broken muxers write it here. */
562
563
564
            case GST_MATROSKA_ID_TRACKDEFAULTDURATION:{
              guint64 num;

565
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
566
                break;
567
568

              if (num == 0) {
569
                GST_WARNING_OBJECT (demux, "Invalid TrackDefaultDuration 0");
570
571
572
                break;
              }

573
574
              GST_DEBUG_OBJECT (demux,
                  "TrackDefaultDuration: %" G_GUINT64_FORMAT, num);
575
576
577
578
579
              context->default_duration = num;
              break;
            }

              /* video framerate */
580
581
              /* NOTE: This one is here only for backward compatibility.
               * Use _TRACKDEFAULDURATION one level up. */
582
583
584
            case GST_MATROSKA_ID_VIDEOFRAMERATE:{
              gdouble num;

585
              if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK)
586
                break;
587
588

              if (num <= 0.0) {
589
                GST_WARNING_OBJECT (demux, "Invalid TrackVideoFPS %lf", num);
590
                break;
591
              }
592

593
              GST_DEBUG_OBJECT (demux, "TrackVideoFrameRate: %lf", num);
594
595
596
597
              if (context->default_duration == 0)
                context->default_duration =
                    gst_gdouble_to_guint64 ((gdouble) GST_SECOND * (1.0 / num));
              videocontext->default_fps = num;
598
599
600
601
602
603
604
              break;
            }

              /* width of the size to display the video at */
            case GST_MATROSKA_ID_VIDEODISPLAYWIDTH:{
              guint64 num;

605
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
606
                break;
607
608

              if (num == 0) {
609
                GST_WARNING_OBJECT (demux, "Invalid TrackVideoDisplayWidth 0");
610
611
612
                break;
              }

613
614
              GST_DEBUG_OBJECT (demux,
                  "TrackVideoDisplayWidth: %" G_GUINT64_FORMAT, num);
615
616
617
618
619
620
621
622
              videocontext->display_width = num;
              break;
            }

              /* height of the size to display the video at */
            case GST_MATROSKA_ID_VIDEODISPLAYHEIGHT:{
              guint64 num;

623
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
624
                break;
625
626

              if (num == 0) {
627
                GST_WARNING_OBJECT (demux, "Invalid TrackVideoDisplayHeight 0");
628
629
630
                break;
              }

631
632
              GST_DEBUG_OBJECT (demux,
                  "TrackVideoDisplayHeight: %" G_GUINT64_FORMAT, num);
633
634
635
636
637
638
639
640
              videocontext->display_height = num;
              break;
            }

              /* width of the video in the file */
            case GST_MATROSKA_ID_VIDEOPIXELWIDTH:{
              guint64 num;

641
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
642
                break;
643
644

              if (num == 0) {
645
                GST_WARNING_OBJECT (demux, "Invalid TrackVideoPixelWidth 0");
646
647
648
                break;
              }

649
650
              GST_DEBUG_OBJECT (demux,
                  "TrackVideoPixelWidth: %" G_GUINT64_FORMAT, num);
651
652
653
654
655
656
657
658
              videocontext->pixel_width = num;
              break;
            }

              /* height of the video in the file */
            case GST_MATROSKA_ID_VIDEOPIXELHEIGHT:{
              guint64 num;

659
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
660
                break;
661
662

              if (num == 0) {
663
                GST_WARNING_OBJECT (demux, "Invalid TrackVideoPixelHeight 0");
664
665
666
                break;
              }

667
668
              GST_DEBUG_OBJECT (demux,
                  "TrackVideoPixelHeight: %" G_GUINT64_FORMAT, num);
669
670
671
672
673
674
675
676
              videocontext->pixel_height = num;
              break;
            }

              /* whether the video is interlaced */
            case GST_MATROSKA_ID_VIDEOFLAGINTERLACED:{
              guint64 num;

677
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
678
                break;
679

680
681
682
683
              if (num)
                context->flags |= GST_MATROSKA_VIDEOTRACK_INTERLACED;
              else
                context->flags &= ~GST_MATROSKA_VIDEOTRACK_INTERLACED;
684
              GST_DEBUG_OBJECT (demux, "TrackVideoInterlaced: %d",
685
686
                  (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED) ? 1 :
                  0);
687
688
689
690
              break;
            }

              /* aspect ratio behaviour */
691
            case GST_MATROSKA_ID_VIDEOASPECTRATIOTYPE:{
692
693
              guint64 num;

694
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
695
                break;
696

697
698
699
              if (num != GST_MATROSKA_ASPECT_RATIO_MODE_FREE &&
                  num != GST_MATROSKA_ASPECT_RATIO_MODE_KEEP &&
                  num != GST_MATROSKA_ASPECT_RATIO_MODE_FIXED) {
700
701
                GST_WARNING_OBJECT (demux,
                    "Unknown TrackVideoAspectRatioType 0x%x", (guint) num);
702
703
                break;
              }
704
705
              GST_DEBUG_OBJECT (demux,
                  "TrackVideoAspectRatioType: %" G_GUINT64_FORMAT, num);
706
707
708
709
710
711
              videocontext->asr_mode = num;
              break;
            }

              /* colourspace (only matters for raw video) fourcc */
            case GST_MATROSKA_ID_VIDEOCOLOURSPACE:{
712
713
714
715
716
717
              guint8 *data;
              guint64 datalen;

              if ((ret =
                      gst_ebml_read_binary (ebml, &id, &data,
                          &datalen)) != GST_FLOW_OK)
718
                break;
719

720
              if (datalen != 4) {
721
                g_free (data);
722
723
724
                GST_WARNING_OBJECT (demux,
                    "Invalid TrackVideoColourSpace length %" G_GUINT64_FORMAT,
                    datalen);
725
726
                break;
              }
727
728
729
730
731

              memcpy (&videocontext->fourcc, data, 4);
              GST_DEBUG_OBJECT (demux,
                  "TrackVideoColourSpace: %" GST_FOURCC_FORMAT,
                  GST_FOURCC_ARGS (videocontext->fourcc));
732
              g_free (data);
733
734
              break;
            }
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
            case GST_MATROSKA_ID_VIDEOSTEREOMODE:
            {
              guint64 num;

              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
                break;

              GST_DEBUG_OBJECT (demux, "StereoMode: %" G_GUINT64_FORMAT, num);

              switch (num) {
                case GST_MATROSKA_STEREO_MODE_SBS_RL:
                  videocontext->multiview_flags =
                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
                  /* fall through */
                case GST_MATROSKA_STEREO_MODE_SBS_LR:
                  videocontext->multiview_mode =
                      GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
                  break;
                case GST_MATROSKA_STEREO_MODE_TB_RL:
                  videocontext->multiview_flags =
                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
                  /* fall through */
                case GST_MATROSKA_STEREO_MODE_TB_LR:
                  videocontext->multiview_mode =
                      GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
                  break;
                case GST_MATROSKA_STEREO_MODE_CHECKER_RL:
                  videocontext->multiview_flags =
                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
                  /* fall through */
                case GST_MATROSKA_STEREO_MODE_CHECKER_LR:
                  videocontext->multiview_mode =
                      GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD;
                  break;
                case GST_MATROSKA_STEREO_MODE_FBF_RL:
                  videocontext->multiview_flags =
                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
                  /* fall through */
                case GST_MATROSKA_STEREO_MODE_FBF_LR:
                  videocontext->multiview_mode =
                      GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
                  /* FIXME: In frame-by-frame mode, left/right frame buffers are
                   * laced within one block, and we'll need to apply FIRST_IN_BUNDLE
                   * accordingly. See http://www.matroska.org/technical/specs/index.html#StereoMode */
                  GST_FIXME_OBJECT (demux,
                      "Frame-by-frame stereoscopic mode not fully implemented");
                  break;
              }
              break;
            }
785

786
787
788
789
            default:
              GST_WARNING_OBJECT (demux,
                  "Unknown TrackVideo subelement 0x%x - ignoring", id);
              /* fall through */
790
791
792
793
794
795
            case GST_MATROSKA_ID_VIDEODISPLAYUNIT:
            case GST_MATROSKA_ID_VIDEOPIXELCROPBOTTOM:
            case GST_MATROSKA_ID_VIDEOPIXELCROPTOP:
            case GST_MATROSKA_ID_VIDEOPIXELCROPLEFT:
            case GST_MATROSKA_ID_VIDEOPIXELCROPRIGHT:
            case GST_MATROSKA_ID_VIDEOGAMMAVALUE:
796
              ret = gst_ebml_read_skip (ebml);
797
798
799
              break;
          }
        }
800
801

        DEBUG_ELEMENT_STOP (demux, ebml, "TrackVideo", ret);
802
        break;
803
804
      }

805
        /* tracktype specific stuff for audio */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
806
      case GST_MATROSKA_ID_TRACKAUDIO:{
807
808
        GstMatroskaTrackAudioContext *audiocontext;

809
810
        DEBUG_ELEMENT_START (demux, ebml, "TrackAudio");

811
        if (!gst_matroska_track_init_audio_context (&context)) {
812
813
          GST_WARNING_OBJECT (demux,
              "TrackAudio element in non-audio track - ignoring track");
814
          ret = GST_FLOW_ERROR;
815
816
          break;
        }
817
818
819
820

        if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
          break;

821
        audiocontext = (GstMatroskaTrackAudioContext *) context;
822
823
        g_ptr_array_index (demux->common.src, demux->common.num_streams - 1)
            = context;
824

825
826
827
        while (ret == GST_FLOW_OK &&
            gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
          if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
828
829
830
831
832
833
834
            break;

          switch (id) {
              /* samplerate */
            case GST_MATROSKA_ID_AUDIOSAMPLINGFREQ:{
              gdouble num;

835
              if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK)
836
                break;
837

838
839

              if (num <= 0.0) {
840
841
                GST_WARNING_OBJECT (demux,
                    "Invalid TrackAudioSamplingFrequency %lf", num);
842
843
844
                break;
              }

845
              GST_DEBUG_OBJECT (demux, "TrackAudioSamplingFrequency: %lf", num);
846
847
848
849
850
851
852
853
              audiocontext->samplerate = num;
              break;
            }

              /* bitdepth */
            case GST_MATROSKA_ID_AUDIOBITDEPTH:{
              guint64 num;

854
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
855
                break;
856
857

              if (num == 0) {
858
                GST_WARNING_OBJECT (demux, "Invalid TrackAudioBitDepth 0");
859
860
861
                break;
              }

862
863
              GST_DEBUG_OBJECT (demux, "TrackAudioBitDepth: %" G_GUINT64_FORMAT,
                  num);
864
865
866
867
868
869
870
871
              audiocontext->bitdepth = num;
              break;
            }

              /* channels */
            case GST_MATROSKA_ID_AUDIOCHANNELS:{
              guint64 num;

872
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
873
                break;
874
875

              if (num == 0) {
876
                GST_WARNING_OBJECT (demux, "Invalid TrackAudioChannels 0");
877
878
879
                break;
              }

880
881
              GST_DEBUG_OBJECT (demux, "TrackAudioChannels: %" G_GUINT64_FORMAT,
                  num);
882
883
884
885
              audiocontext->channels = num;
              break;
            }

886
887
888
889
            default:
              GST_WARNING_OBJECT (demux,
                  "Unknown TrackAudio subelement 0x%x - ignoring", id);
              /* fall through */
890
891
            case GST_MATROSKA_ID_AUDIOCHANNELPOSITIONS:
            case GST_MATROSKA_ID_AUDIOOUTPUTSAMPLINGFREQ:
892
              ret = gst_ebml_read_skip (ebml);
893
894
895
              break;
          }
        }
896
897
898

        DEBUG_ELEMENT_STOP (demux, ebml, "TrackAudio", ret);

899
        break;
900
901
      }

902
        /* codec identifier */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
903
      case GST_MATROSKA_ID_CODECID:{
904
905
        gchar *text;

906
        if ((ret = gst_ebml_read_ascii (ebml, &id, &text)) != GST_FLOW_OK)
907
          break;
908
909

        GST_DEBUG_OBJECT (demux, "CodecID: %s", GST_STR_NULL (text));
910
911
        context->codec_id = text;
        break;
912
913
      }

914
        /* codec private data */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
915
      case GST_MATROSKA_ID_CODECPRIVATE:{
916
917
918
        guint8 *data;
        guint64 size;

919
        if ((ret =
920
                gst_ebml_read_binary (ebml, &id, &data, &size)) != GST_FLOW_OK)
921
          break;
922

923
924
        context->codec_priv = data;
        context->codec_priv_size = size;
925
926
927

        GST_DEBUG_OBJECT (demux, "CodecPrivate of size %" G_GUINT64_FORMAT,
            size);
928
        break;
929
930
      }

931
        /* name of the codec */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
932
      case GST_MATROSKA_ID_CODECNAME:{
933
934
        gchar *text;

935
        if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
936
          break;
937
938

        GST_DEBUG_OBJECT (demux, "CodecName: %s", GST_STR_NULL (text));
939
940
        context->codec_name = text;
        break;
941
942
      }

943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967