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