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


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
#include <gst/base/base.h>

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

René Stadler's avatar
René Stadler committed
64
#include <gst/audio/audio.h>
65
#include <gst/tag/tag.h>
66
#include <gst/pbutils/pbutils.h>
67
#include <gst/video/gstvideocodecalphameta.h>
68
#include <gst/video/video.h>
69

70
#include "gstmatroskaelements.h"
71
72
73
#include "matroska-demux.h"
#include "matroska-ids.h"

74
GST_DEBUG_CATEGORY_STATIC (matroskademux_debug);
75
76
#define GST_CAT_DEFAULT matroskademux_debug

77
78
#define DEBUG_ELEMENT_START(demux, ebml, element) \
    GST_DEBUG_OBJECT (demux, "Parsing " element " element at offset %" \
79
        G_GUINT64_FORMAT, gst_ebml_read_get_pos (ebml))
80
81

#define DEBUG_ELEMENT_STOP(demux, ebml, element, ret) \
82
83
    GST_DEBUG_OBJECT (demux, "Parsing " element " element " \
        " finished with '%s'", gst_flow_get_name (ret))
84

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
85
86
enum
{
87
88
89
  PROP_0,
  PROP_METADATA,
  PROP_STREAMINFO,
90
91
  PROP_MAX_GAP_TIME,
  PROP_MAX_BACKTRACK_DISTANCE
92
93
};

94
95
96
#define DEFAULT_MAX_GAP_TIME           (2 * GST_SECOND)
#define DEFAULT_MAX_BACKTRACK_DISTANCE 30
#define INVALID_DATA_THRESHOLD         (2 * 1024 * 1024)
97

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
98
99
100
static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
101
102
    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
103
    );
104

105
106
/* TODO: fill in caps! */

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

static GstStaticPadTemplate video_src_templ =
Wim Taymans's avatar
Wim Taymans committed
115
GST_STATIC_PAD_TEMPLATE ("video_%u",
116
117
118
119
120
121
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
    GST_STATIC_CAPS ("ANY")
    );

static GstStaticPadTemplate subtitle_src_templ =
Wim Taymans's avatar
Wim Taymans committed
122
    GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
123
124
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
125
    GST_STATIC_CAPS ("text/x-raw, format=pango-markup; application/x-ssa; "
126
        "application/x-ass;application/x-usf; subpicture/x-dvd; "
127
        "subpicture/x-pgs; subtitle/x-kate; " "application/x-subtitle-unknown")
128
129
    );

130
131
static GQuark matroska_block_additional_quark;

132
133
static GstFlowReturn gst_matroska_demux_parse_id (GstMatroskaDemux * demux,
    guint32 id, guint64 length, guint needed);
134

135
/* element functions */
136
137
138
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
139
    GstEvent * event);
140
141
142
static gboolean gst_matroska_demux_element_query (GstElement * element,
    GstQuery * query);

143
/* pad functions */
René Stadler's avatar
René Stadler committed
144
145
146
147
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);
148

149
150
static gboolean gst_matroska_demux_handle_seek_push (GstMatroskaDemux * demux,
    GstPad * pad, GstEvent * event);
151
static gboolean gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
152
    GstPad * pad, GstEvent * event);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
153
static gboolean gst_matroska_demux_handle_src_event (GstPad * pad,
René Stadler's avatar
René Stadler committed
154
    GstObject * parent, GstEvent * event);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
155
static gboolean gst_matroska_demux_handle_src_query (GstPad * pad,
René Stadler's avatar
René Stadler committed
156
    GstObject * parent, GstQuery * query);
157

158
static gboolean gst_matroska_demux_handle_sink_event (GstPad * pad,
René Stadler's avatar
René Stadler committed
159
    GstObject * parent, GstEvent * event);
160
161
static gboolean gst_matroska_demux_handle_sink_query (GstPad * pad,
    GstObject * parent, GstQuery * query);
162
static GstFlowReturn gst_matroska_demux_chain (GstPad * pad,
René Stadler's avatar
René Stadler committed
163
    GstObject * object, GstBuffer * buffer);
164

165
166
167
static GstStateChangeReturn
gst_matroska_demux_change_state (GstElement * element,
    GstStateChange transition);
168
#if 0
169
170
171
static void
gst_matroska_demux_set_index (GstElement * element, GstIndex * index);
static GstIndex *gst_matroska_demux_get_index (GstElement * element);
172
#endif
173
174

/* caps functions */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
175
static GstCaps *gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext
176
177
    * videocontext, const gchar * codec_id, guint8 * data, guint size,
    gchar ** codec_name, guint32 * riff_fourcc);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
178
static GstCaps *gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext
179
    * audiocontext, const gchar * codec_id, guint8 * data, guint size,
180
    gchar ** codec_name, guint16 * riff_audio_fmt, GstClockTime * lead_in_ts);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
181
182
183
static GstCaps
    * gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext *
    subtitlecontext, const gchar * codec_id, gpointer data, guint size);
184
185
186
static const gchar *gst_matroska_track_encryption_algorithm_name (gint val);
static const gchar *gst_matroska_track_encryption_cipher_mode_name (gint val);
static const gchar *gst_matroska_track_encoding_scope_name (gint val);
187
188

/* stream methods */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
189
static void gst_matroska_demux_reset (GstElement * element);
190
static gboolean perform_seek_to_offset (GstMatroskaDemux * demux,
191
    gdouble rate, guint64 offset, guint32 seqnum, GstSeekFlags flags);
192

193
194
195
196
197
198
/* 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);

199
GType gst_matroska_demux_get_type (void);
René Stadler's avatar
René Stadler committed
200
201
#define parent_class gst_matroska_demux_parent_class
G_DEFINE_TYPE (GstMatroskaDemux, gst_matroska_demux, GST_TYPE_ELEMENT);
202
203
204
#define _do_init \
  gst_riff_init (); \
  matroska_element_init (plugin); \
205
206
207
  GST_DEBUG_CATEGORY_INIT (ebmlread_debug, "ebmlread", 0, "EBML stream helper class"); \
  matroska_block_additional_quark = \
      g_quark_from_static_string ("matroska-block-additional");
208
209
210

GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (matroskademux, "matroskademux",
    GST_RANK_PRIMARY, GST_TYPE_MATROSKA_DEMUX, _do_init);
211

212
213
214
215
216
static void
gst_matroska_demux_finalize (GObject * object)
{
  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (object);

217
  gst_matroska_read_common_finalize (&demux->common);
218
  gst_flow_combiner_free (demux->flowcombiner);
219
220
221
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

222
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
223
gst_matroska_demux_class_init (GstMatroskaDemuxClass * klass)
224
{
225
226
  GObjectClass *gobject_class = (GObjectClass *) klass;
  GstElementClass *gstelement_class = (GstElementClass *) klass;
227

228
229
  GST_DEBUG_CATEGORY_INIT (matroskademux_debug, "matroskademux", 0,
      "Matroska demuxer");
230

231
232
  gobject_class->finalize = gst_matroska_demux_finalize;

233
234
235
  gobject_class->get_property = gst_matroska_demux_get_property;
  gobject_class->set_property = gst_matroska_demux_set_property;

236
  g_object_class_install_property (gobject_class, PROP_MAX_GAP_TIME,
237
      g_param_spec_uint64 ("max-gap-time", "Maximum gap time",
René Stadler's avatar
René Stadler committed
238
          "The demuxer sends out segment events for skipping "
239
240
241
          "gaps longer than this (0 = disabled).", 0, G_MAXUINT64,
          DEFAULT_MAX_GAP_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

242
243
244
245
246
247
248
249
250
  g_object_class_install_property (gobject_class, PROP_MAX_BACKTRACK_DISTANCE,
      g_param_spec_uint ("max-backtrack-distance",
          "Maximum backtrack distance",
          "Maximum backtrack distance in seconds when seeking without "
          "and index in pull mode and search for a keyframe "
          "(0 = disable backtracking).",
          0, G_MAXUINT, DEFAULT_MAX_BACKTRACK_DISTANCE,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

251
252
253
254
  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);
255
256
  gstelement_class->query =
      GST_DEBUG_FUNCPTR (gst_matroska_demux_element_query);
257
#if 0
258
259
260
261
  gstelement_class->set_index =
      GST_DEBUG_FUNCPTR (gst_matroska_demux_set_index);
  gstelement_class->get_index =
      GST_DEBUG_FUNCPTR (gst_matroska_demux_get_index);
262
#endif
René Stadler's avatar
René Stadler committed
263

264
265
266
267
268
269
270
  gst_element_class_add_static_pad_template (gstelement_class,
      &video_src_templ);
  gst_element_class_add_static_pad_template (gstelement_class,
      &audio_src_templ);
  gst_element_class_add_static_pad_template (gstelement_class,
      &subtitle_src_templ);
  gst_element_class_add_static_pad_template (gstelement_class, &sink_templ);
René Stadler's avatar
René Stadler committed
271

272
  gst_element_class_set_static_metadata (gstelement_class, "Matroska demuxer",
René Stadler's avatar
René Stadler committed
273
274
      "Codec/Demuxer",
      "Demuxes Matroska/WebM streams into video/audio/subtitles",
275
      "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
276
277
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
278
static void
René Stadler's avatar
René Stadler committed
279
gst_matroska_demux_init (GstMatroskaDemux * demux)
280
{
281
282
283
  demux->common.sinkpad = gst_pad_new_from_static_template (&sink_templ,
      "sink");
  gst_pad_set_activate_function (demux->common.sinkpad,
284
      GST_DEBUG_FUNCPTR (gst_matroska_demux_sink_activate));
René Stadler's avatar
René Stadler committed
285
286
  gst_pad_set_activatemode_function (demux->common.sinkpad,
      GST_DEBUG_FUNCPTR (gst_matroska_demux_sink_activate_mode));
287
  gst_pad_set_chain_function (demux->common.sinkpad,
288
      GST_DEBUG_FUNCPTR (gst_matroska_demux_chain));
289
  gst_pad_set_event_function (demux->common.sinkpad,
290
      GST_DEBUG_FUNCPTR (gst_matroska_demux_handle_sink_event));
291
292
  gst_pad_set_query_function (demux->common.sinkpad,
      GST_DEBUG_FUNCPTR (gst_matroska_demux_handle_sink_query));
293
  gst_element_add_pad (GST_ELEMENT (demux), demux->common.sinkpad);
294

295
296
  /* init defaults for common read context */
  gst_matroska_read_common_init (&demux->common);
297

298
299
  /* property defaults */
  demux->max_gap_time = DEFAULT_MAX_GAP_TIME;
300
  demux->max_backtrack_distance = DEFAULT_MAX_BACKTRACK_DISTANCE;
301

Wim Taymans's avatar
Wim Taymans committed
302
303
  GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);

304
305
  demux->flowcombiner = gst_flow_combiner_new ();

306
307
  /* finish off */
  gst_matroska_demux_reset (GST_ELEMENT (demux));
308
309
}

310
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
311
gst_matroska_demux_reset (GstElement * element)
312
313
314
{
  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);

315
316
  GST_DEBUG_OBJECT (demux, "Resetting state");

317
  gst_matroska_read_common_reset (GST_ELEMENT (demux), &demux->common);
318

319
320
321
  demux->num_a_streams = 0;
  demux->num_t_streams = 0;
  demux->num_v_streams = 0;
322
  demux->have_nonintraonly_v_streams = FALSE;
323

324
325
326
  demux->have_group_id = FALSE;
  demux->group_id = G_MAXUINT;

327
  demux->clock = NULL;
328
  demux->tracks_ebml_offset = G_MAXUINT64;
329

330
  if (demux->clusters) {
331
    g_array_unref (demux->clusters);
332
333
334
    demux->clusters = NULL;
  }

335
  g_list_foreach (demux->seek_parsed,
336
      (GFunc) gst_matroska_read_common_free_parsed_el, NULL);
337
338
339
  g_list_free (demux->seek_parsed);
  demux->seek_parsed = NULL;

340
  demux->last_stop_end = GST_CLOCK_TIME_NONE;
341
  demux->seek_block = 0;
342
  demux->stream_start_time = GST_CLOCK_TIME_NONE;
343
  demux->to_time = GST_CLOCK_TIME_NONE;
344
345
  demux->cluster_time = GST_CLOCK_TIME_NONE;
  demux->cluster_offset = 0;
346
347
  demux->cluster_prevsize = 0;
  demux->seen_cluster_prevsize = FALSE;
348
  demux->next_cluster_offset = 0;
349
350
  demux->stream_last_time = GST_CLOCK_TIME_NONE;
  demux->last_cluster_offset = 0;
351
352
  demux->index_offset = 0;
  demux->seekable = FALSE;
René Stadler's avatar
René Stadler committed
353
  demux->need_segment = FALSE;
354
  demux->upstream_format_is_time = FALSE;
355
  demux->segment_seqnum = 0;
356
357
  demux->requested_seek_time = GST_CLOCK_TIME_NONE;
  demux->seek_offset = -1;
358
  demux->audio_lead_in_ts = 0;
359
360
361
362
363
  demux->building_index = FALSE;
  if (demux->seek_event) {
    gst_event_unref (demux->seek_event);
    demux->seek_event = NULL;
  }
364

365
366
367
  demux->seek_index = NULL;
  demux->seek_entry = 0;

368
369
370
371
  if (demux->new_segment) {
    gst_event_unref (demux->new_segment);
    demux->new_segment = NULL;
  }
372

373
  demux->invalid_duration = FALSE;
374

375
376
  demux->cached_length = G_MAXUINT64;

377
378
379
380
381
  if (demux->deferred_seek_event)
    gst_event_unref (demux->deferred_seek_event);
  demux->deferred_seek_event = NULL;
  demux->deferred_seek_pad = NULL;

382
  gst_flow_combiner_clear (demux->flowcombiner);
383
384
}

385
386
387
static GstBuffer *
gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf)
{
Wim Taymans's avatar
Wim Taymans committed
388
389
390
  GstMapInfo map;
  gpointer data;
  gsize size;
391
  GstBuffer *out_buf = buf;
392
393
394

  g_return_val_if_fail (GST_IS_BUFFER (buf), NULL);

395
396
  GST_DEBUG ("decoding buffer %p", buf);

397
  gst_buffer_map (out_buf, &map, GST_MAP_READ);
Wim Taymans's avatar
Wim Taymans committed
398
399
  data = map.data;
  size = map.size;
René Stadler's avatar
René Stadler committed
400

Wim Taymans's avatar
Wim Taymans committed
401
  g_return_val_if_fail (size > 0, buf);
402
403
404

  if (gst_matroska_decode_data (context->encodings, &data, &size,
          GST_MATROSKA_TRACK_ENCODING_SCOPE_FRAME, FALSE)) {
405
    if (data != map.data) {
406
      gst_buffer_unmap (out_buf, &map);
407
408
      gst_buffer_unref (out_buf);
      out_buf = gst_buffer_new_wrapped (data, size);
409
410
    } else {
      gst_buffer_unmap (out_buf, &map);
411
    }
412
  } else {
413
    GST_DEBUG ("decode data failed");
414
415
    gst_buffer_unmap (out_buf, &map);
    gst_buffer_unref (out_buf);
416
417
    return NULL;
  }
418
419
420
421
422
423
424
425
426
427
428
429
430
  /* Encrypted stream */
  if (context->protection_info) {

    GstStructure *info_protect = gst_structure_copy (context->protection_info);
    gboolean encrypted = FALSE;

    gst_buffer_map (out_buf, &map, GST_MAP_READ);
    data = map.data;
    size = map.size;

    if (gst_matroska_parse_protection_meta (&data, &size, info_protect,
            &encrypted)) {
      if (data != map.data) {
431
432
433
434
435
        GstBuffer *tmp_buf;

        gst_buffer_unmap (out_buf, &map);
        tmp_buf = out_buf;
        out_buf = gst_buffer_copy_region (tmp_buf, GST_BUFFER_COPY_ALL,
436
437
438
439
440
441
442
            gst_buffer_get_size (tmp_buf) - size, size);
        gst_buffer_unref (tmp_buf);
        if (encrypted)
          gst_buffer_add_protection_meta (out_buf, info_protect);
        else
          gst_structure_free (info_protect);
      } else {
443
        gst_buffer_unmap (out_buf, &map);
444
445
446
447
448
449
450
451
452
453
454
455
        gst_structure_free (info_protect);
      }
    } else {
      GST_WARNING ("Adding protection metadata failed");
      gst_buffer_unmap (out_buf, &map);
      gst_buffer_unref (out_buf);
      gst_structure_free (info_protect);
      return NULL;
    }
  }

  return out_buf;
456
457
}

458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
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);
}

483
484
485
486
487
488
489
490
491
static GstFlowReturn
gst_matroska_demux_parse_mastering_metadata (GstMatroskaDemux * demux,
    GstEbmlRead * ebml, GstMatroskaTrackVideoContext * video_context)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstVideoMasteringDisplayInfo minfo;
  guint32 id;
  gdouble num;
  /* Precision defined by HEVC specification */
492
493
  const guint chroma_scale = 50000;
  const guint luma_scale = 10000;
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522

  gst_video_mastering_display_info_init (&minfo);

  DEBUG_ELEMENT_START (demux, ebml, "MasteringMetadata");

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

  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
      goto beach;

    /* all sub elements have float type */
    if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK)
      goto beach;

    /* chromaticity should be in [0, 1] range */
    if (id >= GST_MATROSKA_ID_PRIMARYRCHROMATICITYX &&
        id <= GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY) {
      if (num < 0 || num > 1.0) {
        GST_WARNING_OBJECT (demux, "0x%x has invalid value %f", id, num);
        goto beach;
      }
    } else if (id == GST_MATROSKA_ID_LUMINANCEMAX ||
        id == GST_MATROSKA_ID_LUMINANCEMIN) {
      /* Note: webM spec said valid range is [0, 999.9999] but
       * 1000 cd/m^2 is generally used value on HDR. Just check guint range here.
       * See https://www.webmproject.org/docs/container/#LuminanceMax
       */
523
      if (num < 0 || num > (gdouble) (G_MAXUINT32 / luma_scale)) {
524
525
526
527
528
529
530
        GST_WARNING_OBJECT (demux, "0x%x has invalid value %f", id, num);
        goto beach;
      }
    }

    switch (id) {
      case GST_MATROSKA_ID_PRIMARYRCHROMATICITYX:
531
        minfo.display_primaries[0].x = (guint16) (num * chroma_scale);
532
533
        break;
      case GST_MATROSKA_ID_PRIMARYRCHROMATICITYY:
534
        minfo.display_primaries[0].y = (guint16) (num * chroma_scale);
535
536
        break;
      case GST_MATROSKA_ID_PRIMARYGCHROMATICITYX:
537
        minfo.display_primaries[1].x = (guint16) (num * chroma_scale);
538
539
        break;
      case GST_MATROSKA_ID_PRIMARYGCHROMATICITYY:
540
        minfo.display_primaries[1].y = (guint16) (num * chroma_scale);
541
542
        break;
      case GST_MATROSKA_ID_PRIMARYBCHROMATICITYX:
543
        minfo.display_primaries[2].x = (guint16) (num * chroma_scale);
544
545
        break;
      case GST_MATROSKA_ID_PRIMARYBCHROMATICITYY:
546
        minfo.display_primaries[2].y = (guint16) (num * chroma_scale);
547
548
        break;
      case GST_MATROSKA_ID_WHITEPOINTCHROMATICITYX:
549
        minfo.white_point.x = (guint16) (num * chroma_scale);
550
551
        break;
      case GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY:
552
        minfo.white_point.y = (guint16) (num * chroma_scale);
553
554
        break;
      case GST_MATROSKA_ID_LUMINANCEMAX:
555
        minfo.max_display_mastering_luminance = (guint32) (num * luma_scale);
556
557
        break;
      case GST_MATROSKA_ID_LUMINANCEMIN:
558
        minfo.min_display_mastering_luminance = (guint32) (num * luma_scale);
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
        break;
      default:
        GST_FIXME_OBJECT (demux,
            "Unsupported subelement 0x%x in MasteringMetadata", id);
        ret = gst_ebml_read_skip (ebml);
        break;
    }
  }

  video_context->mastering_display_info = minfo;
  video_context->mastering_display_info_present = TRUE;

beach:
  DEBUG_ELEMENT_STOP (demux, ebml, "MasteringMetadata", ret);

  return ret;
}

577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
static GstFlowReturn
gst_matroska_demux_parse_colour (GstMatroskaDemux * demux, GstEbmlRead * ebml,
    GstMatroskaTrackVideoContext * video_context)
{
  GstFlowReturn ret;
  GstVideoColorimetry colorimetry;
  guint32 id;
  guint64 num;

  colorimetry.range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
  colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
  colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN;
  colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;

  DEBUG_ELEMENT_START (demux, ebml, "TrackVideoColour");

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

  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
      goto beach;

    switch (id) {
      case GST_MATROSKA_ID_VIDEOMATRIXCOEFFICIENTS:{
        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
          goto beach;

605
        colorimetry.matrix = gst_video_color_matrix_from_iso ((guint) num);
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
        break;
      }

      case GST_MATROSKA_ID_VIDEORANGE:{
        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
          goto beach;

        switch (num) {
          case 0:
            colorimetry.range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
            break;
          case 1:
            colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
            break;
          case 2:
            colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
            break;
          default:
            GST_FIXME_OBJECT (demux, "Unsupported color range  %"
                G_GUINT64_FORMAT, num);
            break;
        }
        break;
      }

      case GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS:{
        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
          goto beach;

635
636
        colorimetry.transfer =
            gst_video_transfer_function_from_iso ((guint) num);
637
638
639
640
641
642
643
        break;
      }

      case GST_MATROSKA_ID_VIDEOPRIMARIES:{
        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
          goto beach;

644
645
        colorimetry.primaries =
            gst_video_color_primaries_from_iso ((guint) num);
646
647
648
        break;
      }

649
650
651
652
653
654
655
656
657
658
659
      case GST_MATROSKA_ID_MASTERINGMETADATA:{
        if ((ret =
                gst_matroska_demux_parse_mastering_metadata (demux, ebml,
                    video_context)) != GST_FLOW_OK)
          goto beach;
        break;
      }

      case GST_MATROSKA_ID_MAXCLL:{
        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
          goto beach;
660
        if (num > G_MAXUINT16) {
661
662
663
          GST_WARNING_OBJECT (demux,
              "Too large maxCLL value %" G_GUINT64_FORMAT, num);
        } else {
664
          video_context->content_light_level.max_content_light_level = num;
665
666
667
668
669
670
671
        }
        break;
      }

      case GST_MATROSKA_ID_MAXFALL:{
        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
          goto beach;
672
        if (num >= G_MAXUINT16) {
673
674
675
          GST_WARNING_OBJECT (demux,
              "Too large maxFALL value %" G_GUINT64_FORMAT, num);
        } else {
676
677
          video_context->content_light_level.max_frame_average_light_level =
              num;
678
679
680
681
        }
        break;
      }

682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
      default:
        GST_FIXME_OBJECT (demux, "Unsupported subelement 0x%x in Colour", id);
        ret = gst_ebml_read_skip (ebml);
        break;
    }
  }

  memcpy (&video_context->colorimetry, &colorimetry,
      sizeof (GstVideoColorimetry));

beach:
  DEBUG_ELEMENT_STOP (demux, ebml, "TrackVideoColour", ret);
  return ret;
}

697
static GstFlowReturn
698
699
gst_matroska_demux_parse_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml,
    GstMatroskaTrackContext ** dest_context)
700
701
702
{
  GstMatroskaTrackContext *context;
  GstCaps *caps = NULL;
703
  GstTagList *cached_taglist;
704
  GstFlowReturn ret;
705
706
  guint32 id, riff_fourcc = 0;
  guint16 riff_audio_fmt = 0;
707
  gchar *codec = NULL;
708

709
710
  DEBUG_ELEMENT_START (demux, ebml, "TrackEntry");

711
712
  *dest_context = NULL;

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

719
720
721
  /* allocate generic... if we know the type, we'll g_renew()
   * with the precise type */
  context = g_new0 (GstMatroskaTrackContext, 1);
722
  context->index_writer_id = -1;
723
  context->type = 0;            /* no type yet */
724
  context->default_duration = 0;
725
  context->pos = 0;
726
  context->set_discont = TRUE;
727
728
729
730
  context->timecodescale = 1.0;
  context->flags =
      GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT |
      GST_MATROSKA_TRACK_LACING;
731
732
  context->from_time = GST_CLOCK_TIME_NONE;
  context->from_offset = -1;
733
  context->to_offset = G_MAXINT64;
734
  context->alignment = 1;
735
  context->dts_only = FALSE;
736
  context->intra_only = FALSE;
737
  context->tags = gst_tag_list_new_empty ();
738
739
  g_queue_init (&context->protection_event_queue);
  context->protection_info = NULL;
740

741
742
  GST_DEBUG_OBJECT (demux, "Parsing a TrackEntry (%d tracks parsed so far)",
      demux->common.num_streams);
743
744

  /* try reading the trackentry headers */
745
746
  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
747
      break;
748

749
    switch (id) {
750
        /* track number (unique stream ID) */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
751
      case GST_MATROSKA_ID_TRACKNUMBER:{
752
753
        guint64 num;

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

757
        if (num == 0) {
758
759
760
          GST_ERROR_OBJECT (demux, "Invalid TrackNumber 0");
          ret = GST_FLOW_ERROR;
          break;
761
762
        }

763
        GST_DEBUG_OBJECT (demux, "TrackNumber: %" G_GUINT64_FORMAT, num);
764
765
        context->num = num;
        break;
766
      }
767
        /* track UID (unique identifier) */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
768
      case GST_MATROSKA_ID_TRACKUID:{
769
770
        guint64 num;

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

774
        if (num == 0) {
775
          GST_ERROR_OBJECT (demux, "Invalid TrackUID 0");
776
777
778
779
          ret = GST_FLOW_ERROR;
          break;
        }

780
        GST_DEBUG_OBJECT (demux, "TrackUID: %" G_GUINT64_FORMAT, num);
781
782
        context->uid = num;
        break;
783
784
      }

785
        /* track type (video, audio, combined, subtitle, etc.) */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
786
      case GST_MATROSKA_ID_TRACKTYPE:{
787
        guint64 track_type;
788

789
        if ((ret = gst_ebml_read_uint (ebml, &id, &track_type)) != GST_FLOW_OK) {
790
791
          break;
        }
792
793

        if (context->type != 0 && context->type != track_type) {
794
795
          GST_WARNING_OBJECT (demux,
              "More than one tracktype defined in a TrackEntry - skipping");
796
          break;
797
        } else if (track_type < 1 || track_type > 254) {
798
799
          GST_WARNING_OBJECT (demux, "Invalid TrackType %" G_GUINT64_FORMAT,
              track_type);
800
          break;
801
802
        }

803
804
        GST_DEBUG_OBJECT (demux, "TrackType: %" G_GUINT64_FORMAT, track_type);

805
        /* ok, so we're actually going to reallocate this thing */
806
        switch (track_type) {
807
          case GST_MATROSKA_TRACK_TYPE_VIDEO:
808
            gst_matroska_track_init_video_context (&context);
809
810
            break;
          case GST_MATROSKA_TRACK_TYPE_AUDIO:
811
            gst_matroska_track_init_audio_context (&context);
812
813
            break;
          case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
814
            gst_matroska_track_init_subtitle_context (&context);
815
            break;
816
          case GST_MATROSKA_TRACK_TYPE_COMPLEX:
817
          case GST_MATROSKA_TRACK_TYPE_LOGO:
818
          case GST_MATROSKA_TRACK_TYPE_BUTTONS:
819
820
          case GST_MATROSKA_TRACK_TYPE_CONTROL:
          default:
821
822
823
            GST_WARNING_OBJECT (demux,
                "Unknown or unsupported TrackType %" G_GUINT64_FORMAT,
                track_type);
824
825
826
827
            context->type = 0;
            break;
        }
        break;
828
829
      }

830
        /* tracktype specific stuff for video */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
831
      case GST_MATROSKA_ID_TRACKVIDEO:{
832
833
        GstMatroskaTrackVideoContext *videocontext;

834
835
        DEBUG_ELEMENT_START (demux, ebml, "TrackVideo");

836
        if (!gst_matroska_track_init_video_context (&context)) {
837
838
          GST_WARNING_OBJECT (demux,
              "TrackVideo element in non-video track - ignoring track");
839
          ret = GST_FLOW_ERROR;
840
          break;
841
        } else if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
842
843
844
845
          break;
        }
        videocontext = (GstMatroskaTrackVideoContext *) context;

846
847
848
        while (ret == GST_FLOW_OK &&
            gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
          if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
849
850
851
            break;

          switch (id) {
852
              /* Should be one level up but some broken muxers write it here. */
853
854
855
            case GST_MATROSKA_ID_TRACKDEFAULTDURATION:{
              guint64 num;

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

              if (num == 0) {
860
                GST_WARNING_OBJECT (demux, "Invalid TrackDefaultDuration 0");
861
862
863
                break;
              }

864
865
              GST_DEBUG_OBJECT (demux,
                  "TrackDefaultDuration: %" G_GUINT64_FORMAT, num);
866
867
868
869
870
              context->default_duration = num;
              break;
            }

              /* video framerate */
871
872
              /* NOTE: This one is here only for backward compatibility.
               * Use _TRACKDEFAULDURATION one level up. */
873
874
875
            case GST_MATROSKA_ID_VIDEOFRAMERATE:{
              gdouble num;

876
              if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK)
877
                break;
878
879

              if (num <= 0.0) {
880
                GST_WARNING_OBJECT (demux, "Invalid TrackVideoFPS %lf", num);
881
                break;
882
              }
883

884
              GST_DEBUG_OBJECT (demux, "TrackVideoFrameRate: %lf", num);
885
886
887
888
              if (context->default_duration == 0)
                context->default_duration =
                    gst_gdouble_to_guint64 ((gdouble) GST_SECOND * (1.0 / num));
              videocontext->default_fps = num;
889
890
891
892
893
894
895
              break;
            }

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

896
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
897
                break;
898
899

              if (num == 0) {
900
                GST_WARNING_OBJECT (demux, "Invalid TrackVideoDisplayWidth 0");
901
902
903
                break;
              }

904
905
              GST_DEBUG_OBJECT (demux,
                  "TrackVideoDisplayWidth: %" G_GUINT64_FORMAT, num);
906
907
908
909
910
911
912
913
              videocontext->display_width = num;
              break;
            }

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

914
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
915
                break;
916
917

              if (num == 0) {
918
                GST_WARNING_OBJECT (demux, "Invalid TrackVideoDisplayHeight 0");
919
920
921
                break;
              }

922
923
              GST_DEBUG_OBJECT (demux,
                  "TrackVideoDisplayHeight: %" G_GUINT64_FORMAT, num);
924
925
926
927
928
929
930
931
              videocontext->display_height = num;
              break;
            }

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

932
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
933
                break;
934
935

              if (num == 0) {
936
                GST_WARNING_OBJECT (demux, "Invalid TrackVideoPixelWidth 0");
937
938
939
                break;
              }

940
941
              GST_DEBUG_OBJECT (demux,
                  "TrackVideoPixelWidth: %" G_GUINT64_FORMAT, num);
942
943
944
945
946
947
948
949
              videocontext->pixel_width = num;
              break;
            }

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

950
              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
951
                break;
952
953

              if (num == 0) {
954
                GST_WARNING_OBJECT (demux, "Invalid TrackVideoPixelHeight 0");
955
956
957
                break;
              }

958
959
              GST_DEBUG_OBJECT (demux,
                  "TrackVideoPixelHeight: %" G_GUINT64_FORMAT, num);
960
961
962
963
964
965
966
967
              videocontext->pixel_height = num;
              break;
            }

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

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

971
972
973
974
975
976
              if (num == 1)
                videocontext->interlace_mode =
                    GST_MATROSKA_INTERLACE_MODE_INTERLACED;
              else if (num == 2)
                videocontext->interlace_mode =
                    GST_MATROSKA_INTERLACE_MODE_PROGRESSIVE;
977
              else
978
979
980
981
982
                videocontext->interlace_mode =
                    GST_MATROSKA_INTERLACE_MODE_UNKNOWN;

              GST_DEBUG_OBJECT (demux, "video track interlacing mode: %d",
                  videocontext->interlace_mode);
983
984
985
              break;
            }

986
987
988
989
990
991
992
993
994
995
996
997