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