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