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