1 /* GStreamer Matroska muxer/demuxer
2 * (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 * matroska-read-common.c: shared by matroska file/stream demuxer and parser
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31
32 #ifdef HAVE_ZLIB
33 #include <zlib.h>
34 #endif
35
36 #ifdef HAVE_BZ2
37 #include <bzlib.h>
38 #endif
39
40 #include <gst/tag/tag.h>
41 #include <gst/base/gsttypefindhelper.h>
42 #include <gst/base/gstbytewriter.h>
43
44 #include "lzo.h"
45
46 #include "ebml-read.h"
47 #include "matroska-read-common.h"
48 #include "matroska-ids.h"
49
50 GST_DEBUG_CATEGORY (matroskareadcommon_debug);
51 #define GST_CAT_DEFAULT matroskareadcommon_debug
52
53 #define DEBUG_ELEMENT_START(common, ebml, element) \
54 GST_DEBUG_OBJECT (common->sinkpad, "Parsing " element " element at offset %" \
55 G_GUINT64_FORMAT, gst_ebml_read_get_pos (ebml))
56
57 #define DEBUG_ELEMENT_STOP(common, ebml, element, ret) \
58 GST_DEBUG_OBJECT (common->sinkpad, "Parsing " element " element " \
59 " finished with '%s'", gst_flow_get_name (ret))
60
61 #define GST_MATROSKA_TOC_UID_CHAPTER "chapter"
62 #define GST_MATROSKA_TOC_UID_EDITION "edition"
63 #define GST_MATROSKA_TOC_UID_EMPTY "empty"
64
65 typedef struct
66 {
67 GstTagList *result;
68 guint64 target_type_value;
69 gchar *target_type;
70 gboolean audio_only;
71 } TargetTypeContext;
72
73
74 static gboolean
gst_matroska_decompress_data(GstMatroskaTrackEncoding * enc,gpointer * data_out,gsize * size_out,GstMatroskaTrackCompressionAlgorithm algo)75 gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
76 gpointer * data_out, gsize * size_out,
77 GstMatroskaTrackCompressionAlgorithm algo)
78 {
79 guint8 *new_data = NULL;
80 guint new_size = 0;
81 guint8 *data = *data_out;
82 guint size = *size_out;
83 gboolean ret = TRUE;
84
85 if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_ZLIB) {
86 #ifdef HAVE_ZLIB
87 /* zlib encoded data */
88 z_stream zstream;
89 guint orig_size;
90 int result;
91
92 orig_size = size;
93 zstream.zalloc = (alloc_func) 0;
94 zstream.zfree = (free_func) 0;
95 zstream.opaque = (voidpf) 0;
96 if (inflateInit (&zstream) != Z_OK) {
97 GST_WARNING ("zlib initialization failed.");
98 ret = FALSE;
99 goto out;
100 }
101 zstream.next_in = (Bytef *) data;
102 zstream.avail_in = orig_size;
103 new_size = orig_size;
104 new_data = g_malloc (new_size);
105 zstream.avail_out = new_size;
106 zstream.next_out = (Bytef *) new_data;
107
108 do {
109 result = inflate (&zstream, Z_NO_FLUSH);
110 if (result == Z_STREAM_END) {
111 break;
112 } else if (result != Z_OK) {
113 GST_WARNING ("inflate() returned %d", result);
114 break;
115 }
116
117 new_size += 4096;
118 new_data = g_realloc (new_data, new_size);
119 zstream.next_out = (Bytef *) (new_data + zstream.total_out);
120 zstream.avail_out += 4096;
121 } while (zstream.avail_in > 0);
122
123 if (result != Z_STREAM_END) {
124 ret = FALSE;
125 g_free (new_data);
126 } else {
127 new_size = zstream.total_out;
128 }
129 inflateEnd (&zstream);
130
131 #else
132 GST_WARNING ("zlib encoded tracks not supported.");
133 ret = FALSE;
134 goto out;
135 #endif
136 } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_BZLIB) {
137 #ifdef HAVE_BZ2
138 /* bzip2 encoded data */
139 bz_stream bzstream;
140 guint orig_size;
141 int result;
142
143 bzstream.bzalloc = NULL;
144 bzstream.bzfree = NULL;
145 bzstream.opaque = NULL;
146 orig_size = size;
147
148 if (BZ2_bzDecompressInit (&bzstream, 0, 0) != BZ_OK) {
149 GST_WARNING ("bzip2 initialization failed.");
150 ret = FALSE;
151 goto out;
152 }
153
154 bzstream.next_in = (char *) data;
155 bzstream.avail_in = orig_size;
156 new_size = orig_size;
157 new_data = g_malloc (new_size);
158 bzstream.avail_out = new_size;
159 bzstream.next_out = (char *) new_data;
160
161 do {
162 result = BZ2_bzDecompress (&bzstream);
163 if (result == BZ_STREAM_END) {
164 break;
165 } else if (result != BZ_OK) {
166 GST_WARNING ("BZ2_bzDecompress() returned %d", result);
167 break;
168 }
169
170 new_size += 4096;
171 new_data = g_realloc (new_data, new_size);
172 bzstream.next_out = (char *) (new_data + bzstream.total_out_lo32);
173 bzstream.avail_out += 4096;
174 } while (bzstream.avail_in > 0);
175
176 if (result != BZ_STREAM_END) {
177 ret = FALSE;
178 g_free (new_data);
179 } else {
180 new_size = bzstream.total_out_lo32;
181 }
182 BZ2_bzDecompressEnd (&bzstream);
183
184 #else
185 GST_WARNING ("bzip2 encoded tracks not supported.");
186 ret = FALSE;
187 goto out;
188 #endif
189 } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_LZO1X) {
190 /* lzo encoded data */
191 int result;
192 int orig_size, out_size;
193
194 orig_size = size;
195 out_size = size;
196 new_size = size;
197 new_data = g_malloc (new_size);
198
199 do {
200 orig_size = size;
201 out_size = new_size;
202
203 result = lzo1x_decode (new_data, &out_size, data, &orig_size);
204
205 if (orig_size > 0) {
206 new_size += 4096;
207 new_data = g_realloc (new_data, new_size);
208 }
209 } while (orig_size > 0 && result == LZO_OUTPUT_FULL);
210
211 new_size -= out_size;
212
213 if (result != LZO_OUTPUT_FULL) {
214 GST_WARNING ("lzo decompression failed");
215 g_free (new_data);
216
217 ret = FALSE;
218 goto out;
219 }
220
221 } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_HEADERSTRIP) {
222 /* header stripped encoded data */
223 if (enc->comp_settings_length > 0) {
224 new_data = g_malloc (size + enc->comp_settings_length);
225 new_size = size + enc->comp_settings_length;
226
227 memcpy (new_data, enc->comp_settings, enc->comp_settings_length);
228 memcpy (new_data + enc->comp_settings_length, data, size);
229 }
230 } else {
231 GST_ERROR ("invalid compression algorithm %d", algo);
232 ret = FALSE;
233 }
234
235 out:
236
237 if (!ret) {
238 *data_out = NULL;
239 *size_out = 0;
240 } else {
241 *data_out = new_data;
242 *size_out = new_size;
243 }
244
245 return ret;
246 }
247
248 GstFlowReturn
gst_matroska_decode_content_encodings(GArray * encodings)249 gst_matroska_decode_content_encodings (GArray * encodings)
250 {
251 gint i;
252
253 if (encodings == NULL)
254 return GST_FLOW_OK;
255
256 for (i = 0; i < encodings->len; i++) {
257 GstMatroskaTrackEncoding *enc =
258 &g_array_index (encodings, GstMatroskaTrackEncoding, i);
259 gpointer data = NULL;
260 gsize size;
261
262 if ((enc->scope & GST_MATROSKA_TRACK_ENCODING_SCOPE_NEXT_CONTENT_ENCODING)
263 == 0)
264 continue;
265
266 /* Other than ENCODING_COMPRESSION not handled here */
267 if (enc->type != GST_MATROSKA_ENCODING_COMPRESSION)
268 continue;
269
270 if (i + 1 >= encodings->len)
271 return GST_FLOW_ERROR;
272
273 if (enc->comp_settings_length == 0)
274 continue;
275
276 data = enc->comp_settings;
277 size = enc->comp_settings_length;
278
279 if (!gst_matroska_decompress_data (enc, &data, &size, enc->comp_algo))
280 return GST_FLOW_ERROR;
281
282 g_free (enc->comp_settings);
283
284 enc->comp_settings = data;
285 enc->comp_settings_length = size;
286 }
287
288 return GST_FLOW_OK;
289 }
290
291 gboolean
gst_matroska_decode_data(GArray * encodings,gpointer * data_out,gsize * size_out,GstMatroskaTrackEncodingScope scope,gboolean free)292 gst_matroska_decode_data (GArray * encodings, gpointer * data_out,
293 gsize * size_out, GstMatroskaTrackEncodingScope scope, gboolean free)
294 {
295 gpointer data;
296 gsize size;
297 gboolean ret = TRUE;
298 gint i;
299
300 g_return_val_if_fail (encodings != NULL, FALSE);
301 g_return_val_if_fail (data_out != NULL && *data_out != NULL, FALSE);
302 g_return_val_if_fail (size_out != NULL, FALSE);
303
304 data = *data_out;
305 size = *size_out;
306
307 for (i = 0; i < encodings->len; i++) {
308 GstMatroskaTrackEncoding *enc =
309 &g_array_index (encodings, GstMatroskaTrackEncoding, i);
310 gpointer new_data = NULL;
311 gsize new_size = 0;
312
313 if ((enc->scope & scope) == 0)
314 continue;
315
316 /* Encryption not handled here */
317 if (enc->type != GST_MATROSKA_ENCODING_COMPRESSION) {
318 ret = TRUE;
319 break;
320 }
321
322 new_data = data;
323 new_size = size;
324
325 ret =
326 gst_matroska_decompress_data (enc, &new_data, &new_size,
327 enc->comp_algo);
328
329 if (!ret)
330 break;
331
332 if ((data == *data_out && free) || (data != *data_out))
333 g_free (data);
334
335 data = new_data;
336 size = new_size;
337 }
338
339 if (!ret) {
340 if ((data == *data_out && free) || (data != *data_out))
341 g_free (data);
342
343 *data_out = NULL;
344 *size_out = 0;
345 } else {
346 *data_out = data;
347 *size_out = size;
348 }
349
350 return ret;
351 }
352
353 /* This function parses the protection info of Block/SimpleBlock and extracts the
354 * IV and partitioning format (subsample) information.
355 * Set those parsed information into protection info structure @info_protect which
356 * will be added in protection metadata of the Gstbuffer.
357 * The subsamples format follows the same pssh box format in Common Encryption spec:
358 * subsample number + clear subsample size (16bit bigendian) | encrypted subsample size (32bit bigendian) | ...
359 * @encrypted is an output argument: TRUE if the current Block/SimpleBlock is encrypted else FALSE
360 */
361 gboolean
gst_matroska_parse_protection_meta(gpointer * data_out,gsize * size_out,GstStructure * info_protect,gboolean * encrypted)362 gst_matroska_parse_protection_meta (gpointer * data_out, gsize * size_out,
363 GstStructure * info_protect, gboolean * encrypted)
364 {
365 guint8 *data;
366 GstBuffer *buf_iv;
367 guint8 *data_iv;
368 guint8 *subsamples;
369 guint8 signal_byte;
370 gint i;
371 GstByteReader reader;
372
373 g_return_val_if_fail (data_out != NULL && *data_out != NULL, FALSE);
374 g_return_val_if_fail (size_out != NULL, FALSE);
375 g_return_val_if_fail (info_protect != NULL, FALSE);
376 g_return_val_if_fail (encrypted != NULL, FALSE);
377
378 *encrypted = FALSE;
379 data = *data_out;
380 gst_byte_reader_init (&reader, data, *size_out);
381
382 /* WebM spec:
383 * 4.7 Signal Byte Format
384 * 0 1 2 3 4 5 6 7
385 * +-+-+-+-+-+-+-+-+
386 * |X| RSV |P|E|
387 * +-+-+-+-+-+-+-+-+
388 *
389 * Extension bit (X)
390 * If set, another signal byte will follow this byte. Reserved for future expansion (currently MUST be set to 0).
391 * RSV bits (RSV)
392 * Bits reserved for future use. MUST be set to 0 and MUST be ignored.
393 * Encrypted bit (E)
394 * If set, the Block MUST contain an IV immediately followed by an encrypted frame. If not set, the Block MUST NOT include an IV and the frame MUST be unencrypted. The unencrypted frame MUST immediately follow the Signal Byte.
395 * Partitioned bit (P)
396 * Used to indicate that the sample has subsample partitions. If set, the IV will be followed by a num_partitions byte, and num_partitions * 32-bit partition offsets. This bit can only be set if the E bit is also set.
397 */
398 if (!gst_byte_reader_get_uint8 (&reader, &signal_byte)) {
399 GST_ERROR ("Error reading the signal byte");
400 return FALSE;
401 }
402
403 /* Unencrypted buffer */
404 if (!(signal_byte & GST_MATROSKA_BLOCK_ENCRYPTED)) {
405 return TRUE;
406 }
407
408 /* Encrypted buffer */
409 *encrypted = TRUE;
410 /* Create IV buffer */
411 if (!gst_byte_reader_dup_data (&reader, sizeof (guint64), &data_iv)) {
412 GST_ERROR ("Error reading the IV data");
413 return FALSE;
414 }
415 buf_iv = gst_buffer_new_wrapped ((gpointer) data_iv, sizeof (guint64));
416 gst_structure_set (info_protect, "iv", GST_TYPE_BUFFER, buf_iv, NULL);
417 gst_buffer_unref (buf_iv);
418
419 /* Partitioned in subsample */
420 if (signal_byte & GST_MATROSKA_BLOCK_PARTITIONED) {
421 guint nb_subsample;
422 guint32 offset = 0;
423 guint32 offset_prev;
424 guint32 encrypted_bytes = 0;
425 guint16 clear_bytes = 0;
426 GstBuffer *buf_sub_sample;
427 guint8 nb_part;
428 GstByteWriter writer;
429
430 /* Read the number of partitions (1 byte) */
431 if (!gst_byte_reader_get_uint8 (&reader, &nb_part)) {
432 GST_ERROR ("Error reading the partition number");
433 return FALSE;
434 }
435
436 if (nb_part == 0) {
437 GST_ERROR ("Partitioned, but the subsample number equal to zero");
438 return FALSE;
439 }
440
441 nb_subsample = (nb_part + 2) >> 1;
442
443 gst_structure_set (info_protect, "subsample_count", G_TYPE_UINT,
444 nb_subsample, NULL);
445
446 /* WebM Spec:
447 *
448 * 4.6 Subsample Encrypted Block Format
449 *
450 * The Subsample Encrypted Block format extends the Full-sample format by setting a "partitioned" (P) bit in the Signal Byte.
451 * If this bit is set, the EncryptedBlock header shall include an
452 * 8-bit integer indicating the number of sample partitions (dividers between clear/encrypted sections),
453 * and a series of 32-bit integers in big-endian encoding indicating the byte offsets of such partitions.
454 *
455 * 0 1 2 3
456 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
457 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
458 * | Signal Byte | |
459 * +-+-+-+-+-+-+-+-+ IV |
460 * | |
461 * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
462 * | | num_partition | Partition 0 offset -> |
463 * |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
464 * | -> Partition 0 offset | ... |
465 * |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
466 * | ... | Partition n-1 offset -> |
467 * |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
468 * | -> Partition n-1 offset | |
469 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
470 * | Clear/encrypted sample data |
471 * | |
472 * | |
473 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
474 *
475 * 4.6.1 SAMPLE PARTITIONS
476 *
477 * The samples shall be partitioned into alternating clear and encrypted sections,
478 * always starting with a clear section.
479 * Generally for n clear/encrypted sections there shall be n-1 partition offsets.
480 * However, if it is required that the first section be encrypted, then the first partition shall be at byte offset 0
481 * (indicating a zero-size clear section), and there shall be n partition offsets.
482 * Please refer to the "Sample Encryption" description of the "Common Encryption"
483 * section of the VP Codec ISO Media File Format Binding Specification for more
484 * detail on how subsample encryption is implemented.
485 */
486 subsamples =
487 g_malloc (nb_subsample * (sizeof (guint16) + sizeof (guint32)));
488
489 gst_byte_writer_init_with_data (&writer, subsamples,
490 nb_subsample * (sizeof (guint16) + sizeof (guint32)), FALSE);
491
492 for (i = 0; i <= nb_part; i++) {
493 offset_prev = offset;
494 if (i == nb_part) {
495 offset = gst_byte_reader_get_remaining (&reader);
496 } else {
497 if (!gst_byte_reader_get_uint32_be (&reader, &offset)) {
498 GST_ERROR ("Error reading the partition offset");
499 goto release_err;
500 }
501 }
502
503 if (offset < offset_prev) {
504 GST_ERROR ("Partition offsets should not decrease");
505 goto release_err;
506 }
507
508 if (i % 2 == 0) {
509 if ((offset - offset_prev) & 0xFFFF0000) {
510 GST_ERROR
511 ("The Clear Partition exceed 64KB in encrypted subsample format");
512 goto release_err;
513 }
514 /* We set the Clear partition size in 16 bits, in order to
515 * follow the same format of the box PSSH in CENC spec */
516 clear_bytes = offset - offset_prev;
517 if (i == nb_part)
518 encrypted_bytes = 0;
519 } else {
520 encrypted_bytes = offset - offset_prev;
521 }
522
523 if ((i % 2 == 1) || (i == nb_part)) {
524 if (clear_bytes == 0 && encrypted_bytes == 0) {
525 GST_ERROR ("Found 2 partitions with the same offsets.");
526 goto release_err;
527 }
528 if (!gst_byte_writer_put_uint16_be (&writer, clear_bytes)) {
529 GST_ERROR ("Error writing the number of clear bytes");
530 goto release_err;
531 }
532 if (!gst_byte_writer_put_uint32_be (&writer, encrypted_bytes)) {
533 GST_ERROR ("Error writing the number of encrypted bytes");
534 goto release_err;
535 }
536 }
537 }
538
539 buf_sub_sample =
540 gst_buffer_new_wrapped (subsamples,
541 nb_subsample * (sizeof (guint16) + sizeof (guint32)));
542 gst_structure_set (info_protect, "subsamples", GST_TYPE_BUFFER,
543 buf_sub_sample, NULL);
544 gst_buffer_unref (buf_sub_sample);
545 } else {
546 gst_structure_set (info_protect, "subsample_count", G_TYPE_UINT, 0, NULL);
547 }
548
549 gst_byte_reader_get_data (&reader, 0, (const guint8 **) data_out);
550 *size_out = gst_byte_reader_get_remaining (&reader);
551 return TRUE;
552
553 release_err:
554 g_free (subsamples);
555 return FALSE;
556 }
557
558 static gint
gst_matroska_index_compare(GstMatroskaIndex * i1,GstMatroskaIndex * i2)559 gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2)
560 {
561 if (i1->time < i2->time)
562 return -1;
563 else if (i1->time > i2->time)
564 return 1;
565 else if (i1->block < i2->block)
566 return -1;
567 else if (i1->block > i2->block)
568 return 1;
569 else
570 return 0;
571 }
572
573 gint
gst_matroska_index_seek_find(GstMatroskaIndex * i1,GstClockTime * time,gpointer user_data)574 gst_matroska_index_seek_find (GstMatroskaIndex * i1, GstClockTime * time,
575 gpointer user_data)
576 {
577 if (i1->time < *time)
578 return -1;
579 else if (i1->time > *time)
580 return 1;
581 else
582 return 0;
583 }
584
585 GstMatroskaIndex *
gst_matroska_read_common_do_index_seek(GstMatroskaReadCommon * common,GstMatroskaTrackContext * track,gint64 seek_pos,GArray ** _index,gint * _entry_index,GstSearchMode snap_dir)586 gst_matroska_read_common_do_index_seek (GstMatroskaReadCommon * common,
587 GstMatroskaTrackContext * track, gint64 seek_pos, GArray ** _index,
588 gint * _entry_index, GstSearchMode snap_dir)
589 {
590 GstMatroskaIndex *entry = NULL;
591 GArray *index;
592
593 /* find entry just before or at the requested position */
594 if (track && track->index_table)
595 index = track->index_table;
596 else
597 index = common->index;
598
599 if (!index || !index->len)
600 return NULL;
601
602 entry =
603 gst_util_array_binary_search (index->data, index->len,
604 sizeof (GstMatroskaIndex),
605 (GCompareDataFunc) gst_matroska_index_seek_find, snap_dir, &seek_pos,
606 NULL);
607
608 if (entry == NULL) {
609 if (snap_dir == GST_SEARCH_MODE_AFTER) {
610 /* Can only happen with a reverse seek past the end */
611 entry = &g_array_index (index, GstMatroskaIndex, index->len - 1);
612 } else {
613 /* Can only happen with a forward seek before the start */
614 entry = &g_array_index (index, GstMatroskaIndex, 0);
615 }
616 }
617
618 if (_index)
619 *_index = index;
620 if (_entry_index)
621 *_entry_index = entry - (GstMatroskaIndex *) index->data;
622
623 return entry;
624 }
625
626 static gint
gst_matroska_read_common_encoding_cmp(GstMatroskaTrackEncoding * a,GstMatroskaTrackEncoding * b)627 gst_matroska_read_common_encoding_cmp (GstMatroskaTrackEncoding * a,
628 GstMatroskaTrackEncoding * b)
629 {
630 if (b->order > a->order)
631 return 1;
632 else if (b->order < a->order)
633 return -1;
634 else
635 return 0;
636 }
637
638 static gboolean
gst_matroska_read_common_encoding_order_unique(GArray * encodings,guint64 order)639 gst_matroska_read_common_encoding_order_unique (GArray * encodings, guint64
640 order)
641 {
642 gint i;
643
644 if (encodings == NULL || encodings->len == 0)
645 return TRUE;
646
647 for (i = 0; i < encodings->len; i++)
648 if (g_array_index (encodings, GstMatroskaTrackEncoding, i).order == order)
649 return FALSE;
650
651 return TRUE;
652 }
653
654 /* takes ownership of taglist */
655 void
gst_matroska_read_common_found_global_tag(GstMatroskaReadCommon * common,GstElement * el,GstTagList * taglist)656 gst_matroska_read_common_found_global_tag (GstMatroskaReadCommon * common,
657 GstElement * el, GstTagList * taglist)
658 {
659 if (common->global_tags) {
660 gst_tag_list_insert (common->global_tags, taglist, GST_TAG_MERGE_APPEND);
661 gst_tag_list_unref (taglist);
662 } else {
663 common->global_tags = taglist;
664 }
665 common->global_tags_changed = TRUE;
666 }
667
668 gint64
gst_matroska_read_common_get_length(GstMatroskaReadCommon * common)669 gst_matroska_read_common_get_length (GstMatroskaReadCommon * common)
670 {
671 gint64 end = -1;
672
673 if (!gst_pad_peer_query_duration (common->sinkpad, GST_FORMAT_BYTES,
674 &end) || end < 0)
675 GST_DEBUG_OBJECT (common->sinkpad, "no upstream length");
676
677 return end;
678 }
679
680 /* determine track to seek in */
681 GstMatroskaTrackContext *
gst_matroska_read_common_get_seek_track(GstMatroskaReadCommon * common,GstMatroskaTrackContext * track)682 gst_matroska_read_common_get_seek_track (GstMatroskaReadCommon * common,
683 GstMatroskaTrackContext * track)
684 {
685 gint i;
686
687 if (track && track->type == GST_MATROSKA_TRACK_TYPE_VIDEO)
688 return track;
689
690 for (i = 0; i < common->src->len; i++) {
691 GstMatroskaTrackContext *stream;
692
693 stream = g_ptr_array_index (common->src, i);
694 if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO && stream->index_table)
695 track = stream;
696 }
697
698 return track;
699 }
700
701 /* skip unknown or alike element */
702 GstFlowReturn
gst_matroska_read_common_parse_skip(GstMatroskaReadCommon * common,GstEbmlRead * ebml,const gchar * parent_name,guint id)703 gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * common,
704 GstEbmlRead * ebml, const gchar * parent_name, guint id)
705 {
706 if (id == GST_EBML_ID_VOID) {
707 GST_DEBUG_OBJECT (common->sinkpad, "Skipping EBML Void element");
708 } else if (id == GST_EBML_ID_CRC32) {
709 GST_DEBUG_OBJECT (common->sinkpad, "Skipping EBML CRC32 element");
710 } else {
711 GST_WARNING_OBJECT (common->sinkpad,
712 "Unknown %s subelement 0x%x - ignoring", parent_name, id);
713 }
714
715 return gst_ebml_read_skip (ebml);
716 }
717
718 static GstFlowReturn
gst_matroska_read_common_parse_attached_file(GstMatroskaReadCommon * common,GstEbmlRead * ebml,GstTagList * taglist)719 gst_matroska_read_common_parse_attached_file (GstMatroskaReadCommon * common,
720 GstEbmlRead * ebml, GstTagList * taglist)
721 {
722 guint32 id;
723 GstFlowReturn ret;
724 gchar *description = NULL;
725 gchar *filename = NULL;
726 gchar *mimetype = NULL;
727 guint8 *data = NULL;
728 guint64 datalen = 0;
729
730 DEBUG_ELEMENT_START (common, ebml, "AttachedFile");
731
732 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
733 DEBUG_ELEMENT_STOP (common, ebml, "AttachedFile", ret);
734 return ret;
735 }
736
737 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
738 /* read all sub-entries */
739
740 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
741 break;
742
743 switch (id) {
744 case GST_MATROSKA_ID_FILEDESCRIPTION:
745 if (description) {
746 GST_WARNING_OBJECT (common->sinkpad,
747 "FileDescription can only appear once");
748 break;
749 }
750
751 ret = gst_ebml_read_utf8 (ebml, &id, &description);
752 GST_DEBUG_OBJECT (common->sinkpad, "FileDescription: %s",
753 GST_STR_NULL (description));
754 break;
755 case GST_MATROSKA_ID_FILENAME:
756 if (filename) {
757 GST_WARNING_OBJECT (common->sinkpad, "FileName can only appear once");
758 break;
759 }
760
761 ret = gst_ebml_read_utf8 (ebml, &id, &filename);
762
763 GST_DEBUG_OBJECT (common->sinkpad, "FileName: %s",
764 GST_STR_NULL (filename));
765 break;
766 case GST_MATROSKA_ID_FILEMIMETYPE:
767 if (mimetype) {
768 GST_WARNING_OBJECT (common->sinkpad,
769 "FileMimeType can only appear once");
770 break;
771 }
772
773 ret = gst_ebml_read_ascii (ebml, &id, &mimetype);
774 GST_DEBUG_OBJECT (common->sinkpad, "FileMimeType: %s",
775 GST_STR_NULL (mimetype));
776 break;
777 case GST_MATROSKA_ID_FILEDATA:
778 if (data) {
779 GST_WARNING_OBJECT (common->sinkpad, "FileData can only appear once");
780 break;
781 }
782
783 ret = gst_ebml_read_binary (ebml, &id, &data, &datalen);
784 GST_DEBUG_OBJECT (common->sinkpad,
785 "FileData of size %" G_GUINT64_FORMAT, datalen);
786 break;
787
788 default:
789 ret = gst_matroska_read_common_parse_skip (common, ebml,
790 "AttachedFile", id);
791 break;
792 case GST_MATROSKA_ID_FILEUID:
793 ret = gst_ebml_read_skip (ebml);
794 break;
795 }
796 }
797
798 DEBUG_ELEMENT_STOP (common, ebml, "AttachedFile", ret);
799
800 if (filename && mimetype && data && datalen > 0) {
801 GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
802 GstBuffer *tagbuffer = NULL;
803 GstSample *tagsample = NULL;
804 GstStructure *info = NULL;
805 GstCaps *caps = NULL;
806 gchar *filename_lc = g_utf8_strdown (filename, -1);
807
808 GST_DEBUG_OBJECT (common->sinkpad, "Creating tag for attachment with "
809 "filename '%s', mimetype '%s', description '%s', "
810 "size %" G_GUINT64_FORMAT, filename, mimetype,
811 GST_STR_NULL (description), datalen);
812
813 /* TODO: better heuristics for different image types */
814 if (strstr (filename_lc, "cover")) {
815 if (strstr (filename_lc, "back"))
816 image_type = GST_TAG_IMAGE_TYPE_BACK_COVER;
817 else
818 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
819 } else if (g_str_has_prefix (mimetype, "image/") ||
820 g_str_has_suffix (filename_lc, "png") ||
821 g_str_has_suffix (filename_lc, "jpg") ||
822 g_str_has_suffix (filename_lc, "jpeg") ||
823 g_str_has_suffix (filename_lc, "gif") ||
824 g_str_has_suffix (filename_lc, "bmp")) {
825 image_type = GST_TAG_IMAGE_TYPE_UNDEFINED;
826 }
827 g_free (filename_lc);
828
829 /* First try to create an image tag buffer from this */
830 if (image_type != GST_TAG_IMAGE_TYPE_NONE) {
831 tagsample =
832 gst_tag_image_data_to_image_sample (data, datalen, image_type);
833
834 if (!tagsample) {
835 image_type = GST_TAG_IMAGE_TYPE_NONE;
836 } else {
837 tagbuffer = gst_buffer_ref (gst_sample_get_buffer (tagsample));
838 caps = gst_caps_ref (gst_sample_get_caps (tagsample));
839 info = gst_structure_copy (gst_sample_get_info (tagsample));
840 gst_sample_unref (tagsample);
841 }
842 }
843
844 /* if this failed create an attachment buffer */
845 if (!tagbuffer) {
846 tagbuffer = gst_buffer_new_wrapped (g_memdup (data, datalen), datalen);
847
848 caps = gst_type_find_helper_for_buffer (NULL, tagbuffer, NULL);
849 if (caps == NULL)
850 caps = gst_caps_new_empty_simple (mimetype);
851 }
852
853 /* Set filename and description in the info */
854 if (info == NULL)
855 info = gst_structure_new_empty ("GstTagImageInfo");
856
857 gst_structure_set (info, "filename", G_TYPE_STRING, filename, NULL);
858 if (description)
859 gst_structure_set (info, "description", G_TYPE_STRING, description, NULL);
860
861 tagsample = gst_sample_new (tagbuffer, caps, NULL, info);
862
863 gst_buffer_unref (tagbuffer);
864 gst_caps_unref (caps);
865
866 GST_DEBUG_OBJECT (common->sinkpad,
867 "Created attachment sample: %" GST_PTR_FORMAT, tagsample);
868
869 /* and append to the tag list */
870 if (image_type != GST_TAG_IMAGE_TYPE_NONE)
871 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_IMAGE, tagsample,
872 NULL);
873 else
874 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_ATTACHMENT,
875 tagsample, NULL);
876
877 /* the list adds it own ref */
878 gst_sample_unref (tagsample);
879 }
880
881 g_free (filename);
882 g_free (mimetype);
883 g_free (data);
884 g_free (description);
885
886 return ret;
887 }
888
889 GstFlowReturn
gst_matroska_read_common_parse_attachments(GstMatroskaReadCommon * common,GstElement * el,GstEbmlRead * ebml)890 gst_matroska_read_common_parse_attachments (GstMatroskaReadCommon * common,
891 GstElement * el, GstEbmlRead * ebml)
892 {
893 guint32 id;
894 GstFlowReturn ret = GST_FLOW_OK;
895 GstTagList *taglist;
896
897 DEBUG_ELEMENT_START (common, ebml, "Attachments");
898
899 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
900 DEBUG_ELEMENT_STOP (common, ebml, "Attachments", ret);
901 return ret;
902 }
903
904 taglist = gst_tag_list_new_empty ();
905 gst_tag_list_set_scope (taglist, GST_TAG_SCOPE_GLOBAL);
906
907 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
908 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
909 break;
910
911 switch (id) {
912 case GST_MATROSKA_ID_ATTACHEDFILE:
913 ret = gst_matroska_read_common_parse_attached_file (common, ebml,
914 taglist);
915 break;
916
917 default:
918 ret = gst_matroska_read_common_parse_skip (common, ebml,
919 "Attachments", id);
920 break;
921 }
922 }
923 DEBUG_ELEMENT_STOP (common, ebml, "Attachments", ret);
924
925 if (gst_tag_list_n_tags (taglist) > 0) {
926 GST_DEBUG_OBJECT (common->sinkpad, "Storing attachment tags");
927 gst_matroska_read_common_found_global_tag (common, el, taglist);
928 } else {
929 GST_DEBUG_OBJECT (common->sinkpad, "No valid attachments found");
930 gst_tag_list_unref (taglist);
931 }
932
933 common->attachments_parsed = TRUE;
934
935 return ret;
936 }
937
938 static void
gst_matroska_read_common_parse_toc_tag(GstTocEntry * entry,GstTocEntry * internal_entry,GArray * edition_targets,GArray * chapter_targets,GstTagList * tags)939 gst_matroska_read_common_parse_toc_tag (GstTocEntry * entry,
940 GstTocEntry * internal_entry, GArray * edition_targets,
941 GArray * chapter_targets, GstTagList * tags)
942 {
943 gchar *uid;
944 guint i;
945 guint64 tgt;
946 GArray *targets;
947 GList *cur, *internal_cur;
948 GstTagList *etags;
949
950 targets =
951 (gst_toc_entry_get_entry_type (entry) ==
952 GST_TOC_ENTRY_TYPE_EDITION) ? edition_targets : chapter_targets;
953
954 etags = gst_tag_list_new_empty ();
955
956 for (i = 0; i < targets->len; ++i) {
957 tgt = g_array_index (targets, guint64, i);
958
959 if (tgt == 0)
960 gst_tag_list_insert (etags, tags, GST_TAG_MERGE_APPEND);
961 else {
962 uid = g_strdup_printf ("%" G_GUINT64_FORMAT, tgt);
963 if (g_strcmp0 (gst_toc_entry_get_uid (internal_entry), uid) == 0)
964 gst_tag_list_insert (etags, tags, GST_TAG_MERGE_APPEND);
965 g_free (uid);
966 }
967 }
968
969 gst_toc_entry_merge_tags (entry, etags, GST_TAG_MERGE_APPEND);
970 gst_tag_list_unref (etags);
971
972 cur = gst_toc_entry_get_sub_entries (entry);
973 internal_cur = gst_toc_entry_get_sub_entries (internal_entry);
974 while (cur != NULL && internal_cur != NULL) {
975 gst_matroska_read_common_parse_toc_tag (cur->data, internal_cur->data,
976 edition_targets, chapter_targets, tags);
977 cur = cur->next;
978 internal_cur = internal_cur->next;
979 }
980 }
981
982 static GstFlowReturn
gst_matroska_read_common_parse_metadata_targets(GstMatroskaReadCommon * common,GstEbmlRead * ebml,GArray * edition_targets,GArray * chapter_targets,GArray * track_targets,guint64 * target_type_value,gchar ** target_type)983 gst_matroska_read_common_parse_metadata_targets (GstMatroskaReadCommon * common,
984 GstEbmlRead * ebml, GArray * edition_targets, GArray * chapter_targets,
985 GArray * track_targets, guint64 * target_type_value, gchar ** target_type)
986 {
987 GstFlowReturn ret = GST_FLOW_OK;
988 guint32 id;
989 guint64 uid;
990 guint64 tmp;
991 gchar *str;
992
993 DEBUG_ELEMENT_START (common, ebml, "TagTargets");
994
995 *target_type_value = 50;
996 *target_type = NULL;
997
998 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
999 DEBUG_ELEMENT_STOP (common, ebml, "TagTargets", ret);
1000 return ret;
1001 }
1002
1003 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
1004 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
1005 break;
1006
1007 switch (id) {
1008 case GST_MATROSKA_ID_TARGETCHAPTERUID:
1009 if ((ret = gst_ebml_read_uint (ebml, &id, &uid)) == GST_FLOW_OK)
1010 g_array_append_val (chapter_targets, uid);
1011 break;
1012
1013 case GST_MATROSKA_ID_TARGETEDITIONUID:
1014 if ((ret = gst_ebml_read_uint (ebml, &id, &uid)) == GST_FLOW_OK)
1015 g_array_append_val (edition_targets, uid);
1016 break;
1017
1018 case GST_MATROSKA_ID_TARGETTRACKUID:
1019 if ((ret = gst_ebml_read_uint (ebml, &id, &uid)) == GST_FLOW_OK)
1020 g_array_append_val (track_targets, uid);
1021 break;
1022
1023 case GST_MATROSKA_ID_TARGETTYPEVALUE:
1024 if ((ret = gst_ebml_read_uint (ebml, &id, &tmp)) == GST_FLOW_OK)
1025 *target_type_value = tmp;
1026 break;
1027
1028 case GST_MATROSKA_ID_TARGETTYPE:
1029 if ((ret = gst_ebml_read_ascii (ebml, &id, &str)) == GST_FLOW_OK) {
1030 g_free (*target_type);
1031 *target_type = str;
1032 }
1033 break;
1034
1035 default:
1036 ret =
1037 gst_matroska_read_common_parse_skip (common, ebml, "TagTargets",
1038 id);
1039 break;
1040 }
1041 }
1042
1043 DEBUG_ELEMENT_STOP (common, ebml, "TagTargets", ret);
1044
1045 return ret;
1046 }
1047
1048 static void
gst_matroska_read_common_postprocess_toc_entries(GList * toc_entries,guint64 max,const gchar * parent_uid)1049 gst_matroska_read_common_postprocess_toc_entries (GList * toc_entries,
1050 guint64 max, const gchar * parent_uid)
1051 {
1052 GstTocEntry *cur_info, *prev_info, *next_info;
1053 GList *cur_list, *prev_list, *next_list;
1054 gint64 cur_start, prev_start, stop;
1055
1056 cur_list = toc_entries;
1057 while (cur_list != NULL) {
1058 cur_info = cur_list->data;
1059
1060 switch (gst_toc_entry_get_entry_type (cur_info)) {
1061 case GST_TOC_ENTRY_TYPE_ANGLE:
1062 case GST_TOC_ENTRY_TYPE_VERSION:
1063 case GST_TOC_ENTRY_TYPE_EDITION:
1064 /* in Matroska terms edition has duration of full track */
1065 gst_toc_entry_set_start_stop_times (cur_info, 0, max);
1066
1067 gst_matroska_read_common_postprocess_toc_entries
1068 (gst_toc_entry_get_sub_entries (cur_info), max,
1069 gst_toc_entry_get_uid (cur_info));
1070 break;
1071
1072 case GST_TOC_ENTRY_TYPE_TITLE:
1073 case GST_TOC_ENTRY_TYPE_TRACK:
1074 case GST_TOC_ENTRY_TYPE_CHAPTER:
1075 prev_list = cur_list->prev;
1076 next_list = cur_list->next;
1077
1078 if (prev_list != NULL)
1079 prev_info = prev_list->data;
1080 else
1081 prev_info = NULL;
1082
1083 if (next_list != NULL)
1084 next_info = next_list->data;
1085 else
1086 next_info = NULL;
1087
1088 /* updated stop time in previous chapter and it's subchapters */
1089 if (prev_info != NULL) {
1090 gst_toc_entry_get_start_stop_times (prev_info, &prev_start, &stop);
1091 gst_toc_entry_get_start_stop_times (cur_info, &cur_start, &stop);
1092
1093 stop = cur_start;
1094 gst_toc_entry_set_start_stop_times (prev_info, prev_start, stop);
1095
1096 gst_matroska_read_common_postprocess_toc_entries
1097 (gst_toc_entry_get_sub_entries (prev_info), cur_start,
1098 gst_toc_entry_get_uid (prev_info));
1099 }
1100
1101 /* updated stop time in current chapter and it's subchapters */
1102 if (next_info == NULL) {
1103 gst_toc_entry_get_start_stop_times (cur_info, &cur_start, &stop);
1104
1105 if (stop == -1) {
1106 stop = max;
1107 gst_toc_entry_set_start_stop_times (cur_info, cur_start, stop);
1108 }
1109
1110 gst_matroska_read_common_postprocess_toc_entries
1111 (gst_toc_entry_get_sub_entries (cur_info), stop,
1112 gst_toc_entry_get_uid (cur_info));
1113 }
1114 break;
1115 case GST_TOC_ENTRY_TYPE_INVALID:
1116 break;
1117 }
1118 cur_list = cur_list->next;
1119 }
1120 }
1121
1122 static GstFlowReturn
gst_matroska_read_common_parse_chapter_titles(GstMatroskaReadCommon * common,GstEbmlRead * ebml,GstTagList * titles)1123 gst_matroska_read_common_parse_chapter_titles (GstMatroskaReadCommon * common,
1124 GstEbmlRead * ebml, GstTagList * titles)
1125 {
1126 guint32 id;
1127 gchar *title = NULL;
1128 GstFlowReturn ret = GST_FLOW_OK;
1129
1130 DEBUG_ELEMENT_START (common, ebml, "ChaptersTitles");
1131
1132
1133 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
1134 DEBUG_ELEMENT_STOP (common, ebml, "ChaptersTitles", ret);
1135 return ret;
1136 }
1137
1138 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
1139 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
1140 break;
1141
1142 switch (id) {
1143 case GST_MATROSKA_ID_CHAPSTRING:
1144 ret = gst_ebml_read_utf8 (ebml, &id, &title);
1145 break;
1146
1147 default:
1148 ret =
1149 gst_matroska_read_common_parse_skip (common, ebml, "ChaptersTitles",
1150 id);
1151 break;
1152 }
1153 }
1154
1155 DEBUG_ELEMENT_STOP (common, ebml, "ChaptersTitles", ret);
1156
1157 if (title != NULL && ret == GST_FLOW_OK)
1158 gst_tag_list_add (titles, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, title, NULL);
1159
1160 g_free (title);
1161 return ret;
1162 }
1163
1164 static GstFlowReturn
gst_matroska_read_common_parse_chapter_element(GstMatroskaReadCommon * common,GstEbmlRead * ebml,GList ** subentries,GList ** internal_subentries)1165 gst_matroska_read_common_parse_chapter_element (GstMatroskaReadCommon * common,
1166 GstEbmlRead * ebml, GList ** subentries, GList ** internal_subentries)
1167 {
1168 guint32 id;
1169 guint64 start_time = -1, stop_time = -1;
1170 guint64 is_hidden = 0, is_enabled = 1, uid = 0;
1171 GstFlowReturn ret = GST_FLOW_OK;
1172 GstTocEntry *chapter_info, *internal_chapter_info;
1173 GstTagList *tags;
1174 gchar *uid_str, *string_uid = NULL;
1175 GList *subsubentries = NULL, *internal_subsubentries = NULL, *l, *il;
1176
1177 DEBUG_ELEMENT_START (common, ebml, "ChaptersElement");
1178
1179 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
1180 DEBUG_ELEMENT_STOP (common, ebml, "ChaptersElement", ret);
1181 return ret;
1182 }
1183
1184 tags = gst_tag_list_new_empty ();
1185
1186 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
1187 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
1188 break;
1189
1190 switch (id) {
1191 case GST_MATROSKA_ID_CHAPTERUID:
1192 ret = gst_ebml_read_uint (ebml, &id, &uid);
1193 break;
1194
1195 case GST_MATROSKA_ID_CHAPTERSTRINGUID:
1196 ret = gst_ebml_read_utf8 (ebml, &id, &string_uid);
1197 break;
1198
1199 case GST_MATROSKA_ID_CHAPTERTIMESTART:
1200 ret = gst_ebml_read_uint (ebml, &id, &start_time);
1201 break;
1202
1203 case GST_MATROSKA_ID_CHAPTERTIMESTOP:
1204 ret = gst_ebml_read_uint (ebml, &id, &stop_time);
1205 break;
1206
1207 case GST_MATROSKA_ID_CHAPTERATOM:
1208 ret = gst_matroska_read_common_parse_chapter_element (common, ebml,
1209 &subsubentries, &internal_subsubentries);
1210 break;
1211
1212 case GST_MATROSKA_ID_CHAPTERDISPLAY:
1213 ret =
1214 gst_matroska_read_common_parse_chapter_titles (common, ebml, tags);
1215 break;
1216
1217 case GST_MATROSKA_ID_CHAPTERFLAGHIDDEN:
1218 ret = gst_ebml_read_uint (ebml, &id, &is_hidden);
1219 break;
1220
1221 case GST_MATROSKA_ID_CHAPTERFLAGENABLED:
1222 ret = gst_ebml_read_uint (ebml, &id, &is_enabled);
1223 break;
1224
1225 default:
1226 ret =
1227 gst_matroska_read_common_parse_skip (common, ebml,
1228 "ChaptersElement", id);
1229 break;
1230 }
1231 }
1232
1233 if (uid == 0)
1234 uid = (((guint64) g_random_int ()) << 32) | g_random_int ();
1235 uid_str = g_strdup_printf ("%" G_GUINT64_FORMAT, uid);
1236 if (string_uid != NULL) {
1237 /* init toc with provided String UID */
1238 chapter_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, string_uid);
1239 g_free (string_uid);
1240 } else {
1241 /* No String UID provided => use the internal UID instead */
1242 chapter_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, uid_str);
1243 }
1244 /* init internal toc with internal UID */
1245 internal_chapter_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER,
1246 uid_str);
1247 g_free (uid_str);
1248
1249 gst_toc_entry_set_tags (chapter_info, tags);
1250 gst_toc_entry_set_start_stop_times (chapter_info, start_time, stop_time);
1251
1252 for (l = subsubentries, il = internal_subsubentries;
1253 l && il; l = l->next, il = il->next) {
1254 gst_toc_entry_append_sub_entry (chapter_info, l->data);
1255 gst_toc_entry_append_sub_entry (internal_chapter_info, il->data);
1256 }
1257 g_list_free (subsubentries);
1258 g_list_free (internal_subsubentries);
1259
1260 DEBUG_ELEMENT_STOP (common, ebml, "ChaptersElement", ret);
1261
1262 /* start time is mandatory and has no default value,
1263 * so we should skip chapters without it */
1264 if (is_hidden == 0 && is_enabled > 0 &&
1265 start_time != -1 && ret == GST_FLOW_OK) {
1266 *subentries = g_list_append (*subentries, chapter_info);
1267 *internal_subentries = g_list_append (*internal_subentries,
1268 internal_chapter_info);
1269 } else {
1270 gst_toc_entry_unref (chapter_info);
1271 gst_toc_entry_unref (internal_chapter_info);
1272 }
1273
1274 return ret;
1275 }
1276
1277 static GstFlowReturn
gst_matroska_read_common_parse_chapter_edition(GstMatroskaReadCommon * common,GstEbmlRead * ebml,GstToc * toc,GstToc * internal_toc)1278 gst_matroska_read_common_parse_chapter_edition (GstMatroskaReadCommon * common,
1279 GstEbmlRead * ebml, GstToc * toc, GstToc * internal_toc)
1280 {
1281 guint32 id;
1282 guint64 is_hidden = 0, uid = 0;
1283 GstFlowReturn ret = GST_FLOW_OK;
1284 GstTocEntry *edition_info, *internal_edition_info;
1285 GList *subentries = NULL, *internal_subentries = NULL, *l, *il;
1286 gchar *uid_str;
1287
1288 DEBUG_ELEMENT_START (common, ebml, "ChaptersEdition");
1289
1290 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
1291 DEBUG_ELEMENT_STOP (common, ebml, "ChaptersEdition", ret);
1292 return ret;
1293 }
1294
1295 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
1296 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
1297 break;
1298
1299 switch (id) {
1300 case GST_MATROSKA_ID_EDITIONUID:
1301 ret = gst_ebml_read_uint (ebml, &id, &uid);
1302 break;
1303
1304 case GST_MATROSKA_ID_CHAPTERATOM:
1305 ret = gst_matroska_read_common_parse_chapter_element (common, ebml,
1306 &subentries, &internal_subentries);
1307 break;
1308
1309 case GST_MATROSKA_ID_EDITIONFLAGHIDDEN:
1310 ret = gst_ebml_read_uint (ebml, &id, &is_hidden);
1311 break;
1312
1313 default:
1314 ret =
1315 gst_matroska_read_common_parse_skip (common, ebml,
1316 "ChaptersEdition", id);
1317 break;
1318 }
1319 }
1320
1321 DEBUG_ELEMENT_STOP (common, ebml, "ChaptersEdition", ret);
1322
1323 if (uid == 0)
1324 uid = (((guint64) g_random_int ()) << 32) | g_random_int ();
1325 uid_str = g_strdup_printf ("%" G_GUINT64_FORMAT, uid);
1326 edition_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, uid_str);
1327 gst_toc_entry_set_start_stop_times (edition_info, -1, -1);
1328 internal_edition_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION,
1329 uid_str);
1330 g_free (uid_str);
1331
1332 for (l = subentries, il = internal_subentries; l && il;
1333 l = l->next, il = il->next) {
1334 gst_toc_entry_append_sub_entry (edition_info, l->data);
1335 gst_toc_entry_append_sub_entry (internal_edition_info, il->data);
1336 }
1337 g_list_free (subentries);
1338 g_list_free (internal_subentries);
1339
1340 if (is_hidden == 0 && subentries != NULL && ret == GST_FLOW_OK) {
1341 gst_toc_append_entry (toc, edition_info);
1342 gst_toc_append_entry (internal_toc, internal_edition_info);
1343 } else {
1344 GST_DEBUG_OBJECT (common->sinkpad,
1345 "Skipping empty or hidden edition in the chapters TOC");
1346 gst_toc_entry_unref (edition_info);
1347 gst_toc_entry_unref (internal_edition_info);
1348 }
1349
1350 return ret;
1351 }
1352
1353 GstFlowReturn
gst_matroska_read_common_parse_chapters(GstMatroskaReadCommon * common,GstEbmlRead * ebml)1354 gst_matroska_read_common_parse_chapters (GstMatroskaReadCommon * common,
1355 GstEbmlRead * ebml)
1356 {
1357 guint32 id;
1358 GstFlowReturn ret = GST_FLOW_OK;
1359 GstToc *toc, *internal_toc;
1360
1361 DEBUG_ELEMENT_START (common, ebml, "Chapters");
1362
1363 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
1364 DEBUG_ELEMENT_STOP (common, ebml, "Chapters", ret);
1365 return ret;
1366 }
1367
1368 /* FIXME: create CURRENT toc as well */
1369 toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
1370 internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
1371
1372 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
1373 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
1374 break;
1375
1376 switch (id) {
1377 case GST_MATROSKA_ID_EDITIONENTRY:
1378 ret = gst_matroska_read_common_parse_chapter_edition (common, ebml,
1379 toc, internal_toc);
1380 break;
1381
1382 default:
1383 ret =
1384 gst_matroska_read_common_parse_skip (common, ebml, "Chapters", id);
1385 break;
1386 }
1387 }
1388
1389 if (gst_toc_get_entries (toc) != NULL) {
1390 gst_matroska_read_common_postprocess_toc_entries (gst_toc_get_entries (toc),
1391 common->segment.duration, "");
1392 /* no need to postprocess internal_toc as we don't need to keep track
1393 * of start / end and tags (only UIDs) */
1394
1395 common->toc = toc;
1396 common->internal_toc = internal_toc;
1397 } else {
1398 gst_toc_unref (toc);
1399 gst_toc_unref (internal_toc);
1400 }
1401
1402 common->chapters_parsed = TRUE;
1403
1404 DEBUG_ELEMENT_STOP (common, ebml, "Chapters", ret);
1405 return ret;
1406 }
1407
1408 GstFlowReturn
gst_matroska_read_common_parse_header(GstMatroskaReadCommon * common,GstEbmlRead * ebml)1409 gst_matroska_read_common_parse_header (GstMatroskaReadCommon * common,
1410 GstEbmlRead * ebml)
1411 {
1412 GstFlowReturn ret;
1413 gchar *doctype;
1414 guint version;
1415 guint32 id;
1416
1417 /* this function is the first to be called */
1418
1419 /* default init */
1420 doctype = NULL;
1421 version = 1;
1422
1423 ret = gst_ebml_peek_id (ebml, &id);
1424 if (ret != GST_FLOW_OK)
1425 return ret;
1426
1427 GST_DEBUG_OBJECT (common->sinkpad, "id: %08x", id);
1428
1429 if (id != GST_EBML_ID_HEADER) {
1430 GST_ERROR_OBJECT (common->sinkpad, "Failed to read header");
1431 goto exit;
1432 }
1433
1434 ret = gst_ebml_read_master (ebml, &id);
1435 if (ret != GST_FLOW_OK)
1436 return ret;
1437
1438 while (gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
1439 ret = gst_ebml_peek_id (ebml, &id);
1440 if (ret != GST_FLOW_OK)
1441 goto exit_error;
1442
1443 switch (id) {
1444 /* is our read version uptodate? */
1445 case GST_EBML_ID_EBMLREADVERSION:{
1446 guint64 num;
1447
1448 ret = gst_ebml_read_uint (ebml, &id, &num);
1449 if (ret != GST_FLOW_OK)
1450 goto exit_error;
1451 if (num != GST_EBML_VERSION) {
1452 GST_ERROR_OBJECT (common->sinkpad,
1453 "Unsupported EBML version %" G_GUINT64_FORMAT, num);
1454 goto exit_error;
1455 }
1456
1457 GST_DEBUG_OBJECT (common->sinkpad,
1458 "EbmlReadVersion: %" G_GUINT64_FORMAT, num);
1459 break;
1460 }
1461
1462 /* we only handle 8 byte lengths at max */
1463 case GST_EBML_ID_EBMLMAXSIZELENGTH:{
1464 guint64 num;
1465
1466 ret = gst_ebml_read_uint (ebml, &id, &num);
1467 if (ret != GST_FLOW_OK)
1468 goto exit_error;
1469 if (num > sizeof (guint64)) {
1470 GST_ERROR_OBJECT (common->sinkpad,
1471 "Unsupported EBML maximum size %" G_GUINT64_FORMAT, num);
1472 return GST_FLOW_ERROR;
1473 }
1474 GST_DEBUG_OBJECT (common->sinkpad,
1475 "EbmlMaxSizeLength: %" G_GUINT64_FORMAT, num);
1476 break;
1477 }
1478
1479 /* we handle 4 byte IDs at max */
1480 case GST_EBML_ID_EBMLMAXIDLENGTH:{
1481 guint64 num;
1482
1483 ret = gst_ebml_read_uint (ebml, &id, &num);
1484 if (ret != GST_FLOW_OK)
1485 goto exit_error;
1486 if (num > sizeof (guint32)) {
1487 GST_ERROR_OBJECT (common->sinkpad,
1488 "Unsupported EBML maximum ID %" G_GUINT64_FORMAT, num);
1489 return GST_FLOW_ERROR;
1490 }
1491 GST_DEBUG_OBJECT (common->sinkpad,
1492 "EbmlMaxIdLength: %" G_GUINT64_FORMAT, num);
1493 break;
1494 }
1495
1496 case GST_EBML_ID_DOCTYPE:{
1497 gchar *text;
1498
1499 ret = gst_ebml_read_ascii (ebml, &id, &text);
1500 if (ret != GST_FLOW_OK)
1501 goto exit_error;
1502
1503 GST_DEBUG_OBJECT (common->sinkpad, "EbmlDocType: %s",
1504 GST_STR_NULL (text));
1505
1506 g_free (doctype);
1507 doctype = text;
1508 break;
1509 }
1510
1511 case GST_EBML_ID_DOCTYPEREADVERSION:{
1512 guint64 num;
1513
1514 ret = gst_ebml_read_uint (ebml, &id, &num);
1515 if (ret != GST_FLOW_OK)
1516 goto exit_error;
1517 version = num;
1518 GST_DEBUG_OBJECT (common->sinkpad,
1519 "EbmlReadVersion: %" G_GUINT64_FORMAT, num);
1520 break;
1521 }
1522
1523 default:
1524 ret = gst_matroska_read_common_parse_skip (common, ebml,
1525 "EBML header", id);
1526 if (ret != GST_FLOW_OK)
1527 goto exit_error;
1528 break;
1529
1530 /* we ignore these two, as they don't tell us anything we care about */
1531 case GST_EBML_ID_EBMLVERSION:
1532 case GST_EBML_ID_DOCTYPEVERSION:
1533 ret = gst_ebml_read_skip (ebml);
1534 if (ret != GST_FLOW_OK)
1535 goto exit_error;
1536 break;
1537 }
1538 }
1539
1540 exit:
1541
1542 if ((doctype != NULL && !strcmp (doctype, GST_MATROSKA_DOCTYPE_MATROSKA)) ||
1543 (doctype != NULL && !strcmp (doctype, GST_MATROSKA_DOCTYPE_WEBM)) ||
1544 (doctype == NULL)) {
1545 if (version <= 2) {
1546 if (doctype) {
1547 GST_INFO_OBJECT (common->sinkpad, "Input is %s version %d", doctype,
1548 version);
1549 if (!strcmp (doctype, GST_MATROSKA_DOCTYPE_WEBM))
1550 common->is_webm = TRUE;
1551 } else {
1552 GST_WARNING_OBJECT (common->sinkpad,
1553 "Input is EBML without doctype, assuming " "matroska (version %d)",
1554 version);
1555 }
1556 ret = GST_FLOW_OK;
1557 } else {
1558 GST_ELEMENT_ERROR (common, STREAM, DEMUX, (NULL),
1559 ("Demuxer version (2) is too old to read %s version %d",
1560 GST_STR_NULL (doctype), version));
1561 ret = GST_FLOW_ERROR;
1562 }
1563 } else {
1564 GST_ELEMENT_ERROR (common, STREAM, WRONG_TYPE, (NULL),
1565 ("Input is not a matroska stream (doctype=%s)", doctype));
1566 ret = GST_FLOW_ERROR;
1567 }
1568
1569 exit_error:
1570
1571 g_free (doctype);
1572
1573 return ret;
1574 }
1575
1576 static GstFlowReturn
gst_matroska_read_common_parse_index_cuetrack(GstMatroskaReadCommon * common,GstEbmlRead * ebml,guint * nentries)1577 gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
1578 GstEbmlRead * ebml, guint * nentries)
1579 {
1580 guint32 id;
1581 GstFlowReturn ret;
1582 GstMatroskaIndex idx;
1583
1584 idx.pos = (guint64) - 1;
1585 idx.track = 0;
1586 idx.time = GST_CLOCK_TIME_NONE;
1587 idx.block = 1;
1588
1589 DEBUG_ELEMENT_START (common, ebml, "CueTrackPositions");
1590
1591 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
1592 DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret);
1593 return ret;
1594 }
1595
1596 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
1597 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
1598 break;
1599
1600 switch (id) {
1601 /* track number */
1602 case GST_MATROSKA_ID_CUETRACK:
1603 {
1604 guint64 num;
1605
1606 if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
1607 break;
1608
1609 if (num == 0) {
1610 idx.track = 0;
1611 GST_WARNING_OBJECT (common->sinkpad, "Invalid CueTrack 0");
1612 break;
1613 }
1614
1615 GST_DEBUG_OBJECT (common->sinkpad, "CueTrack: %" G_GUINT64_FORMAT, num);
1616 idx.track = num;
1617 break;
1618 }
1619
1620 /* position in file */
1621 case GST_MATROSKA_ID_CUECLUSTERPOSITION:
1622 {
1623 guint64 num;
1624
1625 if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
1626 break;
1627
1628 if (num > G_MAXINT64) {
1629 GST_WARNING_OBJECT (common->sinkpad,
1630 "CueClusterPosition %" G_GUINT64_FORMAT " too large", num);
1631 break;
1632 }
1633
1634 idx.pos = num;
1635 break;
1636 }
1637
1638 /* number of block in the cluster */
1639 case GST_MATROSKA_ID_CUEBLOCKNUMBER:
1640 {
1641 guint64 num;
1642
1643 if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
1644 break;
1645
1646 if (num == 0) {
1647 GST_WARNING_OBJECT (common->sinkpad, "Invalid CueBlockNumber 0");
1648 break;
1649 }
1650
1651 GST_DEBUG_OBJECT (common->sinkpad, "CueBlockNumber: %" G_GUINT64_FORMAT,
1652 num);
1653 idx.block = num;
1654
1655 /* mild sanity check, disregard strange cases ... */
1656 if (idx.block > G_MAXUINT16) {
1657 GST_DEBUG_OBJECT (common->sinkpad, "... looks suspicious, ignoring");
1658 idx.block = 1;
1659 }
1660 break;
1661 }
1662
1663 default:
1664 ret = gst_matroska_read_common_parse_skip (common, ebml,
1665 "CueTrackPositions", id);
1666 break;
1667
1668 case GST_MATROSKA_ID_CUECODECSTATE:
1669 case GST_MATROSKA_ID_CUEREFERENCE:
1670 ret = gst_ebml_read_skip (ebml);
1671 break;
1672 }
1673 }
1674
1675 DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret);
1676
1677 /* (e.g.) lavf typically creates entries without a block number,
1678 * which is bogus and leads to contradictory information */
1679 if (common->index->len) {
1680 GstMatroskaIndex *last_idx;
1681
1682 last_idx = &g_array_index (common->index, GstMatroskaIndex,
1683 common->index->len - 1);
1684 if (last_idx->block == idx.block && last_idx->pos == idx.pos &&
1685 last_idx->track == idx.track && idx.time > last_idx->time) {
1686 GST_DEBUG_OBJECT (common->sinkpad, "Cue entry refers to same location, "
1687 "but has different time than previous entry; discarding");
1688 idx.track = 0;
1689 }
1690 }
1691
1692 if ((ret == GST_FLOW_OK || ret == GST_FLOW_EOS)
1693 && idx.pos != (guint64) - 1 && idx.track > 0) {
1694 g_array_append_val (common->index, idx);
1695 (*nentries)++;
1696 } else if (ret == GST_FLOW_OK || ret == GST_FLOW_EOS) {
1697 GST_DEBUG_OBJECT (common->sinkpad,
1698 "CueTrackPositions without valid content");
1699 }
1700
1701 return ret;
1702 }
1703
1704 static GstFlowReturn
gst_matroska_read_common_parse_index_pointentry(GstMatroskaReadCommon * common,GstEbmlRead * ebml)1705 gst_matroska_read_common_parse_index_pointentry (GstMatroskaReadCommon *
1706 common, GstEbmlRead * ebml)
1707 {
1708 guint32 id;
1709 GstFlowReturn ret;
1710 GstClockTime time = GST_CLOCK_TIME_NONE;
1711 guint nentries = 0;
1712
1713 DEBUG_ELEMENT_START (common, ebml, "CuePoint");
1714
1715 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
1716 DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret);
1717 return ret;
1718 }
1719
1720 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
1721 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
1722 break;
1723
1724 switch (id) {
1725 /* one single index entry ('point') */
1726 case GST_MATROSKA_ID_CUETIME:
1727 {
1728 if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK)
1729 break;
1730
1731 GST_DEBUG_OBJECT (common->sinkpad, "CueTime: %" G_GUINT64_FORMAT, time);
1732 time = time * common->time_scale;
1733 break;
1734 }
1735
1736 /* position in the file + track to which it belongs */
1737 case GST_MATROSKA_ID_CUETRACKPOSITIONS:
1738 {
1739 ret = gst_matroska_read_common_parse_index_cuetrack (common, ebml,
1740 &nentries);
1741 break;
1742 }
1743
1744 default:
1745 ret = gst_matroska_read_common_parse_skip (common, ebml, "CuePoint",
1746 id);
1747 break;
1748 }
1749 }
1750
1751 DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret);
1752
1753 if (nentries > 0) {
1754 if (time == GST_CLOCK_TIME_NONE) {
1755 GST_WARNING_OBJECT (common->sinkpad, "CuePoint without valid time");
1756 g_array_remove_range (common->index, common->index->len - nentries,
1757 nentries);
1758 } else {
1759 gint i;
1760
1761 for (i = common->index->len - nentries; i < common->index->len; i++) {
1762 GstMatroskaIndex *idx =
1763 &g_array_index (common->index, GstMatroskaIndex, i);
1764
1765 idx->time = time;
1766 GST_DEBUG_OBJECT (common->sinkpad, "Index entry: pos=%" G_GUINT64_FORMAT
1767 ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
1768 GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
1769 }
1770 }
1771 } else {
1772 GST_DEBUG_OBJECT (common->sinkpad, "Empty CuePoint");
1773 }
1774
1775 return ret;
1776 }
1777
1778 gint
gst_matroska_read_common_stream_from_num(GstMatroskaReadCommon * common,guint track_num)1779 gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common,
1780 guint track_num)
1781 {
1782 guint n;
1783
1784 g_assert (common->src->len == common->num_streams);
1785 for (n = 0; n < common->src->len; n++) {
1786 GstMatroskaTrackContext *context = g_ptr_array_index (common->src, n);
1787
1788 if (context->num == track_num) {
1789 return n;
1790 }
1791 }
1792
1793 if (n == common->num_streams)
1794 GST_WARNING_OBJECT (common->sinkpad,
1795 "Failed to find corresponding pad for tracknum %d", track_num);
1796
1797 return -1;
1798 }
1799
1800 GstFlowReturn
gst_matroska_read_common_parse_index(GstMatroskaReadCommon * common,GstEbmlRead * ebml)1801 gst_matroska_read_common_parse_index (GstMatroskaReadCommon * common,
1802 GstEbmlRead * ebml)
1803 {
1804 guint32 id;
1805 GstFlowReturn ret = GST_FLOW_OK;
1806 guint i;
1807
1808 if (common->index)
1809 g_array_free (common->index, TRUE);
1810 common->index =
1811 g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
1812
1813 DEBUG_ELEMENT_START (common, ebml, "Cues");
1814
1815 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
1816 DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret);
1817 return ret;
1818 }
1819
1820 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
1821 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
1822 break;
1823
1824 switch (id) {
1825 /* one single index entry ('point') */
1826 case GST_MATROSKA_ID_POINTENTRY:
1827 ret = gst_matroska_read_common_parse_index_pointentry (common, ebml);
1828 break;
1829
1830 default:
1831 ret = gst_matroska_read_common_parse_skip (common, ebml, "Cues", id);
1832 break;
1833 }
1834 }
1835 DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret);
1836
1837 /* Sort index by time, smallest time first, for easier searching */
1838 g_array_sort (common->index, (GCompareFunc) gst_matroska_index_compare);
1839
1840 /* Now sort the track specific index entries into their own arrays */
1841 for (i = 0; i < common->index->len; i++) {
1842 GstMatroskaIndex *idx = &g_array_index (common->index, GstMatroskaIndex,
1843 i);
1844 gint track_num;
1845 GstMatroskaTrackContext *ctx;
1846
1847 #if 0
1848 if (common->element_index) {
1849 gint writer_id;
1850
1851 if (idx->track != 0 &&
1852 (track_num =
1853 gst_matroska_read_common_stream_from_num (common,
1854 idx->track)) != -1) {
1855 ctx = g_ptr_array_index (common->src, track_num);
1856
1857 if (ctx->index_writer_id == -1)
1858 gst_index_get_writer_id (common->element_index,
1859 GST_OBJECT (ctx->pad), &ctx->index_writer_id);
1860 writer_id = ctx->index_writer_id;
1861 } else {
1862 if (common->element_index_writer_id == -1)
1863 gst_index_get_writer_id (common->element_index, GST_OBJECT (common),
1864 &common->element_index_writer_id);
1865 writer_id = common->element_index_writer_id;
1866 }
1867
1868 GST_LOG_OBJECT (common->sinkpad,
1869 "adding association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT
1870 " for writer id %d", GST_TIME_ARGS (idx->time), idx->pos, writer_id);
1871 gst_index_add_association (common->element_index, writer_id,
1872 GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time,
1873 GST_FORMAT_BYTES, idx->pos + common->ebml_segment_start, NULL);
1874 }
1875 #endif
1876
1877 if (idx->track == 0)
1878 continue;
1879
1880 track_num = gst_matroska_read_common_stream_from_num (common, idx->track);
1881 if (track_num == -1)
1882 continue;
1883
1884 ctx = g_ptr_array_index (common->src, track_num);
1885
1886 if (ctx->index_table == NULL)
1887 ctx->index_table =
1888 g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
1889
1890 g_array_append_vals (ctx->index_table, idx, 1);
1891 }
1892
1893 common->index_parsed = TRUE;
1894
1895 /* sanity check; empty index normalizes to no index */
1896 if (common->index->len == 0) {
1897 g_array_free (common->index, TRUE);
1898 common->index = NULL;
1899 }
1900
1901 return ret;
1902 }
1903
1904 GstFlowReturn
gst_matroska_read_common_parse_info(GstMatroskaReadCommon * common,GstElement * el,GstEbmlRead * ebml)1905 gst_matroska_read_common_parse_info (GstMatroskaReadCommon * common,
1906 GstElement * el, GstEbmlRead * ebml)
1907 {
1908 GstFlowReturn ret = GST_FLOW_OK;
1909 gdouble dur_f = -1.0;
1910 guint32 id;
1911
1912 DEBUG_ELEMENT_START (common, ebml, "SegmentInfo");
1913
1914 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
1915 DEBUG_ELEMENT_STOP (common, ebml, "SegmentInfo", ret);
1916 return ret;
1917 }
1918
1919 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
1920 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
1921 break;
1922
1923 switch (id) {
1924 /* cluster timecode */
1925 case GST_MATROSKA_ID_TIMECODESCALE:{
1926 guint64 num;
1927
1928 if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
1929 break;
1930
1931
1932 GST_DEBUG_OBJECT (common->sinkpad, "TimeCodeScale: %" G_GUINT64_FORMAT,
1933 num);
1934 common->time_scale = num;
1935 break;
1936 }
1937
1938 case GST_MATROSKA_ID_DURATION:{
1939 if ((ret = gst_ebml_read_float (ebml, &id, &dur_f)) != GST_FLOW_OK)
1940 break;
1941
1942 if (dur_f <= 0.0) {
1943 GST_WARNING_OBJECT (common->sinkpad, "Invalid duration %lf", dur_f);
1944 break;
1945 }
1946
1947 GST_DEBUG_OBJECT (common->sinkpad, "Duration: %lf", dur_f);
1948 break;
1949 }
1950
1951 case GST_MATROSKA_ID_WRITINGAPP:{
1952 gchar *text;
1953
1954 if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
1955 break;
1956
1957 GST_DEBUG_OBJECT (common->sinkpad, "WritingApp: %s",
1958 GST_STR_NULL (text));
1959 common->writing_app = text;
1960 break;
1961 }
1962
1963 case GST_MATROSKA_ID_MUXINGAPP:{
1964 gchar *text;
1965
1966 if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
1967 break;
1968
1969 GST_DEBUG_OBJECT (common->sinkpad, "MuxingApp: %s",
1970 GST_STR_NULL (text));
1971 common->muxing_app = text;
1972 break;
1973 }
1974
1975 case GST_MATROSKA_ID_DATEUTC:{
1976 gint64 time;
1977
1978 if ((ret = gst_ebml_read_date (ebml, &id, &time)) != GST_FLOW_OK)
1979 break;
1980
1981 GST_DEBUG_OBJECT (common->sinkpad, "DateUTC: %" G_GINT64_FORMAT, time);
1982 common->created = time;
1983 break;
1984 }
1985
1986 case GST_MATROSKA_ID_TITLE:{
1987 gchar *text;
1988 GstTagList *taglist;
1989
1990 if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
1991 break;
1992
1993 GST_DEBUG_OBJECT (common->sinkpad, "Title: %s", GST_STR_NULL (text));
1994 taglist = gst_tag_list_new (GST_TAG_TITLE, text, NULL);
1995 gst_tag_list_set_scope (taglist, GST_TAG_SCOPE_GLOBAL);
1996 gst_matroska_read_common_found_global_tag (common, el, taglist);
1997 g_free (text);
1998 break;
1999 }
2000
2001 default:
2002 ret = gst_matroska_read_common_parse_skip (common, ebml,
2003 "SegmentInfo", id);
2004 break;
2005
2006 /* fall through */
2007 case GST_MATROSKA_ID_SEGMENTUID:
2008 case GST_MATROSKA_ID_SEGMENTFILENAME:
2009 case GST_MATROSKA_ID_PREVUID:
2010 case GST_MATROSKA_ID_PREVFILENAME:
2011 case GST_MATROSKA_ID_NEXTUID:
2012 case GST_MATROSKA_ID_NEXTFILENAME:
2013 case GST_MATROSKA_ID_SEGMENTFAMILY:
2014 case GST_MATROSKA_ID_CHAPTERTRANSLATE:
2015 ret = gst_ebml_read_skip (ebml);
2016 break;
2017 }
2018 }
2019
2020 if (dur_f > 0.0) {
2021 GstClockTime dur_u;
2022
2023 dur_u = gst_gdouble_to_guint64 (dur_f *
2024 gst_guint64_to_gdouble (common->time_scale));
2025 if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64)
2026 common->segment.duration = dur_u;
2027 }
2028
2029 DEBUG_ELEMENT_STOP (common, ebml, "SegmentInfo", ret);
2030
2031 common->segmentinfo_parsed = TRUE;
2032
2033 return ret;
2034 }
2035
2036 static GstFlowReturn
gst_matroska_read_common_parse_metadata_id_simple_tag(GstMatroskaReadCommon * common,GstEbmlRead * ebml,GstTagList ** p_taglist,gchar * parent)2037 gst_matroska_read_common_parse_metadata_id_simple_tag (GstMatroskaReadCommon *
2038 common, GstEbmlRead * ebml, GstTagList ** p_taglist, gchar * parent)
2039 {
2040 /* FIXME: check if there are more useful mappings */
2041 static const struct
2042 {
2043 const gchar *matroska_tagname;
2044 const gchar *gstreamer_tagname;
2045 }
2046
2047 /* *INDENT-OFF* */
2048 tag_conv[] = {
2049 {
2050 /* The following list has the _same_ order as the one in Matroska spec. Please, don't mess it up. */
2051 /* TODO: Nesting information:
2052 ORIGINAL A special tag that is meant to have other tags inside (using nested tags) to describe the original work of art that this item is based on. All tags in this list can be used "under" the ORIGINAL tag like LYRICIST, PERFORMER, etc.
2053 SAMPLE A tag that contains other tags to describe a sample used in the targeted item taken from another work of art. All tags in this list can be used "under" the SAMPLE tag like TITLE, ARTIST, DATE_RELEASED, etc.
2054 COUNTRY The name of the country (biblio ISO-639-2) that is meant to have other tags inside (using nested tags) to country specific information about the item. All tags in this list can be used "under" the COUNTRY_SPECIFIC tag like LABEL, PUBLISH_RATING, etc.
2055 */
2056
2057 /* Organizational Information */
2058 GST_MATROSKA_TAG_ID_TOTAL_PARTS, GST_TAG_TRACK_COUNT}, {
2059 GST_MATROSKA_TAG_ID_PART_NUMBER, GST_TAG_TRACK_NUMBER}, {
2060 /* TODO: PART_OFFSET A number to add to PART_NUMBER when the parts at that level don't start at 1. (e.g. if TargetType is TRACK, the track number of the second audio CD) */
2061
2062 /* Titles */
2063 GST_MATROSKA_TAG_ID_SUBTITLE, GST_TAG_TITLE}, { /* Sub Title of the entity. Since we're concat'ing all title-like entities anyway, might as well add the sub-title. */
2064 GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
2065 GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, { /* Matroska spec does NOT have this tag! Dunno what it was doing here, probably for compatibility. */
2066
2067 /* TODO: Nested Information:
2068 URL URL corresponding to the tag it's included in.
2069 SORT_WITH A child element to indicate what alternative value the parent tag can have to be sorted, for example "Pet Shop Boys" instead of "The Pet Shop Boys". Or "Marley Bob" and "Marley Ziggy" (no comma needed).
2070 INSTRUMENTS The instruments that are being used/played, separated by a comma. It should be a child of the following tags: ARTIST, LEAD_PERFORMER or ACCOMPANIMENT.
2071 EMAIL Email corresponding to the tag it's included in.
2072 ADDRESS The physical address of the entity. The address should include a country code. It can be useful for a recording label.
2073 FAX The fax number corresponding to the tag it's included in. It can be useful for a recording label.
2074 PHONE The phone number corresponding to the tag it's included in. It can be useful for a recording label.
2075 */
2076
2077 /* Entities */
2078 GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
2079 GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
2080 GST_MATROSKA_TAG_ID_ACCOMPANIMENT, GST_TAG_PERFORMER}, { /* Band/orchestra/accompaniment/musician. This is akin to the TPE2 tag in ID3. */
2081 GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
2082 /* ARRANGER The person who arranged the piece, e.g., Ravel. */
2083 GST_MATROSKA_TAG_ID_LYRICS, GST_TAG_LYRICS}, { /* The lyrics corresponding to a song (in case audio synchronization is not known or as a doublon to a subtitle track). Editing this value when subtitles are found should also result in editing the subtitle track for more consistency. */
2084 /* LYRICIST The person who wrote the lyrics for a musical item. This is akin to the TEXT tag in ID3. */
2085 GST_MATROSKA_TAG_ID_CONDUCTOR, GST_TAG_PERFORMER}, { /* Conductor/performer refinement. This is akin to the TPE3 tag in ID3. */
2086 /* DIRECTOR This is akin to the IART tag in RIFF. */
2087 GST_MATROSKA_TAG_ID_AUTHOR, GST_TAG_ARTIST}, {
2088 /* ASSISTANT_DIRECTOR The name of the assistant director. */
2089 /* DIRECTOR_OF_PHOTOGRAPHY The name of the director of photography, also known as cinematographer. This is akin to the ICNM tag in Extended RIFF. */
2090 /* SOUND_ENGINEER The name of the sound engineer or sound recordist. */
2091 /* ART_DIRECTOR The person who oversees the artists and craftspeople who build the sets. */
2092 /* PRODUCTION_DESIGNER Artist responsible for designing the overall visual appearance of a movie. */
2093 /* CHOREGRAPHER The name of the choregrapher */
2094 /* COSTUME_DESIGNER The name of the costume designer */
2095 /* ACTOR An actor or actress playing a role in this movie. This is the person's real name, not the character's name the person is playing. */
2096 /* CHARACTER The name of the character an actor or actress plays in this movie. This should be a sub-tag of an ACTOR tag in order not to cause ambiguities. */
2097 /* WRITTEN_BY The author of the story or script (used for movies and TV shows). */
2098 /* SCREENPLAY_BY The author of the screenplay or scenario (used for movies and TV shows). */
2099 /* EDITED_BY This is akin to the IEDT tag in Extended RIFF. */
2100 /* PRODUCER Produced by. This is akin to the IPRO tag in Extended RIFF. */
2101 /* COPRODUCER The name of a co-producer. */
2102 /* EXECUTIVE_PRODUCER The name of an executive producer. */
2103 /* DISTRIBUTED_BY This is akin to the IDST tag in Extended RIFF. */
2104 /* MASTERED_BY The engineer who mastered the content for a physical medium or for digital distribution. */
2105 GST_MATROSKA_TAG_ID_ENCODED_BY, GST_TAG_ENCODED_BY}, { /* This is akin to the TENC tag in ID3. */
2106 /* MIXED_BY DJ mix by the artist specified */
2107 /* REMIXED_BY Interpreted, remixed, or otherwise modified by. This is akin to the TPE4 tag in ID3. */
2108 /* PRODUCTION_STUDIO This is akin to the ISTD tag in Extended RIFF. */
2109 /* THANKS_TO A very general tag for everyone else that wants to be listed. */
2110 /* PUBLISHER This is akin to the TPUB tag in ID3. */
2111 /* LABEL The record label or imprint on the disc. */
2112 /* Search / Classification */
2113 GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}, {
2114 /* MOOD Intended to reflect the mood of the item with a few keywords, e.g. "Romantic", "Sad" or "Uplifting". The format follows that of the TMOO tag in ID3. */
2115 /* ORIGINAL_MEDIA_TYPE Describes the original type of the media, such as, "DVD", "CD", "computer image," "drawing," "lithograph," and so forth. This is akin to the TMED tag in ID3. */
2116 /* CONTENT_TYPE The type of the item. e.g. Documentary, Feature Film, Cartoon, Music Video, Music, Sound FX, ... */
2117 /* SUBJECT Describes the topic of the file, such as "Aerial view of Seattle." */
2118 GST_MATROSKA_TAG_ID_DESCRIPTION, GST_TAG_DESCRIPTION}, { /* A short description of the content, such as "Two birds flying." */
2119 GST_MATROSKA_TAG_ID_KEYWORDS, GST_TAG_KEYWORDS}, { /* Keywords to the item separated by a comma, used for searching. */
2120 /* SUMMARY A plot outline or a summary of the story. */
2121 /* SYNOPSIS A description of the story line of the item. */
2122 /* INITIAL_KEY The initial key that a musical track starts in. The format is identical to ID3. */
2123 /* PERIOD Describes the period that the piece is from or about. For example, "Renaissance". */
2124 /* LAW_RATING Depending on the country it's the format of the rating of a movie (P, R, X in the USA, an age in other countries or a URI defining a logo). */
2125 /* ICRA The ICRA content rating for parental control. (Previously RSACi) */
2126
2127 /* Temporal Information */
2128 GST_MATROSKA_TAG_ID_DATE_RELEASED, GST_TAG_DATE}, { /* The time that the item was originaly released. This is akin to the TDRL tag in ID3. */
2129 GST_MATROSKA_TAG_ID_DATE_RECORDED, GST_TAG_DATE}, { /* The time that the recording began. This is akin to the TDRC tag in ID3. */
2130 GST_MATROSKA_TAG_ID_DATE_ENCODED, GST_TAG_DATE}, { /* The time that the encoding of this item was completed began. This is akin to the TDEN tag in ID3. */
2131 GST_MATROSKA_TAG_ID_DATE_TAGGED, GST_TAG_DATE}, { /* The time that the tags were done for this item. This is akin to the TDTG tag in ID3. */
2132 GST_MATROSKA_TAG_ID_DATE_DIGITIZED, GST_TAG_DATE}, { /* The time that the item was tranfered to a digital medium. This is akin to the IDIT tag in RIFF. */
2133 GST_MATROSKA_TAG_ID_DATE_WRITTEN, GST_TAG_DATE}, { /* The time that the writing of the music/script began. */
2134 GST_MATROSKA_TAG_ID_DATE_PURCHASED, GST_TAG_DATE}, { /* Information on when the file was purchased (see also purchase tags). */
2135 GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, { /* Matroska spec does NOT have this tag! Dunno what it was doing here, probably for compatibility. */
2136
2137 /* Spacial Information */
2138 GST_MATROSKA_TAG_ID_RECORDING_LOCATION, GST_TAG_GEO_LOCATION_NAME}, { /* The location where the item was recorded. The countries corresponding to the string, same 2 octets as in Internet domains, or possibly ISO-3166. This code is followed by a comma, then more detailed information such as state/province, another comma, and then city. For example, "US, Texas, Austin". This will allow for easy sorting. It is okay to only store the country, or the country and the state/province. More detailed information can be added after the city through the use of additional commas. In cases where the province/state is unknown, but you want to store the city, simply leave a space between the two commas. For example, "US, , Austin". */
2139 /* COMPOSITION_LOCATION Location that the item was originaly designed/written. The countries corresponding to the string, same 2 octets as in Internet domains, or possibly ISO-3166. This code is followed by a comma, then more detailed information such as state/province, another comma, and then city. For example, "US, Texas, Austin". This will allow for easy sorting. It is okay to only store the country, or the country and the state/province. More detailed information can be added after the city through the use of additional commas. In cases where the province/state is unknown, but you want to store the city, simply leave a space between the two commas. For example, "US, , Austin". */
2140 /* COMPOSER_NATIONALITY Nationality of the main composer of the item, mostly for classical music. The countries corresponding to the string, same 2 octets as in Internet domains, or possibly ISO-3166. */
2141
2142 /* Personal */
2143 GST_MATROSKA_TAG_ID_COMMENT, GST_TAG_COMMENT}, { /* Any comment related to the content. */
2144 GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, { /* Matroska spec does NOT have this tag! Dunno what it was doing here, probably for compatibility. */
2145 /* PLAY_COUNTER The number of time the item has been played. */
2146 /* TODO: RATING A numeric value defining how much a person likes the song/movie. The number is between 0 and 5 with decimal values possible (e.g. 2.7), 5(.0) being the highest possible rating. Other rating systems with different ranges will have to be scaled. */
2147
2148 /* Technical Information */
2149 GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
2150 /* ENCODER_SETTINGS A list of the settings used for encoding this item. No specific format. */
2151 GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
2152 GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, { /* Matroska spec does NOT have this tag! Dunno what it was doing here, probably for compatibility. */
2153 /* WONTFIX (already handled in another way): FPS The average frames per second of the specified item. This is typically the average number of Blocks per second. In the event that lacing is used, each laced chunk is to be counted as a seperate frame. */
2154 GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
2155 /* MEASURE In music, a measure is a unit of time in Western music like "4/4". It represents a regular grouping of beats, a meter, as indicated in musical notation by the time signature.. The majority of the contemporary rock and pop music you hear on the radio these days is written in the 4/4 time signature. */
2156 /* TUNING It is saved as a frequency in hertz to allow near-perfect tuning of instruments to the same tone as the musical piece (e.g. "441.34" in Hertz). The default value is 440.0 Hz. */
2157 /* TODO: REPLAYGAIN_GAIN The gain to apply to reach 89dB SPL on playback. This is based on the Replay Gain standard. Note that ReplayGain information can be found at all TargetType levels (track, album, etc). */
2158 /* TODO: REPLAYGAIN_PEAK The maximum absolute peak value of the item. This is based on the Replay Gain standard. */
2159
2160 /* Identifiers */
2161 GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
2162 /* MCDI This is a binary dump of the TOC of the CDROM that this item was taken from. This holds the same information as the MCDI in ID3. */
2163 /* ISBN International Standard Book Number */
2164 /* BARCODE EAN-13 (European Article Numbering) or UPC-A (Universal Product Code) bar code identifier */
2165 /* CATALOG_NUMBER A label-specific string used to identify the release (TIC 01 for example). */
2166 /* LABEL_CODE A 4-digit or 5-digit number to identify the record label, typically printed as (LC) xxxx or (LC) 0xxxx on CDs medias or covers (only the number is stored). */
2167 /* LCCN Library of Congress Control Number */
2168
2169 /* Commercial */
2170 /* PURCHASE_ITEM URL to purchase this file. This is akin to the WPAY tag in ID3. */
2171 /* PURCHASE_INFO Information on where to purchase this album. This is akin to the WCOM tag in ID3. */
2172 /* PURCHASE_OWNER Information on the person who purchased the file. This is akin to the TOWN tag in ID3. */
2173 /* PURCHASE_PRICE The amount paid for entity. There should only be a numeric value in here. Only numbers, no letters or symbols other than ".". For instance, you would store "15.59" instead of "$15.59USD". */
2174 /* PURCHASE_CURRENCY The currency type used to pay for the entity. Use ISO-4217 for the 3 letter currency code. */
2175
2176 /* Legal */
2177 GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
2178 GST_MATROSKA_TAG_ID_PRODUCTION_COPYRIGHT, GST_TAG_COPYRIGHT}, { /* The copyright information as per the production copyright holder. This is akin to the TPRO tag in ID3. */
2179 GST_MATROSKA_TAG_ID_LICENSE, GST_TAG_LICENSE}, { /* The license applied to the content (like Creative Commons variants). */
2180 GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}
2181 };
2182 /* *INDENT-ON* */
2183 static const struct
2184 {
2185 const gchar *matroska_tagname;
2186 const gchar *gstreamer_tagname;
2187 }
2188
2189 /* *INDENT-OFF* */
2190 child_tag_conv[] = {
2191 {
2192 "TITLE/SORT_WITH=", GST_TAG_TITLE_SORTNAME}, {
2193 "ARTIST/SORT_WITH=", GST_TAG_ARTIST_SORTNAME}, {
2194 /* ALBUM-stuff is handled elsewhere */
2195 "COMPOSER/SORT_WITH=", GST_TAG_TITLE_SORTNAME}, {
2196 "ORIGINAL/URL=", GST_TAG_LOCATION}, {
2197 /* EMAIL, PHONE, FAX all can be mapped to GST_TAG_CONTACT, there is special
2198 * code for that later.
2199 */
2200 "TITLE/URL=", GST_TAG_HOMEPAGE}, {
2201 "ARTIST/URL=", GST_TAG_HOMEPAGE}, {
2202 "COPYRIGHT/URL=", GST_TAG_COPYRIGHT_URI}, {
2203 "LICENSE/URL=", GST_TAG_LICENSE_URI}, {
2204 "LICENSE/URL=", GST_TAG_LICENSE_URI}
2205 };
2206 /* *INDENT-ON* */
2207 GstFlowReturn ret;
2208 guint32 id;
2209 gchar *value = NULL;
2210 gchar *tag = NULL;
2211 gchar *name_with_parent = NULL;
2212 GstTagList *child_taglist = NULL;
2213
2214 DEBUG_ELEMENT_START (common, ebml, "SimpleTag");
2215
2216 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
2217 DEBUG_ELEMENT_STOP (common, ebml, "SimpleTag", ret);
2218 return ret;
2219 }
2220
2221 if (parent)
2222 child_taglist = *p_taglist;
2223 else
2224 child_taglist = gst_tag_list_new_empty ();
2225
2226 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
2227 /* read all sub-entries */
2228
2229 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
2230 break;
2231
2232 switch (id) {
2233 case GST_MATROSKA_ID_TAGNAME:
2234 g_free (tag);
2235 tag = NULL;
2236 ret = gst_ebml_read_ascii (ebml, &id, &tag);
2237 GST_DEBUG_OBJECT (common->sinkpad, "TagName: %s", GST_STR_NULL (tag));
2238 g_free (name_with_parent);
2239 if (parent != NULL)
2240 name_with_parent = g_strdup_printf ("%s/%s", parent, tag);
2241 else
2242 name_with_parent = g_strdup (tag);
2243 break;
2244
2245 case GST_MATROSKA_ID_TAGSTRING:
2246 g_free (value);
2247 value = NULL;
2248 ret = gst_ebml_read_utf8 (ebml, &id, &value);
2249 GST_DEBUG_OBJECT (common->sinkpad, "TagString: %s",
2250 GST_STR_NULL (value));
2251 break;
2252
2253 case GST_MATROSKA_ID_SIMPLETAG:
2254 /* Recursive SimpleTag */
2255 /* This implementation requires tag name of _this_ tag to be known
2256 * in order to read its children. It's not in the spec, just the way
2257 * the code is written.
2258 */
2259 if (name_with_parent != NULL) {
2260 ret = gst_matroska_read_common_parse_metadata_id_simple_tag (common,
2261 ebml, &child_taglist, name_with_parent);
2262 break;
2263 }
2264 /* fall-through */
2265
2266 default:
2267 ret = gst_matroska_read_common_parse_skip (common, ebml, "SimpleTag",
2268 id);
2269 break;
2270
2271 case GST_MATROSKA_ID_TAGLANGUAGE:
2272 case GST_MATROSKA_ID_TAGDEFAULT:
2273 case GST_MATROSKA_ID_TAGBINARY:
2274 ret = gst_ebml_read_skip (ebml);
2275 break;
2276 }
2277 }
2278
2279 DEBUG_ELEMENT_STOP (common, ebml, "SimpleTag", ret);
2280
2281 if (parent && tag && value && *value != '\0') {
2282 /* Don't bother mapping children tags - parent will do that */
2283 gchar *key_val;
2284 /* TODO: read LANGUAGE sub-tag, and use "key[lc]=val" form */
2285 key_val = g_strdup_printf ("%s=%s", name_with_parent, value);
2286 gst_tag_list_add (*p_taglist, GST_TAG_MERGE_APPEND,
2287 GST_TAG_EXTENDED_COMMENT, key_val, NULL);
2288 g_free (key_val);
2289 } else if (tag && value && *value != '\0') {
2290 gboolean matched = FALSE;
2291 guint i;
2292
2293 for (i = 0; !matched && i < G_N_ELEMENTS (tag_conv); i++) {
2294 const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
2295
2296 const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
2297
2298 if (strcmp (tagname_mkv, tag) == 0) {
2299 GValue dest = { 0, };
2300 GType dest_type = gst_tag_get_type (tagname_gst);
2301
2302 /* Ensure that any date string is complete */
2303 if (dest_type == G_TYPE_DATE) {
2304 guint year = 1901, month = 1, day = 1;
2305
2306 /* Dates can be yyyy-MM-dd, yyyy-MM or yyyy, but we need
2307 * the first type */
2308 if (sscanf (value, "%04u-%02u-%02u", &year, &month, &day) != 0) {
2309 g_free (value);
2310 value = g_strdup_printf ("%04u-%02u-%02u", year, month, day);
2311 }
2312 }
2313
2314 g_value_init (&dest, dest_type);
2315 if (gst_value_deserialize (&dest, value)) {
2316 gst_tag_list_add_values (*p_taglist, GST_TAG_MERGE_APPEND,
2317 tagname_gst, &dest, NULL);
2318 } else {
2319 GST_WARNING_OBJECT (common->sinkpad, "Can't transform tag '%s' with "
2320 "value '%s' to target type '%s'", tag, value,
2321 g_type_name (dest_type));
2322 }
2323 g_value_unset (&dest);
2324 matched = TRUE;
2325 }
2326 }
2327 if (!matched) {
2328 gchar *key_val;
2329 /* TODO: read LANGUAGE sub-tag, and use "key[lc]=val" form */
2330 key_val = g_strdup_printf ("%s=%s", tag, value);
2331 gst_tag_list_add (*p_taglist, GST_TAG_MERGE_APPEND,
2332 GST_TAG_EXTENDED_COMMENT, key_val, NULL);
2333 g_free (key_val);
2334 }
2335 }
2336
2337 if (!parent) {
2338 /* Map children tags. This only supports top-anchored mapping. That is,
2339 * we start at toplevel tag (this tag), and see how its combinations
2340 * with its children can be mapped. Which means that grandchildren
2341 * are also combined here, with _this_ tag taken into consideration.
2342 * If grandchildren can be combined only with children, that combination
2343 * will not happen.
2344 */
2345 gint child_tags_n = gst_tag_list_n_tags (child_taglist);
2346 if (child_tags_n > 0) {
2347 gint i;
2348 for (i = 0; i < child_tags_n; i++) {
2349 gint j;
2350 const gchar *child_name = gst_tag_list_nth_tag_name (child_taglist, i);
2351 guint taglen = gst_tag_list_get_tag_size (child_taglist, child_name);
2352 for (j = 0; j < taglen; j++) {
2353 gchar *val;
2354 gboolean matched = FALSE;
2355 gchar *val_pre, *val_post;
2356 gint k;
2357
2358 if (!gst_tag_list_get_string_index (child_taglist, child_name,
2359 j, &val))
2360 continue;
2361 if (!strchr (val, '=')) {
2362 g_free (val);
2363 continue;
2364 }
2365 val_post = g_strdup (strchr (val, '=') + 1);
2366 val_pre = g_strdup (val);
2367 *(strchr (val_pre, '=') + 1) = '\0';
2368
2369 for (k = 0; !matched && k < G_N_ELEMENTS (child_tag_conv); k++) {
2370 const gchar *tagname_gst = child_tag_conv[k].gstreamer_tagname;
2371
2372 const gchar *tagname_mkv = child_tag_conv[k].matroska_tagname;
2373
2374 /* TODO: Once "key[lc]=value" form support is implemented,
2375 * strip [lc] here. It can't be used in combined tags.
2376 * If a tag is not combined, leave [lc] as it is.
2377 */
2378 if (strcmp (tagname_mkv, val_pre) == 0) {
2379 GValue dest = { 0, };
2380 GType dest_type = gst_tag_get_type (tagname_gst);
2381
2382 g_value_init (&dest, dest_type);
2383 if (gst_value_deserialize (&dest, val_post)) {
2384 gst_tag_list_add_values (*p_taglist, GST_TAG_MERGE_APPEND,
2385 tagname_gst, &dest, NULL);
2386 } else {
2387 GST_WARNING_OBJECT (common->sinkpad,
2388 "Can't transform complex tag '%s' " "to target type '%s'",
2389 val, g_type_name (dest_type));
2390 }
2391 g_value_unset (&dest);
2392 matched = TRUE;
2393 }
2394 }
2395 if (!matched) {
2396 gchar *last_slash = strrchr (val_pre, '/');
2397 if (last_slash) {
2398 last_slash++;
2399 if (strcmp (last_slash, "EMAIL=") == 0 ||
2400 strcmp (last_slash, "PHONE=") == 0 ||
2401 strcmp (last_slash, "ADDRESS=") == 0 ||
2402 strcmp (last_slash, "FAX=") == 0) {
2403 gst_tag_list_add (*p_taglist, GST_TAG_MERGE_APPEND,
2404 GST_TAG_CONTACT, val_post, NULL);
2405 matched = TRUE;
2406 }
2407 }
2408 }
2409 if (!matched)
2410 gst_tag_list_add (*p_taglist, GST_TAG_MERGE_APPEND,
2411 GST_TAG_EXTENDED_COMMENT, val, NULL);
2412 g_free (val_post);
2413 g_free (val_pre);
2414 g_free (val);
2415 }
2416 }
2417 }
2418 gst_tag_list_unref (child_taglist);
2419 }
2420
2421 g_free (tag);
2422 g_free (value);
2423 g_free (name_with_parent);
2424
2425 return ret;
2426 }
2427
2428
2429 static void
gst_matroska_read_common_count_streams(GstMatroskaReadCommon * common,gint * a,gint * v,gint * s)2430 gst_matroska_read_common_count_streams (GstMatroskaReadCommon * common,
2431 gint * a, gint * v, gint * s)
2432 {
2433 gint i;
2434 gint video_streams = 0, audio_streams = 0, subtitle_streams = 0;
2435
2436 for (i = 0; i < common->src->len; i++) {
2437 GstMatroskaTrackContext *stream;
2438
2439 stream = g_ptr_array_index (common->src, i);
2440 if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO)
2441 video_streams += 1;
2442 else if (stream->type == GST_MATROSKA_TRACK_TYPE_AUDIO)
2443 audio_streams += 1;
2444 else if (stream->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE)
2445 subtitle_streams += 1;
2446 }
2447 *v = video_streams;
2448 *a = audio_streams;
2449 *s = subtitle_streams;
2450 }
2451
2452
2453 static void
gst_matroska_read_common_apply_target_type_foreach(const GstTagList * list,const gchar * tag,gpointer user_data)2454 gst_matroska_read_common_apply_target_type_foreach (const GstTagList * list,
2455 const gchar * tag, gpointer user_data)
2456 {
2457 guint vallen;
2458 guint i;
2459 TargetTypeContext *ctx = (TargetTypeContext *) user_data;
2460
2461 vallen = gst_tag_list_get_tag_size (list, tag);
2462 if (vallen == 0)
2463 return;
2464
2465 for (i = 0; i < vallen; i++) {
2466 const GValue *val_ref;
2467
2468 val_ref = gst_tag_list_get_value_index (list, tag, i);
2469 if (val_ref == NULL)
2470 continue;
2471
2472 /* TODO: use the optional ctx->target_type somehow */
2473 if (strcmp (tag, GST_TAG_TITLE) == 0) {
2474 if (ctx->target_type_value >= 70 && !ctx->audio_only) {
2475 gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
2476 GST_TAG_SHOW_NAME, val_ref);
2477 continue;
2478 } else if (ctx->target_type_value >= 50) {
2479 gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
2480 GST_TAG_TITLE, val_ref);
2481 continue;
2482 }
2483 } else if (strcmp (tag, GST_TAG_TITLE_SORTNAME) == 0) {
2484 if (ctx->target_type_value >= 70 && !ctx->audio_only) {
2485 gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
2486 GST_TAG_SHOW_SORTNAME, val_ref);
2487 continue;
2488 } else if (ctx->target_type_value >= 50) {
2489 gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
2490 GST_TAG_TITLE_SORTNAME, val_ref);
2491 continue;
2492 }
2493 } else if (strcmp (tag, GST_TAG_ARTIST) == 0) {
2494 if (ctx->target_type_value >= 50) {
2495 gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
2496 GST_TAG_ARTIST, val_ref);
2497 continue;
2498 }
2499 } else if (strcmp (tag, GST_TAG_ARTIST_SORTNAME) == 0) {
2500 if (ctx->target_type_value >= 50) {
2501 gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
2502 GST_TAG_ARTIST_SORTNAME, val_ref);
2503 continue;
2504 }
2505 } else if (strcmp (tag, GST_TAG_TRACK_COUNT) == 0) {
2506 if (ctx->target_type_value >= 60) {
2507 gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
2508 GST_TAG_ALBUM_VOLUME_COUNT, val_ref);
2509 continue;
2510 }
2511 } else if (strcmp (tag, GST_TAG_TRACK_NUMBER) == 0) {
2512 if (ctx->target_type_value >= 60 && !ctx->audio_only) {
2513 gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
2514 GST_TAG_SHOW_SEASON_NUMBER, val_ref);
2515 continue;
2516 } else if (ctx->target_type_value >= 50 && !ctx->audio_only) {
2517 gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
2518 GST_TAG_SHOW_EPISODE_NUMBER, val_ref);
2519 continue;
2520 } else if (ctx->target_type_value >= 50) {
2521 gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
2522 GST_TAG_ALBUM_VOLUME_NUMBER, val_ref);
2523 continue;
2524 }
2525 }
2526 gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND, tag, val_ref);
2527 }
2528 }
2529
2530
2531 static GstTagList *
gst_matroska_read_common_apply_target_type(GstMatroskaReadCommon * common,GstTagList * taglist,guint64 target_type_value,gchar * target_type)2532 gst_matroska_read_common_apply_target_type (GstMatroskaReadCommon * common,
2533 GstTagList * taglist, guint64 target_type_value, gchar * target_type)
2534 {
2535 TargetTypeContext ctx;
2536 gint a = 0;
2537 gint v = 0;
2538 gint s = 0;
2539
2540 gst_matroska_read_common_count_streams (common, &a, &v, &s);
2541
2542 ctx.audio_only = (a > 0 && v == 0 && s == 0);
2543 ctx.result = gst_tag_list_new_empty ();
2544 ctx.target_type_value = target_type_value;
2545 ctx.target_type = target_type;
2546
2547 gst_tag_list_foreach (taglist,
2548 gst_matroska_read_common_apply_target_type_foreach, &ctx);
2549
2550 gst_tag_list_unref (taglist);
2551 return ctx.result;
2552 }
2553
2554
2555 static GstFlowReturn
gst_matroska_read_common_parse_metadata_id_tag(GstMatroskaReadCommon * common,GstEbmlRead * ebml,GstTagList ** p_taglist)2556 gst_matroska_read_common_parse_metadata_id_tag (GstMatroskaReadCommon * common,
2557 GstEbmlRead * ebml, GstTagList ** p_taglist)
2558 {
2559 guint32 id;
2560 GstFlowReturn ret;
2561 GArray *chapter_targets, *edition_targets, *track_targets;
2562 GstTagList *taglist;
2563 GList *cur, *internal_cur;
2564 guint64 target_type_value = 50;
2565 gchar *target_type = NULL;
2566
2567 DEBUG_ELEMENT_START (common, ebml, "Tag");
2568
2569 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
2570 DEBUG_ELEMENT_STOP (common, ebml, "Tag", ret);
2571 return ret;
2572 }
2573
2574 edition_targets = g_array_new (FALSE, FALSE, sizeof (guint64));
2575 chapter_targets = g_array_new (FALSE, FALSE, sizeof (guint64));
2576 track_targets = g_array_new (FALSE, FALSE, sizeof (guint64));
2577 taglist = gst_tag_list_new_empty ();
2578 target_type = NULL;
2579
2580 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
2581 /* read all sub-entries */
2582
2583 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
2584 break;
2585
2586 switch (id) {
2587 case GST_MATROSKA_ID_SIMPLETAG:
2588 ret = gst_matroska_read_common_parse_metadata_id_simple_tag (common,
2589 ebml, &taglist, NULL);
2590 break;
2591
2592 case GST_MATROSKA_ID_TARGETS:
2593 g_free (target_type);
2594 target_type = NULL;
2595 target_type_value = 50;
2596 ret = gst_matroska_read_common_parse_metadata_targets (common, ebml,
2597 edition_targets, chapter_targets, track_targets,
2598 &target_type_value, &target_type);
2599 break;
2600
2601 default:
2602 ret = gst_matroska_read_common_parse_skip (common, ebml, "Tag", id);
2603 break;
2604 }
2605 }
2606
2607 DEBUG_ELEMENT_STOP (common, ebml, "Tag", ret);
2608
2609 taglist = gst_matroska_read_common_apply_target_type (common, taglist,
2610 target_type_value, target_type);
2611 g_free (target_type);
2612
2613 /* if tag is chapter/edition specific - try to find that entry */
2614 if (G_UNLIKELY (chapter_targets->len > 0 || edition_targets->len > 0 ||
2615 track_targets->len > 0)) {
2616 gint i;
2617 if (chapter_targets->len > 0 || edition_targets->len > 0) {
2618 if (common->toc == NULL)
2619 GST_WARNING_OBJECT (common->sinkpad,
2620 "Found chapter/edition specific tag, but TOC is not present");
2621 else {
2622 cur = gst_toc_get_entries (common->toc);
2623 internal_cur = gst_toc_get_entries (common->internal_toc);
2624 while (cur != NULL && internal_cur != NULL) {
2625 gst_matroska_read_common_parse_toc_tag (cur->data, internal_cur->data,
2626 edition_targets, chapter_targets, taglist);
2627 cur = cur->next;
2628 internal_cur = internal_cur->next;
2629 }
2630 common->toc_updated = TRUE;
2631 }
2632 }
2633 for (i = 0; i < track_targets->len; i++) {
2634 gint j;
2635 gboolean found = FALSE;
2636 guint64 tgt = g_array_index (track_targets, guint64, i);
2637
2638 for (j = 0; j < common->src->len; j++) {
2639 GstMatroskaTrackContext *stream = g_ptr_array_index (common->src, j);
2640
2641 if (stream->uid == tgt) {
2642 gst_tag_list_insert (stream->tags, taglist, GST_TAG_MERGE_REPLACE);
2643 stream->tags_changed = TRUE;
2644 found = TRUE;
2645 }
2646 }
2647 if (!found) {
2648 /* Cache the track taglist: possibly belongs to a track that will be parsed
2649 later in gst_matroska_demux.c:gst_matroska_demux_add_stream (...) */
2650 gpointer track_uid = GUINT_TO_POINTER (tgt);
2651 GstTagList *cached_taglist =
2652 g_hash_table_lookup (common->cached_track_taglists, track_uid);
2653 if (cached_taglist)
2654 gst_tag_list_insert (cached_taglist, taglist, GST_TAG_MERGE_REPLACE);
2655 else {
2656 gst_tag_list_ref (taglist);
2657 g_hash_table_insert (common->cached_track_taglists, track_uid,
2658 taglist);
2659 }
2660 GST_DEBUG_OBJECT (common->sinkpad,
2661 "Found track-specific tag(s), but track %" G_GUINT64_FORMAT
2662 " is not known yet, caching", tgt);
2663 }
2664 }
2665 } else
2666 gst_tag_list_insert (*p_taglist, taglist, GST_TAG_MERGE_APPEND);
2667
2668 gst_tag_list_unref (taglist);
2669 g_array_unref (chapter_targets);
2670 g_array_unref (edition_targets);
2671 g_array_unref (track_targets);
2672
2673 return ret;
2674 }
2675
2676 GstFlowReturn
gst_matroska_read_common_parse_metadata(GstMatroskaReadCommon * common,GstElement * el,GstEbmlRead * ebml)2677 gst_matroska_read_common_parse_metadata (GstMatroskaReadCommon * common,
2678 GstElement * el, GstEbmlRead * ebml)
2679 {
2680 GstTagList *taglist;
2681 GstFlowReturn ret = GST_FLOW_OK;
2682 guint32 id;
2683 GList *l;
2684 guint64 curpos;
2685
2686 /* Make sure we don't parse a tags element twice and
2687 * post it's tags twice */
2688 curpos = gst_ebml_read_get_pos (ebml);
2689 for (l = common->tags_parsed; l; l = l->next) {
2690 guint64 *pos = l->data;
2691
2692 if (*pos == curpos) {
2693 GST_DEBUG_OBJECT (common->sinkpad,
2694 "Skipping already parsed Tags at offset %" G_GUINT64_FORMAT, curpos);
2695 return GST_FLOW_OK;
2696 }
2697 }
2698
2699 common->tags_parsed =
2700 g_list_prepend (common->tags_parsed, g_slice_new (guint64));
2701 *((guint64 *) common->tags_parsed->data) = curpos;
2702 /* fall-through */
2703
2704 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
2705 DEBUG_ELEMENT_STOP (common, ebml, "Tags", ret);
2706 return ret;
2707 }
2708
2709 taglist = gst_tag_list_new_empty ();
2710 gst_tag_list_set_scope (taglist, GST_TAG_SCOPE_GLOBAL);
2711 common->toc_updated = FALSE;
2712
2713 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
2714 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
2715 break;
2716
2717 switch (id) {
2718 case GST_MATROSKA_ID_TAG:
2719 ret = gst_matroska_read_common_parse_metadata_id_tag (common, ebml,
2720 &taglist);
2721 break;
2722
2723 default:
2724 ret = gst_matroska_read_common_parse_skip (common, ebml, "Tags", id);
2725 break;
2726 /* FIXME: Use to limit the tags to specific pads */
2727 }
2728 }
2729
2730 DEBUG_ELEMENT_STOP (common, ebml, "Tags", ret);
2731
2732 if (G_LIKELY (!gst_tag_list_is_empty (taglist)))
2733 gst_matroska_read_common_found_global_tag (common, el, taglist);
2734 else
2735 gst_tag_list_unref (taglist);
2736
2737 return ret;
2738 }
2739
2740 static GstFlowReturn
gst_matroska_read_common_peek_adapter(GstMatroskaReadCommon * common,guint peek,const guint8 ** data)2741 gst_matroska_read_common_peek_adapter (GstMatroskaReadCommon * common, guint
2742 peek, const guint8 ** data)
2743 {
2744 /* Caller needs to gst_adapter_unmap. */
2745 *data = gst_adapter_map (common->adapter, peek);
2746 if (*data == NULL)
2747 return GST_FLOW_EOS;
2748
2749 return GST_FLOW_OK;
2750 }
2751
2752 /*
2753 * Calls pull_range for (offset,size) without advancing our offset
2754 */
2755 GstFlowReturn
gst_matroska_read_common_peek_bytes(GstMatroskaReadCommon * common,guint64 offset,guint size,GstBuffer ** p_buf,guint8 ** bytes)2756 gst_matroska_read_common_peek_bytes (GstMatroskaReadCommon * common, guint64
2757 offset, guint size, GstBuffer ** p_buf, guint8 ** bytes)
2758 {
2759 GstFlowReturn ret;
2760
2761 /* Caching here actually makes much less difference than one would expect.
2762 * We do it mainly to avoid pulling buffers of 1 byte all the time */
2763 if (common->cached_buffer) {
2764 guint64 cache_offset = GST_BUFFER_OFFSET (common->cached_buffer);
2765 gsize cache_size = gst_buffer_get_size (common->cached_buffer);
2766
2767 if (cache_offset <= common->offset &&
2768 (common->offset + size) <= (cache_offset + cache_size)) {
2769 if (p_buf)
2770 *p_buf = gst_buffer_copy_region (common->cached_buffer,
2771 GST_BUFFER_COPY_ALL, common->offset - cache_offset, size);
2772 if (bytes) {
2773 if (!common->cached_data) {
2774 gst_buffer_map (common->cached_buffer, &common->cached_map,
2775 GST_MAP_READ);
2776 common->cached_data = common->cached_map.data;
2777 }
2778 *bytes = common->cached_data + common->offset - cache_offset;
2779 }
2780 return GST_FLOW_OK;
2781 }
2782 /* not enough data in the cache, free cache and get a new one */
2783 if (common->cached_data) {
2784 gst_buffer_unmap (common->cached_buffer, &common->cached_map);
2785 common->cached_data = NULL;
2786 }
2787 gst_buffer_unref (common->cached_buffer);
2788 common->cached_buffer = NULL;
2789 }
2790
2791 /* refill the cache */
2792 ret = gst_pad_pull_range (common->sinkpad, common->offset,
2793 MAX (size, 64 * 1024), &common->cached_buffer);
2794 if (ret != GST_FLOW_OK) {
2795 common->cached_buffer = NULL;
2796 return ret;
2797 }
2798
2799 if (gst_buffer_get_size (common->cached_buffer) >= size) {
2800 if (p_buf)
2801 *p_buf = gst_buffer_copy_region (common->cached_buffer,
2802 GST_BUFFER_COPY_ALL, 0, size);
2803 if (bytes) {
2804 gst_buffer_map (common->cached_buffer, &common->cached_map, GST_MAP_READ);
2805 common->cached_data = common->cached_map.data;
2806 *bytes = common->cached_data;
2807 }
2808 return GST_FLOW_OK;
2809 }
2810
2811 /* Not possible to get enough data, try a last time with
2812 * requesting exactly the size we need */
2813 gst_buffer_unref (common->cached_buffer);
2814 common->cached_buffer = NULL;
2815
2816 ret =
2817 gst_pad_pull_range (common->sinkpad, common->offset, size,
2818 &common->cached_buffer);
2819 if (ret != GST_FLOW_OK) {
2820 GST_DEBUG_OBJECT (common->sinkpad, "pull_range returned %d", ret);
2821 if (p_buf)
2822 *p_buf = NULL;
2823 if (bytes)
2824 *bytes = NULL;
2825 return ret;
2826 }
2827
2828 if (gst_buffer_get_size (common->cached_buffer) < size) {
2829 GST_WARNING_OBJECT (common->sinkpad, "Dropping short buffer at offset %"
2830 G_GUINT64_FORMAT ": wanted %u bytes, got %" G_GSIZE_FORMAT " bytes",
2831 common->offset, size, gst_buffer_get_size (common->cached_buffer));
2832
2833 gst_buffer_unref (common->cached_buffer);
2834 common->cached_buffer = NULL;
2835 if (p_buf)
2836 *p_buf = NULL;
2837 if (bytes)
2838 *bytes = NULL;
2839 return GST_FLOW_EOS;
2840 }
2841
2842 if (p_buf)
2843 *p_buf = gst_buffer_copy_region (common->cached_buffer,
2844 GST_BUFFER_COPY_ALL, 0, size);
2845 if (bytes) {
2846 gst_buffer_map (common->cached_buffer, &common->cached_map, GST_MAP_READ);
2847 common->cached_data = common->cached_map.data;
2848 *bytes = common->cached_data;
2849 }
2850
2851 return GST_FLOW_OK;
2852 }
2853
2854 static GstFlowReturn
gst_matroska_read_common_peek_pull(GstMatroskaReadCommon * common,guint peek,guint8 ** data)2855 gst_matroska_read_common_peek_pull (GstMatroskaReadCommon * common, guint peek,
2856 guint8 ** data)
2857 {
2858 return gst_matroska_read_common_peek_bytes (common, common->offset, peek,
2859 NULL, data);
2860 }
2861
2862 GstFlowReturn
gst_matroska_read_common_peek_id_length_pull(GstMatroskaReadCommon * common,GstElement * el,guint32 * _id,guint64 * _length,guint * _needed)2863 gst_matroska_read_common_peek_id_length_pull (GstMatroskaReadCommon * common,
2864 GstElement * el, guint32 * _id, guint64 * _length, guint * _needed)
2865 {
2866 return gst_ebml_peek_id_length (_id, _length, _needed,
2867 (GstPeekData) gst_matroska_read_common_peek_pull, (gpointer) common, el,
2868 common->offset);
2869 }
2870
2871 GstFlowReturn
gst_matroska_read_common_peek_id_length_push(GstMatroskaReadCommon * common,GstElement * el,guint32 * _id,guint64 * _length,guint * _needed)2872 gst_matroska_read_common_peek_id_length_push (GstMatroskaReadCommon * common,
2873 GstElement * el, guint32 * _id, guint64 * _length, guint * _needed)
2874 {
2875 GstFlowReturn ret;
2876
2877 ret = gst_ebml_peek_id_length (_id, _length, _needed,
2878 (GstPeekData) gst_matroska_read_common_peek_adapter, (gpointer) common,
2879 el, common->offset);
2880
2881 gst_adapter_unmap (common->adapter);
2882
2883 return ret;
2884 }
2885
2886 static GstFlowReturn
gst_matroska_read_common_read_track_encoding(GstMatroskaReadCommon * common,GstEbmlRead * ebml,GstMatroskaTrackContext * context)2887 gst_matroska_read_common_read_track_encoding (GstMatroskaReadCommon * common,
2888 GstEbmlRead * ebml, GstMatroskaTrackContext * context)
2889 {
2890 GstMatroskaTrackEncoding enc = { 0, };
2891 GstFlowReturn ret;
2892 guint32 id;
2893
2894 DEBUG_ELEMENT_START (common, ebml, "ContentEncoding");
2895 /* Set default values */
2896 enc.scope = 1;
2897 /* All other default values are 0 */
2898
2899 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
2900 DEBUG_ELEMENT_STOP (common, ebml, "ContentEncoding", ret);
2901 return ret;
2902 }
2903
2904 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
2905 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
2906 break;
2907
2908 switch (id) {
2909 case GST_MATROSKA_ID_CONTENTENCODINGORDER:{
2910 guint64 num;
2911
2912 if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
2913 break;
2914
2915 if (!gst_matroska_read_common_encoding_order_unique (context->encodings,
2916 num)) {
2917 GST_ERROR_OBJECT (common->sinkpad,
2918 "ContentEncodingOrder %" G_GUINT64_FORMAT
2919 "is not unique for track %" G_GUINT64_FORMAT, num, context->num);
2920 ret = GST_FLOW_ERROR;
2921 break;
2922 }
2923
2924 GST_DEBUG_OBJECT (common->sinkpad,
2925 "ContentEncodingOrder: %" G_GUINT64_FORMAT, num);
2926 enc.order = num;
2927 break;
2928 }
2929 case GST_MATROSKA_ID_CONTENTENCODINGSCOPE:{
2930 guint64 num;
2931
2932 if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
2933 break;
2934
2935 if (num > 7 || num == 0) {
2936 GST_ERROR_OBJECT (common->sinkpad, "Invalid ContentEncodingScope %"
2937 G_GUINT64_FORMAT, num);
2938 ret = GST_FLOW_ERROR;
2939 break;
2940 }
2941
2942 GST_DEBUG_OBJECT (common->sinkpad,
2943 "ContentEncodingScope: %" G_GUINT64_FORMAT, num);
2944 enc.scope = num;
2945
2946 break;
2947 }
2948 case GST_MATROSKA_ID_CONTENTENCODINGTYPE:{
2949 guint64 num;
2950
2951 if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
2952 break;
2953
2954 if (num > 1) {
2955 GST_ERROR_OBJECT (common->sinkpad, "Invalid ContentEncodingType %"
2956 G_GUINT64_FORMAT, num);
2957 ret = GST_FLOW_ERROR;
2958 break;
2959 }
2960
2961 if ((!common->is_webm) && (num == GST_MATROSKA_ENCODING_ENCRYPTION)) {
2962 GST_ERROR_OBJECT (common->sinkpad,
2963 "Encrypted tracks are supported only in WebM");
2964 ret = GST_FLOW_ERROR;
2965 break;
2966 }
2967 GST_DEBUG_OBJECT (common->sinkpad,
2968 "ContentEncodingType: %" G_GUINT64_FORMAT, num);
2969 enc.type = num;
2970 break;
2971 }
2972 case GST_MATROSKA_ID_CONTENTCOMPRESSION:{
2973
2974 DEBUG_ELEMENT_START (common, ebml, "ContentCompression");
2975
2976 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
2977 break;
2978
2979 while (ret == GST_FLOW_OK &&
2980 gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
2981 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
2982 break;
2983
2984 switch (id) {
2985 case GST_MATROSKA_ID_CONTENTCOMPALGO:{
2986 guint64 num;
2987
2988 if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) {
2989 break;
2990 }
2991 if (num > 3) {
2992 GST_ERROR_OBJECT (common->sinkpad, "Invalid ContentCompAlgo %"
2993 G_GUINT64_FORMAT, num);
2994 ret = GST_FLOW_ERROR;
2995 break;
2996 }
2997 GST_DEBUG_OBJECT (common->sinkpad,
2998 "ContentCompAlgo: %" G_GUINT64_FORMAT, num);
2999 enc.comp_algo = num;
3000
3001 break;
3002 }
3003 case GST_MATROSKA_ID_CONTENTCOMPSETTINGS:{
3004 guint8 *data;
3005 guint64 size;
3006
3007 if ((ret =
3008 gst_ebml_read_binary (ebml, &id, &data,
3009 &size)) != GST_FLOW_OK) {
3010 break;
3011 }
3012 enc.comp_settings = data;
3013 enc.comp_settings_length = size;
3014 GST_DEBUG_OBJECT (common->sinkpad,
3015 "ContentCompSettings of size %" G_GUINT64_FORMAT, size);
3016 break;
3017 }
3018 default:
3019 GST_WARNING_OBJECT (common->sinkpad,
3020 "Unknown ContentCompression subelement 0x%x - ignoring", id);
3021 ret = gst_ebml_read_skip (ebml);
3022 break;
3023 }
3024 }
3025 DEBUG_ELEMENT_STOP (common, ebml, "ContentCompression", ret);
3026 break;
3027 }
3028
3029 case GST_MATROSKA_ID_CONTENTENCRYPTION:{
3030
3031 DEBUG_ELEMENT_START (common, ebml, "ContentEncryption");
3032
3033 if (enc.type != GST_MATROSKA_ENCODING_ENCRYPTION) {
3034 GST_WARNING_OBJECT (common->sinkpad,
3035 "Unexpected to have Content Encryption because it isn't encryption type");
3036 ret = GST_FLOW_ERROR;
3037 break;
3038 }
3039
3040 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
3041 break;
3042
3043 while (ret == GST_FLOW_OK &&
3044 gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
3045 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
3046 break;
3047
3048 switch (id) {
3049 case GST_MATROSKA_ID_CONTENTENCALGO:{
3050 guint64 num;
3051
3052 if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) {
3053 break;
3054 }
3055
3056 if (num > GST_MATROSKA_TRACK_ENCRYPTION_ALGORITHM_AES) {
3057 GST_ERROR_OBJECT (common->sinkpad, "Invalid ContentEncAlgo %"
3058 G_GUINT64_FORMAT, num);
3059 ret = GST_FLOW_ERROR;
3060 break;
3061 }
3062 GST_DEBUG_OBJECT (common->sinkpad,
3063 "ContentEncAlgo: %" G_GUINT64_FORMAT, num);
3064 enc.enc_algo = num;
3065
3066 break;
3067 }
3068 case GST_MATROSKA_ID_CONTENTENCAESSETTINGS:{
3069
3070 DEBUG_ELEMENT_START (common, ebml, "ContentEncAESSettings");
3071
3072 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
3073 break;
3074
3075 while (ret == GST_FLOW_OK &&
3076 gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
3077 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
3078 break;
3079
3080 switch (id) {
3081 case GST_MATROSKA_ID_AESSETTINGSCIPHERMODE:{
3082 guint64 num;
3083
3084 if ((ret =
3085 gst_ebml_read_uint (ebml, &id,
3086 &num)) != GST_FLOW_OK) {
3087 break;
3088 }
3089 if (num > 3) {
3090 GST_ERROR_OBJECT (common->sinkpad, "Invalid Cipher Mode %"
3091 G_GUINT64_FORMAT, num);
3092 ret = GST_FLOW_ERROR;
3093 break;
3094 }
3095 GST_DEBUG_OBJECT (common->sinkpad,
3096 "ContentEncAESSettings: %" G_GUINT64_FORMAT, num);
3097 enc.enc_cipher_mode = num;
3098 break;
3099 }
3100 default:
3101 GST_WARNING_OBJECT (common->sinkpad,
3102 "Unknown ContentEncAESSettings subelement 0x%x - ignoring",
3103 id);
3104 ret = gst_ebml_read_skip (ebml);
3105 break;
3106 }
3107 }
3108 DEBUG_ELEMENT_STOP (common, ebml, "ContentEncAESSettings", ret);
3109 break;
3110 }
3111
3112 case GST_MATROSKA_ID_CONTENTENCKEYID:{
3113 guint8 *data;
3114 guint64 size;
3115 GstBuffer *keyId_buf;
3116 GstEvent *event;
3117
3118 if ((ret =
3119 gst_ebml_read_binary (ebml, &id, &data,
3120 &size)) != GST_FLOW_OK) {
3121 break;
3122 }
3123 GST_DEBUG_OBJECT (common->sinkpad,
3124 "ContentEncrypt KeyID length : %" G_GUINT64_FORMAT, size);
3125 keyId_buf = gst_buffer_new_wrapped (data, size);
3126
3127 /* Push an event containing the Key ID into the queues of all streams. */
3128 /* system_id field is set to GST_PROTECTION_UNSPECIFIED_SYSTEM_ID because it isn't specified neither in WebM nor in Matroska spec. */
3129 event =
3130 gst_event_new_protection
3131 (GST_PROTECTION_UNSPECIFIED_SYSTEM_ID, keyId_buf,
3132 "matroskademux");
3133 GST_TRACE_OBJECT (common->sinkpad,
3134 "adding protection event for stream %d", context->index);
3135 g_queue_push_tail (&context->protection_event_queue, event);
3136
3137 context->protection_info =
3138 gst_structure_new ("application/x-cenc", "iv_size",
3139 G_TYPE_UINT, 8, "encrypted", G_TYPE_BOOLEAN, TRUE, "kid",
3140 GST_TYPE_BUFFER, keyId_buf, NULL);
3141
3142 gst_buffer_unref (keyId_buf);
3143 break;
3144 }
3145 default:
3146 GST_WARNING_OBJECT (common->sinkpad,
3147 "Unknown ContentEncryption subelement 0x%x - ignoring", id);
3148 ret = gst_ebml_read_skip (ebml);
3149 break;
3150 }
3151 }
3152 DEBUG_ELEMENT_STOP (common, ebml, "ContentEncryption", ret);
3153 break;
3154 }
3155 default:
3156 GST_WARNING_OBJECT (common->sinkpad,
3157 "Unknown ContentEncoding subelement 0x%x - ignoring", id);
3158 ret = gst_ebml_read_skip (ebml);
3159 break;
3160 }
3161 }
3162
3163 DEBUG_ELEMENT_STOP (common, ebml, "ContentEncoding", ret);
3164 if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)
3165 return ret;
3166
3167 /* TODO: Check if the combination of values is valid */
3168
3169 g_array_append_val (context->encodings, enc);
3170
3171 return ret;
3172 }
3173
3174 GstFlowReturn
gst_matroska_read_common_read_track_encodings(GstMatroskaReadCommon * common,GstEbmlRead * ebml,GstMatroskaTrackContext * context)3175 gst_matroska_read_common_read_track_encodings (GstMatroskaReadCommon * common,
3176 GstEbmlRead * ebml, GstMatroskaTrackContext * context)
3177 {
3178 GstFlowReturn ret;
3179 guint32 id;
3180
3181 DEBUG_ELEMENT_START (common, ebml, "ContentEncodings");
3182
3183 if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
3184 DEBUG_ELEMENT_STOP (common, ebml, "ContentEncodings", ret);
3185 return ret;
3186 }
3187
3188 context->encodings =
3189 g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaTrackEncoding), 1);
3190
3191 while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
3192 if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
3193 break;
3194
3195 switch (id) {
3196 case GST_MATROSKA_ID_CONTENTENCODING:
3197 ret = gst_matroska_read_common_read_track_encoding (common, ebml,
3198 context);
3199 break;
3200 default:
3201 GST_WARNING_OBJECT (common->sinkpad,
3202 "Unknown ContentEncodings subelement 0x%x - ignoring", id);
3203 ret = gst_ebml_read_skip (ebml);
3204 break;
3205 }
3206 }
3207
3208 DEBUG_ELEMENT_STOP (common, ebml, "ContentEncodings", ret);
3209 if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)
3210 return ret;
3211
3212 /* Sort encodings according to their order */
3213 g_array_sort (context->encodings,
3214 (GCompareFunc) gst_matroska_read_common_encoding_cmp);
3215
3216 return gst_matroska_decode_content_encodings (context->encodings);
3217 }
3218
3219 void
gst_matroska_read_common_free_parsed_el(gpointer mem,gpointer user_data)3220 gst_matroska_read_common_free_parsed_el (gpointer mem, gpointer user_data)
3221 {
3222 g_slice_free (guint64, mem);
3223 }
3224
3225 void
gst_matroska_read_common_init(GstMatroskaReadCommon * ctx)3226 gst_matroska_read_common_init (GstMatroskaReadCommon * ctx)
3227 {
3228 ctx->src = NULL;
3229 ctx->writing_app = NULL;
3230 ctx->muxing_app = NULL;
3231 ctx->index = NULL;
3232 ctx->global_tags = NULL;
3233 ctx->adapter = gst_adapter_new ();
3234 ctx->toc = NULL;
3235 ctx->internal_toc = NULL;
3236 ctx->toc_updated = FALSE;
3237 ctx->cached_track_taglists =
3238 g_hash_table_new_full (NULL, NULL, NULL,
3239 (GDestroyNotify) gst_tag_list_unref);
3240 }
3241
3242 void
gst_matroska_read_common_finalize(GstMatroskaReadCommon * ctx)3243 gst_matroska_read_common_finalize (GstMatroskaReadCommon * ctx)
3244 {
3245 if (ctx->src) {
3246 g_ptr_array_free (ctx->src, TRUE);
3247 ctx->src = NULL;
3248 }
3249
3250 if (ctx->global_tags) {
3251 gst_tag_list_unref (ctx->global_tags);
3252 ctx->global_tags = NULL;
3253 }
3254
3255 if (ctx->toc) {
3256 gst_toc_unref (ctx->toc);
3257 ctx->toc = NULL;
3258 }
3259 if (ctx->internal_toc) {
3260 gst_toc_unref (ctx->internal_toc);
3261 ctx->internal_toc = NULL;
3262 }
3263
3264 ctx->toc_updated = FALSE;
3265
3266 g_object_unref (ctx->adapter);
3267 g_hash_table_remove_all (ctx->cached_track_taglists);
3268 g_hash_table_unref (ctx->cached_track_taglists);
3269
3270 }
3271
3272 void
gst_matroska_read_common_reset(GstElement * element,GstMatroskaReadCommon * ctx)3273 gst_matroska_read_common_reset (GstElement * element,
3274 GstMatroskaReadCommon * ctx)
3275 {
3276 guint i;
3277
3278 GST_LOG_OBJECT (ctx->sinkpad, "resetting read context");
3279
3280 /* reset input */
3281 ctx->state = GST_MATROSKA_READ_STATE_START;
3282
3283 /* clean up existing streams if any */
3284 if (ctx->src) {
3285 g_assert (ctx->src->len == ctx->num_streams);
3286 for (i = 0; i < ctx->src->len; i++) {
3287 GstMatroskaTrackContext *context = g_ptr_array_index (ctx->src, i);
3288
3289 if (context->pad != NULL)
3290 gst_element_remove_pad (element, context->pad);
3291
3292 gst_matroska_track_free (context);
3293 }
3294 g_ptr_array_free (ctx->src, TRUE);
3295 }
3296 ctx->src = g_ptr_array_new ();
3297 ctx->num_streams = 0;
3298
3299 /* reset media info */
3300 g_free (ctx->writing_app);
3301 ctx->writing_app = NULL;
3302 g_free (ctx->muxing_app);
3303 ctx->muxing_app = NULL;
3304
3305 /* reset stream type */
3306 ctx->is_webm = FALSE;
3307 ctx->has_video = FALSE;
3308
3309 /* reset indexes */
3310 if (ctx->index) {
3311 g_array_free (ctx->index, TRUE);
3312 ctx->index = NULL;
3313 }
3314
3315 /* reset timers */
3316 ctx->time_scale = 1000000;
3317 ctx->created = G_MININT64;
3318
3319 /* cues/tracks/segmentinfo */
3320 ctx->index_parsed = FALSE;
3321 ctx->segmentinfo_parsed = FALSE;
3322 ctx->attachments_parsed = FALSE;
3323 ctx->chapters_parsed = FALSE;
3324
3325 /* tags */
3326 ctx->global_tags_changed = FALSE;
3327 g_list_foreach (ctx->tags_parsed,
3328 (GFunc) gst_matroska_read_common_free_parsed_el, NULL);
3329 g_list_free (ctx->tags_parsed);
3330 ctx->tags_parsed = NULL;
3331 if (ctx->global_tags) {
3332 gst_tag_list_unref (ctx->global_tags);
3333 }
3334 ctx->global_tags = gst_tag_list_new_empty ();
3335 gst_tag_list_set_scope (ctx->global_tags, GST_TAG_SCOPE_GLOBAL);
3336
3337 gst_segment_init (&ctx->segment, GST_FORMAT_TIME);
3338 ctx->offset = 0;
3339 ctx->start_resync_offset = -1;
3340 ctx->state_to_restore = -1;
3341
3342 if (ctx->cached_buffer) {
3343 if (ctx->cached_data) {
3344 gst_buffer_unmap (ctx->cached_buffer, &ctx->cached_map);
3345 ctx->cached_data = NULL;
3346 }
3347 gst_buffer_unref (ctx->cached_buffer);
3348 ctx->cached_buffer = NULL;
3349 }
3350
3351 /* free chapters TOC if any */
3352 if (ctx->toc) {
3353 gst_toc_unref (ctx->toc);
3354 ctx->toc = NULL;
3355 }
3356 if (ctx->internal_toc) {
3357 gst_toc_unref (ctx->internal_toc);
3358 ctx->internal_toc = NULL;
3359 }
3360 ctx->toc_updated = FALSE;
3361 }
3362
3363 /* call with object lock held */
3364 void
gst_matroska_read_common_reset_streams(GstMatroskaReadCommon * common,GstClockTime time,gboolean full)3365 gst_matroska_read_common_reset_streams (GstMatroskaReadCommon * common,
3366 GstClockTime time, gboolean full)
3367 {
3368 gint i;
3369
3370 GST_DEBUG_OBJECT (common->sinkpad, "resetting stream state");
3371
3372 g_assert (common->src->len == common->num_streams);
3373 for (i = 0; i < common->src->len; i++) {
3374 GstMatroskaTrackContext *context = g_ptr_array_index (common->src, i);
3375 context->pos = time;
3376 context->set_discont = TRUE;
3377 context->eos = FALSE;
3378 context->from_time = GST_CLOCK_TIME_NONE;
3379 if (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
3380 GstMatroskaTrackVideoContext *videocontext =
3381 (GstMatroskaTrackVideoContext *) context;
3382 /* demux object lock held by caller */
3383 videocontext->earliest_time = GST_CLOCK_TIME_NONE;
3384 }
3385 }
3386 }
3387
3388 gboolean
gst_matroska_read_common_tracknumber_unique(GstMatroskaReadCommon * common,guint64 num)3389 gst_matroska_read_common_tracknumber_unique (GstMatroskaReadCommon * common,
3390 guint64 num)
3391 {
3392 gint i;
3393
3394 g_assert (common->src->len == common->num_streams);
3395 for (i = 0; i < common->src->len; i++) {
3396 GstMatroskaTrackContext *context = g_ptr_array_index (common->src, i);
3397
3398 if (context->num == num)
3399 return FALSE;
3400 }
3401
3402 return TRUE;
3403 }
3404