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