• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4  * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5  * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6  * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7  * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8  * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9  * Copyright (C) <2013> Intel Corporation
10  * Copyright (C) <2014> Centricular Ltd
11  * Copyright (C) <2015> YouView TV Ltd.
12  * Copyright (C) <2016> British Broadcasting Corporation
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Library General Public
16  * License as published by the Free Software Foundation; either
17  * version 2 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU Library General Public
25  * License along with this library; if not, write to the
26  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27  * Boston, MA 02110-1301, USA.
28  */
29 
30 /**
31  * SECTION:element-qtdemux
32  * @title: qtdemux
33  *
34  * Demuxes a .mov file into raw or compressed audio and/or video streams.
35  *
36  * This element supports both push and pull-based scheduling, depending on the
37  * capabilities of the upstream elements.
38  *
39  * ## Example launch line
40  * |[
41  * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux  demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
42  * ]| Play (parse and decode) a .mov file and try to output it to
43  * an automatically detected soundcard and videosink. If the MOV file contains
44  * compressed audio or video data, this will only work if you have the
45  * right decoder elements/plugins installed.
46  *
47  */
48 
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
52 
53 #include "gst/gst-i18n-plugin.h"
54 
55 #include <glib/gprintf.h>
56 #include <gst/base/base.h>
57 #include <gst/tag/tag.h>
58 #include <gst/audio/audio.h>
59 #include <gst/riff/riff.h>
60 #include <gst/pbutils/pbutils.h>
61 
62 #include "gstisomp4elements.h"
63 #include "qtatomparser.h"
64 #include "qtdemux_types.h"
65 #include "qtdemux_dump.h"
66 #include "fourcc.h"
67 #include "descriptors.h"
68 #include "qtdemux_lang.h"
69 #include "qtdemux.h"
70 #include "qtpalette.h"
71 #include "qtdemux_tags.h"
72 #include "qtdemux_tree.h"
73 #include "qtdemux-webvtt.h"
74 
75 #include <stdlib.h>
76 #include <string.h>
77 
78 #include <math.h>
79 #include <gst/math-compat.h>
80 
81 #ifdef HAVE_ZLIB
82 # include <zlib.h>
83 #endif
84 
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
87 
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
90 
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95     QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96 
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
98 
99 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
100 
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
102 
103 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
104 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
105 #define QTDEMUX_NTH_STREAM(demux,idx) \
106    QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
107 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
108    QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
109 
110 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
111 
112 GST_DEBUG_CATEGORY (qtdemux_debug);
113 #define GST_CAT_DEFAULT qtdemux_debug
114 
115 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
116 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
117 
118 /* Macros for converting to/from timescale */
119 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
121 
122 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
124 
125 /* timestamp is the DTS */
126 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127 /* timestamp + offset + cslg_shift is the outgoing PTS */
128 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129 /* timestamp + offset is the PTS used for internal seek calculations */
130 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
133 
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
135 
136 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
137 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
138     GST_TRACE("Locking from thread %p", g_thread_self()); \
139     g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
140     GST_TRACE("Locked from thread %p", g_thread_self()); \
141  } G_STMT_END
142 
143 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
144     GST_TRACE("Unlocking from thread %p", g_thread_self()); \
145     g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
146  } G_STMT_END
147 
148 /*
149  * Quicktime has tracks and segments. A track is a continuous piece of
150  * multimedia content. The track is not always played from start to finish but
151  * instead, pieces of the track are 'cut out' and played in sequence. This is
152  * what the segments do.
153  *
154  * Inside the track we have keyframes (K) and delta frames. The track has its
155  * own timing, which starts from 0 and extends to end. The position in the track
156  * is called the media_time.
157  *
158  * The segments now describe the pieces that should be played from this track
159  * and are basically tuples of media_time/duration/rate entries. We can have
160  * multiple segments and they are all played after one another. An example:
161  *
162  * segment 1: media_time: 1 second, duration: 1 second, rate 1
163  * segment 2: media_time: 3 second, duration: 2 second, rate 2
164  *
165  * To correctly play back this track, one must play: 1 second of media starting
166  * from media_time 1 followed by 2 seconds of media starting from media_time 3
167  * at a rate of 2.
168  *
169  * Each of the segments will be played at a specific time, the first segment at
170  * time 0, the second one after the duration of the first one, etc.. Note that
171  * the time in resulting playback is not identical to the media_time of the
172  * track anymore.
173  *
174  * Visually, assuming the track has 4 second of media_time:
175  *
176  *                (a)                   (b)          (c)              (d)
177  *         .-----------------------------------------------------------.
178  * track:  | K.....K.........K........K.......K.......K...........K... |
179  *         '-----------------------------------------------------------'
180  *         0              1              2              3              4
181  *           .------------^              ^   .----------^              ^
182  *          /              .-------------'  /       .------------------'
183  *         /              /          .-----'       /
184  *         .--------------.         .--------------.
185  *         | segment 1    |         | segment 2    |
186  *         '--------------'         '--------------'
187  *
188  * The challenge here is to cut out the right pieces of the track for each of
189  * the playback segments. This fortunately can easily be done with the SEGMENT
190  * events of GStreamer.
191  *
192  * For playback of segment 1, we need to provide the decoder with the keyframe
193  * (a), in the above figure, but we must instruct it only to output the decoded
194  * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
195  * position set to the time of the segment: 0.
196  *
197  * We then proceed to push data from keyframe (a) to frame (b). The decoder
198  * decodes but clips all before media_time 1.
199  *
200  * After finishing a segment, we push out a new SEGMENT event with the clipping
201  * boundaries of the new data.
202  *
203  * This is a good usecase for the GStreamer accumulated SEGMENT events.
204  */
205 
206 struct _QtDemuxSegment
207 {
208   /* global time and duration, all gst time */
209   GstClockTime time;
210   GstClockTime stop_time;
211   GstClockTime duration;
212   /* media time of trak, all gst time */
213   GstClockTime media_start;
214   GstClockTime media_stop;
215   gdouble rate;
216   /* Media start time in trak timescale units */
217   guint32 trak_media_start;
218 };
219 
220 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
221 
222 /* Used with fragmented MP4 files (mfra atom) */
223 struct _QtDemuxRandomAccessEntry
224 {
225   GstClockTime ts;
226   guint64 moof_offset;
227 };
228 
229 
230 /* Contains properties and cryptographic info for a set of samples from a
231  * track protected using Common Encryption (cenc) */
232 struct _QtDemuxCencSampleSetInfo
233 {
234   GstStructure *default_properties;
235 
236   /* @crypto_info holds one GstStructure per sample */
237   GPtrArray *crypto_info;
238 };
239 
240 struct _QtDemuxAavdEncryptionInfo
241 {
242   GstStructure *default_properties;
243 };
244 
245 static const gchar *
qt_demux_state_string(enum QtDemuxState state)246 qt_demux_state_string (enum QtDemuxState state)
247 {
248   switch (state) {
249     case QTDEMUX_STATE_INITIAL:
250       return "<INITIAL>";
251     case QTDEMUX_STATE_HEADER:
252       return "<HEADER>";
253     case QTDEMUX_STATE_MOVIE:
254       return "<MOVIE>";
255     case QTDEMUX_STATE_BUFFER_MDAT:
256       return "<BUFFER_MDAT>";
257     default:
258       return "<UNKNOWN>";
259   }
260 }
261 
262 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
263 
264 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
265 
266 static GstStaticPadTemplate gst_qtdemux_sink_template =
267     GST_STATIC_PAD_TEMPLATE ("sink",
268     GST_PAD_SINK,
269     GST_PAD_ALWAYS,
270     GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
271         "application/x-3gp")
272     );
273 
274 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
275 GST_STATIC_PAD_TEMPLATE ("video_%u",
276     GST_PAD_SRC,
277     GST_PAD_SOMETIMES,
278     GST_STATIC_CAPS_ANY);
279 
280 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
281 GST_STATIC_PAD_TEMPLATE ("audio_%u",
282     GST_PAD_SRC,
283     GST_PAD_SOMETIMES,
284     GST_STATIC_CAPS_ANY);
285 
286 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
287 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
288     GST_PAD_SRC,
289     GST_PAD_SOMETIMES,
290     GST_STATIC_CAPS_ANY);
291 
292 #define gst_qtdemux_parent_class parent_class
293 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
294 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
295     GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
296 
297 static void gst_qtdemux_dispose (GObject * object);
298 static void gst_qtdemux_finalize (GObject * object);
299 
300 static guint32
301 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
302     GstClockTime media_time);
303 static guint32
304 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
305     QtDemuxStream * str, gint64 media_offset);
306 
307 #if 0
308 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
309 static GstIndex *gst_qtdemux_get_index (GstElement * element);
310 #endif
311 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
312     GstStateChange transition);
313 static void gst_qtdemux_set_context (GstElement * element,
314     GstContext * context);
315 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
316 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
317     GstObject * parent, GstPadMode mode, gboolean active);
318 
319 static void gst_qtdemux_loop (GstPad * pad);
320 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
321     GstBuffer * inbuf);
322 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
323     GstEvent * event);
324 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
325     GstQuery * query);
326 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
327 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
328     QtDemuxStream * stream);
329 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
330     QtDemuxStream * stream);
331 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
332     gboolean force);
333 
334 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
335 
336 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
337     const guint8 * buffer, guint length);
338 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
339     const guint8 * buffer, guint length);
340 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
341 
342 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
343     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
344     GstTagList * list);
345 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
346     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
347     const guint8 * stsd_entry_data, gchar ** codec_name);
348 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
349     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
350     const guint8 * data, int len, gchar ** codec_name);
351 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
352     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
353     gchar ** codec_name);
354 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
355     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
356     const guint8 * stsd_entry_data, gchar ** codec_name);
357 
358 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
359     QtDemuxStream * stream, guint32 n);
360 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
361 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
362 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
363 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
364 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
365 static void qtdemux_do_allocation (QtDemuxStream * stream,
366     GstQTDemux * qtdemux);
367 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
368     QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
369 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
370     QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
371     GstClockTime * _start, GstClockTime * _stop);
372 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
373     QtDemuxStream * stream, gint segment_index, GstClockTime pos);
374 
375 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
376 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
377 
378 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
379 
380 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
381     QtDemuxStream * stream, guint sample_index);
382 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
383     const gchar * id);
384 static void qtdemux_gst_structure_free (GstStructure * gststructure);
385 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
386 
387 static void
gst_qtdemux_class_init(GstQTDemuxClass * klass)388 gst_qtdemux_class_init (GstQTDemuxClass * klass)
389 {
390   GObjectClass *gobject_class;
391   GstElementClass *gstelement_class;
392 
393   gobject_class = (GObjectClass *) klass;
394   gstelement_class = (GstElementClass *) klass;
395 
396   parent_class = g_type_class_peek_parent (klass);
397 
398   gobject_class->dispose = gst_qtdemux_dispose;
399   gobject_class->finalize = gst_qtdemux_finalize;
400 
401   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
402 #if 0
403   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
404   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
405 #endif
406   gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
407 
408   gst_tag_register_musicbrainz_tags ();
409 
410   gst_element_class_add_static_pad_template (gstelement_class,
411       &gst_qtdemux_sink_template);
412   gst_element_class_add_static_pad_template (gstelement_class,
413       &gst_qtdemux_videosrc_template);
414   gst_element_class_add_static_pad_template (gstelement_class,
415       &gst_qtdemux_audiosrc_template);
416   gst_element_class_add_static_pad_template (gstelement_class,
417       &gst_qtdemux_subsrc_template);
418   gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
419       "Codec/Demuxer",
420       "Demultiplex a QuickTime file into audio and video streams",
421       "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
422 
423   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
424   gst_riff_init ();
425 }
426 
427 static void
gst_qtdemux_init(GstQTDemux * qtdemux)428 gst_qtdemux_init (GstQTDemux * qtdemux)
429 {
430   qtdemux->sinkpad =
431       gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
432   gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
433   gst_pad_set_activatemode_function (qtdemux->sinkpad,
434       qtdemux_sink_activate_mode);
435   gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
436   gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
437   gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
438   gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
439 
440   qtdemux->adapter = gst_adapter_new ();
441   g_queue_init (&qtdemux->protection_event_queue);
442   qtdemux->flowcombiner = gst_flow_combiner_new ();
443   g_mutex_init (&qtdemux->expose_lock);
444 
445   qtdemux->active_streams = g_ptr_array_new_with_free_func
446       ((GDestroyNotify) gst_qtdemux_stream_unref);
447   qtdemux->old_streams = g_ptr_array_new_with_free_func
448       ((GDestroyNotify) gst_qtdemux_stream_unref);
449 
450   GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
451 
452   gst_qtdemux_reset (qtdemux, TRUE);
453 }
454 
455 static void
gst_qtdemux_finalize(GObject * object)456 gst_qtdemux_finalize (GObject * object)
457 {
458   GstQTDemux *qtdemux = GST_QTDEMUX (object);
459 
460   g_free (qtdemux->redirect_location);
461 
462   G_OBJECT_CLASS (parent_class)->finalize (object);
463 }
464 
465 static void
gst_qtdemux_dispose(GObject * object)466 gst_qtdemux_dispose (GObject * object)
467 {
468   GstQTDemux *qtdemux = GST_QTDEMUX (object);
469 
470   if (qtdemux->adapter) {
471     g_object_unref (G_OBJECT (qtdemux->adapter));
472     qtdemux->adapter = NULL;
473   }
474   gst_tag_list_unref (qtdemux->tag_list);
475   gst_flow_combiner_free (qtdemux->flowcombiner);
476   g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
477       NULL);
478   g_queue_clear (&qtdemux->protection_event_queue);
479 
480   g_free (qtdemux->cenc_aux_info_sizes);
481   qtdemux->cenc_aux_info_sizes = NULL;
482   g_mutex_clear (&qtdemux->expose_lock);
483 
484   g_ptr_array_free (qtdemux->active_streams, TRUE);
485   g_ptr_array_free (qtdemux->old_streams, TRUE);
486 
487   G_OBJECT_CLASS (parent_class)->dispose (object);
488 }
489 
490 static void
gst_qtdemux_post_no_playable_stream_error(GstQTDemux * qtdemux)491 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
492 {
493   if (qtdemux->redirect_location) {
494     GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
495         (_("This file contains no playable streams.")),
496         ("no known streams found, a redirect message has been posted"),
497         ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
498   } else {
499     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
500         (_("This file contains no playable streams.")),
501         ("no known streams found"));
502   }
503 }
504 
505 static GstBuffer *
_gst_buffer_new_wrapped(gpointer mem,gsize size,GFreeFunc free_func)506 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
507 {
508   return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
509       mem, size, 0, size, mem, free_func);
510 }
511 
512 static GstFlowReturn
gst_qtdemux_pull_atom(GstQTDemux * qtdemux,guint64 offset,guint64 size,GstBuffer ** buf)513 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
514     GstBuffer ** buf)
515 {
516   GstFlowReturn flow;
517   GstMapInfo map;
518   gsize bsize;
519 
520   if (G_UNLIKELY (size == 0)) {
521     GstFlowReturn ret;
522     GstBuffer *tmp = NULL;
523 
524     ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
525     if (ret != GST_FLOW_OK)
526       return ret;
527 
528     gst_buffer_map (tmp, &map, GST_MAP_READ);
529     size = QT_UINT32 (map.data);
530     GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
531 
532     gst_buffer_unmap (tmp, &map);
533     gst_buffer_unref (tmp);
534   }
535 
536   /* Sanity check: catch bogus sizes (fuzzed/broken files) */
537   if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
538     if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
539       /* we're pulling header but already got most interesting bits,
540        * so never mind the rest (e.g. tags) (that much) */
541       GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
542           size);
543       return GST_FLOW_EOS;
544     } else {
545       GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
546           (_("This file is invalid and cannot be played.")),
547           ("atom has bogus size %" G_GUINT64_FORMAT, size));
548       return GST_FLOW_ERROR;
549     }
550   }
551 
552   flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
553 
554   if (G_UNLIKELY (flow != GST_FLOW_OK))
555     return flow;
556 
557   bsize = gst_buffer_get_size (*buf);
558   /* Catch short reads - we don't want any partial atoms */
559   if (G_UNLIKELY (bsize < size)) {
560     GST_WARNING_OBJECT (qtdemux,
561         "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
562     gst_buffer_unref (*buf);
563     *buf = NULL;
564     return GST_FLOW_EOS;
565   }
566 
567   return flow;
568 }
569 
570 #if 1
571 static gboolean
gst_qtdemux_src_convert(GstQTDemux * qtdemux,GstPad * pad,GstFormat src_format,gint64 src_value,GstFormat dest_format,gint64 * dest_value)572 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
573     GstFormat src_format, gint64 src_value, GstFormat dest_format,
574     gint64 * dest_value)
575 {
576   gboolean res = TRUE;
577   QtDemuxStream *stream = gst_pad_get_element_private (pad);
578   gint32 index;
579 
580   if (stream->subtype != FOURCC_vide) {
581     res = FALSE;
582     goto done;
583   }
584 
585   switch (src_format) {
586     case GST_FORMAT_TIME:
587       switch (dest_format) {
588         case GST_FORMAT_BYTES:{
589           index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
590           if (-1 == index) {
591             res = FALSE;
592             goto done;
593           }
594 
595           *dest_value = stream->samples[index].offset;
596 
597           GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
598               GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
599               GST_TIME_ARGS (src_value), *dest_value);
600           break;
601         }
602         default:
603           res = FALSE;
604           break;
605       }
606       break;
607     case GST_FORMAT_BYTES:
608       switch (dest_format) {
609         case GST_FORMAT_TIME:{
610           index =
611               gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
612               stream, src_value);
613 
614           if (-1 == index) {
615             res = FALSE;
616             goto done;
617           }
618 
619           *dest_value =
620               QTSTREAMTIME_TO_GSTTIME (stream,
621               stream->samples[index].timestamp);
622           GST_DEBUG_OBJECT (qtdemux,
623               "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
624               GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
625           break;
626         }
627         default:
628           res = FALSE;
629           break;
630       }
631       break;
632     default:
633       res = FALSE;
634       break;
635   }
636 
637 done:
638   return res;
639 }
640 #endif
641 
642 static gboolean
gst_qtdemux_get_duration(GstQTDemux * qtdemux,GstClockTime * duration)643 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
644 {
645   gboolean res = FALSE;
646 
647   *duration = GST_CLOCK_TIME_NONE;
648 
649   if (qtdemux->duration != 0 &&
650       qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
651     *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
652     res = TRUE;
653   } else {
654     *duration = GST_CLOCK_TIME_NONE;
655   }
656 
657   return res;
658 }
659 
660 static gboolean
gst_qtdemux_handle_src_query(GstPad * pad,GstObject * parent,GstQuery * query)661 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
662     GstQuery * query)
663 {
664   gboolean res = FALSE;
665   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
666 
667   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
668 
669   switch (GST_QUERY_TYPE (query)) {
670     case GST_QUERY_POSITION:{
671       GstFormat fmt;
672 
673       gst_query_parse_position (query, &fmt, NULL);
674       if (fmt == GST_FORMAT_TIME
675           && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
676         gst_query_set_position (query, GST_FORMAT_TIME,
677             qtdemux->segment.position);
678         res = TRUE;
679       }
680     }
681       break;
682     case GST_QUERY_DURATION:{
683       GstFormat fmt;
684 
685       gst_query_parse_duration (query, &fmt, NULL);
686       if (fmt == GST_FORMAT_TIME) {
687         /* First try to query upstream */
688         res = gst_pad_query_default (pad, parent, query);
689         if (!res) {
690           GstClockTime duration;
691           if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
692             gst_query_set_duration (query, GST_FORMAT_TIME, duration);
693             res = TRUE;
694           }
695         }
696       }
697       break;
698     }
699     case GST_QUERY_CONVERT:{
700       GstFormat src_fmt, dest_fmt;
701       gint64 src_value, dest_value = 0;
702 
703       gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
704 
705       res = gst_qtdemux_src_convert (qtdemux, pad,
706           src_fmt, src_value, dest_fmt, &dest_value);
707       if (res)
708         gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
709 
710       break;
711     }
712     case GST_QUERY_FORMATS:
713       gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
714       res = TRUE;
715       break;
716     case GST_QUERY_SEEKING:{
717       GstFormat fmt;
718       gboolean seekable;
719 
720       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
721 
722       if (fmt == GST_FORMAT_BYTES) {
723         /* We always refuse BYTES seeks from downstream */
724         break;
725       }
726 
727       /* try upstream first */
728       res = gst_pad_query_default (pad, parent, query);
729 
730       if (!res) {
731         gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
732         if (fmt == GST_FORMAT_TIME) {
733           GstClockTime duration;
734 
735           gst_qtdemux_get_duration (qtdemux, &duration);
736           seekable = TRUE;
737           if (!qtdemux->pullbased) {
738             GstQuery *q;
739 
740             /* we might be able with help from upstream */
741             seekable = FALSE;
742             q = gst_query_new_seeking (GST_FORMAT_BYTES);
743             if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
744               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
745               GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
746             }
747             gst_query_unref (q);
748           }
749           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
750           res = TRUE;
751         }
752       }
753       break;
754     }
755     case GST_QUERY_SEGMENT:
756     {
757       GstFormat format;
758       gint64 start, stop;
759 
760       format = qtdemux->segment.format;
761 
762       start =
763           gst_segment_to_stream_time (&qtdemux->segment, format,
764           qtdemux->segment.start);
765       if ((stop = qtdemux->segment.stop) == -1)
766         stop = qtdemux->segment.duration;
767       else
768         stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
769 
770       gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
771       res = TRUE;
772       break;
773     }
774     default:
775       res = gst_pad_query_default (pad, parent, query);
776       break;
777   }
778 
779   return res;
780 }
781 
782 static void
gst_qtdemux_push_tags(GstQTDemux * qtdemux,QtDemuxStream * stream)783 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
784 {
785   if (G_LIKELY (stream->pad)) {
786     GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
787         GST_DEBUG_PAD_NAME (stream->pad));
788 
789     if (!gst_tag_list_is_empty (stream->stream_tags)) {
790       GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
791           stream->stream_tags);
792       gst_pad_push_event (stream->pad,
793           gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
794     }
795 
796     if (G_UNLIKELY (stream->send_global_tags)) {
797       GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
798           qtdemux->tag_list);
799       gst_pad_push_event (stream->pad,
800           gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
801       stream->send_global_tags = FALSE;
802     }
803   }
804 }
805 
806 /* push event on all source pads; takes ownership of the event */
807 static void
gst_qtdemux_push_event(GstQTDemux * qtdemux,GstEvent * event)808 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
809 {
810   gboolean has_valid_stream = FALSE;
811   GstEventType etype = GST_EVENT_TYPE (event);
812   guint i;
813 
814   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
815       GST_EVENT_TYPE_NAME (event));
816 
817   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
818     GstPad *pad;
819     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
820     GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
821 
822     if ((pad = stream->pad)) {
823       has_valid_stream = TRUE;
824 
825       if (etype == GST_EVENT_EOS) {
826         /* let's not send twice */
827         if (stream->sent_eos)
828           continue;
829         stream->sent_eos = TRUE;
830       }
831 
832       gst_pad_push_event (pad, gst_event_ref (event));
833     }
834   }
835 
836   gst_event_unref (event);
837 
838   /* if it is EOS and there are no pads, post an error */
839   if (!has_valid_stream && etype == GST_EVENT_EOS) {
840     gst_qtdemux_post_no_playable_stream_error (qtdemux);
841   }
842 }
843 
844 typedef struct
845 {
846   guint64 media_time;
847 } FindData;
848 
849 static gint
find_func(QtDemuxSample * s1,gint64 * media_time,gpointer user_data)850 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
851 {
852   if ((gint64) s1->timestamp > *media_time)
853     return 1;
854   if ((gint64) s1->timestamp == *media_time)
855     return 0;
856 
857   return -1;
858 }
859 
860 /* find the index of the sample that includes the data for @media_time using a
861  * binary search.  Only to be called in optimized cases of linear search below.
862  *
863  * Returns the index of the sample with the corresponding *DTS*.
864  */
865 static guint32
gst_qtdemux_find_index(GstQTDemux * qtdemux,QtDemuxStream * str,guint64 media_time)866 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
867     guint64 media_time)
868 {
869   QtDemuxSample *result;
870   guint32 index;
871 
872   /* convert media_time to mov format */
873   media_time =
874       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
875 
876   result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
877       sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
878       GST_SEARCH_MODE_BEFORE, &media_time, NULL);
879 
880   if (G_LIKELY (result))
881     index = result - str->samples;
882   else
883     index = 0;
884 
885   return index;
886 }
887 
888 
889 
890 /* find the index of the sample that includes the data for @media_offset using a
891  * linear search
892  *
893  * Returns the index of the sample.
894  */
895 static guint32
gst_qtdemux_find_index_for_given_media_offset_linear(GstQTDemux * qtdemux,QtDemuxStream * str,gint64 media_offset)896 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
897     QtDemuxStream * str, gint64 media_offset)
898 {
899   QtDemuxSample *result = str->samples;
900   guint32 index = 0;
901 
902   if (result == NULL || str->n_samples == 0)
903     return -1;
904 
905   if (media_offset == result->offset)
906     return index;
907 
908   result++;
909   while (index < str->n_samples - 1) {
910     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
911       goto parse_failed;
912 
913     if (media_offset < result->offset)
914       break;
915 
916     index++;
917     result++;
918   }
919   return index;
920 
921   /* ERRORS */
922 parse_failed:
923   {
924     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
925     return -1;
926   }
927 }
928 
929 /* find the index of the sample that includes the data for @media_time using a
930  * linear search, and keeping in mind that not all samples may have been parsed
931  * yet.  If possible, it will delegate to binary search.
932  *
933  * Returns the index of the sample.
934  */
935 static guint32
gst_qtdemux_find_index_linear(GstQTDemux * qtdemux,QtDemuxStream * str,GstClockTime media_time)936 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
937     GstClockTime media_time)
938 {
939   guint32 index = 0;
940   guint64 mov_time;
941   QtDemuxSample *sample;
942 
943   /* convert media_time to mov format */
944   mov_time =
945       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
946 
947   sample = str->samples;
948   if (mov_time == sample->timestamp + sample->pts_offset)
949     return index;
950 
951   /* use faster search if requested time in already parsed range */
952   sample = str->samples + str->stbl_index;
953   if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
954     index = gst_qtdemux_find_index (qtdemux, str, media_time);
955     sample = str->samples + index;
956   } else {
957     while (index < str->n_samples - 1) {
958       if (!qtdemux_parse_samples (qtdemux, str, index + 1))
959         goto parse_failed;
960 
961       sample = str->samples + index + 1;
962       if (mov_time < sample->timestamp) {
963         sample = str->samples + index;
964         break;
965       }
966 
967       index++;
968     }
969   }
970 
971   /* sample->timestamp is now <= media_time, need to find the corresponding
972    * PTS now by looking backwards */
973   while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
974     index--;
975     sample = str->samples + index;
976   }
977 
978   return index;
979 
980   /* ERRORS */
981 parse_failed:
982   {
983     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
984     return -1;
985   }
986 }
987 
988 /* find the index of the keyframe needed to decode the sample at @index
989  * of stream @str, or of a subsequent keyframe (depending on @next)
990  *
991  * Returns the index of the keyframe.
992  */
993 static guint32
gst_qtdemux_find_keyframe(GstQTDemux * qtdemux,QtDemuxStream * str,guint32 index,gboolean next)994 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
995     guint32 index, gboolean next)
996 {
997   guint32 new_index = index;
998 
999   if (index >= str->n_samples) {
1000     new_index = str->n_samples;
1001     goto beach;
1002   }
1003 
1004   /* all keyframes, return index */
1005   if (str->all_keyframe) {
1006     new_index = index;
1007     goto beach;
1008   }
1009 
1010   /* else search until we have a keyframe */
1011   while (new_index < str->n_samples) {
1012     if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1013       goto parse_failed;
1014 
1015     if (str->samples[new_index].keyframe)
1016       break;
1017 
1018     if (new_index == 0)
1019       break;
1020 
1021     if (next)
1022       new_index++;
1023     else
1024       new_index--;
1025   }
1026 
1027   if (new_index == str->n_samples) {
1028     GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1029     new_index = -1;
1030   }
1031 
1032 beach:
1033   GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1034       "gave %u", next ? "after" : "before", index, new_index);
1035 
1036   return new_index;
1037 
1038   /* ERRORS */
1039 parse_failed:
1040   {
1041     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1042     return -1;
1043   }
1044 }
1045 
1046 /* find the segment for @time_position for @stream
1047  *
1048  * Returns the index of the segment containing @time_position.
1049  * Returns the last segment and sets the @eos variable to TRUE
1050  * if the time is beyond the end. @eos may be NULL
1051  */
1052 static guint32
gst_qtdemux_find_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime time_position)1053 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1054     GstClockTime time_position)
1055 {
1056   gint i;
1057   guint32 seg_idx;
1058 
1059   GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1060       GST_TIME_ARGS (time_position));
1061 
1062   seg_idx = -1;
1063   for (i = 0; i < stream->n_segments; i++) {
1064     QtDemuxSegment *segment = &stream->segments[i];
1065 
1066     GST_LOG_OBJECT (stream->pad,
1067         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1068         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1069 
1070     /* For the last segment we include stop_time in the last segment */
1071     if (i < stream->n_segments - 1) {
1072       if (segment->time <= time_position && time_position < segment->stop_time) {
1073         GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1074         seg_idx = i;
1075         break;
1076       }
1077     } else {
1078       /* Last segment always matches */
1079       seg_idx = i;
1080       break;
1081     }
1082   }
1083   return seg_idx;
1084 }
1085 
1086 /* move the stream @str to the sample position @index.
1087  *
1088  * Updates @str->sample_index and marks discontinuity if needed.
1089  */
1090 static void
gst_qtdemux_move_stream(GstQTDemux * qtdemux,QtDemuxStream * str,guint32 index)1091 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1092     guint32 index)
1093 {
1094   /* no change needed */
1095   if (index == str->sample_index)
1096     return;
1097 
1098   GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1099       str->n_samples);
1100 
1101   /* position changed, we have a discont */
1102   str->sample_index = index;
1103   str->offset_in_sample = 0;
1104   /* Each time we move in the stream we store the position where we are
1105    * starting from */
1106   str->from_sample = index;
1107   str->discont = TRUE;
1108 }
1109 
1110 #ifdef OHOS_OPT_COMPAT
1111 /* ohos.opt.compat.0055 */
gst_qtdemux_get_all_tracks_minimum_duration(GstQTDemux * qtdemux)1112 static gint64 gst_qtdemux_get_all_tracks_minimum_duration(GstQTDemux * qtdemux)
1113 {
1114   guint64 min_duration = G_MAXUINT64;
1115   for (guint i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1116     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
1117     if (str->duration < min_duration) {
1118       min_duration = str->duration;
1119     }
1120   }
1121   return min_duration;
1122 }
1123 #endif
1124 
1125 static void
gst_qtdemux_adjust_seek(GstQTDemux * qtdemux,gint64 desired_time,gboolean use_sparse,gboolean next,gint64 * key_time,gint64 * key_offset)1126 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1127     gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1128 {
1129   guint64 min_offset;
1130 #ifdef OHOS_OPT_COMPAT
1131   /* ohos.opt.compat.0055 */
1132   guint64 max_time = 0;
1133   guint64 min_duration = gst_qtdemux_get_all_tracks_minimum_duration(qtdemux);
1134 #endif
1135   gint64 min_byte_offset = -1;
1136   guint i;
1137 
1138   min_offset = desired_time;
1139 
1140   /* for each stream, find the index of the sample in the segment
1141    * and move back to the previous keyframe. */
1142   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1143     QtDemuxStream *str;
1144     guint32 index, kindex;
1145     guint32 seg_idx;
1146     GstClockTime media_start;
1147     GstClockTime media_time;
1148     GstClockTime seg_time;
1149     QtDemuxSegment *seg;
1150     gboolean empty_segment = FALSE;
1151 
1152     str = QTDEMUX_NTH_STREAM (qtdemux, i);
1153 
1154     if (CUR_STREAM (str)->sparse && !use_sparse)
1155       continue;
1156 
1157     seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1158     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1159 
1160     /* get segment and time in the segment */
1161     seg = &str->segments[seg_idx];
1162     seg_time = (desired_time - seg->time) * seg->rate;
1163 
1164     while (QTSEGMENT_IS_EMPTY (seg)) {
1165       seg_time = 0;
1166       empty_segment = TRUE;
1167       GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1168           seg_idx);
1169       seg_idx++;
1170       if (seg_idx == str->n_segments)
1171         break;
1172       seg = &str->segments[seg_idx];
1173     }
1174 
1175     if (seg_idx == str->n_segments) {
1176       /* FIXME track shouldn't have the last segment as empty, but if it
1177        * happens we better handle it */
1178       continue;
1179     }
1180 
1181     /* get the media time in the segment */
1182     media_start = seg->media_start + seg_time;
1183 
1184     /* get the index of the sample with media time */
1185     index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1186     GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1187         " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1188         GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1189         empty_segment);
1190 
1191     /* shift to next frame if we are looking for next keyframe */
1192     if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1193         && index < str->stbl_index)
1194       index++;
1195 
1196     if (!empty_segment) {
1197       /* find previous keyframe */
1198       kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1199 
1200       /* we will settle for one before if none found after */
1201       if (next && kindex == -1)
1202         kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1203 
1204       /* Update the requested time whenever a keyframe was found, to make it
1205        * accurate and avoid having the first buffer fall outside of the segment
1206        */
1207       if (kindex != -1) {
1208         index = kindex;
1209 
1210         /* get timestamp of keyframe */
1211         media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1212         GST_DEBUG_OBJECT (qtdemux,
1213             "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1214             G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1215             str->samples[kindex].offset);
1216 #ifdef OHOS_OPT_COMPAT
1217         /**
1218          * ohos.opt.compat.0055
1219          * when video stream and audio stream are different duration(edge. video duration is 01:50,
1220          * audio duration is 0:35), it will lead seek done offset has a huge gap with seek offset.
1221          * Thus, return a timestamp closest to the seek offset.
1222          */
1223         GST_DEBUG_OBJECT (qtdemux,
1224           "min_duration %" GST_TIME_FORMAT " desired_time %" GST_TIME_FORMAT " next %d max_time %" GST_TIME_FORMAT "",
1225           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME(str, min_duration)),
1226           GST_TIME_ARGS (desired_time), next, GST_TIME_ARGS (max_time));
1227         /**
1228          * diffent: compared with the original logic, forward seek may miss video key frames
1229          * forward seek, find all tracks the biggest key frames time
1230          */
1231         if ((min_duration < desired_time) && (!next && (max_time > media_time))) {
1232           continue;
1233         }
1234         max_time = media_time;
1235 #endif
1236         /* keyframes in the segment get a chance to change the
1237          * desired_offset. keyframes out of the segment are
1238          * ignored. */
1239         if (media_time >= seg->media_start) {
1240           GstClockTime seg_time;
1241 
1242           /* this keyframe is inside the segment, convert back to
1243            * segment time */
1244           seg_time = (media_time - seg->media_start) + seg->time;
1245           if ((!next && (seg_time < min_offset)) ||
1246               (next && (seg_time > min_offset)))
1247             min_offset = seg_time;
1248         }
1249       }
1250     }
1251 
1252     if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1253       min_byte_offset = str->samples[index].offset;
1254   }
1255 
1256   if (key_time)
1257     *key_time = min_offset;
1258   if (key_offset)
1259     *key_offset = min_byte_offset;
1260 }
1261 
1262 static gboolean
gst_qtdemux_convert_seek(GstPad * pad,GstFormat * format,GstSeekType cur_type,gint64 * cur,GstSeekType stop_type,gint64 * stop)1263 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1264     GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1265 {
1266   gboolean res;
1267 
1268   g_return_val_if_fail (format != NULL, FALSE);
1269   g_return_val_if_fail (cur != NULL, FALSE);
1270   g_return_val_if_fail (stop != NULL, FALSE);
1271 
1272   if (*format == GST_FORMAT_TIME)
1273     return TRUE;
1274 
1275   res = TRUE;
1276   if (cur_type != GST_SEEK_TYPE_NONE)
1277     res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1278   if (res && stop_type != GST_SEEK_TYPE_NONE)
1279     res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1280 
1281   if (res)
1282     *format = GST_FORMAT_TIME;
1283 
1284   return res;
1285 }
1286 
1287 /* perform seek in push based mode:
1288    find BYTE position to move to based on time and delegate to upstream
1289 */
1290 static gboolean
gst_qtdemux_do_push_seek(GstQTDemux * qtdemux,GstPad * pad,GstEvent * event)1291 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1292 {
1293   gdouble rate;
1294   GstFormat format;
1295   GstSeekFlags flags;
1296   GstSeekType cur_type, stop_type;
1297   gint64 cur, stop, key_cur;
1298   gboolean res;
1299   gint64 byte_cur;
1300   gint64 original_stop;
1301   guint32 seqnum;
1302 
1303   GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1304 
1305   gst_event_parse_seek (event, &rate, &format, &flags,
1306       &cur_type, &cur, &stop_type, &stop);
1307   seqnum = gst_event_get_seqnum (event);
1308 
1309   /* Directly send the instant-rate-change event here before taking the
1310    * stream-lock so that it can be applied as soon as possible */
1311   if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1312     GstEvent *ev;
1313 
1314     /* instant rate change only supported if direction does not change. All
1315      * other requirements are already checked before creating the seek event
1316      * but let's double-check here to be sure */
1317     if ((qtdemux->segment.rate > 0 && rate < 0) ||
1318         (qtdemux->segment.rate < 0 && rate > 0) ||
1319         cur_type != GST_SEEK_TYPE_NONE ||
1320         stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1321       GST_ERROR_OBJECT (qtdemux,
1322           "Instant rate change seeks only supported in the "
1323           "same direction, without flushing and position change");
1324       return FALSE;
1325     }
1326 
1327     ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1328         (GstSegmentFlags) flags);
1329     gst_event_set_seqnum (ev, seqnum);
1330     gst_qtdemux_push_event (qtdemux, ev);
1331     return TRUE;
1332   }
1333 
1334   /* only forward streaming and seeking is possible */
1335   if (rate <= 0)
1336     goto unsupported_seek;
1337 
1338   /* convert to TIME if needed and possible */
1339   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1340           stop_type, &stop))
1341     goto no_format;
1342 
1343   /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1344    * the original stop position to use when upstream pushes the new segment
1345    * for this seek */
1346   original_stop = stop;
1347   stop = -1;
1348 
1349   /* find reasonable corresponding BYTE position,
1350    * also try to mind about keyframes, since we can not go back a bit for them
1351    * later on */
1352   /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1353    * mostly just work, but let's not yet boldly go there  ... */
1354   gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1355 
1356   if (byte_cur == -1)
1357     goto abort_seek;
1358 
1359   GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1360       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1361       stop);
1362 
1363   GST_OBJECT_LOCK (qtdemux);
1364   qtdemux->seek_offset = byte_cur;
1365   if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1366     qtdemux->push_seek_start = cur;
1367   } else {
1368     qtdemux->push_seek_start = key_cur;
1369   }
1370 
1371   if (stop_type == GST_SEEK_TYPE_NONE) {
1372     qtdemux->push_seek_stop = qtdemux->segment.stop;
1373   } else {
1374     qtdemux->push_seek_stop = original_stop;
1375   }
1376   GST_OBJECT_UNLOCK (qtdemux);
1377 
1378   qtdemux->segment_seqnum = seqnum;
1379   /* BYTE seek event */
1380   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1381       stop_type, stop);
1382   gst_event_set_seqnum (event, seqnum);
1383   res = gst_pad_push_event (qtdemux->sinkpad, event);
1384 
1385   return res;
1386 
1387   /* ERRORS */
1388 abort_seek:
1389   {
1390     GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1391         "seek aborted.");
1392     return FALSE;
1393   }
1394 unsupported_seek:
1395   {
1396     GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1397     return FALSE;
1398   }
1399 no_format:
1400   {
1401     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1402     return FALSE;
1403   }
1404 }
1405 
1406 /* perform the seek.
1407  *
1408  * We set all segment_indexes in the streams to unknown and
1409  * adjust the time_position to the desired position. this is enough
1410  * to trigger a segment switch in the streaming thread to start
1411  * streaming from the desired position.
1412  *
1413  * Keyframe seeking is a little more complicated when dealing with
1414  * segments. Ideally we want to move to the previous keyframe in
1415  * the segment but there might not be a keyframe in the segment. In
1416  * fact, none of the segments could contain a keyframe. We take a
1417  * practical approach: seek to the previous keyframe in the segment,
1418  * if there is none, seek to the beginning of the segment.
1419  *
1420  * Called with STREAM_LOCK
1421  */
1422 static gboolean
gst_qtdemux_perform_seek(GstQTDemux * qtdemux,GstSegment * segment,guint32 seqnum,GstSeekFlags flags)1423 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1424     guint32 seqnum, GstSeekFlags flags)
1425 {
1426   gint64 desired_offset;
1427   guint i;
1428 
1429   desired_offset = segment->position;
1430 
1431   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1432       GST_TIME_ARGS (desired_offset));
1433 
1434   /* may not have enough fragmented info to do this adjustment,
1435    * and we can't scan (and probably should not) at this time with
1436    * possibly flushing upstream */
1437   if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1438     gint64 min_offset;
1439     gboolean next, before, after;
1440 
1441     before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1442     after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1443     next = after && !before;
1444     if (segment->rate < 0)
1445       next = !next;
1446 
1447     gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1448         NULL);
1449     GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1450         GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1451     desired_offset = min_offset;
1452   }
1453 
1454   /* and set all streams to the final position */
1455   GST_OBJECT_LOCK (qtdemux);
1456   gst_flow_combiner_reset (qtdemux->flowcombiner);
1457   GST_OBJECT_UNLOCK (qtdemux);
1458   qtdemux->segment_seqnum = seqnum;
1459   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1460     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1461 
1462     stream->time_position = desired_offset;
1463     stream->accumulated_base = 0;
1464     stream->sample_index = -1;
1465     stream->offset_in_sample = 0;
1466     stream->segment_index = -1;
1467     stream->sent_eos = FALSE;
1468     stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1469 
1470     if (segment->flags & GST_SEEK_FLAG_FLUSH)
1471       gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1472   }
1473   segment->position = desired_offset;
1474   if (segment->rate >= 0) {
1475     segment->start = desired_offset;
1476     /* We need to update time as we update start in that direction */
1477     segment->time = desired_offset;
1478 
1479     /* we stop at the end */
1480     if (segment->stop == -1)
1481       segment->stop = segment->duration;
1482   } else {
1483     segment->stop = desired_offset;
1484   }
1485 
1486   if (qtdemux->fragmented)
1487     qtdemux->fragmented_seek_pending = TRUE;
1488 
1489   return TRUE;
1490 }
1491 
1492 /* do a seek in pull based mode */
1493 static gboolean
gst_qtdemux_do_seek(GstQTDemux * qtdemux,GstPad * pad,GstEvent * event)1494 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1495 {
1496   gdouble rate = 1.0;
1497   GstFormat format;
1498   GstSeekFlags flags;
1499   GstSeekType cur_type, stop_type;
1500   gint64 cur, stop;
1501   gboolean flush, instant_rate_change;
1502   gboolean update;
1503   GstSegment seeksegment;
1504   guint32 seqnum = GST_SEQNUM_INVALID;
1505   GstEvent *flush_event;
1506   gboolean ret;
1507 
1508   GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1509 
1510   gst_event_parse_seek (event, &rate, &format, &flags,
1511       &cur_type, &cur, &stop_type, &stop);
1512   seqnum = gst_event_get_seqnum (event);
1513 
1514   /* we have to have a format as the segment format. Try to convert
1515    * if not. */
1516   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1517           stop_type, &stop))
1518     goto no_format;
1519 
1520   GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1521 
1522   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1523   instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1524 
1525   /* Directly send the instant-rate-change event here before taking the
1526    * stream-lock so that it can be applied as soon as possible */
1527   if (instant_rate_change) {
1528     GstEvent *ev;
1529 
1530     /* instant rate change only supported if direction does not change. All
1531      * other requirements are already checked before creating the seek event
1532      * but let's double-check here to be sure */
1533     if ((qtdemux->segment.rate > 0 && rate < 0) ||
1534         (qtdemux->segment.rate < 0 && rate > 0) ||
1535         cur_type != GST_SEEK_TYPE_NONE ||
1536         stop_type != GST_SEEK_TYPE_NONE || flush) {
1537       GST_ERROR_OBJECT (qtdemux,
1538           "Instant rate change seeks only supported in the "
1539           "same direction, without flushing and position change");
1540       return FALSE;
1541     }
1542 
1543     ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1544         (GstSegmentFlags) flags);
1545     gst_event_set_seqnum (ev, seqnum);
1546     gst_qtdemux_push_event (qtdemux, ev);
1547     return TRUE;
1548   }
1549 
1550   /* stop streaming, either by flushing or by pausing the task */
1551   if (flush) {
1552     flush_event = gst_event_new_flush_start ();
1553     if (seqnum != GST_SEQNUM_INVALID)
1554       gst_event_set_seqnum (flush_event, seqnum);
1555     /* unlock upstream pull_range */
1556     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1557     /* make sure out loop function exits */
1558     gst_qtdemux_push_event (qtdemux, flush_event);
1559   } else {
1560     /* non flushing seek, pause the task */
1561     gst_pad_pause_task (qtdemux->sinkpad);
1562   }
1563 
1564   /* wait for streaming to finish */
1565   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1566 
1567   /* copy segment, we need this because we still need the old
1568    * segment when we close the current segment. */
1569   memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1570 
1571   /* configure the segment with the seek variables */
1572   GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1573   if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1574           cur_type, cur, stop_type, stop, &update)) {
1575     ret = FALSE;
1576     GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1577   } else {
1578     /* now do the seek */
1579     ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1580   }
1581 
1582   /* prepare for streaming again */
1583   if (flush) {
1584     flush_event = gst_event_new_flush_stop (TRUE);
1585     if (seqnum != GST_SEQNUM_INVALID)
1586       gst_event_set_seqnum (flush_event, seqnum);
1587 
1588     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1589     gst_qtdemux_push_event (qtdemux, flush_event);
1590   }
1591 
1592   /* commit the new segment */
1593   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1594 
1595   if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1596     GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1597         qtdemux->segment.format, qtdemux->segment.position);
1598     if (seqnum != GST_SEQNUM_INVALID)
1599       gst_message_set_seqnum (msg, seqnum);
1600     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1601   }
1602 
1603   /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1604   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1605       qtdemux->sinkpad, NULL);
1606 
1607   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1608 
1609   return ret;
1610 
1611   /* ERRORS */
1612 no_format:
1613   {
1614     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1615     return FALSE;
1616   }
1617 }
1618 
1619 static gboolean
qtdemux_ensure_index(GstQTDemux * qtdemux)1620 qtdemux_ensure_index (GstQTDemux * qtdemux)
1621 {
1622   guint i;
1623 
1624   GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1625 
1626   /* Build complete index */
1627   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1628     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1629 
1630     if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1631       GST_LOG_OBJECT (qtdemux,
1632           "Building complete index of track-id %u for seeking failed!",
1633           stream->track_id);
1634       return FALSE;
1635     }
1636   }
1637 
1638   return TRUE;
1639 }
1640 
1641 static gboolean
gst_qtdemux_handle_src_event(GstPad * pad,GstObject * parent,GstEvent * event)1642 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1643     GstEvent * event)
1644 {
1645   gboolean res = TRUE;
1646   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1647 
1648   switch (GST_EVENT_TYPE (event)) {
1649     case GST_EVENT_RECONFIGURE:
1650       GST_OBJECT_LOCK (qtdemux);
1651       gst_flow_combiner_reset (qtdemux->flowcombiner);
1652       GST_OBJECT_UNLOCK (qtdemux);
1653       res = gst_pad_event_default (pad, parent, event);
1654       break;
1655     case GST_EVENT_SEEK:
1656     {
1657       GstSeekFlags flags = 0;
1658       GstFormat seek_format;
1659       gboolean instant_rate_change;
1660 
1661 #ifndef GST_DISABLE_GST_DEBUG
1662       GstClockTime ts = gst_util_get_timestamp ();
1663 #endif
1664       guint32 seqnum = gst_event_get_seqnum (event);
1665 
1666       qtdemux->received_seek = TRUE;
1667 
1668       gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1669           NULL);
1670       instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1671 
1672       if (seqnum == qtdemux->segment_seqnum) {
1673         GST_LOG_OBJECT (pad,
1674             "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1675         gst_event_unref (event);
1676         return TRUE;
1677       }
1678 
1679       if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1680         /* seek should be handled by upstream, we might need to re-download fragments */
1681         GST_DEBUG_OBJECT (qtdemux,
1682             "let upstream handle seek for fragmented playback");
1683         goto upstream;
1684       }
1685 
1686       if (seek_format == GST_FORMAT_BYTES) {
1687         GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1688         gst_event_unref (event);
1689         return FALSE;
1690       }
1691 
1692       gst_event_parse_seek_trickmode_interval (event,
1693           &qtdemux->trickmode_interval);
1694 
1695       /* Build complete index for seeking;
1696        * if not a fragmented file at least and we're really doing a seek,
1697        * not just an instant-rate-change */
1698       if (!qtdemux->fragmented && !instant_rate_change) {
1699         if (!qtdemux_ensure_index (qtdemux))
1700           goto index_failed;
1701       }
1702 #ifndef GST_DISABLE_GST_DEBUG
1703       ts = gst_util_get_timestamp () - ts;
1704       GST_INFO_OBJECT (qtdemux,
1705           "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1706 #endif
1707       if (qtdemux->pullbased) {
1708         res = gst_qtdemux_do_seek (qtdemux, pad, event);
1709       } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1710         GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1711         res = TRUE;
1712       } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1713           && QTDEMUX_N_STREAMS (qtdemux)
1714           && !qtdemux->fragmented) {
1715         res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1716       } else {
1717         GST_DEBUG_OBJECT (qtdemux,
1718             "ignoring seek in push mode in current state");
1719         res = FALSE;
1720       }
1721       gst_event_unref (event);
1722     }
1723       break;
1724     default:
1725     upstream:
1726       res = gst_pad_event_default (pad, parent, event);
1727       break;
1728   }
1729 
1730 done:
1731   return res;
1732 
1733   /* ERRORS */
1734 index_failed:
1735   {
1736     GST_ERROR_OBJECT (qtdemux, "Index failed");
1737     gst_event_unref (event);
1738     res = FALSE;
1739     goto done;
1740   }
1741 }
1742 
1743 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1744  *
1745  * If @fw is false, the coding order is explored backwards.
1746  *
1747  * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1748  * sample is found for that track.
1749  *
1750  * The stream and sample index of the sample with the minimum offset in the direction explored
1751  * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1752  *
1753  * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1754  * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1755  * @_stream and @_index. */
1756 static void
gst_qtdemux_find_sample(GstQTDemux * qtdemux,gint64 byte_pos,gboolean fw,gboolean set,QtDemuxStream ** _stream,gint * _index,gint64 * _time)1757 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1758     gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1759 {
1760   gint i, index;
1761   gint64 time, min_time;
1762   QtDemuxStream *stream;
1763   gint iter;
1764 
1765   min_time = -1;
1766   stream = NULL;
1767   index = -1;
1768 
1769   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1770     QtDemuxStream *str;
1771     gint inc;
1772     gboolean set_sample;
1773 
1774     str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1775     set_sample = !set;
1776 
1777     if (fw) {
1778       i = 0;
1779       inc = 1;
1780     } else {
1781       i = str->n_samples - 1;
1782       inc = -1;
1783     }
1784 
1785     for (; (i >= 0) && (i < str->n_samples); i += inc) {
1786       if (str->samples[i].size == 0)
1787         continue;
1788 
1789       if (fw && (str->samples[i].offset < byte_pos))
1790         continue;
1791 
1792       if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1793         continue;
1794 
1795       /* move stream to first available sample */
1796       if (set) {
1797         gst_qtdemux_move_stream (qtdemux, str, i);
1798         set_sample = TRUE;
1799       }
1800 
1801       /* avoid index from sparse streams since they might be far away */
1802       if (!CUR_STREAM (str)->sparse) {
1803         /* determine min/max time */
1804         time = QTSAMPLE_PTS (str, &str->samples[i]);
1805         if (min_time == -1 || (!fw && time > min_time) ||
1806             (fw && time < min_time)) {
1807           min_time = time;
1808         }
1809 
1810         /* determine stream with leading sample, to get its position */
1811         if (!stream ||
1812             (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1813             (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1814           stream = str;
1815           index = i;
1816         }
1817       }
1818       break;
1819     }
1820 
1821     /* no sample for this stream, mark eos */
1822     if (!set_sample)
1823       gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1824   }
1825 
1826   if (_time)
1827     *_time = min_time;
1828   if (_stream)
1829     *_stream = stream;
1830   if (_index)
1831     *_index = index;
1832 }
1833 
1834 /* Copied from mpegtsbase code */
1835 /* FIXME: replace this function when we add new util function for stream-id creation */
1836 static gchar *
_get_upstream_id(GstQTDemux * demux)1837 _get_upstream_id (GstQTDemux * demux)
1838 {
1839   gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1840 
1841   if (!upstream_id) {
1842     /* Try to create one from the upstream URI, else use a randome number */
1843     GstQuery *query;
1844     gchar *uri = NULL;
1845 
1846     /* Try to generate one from the URI query and
1847      * if it fails take a random number instead */
1848     query = gst_query_new_uri ();
1849     if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1850       gst_query_parse_uri (query, &uri);
1851     }
1852 
1853     if (uri) {
1854       GChecksum *cs;
1855 
1856       /* And then generate an SHA256 sum of the URI */
1857       cs = g_checksum_new (G_CHECKSUM_SHA256);
1858       g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1859       g_free (uri);
1860       upstream_id = g_strdup (g_checksum_get_string (cs));
1861       g_checksum_free (cs);
1862     } else {
1863       /* Just get some random number if the URI query fails */
1864       GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1865           "implementing a deterministic way of creating a stream-id");
1866       upstream_id =
1867           g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1868           g_random_int (), g_random_int ());
1869     }
1870 
1871     gst_query_unref (query);
1872   }
1873   return upstream_id;
1874 }
1875 
1876 static QtDemuxStream *
_create_stream(GstQTDemux * demux,guint32 track_id)1877 _create_stream (GstQTDemux * demux, guint32 track_id)
1878 {
1879   QtDemuxStream *stream;
1880   gchar *upstream_id;
1881 
1882   stream = g_new0 (QtDemuxStream, 1);
1883   stream->demux = demux;
1884   stream->track_id = track_id;
1885   upstream_id = _get_upstream_id (demux);
1886   stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1887   g_free (upstream_id);
1888   /* new streams always need a discont */
1889   stream->discont = TRUE;
1890   /* we enable clipping for raw audio/video streams */
1891   stream->need_clip = FALSE;
1892   stream->process_func = NULL;
1893   stream->segment_index = -1;
1894   stream->time_position = 0;
1895   stream->sample_index = -1;
1896   stream->offset_in_sample = 0;
1897   stream->new_stream = TRUE;
1898   stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1899   stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1900   stream->protected = FALSE;
1901   stream->protection_scheme_type = 0;
1902   stream->protection_scheme_version = 0;
1903   stream->protection_scheme_info = NULL;
1904   stream->n_samples_moof = 0;
1905   stream->duration_moof = 0;
1906   stream->duration_last_moof = 0;
1907   stream->alignment = 1;
1908   stream->stream_tags = gst_tag_list_new_empty ();
1909   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1910   g_queue_init (&stream->protection_scheme_event_queue);
1911   stream->ref_count = 1;
1912   /* consistent default for push based mode */
1913   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1914 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
1915   stream->has_push_first_frame = FALSE;
1916 #endif
1917   return stream;
1918 }
1919 
1920 static gboolean
gst_qtdemux_setcaps(GstQTDemux * demux,GstCaps * caps)1921 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1922 {
1923   GstStructure *structure;
1924   const gchar *variant;
1925   const GstCaps *mediacaps = NULL;
1926 
1927   GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1928 
1929   structure = gst_caps_get_structure (caps, 0);
1930   variant = gst_structure_get_string (structure, "variant");
1931 
1932   if (variant && strcmp (variant, "mss-fragmented") == 0) {
1933     QtDemuxStream *stream;
1934     const GValue *value;
1935 
1936     demux->fragmented = TRUE;
1937     demux->mss_mode = TRUE;
1938 
1939     if (QTDEMUX_N_STREAMS (demux) > 1) {
1940       /* can't do this, we can only renegotiate for another mss format */
1941       return FALSE;
1942     }
1943 
1944     value = gst_structure_get_value (structure, "media-caps");
1945     /* create stream */
1946     if (value) {
1947       const GValue *timescale_v;
1948 
1949       /* TODO update when stream changes during playback */
1950 
1951       if (QTDEMUX_N_STREAMS (demux) == 0) {
1952         stream = _create_stream (demux, 1);
1953         g_ptr_array_add (demux->active_streams, stream);
1954         /* mss has no stsd/stsd entry, use id 0 as default */
1955         stream->stsd_entries_length = 1;
1956         stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1957         stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1958       } else {
1959         stream = QTDEMUX_NTH_STREAM (demux, 0);
1960       }
1961 
1962       timescale_v = gst_structure_get_value (structure, "timescale");
1963       if (timescale_v) {
1964         stream->timescale = g_value_get_uint64 (timescale_v);
1965       } else {
1966         /* default mss timescale */
1967         stream->timescale = 10000000;
1968       }
1969       demux->timescale = stream->timescale;
1970 
1971       mediacaps = gst_value_get_caps (value);
1972       if (!CUR_STREAM (stream)->caps
1973           || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1974         GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1975             mediacaps);
1976         stream->new_caps = TRUE;
1977       }
1978       gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1979       structure = gst_caps_get_structure (mediacaps, 0);
1980       if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1981         stream->subtype = FOURCC_vide;
1982 
1983         gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1984         gst_structure_get_int (structure, "height",
1985             &CUR_STREAM (stream)->height);
1986         gst_structure_get_fraction (structure, "framerate",
1987             &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1988       } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1989         gint rate = 0;
1990         stream->subtype = FOURCC_soun;
1991         gst_structure_get_int (structure, "channels",
1992             &CUR_STREAM (stream)->n_channels);
1993         gst_structure_get_int (structure, "rate", &rate);
1994         CUR_STREAM (stream)->rate = rate;
1995       } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1996         if (gst_structure_has_field (structure, "original-media-type")) {
1997           const gchar *media_type =
1998               gst_structure_get_string (structure, "original-media-type");
1999           if (g_str_has_prefix (media_type, "video")) {
2000             stream->subtype = FOURCC_vide;
2001           } else if (g_str_has_prefix (media_type, "audio")) {
2002             stream->subtype = FOURCC_soun;
2003           }
2004         }
2005       }
2006     }
2007     gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2008   } else {
2009     demux->mss_mode = FALSE;
2010   }
2011 
2012   return TRUE;
2013 }
2014 
2015 static void
gst_qtdemux_reset(GstQTDemux * qtdemux,gboolean hard)2016 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2017 {
2018   gint i;
2019 
2020   GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2021   gst_pad_stop_task (qtdemux->sinkpad);
2022 
2023   if (hard || qtdemux->upstream_format_is_time) {
2024     qtdemux->state = QTDEMUX_STATE_INITIAL;
2025     qtdemux->neededbytes = 16;
2026     qtdemux->todrop = 0;
2027     qtdemux->pullbased = FALSE;
2028     g_clear_pointer (&qtdemux->redirect_location, g_free);
2029     qtdemux->first_mdat = -1;
2030     qtdemux->header_size = 0;
2031     qtdemux->mdatoffset = -1;
2032     qtdemux->restoredata_offset = -1;
2033     if (qtdemux->mdatbuffer)
2034       gst_buffer_unref (qtdemux->mdatbuffer);
2035     if (qtdemux->restoredata_buffer)
2036       gst_buffer_unref (qtdemux->restoredata_buffer);
2037     qtdemux->mdatbuffer = NULL;
2038     qtdemux->restoredata_buffer = NULL;
2039     qtdemux->mdatleft = 0;
2040     qtdemux->mdatsize = 0;
2041     if (qtdemux->comp_brands)
2042       gst_buffer_unref (qtdemux->comp_brands);
2043     qtdemux->comp_brands = NULL;
2044     qtdemux->last_moov_offset = -1;
2045     if (qtdemux->moov_node_compressed) {
2046       g_node_destroy (qtdemux->moov_node_compressed);
2047       if (qtdemux->moov_node)
2048         g_free (qtdemux->moov_node->data);
2049     }
2050     qtdemux->moov_node_compressed = NULL;
2051     if (qtdemux->moov_node)
2052       g_node_destroy (qtdemux->moov_node);
2053     qtdemux->moov_node = NULL;
2054     if (qtdemux->tag_list)
2055       gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2056     qtdemux->tag_list = gst_tag_list_new_empty ();
2057     gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2058 #if 0
2059     if (qtdemux->element_index)
2060       gst_object_unref (qtdemux->element_index);
2061     qtdemux->element_index = NULL;
2062 #endif
2063     qtdemux->major_brand = 0;
2064     qtdemux->upstream_format_is_time = FALSE;
2065     qtdemux->upstream_seekable = FALSE;
2066     qtdemux->upstream_size = 0;
2067 
2068     qtdemux->fragment_start = -1;
2069     qtdemux->fragment_start_offset = -1;
2070     qtdemux->duration = 0;
2071     qtdemux->moof_offset = 0;
2072     qtdemux->chapters_track_id = 0;
2073     qtdemux->have_group_id = FALSE;
2074     qtdemux->group_id = G_MAXUINT;
2075 
2076     g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2077         NULL);
2078     g_queue_clear (&qtdemux->protection_event_queue);
2079 
2080     qtdemux->received_seek = FALSE;
2081     qtdemux->first_moof_already_parsed = FALSE;
2082   }
2083   qtdemux->offset = 0;
2084   gst_adapter_clear (qtdemux->adapter);
2085   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2086   qtdemux->need_segment = TRUE;
2087 
2088   if (hard) {
2089     qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2090     qtdemux->trickmode_interval = 0;
2091     g_ptr_array_set_size (qtdemux->active_streams, 0);
2092     g_ptr_array_set_size (qtdemux->old_streams, 0);
2093     qtdemux->n_video_streams = 0;
2094     qtdemux->n_audio_streams = 0;
2095     qtdemux->n_sub_streams = 0;
2096     qtdemux->exposed = FALSE;
2097     qtdemux->fragmented = FALSE;
2098     qtdemux->mss_mode = FALSE;
2099     gst_caps_replace (&qtdemux->media_caps, NULL);
2100     qtdemux->timescale = 0;
2101     qtdemux->got_moov = FALSE;
2102     qtdemux->cenc_aux_info_offset = 0;
2103     qtdemux->cenc_aux_info_sizes = NULL;
2104     qtdemux->cenc_aux_sample_count = 0;
2105     if (qtdemux->protection_system_ids) {
2106       g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2107       qtdemux->protection_system_ids = NULL;
2108     }
2109     qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2110         && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2111         GST_BIN_FLAG_STREAMS_AWARE);
2112 
2113     if (qtdemux->preferred_protection_system_id) {
2114       g_free (qtdemux->preferred_protection_system_id);
2115       qtdemux->preferred_protection_system_id = NULL;
2116     }
2117   } else if (qtdemux->mss_mode) {
2118     gst_flow_combiner_reset (qtdemux->flowcombiner);
2119     g_ptr_array_foreach (qtdemux->active_streams,
2120         (GFunc) gst_qtdemux_stream_clear, NULL);
2121   } else {
2122     gst_flow_combiner_reset (qtdemux->flowcombiner);
2123     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2124       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2125       stream->sent_eos = FALSE;
2126       stream->time_position = 0;
2127       stream->accumulated_base = 0;
2128       stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2129     }
2130   }
2131 }
2132 
2133 
2134 /* Maps the @segment to the qt edts internal segments and pushes
2135  * the corresponding segment event.
2136  *
2137  * If it ends up being at a empty segment, a gap will be pushed and the next
2138  * edts segment will be activated in sequence.
2139  *
2140  * To be used in push-mode only */
2141 static void
gst_qtdemux_map_and_push_segments(GstQTDemux * qtdemux,GstSegment * segment)2142 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2143 {
2144   gint i, iter;
2145 
2146   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2147     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2148 
2149     stream->time_position = segment->start;
2150 
2151     /* in push mode we should be guaranteed that we will have empty segments
2152      * at the beginning and then one segment after, other scenarios are not
2153      * supported and are discarded when parsing the edts */
2154     for (i = 0; i < stream->n_segments; i++) {
2155       if (stream->segments[i].stop_time > segment->start) {
2156         /* push the empty segment and move to the next one */
2157         gst_qtdemux_activate_segment (qtdemux, stream, i,
2158             stream->time_position);
2159         if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2160           gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2161               stream->time_position);
2162 
2163           /* accumulate previous segments */
2164           if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2165             stream->accumulated_base +=
2166                 (stream->segment.stop -
2167                 stream->segment.start) / ABS (stream->segment.rate);
2168           continue;
2169         }
2170 
2171         g_assert (i == stream->n_segments - 1);
2172       }
2173     }
2174   }
2175 }
2176 
2177 static void
gst_qtdemux_stream_concat(GstQTDemux * qtdemux,GPtrArray * dest,GPtrArray * src)2178 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2179     GPtrArray * src)
2180 {
2181   guint i;
2182   guint len;
2183 
2184   len = src->len;
2185 
2186   if (len == 0)
2187     return;
2188 
2189   for (i = 0; i < len; i++) {
2190     QtDemuxStream *stream = g_ptr_array_index (src, i);
2191 
2192 #ifndef GST_DISABLE_GST_DEBUG
2193     GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2194         stream, GST_STR_NULL (stream->stream_id), dest);
2195 #endif
2196     g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2197   }
2198 
2199   g_ptr_array_set_size (src, 0);
2200 }
2201 
2202 static gboolean
gst_qtdemux_handle_sink_event(GstPad * sinkpad,GstObject * parent,GstEvent * event)2203 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2204     GstEvent * event)
2205 {
2206   GstQTDemux *demux = GST_QTDEMUX (parent);
2207   gboolean res = TRUE;
2208 
2209   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2210 
2211   switch (GST_EVENT_TYPE (event)) {
2212     case GST_EVENT_SEGMENT:
2213     {
2214       gint64 offset = 0;
2215       QtDemuxStream *stream;
2216       gint idx;
2217       GstSegment segment;
2218 
2219       /* some debug output */
2220       gst_event_copy_segment (event, &segment);
2221       GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2222           &segment);
2223 
2224       if (segment.format == GST_FORMAT_TIME) {
2225         demux->upstream_format_is_time = TRUE;
2226         demux->segment_seqnum = gst_event_get_seqnum (event);
2227       } else {
2228         GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2229             "not in time format");
2230 
2231         /* chain will send initial newsegment after pads have been added */
2232         if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2233           GST_DEBUG_OBJECT (demux, "still starting, eating event");
2234           goto exit;
2235         }
2236       }
2237 
2238       /* check if this matches a time seek we received previously
2239        * FIXME for backwards compatibility reasons we use the
2240        * seek_offset here to compare. In the future we might want to
2241        * change this to use the seqnum as it uniquely should identify
2242        * the segment that corresponds to the seek. */
2243       GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2244           ", received segment offset %" G_GINT64_FORMAT,
2245           demux->seek_offset, segment.start);
2246       if (segment.format == GST_FORMAT_BYTES
2247           && demux->seek_offset == segment.start) {
2248         GST_OBJECT_LOCK (demux);
2249         offset = segment.start;
2250 
2251         segment.format = GST_FORMAT_TIME;
2252         segment.start = demux->push_seek_start;
2253         segment.stop = demux->push_seek_stop;
2254         GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2255             "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2256             GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2257         GST_OBJECT_UNLOCK (demux);
2258       }
2259 
2260       /* we only expect a BYTE segment, e.g. following a seek */
2261       if (segment.format == GST_FORMAT_BYTES) {
2262         if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2263           offset = segment.start;
2264 
2265           gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2266               NULL, (gint64 *) & segment.start);
2267           if ((gint64) segment.start < 0)
2268             segment.start = 0;
2269         }
2270         if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2271           gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2272               NULL, (gint64 *) & segment.stop);
2273           /* keyframe seeking should already arrange for start >= stop,
2274            * but make sure in other rare cases */
2275           segment.stop = MAX (segment.stop, segment.start);
2276         }
2277       } else if (segment.format == GST_FORMAT_TIME) {
2278         /* push all data on the adapter before starting this
2279          * new segment */
2280         gst_qtdemux_process_adapter (demux, TRUE);
2281       } else {
2282         GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2283         goto exit;
2284       }
2285 
2286       /* We shouldn't modify upstream driven TIME FORMAT segment */
2287       if (!demux->upstream_format_is_time) {
2288         /* accept upstream's notion of segment and distribute along */
2289         segment.format = GST_FORMAT_TIME;
2290         segment.position = segment.time = segment.start;
2291         segment.duration = demux->segment.duration;
2292         segment.base = gst_segment_to_running_time (&demux->segment,
2293             GST_FORMAT_TIME, demux->segment.position);
2294       }
2295 
2296       gst_segment_copy_into (&segment, &demux->segment);
2297       GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2298 
2299       /* map segment to internal qt segments and push on each stream */
2300       if (QTDEMUX_N_STREAMS (demux)) {
2301         demux->need_segment = TRUE;
2302         gst_qtdemux_check_send_pending_segment (demux);
2303       }
2304 
2305       /* clear leftover in current segment, if any */
2306       gst_adapter_clear (demux->adapter);
2307 
2308       /* set up streaming thread */
2309       demux->offset = offset;
2310       if (demux->upstream_format_is_time) {
2311         GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2312             "set values to restart reading from a new atom");
2313         demux->neededbytes = 16;
2314         demux->todrop = 0;
2315       } else {
2316         gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2317             NULL);
2318         if (stream) {
2319           demux->todrop = stream->samples[idx].offset - offset;
2320           demux->neededbytes = demux->todrop + stream->samples[idx].size;
2321         } else {
2322           /* set up for EOS */
2323           demux->neededbytes = -1;
2324           demux->todrop = 0;
2325         }
2326       }
2327     exit:
2328       gst_event_unref (event);
2329       res = TRUE;
2330       goto drop;
2331     }
2332     case GST_EVENT_FLUSH_START:
2333     {
2334       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2335         gst_event_unref (event);
2336         goto drop;
2337       }
2338       QTDEMUX_EXPOSE_LOCK (demux);
2339       res = gst_pad_event_default (demux->sinkpad, parent, event);
2340       QTDEMUX_EXPOSE_UNLOCK (demux);
2341       goto drop;
2342     }
2343     case GST_EVENT_FLUSH_STOP:
2344     {
2345       guint64 dur;
2346 
2347       dur = demux->segment.duration;
2348       gst_qtdemux_reset (demux, FALSE);
2349       demux->segment.duration = dur;
2350 
2351       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2352         gst_event_unref (event);
2353         goto drop;
2354       }
2355       break;
2356     }
2357     case GST_EVENT_EOS:
2358       /* If we are in push mode, and get an EOS before we've seen any streams,
2359        * then error out - we have nowhere to send the EOS */
2360       if (!demux->pullbased) {
2361         gint i;
2362         gboolean has_valid_stream = FALSE;
2363         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2364           if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2365             has_valid_stream = TRUE;
2366             break;
2367           }
2368         }
2369         if (!has_valid_stream)
2370           gst_qtdemux_post_no_playable_stream_error (demux);
2371         else {
2372           GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2373               (guint) gst_adapter_available (demux->adapter));
2374           if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2375             res = FALSE;
2376           }
2377         }
2378       }
2379       break;
2380     case GST_EVENT_CAPS:{
2381       GstCaps *caps = NULL;
2382 
2383       gst_event_parse_caps (event, &caps);
2384       gst_qtdemux_setcaps (demux, caps);
2385       res = TRUE;
2386       gst_event_unref (event);
2387       goto drop;
2388     }
2389     case GST_EVENT_PROTECTION:
2390     {
2391       const gchar *system_id = NULL;
2392 
2393       gst_event_parse_protection (event, &system_id, NULL, NULL);
2394       GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2395           system_id);
2396       gst_qtdemux_append_protection_system_id (demux, system_id);
2397       /* save the event for later, for source pads that have not been created */
2398       g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2399       /* send it to all pads that already exist */
2400       gst_qtdemux_push_event (demux, event);
2401       res = TRUE;
2402       goto drop;
2403     }
2404     case GST_EVENT_STREAM_START:
2405     {
2406       res = TRUE;
2407       gst_event_unref (event);
2408 
2409       /* Drain all the buffers */
2410       gst_qtdemux_process_adapter (demux, TRUE);
2411       gst_qtdemux_reset (demux, FALSE);
2412       /* We expect new moov box after new stream-start event */
2413       if (demux->exposed) {
2414         gst_qtdemux_stream_concat (demux,
2415             demux->old_streams, demux->active_streams);
2416       }
2417 
2418       goto drop;
2419     }
2420     default:
2421       break;
2422   }
2423 
2424   res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2425 
2426 drop:
2427   return res;
2428 }
2429 
2430 static gboolean
gst_qtdemux_handle_sink_query(GstPad * pad,GstObject * parent,GstQuery * query)2431 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2432     GstQuery * query)
2433 {
2434   GstQTDemux *demux = GST_QTDEMUX (parent);
2435   gboolean res = FALSE;
2436 
2437   switch (GST_QUERY_TYPE (query)) {
2438     case GST_QUERY_BITRATE:
2439     {
2440       GstClockTime duration;
2441 
2442       /* populate demux->upstream_size if not done yet */
2443       gst_qtdemux_check_seekability (demux);
2444 
2445       if (demux->upstream_size != -1
2446           && gst_qtdemux_get_duration (demux, &duration)) {
2447         guint bitrate =
2448             gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2449             duration);
2450 
2451         GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2452             " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2453             demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2454 
2455         /* TODO: better results based on ranges/index tables */
2456         gst_query_set_bitrate (query, bitrate);
2457         res = TRUE;
2458       }
2459       break;
2460     }
2461     default:
2462       res = gst_pad_query_default (pad, (GstObject *) demux, query);
2463       break;
2464   }
2465 
2466   return res;
2467 }
2468 
2469 
2470 #if 0
2471 static void
2472 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2473 {
2474   GstQTDemux *demux = GST_QTDEMUX (element);
2475 
2476   GST_OBJECT_LOCK (demux);
2477   if (demux->element_index)
2478     gst_object_unref (demux->element_index);
2479   if (index) {
2480     demux->element_index = gst_object_ref (index);
2481   } else {
2482     demux->element_index = NULL;
2483   }
2484   GST_OBJECT_UNLOCK (demux);
2485   /* object lock might be taken again */
2486   if (index)
2487     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2488   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2489       demux->element_index, demux->index_id);
2490 }
2491 
2492 static GstIndex *
2493 gst_qtdemux_get_index (GstElement * element)
2494 {
2495   GstIndex *result = NULL;
2496   GstQTDemux *demux = GST_QTDEMUX (element);
2497 
2498   GST_OBJECT_LOCK (demux);
2499   if (demux->element_index)
2500     result = gst_object_ref (demux->element_index);
2501   GST_OBJECT_UNLOCK (demux);
2502 
2503   GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2504 
2505   return result;
2506 }
2507 #endif
2508 
2509 static void
gst_qtdemux_stbl_free(QtDemuxStream * stream)2510 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2511 {
2512   g_free ((gpointer) stream->stco.data);
2513   stream->stco.data = NULL;
2514   g_free ((gpointer) stream->stsz.data);
2515   stream->stsz.data = NULL;
2516   g_free ((gpointer) stream->stsc.data);
2517   stream->stsc.data = NULL;
2518   g_free ((gpointer) stream->stts.data);
2519   stream->stts.data = NULL;
2520   g_free ((gpointer) stream->stss.data);
2521   stream->stss.data = NULL;
2522   g_free ((gpointer) stream->stps.data);
2523   stream->stps.data = NULL;
2524   g_free ((gpointer) stream->ctts.data);
2525   stream->ctts.data = NULL;
2526 }
2527 
2528 static void
gst_qtdemux_stream_flush_segments_data(QtDemuxStream * stream)2529 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2530 {
2531   g_free (stream->segments);
2532   stream->segments = NULL;
2533   stream->segment_index = -1;
2534   stream->accumulated_base = 0;
2535 }
2536 
2537 static void
gst_qtdemux_stream_flush_samples_data(QtDemuxStream * stream)2538 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2539 {
2540   g_free (stream->samples);
2541   stream->samples = NULL;
2542   gst_qtdemux_stbl_free (stream);
2543 
2544   /* fragments */
2545   g_free (stream->ra_entries);
2546   stream->ra_entries = NULL;
2547   stream->n_ra_entries = 0;
2548 
2549   stream->sample_index = -1;
2550   stream->stbl_index = -1;
2551   stream->n_samples = 0;
2552   stream->time_position = 0;
2553 
2554   stream->n_samples_moof = 0;
2555   stream->duration_moof = 0;
2556   stream->duration_last_moof = 0;
2557 }
2558 
2559 static void
gst_qtdemux_stream_clear(QtDemuxStream * stream)2560 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2561 {
2562   gint i;
2563   if (stream->allocator)
2564     gst_object_unref (stream->allocator);
2565   while (stream->buffers) {
2566     gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2567     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2568   }
2569   for (i = 0; i < stream->stsd_entries_length; i++) {
2570     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2571     if (entry->rgb8_palette) {
2572       gst_memory_unref (entry->rgb8_palette);
2573       entry->rgb8_palette = NULL;
2574     }
2575     entry->sparse = FALSE;
2576   }
2577 
2578   if (stream->stream_tags)
2579     gst_tag_list_unref (stream->stream_tags);
2580 
2581   stream->stream_tags = gst_tag_list_new_empty ();
2582   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2583   g_free (stream->redirect_uri);
2584   stream->redirect_uri = NULL;
2585   stream->sent_eos = FALSE;
2586   stream->protected = FALSE;
2587 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
2588   stream->has_push_first_frame = FALSE;
2589 #endif
2590   if (stream->protection_scheme_info) {
2591     if (stream->protection_scheme_type == FOURCC_cenc
2592         || stream->protection_scheme_type == FOURCC_cbcs) {
2593       QtDemuxCencSampleSetInfo *info =
2594           (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2595       if (info->default_properties)
2596         gst_structure_free (info->default_properties);
2597       if (info->crypto_info)
2598         g_ptr_array_free (info->crypto_info, TRUE);
2599     }
2600     if (stream->protection_scheme_type == FOURCC_aavd) {
2601       QtDemuxAavdEncryptionInfo *info =
2602           (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2603       if (info->default_properties)
2604         gst_structure_free (info->default_properties);
2605     }
2606     g_free (stream->protection_scheme_info);
2607     stream->protection_scheme_info = NULL;
2608   }
2609   stream->protection_scheme_type = 0;
2610   stream->protection_scheme_version = 0;
2611   g_queue_foreach (&stream->protection_scheme_event_queue,
2612       (GFunc) gst_event_unref, NULL);
2613   g_queue_clear (&stream->protection_scheme_event_queue);
2614   gst_qtdemux_stream_flush_segments_data (stream);
2615   gst_qtdemux_stream_flush_samples_data (stream);
2616 }
2617 
2618 static void
gst_qtdemux_stream_reset(QtDemuxStream * stream)2619 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2620 {
2621   gint i;
2622   gst_qtdemux_stream_clear (stream);
2623   for (i = 0; i < stream->stsd_entries_length; i++) {
2624     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2625     if (entry->caps) {
2626       gst_caps_unref (entry->caps);
2627       entry->caps = NULL;
2628     }
2629   }
2630   g_free (stream->stsd_entries);
2631   stream->stsd_entries = NULL;
2632   stream->stsd_entries_length = 0;
2633 }
2634 
2635 static QtDemuxStream *
gst_qtdemux_stream_ref(QtDemuxStream * stream)2636 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2637 {
2638   g_atomic_int_add (&stream->ref_count, 1);
2639 
2640   return stream;
2641 }
2642 
2643 static void
gst_qtdemux_stream_unref(QtDemuxStream * stream)2644 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2645 {
2646   if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2647     gst_qtdemux_stream_reset (stream);
2648     gst_tag_list_unref (stream->stream_tags);
2649     if (stream->pad) {
2650       GstQTDemux *demux = stream->demux;
2651       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2652       GST_OBJECT_LOCK (demux);
2653       gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2654       GST_OBJECT_UNLOCK (demux);
2655     }
2656     g_free (stream->stream_id);
2657     g_free (stream);
2658   }
2659 }
2660 
2661 static GstStateChangeReturn
gst_qtdemux_change_state(GstElement * element,GstStateChange transition)2662 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2663 {
2664   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2665   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2666 
2667   switch (transition) {
2668     case GST_STATE_CHANGE_READY_TO_PAUSED:
2669       gst_qtdemux_reset (qtdemux, TRUE);
2670       break;
2671     default:
2672       break;
2673   }
2674 
2675   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2676 
2677   switch (transition) {
2678     case GST_STATE_CHANGE_PAUSED_TO_READY:{
2679       gst_qtdemux_reset (qtdemux, TRUE);
2680       break;
2681     }
2682     default:
2683       break;
2684   }
2685 
2686   return result;
2687 }
2688 
2689 static void
gst_qtdemux_set_context(GstElement * element,GstContext * context)2690 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2691 {
2692   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2693 
2694   g_return_if_fail (GST_IS_CONTEXT (context));
2695 
2696   if (gst_context_has_context_type (context,
2697           "drm-preferred-decryption-system-id")) {
2698     const GstStructure *s;
2699 
2700     s = gst_context_get_structure (context);
2701     g_free (qtdemux->preferred_protection_system_id);
2702     qtdemux->preferred_protection_system_id =
2703         g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2704     GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2705         qtdemux->preferred_protection_system_id);
2706   }
2707 
2708   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2709 }
2710 
2711 static void
qtdemux_parse_ftyp(GstQTDemux * qtdemux,const guint8 * buffer,gint length)2712 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2713 {
2714   /* counts as header data */
2715   qtdemux->header_size += length;
2716 
2717   /* only consider at least a sufficiently complete ftyp atom */
2718   if (length >= 20) {
2719     GstBuffer *buf;
2720 
2721     qtdemux->major_brand = QT_FOURCC (buffer + 8);
2722     GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2723         GST_FOURCC_ARGS (qtdemux->major_brand));
2724     if (qtdemux->comp_brands)
2725       gst_buffer_unref (qtdemux->comp_brands);
2726     buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2727     gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2728   }
2729 }
2730 
2731 static void
qtdemux_update_default_sample_cenc_settings(GstQTDemux * qtdemux,QtDemuxCencSampleSetInfo * info,guint32 is_encrypted,guint32 protection_scheme_type,guint8 iv_size,const guint8 * kid,guint crypt_byte_block,guint skip_byte_block,guint8 constant_iv_size,const guint8 * constant_iv)2732 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2733     QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2734     guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2735     guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2736     const guint8 * constant_iv)
2737 {
2738   GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2739   gst_buffer_fill (kid_buf, 0, kid, 16);
2740   if (info->default_properties)
2741     gst_structure_free (info->default_properties);
2742   info->default_properties =
2743       gst_structure_new ("application/x-cenc",
2744       "iv_size", G_TYPE_UINT, iv_size,
2745       "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2746       "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2747   GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2748       "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2749   gst_buffer_unref (kid_buf);
2750   if (protection_scheme_type == FOURCC_cbcs) {
2751     if (crypt_byte_block != 0 || skip_byte_block != 0) {
2752       gst_structure_set (info->default_properties, "crypt_byte_block",
2753           G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2754           skip_byte_block, NULL);
2755     }
2756     if (constant_iv != NULL) {
2757       GstBuffer *constant_iv_buf =
2758           gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2759       gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2760       gst_structure_set (info->default_properties, "constant_iv_size",
2761           G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2762           NULL);
2763       gst_buffer_unref (constant_iv_buf);
2764     }
2765     gst_structure_set (info->default_properties, "cipher-mode",
2766         G_TYPE_STRING, "cbcs", NULL);
2767   } else {
2768     gst_structure_set (info->default_properties, "cipher-mode",
2769         G_TYPE_STRING, "cenc", NULL);
2770   }
2771 }
2772 
2773 static gboolean
qtdemux_update_default_piff_encryption_settings(GstQTDemux * qtdemux,QtDemuxCencSampleSetInfo * info,GstByteReader * br)2774 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2775     QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2776 {
2777   guint32 algorithm_id = 0;
2778   const guint8 *kid;
2779   gboolean is_encrypted = TRUE;
2780   guint8 iv_size = 8;
2781 
2782   if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2783     GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2784     return FALSE;
2785   }
2786 
2787   algorithm_id >>= 8;
2788   if (algorithm_id == 0) {
2789     is_encrypted = FALSE;
2790   } else if (algorithm_id == 1) {
2791     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2792   } else if (algorithm_id == 2) {
2793     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2794   }
2795 
2796   if (!gst_byte_reader_get_uint8 (br, &iv_size))
2797     return FALSE;
2798 
2799   if (!gst_byte_reader_get_data (br, 16, &kid))
2800     return FALSE;
2801 
2802   qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2803       is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2804   gst_structure_set (info->default_properties, "piff_algorithm_id",
2805       G_TYPE_UINT, algorithm_id, NULL);
2806   return TRUE;
2807 }
2808 
2809 
2810 static void
qtdemux_parse_piff(GstQTDemux * qtdemux,const guint8 * buffer,gint length,guint offset)2811 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2812     guint offset)
2813 {
2814   GstByteReader br;
2815   guint8 version;
2816   guint32 flags = 0;
2817   guint i;
2818   guint iv_size = 8;
2819   QtDemuxStream *stream;
2820   GstStructure *structure;
2821   QtDemuxCencSampleSetInfo *ss_info = NULL;
2822   const gchar *system_id;
2823   gboolean uses_sub_sample_encryption = FALSE;
2824   guint32 sample_count;
2825 
2826   if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2827     return;
2828 
2829   stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2830 
2831   structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2832   if (!gst_structure_has_name (structure, "application/x-cenc")) {
2833     GST_WARNING_OBJECT (qtdemux,
2834         "Attempting PIFF box parsing on an unencrypted stream.");
2835     return;
2836   }
2837 
2838   gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2839       G_TYPE_STRING, &system_id, NULL);
2840   gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2841 
2842   stream->protected = TRUE;
2843   stream->protection_scheme_type = FOURCC_cenc;
2844 
2845   if (!stream->protection_scheme_info)
2846     stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2847 
2848   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2849   if (!ss_info->default_properties) {
2850     ss_info->default_properties =
2851         gst_structure_new ("application/x-cenc",
2852         "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2853         NULL);
2854 
2855   }
2856 
2857   if (ss_info->crypto_info) {
2858     GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2859     g_ptr_array_free (ss_info->crypto_info, TRUE);
2860     ss_info->crypto_info = NULL;
2861   }
2862 
2863   /* skip UUID */
2864   gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2865 
2866   if (!gst_byte_reader_get_uint8 (&br, &version)) {
2867     GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2868     return;
2869   }
2870 
2871   if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2872     GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2873     return;
2874   }
2875 
2876   if ((flags & 0x000001)) {
2877     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2878             &br))
2879       return;
2880   } else if ((flags & 0x000002)) {
2881     uses_sub_sample_encryption = TRUE;
2882   }
2883 
2884   if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2885           &iv_size)) {
2886     GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2887     return;
2888   }
2889 
2890   if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2891     GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2892     return;
2893   }
2894 
2895   ss_info->crypto_info =
2896       g_ptr_array_new_full (sample_count,
2897       (GDestroyNotify) qtdemux_gst_structure_free);
2898 
2899   for (i = 0; i < sample_count; ++i) {
2900     GstStructure *properties;
2901     guint8 *data;
2902     GstBuffer *buf;
2903 
2904     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2905     if (properties == NULL) {
2906       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2907       qtdemux->cenc_aux_sample_count = i;
2908       return;
2909     }
2910 
2911     if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2912       GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2913       gst_structure_free (properties);
2914       qtdemux->cenc_aux_sample_count = i;
2915       return;
2916     }
2917     buf = gst_buffer_new_wrapped (data, iv_size);
2918     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2919     gst_buffer_unref (buf);
2920 
2921     if (uses_sub_sample_encryption) {
2922       guint16 n_subsamples;
2923       const GValue *kid_buf_value;
2924 
2925       if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2926           || n_subsamples == 0) {
2927         GST_ERROR_OBJECT (qtdemux,
2928             "failed to get subsample count for sample %u", i);
2929         gst_structure_free (properties);
2930         qtdemux->cenc_aux_sample_count = i;
2931         return;
2932       }
2933       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2934       if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2935         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2936             i);
2937         gst_structure_free (properties);
2938         qtdemux->cenc_aux_sample_count = i;
2939         return;
2940       }
2941       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2942 
2943       kid_buf_value =
2944           gst_structure_get_value (ss_info->default_properties, "kid");
2945 
2946       gst_structure_set (properties,
2947           "subsample_count", G_TYPE_UINT, n_subsamples,
2948           "subsamples", GST_TYPE_BUFFER, buf, NULL);
2949       gst_structure_set_value (properties, "kid", kid_buf_value);
2950       gst_buffer_unref (buf);
2951     } else {
2952       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2953     }
2954 
2955     g_ptr_array_add (ss_info->crypto_info, properties);
2956   }
2957 
2958   qtdemux->cenc_aux_sample_count = sample_count;
2959 }
2960 
2961 static void
qtdemux_parse_uuid(GstQTDemux * qtdemux,const guint8 * buffer,gint length)2962 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2963 {
2964   static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2965     0x97, 0xA9, 0x42, 0xE8,
2966     0x9C, 0x71, 0x99, 0x94,
2967     0x91, 0xE3, 0xAF, 0xAC
2968   };
2969   static const guint8 playready_uuid[] = {
2970     0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2971     0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2972   };
2973 
2974   static const guint8 piff_sample_encryption_uuid[] = {
2975     0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2976     0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2977   };
2978 
2979   guint offset;
2980 
2981   /* counts as header data */
2982   qtdemux->header_size += length;
2983 
2984   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2985 
2986   if (length <= offset + 16) {
2987     GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2988     return;
2989   }
2990 
2991   if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2992     GstBuffer *buf;
2993     GstTagList *taglist;
2994 
2995     buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2996         length - offset - 16, NULL);
2997     taglist = gst_tag_list_from_xmp_buffer (buf);
2998     gst_buffer_unref (buf);
2999 
3000     /* make sure we have a usable taglist */
3001     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3002 
3003     qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3004 
3005   } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3006     int len;
3007     const gunichar2 *s_utf16;
3008     char *contents;
3009 
3010     len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3011     s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3012     contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3013     GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3014 
3015     g_free (contents);
3016 
3017     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3018         (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3019         (NULL));
3020   } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3021     qtdemux_parse_piff (qtdemux, buffer, length, offset);
3022   } else {
3023     GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3024         GST_READ_UINT32_LE (buffer + offset),
3025         GST_READ_UINT32_LE (buffer + offset + 4),
3026         GST_READ_UINT32_LE (buffer + offset + 8),
3027         GST_READ_UINT32_LE (buffer + offset + 12));
3028   }
3029 }
3030 
3031 static void
qtdemux_parse_sidx(GstQTDemux * qtdemux,const guint8 * buffer,gint length)3032 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3033 {
3034   GstSidxParser sidx_parser;
3035   GstIsoffParserResult res;
3036   guint consumed;
3037 
3038   gst_isoff_qt_sidx_parser_init (&sidx_parser);
3039 
3040   res =
3041       gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3042       &consumed);
3043   GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3044   if (res == GST_ISOFF_QT_PARSER_DONE) {
3045     check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3046   }
3047   gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3048 }
3049 
3050 /* caller verifies at least 8 bytes in buf */
3051 static void
extract_initial_length_and_fourcc(const guint8 * data,guint size,guint64 * plength,guint32 * pfourcc)3052 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3053     guint64 * plength, guint32 * pfourcc)
3054 {
3055   guint64 length;
3056   guint32 fourcc;
3057 
3058   length = QT_UINT32 (data);
3059   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3060   fourcc = QT_FOURCC (data + 4);
3061   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3062 
3063   if (length == 0) {
3064     length = G_MAXUINT64;
3065   } else if (length == 1 && size >= 16) {
3066     /* this means we have an extended size, which is the 64 bit value of
3067      * the next 8 bytes */
3068     length = QT_UINT64 (data + 8);
3069     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3070   }
3071 
3072   if (plength)
3073     *plength = length;
3074   if (pfourcc)
3075     *pfourcc = fourcc;
3076 }
3077 
3078 static gboolean
qtdemux_parse_mehd(GstQTDemux * qtdemux,GstByteReader * br)3079 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3080 {
3081   guint32 version = 0;
3082   GstClockTime duration = 0;
3083 
3084   if (!gst_byte_reader_get_uint32_be (br, &version))
3085     goto failed;
3086 
3087   version >>= 24;
3088   if (version == 1) {
3089     if (!gst_byte_reader_get_uint64_be (br, &duration))
3090       goto failed;
3091   } else {
3092     guint32 dur = 0;
3093 
3094     if (!gst_byte_reader_get_uint32_be (br, &dur))
3095       goto failed;
3096     duration = dur;
3097   }
3098 
3099   GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3100   qtdemux->duration = duration;
3101 
3102   return TRUE;
3103 
3104 failed:
3105   {
3106     GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3107     return FALSE;
3108   }
3109 }
3110 
3111 static gboolean
qtdemux_parse_trex(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 * ds_duration,guint32 * ds_size,guint32 * ds_flags)3112 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3113     guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3114 {
3115   if (!stream->parsed_trex && qtdemux->moov_node) {
3116     GNode *mvex, *trex;
3117     GstByteReader trex_data;
3118 
3119     mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3120     if (mvex) {
3121       trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3122           &trex_data);
3123       while (trex) {
3124         guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3125 
3126         /* skip version/flags */
3127         if (!gst_byte_reader_skip (&trex_data, 4))
3128           goto next;
3129         if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3130           goto next;
3131         if (id != stream->track_id)
3132           goto next;
3133         if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3134           goto next;
3135         if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3136           goto next;
3137         if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3138           goto next;
3139         if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3140           goto next;
3141 
3142         GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3143             "duration %d,  size %d, flags 0x%x", stream->track_id,
3144             dur, size, flags);
3145 
3146         stream->parsed_trex = TRUE;
3147         stream->def_sample_description_index = sdi;
3148         stream->def_sample_duration = dur;
3149         stream->def_sample_size = size;
3150         stream->def_sample_flags = flags;
3151 
3152       next:
3153         /* iterate all siblings */
3154         trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3155             &trex_data);
3156       }
3157     }
3158   }
3159 
3160   *ds_duration = stream->def_sample_duration;
3161   *ds_size = stream->def_sample_size;
3162   *ds_flags = stream->def_sample_flags;
3163 
3164   /* even then, above values are better than random ... */
3165   if (G_UNLIKELY (!stream->parsed_trex)) {
3166     GST_WARNING_OBJECT (qtdemux,
3167         "failed to find fragment defaults for stream %d", stream->track_id);
3168     return FALSE;
3169   }
3170 
3171   return TRUE;
3172 }
3173 
3174 /* This method should be called whenever a more accurate duration might
3175  * have been found. It will update all relevant variables if/where needed
3176  */
3177 static void
check_update_duration(GstQTDemux * qtdemux,GstClockTime duration)3178 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3179 {
3180   guint i;
3181   guint64 movdur;
3182   GstClockTime prevdur;
3183 
3184   movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3185 
3186   if (movdur > qtdemux->duration) {
3187     prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3188     GST_DEBUG_OBJECT (qtdemux,
3189         "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3190         GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3191     qtdemux->duration = movdur;
3192     GST_DEBUG_OBJECT (qtdemux,
3193         "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3194         GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3195         GST_TIME_ARGS (qtdemux->segment.stop));
3196     if (qtdemux->segment.duration == prevdur) {
3197       /* If the current segment has duration/stop identical to previous duration
3198        * update them also (because they were set at that point in time with
3199        * the wrong duration */
3200       /* We convert the value *from* the timescale version to avoid rounding errors */
3201       GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3202       GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3203       qtdemux->segment.duration = fixeddur;
3204       qtdemux->segment.stop = fixeddur;
3205     }
3206   }
3207 
3208   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3209     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3210 
3211     movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3212     if (movdur > stream->duration) {
3213       GST_DEBUG_OBJECT (qtdemux,
3214           "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3215           GST_TIME_ARGS (duration));
3216       stream->duration = movdur;
3217       /* internal duration tracking state has been updated above, so */
3218       /* preserve an open-ended dummy segment rather than repeatedly updating
3219        * it and spamming downstream accordingly with segment events */
3220       /* also mangle the edit list end time when fragmented with a single edit
3221        * list that may only cover any non-fragmented data */
3222       if ((stream->dummy_segment ||
3223               (qtdemux->fragmented && stream->n_segments == 1)) &&
3224           GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3225         /* Update all dummy values to new duration */
3226         stream->segments[0].stop_time = duration;
3227         stream->segments[0].duration = duration;
3228         stream->segments[0].media_stop = duration;
3229 
3230         /* let downstream know we possibly have a new stop time */
3231         if (stream->segment_index != -1) {
3232           GstClockTime pos;
3233 
3234           if (qtdemux->segment.rate >= 0) {
3235             pos = stream->segment.start;
3236           } else {
3237             pos = stream->segment.stop;
3238           }
3239 
3240           gst_qtdemux_stream_update_segment (qtdemux, stream,
3241               stream->segment_index, pos, NULL, NULL);
3242         }
3243       }
3244     }
3245   }
3246 }
3247 
3248 static gboolean
qtdemux_parse_trun(GstQTDemux * qtdemux,GstByteReader * trun,QtDemuxStream * stream,guint32 d_sample_duration,guint32 d_sample_size,guint32 d_sample_flags,gint64 moof_offset,gint64 moof_length,gint64 * base_offset,gint64 * running_offset,gint64 decode_ts,gboolean has_tfdt)3249 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3250     QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3251     guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3252     gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3253     gboolean has_tfdt)
3254 {
3255   GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3256   guint64 timestamp;
3257   gint32 data_offset = 0;
3258   guint8 version;
3259   guint32 flags = 0, first_flags = 0, samples_count = 0;
3260   gint i;
3261   guint8 *data;
3262   guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3263   QtDemuxSample *sample;
3264   gboolean ismv = FALSE;
3265   gint64 initial_offset;
3266   gint32 min_ct = 0;
3267 
3268   GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3269       "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3270       "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3271       d_sample_size, d_sample_flags, *base_offset, decode_ts);
3272 
3273   if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3274     GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3275     return TRUE;
3276   }
3277 
3278   /* presence of stss or not can't really tell us much,
3279    * and flags and so on tend to be marginally reliable in these files */
3280   if (stream->subtype == FOURCC_soun) {
3281     GST_DEBUG_OBJECT (qtdemux,
3282         "sound track in fragmented file; marking all keyframes");
3283     stream->all_keyframe = TRUE;
3284   }
3285 
3286   if (!gst_byte_reader_get_uint8 (trun, &version) ||
3287       !gst_byte_reader_get_uint24_be (trun, &flags))
3288     goto fail;
3289 
3290   if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3291     goto fail;
3292 
3293   if (flags & TR_DATA_OFFSET) {
3294     /* note this is really signed */
3295     if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3296       goto fail;
3297     GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3298     /* default base offset = first byte of moof */
3299     if (*base_offset == -1) {
3300       GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3301       *base_offset = moof_offset;
3302     }
3303     *running_offset = *base_offset + data_offset;
3304   } else {
3305     /* if no offset at all, that would mean data starts at moof start,
3306      * which is a bit wrong and is ismv crappy way, so compensate
3307      * assuming data is in mdat following moof */
3308     if (*base_offset == -1) {
3309       *base_offset = moof_offset + moof_length + 8;
3310       GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3311       ismv = TRUE;
3312     }
3313     if (*running_offset == -1)
3314       *running_offset = *base_offset;
3315   }
3316 
3317   GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3318       *running_offset);
3319   GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3320       data_offset, flags, samples_count);
3321 
3322   if (flags & TR_FIRST_SAMPLE_FLAGS) {
3323     if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3324       GST_DEBUG_OBJECT (qtdemux,
3325           "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3326       flags ^= TR_FIRST_SAMPLE_FLAGS;
3327     } else {
3328       if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3329         goto fail;
3330       GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3331     }
3332   }
3333 
3334   /* FIXME ? spec says other bits should also be checked to determine
3335    * entry size (and prefix size for that matter) */
3336   entry_size = 0;
3337   dur_offset = size_offset = 0;
3338   if (flags & TR_SAMPLE_DURATION) {
3339     GST_LOG_OBJECT (qtdemux, "entry duration present");
3340     dur_offset = entry_size;
3341     entry_size += 4;
3342   }
3343   if (flags & TR_SAMPLE_SIZE) {
3344     GST_LOG_OBJECT (qtdemux, "entry size present");
3345     size_offset = entry_size;
3346     entry_size += 4;
3347   }
3348   if (flags & TR_SAMPLE_FLAGS) {
3349     GST_LOG_OBJECT (qtdemux, "entry flags present");
3350     flags_offset = entry_size;
3351     entry_size += 4;
3352   }
3353   if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3354     GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3355     ct_offset = entry_size;
3356     entry_size += 4;
3357   }
3358 
3359   if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3360     goto fail;
3361   data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3362 
3363   if (stream->n_samples + samples_count >=
3364       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3365     goto index_too_big;
3366 
3367   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3368       stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3369       (stream->n_samples + samples_count) *
3370       sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3371 
3372   /* create a new array of samples if it's the first sample parsed */
3373   if (stream->n_samples == 0) {
3374     g_assert (stream->samples == NULL);
3375     stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3376     /* or try to reallocate it with space enough to insert the new samples */
3377   } else
3378     stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3379         stream->n_samples + samples_count);
3380   if (stream->samples == NULL)
3381     goto out_of_memory;
3382 
3383   if (qtdemux->fragment_start != -1) {
3384     timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3385     qtdemux->fragment_start = -1;
3386   } else {
3387     if (stream->n_samples == 0) {
3388       if (decode_ts > 0) {
3389         timestamp = decode_ts;
3390       } else if (stream->pending_seek != NULL) {
3391         /* if we don't have a timestamp from a tfdt box, we'll use the one
3392          * from the mfra seek table */
3393         GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3394             GST_TIME_ARGS (stream->pending_seek->ts));
3395 
3396         /* FIXME: this is not fully correct, the timestamp refers to the random
3397          * access sample refered to in the tfra entry, which may not necessarily
3398          * be the first sample in the tfrag/trun (but hopefully/usually is) */
3399         timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3400       } else {
3401         timestamp = 0;
3402       }
3403 
3404       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3405       GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3406           GST_TIME_ARGS (gst_ts));
3407     } else {
3408       /* subsequent fragments extend stream */
3409       timestamp =
3410           stream->samples[stream->n_samples - 1].timestamp +
3411           stream->samples[stream->n_samples - 1].duration;
3412 
3413       /* If this is a GST_FORMAT_BYTES stream and there's a significant
3414        * difference (1 sec.) between decode_ts and timestamp, prefer the
3415        * former */
3416       if (has_tfdt && !qtdemux->upstream_format_is_time
3417           && ABSDIFF (decode_ts, timestamp) >
3418           MAX (stream->duration_last_moof / 2,
3419               GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3420         GST_INFO_OBJECT (qtdemux,
3421             "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3422             ") are significantly different (more than %" GST_TIME_FORMAT
3423             "), using decode_ts",
3424             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3425             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3426             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3427                     MAX (stream->duration_last_moof / 2,
3428                         GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3429         timestamp = decode_ts;
3430       }
3431 
3432       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3433       GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3434           " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3435     }
3436   }
3437 
3438   initial_offset = *running_offset;
3439 
3440   sample = stream->samples + stream->n_samples;
3441   for (i = 0; i < samples_count; i++) {
3442     guint32 dur, size, sflags;
3443     gint32 ct;
3444 
3445     /* first read sample data */
3446     if (flags & TR_SAMPLE_DURATION) {
3447       dur = QT_UINT32 (data + dur_offset);
3448     } else {
3449       dur = d_sample_duration;
3450     }
3451     if (flags & TR_SAMPLE_SIZE) {
3452       size = QT_UINT32 (data + size_offset);
3453     } else {
3454       size = d_sample_size;
3455     }
3456     if (flags & TR_FIRST_SAMPLE_FLAGS) {
3457       if (i == 0) {
3458         sflags = first_flags;
3459       } else {
3460         sflags = d_sample_flags;
3461       }
3462     } else if (flags & TR_SAMPLE_FLAGS) {
3463       sflags = QT_UINT32 (data + flags_offset);
3464     } else {
3465       sflags = d_sample_flags;
3466     }
3467 
3468     if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3469       /* Read offsets as signed numbers regardless of trun version as very
3470        * high offsets are unlikely and there are files out there that use
3471        * version=0 truns with negative offsets */
3472       ct = QT_UINT32 (data + ct_offset);
3473 
3474       /* FIXME: Set offset to 0 for "no decode samples". This needs
3475        * to be handled in a codec specific manner ideally. */
3476       if (ct == G_MININT32)
3477         ct = 0;
3478     } else {
3479       ct = 0;
3480     }
3481     data += entry_size;
3482 
3483     /* fill the sample information */
3484     sample->offset = *running_offset;
3485     sample->pts_offset = ct;
3486     sample->size = size;
3487     sample->timestamp = timestamp;
3488     sample->duration = dur;
3489     /* sample-is-difference-sample */
3490     /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3491      * now idea how it relates to bitfield other than massive LE/BE confusion */
3492     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3493     *running_offset += size;
3494     timestamp += dur;
3495     stream->duration_moof += dur;
3496     sample++;
3497 
3498     if (ct < min_ct)
3499       min_ct = ct;
3500   }
3501 
3502   /* Shift PTS/DTS to allow for negative composition offsets while keeping
3503    * A/V sync in place. This is similar to the code handling ctts/cslg in the
3504    * non-fragmented case.
3505    */
3506   if (min_ct < 0)
3507     stream->cslg_shift = -min_ct;
3508   else
3509     stream->cslg_shift = 0;
3510 
3511   GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3512       stream->cslg_shift);
3513 
3514   /* Update total duration if needed */
3515   check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3516 
3517   /* Pre-emptively figure out size of mdat based on trun information.
3518    * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3519    * size, else we will still be able to use this when dealing with gap'ed
3520    * input */
3521   qtdemux->mdatleft = *running_offset - initial_offset;
3522   qtdemux->mdatoffset = initial_offset;
3523   qtdemux->mdatsize = qtdemux->mdatleft;
3524 
3525   stream->n_samples += samples_count;
3526   stream->n_samples_moof += samples_count;
3527 
3528   if (stream->pending_seek != NULL)
3529     stream->pending_seek = NULL;
3530 
3531   return TRUE;
3532 
3533 fail:
3534   {
3535     GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3536     return FALSE;
3537   }
3538 out_of_memory:
3539   {
3540     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3541         stream->n_samples);
3542     return FALSE;
3543   }
3544 index_too_big:
3545   {
3546     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3547         "be larger than %uMB (broken file?)", stream->n_samples,
3548         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3549     return FALSE;
3550   }
3551 }
3552 
3553 /* find stream with @id */
3554 static inline QtDemuxStream *
qtdemux_find_stream(GstQTDemux * qtdemux,guint32 id)3555 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3556 {
3557   QtDemuxStream *stream;
3558   gint i;
3559 
3560   /* check */
3561   if (G_UNLIKELY (!id)) {
3562     GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3563     return NULL;
3564   }
3565 
3566   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3567     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3568     if (stream->track_id == id)
3569       return stream;
3570   }
3571   if (qtdemux->mss_mode) {
3572     /* mss should have only 1 stream anyway */
3573     return QTDEMUX_NTH_STREAM (qtdemux, 0);
3574   }
3575 
3576   return NULL;
3577 }
3578 
3579 static gboolean
qtdemux_parse_mfhd(GstQTDemux * qtdemux,GstByteReader * mfhd,guint32 * fragment_number)3580 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3581     guint32 * fragment_number)
3582 {
3583   if (!gst_byte_reader_skip (mfhd, 4))
3584     goto fail;
3585   if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3586     goto fail;
3587   return TRUE;
3588 fail:
3589   {
3590     GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3591     return FALSE;
3592   }
3593 }
3594 
3595 static gboolean
qtdemux_parse_tfhd(GstQTDemux * qtdemux,GstByteReader * tfhd,QtDemuxStream ** stream,guint32 * default_sample_duration,guint32 * default_sample_size,guint32 * default_sample_flags,gint64 * base_offset)3596 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3597     QtDemuxStream ** stream, guint32 * default_sample_duration,
3598     guint32 * default_sample_size, guint32 * default_sample_flags,
3599     gint64 * base_offset)
3600 {
3601   guint32 flags = 0;
3602   guint32 track_id = 0;
3603 
3604   if (!gst_byte_reader_skip (tfhd, 1) ||
3605       !gst_byte_reader_get_uint24_be (tfhd, &flags))
3606     goto invalid_track;
3607 
3608   if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3609     goto invalid_track;
3610 
3611   *stream = qtdemux_find_stream (qtdemux, track_id);
3612   if (G_UNLIKELY (!*stream))
3613     goto unknown_stream;
3614 
3615   if (flags & TF_DEFAULT_BASE_IS_MOOF)
3616     *base_offset = qtdemux->moof_offset;
3617 
3618   if (flags & TF_BASE_DATA_OFFSET)
3619     if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3620       goto invalid_track;
3621 
3622   /* obtain stream defaults */
3623   qtdemux_parse_trex (qtdemux, *stream,
3624       default_sample_duration, default_sample_size, default_sample_flags);
3625 
3626   (*stream)->stsd_sample_description_id =
3627       (*stream)->def_sample_description_index - 1;
3628 
3629   if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3630     guint32 sample_description_index;
3631     if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3632       goto invalid_track;
3633     (*stream)->stsd_sample_description_id = sample_description_index - 1;
3634   }
3635 
3636   if (qtdemux->mss_mode) {
3637     /* mss has no stsd entry */
3638     (*stream)->stsd_sample_description_id = 0;
3639   }
3640 
3641   if (flags & TF_DEFAULT_SAMPLE_DURATION)
3642     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3643       goto invalid_track;
3644 
3645   if (flags & TF_DEFAULT_SAMPLE_SIZE)
3646     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3647       goto invalid_track;
3648 
3649   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3650     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3651       goto invalid_track;
3652 
3653   return TRUE;
3654 
3655 invalid_track:
3656   {
3657     GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3658     return FALSE;
3659   }
3660 unknown_stream:
3661   {
3662     GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3663     return TRUE;
3664   }
3665 }
3666 
3667 static gboolean
qtdemux_parse_tfdt(GstQTDemux * qtdemux,GstByteReader * br,guint64 * decode_time)3668 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3669     guint64 * decode_time)
3670 {
3671   guint32 version = 0;
3672 
3673   if (!gst_byte_reader_get_uint32_be (br, &version))
3674     return FALSE;
3675 
3676   version >>= 24;
3677   if (version == 1) {
3678     if (!gst_byte_reader_get_uint64_be (br, decode_time))
3679       goto failed;
3680   } else {
3681     guint32 dec_time = 0;
3682     if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3683       goto failed;
3684     *decode_time = dec_time;
3685   }
3686 
3687   GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3688       *decode_time);
3689 
3690   return TRUE;
3691 
3692 failed:
3693   {
3694     GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3695     return FALSE;
3696   }
3697 }
3698 
3699 /* Returns a pointer to a GstStructure containing the properties of
3700  * the stream sample identified by @sample_index. The caller must unref
3701  * the returned object after use. Returns NULL if unsuccessful. */
3702 static GstStructure *
qtdemux_get_cenc_sample_properties(GstQTDemux * qtdemux,QtDemuxStream * stream,guint sample_index)3703 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3704     QtDemuxStream * stream, guint sample_index)
3705 {
3706   QtDemuxCencSampleSetInfo *info = NULL;
3707 
3708   g_return_val_if_fail (stream != NULL, NULL);
3709   g_return_val_if_fail (stream->protected, NULL);
3710   g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3711 
3712   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3713 
3714   /* Currently, cenc properties for groups of samples are not supported, so
3715    * simply return a copy of the default sample properties */
3716   return gst_structure_copy (info->default_properties);
3717 }
3718 
3719 /* Parses the sizes of sample auxiliary information contained within a stream,
3720  * as given in a saiz box. Returns array of sample_count guint8 size values,
3721  * or NULL on failure */
3722 static guint8 *
qtdemux_parse_saiz(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint32 * sample_count)3723 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3724     GstByteReader * br, guint32 * sample_count)
3725 {
3726   guint32 flags = 0;
3727   guint8 *info_sizes;
3728   guint8 default_info_size;
3729 
3730   g_return_val_if_fail (qtdemux != NULL, NULL);
3731   g_return_val_if_fail (stream != NULL, NULL);
3732   g_return_val_if_fail (br != NULL, NULL);
3733   g_return_val_if_fail (sample_count != NULL, NULL);
3734 
3735   if (!gst_byte_reader_get_uint32_be (br, &flags))
3736     return NULL;
3737 
3738   if (flags & 0x1) {
3739     /* aux_info_type and aux_info_type_parameter are ignored */
3740     if (!gst_byte_reader_skip (br, 8))
3741       return NULL;
3742   }
3743 
3744   if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3745     return NULL;
3746   GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3747 
3748   if (!gst_byte_reader_get_uint32_be (br, sample_count))
3749     return NULL;
3750   GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3751 
3752 
3753   if (default_info_size == 0) {
3754     if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3755       return NULL;
3756     }
3757   } else {
3758     info_sizes = g_new (guint8, *sample_count);
3759     memset (info_sizes, default_info_size, *sample_count);
3760   }
3761 
3762   return info_sizes;
3763 }
3764 
3765 /* Parses the offset of sample auxiliary information contained within a stream,
3766  * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3767 static gboolean
qtdemux_parse_saio(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint32 * info_type,guint32 * info_type_parameter,guint64 * offset)3768 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3769     GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3770     guint64 * offset)
3771 {
3772   guint8 version = 0;
3773   guint32 flags = 0;
3774   guint32 aux_info_type = 0;
3775   guint32 aux_info_type_parameter = 0;
3776   guint32 entry_count;
3777   guint32 off_32;
3778   guint64 off_64;
3779   const guint8 *aux_info_type_data = NULL;
3780 
3781   g_return_val_if_fail (qtdemux != NULL, FALSE);
3782   g_return_val_if_fail (stream != NULL, FALSE);
3783   g_return_val_if_fail (br != NULL, FALSE);
3784   g_return_val_if_fail (offset != NULL, FALSE);
3785 
3786   if (!gst_byte_reader_get_uint8 (br, &version))
3787     return FALSE;
3788 
3789   if (!gst_byte_reader_get_uint24_be (br, &flags))
3790     return FALSE;
3791 
3792   if (flags & 0x1) {
3793 
3794     if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3795       return FALSE;
3796     aux_info_type = QT_FOURCC (aux_info_type_data);
3797 
3798     if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3799       return FALSE;
3800   } else if (stream->protected) {
3801     aux_info_type = stream->protection_scheme_type;
3802   } else {
3803     aux_info_type = CUR_STREAM (stream)->fourcc;
3804   }
3805 
3806   if (info_type)
3807     *info_type = aux_info_type;
3808   if (info_type_parameter)
3809     *info_type_parameter = aux_info_type_parameter;
3810 
3811   GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3812       "aux_info_type_parameter:  %#06x",
3813       GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3814 
3815   if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3816     return FALSE;
3817 
3818   if (entry_count != 1) {
3819     GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3820     return FALSE;
3821   }
3822 
3823   if (version == 0) {
3824     if (!gst_byte_reader_get_uint32_be (br, &off_32))
3825       return FALSE;
3826     *offset = (guint64) off_32;
3827   } else {
3828     if (!gst_byte_reader_get_uint64_be (br, &off_64))
3829       return FALSE;
3830     *offset = off_64;
3831   }
3832 
3833   GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3834   return TRUE;
3835 }
3836 
3837 static void
qtdemux_gst_structure_free(GstStructure * gststructure)3838 qtdemux_gst_structure_free (GstStructure * gststructure)
3839 {
3840   if (gststructure) {
3841     gst_structure_free (gststructure);
3842   }
3843 }
3844 
3845 /* Parses auxiliary information relating to samples protected using
3846  * Common Encryption (cenc); the format of this information
3847  * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3848  * otherwise. */
3849 static gboolean
qtdemux_parse_cenc_aux_info(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint8 * info_sizes,guint32 sample_count)3850 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3851     GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3852 {
3853   QtDemuxCencSampleSetInfo *ss_info = NULL;
3854   guint8 size;
3855   gint i;
3856   GPtrArray *old_crypto_info = NULL;
3857   guint old_entries = 0;
3858 
3859   g_return_val_if_fail (qtdemux != NULL, FALSE);
3860   g_return_val_if_fail (stream != NULL, FALSE);
3861   g_return_val_if_fail (br != NULL, FALSE);
3862   g_return_val_if_fail (stream->protected, FALSE);
3863   g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3864 
3865   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3866 
3867   if (ss_info->crypto_info) {
3868     old_crypto_info = ss_info->crypto_info;
3869     /* Count number of non-null entries remaining at the tail end */
3870     for (i = old_crypto_info->len - 1; i >= 0; i--) {
3871       if (g_ptr_array_index (old_crypto_info, i) == NULL)
3872         break;
3873       old_entries++;
3874     }
3875   }
3876 
3877   ss_info->crypto_info =
3878       g_ptr_array_new_full (sample_count + old_entries,
3879       (GDestroyNotify) qtdemux_gst_structure_free);
3880 
3881   /* We preserve old entries because we parse the next moof in advance
3882    * of consuming all samples from the previous moof, and otherwise
3883    * we'd discard the corresponding crypto info for the samples
3884    * from the previous fragment. */
3885   if (old_entries) {
3886     GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3887         old_entries);
3888     for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3889       g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3890               i));
3891       g_ptr_array_index (old_crypto_info, i) = NULL;
3892     }
3893   }
3894 
3895   if (old_crypto_info) {
3896     /* Everything now belongs to the new array */
3897     g_ptr_array_free (old_crypto_info, TRUE);
3898   }
3899 
3900   for (i = 0; i < sample_count; ++i) {
3901     GstStructure *properties;
3902     guint16 n_subsamples = 0;
3903     guint8 *data;
3904     guint iv_size;
3905     GstBuffer *buf;
3906     gboolean could_read_iv;
3907 
3908     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3909     if (properties == NULL) {
3910       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3911       return FALSE;
3912     }
3913     if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3914       GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3915       gst_structure_free (properties);
3916       return FALSE;
3917     }
3918     could_read_iv =
3919         iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3920     if (could_read_iv) {
3921       buf = gst_buffer_new_wrapped (data, iv_size);
3922       gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3923       gst_buffer_unref (buf);
3924     } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3925       const GValue *constant_iv_size_value =
3926           gst_structure_get_value (properties, "constant_iv_size");
3927       const GValue *constant_iv_value =
3928           gst_structure_get_value (properties, "iv");
3929       if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3930         GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3931         gst_structure_free (properties);
3932         return FALSE;
3933       }
3934       gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3935       gst_structure_remove_field (properties, "constant_iv_size");
3936     } else if (stream->protection_scheme_type == FOURCC_cenc) {
3937       GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3938       gst_structure_free (properties);
3939       return FALSE;
3940     }
3941     size = info_sizes[i];
3942     if (size > iv_size) {
3943       if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3944           || !(n_subsamples > 0)) {
3945         gst_structure_free (properties);
3946         GST_ERROR_OBJECT (qtdemux,
3947             "failed to get subsample count for sample %u", i);
3948         return FALSE;
3949       }
3950       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3951       if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3952         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3953             i);
3954         gst_structure_free (properties);
3955         return FALSE;
3956       }
3957       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3958       if (!buf) {
3959         gst_structure_free (properties);
3960         return FALSE;
3961       }
3962       gst_structure_set (properties,
3963           "subsample_count", G_TYPE_UINT, n_subsamples,
3964           "subsamples", GST_TYPE_BUFFER, buf, NULL);
3965       gst_buffer_unref (buf);
3966     } else {
3967       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3968     }
3969     g_ptr_array_add (ss_info->crypto_info, properties);
3970   }
3971   return TRUE;
3972 }
3973 
3974 /* Converts a UUID in raw byte form to a string representation, as defined in
3975  * RFC 4122. The caller takes ownership of the returned string and is
3976  * responsible for freeing it after use. */
3977 static gchar *
qtdemux_uuid_bytes_to_string(gconstpointer uuid_bytes)3978 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3979 {
3980   const guint8 *uuid = (const guint8 *) uuid_bytes;
3981 
3982   return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3983       "%02x%02x-%02x%02x%02x%02x%02x%02x",
3984       uuid[0], uuid[1], uuid[2], uuid[3],
3985       uuid[4], uuid[5], uuid[6], uuid[7],
3986       uuid[8], uuid[9], uuid[10], uuid[11],
3987       uuid[12], uuid[13], uuid[14], uuid[15]);
3988 }
3989 
3990 /* Parses a Protection System Specific Header box (pssh), as defined in the
3991  * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3992  * information needed by a specific content protection system in order to
3993  * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3994  * otherwise. */
3995 static gboolean
qtdemux_parse_pssh(GstQTDemux * qtdemux,GNode * node)3996 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3997 {
3998   gchar *sysid_string;
3999   guint32 pssh_size = QT_UINT32 (node->data);
4000   GstBuffer *pssh = NULL;
4001   GstEvent *event = NULL;
4002   guint32 parent_box_type;
4003   gint i;
4004 
4005   if (G_UNLIKELY (pssh_size < 32U)) {
4006     GST_ERROR_OBJECT (qtdemux, "invalid box size");
4007     return FALSE;
4008   }
4009 
4010   sysid_string =
4011       qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4012 
4013   gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4014 
4015   pssh = gst_buffer_new_memdup (node->data, pssh_size);
4016   GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4017       gst_buffer_get_size (pssh));
4018 
4019   parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4020 
4021   /* Push an event containing the pssh box onto the queues of all streams. */
4022   event = gst_event_new_protection (sysid_string, pssh,
4023       (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4024   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4025     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4026     GST_TRACE_OBJECT (qtdemux,
4027         "adding protection event for stream %s and system %s",
4028         stream->stream_id, sysid_string);
4029     g_queue_push_tail (&stream->protection_scheme_event_queue,
4030         gst_event_ref (event));
4031   }
4032   g_free (sysid_string);
4033   gst_event_unref (event);
4034   gst_buffer_unref (pssh);
4035   return TRUE;
4036 }
4037 
4038 static gboolean
qtdemux_parse_moof(GstQTDemux * qtdemux,const guint8 * buffer,guint length,guint64 moof_offset,QtDemuxStream * stream)4039 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4040     guint64 moof_offset, QtDemuxStream * stream)
4041 {
4042   GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4043   GNode *uuid_node;
4044   GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4045   GNode *saiz_node, *saio_node, *pssh_node;
4046   GstByteReader saiz_data, saio_data;
4047   guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4048   gint64 base_offset, running_offset;
4049   guint32 frag_num;
4050   GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4051 
4052   /* NOTE @stream ignored */
4053 
4054   moof_node = g_node_new ((guint8 *) buffer);
4055   qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4056   qtdemux_node_dump (qtdemux, moof_node);
4057 
4058   /* Get fragment number from mfhd and check it's valid */
4059   mfhd_node =
4060       qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4061   if (mfhd_node == NULL)
4062     goto missing_mfhd;
4063   if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4064     goto fail;
4065   GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4066 
4067   /* unknown base_offset to start with */
4068   base_offset = running_offset = -1;
4069   traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4070   while (traf_node) {
4071     guint64 decode_time = 0;
4072 
4073     /* Fragment Header node */
4074     tfhd_node =
4075         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4076         &tfhd_data);
4077     if (!tfhd_node)
4078       goto missing_tfhd;
4079     if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4080             &ds_size, &ds_flags, &base_offset))
4081       goto missing_tfhd;
4082 
4083     /* The following code assumes at most a single set of sample auxiliary
4084      * data in the fragment (consisting of a saiz box and a corresponding saio
4085      * box); in theory, however, there could be multiple sets of sample
4086      * auxiliary data in a fragment. */
4087     saiz_node =
4088         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4089         &saiz_data);
4090     if (saiz_node) {
4091       guint32 info_type = 0;
4092       guint64 offset = 0;
4093       guint32 info_type_parameter = 0;
4094 
4095       g_free (qtdemux->cenc_aux_info_sizes);
4096 
4097       qtdemux->cenc_aux_info_sizes =
4098           qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4099           &qtdemux->cenc_aux_sample_count);
4100       if (qtdemux->cenc_aux_info_sizes == NULL) {
4101         GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4102         goto fail;
4103       }
4104       saio_node =
4105           qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4106           &saio_data);
4107       if (!saio_node) {
4108         GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4109         g_free (qtdemux->cenc_aux_info_sizes);
4110         qtdemux->cenc_aux_info_sizes = NULL;
4111         goto fail;
4112       }
4113 
4114       if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4115                   &info_type, &info_type_parameter, &offset))) {
4116         GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4117         g_free (qtdemux->cenc_aux_info_sizes);
4118         qtdemux->cenc_aux_info_sizes = NULL;
4119         goto fail;
4120       }
4121       if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4122         offset += (guint64) (base_offset - qtdemux->moof_offset);
4123       if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4124           && info_type_parameter == 0U) {
4125         GstByteReader br;
4126         if (offset > length) {
4127           GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4128           qtdemux->cenc_aux_info_offset = offset;
4129         } else {
4130           gst_byte_reader_init (&br, buffer + offset, length - offset);
4131           if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4132                   qtdemux->cenc_aux_info_sizes,
4133                   qtdemux->cenc_aux_sample_count)) {
4134             GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4135             g_free (qtdemux->cenc_aux_info_sizes);
4136             qtdemux->cenc_aux_info_sizes = NULL;
4137             goto fail;
4138           }
4139         }
4140       }
4141     }
4142 
4143     tfdt_node =
4144         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4145         &tfdt_data);
4146     if (tfdt_node) {
4147       /* We'll use decode_time to interpolate timestamps
4148        * in case the input timestamps are missing */
4149       qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4150 
4151       GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4152           " (%" GST_TIME_FORMAT ")", decode_time,
4153           GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4154                   decode_time) : GST_CLOCK_TIME_NONE));
4155 
4156       /* Discard the fragment buffer timestamp info to avoid using it.
4157        * Rely on tfdt instead as it is more accurate than the timestamp
4158        * that is fetched from a manifest/playlist and is usually
4159        * less accurate. */
4160       qtdemux->fragment_start = -1;
4161     }
4162 
4163     if (G_UNLIKELY (!stream)) {
4164       /* we lost track of offset, we'll need to regain it,
4165        * but can delay complaining until later or avoid doing so altogether */
4166       base_offset = -2;
4167       goto next;
4168     }
4169     if (G_UNLIKELY (base_offset < -1))
4170       goto lost_offset;
4171 
4172     min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4173 
4174     if (!qtdemux->pullbased) {
4175       /* Sample tables can grow enough to be problematic if the system memory
4176        * is very low (e.g. embedded devices) and the videos very long
4177        * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4178        * Fortunately, we can easily discard them for each new fragment when
4179        * we know qtdemux will not receive seeks outside of the current fragment.
4180        * adaptivedemux honors this assumption.
4181        * This optimization is also useful for applications that use qtdemux as
4182        * a push-based simple demuxer, like Media Source Extensions. */
4183       gst_qtdemux_stream_flush_samples_data (stream);
4184     }
4185 
4186     /* initialise moof sample data */
4187     stream->n_samples_moof = 0;
4188     stream->duration_last_moof = stream->duration_moof;
4189     stream->duration_moof = 0;
4190 
4191     /* Track Run node */
4192     trun_node =
4193         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4194         &trun_data);
4195     while (trun_node) {
4196       qtdemux_parse_trun (qtdemux, &trun_data, stream,
4197           ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4198           &running_offset, decode_time, (tfdt_node != NULL));
4199       /* iterate all siblings */
4200       trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4201           &trun_data);
4202       /* don't use tfdt for subsequent trun as it only refers to the first */
4203       tfdt_node = NULL;
4204     }
4205 
4206     uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4207     if (uuid_node) {
4208       guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4209       guint32 box_length = QT_UINT32 (uuid_buffer);
4210 
4211       qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4212     }
4213 
4214     /* if no new base_offset provided for next traf,
4215      * base is end of current traf */
4216     base_offset = running_offset;
4217     running_offset = -1;
4218 
4219     if (stream->n_samples_moof && stream->duration_moof)
4220       stream->new_caps = TRUE;
4221 
4222   next:
4223     /* iterate all siblings */
4224     traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4225   }
4226 
4227   /* parse any protection system info */
4228   pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4229   while (pssh_node) {
4230     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4231     qtdemux_parse_pssh (qtdemux, pssh_node);
4232     pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4233   }
4234 
4235   if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4236       && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4237       && min_dts != 0) {
4238     /* Unless the user has explicitly requested another seek, perform an
4239      * internal seek to the time specified in the tfdt.
4240      *
4241      * This way if the user opens a file where the first tfdt is 1 hour
4242      * into the presentation, they will not have to wait 1 hour for run
4243      * time to catch up and actual playback to start. */
4244     gint i;
4245 
4246     GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4247         "performing an internal seek to %" GST_TIME_FORMAT,
4248         GST_TIME_ARGS (min_dts));
4249 
4250     qtdemux->segment.start = min_dts;
4251     qtdemux->segment.time = qtdemux->segment.position = min_dts;
4252 
4253     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4254       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4255       stream->time_position = min_dts;
4256     }
4257 
4258     /* Before this code was run a segment was already sent when the moov was
4259      * parsed... which is OK -- some apps (mostly tests) expect a segment to
4260      * be emitted after a moov, and we can emit a second segment anyway for
4261      * special cases like this. */
4262     qtdemux->need_segment = TRUE;
4263   }
4264 
4265   qtdemux->first_moof_already_parsed = TRUE;
4266 
4267   g_node_destroy (moof_node);
4268   return TRUE;
4269 
4270 missing_tfhd:
4271   {
4272     GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4273     goto fail;
4274   }
4275 missing_mfhd:
4276   {
4277     GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4278     goto fail;
4279   }
4280 lost_offset:
4281   {
4282     GST_DEBUG_OBJECT (qtdemux, "lost offset");
4283     goto fail;
4284   }
4285 fail:
4286   {
4287     g_node_destroy (moof_node);
4288     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4289         (_("This file is corrupt and cannot be played.")), (NULL));
4290     return FALSE;
4291   }
4292 }
4293 
4294 #if 0
4295 /* might be used if some day we actually use mfra & co
4296  * for random access to fragments,
4297  * but that will require quite some modifications and much less relying
4298  * on a sample array */
4299 #endif
4300 
4301 static gboolean
qtdemux_parse_tfra(GstQTDemux * qtdemux,GNode * tfra_node)4302 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4303 {
4304   QtDemuxStream *stream;
4305   guint32 ver_flags, track_id, len, num_entries, i;
4306   guint value_size, traf_size, trun_size, sample_size;
4307   guint64 time = 0, moof_offset = 0;
4308 #if 0
4309   GstBuffer *buf = NULL;
4310   GstFlowReturn ret;
4311 #endif
4312   GstByteReader tfra;
4313 
4314   gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4315 
4316   if (!gst_byte_reader_skip (&tfra, 8))
4317     return FALSE;
4318 
4319   if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4320     return FALSE;
4321 
4322   if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4323       || !gst_byte_reader_get_uint32_be (&tfra, &len)
4324       || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4325     return FALSE;
4326 
4327   GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4328 
4329   stream = qtdemux_find_stream (qtdemux, track_id);
4330   if (stream == NULL)
4331     goto unknown_trackid;
4332 
4333   value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4334   sample_size = (len & 3) + 1;
4335   trun_size = ((len & 12) >> 2) + 1;
4336   traf_size = ((len & 48) >> 4) + 1;
4337 
4338   GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4339       "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4340 
4341   if (num_entries == 0)
4342     goto no_samples;
4343 
4344   if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4345           value_size + value_size + traf_size + trun_size + sample_size))
4346     goto corrupt_file;
4347 
4348   g_free (stream->ra_entries);
4349   stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4350   stream->n_ra_entries = num_entries;
4351 
4352   for (i = 0; i < num_entries; i++) {
4353     qt_atom_parser_get_offset (&tfra, value_size, &time);
4354     qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4355     qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4356     qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4357     qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4358 
4359     time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4360 
4361     GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4362         " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4363 
4364     stream->ra_entries[i].ts = time;
4365     stream->ra_entries[i].moof_offset = moof_offset;
4366 
4367     /* don't want to go through the entire file and read all moofs at startup */
4368 #if 0
4369     ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4370     if (ret != GST_FLOW_OK)
4371       goto corrupt_file;
4372     qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4373         moof_offset, stream);
4374     gst_buffer_unref (buf);
4375 #endif
4376   }
4377 
4378   check_update_duration (qtdemux, time);
4379 
4380   return TRUE;
4381 
4382 /* ERRORS */
4383 unknown_trackid:
4384   {
4385     GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4386     return FALSE;
4387   }
4388 corrupt_file:
4389   {
4390     GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4391     return FALSE;
4392   }
4393 no_samples:
4394   {
4395     GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4396     return FALSE;
4397   }
4398 }
4399 
4400 static gboolean
qtdemux_pull_mfro_mfra(GstQTDemux * qtdemux)4401 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4402 {
4403   GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4404   GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4405   GstBuffer *mfro = NULL, *mfra = NULL;
4406   GstFlowReturn flow;
4407   gboolean ret = FALSE;
4408   GNode *mfra_node, *tfra_node;
4409   guint64 mfra_offset = 0;
4410   guint32 fourcc, mfra_size;
4411   gint64 len;
4412 
4413   /* query upstream size in bytes */
4414   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4415     goto size_query_failed;
4416 
4417   /* mfro box should be at the very end of the file */
4418   flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4419   if (flow != GST_FLOW_OK)
4420     goto exit;
4421 
4422   gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4423 
4424   fourcc = QT_FOURCC (mfro_map.data + 4);
4425   if (fourcc != FOURCC_mfro)
4426     goto exit;
4427 
4428   GST_INFO_OBJECT (qtdemux, "Found mfro box");
4429   if (mfro_map.size < 16)
4430     goto invalid_mfro_size;
4431 
4432   mfra_size = QT_UINT32 (mfro_map.data + 12);
4433   if (mfra_size >= len)
4434     goto invalid_mfra_size;
4435 
4436   mfra_offset = len - mfra_size;
4437 
4438   GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4439       mfra_offset, mfra_size);
4440 
4441   /* now get and parse mfra box */
4442   flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4443   if (flow != GST_FLOW_OK)
4444     goto broken_file;
4445 
4446   gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4447 
4448   mfra_node = g_node_new ((guint8 *) mfra_map.data);
4449   qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4450 
4451   tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4452 
4453   while (tfra_node) {
4454     qtdemux_parse_tfra (qtdemux, tfra_node);
4455     /* iterate all siblings */
4456     tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4457   }
4458   g_node_destroy (mfra_node);
4459 
4460   GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4461   ret = TRUE;
4462 
4463 exit:
4464 
4465   if (mfro) {
4466     if (mfro_map.memory != NULL)
4467       gst_buffer_unmap (mfro, &mfro_map);
4468     gst_buffer_unref (mfro);
4469   }
4470   if (mfra) {
4471     if (mfra_map.memory != NULL)
4472       gst_buffer_unmap (mfra, &mfra_map);
4473     gst_buffer_unref (mfra);
4474   }
4475   return ret;
4476 
4477 /* ERRORS */
4478 size_query_failed:
4479   {
4480     GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4481     goto exit;
4482   }
4483 invalid_mfro_size:
4484   {
4485     GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4486     goto exit;
4487   }
4488 invalid_mfra_size:
4489   {
4490     GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4491     goto exit;
4492   }
4493 broken_file:
4494   {
4495     GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4496     goto exit;
4497   }
4498 }
4499 
4500 static guint64
add_offset(guint64 offset,guint64 advance)4501 add_offset (guint64 offset, guint64 advance)
4502 {
4503   /* Avoid 64-bit overflow by clamping */
4504   if (offset > G_MAXUINT64 - advance)
4505     return G_MAXUINT64;
4506   return offset + advance;
4507 }
4508 
4509 static GstFlowReturn
gst_qtdemux_loop_state_header(GstQTDemux * qtdemux)4510 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4511 {
4512   guint64 length = 0;
4513   guint32 fourcc = 0;
4514   GstBuffer *buf = NULL;
4515   GstFlowReturn ret = GST_FLOW_OK;
4516   guint64 cur_offset = qtdemux->offset;
4517   GstMapInfo map;
4518 
4519   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4520   if (G_UNLIKELY (ret != GST_FLOW_OK))
4521     goto beach;
4522   gst_buffer_map (buf, &map, GST_MAP_READ);
4523   if (G_LIKELY (map.size >= 8))
4524     extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4525   gst_buffer_unmap (buf, &map);
4526   gst_buffer_unref (buf);
4527 
4528   /* maybe we already got most we needed, so only consider this eof */
4529   if (G_UNLIKELY (length == 0)) {
4530     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4531         (_("Invalid atom size.")),
4532         ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4533             GST_FOURCC_ARGS (fourcc)));
4534     ret = GST_FLOW_EOS;
4535     goto beach;
4536   }
4537 
4538   switch (fourcc) {
4539     case FOURCC_moof:
4540       /* record for later parsing when needed */
4541       if (!qtdemux->moof_offset) {
4542         qtdemux->moof_offset = qtdemux->offset;
4543       }
4544       if (qtdemux_pull_mfro_mfra (qtdemux)) {
4545         /* FIXME */
4546       } else {
4547         qtdemux->offset += length;      /* skip moof and keep going */
4548       }
4549       if (qtdemux->got_moov) {
4550         GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4551         ret = GST_FLOW_EOS;
4552         goto beach;
4553       }
4554       break;
4555     case FOURCC_mdat:
4556     case FOURCC_free:
4557     case FOURCC_skip:
4558     case FOURCC_wide:
4559     case FOURCC_PICT:
4560     case FOURCC_pnot:
4561     {
4562       GST_LOG_OBJECT (qtdemux,
4563           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4564           GST_FOURCC_ARGS (fourcc), cur_offset);
4565       qtdemux->offset = add_offset (qtdemux->offset, length);
4566       break;
4567     }
4568     case FOURCC_moov:
4569     {
4570       GstBuffer *moov = NULL;
4571 
4572       if (qtdemux->got_moov) {
4573         GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4574         qtdemux->offset = add_offset (qtdemux->offset, length);
4575         goto beach;
4576       }
4577 
4578       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4579       if (ret != GST_FLOW_OK)
4580         goto beach;
4581       gst_buffer_map (moov, &map, GST_MAP_READ);
4582 
4583       if (length != map.size) {
4584         /* Some files have a 'moov' atom at the end of the file which contains
4585          * a terminal 'free' atom where the body of the atom is missing.
4586          * Check for, and permit, this special case.
4587          */
4588         if (map.size >= 8) {
4589           guint8 *final_data = map.data + (map.size - 8);
4590           guint32 final_length = QT_UINT32 (final_data);
4591           guint32 final_fourcc = QT_FOURCC (final_data + 4);
4592 
4593           if (final_fourcc == FOURCC_free
4594               && map.size + final_length - 8 == length) {
4595             /* Ok, we've found that special case. Allocate a new buffer with
4596              * that free atom actually present. */
4597             GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4598             gst_buffer_fill (newmoov, 0, map.data, map.size);
4599             gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4600             gst_buffer_unmap (moov, &map);
4601             gst_buffer_unref (moov);
4602             moov = newmoov;
4603             gst_buffer_map (moov, &map, GST_MAP_READ);
4604           }
4605         }
4606       }
4607 
4608       if (length != map.size) {
4609         GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4610             (_("This file is incomplete and cannot be played.")),
4611             ("We got less than expected (received %" G_GSIZE_FORMAT
4612                 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4613                 (guint) length, cur_offset));
4614         gst_buffer_unmap (moov, &map);
4615         gst_buffer_unref (moov);
4616         ret = GST_FLOW_ERROR;
4617         goto beach;
4618       }
4619       qtdemux->offset += length;
4620 
4621       qtdemux_parse_moov (qtdemux, map.data, length);
4622       qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4623 
4624       qtdemux_parse_tree (qtdemux);
4625       if (qtdemux->moov_node_compressed) {
4626         g_node_destroy (qtdemux->moov_node_compressed);
4627         g_free (qtdemux->moov_node->data);
4628       }
4629       qtdemux->moov_node_compressed = NULL;
4630       g_node_destroy (qtdemux->moov_node);
4631       qtdemux->moov_node = NULL;
4632       gst_buffer_unmap (moov, &map);
4633       gst_buffer_unref (moov);
4634       qtdemux->got_moov = TRUE;
4635 
4636       break;
4637     }
4638     case FOURCC_ftyp:
4639     {
4640       GstBuffer *ftyp = NULL;
4641 
4642       /* extract major brand; might come in handy for ISO vs QT issues */
4643       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4644       if (ret != GST_FLOW_OK)
4645         goto beach;
4646       qtdemux->offset += length;
4647       gst_buffer_map (ftyp, &map, GST_MAP_READ);
4648       qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4649       gst_buffer_unmap (ftyp, &map);
4650       gst_buffer_unref (ftyp);
4651       break;
4652     }
4653     case FOURCC_uuid:
4654     {
4655       GstBuffer *uuid = NULL;
4656 
4657       /* uuid are extension atoms */
4658       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4659       if (ret != GST_FLOW_OK)
4660         goto beach;
4661       qtdemux->offset += length;
4662       gst_buffer_map (uuid, &map, GST_MAP_READ);
4663       qtdemux_parse_uuid (qtdemux, map.data, map.size);
4664       gst_buffer_unmap (uuid, &map);
4665       gst_buffer_unref (uuid);
4666       break;
4667     }
4668     case FOURCC_sidx:
4669     {
4670       GstBuffer *sidx = NULL;
4671       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4672       if (ret != GST_FLOW_OK)
4673         goto beach;
4674       qtdemux->offset += length;
4675       gst_buffer_map (sidx, &map, GST_MAP_READ);
4676       qtdemux_parse_sidx (qtdemux, map.data, map.size);
4677       gst_buffer_unmap (sidx, &map);
4678       gst_buffer_unref (sidx);
4679       break;
4680     }
4681     default:
4682     {
4683       GstBuffer *unknown = NULL;
4684 
4685       GST_LOG_OBJECT (qtdemux,
4686           "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4687           " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4688           cur_offset);
4689       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4690       if (ret != GST_FLOW_OK)
4691         goto beach;
4692       gst_buffer_map (unknown, &map, GST_MAP_READ);
4693       GST_MEMDUMP ("Unknown tag", map.data, map.size);
4694       gst_buffer_unmap (unknown, &map);
4695       gst_buffer_unref (unknown);
4696       qtdemux->offset += length;
4697       break;
4698     }
4699   }
4700 
4701 beach:
4702   if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4703     /* digested all data, show what we have */
4704     qtdemux_prepare_streams (qtdemux);
4705     QTDEMUX_EXPOSE_LOCK (qtdemux);
4706     ret = qtdemux_expose_streams (qtdemux);
4707     QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4708 
4709     qtdemux->state = QTDEMUX_STATE_MOVIE;
4710     GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4711         qtdemux->state);
4712     return ret;
4713   }
4714   return ret;
4715 }
4716 
4717 /* Seeks to the previous keyframe of the indexed stream and
4718  * aligns other streams with respect to the keyframe timestamp
4719  * of indexed stream. Only called in case of Reverse Playback
4720  */
4721 static GstFlowReturn
gst_qtdemux_seek_to_previous_keyframe(GstQTDemux * qtdemux)4722 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4723 {
4724   guint32 seg_idx = 0, k_index = 0;
4725   guint32 ref_seg_idx, ref_k_index;
4726   GstClockTime k_pos = 0, last_stop = 0;
4727   QtDemuxSegment *seg = NULL;
4728   QtDemuxStream *ref_str = NULL;
4729   guint64 seg_media_start_mov;  /* segment media start time in mov format */
4730   guint64 target_ts;
4731   gint i;
4732 
4733   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4734    * and finally align all the other streams on that timestamp with their
4735    * respective keyframes */
4736   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4737     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4738 
4739     /* No candidate yet, take the first stream */
4740     if (!ref_str) {
4741       ref_str = str;
4742       continue;
4743     }
4744 
4745     /* So that stream has a segment, we prefer video streams */
4746     if (str->subtype == FOURCC_vide) {
4747       ref_str = str;
4748       break;
4749     }
4750   }
4751 
4752   if (G_UNLIKELY (!ref_str)) {
4753     GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4754     goto eos;
4755   }
4756 
4757   if (G_UNLIKELY (!ref_str->from_sample)) {
4758     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4759     goto eos;
4760   }
4761 
4762   /* So that stream has been playing from from_sample to to_sample. We will
4763    * get the timestamp of the previous sample and search for a keyframe before
4764    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4765   if (ref_str->subtype == FOURCC_vide) {
4766     k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4767         ref_str->from_sample - 1, FALSE);
4768   } else {
4769     if (ref_str->from_sample >= 10)
4770       k_index = ref_str->from_sample - 10;
4771     else
4772       k_index = 0;
4773   }
4774 
4775   target_ts =
4776       ref_str->samples[k_index].timestamp +
4777       ref_str->samples[k_index].pts_offset;
4778 
4779   /* get current segment for that stream */
4780   seg = &ref_str->segments[ref_str->segment_index];
4781   /* Use segment start in original timescale for comparisons */
4782   seg_media_start_mov = seg->trak_media_start;
4783 
4784   GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4785       " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4786       k_index, target_ts, seg_media_start_mov,
4787       GST_TIME_ARGS (seg->media_start));
4788 
4789   /* Crawl back through segments to find the one containing this I frame */
4790   while (target_ts < seg_media_start_mov) {
4791     GST_DEBUG_OBJECT (qtdemux,
4792         "keyframe position (sample %u) is out of segment %u " " target %"
4793         G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4794         ref_str->segment_index, target_ts, seg_media_start_mov);
4795 
4796     if (G_UNLIKELY (!ref_str->segment_index)) {
4797       /* Reached first segment, let's consider it's EOS */
4798       goto eos;
4799     }
4800     ref_str->segment_index--;
4801     seg = &ref_str->segments[ref_str->segment_index];
4802     /* Use segment start in original timescale for comparisons */
4803     seg_media_start_mov = seg->trak_media_start;
4804   }
4805   /* Calculate time position of the keyframe and where we should stop */
4806   k_pos =
4807       QTSTREAMTIME_TO_GSTTIME (ref_str,
4808       target_ts - seg->trak_media_start) + seg->time;
4809   last_stop =
4810       QTSTREAMTIME_TO_GSTTIME (ref_str,
4811       ref_str->samples[ref_str->from_sample].timestamp -
4812       seg->trak_media_start) + seg->time;
4813 
4814   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4815       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4816       k_index, GST_TIME_ARGS (k_pos));
4817 
4818   /* Set last_stop with the keyframe timestamp we pushed of that stream */
4819   qtdemux->segment.position = last_stop;
4820   GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4821       GST_TIME_ARGS (last_stop));
4822 
4823   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4824     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4825     goto eos;
4826   }
4827 
4828   ref_seg_idx = ref_str->segment_index;
4829   ref_k_index = k_index;
4830 
4831   /* Align them all on this */
4832   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4833     guint32 index = 0;
4834     GstClockTime seg_time = 0;
4835     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4836 
4837     /* aligning reference stream again might lead to backing up to yet another
4838      * keyframe (due to timestamp rounding issues),
4839      * potentially putting more load on downstream; so let's try to avoid */
4840     if (str == ref_str) {
4841       seg_idx = ref_seg_idx;
4842       seg = &str->segments[seg_idx];
4843       k_index = ref_k_index;
4844       GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4845           "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4846     } else {
4847       seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4848       GST_DEBUG_OBJECT (qtdemux,
4849           "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4850           str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4851 
4852       /* get segment and time in the segment */
4853       seg = &str->segments[seg_idx];
4854       seg_time = k_pos - seg->time;
4855 
4856       /* get the media time in the segment.
4857        * No adjustment for empty "filler" segments */
4858       if (seg->media_start != GST_CLOCK_TIME_NONE)
4859         seg_time += seg->media_start;
4860 
4861       /* get the index of the sample with media time */
4862       index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4863       GST_DEBUG_OBJECT (qtdemux,
4864           "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4865           GST_TIME_ARGS (seg_time), index);
4866 
4867       /* find previous keyframe */
4868       k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4869     }
4870 
4871     /* Remember until where we want to go */
4872     str->to_sample = str->from_sample - 1;
4873     /* Define our time position */
4874     target_ts =
4875         str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4876     str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4877     if (seg->media_start != GST_CLOCK_TIME_NONE)
4878       str->time_position -= seg->media_start;
4879 
4880     /* Now seek back in time */
4881     gst_qtdemux_move_stream (qtdemux, str, k_index);
4882     GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4883         GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4884         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4885   }
4886 
4887   return GST_FLOW_OK;
4888 
4889 eos:
4890   return GST_FLOW_EOS;
4891 }
4892 
4893 /*
4894  * Gets the current qt segment start, stop and position for the
4895  * given time offset. This is used in update_segment()
4896  */
4897 static void
gst_qtdemux_stream_segment_get_boundaries(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime offset,GstClockTime * _start,GstClockTime * _stop,GstClockTime * _time)4898 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4899     QtDemuxStream * stream, GstClockTime offset,
4900     GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4901 {
4902   GstClockTime seg_time;
4903   GstClockTime start, stop, time;
4904   QtDemuxSegment *segment;
4905 
4906   segment = &stream->segments[stream->segment_index];
4907 
4908   /* get time in this segment */
4909   seg_time = (offset - segment->time) * segment->rate;
4910 
4911   GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4912       GST_TIME_ARGS (seg_time));
4913 
4914   if (G_UNLIKELY (seg_time > segment->duration)) {
4915     GST_LOG_OBJECT (stream->pad,
4916         "seg_time > segment->duration %" GST_TIME_FORMAT,
4917         GST_TIME_ARGS (segment->duration));
4918     seg_time = segment->duration;
4919   }
4920 
4921   /* qtdemux->segment.stop is in outside-time-realm, whereas
4922    * segment->media_stop is in track-time-realm.
4923    *
4924    * In order to compare the two, we need to bring segment.stop
4925    * into the track-time-realm
4926    *
4927    * FIXME - does this comment still hold? Don't see any conversion here */
4928 
4929   stop = qtdemux->segment.stop;
4930   if (stop == GST_CLOCK_TIME_NONE)
4931     stop = qtdemux->segment.duration;
4932   if (stop == GST_CLOCK_TIME_NONE)
4933     stop = segment->media_stop;
4934   else
4935     stop =
4936         MIN (segment->media_stop, stop - segment->time + segment->media_start);
4937 
4938   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4939     start = segment->time + seg_time;
4940     time = offset;
4941     stop = start - seg_time + segment->duration;
4942   } else if (qtdemux->segment.rate >= 0) {
4943     start = MIN (segment->media_start + seg_time, stop);
4944     time = offset;
4945   } else {
4946     if (segment->media_start >= qtdemux->segment.start) {
4947       time = segment->time;
4948     } else {
4949       time = segment->time + (qtdemux->segment.start - segment->media_start);
4950     }
4951 
4952     start = MAX (segment->media_start, qtdemux->segment.start);
4953     stop = MIN (segment->media_start + seg_time, stop);
4954   }
4955 
4956   *_start = start;
4957   *_stop = stop;
4958   *_time = time;
4959 }
4960 
4961 /*
4962  * Updates the qt segment used for the stream and pushes a new segment event
4963  * downstream on this stream's pad.
4964  */
4965 static gboolean
gst_qtdemux_stream_update_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,gint seg_idx,GstClockTime offset,GstClockTime * _start,GstClockTime * _stop)4966 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4967     gint seg_idx, GstClockTime offset, GstClockTime * _start,
4968     GstClockTime * _stop)
4969 {
4970   QtDemuxSegment *segment;
4971   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4972   gdouble rate;
4973   GstEvent *event;
4974 
4975   /* update the current segment */
4976   stream->segment_index = seg_idx;
4977 
4978   /* get the segment */
4979   segment = &stream->segments[seg_idx];
4980 
4981   if (G_UNLIKELY (offset < segment->time)) {
4982     GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4983         GST_TIME_ARGS (segment->time));
4984     return FALSE;
4985   }
4986 
4987   /* segment lies beyond total indicated duration */
4988   if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4989           segment->time > qtdemux->segment.duration)) {
4990     GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4991         " < segment->time %" GST_TIME_FORMAT,
4992         GST_TIME_ARGS (qtdemux->segment.duration),
4993         GST_TIME_ARGS (segment->time));
4994     return FALSE;
4995   }
4996 
4997   gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4998       &start, &stop, &time);
4999 
5000   GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5001       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5002       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5003 
5004   /* combine global rate with that of the segment */
5005   rate = segment->rate * qtdemux->segment.rate;
5006 
5007   /* Copy flags from main segment */
5008   stream->segment.flags = qtdemux->segment.flags;
5009 
5010   /* update the segment values used for clipping */
5011   stream->segment.offset = qtdemux->segment.offset;
5012   stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5013   stream->segment.applied_rate = qtdemux->segment.applied_rate;
5014   stream->segment.rate = rate;
5015   stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5016       stream->cslg_shift);
5017   if (stop != -1)
5018     stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5019         stream->cslg_shift);
5020   else
5021     stream->segment.stop = stop;
5022   stream->segment.time = time;
5023   stream->segment.position = stream->segment.start;
5024 
5025   GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5026       &stream->segment);
5027 
5028   /* now prepare and send the segment */
5029   if (stream->pad) {
5030     event = gst_event_new_segment (&stream->segment);
5031     if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5032       gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5033     }
5034     gst_pad_push_event (stream->pad, event);
5035     /* assume we can send more data now */
5036     GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5037     /* clear to send tags on this pad now */
5038     gst_qtdemux_push_tags (qtdemux, stream);
5039   }
5040 
5041   if (_start)
5042     *_start = start;
5043   if (_stop)
5044     *_stop = stop;
5045 
5046   return TRUE;
5047 }
5048 
5049 /* activate the given segment number @seg_idx of @stream at time @offset.
5050  * @offset is an absolute global position over all the segments.
5051  *
5052  * This will push out a NEWSEGMENT event with the right values and
5053  * position the stream index to the first decodable sample before
5054  * @offset.
5055  */
5056 static gboolean
gst_qtdemux_activate_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 seg_idx,GstClockTime offset)5057 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5058     guint32 seg_idx, GstClockTime offset)
5059 {
5060   QtDemuxSegment *segment;
5061   guint32 index, kf_index;
5062   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5063 
5064   GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5065       seg_idx, GST_TIME_ARGS (offset));
5066 
5067   if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5068           &start, &stop))
5069     return FALSE;
5070 
5071   segment = &stream->segments[stream->segment_index];
5072 
5073   /* in the fragmented case, we pick a fragment that starts before our
5074    * desired position and rely on downstream to wait for a keyframe
5075    * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5076    * tfra entries tells us which trun/sample the key unit is in, but we don't
5077    * make use of this additional information at the moment) */
5078   if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5079     stream->to_sample = G_MAXUINT32;
5080     return TRUE;
5081   } else {
5082     /* well, it will be taken care of below */
5083     qtdemux->fragmented_seek_pending = FALSE;
5084     /* FIXME ideally the do_fragmented_seek can be done right here,
5085      * rather than at loop level
5086      * (which might even allow handling edit lists in a fragmented file) */
5087   }
5088 
5089   /* We don't need to look for a sample in push-based */
5090   if (!qtdemux->pullbased)
5091     return TRUE;
5092 
5093   /* and move to the keyframe before the indicated media time of the
5094    * segment */
5095   if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5096     if (qtdemux->segment.rate >= 0) {
5097       index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5098       stream->to_sample = G_MAXUINT32;
5099       GST_DEBUG_OBJECT (stream->pad,
5100           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5101           GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5102           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5103     } else {
5104       index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5105       stream->to_sample = index;
5106       GST_DEBUG_OBJECT (stream->pad,
5107           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5108           GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5109           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5110     }
5111   } else {
5112     GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5113         "this is an empty segment");
5114     return TRUE;
5115   }
5116 
5117   /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5118    * encountered an error and printed a message so we return appropriately */
5119   if (index == -1)
5120     return FALSE;
5121 
5122   /* we're at the right spot */
5123   if (index == stream->sample_index) {
5124     GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5125     return TRUE;
5126   }
5127 
5128   /* find keyframe of the target index */
5129   kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5130 
5131   /* go back two frames to provide lead-in for non-raw audio decoders */
5132   if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5133     guint32 lead_in = 2;
5134     guint32 old_index = kf_index;
5135     GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5136 
5137     if (gst_structure_has_name (s, "audio/mpeg")) {
5138       gint mpegversion;
5139       if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5140           && mpegversion == 1) {
5141         /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5142         lead_in = 30;
5143       }
5144     }
5145 
5146     kf_index = MAX (kf_index, lead_in) - lead_in;
5147     if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5148       GST_DEBUG_OBJECT (stream->pad,
5149           "Moving backwards %u frames to ensure sufficient sound lead-in",
5150           old_index - kf_index);
5151     } else {
5152       kf_index = old_index;
5153     }
5154   }
5155 
5156   /* if we move forwards, we don't have to go back to the previous
5157    * keyframe since we already sent that. We can also just jump to
5158    * the keyframe right before the target index if there is one. */
5159   if (index > stream->sample_index) {
5160     /* moving forwards check if we move past a keyframe */
5161     if (kf_index > stream->sample_index) {
5162       GST_DEBUG_OBJECT (stream->pad,
5163           "moving forwards to keyframe at %u "
5164           "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5165           kf_index,
5166           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5167           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5168       gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5169     } else {
5170       GST_DEBUG_OBJECT (stream->pad,
5171           "moving forwards, keyframe at %u "
5172           "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5173           kf_index,
5174           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5175           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5176     }
5177   } else {
5178     GST_DEBUG_OBJECT (stream->pad,
5179         "moving backwards to %sframe at %u "
5180         "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5181         (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5182         GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5183         GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5184     gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5185   }
5186 
5187   return TRUE;
5188 }
5189 
5190 /* prepare to get the current sample of @stream, getting essential values.
5191  *
5192  * This function will also prepare and send the segment when needed.
5193  *
5194  * Return FALSE if the stream is EOS.
5195  *
5196  * PULL-BASED
5197  */
5198 static gboolean
gst_qtdemux_prepare_current_sample(GstQTDemux * qtdemux,QtDemuxStream * stream,gboolean * empty,guint64 * offset,guint * size,GstClockTime * dts,GstClockTime * pts,GstClockTime * duration,gboolean * keyframe)5199 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5200     QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5201     GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5202     gboolean * keyframe)
5203 {
5204   QtDemuxSample *sample;
5205   GstClockTime time_position;
5206   guint32 seg_idx;
5207 
5208   g_return_val_if_fail (stream != NULL, FALSE);
5209 
5210   time_position = stream->time_position;
5211   if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5212     goto eos;
5213 
5214   seg_idx = stream->segment_index;
5215   if (G_UNLIKELY (seg_idx == -1)) {
5216     /* find segment corresponding to time_position if we are looking
5217      * for a segment. */
5218     seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5219   }
5220 
5221   /* different segment, activate it, sample_index will be set. */
5222   if (G_UNLIKELY (stream->segment_index != seg_idx))
5223     gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5224 
5225   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5226               segments[stream->segment_index]))) {
5227     QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5228 
5229     GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5230         " prepare empty sample");
5231 
5232     *empty = TRUE;
5233     *pts = *dts = time_position;
5234     *duration = seg->duration - (time_position - seg->time);
5235 
5236     return TRUE;
5237   }
5238 
5239   *empty = FALSE;
5240 
5241   if (stream->sample_index == -1)
5242     stream->sample_index = 0;
5243 
5244   GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5245       stream->sample_index, stream->n_samples);
5246 
5247   if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5248     if (!qtdemux->fragmented)
5249       goto eos;
5250 
5251     GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5252     do {
5253       GstFlowReturn flow;
5254 
5255       GST_OBJECT_LOCK (qtdemux);
5256       flow = qtdemux_add_fragmented_samples (qtdemux);
5257       GST_OBJECT_UNLOCK (qtdemux);
5258 
5259       if (flow != GST_FLOW_OK)
5260         goto eos;
5261     }
5262     while (stream->sample_index >= stream->n_samples);
5263   }
5264 
5265   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5266     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5267         stream->sample_index);
5268     return FALSE;
5269   }
5270 
5271   /* now get the info for the sample we're at */
5272   sample = &stream->samples[stream->sample_index];
5273 
5274   *dts = QTSAMPLE_DTS (stream, sample);
5275   *pts = QTSAMPLE_PTS (stream, sample);
5276   *offset = sample->offset;
5277   *size = sample->size;
5278   *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5279   *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5280 
5281   return TRUE;
5282 
5283   /* special cases */
5284 eos:
5285   {
5286     stream->time_position = GST_CLOCK_TIME_NONE;
5287     return FALSE;
5288   }
5289 }
5290 
5291 /* move to the next sample in @stream.
5292  *
5293  * Moves to the next segment when needed.
5294  */
5295 static void
gst_qtdemux_advance_sample(GstQTDemux * qtdemux,QtDemuxStream * stream)5296 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5297 {
5298   QtDemuxSample *sample;
5299   QtDemuxSegment *segment;
5300 
5301   /* get current segment */
5302   segment = &stream->segments[stream->segment_index];
5303 
5304   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5305     GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5306     goto next_segment;
5307   }
5308 
5309   if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5310     /* Mark the stream as EOS */
5311     GST_DEBUG_OBJECT (qtdemux,
5312         "reached max allowed sample %u, mark EOS", stream->to_sample);
5313     stream->time_position = GST_CLOCK_TIME_NONE;
5314     return;
5315   }
5316 
5317   /* move to next sample */
5318   stream->sample_index++;
5319   stream->offset_in_sample = 0;
5320 
5321   GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5322       stream->n_samples);
5323 
5324   /* reached the last sample, we need the next segment */
5325   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5326     goto next_segment;
5327 
5328   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5329     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5330         stream->sample_index);
5331     return;
5332   }
5333 
5334   /* get next sample */
5335   sample = &stream->samples[stream->sample_index];
5336 
5337   GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5338       GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5339       GST_TIME_ARGS (segment->media_stop));
5340 
5341   /* see if we are past the segment */
5342   if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5343     goto next_segment;
5344 
5345   if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5346     /* inside the segment, update time_position, looks very familiar to
5347      * GStreamer segments, doesn't it? */
5348     stream->time_position =
5349         QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5350   } else {
5351     /* not yet in segment, time does not yet increment. This means
5352      * that we are still prerolling keyframes to the decoder so it can
5353      * decode the first sample of the segment. */
5354     stream->time_position = segment->time;
5355   }
5356   return;
5357 
5358   /* move to the next segment */
5359 next_segment:
5360   {
5361     GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5362 
5363     if (stream->segment_index == stream->n_segments - 1) {
5364       /* are we at the end of the last segment, we're EOS */
5365       stream->time_position = GST_CLOCK_TIME_NONE;
5366     } else {
5367       /* else we're only at the end of the current segment */
5368       stream->time_position = segment->stop_time;
5369     }
5370     /* make sure we select a new segment */
5371 
5372     /* accumulate previous segments */
5373     if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5374       stream->accumulated_base +=
5375           (stream->segment.stop -
5376           stream->segment.start) / ABS (stream->segment.rate);
5377 
5378     stream->segment_index = -1;
5379   }
5380 }
5381 
5382 static void
gst_qtdemux_sync_streams(GstQTDemux * demux)5383 gst_qtdemux_sync_streams (GstQTDemux * demux)
5384 {
5385   gint i;
5386 
5387   if (QTDEMUX_N_STREAMS (demux) <= 1)
5388     return;
5389 
5390   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5391     QtDemuxStream *stream;
5392     GstClockTime end_time;
5393 
5394     stream = QTDEMUX_NTH_STREAM (demux, i);
5395 
5396     if (!stream->pad)
5397       continue;
5398 
5399     /* TODO advance time on subtitle streams here, if any some day */
5400 
5401     /* some clips/trailers may have unbalanced streams at the end,
5402      * so send EOS on shorter stream to prevent stalling others */
5403 
5404     /* do not mess with EOS if SEGMENT seeking */
5405     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5406       continue;
5407 
5408     if (demux->pullbased) {
5409       /* loop mode is sample time based */
5410       if (!STREAM_IS_EOS (stream))
5411         continue;
5412     } else {
5413       /* push mode is byte position based */
5414       if (stream->n_samples &&
5415           stream->samples[stream->n_samples - 1].offset >= demux->offset)
5416         continue;
5417     }
5418 
5419     if (stream->sent_eos)
5420       continue;
5421 
5422     /* only act if some gap */
5423     end_time = stream->segments[stream->n_segments - 1].stop_time;
5424     GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5425         ", stream end: %" GST_TIME_FORMAT,
5426         GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5427     if (GST_CLOCK_TIME_IS_VALID (end_time)
5428         && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5429       GstEvent *event;
5430 
5431       GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5432           GST_PAD_NAME (stream->pad));
5433       stream->sent_eos = TRUE;
5434       event = gst_event_new_eos ();
5435       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5436         gst_event_set_seqnum (event, demux->segment_seqnum);
5437       gst_pad_push_event (stream->pad, event);
5438     }
5439   }
5440 }
5441 
5442 /* EOS and NOT_LINKED need to be combined. This means that we return:
5443  *
5444  *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5445  *  GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5446  */
5447 static GstFlowReturn
gst_qtdemux_combine_flows(GstQTDemux * demux,QtDemuxStream * stream,GstFlowReturn ret)5448 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5449     GstFlowReturn ret)
5450 {
5451   GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5452 
5453   if (stream->pad)
5454     ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5455         ret);
5456   else
5457     ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5458 
5459   GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5460   return ret;
5461 }
5462 
5463 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5464  * completely clipped
5465  *
5466  * Should be used only with raw buffers */
5467 static GstBuffer *
gst_qtdemux_clip_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5468 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5469     GstBuffer * buf)
5470 {
5471   guint64 start, stop, cstart, cstop, diff;
5472   GstClockTime pts, duration;
5473   gsize size, osize;
5474   gint num_rate, denom_rate;
5475   gint frame_size;
5476   gboolean clip_data;
5477   guint offset;
5478 
5479   osize = size = gst_buffer_get_size (buf);
5480   offset = 0;
5481 
5482   /* depending on the type, setup the clip parameters */
5483   if (stream->subtype == FOURCC_soun) {
5484     frame_size = CUR_STREAM (stream)->bytes_per_frame;
5485     num_rate = GST_SECOND;
5486     denom_rate = (gint) CUR_STREAM (stream)->rate;
5487     clip_data = TRUE;
5488   } else if (stream->subtype == FOURCC_vide) {
5489     frame_size = size;
5490     num_rate = CUR_STREAM (stream)->fps_n;
5491     denom_rate = CUR_STREAM (stream)->fps_d;
5492     clip_data = FALSE;
5493   } else
5494     goto wrong_type;
5495 
5496   if (frame_size <= 0)
5497     goto bad_frame_size;
5498 
5499   /* we can only clip if we have a valid pts */
5500   pts = GST_BUFFER_PTS (buf);
5501   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5502     goto no_pts;
5503 
5504   duration = GST_BUFFER_DURATION (buf);
5505 
5506   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5507     duration =
5508         gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5509   }
5510 
5511   start = pts;
5512   stop = start + duration;
5513 
5514   if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5515               GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5516     goto clipped;
5517 
5518   /* see if some clipping happened */
5519   diff = cstart - start;
5520   if (diff > 0) {
5521     pts += diff;
5522     duration -= diff;
5523 
5524     if (clip_data) {
5525       /* bring clipped time to samples and to bytes */
5526       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5527       diff *= frame_size;
5528 
5529       GST_DEBUG_OBJECT (qtdemux,
5530           "clipping start to %" GST_TIME_FORMAT " %"
5531           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5532 
5533       offset = diff;
5534       size -= diff;
5535     }
5536   }
5537   diff = stop - cstop;
5538   if (diff > 0) {
5539     duration -= diff;
5540 
5541     if (clip_data) {
5542       /* bring clipped time to samples and then to bytes */
5543       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5544       diff *= frame_size;
5545       GST_DEBUG_OBJECT (qtdemux,
5546           "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5547           " bytes", GST_TIME_ARGS (cstop), diff);
5548       size -= diff;
5549     }
5550   }
5551 
5552   if (offset != 0 || size != osize)
5553     gst_buffer_resize (buf, offset, size);
5554 
5555   GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5556   GST_BUFFER_PTS (buf) = pts;
5557   GST_BUFFER_DURATION (buf) = duration;
5558 
5559   return buf;
5560 
5561   /* dropped buffer */
5562 wrong_type:
5563   {
5564     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5565     return buf;
5566   }
5567 bad_frame_size:
5568   {
5569     GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5570     return buf;
5571   }
5572 no_pts:
5573   {
5574     GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5575     return buf;
5576   }
5577 clipped:
5578   {
5579     GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5580     gst_buffer_unref (buf);
5581     return NULL;
5582   }
5583 }
5584 
5585 static GstBuffer *
gst_qtdemux_align_buffer(GstQTDemux * demux,GstBuffer * buffer,gsize alignment)5586 gst_qtdemux_align_buffer (GstQTDemux * demux,
5587     GstBuffer * buffer, gsize alignment)
5588 {
5589   GstMapInfo map;
5590 
5591   gst_buffer_map (buffer, &map, GST_MAP_READ);
5592 
5593   if (map.size < sizeof (guintptr)) {
5594     gst_buffer_unmap (buffer, &map);
5595     return buffer;
5596   }
5597 
5598   if (((guintptr) map.data) & (alignment - 1)) {
5599     GstBuffer *new_buffer;
5600     GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5601 
5602     new_buffer = gst_buffer_new_allocate (NULL,
5603         gst_buffer_get_size (buffer), &params);
5604 
5605     /* Copy data "by hand", so ensure alignment is kept: */
5606     gst_buffer_fill (new_buffer, 0, map.data, map.size);
5607 
5608     gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5609     GST_DEBUG_OBJECT (demux,
5610         "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5611         alignment);
5612 
5613     gst_buffer_unmap (buffer, &map);
5614     gst_buffer_unref (buffer);
5615 
5616     return new_buffer;
5617   }
5618 
5619   gst_buffer_unmap (buffer, &map);
5620   return buffer;
5621 }
5622 
5623 static guint8 *
convert_to_s334_1a(const guint8 * ccpair,guint8 ccpair_size,guint field,gsize * res)5624 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5625     gsize * res)
5626 {
5627   guint8 *storage;
5628   gsize i;
5629 
5630   /* We are converting from pairs to triplets */
5631   *res = ccpair_size / 2 * 3;
5632   storage = g_malloc (*res);
5633   for (i = 0; i * 2 < ccpair_size; i += 1) {
5634     /* FIXME: Use line offset 0 as we simply can't know here */
5635     if (field == 1)
5636       storage[i * 3] = 0x80 | 0x00;
5637     else
5638       storage[i * 3] = 0x00 | 0x00;
5639     storage[i * 3 + 1] = ccpair[i * 2];
5640     storage[i * 3 + 2] = ccpair[i * 2 + 1];
5641   }
5642 
5643   return storage;
5644 }
5645 
5646 static guint8 *
extract_cc_from_data(QtDemuxStream * stream,const guint8 * data,gsize size,gsize * cclen)5647 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5648     gsize * cclen)
5649 {
5650   guint8 *res = NULL;
5651   guint32 atom_length, fourcc;
5652   QtDemuxStreamStsdEntry *stsd_entry;
5653 
5654   GST_MEMDUMP ("caption atom", data, size);
5655 
5656   /* There might be multiple atoms */
5657 
5658   *cclen = 0;
5659   if (size < 8)
5660     goto invalid_cdat;
5661   atom_length = QT_UINT32 (data);
5662   fourcc = QT_FOURCC (data + 4);
5663   if (G_UNLIKELY (atom_length > size || atom_length == 8))
5664     goto invalid_cdat;
5665 
5666   GST_DEBUG_OBJECT (stream->pad, "here");
5667 
5668   /* Check if we have something compatible */
5669   stsd_entry = CUR_STREAM (stream);
5670   switch (stsd_entry->fourcc) {
5671     case FOURCC_c608:{
5672       guint8 *cdat = NULL, *cdt2 = NULL;
5673       gsize cdat_size = 0, cdt2_size = 0;
5674       /* Should be cdat or cdt2 */
5675       if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5676         GST_WARNING_OBJECT (stream->pad,
5677             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5678             GST_FOURCC_ARGS (fourcc));
5679         goto invalid_cdat;
5680       }
5681 
5682       /* Convert to S334-1 Annex A byte triplet */
5683       if (fourcc == FOURCC_cdat)
5684         cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5685       else
5686         cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5687       GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5688           size, atom_length);
5689 
5690       /* Check for another atom ? */
5691       if (size > atom_length + 8) {
5692         guint32 new_atom_length = QT_UINT32 (data + atom_length);
5693         if (size >= atom_length + new_atom_length) {
5694           fourcc = QT_FOURCC (data + atom_length + 4);
5695           if (fourcc == FOURCC_cdat) {
5696             if (cdat == NULL)
5697               cdat =
5698                   convert_to_s334_1a (data + atom_length + 8,
5699                   new_atom_length - 8, 1, &cdat_size);
5700             else
5701               GST_WARNING_OBJECT (stream->pad,
5702                   "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5703           } else {
5704             if (cdt2 == NULL)
5705               cdt2 =
5706                   convert_to_s334_1a (data + atom_length + 8,
5707                   new_atom_length - 8, 2, &cdt2_size);
5708             else
5709               GST_WARNING_OBJECT (stream->pad,
5710                   "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5711           }
5712         }
5713       }
5714 
5715       *cclen = cdat_size + cdt2_size;
5716       res = g_malloc (*cclen);
5717       if (cdat_size)
5718         memcpy (res, cdat, cdat_size);
5719       if (cdt2_size)
5720         memcpy (res + cdat_size, cdt2, cdt2_size);
5721       g_free (cdat);
5722       g_free (cdt2);
5723     }
5724       break;
5725     case FOURCC_c708:
5726       if (fourcc != FOURCC_ccdp) {
5727         GST_WARNING_OBJECT (stream->pad,
5728             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5729             GST_FOURCC_ARGS (fourcc));
5730         goto invalid_cdat;
5731       }
5732       *cclen = atom_length - 8;
5733       res = g_memdup2 (data + 8, *cclen);
5734       break;
5735     default:
5736       /* Keep this here in case other closed caption formats are added */
5737       g_assert_not_reached ();
5738       break;
5739   }
5740 
5741   GST_MEMDUMP ("Output", res, *cclen);
5742   return res;
5743 
5744   /* Errors */
5745 invalid_cdat:
5746   GST_WARNING ("[cdat] atom is too small or invalid");
5747   return NULL;
5748 }
5749 
5750 /* Handle Closed Caption sample buffers.
5751  * The input buffer metadata must be writable,
5752  * but time/duration etc not yet set and need not be preserved */
5753 static GstBuffer *
gst_qtdemux_process_buffer_clcp(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5754 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5755     GstBuffer * buf)
5756 {
5757   GstBuffer *outbuf = NULL;
5758   GstMapInfo map;
5759   guint8 *cc;
5760   gsize cclen = 0;
5761 
5762   gst_buffer_map (buf, &map, GST_MAP_READ);
5763 
5764   /* empty buffer is sent to terminate previous subtitle */
5765   if (map.size <= 2) {
5766     gst_buffer_unmap (buf, &map);
5767     gst_buffer_unref (buf);
5768     return NULL;
5769   }
5770 
5771   /* For closed caption, we need to extract the information from the
5772    * [cdat],[cdt2] or [ccdp] atom */
5773   cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5774   gst_buffer_unmap (buf, &map);
5775   if (cc) {
5776     outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5777     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5778   } else {
5779     /* Conversion failed or there's nothing */
5780   }
5781   gst_buffer_unref (buf);
5782 
5783   return outbuf;
5784 }
5785 
5786 /* DVD subpicture specific sample handling.
5787  * the input buffer metadata must be writable,
5788  * but time/duration etc not yet set and need not be preserved */
5789 static GstBuffer *
gst_qtdemux_process_buffer_dvd(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5790 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5791     GstBuffer * buf)
5792 {
5793   /* send a one time dvd clut event */
5794   if (stream->pending_event && stream->pad)
5795     gst_pad_push_event (stream->pad, stream->pending_event);
5796   stream->pending_event = NULL;
5797 
5798   /* empty buffer is sent to terminate previous subtitle */
5799   if (gst_buffer_get_size (buf) <= 2) {
5800     gst_buffer_unref (buf);
5801     return NULL;
5802   }
5803 
5804   /* That's all the processing needed for subpictures */
5805   return buf;
5806 }
5807 
5808 /* Timed text formats
5809  * the input buffer metadata must be writable,
5810  * but time/duration etc not yet set and need not be preserved */
5811 static GstBuffer *
gst_qtdemux_process_buffer_text(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5812 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5813     GstBuffer * buf)
5814 {
5815   GstBuffer *outbuf = NULL;
5816   GstMapInfo map;
5817   guint nsize = 0;
5818   gchar *str;
5819 
5820   /* not many cases for now */
5821   if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5822           stream->subtype != FOURCC_sbtl)) {
5823     return buf;
5824   }
5825 
5826   gst_buffer_map (buf, &map, GST_MAP_READ);
5827 
5828   /* empty buffer is sent to terminate previous subtitle */
5829   if (map.size <= 2) {
5830     gst_buffer_unmap (buf, &map);
5831     gst_buffer_unref (buf);
5832     return NULL;
5833   }
5834 
5835   nsize = GST_READ_UINT16_BE (map.data);
5836   nsize = MIN (nsize, map.size - 2);
5837 
5838   GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5839       nsize, map.size);
5840 
5841   /* takes care of UTF-8 validation or UTF-16 recognition,
5842    * no other encoding expected */
5843   str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5844   gst_buffer_unmap (buf, &map);
5845 
5846   if (str) {
5847     outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5848     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5849   } else {
5850     /* this should not really happen unless the subtitle is corrupted */
5851   }
5852   gst_buffer_unref (buf);
5853 
5854   /* FIXME ? convert optional subsequent style info to markup */
5855 
5856   return outbuf;
5857 }
5858 
5859 /* WebVTT sample handling according to 14496-30 */
5860 static GstBuffer *
gst_qtdemux_process_buffer_wvtt(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5861 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5862     GstBuffer * buf)
5863 {
5864   GstBuffer *outbuf = NULL;
5865   GstMapInfo map;
5866 
5867   if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5868     g_assert_not_reached ();    /* The buffer must be mappable */
5869   }
5870 
5871   if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5872     GstEvent *gap = NULL;
5873     /* Push a gap event */
5874     stream->segment.position = GST_BUFFER_PTS (buf);
5875     gap =
5876         gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5877     gst_pad_push_event (stream->pad, gap);
5878 
5879     if (GST_BUFFER_DURATION_IS_VALID (buf))
5880       stream->segment.position += GST_BUFFER_DURATION (buf);
5881   } else {
5882     outbuf =
5883         qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5884         GST_BUFFER_DURATION (buf), map.data, map.size);
5885     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5886   }
5887 
5888   gst_buffer_unmap (buf, &map);
5889   gst_buffer_unref (buf);
5890 
5891   return outbuf;
5892 }
5893 
5894 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
5895 static void
kpi_log_demux_push_first_frame(GstQTDemux * qtdemux,QtDemuxStream * stream)5896 kpi_log_demux_push_first_frame (GstQTDemux *qtdemux, QtDemuxStream *stream)
5897 {
5898   if (stream->has_push_first_frame) {
5899     return;
5900   }
5901 
5902   if (stream->subtype == FOURCC_vide && stream->on_keyframe) {
5903     stream->has_push_first_frame = TRUE;
5904     GST_WARNING_OBJECT(qtdemux, "KPI-TRACE: FIRST-VIDEO-FRAME demux push first video keyframe");
5905   } else if (stream->subtype == FOURCC_soun) {
5906     stream->has_push_first_frame = TRUE;
5907     GST_WARNING_OBJECT(qtdemux, "KPI-TRACE: demux push first audio frame");
5908   }
5909 }
5910 #endif
5911 
5912 static GstFlowReturn
gst_qtdemux_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5913 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5914     GstBuffer * buf)
5915 {
5916   GstFlowReturn ret = GST_FLOW_OK;
5917   GstClockTime pts, duration;
5918 
5919   if (stream->need_clip)
5920     buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5921 
5922   if (G_UNLIKELY (buf == NULL))
5923     goto exit;
5924 
5925   if (G_UNLIKELY (stream->discont)) {
5926     GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5927     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5928     stream->discont = FALSE;
5929   } else {
5930     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5931   }
5932 
5933   GST_LOG_OBJECT (qtdemux,
5934       "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5935       ", duration %" GST_TIME_FORMAT " on pad %s",
5936       GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5937       GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5938       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5939 
5940   if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5941     GstStructure *crypto_info;
5942     QtDemuxAavdEncryptionInfo *info =
5943         (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5944 
5945     crypto_info = gst_structure_copy (info->default_properties);
5946     if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5947       GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5948   }
5949 
5950   if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5951           || stream->protection_scheme_type == FOURCC_cbcs)) {
5952     GstStructure *crypto_info;
5953     QtDemuxCencSampleSetInfo *info =
5954         (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5955     gint index;
5956     GstEvent *event;
5957 
5958     while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5959       GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5960           GST_PTR_FORMAT, event);
5961       gst_pad_push_event (stream->pad, event);
5962     }
5963 
5964     if (info->crypto_info == NULL) {
5965       if (stream->protection_scheme_type == FOURCC_cbcs) {
5966         crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5967         if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5968           GST_ERROR_OBJECT (qtdemux,
5969               "failed to attach cbcs metadata to buffer");
5970           qtdemux_gst_structure_free (crypto_info);
5971         } else {
5972           GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5973         }
5974       } else {
5975         GST_DEBUG_OBJECT (qtdemux,
5976             "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5977       }
5978     } else {
5979       /* The end of the crypto_info array matches our n_samples position,
5980        * so count backward from there */
5981       index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5982       if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5983         /* steal structure from array */
5984         crypto_info = g_ptr_array_index (info->crypto_info, index);
5985         g_ptr_array_index (info->crypto_info, index) = NULL;
5986         GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5987             info->crypto_info->len);
5988         if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5989           GST_ERROR_OBJECT (qtdemux,
5990               "failed to attach cenc metadata to buffer");
5991       } else {
5992         GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5993             index, stream->sample_index);
5994       }
5995     }
5996   }
5997 
5998   if (stream->alignment > 1)
5999     buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6000 
6001   pts = GST_BUFFER_PTS (buf);
6002   duration = GST_BUFFER_DURATION (buf);
6003 
6004 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: add log for kpi
6005   kpi_log_demux_push_first_frame (qtdemux, stream);
6006 #endif
6007   ret = gst_pad_push (stream->pad, buf);
6008 
6009   if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6010     /* mark position in stream, we'll need this to know when to send GAP event */
6011     stream->segment.position = pts + duration;
6012   }
6013 
6014 exit:
6015 
6016   return ret;
6017 }
6018 
6019 static GstFlowReturn
gst_qtdemux_split_and_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)6020 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6021     GstBuffer * buf)
6022 {
6023   GstFlowReturn ret = GST_FLOW_OK;
6024 
6025   if (stream->subtype == FOURCC_clcp
6026       && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6027     GstMapInfo map;
6028     guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6029     guint n_triplets, i;
6030     guint field1_off = 0, field2_off = 0;
6031 
6032     /* We have to split CEA608 buffers so that each outgoing buffer contains
6033      * one byte pair per field according to the framerate of the video track.
6034      *
6035      * If there is only a single byte pair per field we don't have to do
6036      * anything
6037      */
6038 
6039     gst_buffer_map (buf, &map, GST_MAP_READ);
6040 
6041     n_triplets = map.size / 3;
6042     for (i = 0; i < n_triplets; i++) {
6043       if (map.data[3 * i] & 0x80)
6044         n_field1++;
6045       else
6046         n_field2++;
6047     }
6048 
6049     g_assert (n_field1 || n_field2);
6050 
6051     /* If there's more than 1 frame we have to split, otherwise we can just
6052      * pass through */
6053     if (n_field1 > 1 || n_field2 > 1) {
6054       n_output_buffers =
6055           gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6056           CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6057 
6058       for (i = 0; i < n_output_buffers; i++) {
6059         GstBuffer *outbuf =
6060             gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6061         GstMapInfo outmap;
6062         guint8 *outptr;
6063 
6064         gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6065         outptr = outmap.data;
6066 
6067         if (n_field1) {
6068           gboolean found = FALSE;
6069 
6070           while (map.data + field1_off < map.data + map.size) {
6071             if (map.data[field1_off] & 0x80) {
6072               memcpy (outptr, &map.data[field1_off], 3);
6073               field1_off += 3;
6074               found = TRUE;
6075               break;
6076             }
6077             field1_off += 3;
6078           }
6079 
6080           if (!found) {
6081             const guint8 empty[] = { 0x80, 0x80, 0x80 };
6082 
6083             memcpy (outptr, empty, 3);
6084           }
6085 
6086           outptr += 3;
6087         }
6088 
6089         if (n_field2) {
6090           gboolean found = FALSE;
6091 
6092           while (map.data + field2_off < map.data + map.size) {
6093             if ((map.data[field2_off] & 0x80) == 0) {
6094               memcpy (outptr, &map.data[field2_off], 3);
6095               field2_off += 3;
6096               found = TRUE;
6097               break;
6098             }
6099             field2_off += 3;
6100           }
6101 
6102           if (!found) {
6103             const guint8 empty[] = { 0x00, 0x80, 0x80 };
6104 
6105             memcpy (outptr, empty, 3);
6106           }
6107 
6108           outptr += 3;
6109         }
6110 
6111         gst_buffer_unmap (outbuf, &outmap);
6112 
6113         GST_BUFFER_PTS (outbuf) =
6114             GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6115             GST_SECOND * CUR_STREAM (stream)->fps_d,
6116             CUR_STREAM (stream)->fps_n);
6117         GST_BUFFER_DURATION (outbuf) =
6118             gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6119             CUR_STREAM (stream)->fps_n);
6120         GST_BUFFER_OFFSET (outbuf) = -1;
6121         GST_BUFFER_OFFSET_END (outbuf) = -1;
6122 
6123         ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6124 
6125         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6126           break;
6127       }
6128       gst_buffer_unmap (buf, &map);
6129       gst_buffer_unref (buf);
6130     } else {
6131       gst_buffer_unmap (buf, &map);
6132       ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6133     }
6134   } else {
6135     ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6136   }
6137 
6138   return ret;
6139 }
6140 
6141 /* Sets a buffer's attributes properly and pushes it downstream.
6142  * Also checks for additional actions and custom processing that may
6143  * need to be done first.
6144  */
6145 static GstFlowReturn
gst_qtdemux_decorate_and_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf,GstClockTime dts,GstClockTime pts,GstClockTime duration,gboolean keyframe,GstClockTime position,guint64 byte_position)6146 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6147     QtDemuxStream * stream, GstBuffer * buf,
6148     GstClockTime dts, GstClockTime pts, GstClockTime duration,
6149     gboolean keyframe, GstClockTime position, guint64 byte_position)
6150 {
6151   GstFlowReturn ret = GST_FLOW_OK;
6152 
6153   /* offset the timestamps according to the edit list */
6154 
6155   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6156     gchar *url;
6157     GstMapInfo map;
6158 
6159     gst_buffer_map (buf, &map, GST_MAP_READ);
6160     url = g_strndup ((gchar *) map.data, map.size);
6161     gst_buffer_unmap (buf, &map);
6162     if (url != NULL && strlen (url) != 0) {
6163       /* we have RTSP redirect now */
6164       g_free (qtdemux->redirect_location);
6165       qtdemux->redirect_location = g_strdup (url);
6166       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6167           gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6168               gst_structure_new ("redirect",
6169                   "new-location", G_TYPE_STRING, url, NULL)));
6170     } else {
6171       GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6172           "posting");
6173     }
6174     g_free (url);
6175   }
6176 
6177   /* position reporting */
6178   if (qtdemux->segment.rate >= 0) {
6179     qtdemux->segment.position = position;
6180     gst_qtdemux_sync_streams (qtdemux);
6181   }
6182 
6183   if (G_UNLIKELY (!stream->pad)) {
6184     GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6185     gst_buffer_unref (buf);
6186     goto exit;
6187   }
6188 
6189   /* send out pending buffers */
6190   while (stream->buffers) {
6191     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6192 
6193     if (G_UNLIKELY (stream->discont)) {
6194       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6195       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6196       stream->discont = FALSE;
6197     } else {
6198       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6199     }
6200 
6201     if (stream->alignment > 1)
6202       buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6203     gst_pad_push (stream->pad, buffer);
6204 
6205     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6206   }
6207 
6208   /* we're going to modify the metadata */
6209   buf = gst_buffer_make_writable (buf);
6210 
6211   GST_BUFFER_DTS (buf) = dts;
6212   GST_BUFFER_PTS (buf) = pts;
6213   GST_BUFFER_DURATION (buf) = duration;
6214   GST_BUFFER_OFFSET (buf) = -1;
6215   GST_BUFFER_OFFSET_END (buf) = -1;
6216 
6217   if (G_UNLIKELY (stream->process_func))
6218     buf = stream->process_func (qtdemux, stream, buf);
6219 
6220   if (!buf) {
6221     goto exit;
6222   }
6223 
6224   if (!keyframe) {
6225     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6226     stream->on_keyframe = FALSE;
6227   } else {
6228     stream->on_keyframe = TRUE;
6229   }
6230 
6231   if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6232     gst_buffer_append_memory (buf,
6233         gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6234 
6235   if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6236     gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6237   }
6238 #if 0
6239   if (G_UNLIKELY (qtdemux->element_index)) {
6240     GstClockTime stream_time;
6241 
6242     stream_time =
6243         gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6244         timestamp);
6245     if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6246       GST_LOG_OBJECT (qtdemux,
6247           "adding association %" GST_TIME_FORMAT "-> %"
6248           G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6249       gst_index_add_association (qtdemux->element_index,
6250           qtdemux->index_id,
6251           keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6252           GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6253           GST_FORMAT_BYTES, byte_position, NULL);
6254     }
6255   }
6256 #endif
6257 
6258   ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6259 
6260 exit:
6261   return ret;
6262 }
6263 
6264 static const QtDemuxRandomAccessEntry *
gst_qtdemux_stream_seek_fragment(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime pos,gboolean after)6265 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6266     GstClockTime pos, gboolean after)
6267 {
6268   QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6269   guint n_entries = stream->n_ra_entries;
6270   guint i;
6271 
6272   /* we assume the table is sorted */
6273   for (i = 0; i < n_entries; ++i) {
6274     if (entries[i].ts > pos)
6275       break;
6276   }
6277 
6278   /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6279    * probably okay to assume that the index lists the very first fragment */
6280   if (i == 0)
6281     return &entries[0];
6282 
6283   if (after)
6284     return &entries[i];
6285   else
6286     return &entries[i - 1];
6287 }
6288 
6289 static gboolean
gst_qtdemux_do_fragmented_seek(GstQTDemux * qtdemux)6290 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6291 {
6292   const QtDemuxRandomAccessEntry *best_entry = NULL;
6293   gint i;
6294 
6295   GST_OBJECT_LOCK (qtdemux);
6296 
6297   g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6298 
6299   /* first see if we can determine where to go to using mfra,
6300    * before we start clearing things */
6301   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6302     const QtDemuxRandomAccessEntry *entry;
6303     QtDemuxStream *stream;
6304     gboolean is_audio_or_video;
6305 
6306     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6307 
6308     if (stream->ra_entries == NULL)
6309       continue;
6310 
6311     if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6312       is_audio_or_video = TRUE;
6313     else
6314       is_audio_or_video = FALSE;
6315 
6316     entry =
6317         gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6318         stream->time_position, !is_audio_or_video);
6319 
6320     GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6321         "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6322 
6323     stream->pending_seek = entry;
6324 
6325     /* decide position to jump to just based on audio/video tracks, not subs */
6326     if (!is_audio_or_video)
6327       continue;
6328 
6329     if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6330       best_entry = entry;
6331   }
6332 
6333   /* no luck, will handle seek otherwise */
6334   if (best_entry == NULL) {
6335     GST_OBJECT_UNLOCK (qtdemux);
6336     return FALSE;
6337   }
6338 
6339   /* ok, now we can prepare for processing as of located moof */
6340   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6341     QtDemuxStream *stream;
6342 
6343     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6344 
6345     g_free (stream->samples);
6346     stream->samples = NULL;
6347     stream->n_samples = 0;
6348     stream->stbl_index = -1;    /* no samples have yet been parsed */
6349     stream->sample_index = -1;
6350 
6351     if (stream->protection_scheme_info) {
6352       /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6353       if (stream->protection_scheme_type == FOURCC_cenc
6354           || stream->protection_scheme_type == FOURCC_cbcs) {
6355         QtDemuxCencSampleSetInfo *info =
6356             (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6357         if (info->crypto_info) {
6358           g_ptr_array_free (info->crypto_info, TRUE);
6359           info->crypto_info = NULL;
6360         }
6361       }
6362     }
6363   }
6364 
6365   GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6366       "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6367       GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6368       best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6369 
6370   qtdemux->moof_offset = best_entry->moof_offset;
6371 
6372   qtdemux_add_fragmented_samples (qtdemux);
6373 
6374   GST_OBJECT_UNLOCK (qtdemux);
6375   return TRUE;
6376 }
6377 
6378 static GstFlowReturn
gst_qtdemux_loop_state_movie(GstQTDemux * qtdemux)6379 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6380 {
6381   GstFlowReturn ret = GST_FLOW_OK;
6382   GstBuffer *buf = NULL;
6383   QtDemuxStream *stream, *target_stream = NULL;
6384   GstClockTime min_time;
6385   guint64 offset = 0;
6386   GstClockTime dts = GST_CLOCK_TIME_NONE;
6387   GstClockTime pts = GST_CLOCK_TIME_NONE;
6388   GstClockTime duration = 0;
6389   gboolean keyframe = FALSE;
6390   guint sample_size = 0;
6391   guint num_samples = 1;
6392   gboolean empty = 0;
6393   guint size;
6394   gint i;
6395 
6396   if (qtdemux->fragmented_seek_pending) {
6397     GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6398     if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6399       GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6400       qtdemux->fragmented_seek_pending = FALSE;
6401     } else {
6402       GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6403     }
6404   }
6405 
6406   /* Figure out the next stream sample to output, min_time is expressed in
6407    * global time and runs over the edit list segments. */
6408   min_time = G_MAXUINT64;
6409   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6410     GstClockTime position;
6411 
6412     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6413     position = stream->time_position;
6414 
6415     if (!GST_CLOCK_TIME_IS_VALID (position))
6416       continue;
6417 
6418     if (stream->segment_index != -1) {
6419       QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6420       position += segment->media_start;
6421     }
6422 
6423     /* position of -1 is EOS */
6424     if (position < min_time) {
6425       min_time = position;
6426       target_stream = stream;
6427     }
6428   }
6429   /* all are EOS */
6430   if (G_UNLIKELY (target_stream == NULL)) {
6431     GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6432     goto eos;
6433   }
6434 
6435   /* check for segment end */
6436   if (G_UNLIKELY (qtdemux->segment.stop != -1
6437           && qtdemux->segment.rate >= 0
6438           && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6439     GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6440     target_stream->time_position = GST_CLOCK_TIME_NONE;
6441     goto eos_stream;
6442   }
6443 
6444   /* gap events for subtitle streams */
6445   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6446     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6447     if (stream->pad) {
6448       GstClockTime gap_threshold;
6449 
6450       /* Only send gap events on non-subtitle streams if lagging way behind. */
6451       if (stream->subtype == FOURCC_subp
6452           || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6453           stream->subtype == FOURCC_wvtt)
6454         gap_threshold = 1 * GST_SECOND;
6455       else
6456         gap_threshold = 3 * GST_SECOND;
6457 
6458       /* send gap events until the stream catches up */
6459       /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6460       while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6461           GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6462           stream->segment.position + gap_threshold < min_time) {
6463         GstEvent *gap =
6464             gst_event_new_gap (stream->segment.position, gap_threshold);
6465         gst_pad_push_event (stream->pad, gap);
6466         stream->segment.position += gap_threshold;
6467       }
6468     }
6469   }
6470 
6471   stream = target_stream;
6472   /* fetch info for the current sample of this stream */
6473   if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6474               &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6475     goto eos_stream;
6476 
6477   gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6478   if (stream->new_caps) {
6479     gst_qtdemux_configure_stream (qtdemux, stream);
6480     qtdemux_do_allocation (stream, qtdemux);
6481   }
6482 
6483   /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6484   if (G_UNLIKELY (qtdemux->segment.
6485           flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6486     if (stream->subtype == FOURCC_vide) {
6487       if (!keyframe) {
6488         GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6489             stream->track_id);
6490         goto next;
6491       } else if (qtdemux->trickmode_interval > 0) {
6492         GstClockTimeDiff interval;
6493 
6494         if (qtdemux->segment.rate > 0)
6495           interval = stream->time_position - stream->last_keyframe_dts;
6496         else
6497           interval = stream->last_keyframe_dts - stream->time_position;
6498 
6499         if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6500             && interval < qtdemux->trickmode_interval) {
6501           GST_LOG_OBJECT (qtdemux,
6502               "Skipping keyframe within interval on track-id %u",
6503               stream->track_id);
6504           goto next;
6505         } else {
6506           stream->last_keyframe_dts = stream->time_position;
6507         }
6508       }
6509     }
6510   }
6511 
6512   GST_DEBUG_OBJECT (qtdemux,
6513       "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6514       ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6515       ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6516       sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6517       GST_TIME_ARGS (duration));
6518 
6519   if (G_UNLIKELY (empty)) {
6520     /* empty segment, push a gap if there's a second or more
6521      * difference and move to the next one */
6522     if ((pts + duration - stream->segment.position) >= GST_SECOND)
6523       gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6524     stream->segment.position = pts + duration;
6525     goto next;
6526   }
6527 
6528   /* hmm, empty sample, skip and move to next sample */
6529   if (G_UNLIKELY (sample_size <= 0))
6530     goto next;
6531 
6532   /* last pushed sample was out of boundary, goto next sample */
6533   if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6534     goto next;
6535 
6536   if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6537     GST_DEBUG_OBJECT (qtdemux,
6538         "size %d larger than stream max_buffer_size %d, trimming",
6539         sample_size, stream->max_buffer_size);
6540     size =
6541         MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6542   } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6543       && sample_size < stream->min_buffer_size) {
6544     guint start_sample_index = stream->sample_index;
6545     guint accumulated_size = sample_size;
6546     guint64 expected_next_offset = offset + sample_size;
6547 
6548     GST_DEBUG_OBJECT (qtdemux,
6549         "size %d smaller than stream min_buffer_size %d, combining with the next",
6550         sample_size, stream->min_buffer_size);
6551 
6552     while (stream->sample_index < stream->to_sample
6553         && stream->sample_index + 1 < stream->n_samples) {
6554       const QtDemuxSample *next_sample;
6555 
6556       /* Increment temporarily */
6557       stream->sample_index++;
6558 
6559       /* Failed to parse sample so let's go back to the previous one that was
6560        * still successful */
6561       if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6562         stream->sample_index--;
6563         break;
6564       }
6565 
6566       next_sample = &stream->samples[stream->sample_index];
6567 
6568       /* Not contiguous with the previous sample so let's go back to the
6569        * previous one that was still successful */
6570       if (next_sample->offset != expected_next_offset) {
6571         stream->sample_index--;
6572         break;
6573       }
6574 
6575       accumulated_size += next_sample->size;
6576       expected_next_offset += next_sample->size;
6577       if (accumulated_size >= stream->min_buffer_size)
6578         break;
6579     }
6580 
6581     num_samples = stream->sample_index + 1 - start_sample_index;
6582     stream->sample_index = start_sample_index;
6583     GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6584         num_samples, accumulated_size);
6585     size = accumulated_size;
6586   } else {
6587     size = sample_size;
6588   }
6589 
6590   if (qtdemux->cenc_aux_info_offset > 0) {
6591     GstMapInfo map;
6592     GstByteReader br;
6593     GstBuffer *aux_info = NULL;
6594 
6595     /* pull the data stored before the sample */
6596     ret =
6597         gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6598         offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6599     if (G_UNLIKELY (ret != GST_FLOW_OK))
6600       goto beach;
6601     gst_buffer_map (aux_info, &map, GST_MAP_READ);
6602     GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6603     gst_byte_reader_init (&br, map.data + 8, map.size);
6604     if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6605             qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6606       GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6607       gst_buffer_unmap (aux_info, &map);
6608       gst_buffer_unref (aux_info);
6609       ret = GST_FLOW_ERROR;
6610       goto beach;
6611     }
6612     gst_buffer_unmap (aux_info, &map);
6613     gst_buffer_unref (aux_info);
6614   }
6615 
6616   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6617       offset);
6618 
6619   if (stream->use_allocator) {
6620     /* if we have a per-stream allocator, use it */
6621     buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6622   }
6623 
6624   ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6625       size, &buf);
6626   if (G_UNLIKELY (ret != GST_FLOW_OK))
6627     goto beach;
6628 
6629   /* Update for both splitting and combining of samples */
6630   if (size != sample_size) {
6631     pts += gst_util_uint64_scale_int (GST_SECOND,
6632         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6633         stream->timescale);
6634     dts +=
6635         gst_util_uint64_scale_int (GST_SECOND,
6636         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6637         stream->timescale);
6638     duration =
6639         gst_util_uint64_scale_int (GST_SECOND,
6640         size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6641   }
6642 
6643   ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6644       dts, pts, duration, keyframe, min_time, offset);
6645 
6646   if (size < sample_size) {
6647     QtDemuxSample *sample = &stream->samples[stream->sample_index];
6648     QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6649 
6650     GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6651         sample->timestamp +
6652         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6653     if (time_position >= segment->media_start) {
6654       /* inside the segment, update time_position, looks very familiar to
6655        * GStreamer segments, doesn't it? */
6656       stream->time_position = (time_position - segment->media_start) +
6657           segment->time;
6658     } else {
6659       /* not yet in segment, time does not yet increment. This means
6660        * that we are still prerolling keyframes to the decoder so it can
6661        * decode the first sample of the segment. */
6662       stream->time_position = segment->time;
6663     }
6664   } else if (size > sample_size) {
6665     /* Increase to the last sample we already pulled so that advancing
6666      * below brings us to the next sample we need to pull */
6667     stream->sample_index += num_samples - 1;
6668   }
6669 
6670   /* combine flows */
6671   GST_OBJECT_LOCK (qtdemux);
6672   ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6673   GST_OBJECT_UNLOCK (qtdemux);
6674   /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6675    * we have no more data for the pad to push */
6676   if (ret == GST_FLOW_EOS)
6677     ret = GST_FLOW_OK;
6678 
6679   stream->offset_in_sample += size;
6680   if (stream->offset_in_sample >= sample_size) {
6681     gst_qtdemux_advance_sample (qtdemux, stream);
6682   }
6683   goto beach;
6684 
6685 next:
6686   gst_qtdemux_advance_sample (qtdemux, stream);
6687 
6688 beach:
6689   return ret;
6690 
6691   /* special cases */
6692 eos:
6693   {
6694     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6695     ret = GST_FLOW_EOS;
6696     goto beach;
6697   }
6698 eos_stream:
6699   {
6700     GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6701     /* EOS will be raised if all are EOS */
6702     ret = GST_FLOW_OK;
6703     goto beach;
6704   }
6705 }
6706 
6707 static void
gst_qtdemux_loop(GstPad * pad)6708 gst_qtdemux_loop (GstPad * pad)
6709 {
6710   GstQTDemux *qtdemux;
6711   guint64 cur_offset;
6712   GstFlowReturn ret;
6713 
6714   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6715 
6716   cur_offset = qtdemux->offset;
6717   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6718       cur_offset, qt_demux_state_string (qtdemux->state));
6719 
6720   switch (qtdemux->state) {
6721     case QTDEMUX_STATE_INITIAL:
6722     case QTDEMUX_STATE_HEADER:
6723       ret = gst_qtdemux_loop_state_header (qtdemux);
6724       break;
6725     case QTDEMUX_STATE_MOVIE:
6726       ret = gst_qtdemux_loop_state_movie (qtdemux);
6727       if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6728         ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6729       }
6730       break;
6731     default:
6732       /* ouch */
6733       goto invalid_state;
6734   }
6735 
6736   /* if something went wrong, pause */
6737   if (ret != GST_FLOW_OK)
6738     goto pause;
6739 
6740 done:
6741   gst_object_unref (qtdemux);
6742   return;
6743 
6744   /* ERRORS */
6745 invalid_state:
6746   {
6747     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6748         (NULL), ("streaming stopped, invalid state"));
6749     gst_pad_pause_task (pad);
6750     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6751     goto done;
6752   }
6753 pause:
6754   {
6755     const gchar *reason = gst_flow_get_name (ret);
6756 
6757     GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6758 
6759     gst_pad_pause_task (pad);
6760 
6761     /* fatal errors need special actions */
6762     /* check EOS */
6763     if (ret == GST_FLOW_EOS) {
6764       if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6765         /* we have no streams, post an error */
6766         gst_qtdemux_post_no_playable_stream_error (qtdemux);
6767       }
6768       if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6769         gint64 stop;
6770 
6771         if ((stop = qtdemux->segment.stop) == -1)
6772           stop = qtdemux->segment.duration;
6773 
6774         if (qtdemux->segment.rate >= 0) {
6775           GstMessage *message;
6776           GstEvent *event;
6777 
6778           GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6779           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6780               GST_FORMAT_TIME, stop);
6781           event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6782           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6783             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6784             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6785           }
6786           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6787           gst_qtdemux_push_event (qtdemux, event);
6788         } else {
6789           GstMessage *message;
6790           GstEvent *event;
6791 
6792           /*  For Reverse Playback */
6793           GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6794           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6795               GST_FORMAT_TIME, qtdemux->segment.start);
6796           event = gst_event_new_segment_done (GST_FORMAT_TIME,
6797               qtdemux->segment.start);
6798           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6799             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6800             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6801           }
6802           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6803           gst_qtdemux_push_event (qtdemux, event);
6804         }
6805       } else {
6806         GstEvent *event;
6807 
6808         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6809         event = gst_event_new_eos ();
6810         if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6811           gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6812         gst_qtdemux_push_event (qtdemux, event);
6813       }
6814     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6815       GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6816       gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6817     }
6818     goto done;
6819   }
6820 }
6821 
6822 /*
6823  * has_next_entry
6824  *
6825  * Returns if there are samples to be played.
6826  */
6827 static gboolean
has_next_entry(GstQTDemux * demux)6828 has_next_entry (GstQTDemux * demux)
6829 {
6830   QtDemuxStream *stream;
6831   gint i;
6832 
6833   GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6834 
6835   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6836     stream = QTDEMUX_NTH_STREAM (demux, i);
6837 
6838     if (stream->sample_index == -1) {
6839       stream->sample_index = 0;
6840       stream->offset_in_sample = 0;
6841     }
6842 
6843     if (stream->sample_index >= stream->n_samples) {
6844       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6845       continue;
6846     }
6847     GST_DEBUG_OBJECT (demux, "Found a sample");
6848     return TRUE;
6849   }
6850 
6851   GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6852   return FALSE;
6853 }
6854 
6855 /*
6856  * next_entry_size
6857  *
6858  * Returns the size of the first entry at the current offset.
6859  * If -1, there are none (which means EOS or empty file).
6860  */
6861 static guint64
next_entry_size(GstQTDemux * demux)6862 next_entry_size (GstQTDemux * demux)
6863 {
6864   QtDemuxStream *stream, *target_stream = NULL;
6865   guint64 smalloffs = (guint64) - 1;
6866   QtDemuxSample *sample;
6867   gint i;
6868 
6869   GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6870       demux->offset);
6871 
6872   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6873     stream = QTDEMUX_NTH_STREAM (demux, i);
6874 
6875     if (stream->sample_index == -1) {
6876       stream->sample_index = 0;
6877       stream->offset_in_sample = 0;
6878     }
6879 
6880     if (stream->sample_index >= stream->n_samples) {
6881       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6882       continue;
6883     }
6884 
6885     if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6886       GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6887           stream->sample_index);
6888       return -1;
6889     }
6890 
6891     sample = &stream->samples[stream->sample_index];
6892 
6893     GST_LOG_OBJECT (demux,
6894         "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6895         " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6896         stream->sample_index, sample->offset, sample->size);
6897 
6898     if (((smalloffs == -1)
6899             || (sample->offset < smalloffs)) && (sample->size)) {
6900       smalloffs = sample->offset;
6901       target_stream = stream;
6902     }
6903   }
6904 
6905   if (!target_stream)
6906     return -1;
6907 
6908   GST_LOG_OBJECT (demux,
6909       "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6910       G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6911 
6912   stream = target_stream;
6913   sample = &stream->samples[stream->sample_index];
6914 
6915   if (sample->offset >= demux->offset) {
6916     demux->todrop = sample->offset - demux->offset;
6917     return sample->size + demux->todrop;
6918   }
6919 
6920   GST_DEBUG_OBJECT (demux,
6921       "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6922   return -1;
6923 }
6924 
6925 static void
gst_qtdemux_post_progress(GstQTDemux * demux,gint num,gint denom)6926 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6927 {
6928   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6929 
6930   gst_element_post_message (GST_ELEMENT_CAST (demux),
6931       gst_message_new_element (GST_OBJECT_CAST (demux),
6932           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6933 }
6934 
6935 static gboolean
qtdemux_seek_offset(GstQTDemux * demux,guint64 offset)6936 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6937 {
6938   GstEvent *event;
6939   gboolean res = 0;
6940 
6941   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6942 
6943   event =
6944       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6945       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6946       GST_SEEK_TYPE_NONE, -1);
6947 
6948   /* store seqnum to drop flush events, they don't need to reach downstream */
6949   demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6950   res = gst_pad_push_event (demux->sinkpad, event);
6951   demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6952 
6953   return res;
6954 }
6955 
6956 /* check for seekable upstream, above and beyond a mere query */
6957 static void
gst_qtdemux_check_seekability(GstQTDemux * demux)6958 gst_qtdemux_check_seekability (GstQTDemux * demux)
6959 {
6960   GstQuery *query;
6961   gboolean seekable = FALSE;
6962   gint64 start = -1, stop = -1;
6963 
6964   if (demux->upstream_size)
6965     return;
6966 
6967   if (demux->upstream_format_is_time)
6968     return;
6969 
6970   query = gst_query_new_seeking (GST_FORMAT_BYTES);
6971   if (!gst_pad_peer_query (demux->sinkpad, query)) {
6972     GST_DEBUG_OBJECT (demux, "seeking query failed");
6973     goto done;
6974   }
6975 
6976   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6977 
6978   /* try harder to query upstream size if we didn't get it the first time */
6979   if (seekable && stop == -1) {
6980     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6981     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6982   }
6983 
6984   /* if upstream doesn't know the size, it's likely that it's not seekable in
6985    * practice even if it technically may be seekable */
6986   if (seekable && (start != 0 || stop <= start)) {
6987     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6988     seekable = FALSE;
6989   }
6990 
6991 done:
6992   gst_query_unref (query);
6993 
6994   GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6995       G_GUINT64_FORMAT ")", seekable, start, stop);
6996   demux->upstream_seekable = seekable;
6997   demux->upstream_size = seekable ? stop : -1;
6998 }
6999 
7000 static void
gst_qtdemux_drop_data(GstQTDemux * demux,gint bytes)7001 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7002 {
7003   g_return_if_fail (bytes <= demux->todrop);
7004 
7005   GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7006   gst_adapter_flush (demux->adapter, bytes);
7007   demux->neededbytes -= bytes;
7008   demux->offset += bytes;
7009   demux->todrop -= bytes;
7010 }
7011 
7012 /* PUSH-MODE only: Send a segment, if not done already. */
7013 static void
gst_qtdemux_check_send_pending_segment(GstQTDemux * demux)7014 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7015 {
7016   if (G_UNLIKELY (demux->need_segment)) {
7017     gint i;
7018 
7019     if (!demux->upstream_format_is_time) {
7020       gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7021     } else {
7022       GstEvent *segment_event;
7023       segment_event = gst_event_new_segment (&demux->segment);
7024       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7025         gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7026       gst_qtdemux_push_event (demux, segment_event);
7027     }
7028 
7029     demux->need_segment = FALSE;
7030 
7031     /* clear to send tags on all streams */
7032     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7033       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7034       gst_qtdemux_push_tags (demux, stream);
7035       if (CUR_STREAM (stream)->sparse) {
7036         GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7037         gst_pad_push_event (stream->pad,
7038             gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7039       }
7040     }
7041   }
7042 }
7043 
7044 /* Used for push mode only. */
7045 static void
gst_qtdemux_send_gap_for_segment(GstQTDemux * demux,QtDemuxStream * stream,gint segment_index,GstClockTime pos)7046 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7047     QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7048 {
7049   GstClockTime ts, dur;
7050 
7051   ts = pos;
7052   dur =
7053       stream->segments[segment_index].duration - (pos -
7054       stream->segments[segment_index].time);
7055   stream->time_position += dur;
7056 
7057   /* Only gaps with a duration of at least one second are propagated.
7058    * Same workaround as in pull mode.
7059    * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7060   if (dur >= GST_SECOND) {
7061     GstEvent *gap;
7062     gap = gst_event_new_gap (ts, dur);
7063 
7064     GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7065         "segment: %" GST_PTR_FORMAT, gap);
7066     gst_pad_push_event (stream->pad, gap);
7067   }
7068 }
7069 
7070 static GstFlowReturn
gst_qtdemux_chain(GstPad * sinkpad,GstObject * parent,GstBuffer * inbuf)7071 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7072 {
7073   GstQTDemux *demux;
7074 
7075   demux = GST_QTDEMUX (parent);
7076 
7077   GST_DEBUG_OBJECT (demux,
7078       "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7079       " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7080       G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7081       GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7082       gst_buffer_get_size (inbuf), demux->offset);
7083 
7084   if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7085     gboolean is_gap_input = FALSE;
7086     gint i;
7087 
7088     GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7089 
7090     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7091       QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7092     }
7093 
7094     /* Check if we can land back on our feet in the case where upstream is
7095      * handling the seeking/pushing of samples with gaps in between (like
7096      * in the case of trick-mode DASH for example) */
7097     if (demux->upstream_format_is_time
7098         && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7099       for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7100         guint32 res;
7101         QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7102         GST_LOG_OBJECT (demux,
7103             "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7104             " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7105         res =
7106             gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7107             stream, GST_BUFFER_OFFSET (inbuf));
7108         if (res != -1) {
7109           QtDemuxSample *sample = &stream->samples[res];
7110           GST_LOG_OBJECT (demux,
7111               "Checking if sample %d from track-id %u is valid (offset:%"
7112               G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7113               stream->track_id, sample->offset, sample->size);
7114           if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7115             GST_LOG_OBJECT (demux,
7116                 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7117                 res);
7118             is_gap_input = TRUE;
7119             /* We can go back to standard playback mode */
7120             demux->state = QTDEMUX_STATE_MOVIE;
7121             /* Remember which sample this stream is at */
7122             stream->sample_index = res;
7123             /* Finally update all push-based values to the expected values */
7124             demux->neededbytes = stream->samples[res].size;
7125             demux->offset = GST_BUFFER_OFFSET (inbuf);
7126             demux->mdatleft =
7127                 demux->mdatsize - demux->offset + demux->mdatoffset;
7128             demux->todrop = 0;
7129           }
7130         }
7131       }
7132       if (!is_gap_input) {
7133         GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7134         /* Reset state if it's a real discont */
7135         demux->neededbytes = 16;
7136         demux->state = QTDEMUX_STATE_INITIAL;
7137         demux->offset = GST_BUFFER_OFFSET (inbuf);
7138         gst_adapter_clear (demux->adapter);
7139       }
7140     }
7141     /* Reverse fragmented playback, need to flush all we have before
7142      * consuming a new fragment.
7143      * The samples array have the timestamps calculated by accumulating the
7144      * durations but this won't work for reverse playback of fragments as
7145      * the timestamps of a subsequent fragment should be smaller than the
7146      * previously received one. */
7147     if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7148       gst_qtdemux_process_adapter (demux, TRUE);
7149       g_ptr_array_foreach (demux->active_streams,
7150           (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7151     }
7152   }
7153 
7154   gst_adapter_push (demux->adapter, inbuf);
7155 
7156   GST_DEBUG_OBJECT (demux,
7157       "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7158       demux->neededbytes, gst_adapter_available (demux->adapter));
7159 
7160   return gst_qtdemux_process_adapter (demux, FALSE);
7161 }
7162 
7163 static GstFlowReturn
gst_qtdemux_process_adapter(GstQTDemux * demux,gboolean force)7164 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7165 {
7166   GstFlowReturn ret = GST_FLOW_OK;
7167 
7168   /* we never really mean to buffer that much */
7169   if (demux->neededbytes == -1) {
7170     goto eos;
7171   }
7172 
7173   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7174       (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7175 
7176 #ifndef GST_DISABLE_GST_DEBUG
7177     {
7178       guint64 discont_offset, distance_from_discont;
7179 
7180       discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7181       distance_from_discont =
7182           gst_adapter_distance_from_discont (demux->adapter);
7183 
7184       GST_DEBUG_OBJECT (demux,
7185           "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7186           " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7187           " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7188           demux->offset, discont_offset, distance_from_discont);
7189     }
7190 #endif
7191 
7192     switch (demux->state) {
7193       case QTDEMUX_STATE_INITIAL:{
7194         const guint8 *data;
7195         guint32 fourcc;
7196         guint64 size;
7197 
7198         gst_qtdemux_check_seekability (demux);
7199 
7200         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7201 
7202         /* get fourcc/length, set neededbytes */
7203         extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7204             &size, &fourcc);
7205         gst_adapter_unmap (demux->adapter);
7206         data = NULL;
7207         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7208             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7209         if (size == 0) {
7210           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7211               (_("This file is invalid and cannot be played.")),
7212               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7213                   GST_FOURCC_ARGS (fourcc)));
7214           ret = GST_FLOW_ERROR;
7215           break;
7216         }
7217         if (fourcc == FOURCC_mdat) {
7218           gint next_entry = next_entry_size (demux);
7219           if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7220                   || !demux->fragmented)) {
7221             /* we have the headers, start playback */
7222             demux->state = QTDEMUX_STATE_MOVIE;
7223             demux->neededbytes = next_entry;
7224             demux->mdatleft = size;
7225             demux->mdatsize = demux->mdatleft;
7226           } else {
7227             /* no headers yet, try to get them */
7228             guint bs;
7229             gboolean res;
7230             guint64 old, target;
7231 
7232           buffer_data:
7233             old = demux->offset;
7234             target = old + size;
7235 
7236             /* try to jump over the atom with a seek */
7237             /* only bother if it seems worth doing so,
7238              * and avoids possible upstream/server problems */
7239             if (demux->upstream_seekable &&
7240                 demux->upstream_size > 4 * (1 << 20)) {
7241               res = qtdemux_seek_offset (demux, target);
7242             } else {
7243               GST_DEBUG_OBJECT (demux, "skipping seek");
7244               res = FALSE;
7245             }
7246 
7247             if (res) {
7248               GST_DEBUG_OBJECT (demux, "seek success");
7249               /* remember the offset fo the first mdat so we can seek back to it
7250                * after we have the headers */
7251               if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7252                 demux->first_mdat = old;
7253                 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7254                     demux->first_mdat);
7255               }
7256               /* seek worked, continue reading */
7257               demux->offset = target;
7258               demux->neededbytes = 16;
7259               demux->state = QTDEMUX_STATE_INITIAL;
7260             } else {
7261               /* seek failed, need to buffer */
7262               demux->offset = old;
7263               GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7264               /* there may be multiple mdat (or alike) buffers */
7265               /* sanity check */
7266               if (demux->mdatbuffer)
7267                 bs = gst_buffer_get_size (demux->mdatbuffer);
7268               else
7269                 bs = 0;
7270               if (size + bs > 10 * (1 << 20))
7271                 goto no_moov;
7272               demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7273               demux->neededbytes = size;
7274               if (!demux->mdatbuffer)
7275                 demux->mdatoffset = demux->offset;
7276             }
7277           }
7278         } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7279           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7280               (_("This file is invalid and cannot be played.")),
7281               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7282                   GST_FOURCC_ARGS (fourcc), size));
7283           ret = GST_FLOW_ERROR;
7284           break;
7285         } else {
7286           /* this means we already started buffering and still no moov header,
7287            * let's continue buffering everything till we get moov */
7288           if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7289                   || fourcc == FOURCC_moof))
7290             goto buffer_data;
7291           demux->neededbytes = size;
7292           demux->state = QTDEMUX_STATE_HEADER;
7293         }
7294         break;
7295       }
7296       case QTDEMUX_STATE_HEADER:{
7297         const guint8 *data;
7298         guint32 fourcc;
7299 
7300         GST_DEBUG_OBJECT (demux, "In header");
7301 
7302         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7303 
7304         /* parse the header */
7305         extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7306             &fourcc);
7307         if (fourcc == FOURCC_moov) {
7308           /* in usual fragmented setup we could try to scan for more
7309            * and end up at the the moov (after mdat) again */
7310           if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7311               (!demux->fragmented
7312                   || demux->last_moov_offset == demux->offset)) {
7313             GST_DEBUG_OBJECT (demux,
7314                 "Skipping moov atom as we have (this) one already");
7315           } else {
7316             GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7317 
7318             if (demux->got_moov && demux->fragmented) {
7319               GST_DEBUG_OBJECT (demux,
7320                   "Got a second moov, clean up data from old one");
7321               if (demux->moov_node_compressed) {
7322                 g_node_destroy (demux->moov_node_compressed);
7323                 if (demux->moov_node)
7324                   g_free (demux->moov_node->data);
7325               }
7326               demux->moov_node_compressed = NULL;
7327               if (demux->moov_node)
7328                 g_node_destroy (demux->moov_node);
7329               demux->moov_node = NULL;
7330             }
7331 
7332             demux->last_moov_offset = demux->offset;
7333 
7334             /* Update streams with new moov */
7335             gst_qtdemux_stream_concat (demux,
7336                 demux->old_streams, demux->active_streams);
7337 
7338             qtdemux_parse_moov (demux, data, demux->neededbytes);
7339             qtdemux_node_dump (demux, demux->moov_node);
7340             qtdemux_parse_tree (demux);
7341             qtdemux_prepare_streams (demux);
7342             QTDEMUX_EXPOSE_LOCK (demux);
7343             qtdemux_expose_streams (demux);
7344             QTDEMUX_EXPOSE_UNLOCK (demux);
7345 
7346             demux->got_moov = TRUE;
7347 
7348             gst_qtdemux_check_send_pending_segment (demux);
7349 
7350             if (demux->moov_node_compressed) {
7351               g_node_destroy (demux->moov_node_compressed);
7352               g_free (demux->moov_node->data);
7353             }
7354             demux->moov_node_compressed = NULL;
7355             g_node_destroy (demux->moov_node);
7356             demux->moov_node = NULL;
7357             GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7358           }
7359         } else if (fourcc == FOURCC_moof) {
7360           if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7361             guint64 dist = 0;
7362             GstClockTime prev_pts;
7363             guint64 prev_offset;
7364             guint64 adapter_discont_offset, adapter_discont_dist;
7365 
7366             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7367 
7368             /*
7369              * The timestamp of the moof buffer is relevant as some scenarios
7370              * won't have the initial timestamp in the atoms. Whenever a new
7371              * buffer has started, we get that buffer's PTS and use it as a base
7372              * timestamp for the trun entries.
7373              *
7374              * To keep track of the current buffer timestamp and starting point
7375              * we use gst_adapter_prev_pts that gives us the PTS and the distance
7376              * from the beginning of the buffer, with the distance and demux->offset
7377              * we know if it is still the same buffer or not.
7378              */
7379             prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7380             prev_offset = demux->offset - dist;
7381             if (demux->fragment_start_offset == -1
7382                 || prev_offset > demux->fragment_start_offset) {
7383               demux->fragment_start_offset = prev_offset;
7384               demux->fragment_start = prev_pts;
7385               GST_DEBUG_OBJECT (demux,
7386                   "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7387                   GST_TIME_FORMAT, demux->fragment_start_offset,
7388                   GST_TIME_ARGS (demux->fragment_start));
7389             }
7390 
7391             /* We can't use prev_offset() here because this would require
7392              * upstream to set consistent and correct offsets on all buffers
7393              * since the discont. Nothing ever did that in the past and we
7394              * would break backwards compatibility here then.
7395              * Instead take the offset we had at the last discont and count
7396              * the bytes from there. This works with old code as there would
7397              * be no discont between moov and moof, and also works with
7398              * adaptivedemux which correctly sets offset and will set the
7399              * DISCONT flag accordingly when needed.
7400              *
7401              * We also only do this for upstream TIME segments as otherwise
7402              * there are potential backwards compatibility problems with
7403              * seeking in PUSH mode and upstream providing inconsistent
7404              * timestamps. */
7405             adapter_discont_offset =
7406                 gst_adapter_offset_at_discont (demux->adapter);
7407             adapter_discont_dist =
7408                 gst_adapter_distance_from_discont (demux->adapter);
7409 
7410             GST_DEBUG_OBJECT (demux,
7411                 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7412                 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7413                 demux->offset, adapter_discont_offset, adapter_discont_dist);
7414 
7415             if (demux->upstream_format_is_time) {
7416               demux->moof_offset = adapter_discont_offset;
7417               if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7418                 demux->moof_offset += adapter_discont_dist;
7419               if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7420                 demux->moof_offset = demux->offset;
7421             } else {
7422               demux->moof_offset = demux->offset;
7423             }
7424 
7425             if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7426                     demux->moof_offset, NULL)) {
7427               gst_adapter_unmap (demux->adapter);
7428               ret = GST_FLOW_ERROR;
7429               goto done;
7430             }
7431 
7432             /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7433             if (demux->mss_mode && !demux->exposed) {
7434               QTDEMUX_EXPOSE_LOCK (demux);
7435               qtdemux_expose_streams (demux);
7436               QTDEMUX_EXPOSE_UNLOCK (demux);
7437             }
7438 
7439             gst_qtdemux_check_send_pending_segment (demux);
7440           } else {
7441             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7442           }
7443         } else if (fourcc == FOURCC_ftyp) {
7444           GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7445           qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7446         } else if (fourcc == FOURCC_uuid) {
7447           GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7448           qtdemux_parse_uuid (demux, data, demux->neededbytes);
7449         } else if (fourcc == FOURCC_sidx) {
7450           GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7451           qtdemux_parse_sidx (demux, data, demux->neededbytes);
7452         } else {
7453           switch (fourcc) {
7454             case FOURCC_styp:
7455               /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7456                * FALLTHROUGH */
7457             case FOURCC_skip:
7458             case FOURCC_free:
7459               /* [free] and [skip] are padding atoms */
7460               GST_DEBUG_OBJECT (demux,
7461                   "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7462                   GST_FOURCC_ARGS (fourcc));
7463               break;
7464             default:
7465               GST_WARNING_OBJECT (demux,
7466                   "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7467                   GST_FOURCC_ARGS (fourcc));
7468               /* Let's jump that one and go back to initial state */
7469               break;
7470           }
7471         }
7472         gst_adapter_unmap (demux->adapter);
7473         data = NULL;
7474 
7475         if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7476           gsize remaining_data_size = 0;
7477 
7478           /* the mdat was before the header */
7479           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7480               QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7481           /* restore our adapter/offset view of things with upstream;
7482            * put preceding buffered data ahead of current moov data.
7483            * This should also handle evil mdat, moov, mdat cases and alike */
7484           gst_adapter_flush (demux->adapter, demux->neededbytes);
7485 
7486           /* Store any remaining data after the mdat for later usage */
7487           remaining_data_size = gst_adapter_available (demux->adapter);
7488           if (remaining_data_size > 0) {
7489             g_assert (demux->restoredata_buffer == NULL);
7490             demux->restoredata_buffer =
7491                 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7492             demux->restoredata_offset = demux->offset + demux->neededbytes;
7493             GST_DEBUG_OBJECT (demux,
7494                 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7495                 G_GUINT64_FORMAT, remaining_data_size,
7496                 demux->restoredata_offset);
7497           }
7498 
7499           gst_adapter_push (demux->adapter, demux->mdatbuffer);
7500           demux->mdatbuffer = NULL;
7501           demux->offset = demux->mdatoffset;
7502           demux->neededbytes = next_entry_size (demux);
7503           demux->state = QTDEMUX_STATE_MOVIE;
7504           demux->mdatleft = gst_adapter_available (demux->adapter);
7505           demux->mdatsize = demux->mdatleft;
7506         } else {
7507           GST_DEBUG_OBJECT (demux, "Carrying on normally");
7508           gst_adapter_flush (demux->adapter, demux->neededbytes);
7509 
7510           /* only go back to the mdat if there are samples to play */
7511           if (demux->got_moov && demux->first_mdat != -1
7512               && has_next_entry (demux)) {
7513             gboolean res;
7514 
7515             /* we need to seek back */
7516             res = qtdemux_seek_offset (demux, demux->first_mdat);
7517             if (res) {
7518               demux->offset = demux->first_mdat;
7519             } else {
7520               GST_DEBUG_OBJECT (demux, "Seek back failed");
7521             }
7522           } else {
7523             demux->offset += demux->neededbytes;
7524           }
7525           demux->neededbytes = 16;
7526           demux->state = QTDEMUX_STATE_INITIAL;
7527         }
7528 
7529         break;
7530       }
7531       case QTDEMUX_STATE_BUFFER_MDAT:{
7532         GstBuffer *buf;
7533         guint8 fourcc[4];
7534 
7535         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7536             demux->offset);
7537         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7538         gst_buffer_extract (buf, 0, fourcc, 4);
7539         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7540             GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7541         if (demux->mdatbuffer)
7542           demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7543         else
7544           demux->mdatbuffer = buf;
7545         demux->offset += demux->neededbytes;
7546         demux->neededbytes = 16;
7547         demux->state = QTDEMUX_STATE_INITIAL;
7548         gst_qtdemux_post_progress (demux, 1, 1);
7549 
7550         break;
7551       }
7552       case QTDEMUX_STATE_MOVIE:{
7553         QtDemuxStream *stream = NULL;
7554         QtDemuxSample *sample;
7555         GstClockTime dts, pts, duration;
7556         gboolean keyframe;
7557         gint i;
7558 
7559         GST_DEBUG_OBJECT (demux,
7560             "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7561 
7562         if (demux->fragmented) {
7563           GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7564               demux->mdatleft);
7565           if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7566             /* if needed data starts within this atom,
7567              * then it should not exceed this atom */
7568             if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7569               GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7570                   (_("This file is invalid and cannot be played.")),
7571                   ("sample data crosses atom boundary"));
7572               ret = GST_FLOW_ERROR;
7573               break;
7574             }
7575             demux->mdatleft -= demux->neededbytes;
7576           } else {
7577             GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7578             /* so we are dropping more than left in this atom */
7579             gst_qtdemux_drop_data (demux, demux->mdatleft);
7580             demux->mdatleft = 0;
7581 
7582             /* need to resume atom parsing so we do not miss any other pieces */
7583             demux->state = QTDEMUX_STATE_INITIAL;
7584             demux->neededbytes = 16;
7585 
7586             /* check if there was any stored post mdat data from previous buffers */
7587             if (demux->restoredata_buffer) {
7588               g_assert (gst_adapter_available (demux->adapter) == 0);
7589 
7590               gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7591               demux->restoredata_buffer = NULL;
7592               demux->offset = demux->restoredata_offset;
7593             }
7594 
7595             break;
7596           }
7597         }
7598 
7599         if (demux->todrop) {
7600           if (demux->cenc_aux_info_offset > 0) {
7601             GstByteReader br;
7602             const guint8 *data;
7603 
7604             GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7605             data = gst_adapter_map (demux->adapter, demux->todrop);
7606             gst_byte_reader_init (&br, data + 8, demux->todrop);
7607             if (!qtdemux_parse_cenc_aux_info (demux,
7608                     QTDEMUX_NTH_STREAM (demux, 0), &br,
7609                     demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7610               GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7611               ret = GST_FLOW_ERROR;
7612               gst_adapter_unmap (demux->adapter);
7613               g_free (demux->cenc_aux_info_sizes);
7614               demux->cenc_aux_info_sizes = NULL;
7615               goto done;
7616             }
7617             demux->cenc_aux_info_offset = 0;
7618             g_free (demux->cenc_aux_info_sizes);
7619             demux->cenc_aux_info_sizes = NULL;
7620             gst_adapter_unmap (demux->adapter);
7621           }
7622           gst_qtdemux_drop_data (demux, demux->todrop);
7623         }
7624 
7625         /* first buffer? */
7626         /* initial newsegment sent here after having added pads,
7627          * possible others in sink_event */
7628         gst_qtdemux_check_send_pending_segment (demux);
7629 
7630         /* Figure out which stream this packet belongs to */
7631         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7632           stream = QTDEMUX_NTH_STREAM (demux, i);
7633           if (stream->sample_index >= stream->n_samples) {
7634             /* reset to be checked below G_UNLIKELY (stream == NULL) */
7635             stream = NULL;
7636             continue;
7637           }
7638           GST_LOG_OBJECT (demux,
7639               "Checking track-id %u (sample_index:%d / offset:%"
7640               G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7641               stream->sample_index,
7642               stream->samples[stream->sample_index].offset,
7643               stream->samples[stream->sample_index].size);
7644 
7645           if (stream->samples[stream->sample_index].offset == demux->offset)
7646             break;
7647         }
7648 
7649         if (G_UNLIKELY (stream == NULL))
7650           goto unknown_stream;
7651 
7652         gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7653 
7654         if (stream->new_caps) {
7655           gst_qtdemux_configure_stream (demux, stream);
7656         }
7657 
7658         /* Put data in a buffer, set timestamps, caps, ... */
7659         sample = &stream->samples[stream->sample_index];
7660 
7661         if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7662           GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7663               GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7664 
7665           dts = QTSAMPLE_DTS (stream, sample);
7666           pts = QTSAMPLE_PTS (stream, sample);
7667           duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7668           keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7669 
7670           /* check for segment end */
7671           if (G_UNLIKELY (demux->segment.stop != -1
7672                   && demux->segment.stop <= pts && stream->on_keyframe)
7673               && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7674             GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7675             stream->time_position = GST_CLOCK_TIME_NONE;        /* this means EOS */
7676 
7677             /* skip this data, stream is EOS */
7678             gst_adapter_flush (demux->adapter, demux->neededbytes);
7679             demux->offset += demux->neededbytes;
7680 
7681             /* check if all streams are eos */
7682             ret = GST_FLOW_EOS;
7683             for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7684               if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7685                 ret = GST_FLOW_OK;
7686                 break;
7687               }
7688             }
7689           } else {
7690             GstBuffer *outbuf;
7691 
7692             outbuf =
7693                 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7694 
7695             /* FIXME: should either be an assert or a plain check */
7696             g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7697 
7698             ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7699                 dts, pts, duration, keyframe, dts, demux->offset);
7700           }
7701 
7702           /* combine flows */
7703           GST_OBJECT_LOCK (demux);
7704           ret = gst_qtdemux_combine_flows (demux, stream, ret);
7705           GST_OBJECT_UNLOCK (demux);
7706         } else {
7707           /* skip this data, stream is EOS */
7708           gst_adapter_flush (demux->adapter, demux->neededbytes);
7709         }
7710 
7711         stream->sample_index++;
7712         stream->offset_in_sample = 0;
7713 
7714         /* update current offset and figure out size of next buffer */
7715         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7716             demux->offset, demux->neededbytes);
7717         demux->offset += demux->neededbytes;
7718         GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7719             demux->offset);
7720 
7721 
7722         if (ret == GST_FLOW_EOS) {
7723           GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7724           demux->neededbytes = -1;
7725           goto eos;
7726         }
7727 
7728         if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7729           if (demux->fragmented) {
7730             GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7731             /* there may be more to follow, only finish this atom */
7732             demux->todrop = demux->mdatleft;
7733             demux->neededbytes = demux->todrop;
7734             break;
7735           }
7736           goto eos;
7737         }
7738         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7739           goto non_ok_unlinked_flow;
7740         }
7741         break;
7742       }
7743       default:
7744         goto invalid_state;
7745     }
7746   }
7747 
7748   /* when buffering movie data, at least show user something is happening */
7749   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7750       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7751     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7752         demux->neededbytes);
7753   }
7754 done:
7755 
7756   return ret;
7757 
7758   /* ERRORS */
7759 non_ok_unlinked_flow:
7760   {
7761     GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7762         gst_flow_get_name (ret));
7763     return ret;
7764   }
7765 unknown_stream:
7766   {
7767     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7768     ret = GST_FLOW_ERROR;
7769     goto done;
7770   }
7771 eos:
7772   {
7773     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7774     ret = GST_FLOW_EOS;
7775     goto done;
7776   }
7777 invalid_state:
7778   {
7779     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7780         (NULL), ("qtdemuxer invalid state %d", demux->state));
7781     ret = GST_FLOW_ERROR;
7782     goto done;
7783   }
7784 no_moov:
7785   {
7786     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7787         (NULL), ("no 'moov' atom within the first 10 MB"));
7788     ret = GST_FLOW_ERROR;
7789     goto done;
7790   }
7791 }
7792 
7793 static gboolean
qtdemux_sink_activate(GstPad * sinkpad,GstObject * parent)7794 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7795 {
7796   GstQuery *query;
7797   gboolean pull_mode;
7798 
7799   query = gst_query_new_scheduling ();
7800 
7801   if (!gst_pad_peer_query (sinkpad, query)) {
7802     gst_query_unref (query);
7803     goto activate_push;
7804   }
7805 
7806   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7807       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7808   gst_query_unref (query);
7809 
7810   if (!pull_mode)
7811     goto activate_push;
7812 
7813   GST_DEBUG_OBJECT (sinkpad, "activating pull");
7814   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7815 
7816 activate_push:
7817   {
7818     GST_DEBUG_OBJECT (sinkpad, "activating push");
7819     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7820   }
7821 }
7822 
7823 static gboolean
qtdemux_sink_activate_mode(GstPad * sinkpad,GstObject * parent,GstPadMode mode,gboolean active)7824 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7825     GstPadMode mode, gboolean active)
7826 {
7827   gboolean res;
7828   GstQTDemux *demux = GST_QTDEMUX (parent);
7829 
7830   switch (mode) {
7831     case GST_PAD_MODE_PUSH:
7832       demux->pullbased = FALSE;
7833       res = TRUE;
7834       break;
7835     case GST_PAD_MODE_PULL:
7836       if (active) {
7837         demux->pullbased = TRUE;
7838         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7839             sinkpad, NULL);
7840       } else {
7841         res = gst_pad_stop_task (sinkpad);
7842       }
7843       break;
7844     default:
7845       res = FALSE;
7846       break;
7847   }
7848   return res;
7849 }
7850 
7851 #ifdef HAVE_ZLIB
7852 static void *
qtdemux_inflate(void * z_buffer,guint z_length,guint * length)7853 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7854 {
7855   guint8 *buffer;
7856   z_stream z;
7857   int ret;
7858 
7859   memset (&z, 0, sizeof (z));
7860   z.zalloc = NULL;
7861   z.zfree = NULL;
7862   z.opaque = NULL;
7863 
7864   if ((ret = inflateInit (&z)) != Z_OK) {
7865     GST_ERROR ("inflateInit() returned %d", ret);
7866     return NULL;
7867   }
7868 
7869   z.next_in = z_buffer;
7870   z.avail_in = z_length;
7871 
7872   buffer = (guint8 *) g_malloc (*length);
7873   z.avail_out = *length;
7874   z.next_out = (Bytef *) buffer;
7875   do {
7876     ret = inflate (&z, Z_NO_FLUSH);
7877     if (ret == Z_STREAM_END) {
7878       break;
7879     } else if (ret != Z_OK) {
7880       GST_WARNING ("inflate() returned %d", ret);
7881       break;
7882     }
7883 
7884     if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) {
7885       GST_WARNING ("too big decompressed data");
7886       ret = Z_MEM_ERROR;
7887       break;
7888     }
7889 
7890     *length += 4096;
7891     buffer = (guint8 *) g_realloc (buffer, *length);
7892     z.next_out = (Bytef *) (buffer + z.total_out);
7893     z.avail_out += *length - z.total_out;
7894   } while (z.avail_in > 0);
7895 
7896   if (ret != Z_STREAM_END) {
7897     g_free (buffer);
7898     buffer = NULL;
7899     *length = 0;
7900   } else {
7901     *length = z.total_out;
7902   }
7903 
7904   inflateEnd (&z);
7905 
7906   return buffer;
7907 }
7908 #endif /* HAVE_ZLIB */
7909 
7910 static gboolean
qtdemux_parse_moov(GstQTDemux * qtdemux,const guint8 * buffer,guint length)7911 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7912 {
7913   GNode *cmov;
7914 
7915   qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7916 
7917   /* counts as header data */
7918   qtdemux->header_size += length;
7919 
7920   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7921   qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7922 
7923   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7924   if (cmov) {
7925     guint32 method;
7926     GNode *dcom;
7927     GNode *cmvd;
7928     guint32 dcom_len;
7929 
7930     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7931     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7932     if (dcom == NULL || cmvd == NULL)
7933       goto invalid_compression;
7934 
7935     dcom_len = QT_UINT32 (dcom->data);
7936     if (dcom_len < 12)
7937       goto invalid_compression;
7938 
7939     method = QT_FOURCC ((guint8 *) dcom->data + 8);
7940     switch (method) {
7941 #ifdef HAVE_ZLIB
7942       case FOURCC_zlib:{
7943         guint uncompressed_length;
7944         guint compressed_length;
7945         guint8 *buf;
7946         guint32 cmvd_len;
7947 
7948         cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7949         if (cmvd_len < 12)
7950           goto invalid_compression;
7951 
7952         uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7953         compressed_length = cmvd_len - 12;
7954         GST_LOG ("length = %u", uncompressed_length);
7955 
7956         buf =
7957             (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7958             compressed_length, &uncompressed_length);
7959 
7960         if (buf) {
7961           qtdemux->moov_node_compressed = qtdemux->moov_node;
7962           qtdemux->moov_node = g_node_new (buf);
7963 
7964           qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7965               uncompressed_length);
7966         }
7967         break;
7968       }
7969 #endif /* HAVE_ZLIB */
7970       default:
7971         GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7972             "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7973         break;
7974     }
7975   }
7976   return TRUE;
7977 
7978   /* ERRORS */
7979 invalid_compression:
7980   {
7981     GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7982     return FALSE;
7983   }
7984 }
7985 
7986 static gboolean
qtdemux_parse_container(GstQTDemux * qtdemux,GNode * node,const guint8 * buf,const guint8 * end)7987 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7988     const guint8 * end)
7989 {
7990   while (G_UNLIKELY (buf < end)) {
7991     GNode *child;
7992     guint32 len;
7993 
7994     if (G_UNLIKELY (buf + 4 > end)) {
7995       GST_LOG_OBJECT (qtdemux, "buffer overrun");
7996       break;
7997     }
7998     len = QT_UINT32 (buf);
7999     if (G_UNLIKELY (len == 0)) {
8000       GST_LOG_OBJECT (qtdemux, "empty container");
8001       break;
8002     }
8003     if (G_UNLIKELY (len < 8)) {
8004       GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8005       break;
8006     }
8007     if (G_UNLIKELY (len > (end - buf))) {
8008       GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8009           (gint) (end - buf));
8010       break;
8011     }
8012 
8013     child = g_node_new ((guint8 *) buf);
8014     g_node_append (node, child);
8015     GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8016     qtdemux_parse_node (qtdemux, child, buf, len);
8017 
8018     buf += len;
8019   }
8020   return TRUE;
8021 }
8022 
8023 static gboolean
qtdemux_parse_theora_extension(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * xdxt)8024 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8025     GNode * xdxt)
8026 {
8027   int len = QT_UINT32 (xdxt->data);
8028   guint8 *buf = xdxt->data;
8029   guint8 *end = buf + len;
8030   GstBuffer *buffer;
8031 
8032   /* skip size and type */
8033   buf += 8;
8034   end -= 8;
8035 
8036   while (buf < end) {
8037     gint size;
8038     guint32 type;
8039 
8040     size = QT_UINT32 (buf);
8041     type = QT_FOURCC (buf + 4);
8042 
8043     GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8044 
8045     if (buf + size > end || size <= 0)
8046       break;
8047 
8048     buf += 8;
8049     size -= 8;
8050 
8051     GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8052         GST_FOURCC_ARGS (type));
8053 
8054     switch (type) {
8055       case FOURCC_tCtH:
8056         buffer = gst_buffer_new_and_alloc (size);
8057         gst_buffer_fill (buffer, 0, buf, size);
8058         stream->buffers = g_slist_append (stream->buffers, buffer);
8059         GST_LOG_OBJECT (qtdemux, "parsing theora header");
8060         break;
8061       case FOURCC_tCt_:
8062         buffer = gst_buffer_new_and_alloc (size);
8063         gst_buffer_fill (buffer, 0, buf, size);
8064         stream->buffers = g_slist_append (stream->buffers, buffer);
8065         GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8066         break;
8067       case FOURCC_tCtC:
8068         buffer = gst_buffer_new_and_alloc (size);
8069         gst_buffer_fill (buffer, 0, buf, size);
8070         stream->buffers = g_slist_append (stream->buffers, buffer);
8071         GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8072         break;
8073       default:
8074         GST_WARNING_OBJECT (qtdemux,
8075             "unknown theora cookie %" GST_FOURCC_FORMAT,
8076             GST_FOURCC_ARGS (type));
8077         break;
8078     }
8079     buf += size;
8080   }
8081   return TRUE;
8082 }
8083 
8084 static gboolean
qtdemux_parse_node(GstQTDemux * qtdemux,GNode * node,const guint8 * buffer,guint length)8085 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8086     guint length)
8087 {
8088   guint32 fourcc = 0;
8089   guint32 node_length = 0;
8090   const QtNodeType *type;
8091   const guint8 *end;
8092 
8093   GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8094 
8095   if (G_UNLIKELY (length < 8))
8096     goto not_enough_data;
8097 
8098   node_length = QT_UINT32 (buffer);
8099   fourcc = QT_FOURCC (buffer + 4);
8100 
8101   /* ignore empty nodes */
8102   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8103     return TRUE;
8104 
8105   type = qtdemux_type_get (fourcc);
8106 
8107   end = buffer + length;
8108 
8109   GST_LOG_OBJECT (qtdemux,
8110       "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8111       GST_FOURCC_ARGS (fourcc), node_length, type->name);
8112 
8113   if (node_length > length)
8114     goto broken_atom_size;
8115 
8116   if (type->flags & QT_FLAG_CONTAINER) {
8117     qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8118   } else {
8119     switch (fourcc) {
8120       case FOURCC_stsd:
8121       {
8122         if (node_length < 20) {
8123           GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8124           break;
8125         }
8126         GST_DEBUG_OBJECT (qtdemux,
8127             "parsing stsd (sample table, sample description) atom");
8128         /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8129         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8130         break;
8131       }
8132       case FOURCC_mp4a:
8133       case FOURCC_alac:
8134       case FOURCC_fLaC:
8135       case FOURCC_aavd:
8136       {
8137         guint32 version;
8138         guint32 offset;
8139         guint min_size;
8140 
8141         /* also read alac (or whatever) in stead of mp4a in the following,
8142          * since a similar layout is used in other cases as well */
8143         if (fourcc == FOURCC_mp4a)
8144           min_size = 20;
8145         else if (fourcc == FOURCC_fLaC)
8146           min_size = 86;
8147         else
8148           min_size = 40;
8149 
8150         /* There are two things we might encounter here: a true mp4a atom, and
8151            an mp4a entry in an stsd atom. The latter is what we're interested
8152            in, and it looks like an atom, but isn't really one. The true mp4a
8153            atom is short, so we detect it based on length here. */
8154         if (length < min_size) {
8155           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8156               GST_FOURCC_ARGS (fourcc));
8157           break;
8158         }
8159 
8160         /* 'version' here is the sound sample description version. Types 0 and
8161            1 are documented in the QTFF reference, but type 2 is not: it's
8162            described in Apple header files instead (struct SoundDescriptionV2
8163            in Movies.h) */
8164         version = QT_UINT16 (buffer + 16);
8165 
8166         GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8167             GST_FOURCC_ARGS (fourcc), version);
8168 
8169         /* parse any esds descriptors */
8170         switch (version) {
8171           case 0:
8172             offset = 0x24;
8173             break;
8174           case 1:
8175             offset = 0x34;
8176             break;
8177           case 2:
8178             offset = 0x48;
8179             break;
8180           default:
8181             GST_WARNING_OBJECT (qtdemux,
8182                 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8183                 GST_FOURCC_ARGS (fourcc), version);
8184             offset = 0;
8185             break;
8186         }
8187         if (offset)
8188           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8189         break;
8190       }
8191       case FOURCC_mp4v:
8192       case FOURCC_MP4V:
8193       case FOURCC_fmp4:
8194       case FOURCC_FMP4:
8195       case FOURCC_apcs:
8196       case FOURCC_apch:
8197       case FOURCC_apcn:
8198       case FOURCC_apco:
8199       case FOURCC_ap4h:
8200       case FOURCC_xvid:
8201       case FOURCC_XVID:
8202       case FOURCC_H264:
8203       case FOURCC_avc1:
8204       case FOURCC_avc3:
8205       case FOURCC_H265:
8206       case FOURCC_hvc1:
8207       case FOURCC_hev1:
8208       case FOURCC_dvh1:
8209       case FOURCC_dvhe:
8210       case FOURCC_mjp2:
8211       case FOURCC_encv:
8212       {
8213         guint32 version;
8214         guint32 str_len;
8215 
8216         /* codec_data is contained inside these atoms, which all have
8217          * the same format. */
8218         /* video sample description size is 86 bytes without extension.
8219          * node_length have to be bigger than 86 bytes because video sample
8220          * description can include extensions such as esds, fiel, glbl, etc. */
8221         if (node_length < 86) {
8222           GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8223               " sample description length too short (%u < 86)",
8224               GST_FOURCC_ARGS (fourcc), node_length);
8225           break;
8226         }
8227 
8228         GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8229             GST_FOURCC_ARGS (fourcc));
8230 
8231         /* version (2 bytes) : this is set to 0, unless a compressor has changed
8232          *              its data format.
8233          * revision level (2 bytes) : must be set to 0. */
8234         version = QT_UINT32 (buffer + 16);
8235         GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8236 
8237         /* compressor name : PASCAL string and informative purposes
8238          * first byte : the number of bytes to be displayed.
8239          *              it has to be less than 32 because it is reserved
8240          *              space of 32 bytes total including itself. */
8241         str_len = QT_UINT8 (buffer + 50);
8242         if (str_len < 32)
8243           GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8244               (char *) buffer + 51);
8245         else
8246           GST_WARNING_OBJECT (qtdemux,
8247               "compressorname length too big (%u > 31)", str_len);
8248 
8249         GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8250             end - buffer);
8251         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8252         break;
8253       }
8254       case FOURCC_meta:
8255       {
8256         GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8257 
8258         /* You are reading this correctly. QTFF specifies that the
8259          * metadata atom is a short atom, whereas ISO BMFF specifies
8260          * it's a full atom. But since so many people are doing things
8261          * differently, we actually peek into the atom to see which
8262          * variant it is */
8263         if (length < 16) {
8264           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8265               GST_FOURCC_ARGS (fourcc));
8266           break;
8267         }
8268         if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8269           /* Variant 1: What QTFF specifies. 'meta' is a short header which
8270            * starts with a 'hdlr' atom */
8271           qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8272         } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8273           /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8274            * with version/flags both set to zero */
8275           qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8276         } else
8277           GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8278         break;
8279       }
8280       case FOURCC_mp4s:
8281       {
8282         GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8283         /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8284         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8285         break;
8286       }
8287       case FOURCC_XiTh:
8288       {
8289         guint32 version;
8290         guint32 offset;
8291 
8292         if (length < 16) {
8293           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8294               GST_FOURCC_ARGS (fourcc));
8295           break;
8296         }
8297 
8298         version = QT_UINT32 (buffer + 12);
8299         GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8300 
8301         switch (version) {
8302           case 0x00000001:
8303             offset = 0x62;
8304             break;
8305           default:
8306             GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8307             offset = 0;
8308             break;
8309         }
8310         if (offset) {
8311           if (length < offset) {
8312             GST_WARNING_OBJECT (qtdemux,
8313                 "skipping too small %" GST_FOURCC_FORMAT " box",
8314                 GST_FOURCC_ARGS (fourcc));
8315             break;
8316           }
8317           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8318         }
8319         break;
8320       }
8321       case FOURCC_in24:
8322       {
8323         qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8324         break;
8325       }
8326       case FOURCC_uuid:
8327       {
8328         qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8329         break;
8330       }
8331       case FOURCC_enca:
8332       {
8333         qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8334         break;
8335       }
8336       default:
8337         if (!strcmp (type->name, "unknown"))
8338           GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8339         break;
8340     }
8341   }
8342   GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8343       GST_FOURCC_ARGS (fourcc));
8344   return TRUE;
8345 
8346 /* ERRORS */
8347 not_enough_data:
8348   {
8349     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8350         (_("This file is corrupt and cannot be played.")),
8351         ("Not enough data for an atom header, got only %u bytes", length));
8352     return FALSE;
8353   }
8354 broken_atom_size:
8355   {
8356     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8357         (_("This file is corrupt and cannot be played.")),
8358         ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8359             "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8360             length));
8361     return FALSE;
8362   }
8363 }
8364 
8365 static void
qtdemux_do_allocation(QtDemuxStream * stream,GstQTDemux * qtdemux)8366 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8367 {
8368 /* FIXME: This can only reliably work if demuxers have a
8369  * separate streaming thread per srcpad. This should be
8370  * done in a demuxer base class, which integrates parts
8371  * of multiqueue
8372  *
8373  * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8374  */
8375 #if 0
8376   GstQuery *query;
8377 
8378   query = gst_query_new_allocation (stream->caps, FALSE);
8379 
8380   if (!gst_pad_peer_query (stream->pad, query)) {
8381     /* not a problem, just debug a little */
8382     GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8383   }
8384 
8385   if (stream->allocator)
8386     gst_object_unref (stream->allocator);
8387 
8388   if (gst_query_get_n_allocation_params (query) > 0) {
8389     /* try the allocator */
8390     gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8391         &stream->params);
8392     stream->use_allocator = TRUE;
8393   } else {
8394     stream->allocator = NULL;
8395     gst_allocation_params_init (&stream->params);
8396     stream->use_allocator = FALSE;
8397   }
8398   gst_query_unref (query);
8399 #endif
8400 }
8401 
8402 static gboolean
pad_query(const GValue * item,GValue * value,gpointer user_data)8403 pad_query (const GValue * item, GValue * value, gpointer user_data)
8404 {
8405   GstPad *pad = g_value_get_object (item);
8406   GstQuery *query = user_data;
8407   gboolean res;
8408 
8409   res = gst_pad_peer_query (pad, query);
8410 
8411   if (res) {
8412     g_value_set_boolean (value, TRUE);
8413     return FALSE;
8414   }
8415 
8416   GST_INFO_OBJECT (pad, "pad peer query failed");
8417   return TRUE;
8418 }
8419 
8420 static gboolean
gst_qtdemux_run_query(GstElement * element,GstQuery * query,GstPadDirection direction)8421 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8422     GstPadDirection direction)
8423 {
8424   GstIterator *it;
8425   GstIteratorFoldFunction func = pad_query;
8426   GValue res = { 0, };
8427 
8428   g_value_init (&res, G_TYPE_BOOLEAN);
8429   g_value_set_boolean (&res, FALSE);
8430 
8431   /* Ask neighbor */
8432   if (direction == GST_PAD_SRC)
8433     it = gst_element_iterate_src_pads (element);
8434   else
8435     it = gst_element_iterate_sink_pads (element);
8436 
8437   while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8438     gst_iterator_resync (it);
8439 
8440   gst_iterator_free (it);
8441 
8442   return g_value_get_boolean (&res);
8443 }
8444 
8445 static void
gst_qtdemux_request_protection_context(GstQTDemux * qtdemux,QtDemuxStream * stream)8446 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8447     QtDemuxStream * stream)
8448 {
8449   GstQuery *query;
8450   GstContext *ctxt;
8451   GstElement *element = GST_ELEMENT (qtdemux);
8452   GstStructure *st;
8453   gchar **filtered_sys_ids;
8454   GValue event_list = G_VALUE_INIT;
8455   GList *walk;
8456 
8457   /* 1. Check if we already have the context. */
8458   if (qtdemux->preferred_protection_system_id != NULL) {
8459     GST_LOG_OBJECT (element,
8460         "already have the protection context, no need to request it again");
8461     return;
8462   }
8463 
8464   g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8465   filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8466       (const gchar **) qtdemux->protection_system_ids->pdata);
8467 
8468   g_ptr_array_remove_index (qtdemux->protection_system_ids,
8469       qtdemux->protection_system_ids->len - 1);
8470   GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8471       "decryptors for %u of them, running context request",
8472       qtdemux->protection_system_ids->len,
8473       filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8474 
8475 
8476   if (stream->protection_scheme_event_queue.length) {
8477     GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8478         stream->protection_scheme_event_queue.length);
8479     walk = stream->protection_scheme_event_queue.tail;
8480   } else {
8481     GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8482         qtdemux->protection_event_queue.length);
8483     walk = qtdemux->protection_event_queue.tail;
8484   }
8485 
8486   g_value_init (&event_list, GST_TYPE_LIST);
8487   for (; walk; walk = g_list_previous (walk)) {
8488     GValue *event_value = g_new0 (GValue, 1);
8489     g_value_init (event_value, GST_TYPE_EVENT);
8490     g_value_set_boxed (event_value, walk->data);
8491     gst_value_list_append_and_take_value (&event_list, event_value);
8492   }
8493 
8494   /*  2a) Query downstream with GST_QUERY_CONTEXT for the context and
8495    *      check if downstream already has a context of the specific type
8496    *  2b) Query upstream as above.
8497    */
8498   query = gst_query_new_context ("drm-preferred-decryption-system-id");
8499   st = gst_query_writable_structure (query);
8500   gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8501       "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8502       NULL);
8503   gst_structure_set_value (st, "stream-encryption-events", &event_list);
8504   if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8505     gst_query_parse_context (query, &ctxt);
8506     GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8507     gst_element_set_context (element, ctxt);
8508   } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8509     gst_query_parse_context (query, &ctxt);
8510     GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8511     gst_element_set_context (element, ctxt);
8512   } else {
8513     /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8514      *    the required context type and afterwards check if a
8515      *    usable context was set now as in 1). The message could
8516      *    be handled by the parent bins of the element and the
8517      *    application.
8518      */
8519     GstMessage *msg;
8520 
8521     GST_INFO_OBJECT (element, "posting need context message");
8522     msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8523         "drm-preferred-decryption-system-id");
8524     st = (GstStructure *) gst_message_get_structure (msg);
8525     gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8526         "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8527         NULL);
8528 
8529     gst_structure_set_value (st, "stream-encryption-events", &event_list);
8530     gst_element_post_message (element, msg);
8531   }
8532 
8533   g_strfreev (filtered_sys_ids);
8534   g_value_unset (&event_list);
8535   gst_query_unref (query);
8536 }
8537 
8538 static gboolean
gst_qtdemux_configure_protected_caps(GstQTDemux * qtdemux,QtDemuxStream * stream)8539 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8540     QtDemuxStream * stream)
8541 {
8542   GstStructure *s;
8543   const gchar *selected_system = NULL;
8544 
8545   g_return_val_if_fail (qtdemux != NULL, FALSE);
8546   g_return_val_if_fail (stream != NULL, FALSE);
8547   g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8548       FALSE);
8549 
8550   if (stream->protection_scheme_type == FOURCC_aavd) {
8551     s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8552     if (!gst_structure_has_name (s, "application/x-aavd")) {
8553       gst_structure_set (s,
8554           "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8555           NULL);
8556       gst_structure_set_name (s, "application/x-aavd");
8557     }
8558     return TRUE;
8559   }
8560 
8561   if (stream->protection_scheme_type != FOURCC_cenc
8562       && stream->protection_scheme_type != FOURCC_cbcs) {
8563     GST_ERROR_OBJECT (qtdemux,
8564         "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8565         GST_FOURCC_ARGS (stream->protection_scheme_type));
8566     return FALSE;
8567   }
8568 
8569   s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8570   if (!gst_structure_has_name (s, "application/x-cenc")) {
8571     gst_structure_set (s,
8572         "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8573     gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8574         (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8575         NULL);
8576     gst_structure_set_name (s, "application/x-cenc");
8577   }
8578 
8579   if (qtdemux->protection_system_ids == NULL) {
8580     GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8581         "cenc protection system information has been found, not setting a "
8582         "protection system UUID");
8583     return TRUE;
8584   }
8585 
8586   gst_qtdemux_request_protection_context (qtdemux, stream);
8587   if (qtdemux->preferred_protection_system_id != NULL) {
8588     const gchar *preferred_system_array[] =
8589         { qtdemux->preferred_protection_system_id, NULL };
8590 
8591     selected_system = gst_protection_select_system (preferred_system_array);
8592 
8593     if (selected_system) {
8594       GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8595           qtdemux->preferred_protection_system_id);
8596     } else {
8597       GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8598           "because there is no available decryptor",
8599           qtdemux->preferred_protection_system_id);
8600     }
8601   }
8602 
8603   if (!selected_system) {
8604     g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8605     selected_system = gst_protection_select_system ((const gchar **)
8606         qtdemux->protection_system_ids->pdata);
8607     g_ptr_array_remove_index (qtdemux->protection_system_ids,
8608         qtdemux->protection_system_ids->len - 1);
8609   }
8610 
8611   if (!selected_system) {
8612     GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8613         "suitable decryptor element has been found");
8614     return FALSE;
8615   }
8616 
8617   GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8618       selected_system);
8619 
8620   gst_structure_set (s,
8621       GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8622       NULL);
8623 
8624   return TRUE;
8625 }
8626 
8627 static gboolean
gst_qtdemux_guess_framerate(GstQTDemux * qtdemux,QtDemuxStream * stream)8628 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8629 {
8630   /* fps is calculated base on the duration of the average framerate since
8631    * qt does not have a fixed framerate. */
8632   gboolean fps_available = TRUE;
8633   guint32 first_duration = 0;
8634 
8635   if (stream->n_samples > 0)
8636     first_duration = stream->samples[0].duration;
8637 
8638   if ((stream->n_samples == 1 && first_duration == 0)
8639       || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8640     /* still frame */
8641     CUR_STREAM (stream)->fps_n = 0;
8642     CUR_STREAM (stream)->fps_d = 1;
8643   } else {
8644     if (stream->duration == 0 || stream->n_samples < 2) {
8645       CUR_STREAM (stream)->fps_n = stream->timescale;
8646       CUR_STREAM (stream)->fps_d = 1;
8647       fps_available = FALSE;
8648     } else {
8649       GstClockTime avg_duration;
8650       guint64 duration;
8651       guint32 n_samples;
8652 
8653       /* duration and n_samples can be updated for fragmented format
8654        * so, framerate of fragmented format is calculated using data in a moof */
8655       if (qtdemux->fragmented && stream->n_samples_moof > 0
8656           && stream->duration_moof > 0) {
8657         n_samples = stream->n_samples_moof;
8658         duration = stream->duration_moof;
8659       } else {
8660         n_samples = stream->n_samples;
8661         duration = stream->duration;
8662       }
8663 
8664       /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8665       /* stream->duration is guint64, timescale, n_samples are guint32 */
8666       avg_duration =
8667           gst_util_uint64_scale_round (duration -
8668           first_duration, GST_SECOND,
8669           (guint64) (stream->timescale) * (n_samples - 1));
8670 
8671       GST_LOG_OBJECT (qtdemux,
8672           "Calculating avg sample duration based on stream (or moof) duration %"
8673           G_GUINT64_FORMAT
8674           " minus first sample %u, leaving %d samples gives %"
8675           GST_TIME_FORMAT, duration, first_duration,
8676           n_samples - 1, GST_TIME_ARGS (avg_duration));
8677 #ifdef OHOS_OPT_COMPAT
8678       /**
8679        * ohos.opt.compat.0038
8680        * Solve the problem of correct frame rate not passing forward
8681        */
8682       if (avg_duration == 0) {
8683         fps_available = FALSE;
8684         GST_ERROR_OBJECT (qtdemux, "Calculating avg duration abnormal");
8685       } else {
8686         gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8687         GST_DEBUG_OBJECT (qtdemux, "Guess framerate fps_n %d fps_d %d",
8688             CUR_STREAM (stream)->fps_n, CUR_STREAM (stream)->fps_d);
8689       }
8690 #else
8691       fps_available =
8692           gst_video_guess_framerate (avg_duration,
8693           &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8694 #endif
8695       GST_DEBUG_OBJECT (qtdemux,
8696           "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8697           stream->timescale, CUR_STREAM (stream)->fps_n,
8698           CUR_STREAM (stream)->fps_d);
8699     }
8700   }
8701 
8702   return fps_available;
8703 }
8704 
8705 static gboolean
gst_qtdemux_configure_stream(GstQTDemux * qtdemux,QtDemuxStream * stream)8706 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8707 {
8708   if (stream->subtype == FOURCC_vide) {
8709     gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8710 
8711     if (CUR_STREAM (stream)->caps) {
8712       CUR_STREAM (stream)->caps =
8713           gst_caps_make_writable (CUR_STREAM (stream)->caps);
8714 
8715       if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8716         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8717             "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8718             "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8719 
8720       /* set framerate if calculated framerate is reliable */
8721       if (fps_available) {
8722         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8723             "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8724             CUR_STREAM (stream)->fps_d, NULL);
8725       }
8726 
8727       /* calculate pixel-aspect-ratio using display width and height */
8728       GST_DEBUG_OBJECT (qtdemux,
8729           "video size %dx%d, target display size %dx%d",
8730           CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8731           stream->display_width, stream->display_height);
8732       /* qt file might have pasp atom */
8733       if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8734         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8735             CUR_STREAM (stream)->par_h);
8736         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8737             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8738             CUR_STREAM (stream)->par_h, NULL);
8739       } else if (stream->display_width > 0 && stream->display_height > 0
8740           && CUR_STREAM (stream)->width > 0
8741           && CUR_STREAM (stream)->height > 0) {
8742         gint n, d;
8743 
8744         /* calculate the pixel aspect ratio using the display and pixel w/h */
8745         n = stream->display_width * CUR_STREAM (stream)->height;
8746         d = stream->display_height * CUR_STREAM (stream)->width;
8747         if (n == d)
8748           n = d = 1;
8749         GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8750         CUR_STREAM (stream)->par_w = n;
8751         CUR_STREAM (stream)->par_h = d;
8752         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8753             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8754             CUR_STREAM (stream)->par_h, NULL);
8755       }
8756 
8757       if (CUR_STREAM (stream)->interlace_mode > 0) {
8758         if (CUR_STREAM (stream)->interlace_mode == 1) {
8759           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8760               G_TYPE_STRING, "progressive", NULL);
8761         } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8762           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8763               G_TYPE_STRING, "interleaved", NULL);
8764           if (CUR_STREAM (stream)->field_order == 9) {
8765             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8766                 G_TYPE_STRING, "top-field-first", NULL);
8767           } else if (CUR_STREAM (stream)->field_order == 14) {
8768             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8769                 G_TYPE_STRING, "bottom-field-first", NULL);
8770           }
8771         }
8772       }
8773 
8774       /* Create incomplete colorimetry here if needed */
8775       if (CUR_STREAM (stream)->colorimetry.range ||
8776           CUR_STREAM (stream)->colorimetry.matrix ||
8777           CUR_STREAM (stream)->colorimetry.transfer
8778           || CUR_STREAM (stream)->colorimetry.primaries) {
8779         gchar *colorimetry =
8780             gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8781         gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8782             G_TYPE_STRING, colorimetry, NULL);
8783         g_free (colorimetry);
8784       }
8785 
8786       if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8787         guint par_w = 1, par_h = 1;
8788 
8789         if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8790           par_w = CUR_STREAM (stream)->par_w;
8791           par_h = CUR_STREAM (stream)->par_h;
8792         }
8793 
8794         if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8795                 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8796                 par_h)) {
8797           stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8798         }
8799 
8800         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8801             "multiview-mode", G_TYPE_STRING,
8802             gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8803             "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8804             stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8805       }
8806     }
8807   }
8808 
8809   else if (stream->subtype == FOURCC_soun) {
8810     if (CUR_STREAM (stream)->caps) {
8811       CUR_STREAM (stream)->caps =
8812           gst_caps_make_writable (CUR_STREAM (stream)->caps);
8813       if (CUR_STREAM (stream)->rate > 0)
8814         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8815             "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8816       if (CUR_STREAM (stream)->n_channels > 0)
8817         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8818             "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8819       if (CUR_STREAM (stream)->n_channels > 2) {
8820         /* FIXME: Need to parse the 'chan' atom to get channel layouts
8821          * correctly; this is just the minimum we can do - assume
8822          * we don't actually have any channel positions. */
8823         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8824             "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8825       }
8826     }
8827   }
8828 
8829   else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8830     const GstStructure *s;
8831     QtDemuxStream *fps_stream = NULL;
8832     gboolean fps_available = FALSE;
8833 
8834     /* CEA608 closed caption tracks are a bit special in that each sample
8835      * can contain CCs for multiple frames, and CCs can be omitted and have to
8836      * be inferred from the duration of the sample then.
8837      *
8838      * As such we take the framerate from the (first) video track here for
8839      * CEA608 as there must be one CC byte pair for every video frame
8840      * according to the spec.
8841      *
8842      * For CEA708 all is fine and there is one sample per frame.
8843      */
8844 
8845     s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8846     if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8847       gint i;
8848 
8849       for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8850         QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8851 
8852         if (tmp->subtype == FOURCC_vide) {
8853           fps_stream = tmp;
8854           break;
8855         }
8856       }
8857 
8858       if (fps_stream) {
8859         fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8860         CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8861         CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8862       }
8863     } else {
8864       fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8865       fps_stream = stream;
8866     }
8867 
8868     CUR_STREAM (stream)->caps =
8869         gst_caps_make_writable (CUR_STREAM (stream)->caps);
8870 
8871     /* set framerate if calculated framerate is reliable */
8872     if (fps_available) {
8873       gst_caps_set_simple (CUR_STREAM (stream)->caps,
8874           "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8875           CUR_STREAM (stream)->fps_d, NULL);
8876     }
8877   }
8878 
8879   if (stream->pad) {
8880     GstCaps *prev_caps = NULL;
8881 
8882     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8883     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8884     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8885     gst_pad_set_active (stream->pad, TRUE);
8886 
8887     gst_pad_use_fixed_caps (stream->pad);
8888 
8889     if (stream->protected) {
8890       if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8891         GST_ERROR_OBJECT (qtdemux,
8892             "Failed to configure protected stream caps.");
8893         return FALSE;
8894       }
8895     }
8896 
8897     GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8898         CUR_STREAM (stream)->caps);
8899     if (stream->new_stream) {
8900       GstEvent *event;
8901       GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8902 
8903       event =
8904           gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8905           0);
8906       if (event) {
8907         gst_event_parse_stream_flags (event, &stream_flags);
8908         if (gst_event_parse_group_id (event, &qtdemux->group_id))
8909           qtdemux->have_group_id = TRUE;
8910         else
8911           qtdemux->have_group_id = FALSE;
8912         gst_event_unref (event);
8913       } else if (!qtdemux->have_group_id) {
8914         qtdemux->have_group_id = TRUE;
8915         qtdemux->group_id = gst_util_group_id_next ();
8916       }
8917 
8918       stream->new_stream = FALSE;
8919       event = gst_event_new_stream_start (stream->stream_id);
8920       if (qtdemux->have_group_id)
8921         gst_event_set_group_id (event, qtdemux->group_id);
8922       if (stream->disabled)
8923         stream_flags |= GST_STREAM_FLAG_UNSELECT;
8924       if (CUR_STREAM (stream)->sparse) {
8925         stream_flags |= GST_STREAM_FLAG_SPARSE;
8926       } else {
8927         stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8928       }
8929       gst_event_set_stream_flags (event, stream_flags);
8930       gst_pad_push_event (stream->pad, event);
8931     }
8932 
8933     prev_caps = gst_pad_get_current_caps (stream->pad);
8934 
8935     if (CUR_STREAM (stream)->caps) {
8936       if (!prev_caps
8937           || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8938         GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8939             CUR_STREAM (stream)->caps);
8940         gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8941       } else {
8942         GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8943       }
8944     } else {
8945       GST_WARNING_OBJECT (qtdemux, "stream without caps");
8946     }
8947 
8948     if (prev_caps)
8949       gst_caps_unref (prev_caps);
8950     stream->new_caps = FALSE;
8951   }
8952   return TRUE;
8953 }
8954 
8955 static void
gst_qtdemux_stream_check_and_change_stsd_index(GstQTDemux * demux,QtDemuxStream * stream)8956 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8957     QtDemuxStream * stream)
8958 {
8959   if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8960     return;
8961 
8962   GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8963       stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8964   if (G_UNLIKELY (stream->stsd_sample_description_id >=
8965           stream->stsd_entries_length)) {
8966     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8967         (_("This file is invalid and cannot be played.")),
8968         ("New sample description id is out of bounds (%d >= %d)",
8969             stream->stsd_sample_description_id, stream->stsd_entries_length));
8970   } else {
8971     stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8972     stream->new_caps = TRUE;
8973   }
8974 }
8975 
8976 static gboolean
gst_qtdemux_add_stream(GstQTDemux * qtdemux,QtDemuxStream * stream,GstTagList * list)8977 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8978     QtDemuxStream * stream, GstTagList * list)
8979 {
8980   gboolean ret = TRUE;
8981 
8982   if (stream->subtype == FOURCC_vide) {
8983     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8984 
8985     stream->pad =
8986         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8987     g_free (name);
8988 
8989     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8990       gst_object_unref (stream->pad);
8991       stream->pad = NULL;
8992       ret = FALSE;
8993       goto done;
8994     }
8995 
8996     qtdemux->n_video_streams++;
8997   } else if (stream->subtype == FOURCC_soun) {
8998     gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8999 
9000     stream->pad =
9001         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9002     g_free (name);
9003     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9004       gst_object_unref (stream->pad);
9005       stream->pad = NULL;
9006       ret = FALSE;
9007       goto done;
9008     }
9009     qtdemux->n_audio_streams++;
9010   } else if (stream->subtype == FOURCC_strm) {
9011     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9012   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9013       || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9014       || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
9015     gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9016 
9017     stream->pad =
9018         gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9019     g_free (name);
9020     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9021       gst_object_unref (stream->pad);
9022       stream->pad = NULL;
9023       ret = FALSE;
9024       goto done;
9025     }
9026     qtdemux->n_sub_streams++;
9027   } else if (CUR_STREAM (stream)->caps) {
9028     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9029 
9030     stream->pad =
9031         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9032     g_free (name);
9033     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9034       gst_object_unref (stream->pad);
9035       stream->pad = NULL;
9036       ret = FALSE;
9037       goto done;
9038     }
9039     qtdemux->n_video_streams++;
9040   } else {
9041     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9042     goto done;
9043   }
9044 
9045   if (stream->pad) {
9046     GList *l;
9047 
9048     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9049         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9050     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9051     GST_OBJECT_LOCK (qtdemux);
9052     gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9053     GST_OBJECT_UNLOCK (qtdemux);
9054 
9055     if (stream->stream_tags)
9056       gst_tag_list_unref (stream->stream_tags);
9057     stream->stream_tags = list;
9058     list = NULL;
9059     /* global tags go on each pad anyway */
9060     stream->send_global_tags = TRUE;
9061     /* send upstream GST_EVENT_PROTECTION events that were received before
9062        this source pad was created */
9063     for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9064       gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9065   }
9066 done:
9067   if (list)
9068     gst_tag_list_unref (list);
9069   return ret;
9070 }
9071 
9072 /* find next atom with @fourcc starting at @offset */
9073 static GstFlowReturn
qtdemux_find_atom(GstQTDemux * qtdemux,guint64 * offset,guint64 * length,guint32 fourcc)9074 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9075     guint64 * length, guint32 fourcc)
9076 {
9077   GstFlowReturn ret;
9078   guint32 lfourcc;
9079   GstBuffer *buf;
9080 
9081   GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9082       G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9083 
9084   while (TRUE) {
9085     GstMapInfo map;
9086 
9087     buf = NULL;
9088     ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9089     if (G_UNLIKELY (ret != GST_FLOW_OK))
9090       goto locate_failed;
9091     if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9092       /* likely EOF */
9093       ret = GST_FLOW_EOS;
9094       gst_buffer_unref (buf);
9095       goto locate_failed;
9096     }
9097     gst_buffer_map (buf, &map, GST_MAP_READ);
9098     extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9099     gst_buffer_unmap (buf, &map);
9100     gst_buffer_unref (buf);
9101 
9102     if (G_UNLIKELY (*length == 0)) {
9103       GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9104       ret = GST_FLOW_ERROR;
9105       goto locate_failed;
9106     }
9107 
9108     if (lfourcc == fourcc) {
9109       GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9110           G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9111       break;
9112     } else {
9113       GST_LOG_OBJECT (qtdemux,
9114           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9115           GST_FOURCC_ARGS (lfourcc), *offset);
9116       if (*offset == G_MAXUINT64)
9117         goto locate_failed;
9118       *offset += *length;
9119     }
9120   }
9121 
9122   return GST_FLOW_OK;
9123 
9124 locate_failed:
9125   {
9126     /* might simply have had last one */
9127     GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9128     return ret;
9129   }
9130 }
9131 
9132 /* should only do something in pull mode */
9133 /* call with OBJECT lock */
9134 static GstFlowReturn
qtdemux_add_fragmented_samples(GstQTDemux * qtdemux)9135 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9136 {
9137   guint64 length, offset;
9138   GstBuffer *buf = NULL;
9139   GstFlowReturn ret = GST_FLOW_OK;
9140   GstFlowReturn res = GST_FLOW_OK;
9141   GstMapInfo map;
9142 
9143   offset = qtdemux->moof_offset;
9144   GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9145 
9146   if (!offset) {
9147     GST_DEBUG_OBJECT (qtdemux, "no next moof");
9148     return GST_FLOW_EOS;
9149   }
9150 
9151   /* best not do pull etc with lock held */
9152   GST_OBJECT_UNLOCK (qtdemux);
9153 
9154   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9155   if (ret != GST_FLOW_OK)
9156     goto flow_failed;
9157 
9158   ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9159   if (G_UNLIKELY (ret != GST_FLOW_OK))
9160     goto flow_failed;
9161   gst_buffer_map (buf, &map, GST_MAP_READ);
9162   if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9163     gst_buffer_unmap (buf, &map);
9164     gst_buffer_unref (buf);
9165     buf = NULL;
9166     goto parse_failed;
9167   }
9168 
9169   gst_buffer_unmap (buf, &map);
9170   gst_buffer_unref (buf);
9171   buf = NULL;
9172 
9173   offset += length;
9174   /* look for next moof */
9175   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9176   if (G_UNLIKELY (ret != GST_FLOW_OK))
9177     goto flow_failed;
9178 
9179 exit:
9180   GST_OBJECT_LOCK (qtdemux);
9181 
9182   qtdemux->moof_offset = offset;
9183 
9184   return res;
9185 
9186 parse_failed:
9187   {
9188     GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9189     offset = 0;
9190     res = GST_FLOW_ERROR;
9191     goto exit;
9192   }
9193 flow_failed:
9194   {
9195     /* maybe upstream temporarily flushing */
9196     if (ret != GST_FLOW_FLUSHING) {
9197       GST_DEBUG_OBJECT (qtdemux, "no next moof");
9198       offset = 0;
9199     } else {
9200       GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9201       /* resume at current position next time */
9202     }
9203     res = ret;
9204     goto exit;
9205   }
9206 }
9207 
9208 static void
qtdemux_merge_sample_table(GstQTDemux * qtdemux,QtDemuxStream * stream)9209 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9210 {
9211   guint i;
9212   guint32 num_chunks;
9213   gint32 stts_duration;
9214   GstByteWriter stsc, stts, stsz;
9215 
9216   /* Each sample has a different size, which we don't support for merging */
9217   if (stream->sample_size == 0) {
9218     GST_DEBUG_OBJECT (qtdemux,
9219         "Not all samples have the same size, not merging");
9220     return;
9221   }
9222 
9223   /* The stream has a ctts table, we don't support that */
9224   if (stream->ctts_present) {
9225     GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9226     return;
9227   }
9228 
9229   /* If there's a sync sample table also ignore this stream */
9230   if (stream->stps_present || stream->stss_present) {
9231     GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9232     return;
9233   }
9234 
9235   /* If chunks are considered samples already ignore this stream */
9236   if (stream->chunks_are_samples) {
9237     GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9238     return;
9239   }
9240 
9241   /* Require that all samples have the same duration */
9242   if (stream->n_sample_times > 1) {
9243     GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9244     return;
9245   }
9246 
9247   /* Parse the stts to get the sample duration and number of samples */
9248   gst_byte_reader_skip_unchecked (&stream->stts, 4);
9249   stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9250 
9251   /* Parse the number of chunks from the stco manually because the
9252    * reader is already behind that */
9253   num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9254 
9255   GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9256       num_chunks);
9257 
9258   /* Now parse stsc, convert chunks into single samples and generate a
9259    * new stsc, stts and stsz from this information */
9260   gst_byte_writer_init (&stsc);
9261   gst_byte_writer_init (&stts);
9262   gst_byte_writer_init (&stsz);
9263 
9264   /* Note: we skip fourccs, size, version, flags and other fields of the new
9265    * atoms as the byte readers with them are already behind that position
9266    * anyway and only update the values of those inside the stream directly.
9267    */
9268   stream->n_sample_times = 0;
9269   stream->n_samples = 0;
9270   for (i = 0; i < stream->n_samples_per_chunk; i++) {
9271     guint j;
9272     guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9273 
9274     first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9275     samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9276     sample_description_id =
9277         gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9278 
9279     if (i == stream->n_samples_per_chunk - 1) {
9280       /* +1 because first_chunk is 1-based */
9281       last_chunk = num_chunks + 1;
9282     } else {
9283       last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9284     }
9285 
9286     GST_DEBUG_OBJECT (qtdemux,
9287         "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9288         first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9289 
9290     gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9291     /* One sample in this chunk */
9292     gst_byte_writer_put_uint32_be (&stsc, 1);
9293     gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9294 
9295     /* For each chunk write a stts and stsz entry now */
9296     gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9297     gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9298     for (j = first_chunk; j < last_chunk; j++) {
9299       gst_byte_writer_put_uint32_be (&stsz,
9300           stream->sample_size * samples_per_chunk);
9301     }
9302 
9303     stream->n_sample_times += 1;
9304     stream->n_samples += last_chunk - first_chunk;
9305   }
9306 
9307   g_assert_cmpint (stream->n_samples, ==, num_chunks);
9308 
9309   GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9310       stream->n_samples, stream->n_sample_times);
9311 
9312   /* We don't have a fixed sample size anymore */
9313   stream->sample_size = 0;
9314 
9315   /* Free old data for the atoms */
9316   g_free ((gpointer) stream->stsz.data);
9317   stream->stsz.data = NULL;
9318   g_free ((gpointer) stream->stsc.data);
9319   stream->stsc.data = NULL;
9320   g_free ((gpointer) stream->stts.data);
9321   stream->stts.data = NULL;
9322 
9323   /* Store new data and replace byte readers */
9324   stream->stsz.size = gst_byte_writer_get_size (&stsz);
9325   stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9326   gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9327   stream->stts.size = gst_byte_writer_get_size (&stts);
9328   stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9329   gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9330   stream->stsc.size = gst_byte_writer_get_size (&stsc);
9331   stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9332   gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9333 }
9334 
9335 /* initialise bytereaders for stbl sub-atoms */
9336 static gboolean
qtdemux_stbl_init(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * stbl)9337 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9338 {
9339   stream->stbl_index = -1;      /* no samples have yet been parsed */
9340   stream->sample_index = -1;
9341 
9342   /* time-to-sample atom */
9343   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9344     goto corrupt_file;
9345 
9346   /* copy atom data into a new buffer for later use */
9347   stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9348 
9349   /* skip version + flags */
9350   if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9351       !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9352     goto corrupt_file;
9353   GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9354 
9355   /* make sure there's enough data */
9356   if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9357     stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9358     GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9359         stream->n_sample_times);
9360     if (!stream->n_sample_times)
9361       goto corrupt_file;
9362   }
9363 
9364   /* sync sample atom */
9365   stream->stps_present = FALSE;
9366   if ((stream->stss_present =
9367           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9368               &stream->stss) ? TRUE : FALSE) == TRUE) {
9369     /* copy atom data into a new buffer for later use */
9370     stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9371 
9372     /* skip version + flags */
9373     if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9374         !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9375       goto corrupt_file;
9376 
9377     if (stream->n_sample_syncs) {
9378       /* make sure there's enough data */
9379       if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9380         goto corrupt_file;
9381     }
9382 
9383     /* partial sync sample atom */
9384     if ((stream->stps_present =
9385             ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9386                 &stream->stps) ? TRUE : FALSE) == TRUE) {
9387       /* copy atom data into a new buffer for later use */
9388       stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9389 
9390       /* skip version + flags */
9391       if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9392           !gst_byte_reader_get_uint32_be (&stream->stps,
9393               &stream->n_sample_partial_syncs))
9394         goto corrupt_file;
9395 
9396       /* if there are no entries, the stss table contains the real
9397        * sync samples */
9398       if (stream->n_sample_partial_syncs) {
9399         /* make sure there's enough data */
9400         if (!qt_atom_parser_has_chunks (&stream->stps,
9401                 stream->n_sample_partial_syncs, 4))
9402           goto corrupt_file;
9403       }
9404     }
9405   }
9406 
9407   /* sample size */
9408   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9409     goto no_samples;
9410 
9411   /* copy atom data into a new buffer for later use */
9412   stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9413 
9414   /* skip version + flags */
9415   if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9416       !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9417     goto corrupt_file;
9418 
9419   if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9420     goto corrupt_file;
9421 
9422   if (!stream->n_samples)
9423     goto no_samples;
9424 
9425   /* sample-to-chunk atom */
9426   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9427     goto corrupt_file;
9428 
9429   /* copy atom data into a new buffer for later use */
9430   stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9431 
9432   /* skip version + flags */
9433   if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9434       !gst_byte_reader_get_uint32_be (&stream->stsc,
9435           &stream->n_samples_per_chunk))
9436     goto corrupt_file;
9437 
9438   GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9439       stream->n_samples_per_chunk);
9440 
9441   /* make sure there's enough data */
9442   if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9443           12))
9444     goto corrupt_file;
9445 
9446 
9447   /* chunk offset */
9448   if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9449     stream->co_size = sizeof (guint32);
9450   else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9451           &stream->stco))
9452     stream->co_size = sizeof (guint64);
9453   else
9454     goto corrupt_file;
9455 
9456   /* copy atom data into a new buffer for later use */
9457   stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9458 
9459   /* skip version + flags */
9460   if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9461     goto corrupt_file;
9462 
9463   /* chunks_are_samples == TRUE means treat chunks as samples */
9464   stream->chunks_are_samples = stream->sample_size
9465       && !CUR_STREAM (stream)->sampled;
9466   if (stream->chunks_are_samples) {
9467     /* treat chunks as samples */
9468     if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9469       goto corrupt_file;
9470   } else {
9471     /* skip number of entries */
9472     if (!gst_byte_reader_skip (&stream->stco, 4))
9473       goto corrupt_file;
9474 
9475     /* make sure there are enough data in the stsz atom */
9476     if (!stream->sample_size) {
9477       /* different sizes for each sample */
9478       if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9479         goto corrupt_file;
9480     }
9481   }
9482 
9483   /* composition time-to-sample */
9484   if ((stream->ctts_present =
9485           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9486               &stream->ctts) ? TRUE : FALSE) == TRUE) {
9487     GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9488     guint8 ctts_version;
9489     gboolean checked_ctts = FALSE;
9490 
9491     /* copy atom data into a new buffer for later use */
9492     stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9493 
9494     /* version 1 has signed offsets */
9495     if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9496       goto corrupt_file;
9497 
9498     /* flags */
9499     if (!gst_byte_reader_skip (&stream->ctts, 3)
9500         || !gst_byte_reader_get_uint32_be (&stream->ctts,
9501             &stream->n_composition_times))
9502       goto corrupt_file;
9503 
9504     /* make sure there's enough data */
9505     if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9506             4 + 4))
9507       goto corrupt_file;
9508 
9509     /* This is optional, if missing we iterate the ctts */
9510     if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9511       guint8 cslg_version;
9512 
9513       /* cslg version 1 has 64 bit fields */
9514       if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9515         goto corrupt_file;
9516 
9517       /* skip flags */
9518       if (!gst_byte_reader_skip (&cslg, 3))
9519         goto corrupt_file;
9520 
9521       if (cslg_version == 0) {
9522         gint32 composition_to_dts_shift;
9523 
9524         if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9525           goto corrupt_file;
9526 
9527         stream->cslg_shift = MAX (0, composition_to_dts_shift);
9528       } else {
9529         gint64 composition_to_dts_shift;
9530 
9531         if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9532           goto corrupt_file;
9533 
9534         stream->cslg_shift = MAX (0, composition_to_dts_shift);
9535       }
9536     } else {
9537       gint32 cslg_least = 0;
9538       guint num_entries, pos;
9539       gint i;
9540 
9541       pos = gst_byte_reader_get_pos (&stream->ctts);
9542       num_entries = stream->n_composition_times;
9543 
9544       checked_ctts = TRUE;
9545 
9546       stream->cslg_shift = 0;
9547 
9548       for (i = 0; i < num_entries; i++) {
9549         gint32 offset;
9550 
9551         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9552         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9553         /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9554          * slightly inaccurate PTS could be more usable than corrupted one */
9555         if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9556                 && ABS (offset) / 2 > stream->duration)) {
9557           GST_WARNING_OBJECT (qtdemux,
9558               "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9559               " larger than duration %" G_GUINT64_FORMAT, offset,
9560               stream->duration);
9561 
9562           stream->cslg_shift = 0;
9563           stream->ctts_present = FALSE;
9564           goto done;
9565         }
9566 
9567         /* Don't consider "no decode samples" with offset G_MININT32
9568          * for the DTS/PTS shift */
9569         if (offset != G_MININT32 && offset < cslg_least)
9570           cslg_least = offset;
9571       }
9572 
9573       if (cslg_least < 0)
9574         stream->cslg_shift = -cslg_least;
9575       else
9576         stream->cslg_shift = 0;
9577 
9578       /* reset the reader so we can generate sample table */
9579       gst_byte_reader_set_pos (&stream->ctts, pos);
9580     }
9581 
9582     /* Check if ctts values are looking reasonable if that didn't happen above */
9583     if (!checked_ctts) {
9584       guint num_entries, pos;
9585       gint i;
9586 
9587       pos = gst_byte_reader_get_pos (&stream->ctts);
9588       num_entries = stream->n_composition_times;
9589 
9590       for (i = 0; i < num_entries; i++) {
9591         gint32 offset;
9592 
9593         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9594         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9595         /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9596          * slightly inaccurate PTS could be more usable than corrupted one */
9597         if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9598                 && ABS (offset) / 2 > stream->duration)) {
9599           GST_WARNING_OBJECT (qtdemux,
9600               "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9601               " larger than duration %" G_GUINT64_FORMAT, offset,
9602               stream->duration);
9603 
9604           stream->cslg_shift = 0;
9605           stream->ctts_present = FALSE;
9606           goto done;
9607         }
9608       }
9609 
9610       /* reset the reader so we can generate sample table */
9611       gst_byte_reader_set_pos (&stream->ctts, pos);
9612     }
9613   } else {
9614     /* Ensure the cslg_shift value is consistent so we can use it
9615      * unconditionally to produce TS and Segment */
9616     stream->cslg_shift = 0;
9617   }
9618 
9619   GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9620       stream->cslg_shift);
9621 
9622   /* For raw audio streams especially we might want to merge the samples
9623    * to not output one audio sample per buffer. We're doing this here
9624    * before allocating the sample tables so that from this point onwards
9625    * the number of container samples are static */
9626   if (stream->min_buffer_size > 0) {
9627     qtdemux_merge_sample_table (qtdemux, stream);
9628   }
9629 
9630 done:
9631   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9632       stream->n_samples, (guint) sizeof (QtDemuxSample),
9633       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9634 
9635   if (stream->n_samples >=
9636       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9637     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9638         "be larger than %uMB (broken file?)", stream->n_samples,
9639         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9640     return FALSE;
9641   }
9642 
9643   g_assert (stream->samples == NULL);
9644   stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9645   if (!stream->samples) {
9646     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9647         stream->n_samples);
9648     return FALSE;
9649   }
9650 
9651   return TRUE;
9652 
9653 corrupt_file:
9654   {
9655     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9656         (_("This file is corrupt and cannot be played.")), (NULL));
9657     return FALSE;
9658   }
9659 no_samples:
9660   {
9661     gst_qtdemux_stbl_free (stream);
9662     if (!qtdemux->fragmented) {
9663       /* not quite good */
9664       GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9665       return FALSE;
9666     } else {
9667       /* may pick up samples elsewhere */
9668       return TRUE;
9669     }
9670   }
9671 }
9672 
9673 /* collect samples from the next sample to be parsed up to sample @n for @stream
9674  * by reading the info from @stbl
9675  *
9676  * This code can be executed from both the streaming thread and the seeking
9677  * thread so it takes the object lock to protect itself
9678  */
9679 static gboolean
qtdemux_parse_samples(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 n)9680 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9681 {
9682   gint i, j, k;
9683   QtDemuxSample *samples, *first, *cur, *last;
9684   guint32 n_samples_per_chunk;
9685   guint32 n_samples;
9686 
9687   GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9688       GST_FOURCC_FORMAT ", pad %s",
9689       GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9690       stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9691 
9692   n_samples = stream->n_samples;
9693 
9694   if (n >= n_samples)
9695     goto out_of_samples;
9696 
9697   GST_OBJECT_LOCK (qtdemux);
9698   if (n <= stream->stbl_index)
9699     goto already_parsed;
9700 
9701   GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9702 
9703   if (!stream->stsz.data) {
9704     /* so we already parsed and passed all the moov samples;
9705      * onto fragmented ones */
9706     g_assert (qtdemux->fragmented);
9707     goto done;
9708   }
9709 
9710   /* pointer to the sample table */
9711   samples = stream->samples;
9712 
9713   /* starts from -1, moves to the next sample index to parse */
9714   stream->stbl_index++;
9715 
9716   /* keep track of the first and last sample to fill */
9717   first = &samples[stream->stbl_index];
9718   last = &samples[n];
9719 
9720   if (!stream->chunks_are_samples) {
9721     /* set the sample sizes */
9722     if (stream->sample_size == 0) {
9723       /* different sizes for each sample */
9724       for (cur = first; cur <= last; cur++) {
9725         cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9726         GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9727             (guint) (cur - samples), cur->size);
9728       }
9729     } else {
9730       /* samples have the same size */
9731       GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9732       for (cur = first; cur <= last; cur++)
9733         cur->size = stream->sample_size;
9734     }
9735   }
9736 
9737   n_samples_per_chunk = stream->n_samples_per_chunk;
9738   cur = first;
9739 
9740   for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9741     guint32 last_chunk;
9742 
9743     if (stream->stsc_chunk_index >= stream->last_chunk
9744         || stream->stsc_chunk_index < stream->first_chunk) {
9745       stream->first_chunk =
9746           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9747       stream->samples_per_chunk =
9748           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9749       /* starts from 1 */
9750       stream->stsd_sample_description_id =
9751           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9752 
9753       /* chunk numbers are counted from 1 it seems */
9754       if (G_UNLIKELY (stream->first_chunk == 0))
9755         goto corrupt_file;
9756 
9757       --stream->first_chunk;
9758 
9759       /* the last chunk of each entry is calculated by taking the first chunk
9760        * of the next entry; except if there is no next, where we fake it with
9761        * INT_MAX */
9762       if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9763         stream->last_chunk = G_MAXUINT32;
9764       } else {
9765         stream->last_chunk =
9766             gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9767         if (G_UNLIKELY (stream->last_chunk == 0))
9768           goto corrupt_file;
9769 
9770         --stream->last_chunk;
9771       }
9772 
9773       GST_LOG_OBJECT (qtdemux,
9774           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9775           "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9776           stream->samples_per_chunk, stream->stsd_sample_description_id);
9777 
9778       if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9779         goto corrupt_file;
9780 
9781       if (stream->last_chunk != G_MAXUINT32) {
9782         if (!qt_atom_parser_peek_sub (&stream->stco,
9783                 stream->first_chunk * stream->co_size,
9784                 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9785                 &stream->co_chunk))
9786           goto corrupt_file;
9787 
9788       } else {
9789         stream->co_chunk = stream->stco;
9790         if (!gst_byte_reader_skip (&stream->co_chunk,
9791                 stream->first_chunk * stream->co_size))
9792           goto corrupt_file;
9793       }
9794 
9795       stream->stsc_chunk_index = stream->first_chunk;
9796     }
9797 
9798     last_chunk = stream->last_chunk;
9799 
9800     if (stream->chunks_are_samples) {
9801       cur = &samples[stream->stsc_chunk_index];
9802 
9803       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9804         if (j > n) {
9805           /* save state */
9806           stream->stsc_chunk_index = j;
9807           goto done;
9808         }
9809 
9810         cur->offset =
9811             qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9812             stream->co_size);
9813 
9814         GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9815             "%" G_GUINT64_FORMAT, j, cur->offset);
9816 
9817         if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9818             CUR_STREAM (stream)->bytes_per_frame > 0) {
9819           cur->size =
9820               (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9821               CUR_STREAM (stream)->samples_per_frame *
9822               CUR_STREAM (stream)->bytes_per_frame;
9823         } else {
9824           cur->size = stream->samples_per_chunk;
9825         }
9826 
9827         GST_DEBUG_OBJECT (qtdemux,
9828             "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9829             j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9830                     stream->stco_sample_index)), cur->size);
9831 
9832         cur->timestamp = stream->stco_sample_index;
9833         cur->duration = stream->samples_per_chunk;
9834         cur->keyframe = TRUE;
9835         cur++;
9836 
9837         stream->stco_sample_index += stream->samples_per_chunk;
9838       }
9839       stream->stsc_chunk_index = j;
9840     } else {
9841       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9842         guint32 samples_per_chunk;
9843         guint64 chunk_offset;
9844 
9845         if (!stream->stsc_sample_index
9846             && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9847                 &stream->chunk_offset))
9848           goto corrupt_file;
9849 
9850         samples_per_chunk = stream->samples_per_chunk;
9851         chunk_offset = stream->chunk_offset;
9852 
9853         for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9854           GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9855               G_GUINT64_FORMAT " and size %d",
9856               (guint) (cur - samples), chunk_offset, cur->size);
9857 
9858           cur->offset = chunk_offset;
9859           chunk_offset += cur->size;
9860           cur++;
9861 
9862           if (G_UNLIKELY (cur > last)) {
9863             /* save state */
9864             stream->stsc_sample_index = k + 1;
9865             stream->chunk_offset = chunk_offset;
9866             stream->stsc_chunk_index = j;
9867             goto done2;
9868           }
9869         }
9870         stream->stsc_sample_index = 0;
9871       }
9872       stream->stsc_chunk_index = j;
9873     }
9874     stream->stsc_index++;
9875   }
9876 
9877   if (stream->chunks_are_samples)
9878     goto ctts;
9879 done2:
9880   {
9881     guint32 n_sample_times;
9882 
9883     n_sample_times = stream->n_sample_times;
9884     cur = first;
9885 
9886     for (i = stream->stts_index; i < n_sample_times; i++) {
9887       guint32 stts_samples;
9888       gint32 stts_duration;
9889       gint64 stts_time;
9890 
9891       if (stream->stts_sample_index >= stream->stts_samples
9892           || !stream->stts_sample_index) {
9893 
9894         stream->stts_samples =
9895             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9896         stream->stts_duration =
9897             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9898 
9899         GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9900             i, stream->stts_samples, stream->stts_duration);
9901 
9902         stream->stts_sample_index = 0;
9903       }
9904 
9905       stts_samples = stream->stts_samples;
9906       stts_duration = stream->stts_duration;
9907       stts_time = stream->stts_time;
9908 
9909       for (j = stream->stts_sample_index; j < stts_samples; j++) {
9910         GST_DEBUG_OBJECT (qtdemux,
9911             "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9912             (guint) (cur - samples), j,
9913             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9914 
9915         cur->timestamp = stts_time;
9916         cur->duration = stts_duration;
9917 
9918         /* avoid 32-bit wrap-around,
9919          * but still mind possible 'negative' duration */
9920         stts_time += (gint64) stts_duration;
9921         cur++;
9922 
9923         if (G_UNLIKELY (cur > last)) {
9924           /* save values */
9925           stream->stts_time = stts_time;
9926           stream->stts_sample_index = j + 1;
9927           if (stream->stts_sample_index >= stream->stts_samples)
9928             stream->stts_index++;
9929           goto done3;
9930         }
9931       }
9932       stream->stts_sample_index = 0;
9933       stream->stts_time = stts_time;
9934       stream->stts_index++;
9935     }
9936     /* fill up empty timestamps with the last timestamp, this can happen when
9937      * the last samples do not decode and so we don't have timestamps for them.
9938      * We however look at the last timestamp to estimate the track length so we
9939      * need something in here. */
9940     for (; cur < last; cur++) {
9941       GST_DEBUG_OBJECT (qtdemux,
9942           "fill sample %d: timestamp %" GST_TIME_FORMAT,
9943           (guint) (cur - samples),
9944           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9945       cur->timestamp = stream->stts_time;
9946       cur->duration = -1;
9947     }
9948   }
9949 done3:
9950   {
9951     /* sample sync, can be NULL */
9952     if (stream->stss_present == TRUE) {
9953       guint32 n_sample_syncs;
9954 
9955       n_sample_syncs = stream->n_sample_syncs;
9956 
9957       if (!n_sample_syncs) {
9958         GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9959         stream->all_keyframe = TRUE;
9960       } else {
9961         for (i = stream->stss_index; i < n_sample_syncs; i++) {
9962           /* note that the first sample is index 1, not 0 */
9963           guint32 index;
9964 
9965           index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9966 
9967           if (G_LIKELY (index > 0 && index <= n_samples)) {
9968             index -= 1;
9969             samples[index].keyframe = TRUE;
9970             GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9971             /* and exit if we have enough samples */
9972             if (G_UNLIKELY (index >= n)) {
9973               i++;
9974               break;
9975             }
9976           }
9977         }
9978         /* save state */
9979         stream->stss_index = i;
9980       }
9981 
9982       /* stps marks partial sync frames like open GOP I-Frames */
9983       if (stream->stps_present == TRUE) {
9984         guint32 n_sample_partial_syncs;
9985 
9986         n_sample_partial_syncs = stream->n_sample_partial_syncs;
9987 
9988         /* if there are no entries, the stss table contains the real
9989          * sync samples */
9990         if (n_sample_partial_syncs) {
9991           for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9992             /* note that the first sample is index 1, not 0 */
9993             guint32 index;
9994 
9995             index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9996 
9997             if (G_LIKELY (index > 0 && index <= n_samples)) {
9998               index -= 1;
9999               samples[index].keyframe = TRUE;
10000               GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10001               /* and exit if we have enough samples */
10002               if (G_UNLIKELY (index >= n)) {
10003                 i++;
10004                 break;
10005               }
10006             }
10007           }
10008           /* save state */
10009           stream->stps_index = i;
10010         }
10011       }
10012     } else {
10013       /* no stss, all samples are keyframes */
10014       stream->all_keyframe = TRUE;
10015       GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10016     }
10017   }
10018 
10019 ctts:
10020   /* composition time to sample */
10021   if (stream->ctts_present == TRUE) {
10022     guint32 n_composition_times;
10023     guint32 ctts_count;
10024     gint32 ctts_soffset;
10025 
10026     /* Fill in the pts_offsets */
10027     cur = first;
10028     n_composition_times = stream->n_composition_times;
10029 
10030     for (i = stream->ctts_index; i < n_composition_times; i++) {
10031       if (stream->ctts_sample_index >= stream->ctts_count
10032           || !stream->ctts_sample_index) {
10033         stream->ctts_count =
10034             gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10035         stream->ctts_soffset =
10036             gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10037         stream->ctts_sample_index = 0;
10038       }
10039 
10040       ctts_count = stream->ctts_count;
10041       ctts_soffset = stream->ctts_soffset;
10042 
10043       /* FIXME: Set offset to 0 for "no decode samples". This needs
10044        * to be handled in a codec specific manner ideally. */
10045       if (ctts_soffset == G_MININT32)
10046         ctts_soffset = 0;
10047 
10048       for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10049         cur->pts_offset = ctts_soffset;
10050         cur++;
10051 
10052         if (G_UNLIKELY (cur > last)) {
10053           /* save state */
10054           stream->ctts_sample_index = j + 1;
10055           goto done;
10056         }
10057       }
10058       stream->ctts_sample_index = 0;
10059       stream->ctts_index++;
10060     }
10061   }
10062 done:
10063   stream->stbl_index = n;
10064   /* if index has been completely parsed, free data that is no-longer needed */
10065   if (n + 1 == stream->n_samples) {
10066     gst_qtdemux_stbl_free (stream);
10067     GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10068     if (qtdemux->pullbased) {
10069       GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10070       while (n + 1 == stream->n_samples)
10071         if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10072           break;
10073     }
10074   }
10075   GST_OBJECT_UNLOCK (qtdemux);
10076 
10077   return TRUE;
10078 
10079   /* SUCCESS */
10080 already_parsed:
10081   {
10082     GST_LOG_OBJECT (qtdemux,
10083         "Tried to parse up to sample %u but this sample has already been parsed",
10084         n);
10085     /* if fragmented, there may be more */
10086     if (qtdemux->fragmented && n == stream->stbl_index)
10087       goto done;
10088     GST_OBJECT_UNLOCK (qtdemux);
10089     return TRUE;
10090   }
10091   /* ERRORS */
10092 out_of_samples:
10093   {
10094     GST_LOG_OBJECT (qtdemux,
10095         "Tried to parse up to sample %u but there are only %u samples", n + 1,
10096         stream->n_samples);
10097     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10098         (_("This file is corrupt and cannot be played.")), (NULL));
10099     return FALSE;
10100   }
10101 corrupt_file:
10102   {
10103     GST_OBJECT_UNLOCK (qtdemux);
10104     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10105         (_("This file is corrupt and cannot be played.")), (NULL));
10106     return FALSE;
10107   }
10108 }
10109 
10110 /* collect all segment info for @stream.
10111  */
10112 static gboolean
qtdemux_parse_segments(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * trak)10113 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10114     GNode * trak)
10115 {
10116   GNode *edts;
10117   /* accept edts if they contain gaps at start and there is only
10118    * one media segment */
10119   gboolean allow_pushbased_edts = TRUE;
10120   gint media_segments_count = 0;
10121 
10122   /* parse and prepare segment info from the edit list */
10123   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10124   stream->n_segments = 0;
10125   stream->segments = NULL;
10126   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10127     GNode *elst;
10128     gint n_segments;
10129     gint segment_number, entry_size;
10130     guint64 time;
10131     GstClockTime stime;
10132     const guint8 *buffer;
10133     guint8 version;
10134     guint32 size;
10135 
10136     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10137     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10138       goto done;
10139 
10140     buffer = elst->data;
10141 
10142     size = QT_UINT32 (buffer);
10143     /* version, flags, n_segments */
10144     if (size < 16) {
10145       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10146       goto done;
10147     }
10148     version = QT_UINT8 (buffer + 8);
10149     entry_size = (version == 1) ? 20 : 12;
10150 
10151     n_segments = QT_UINT32 (buffer + 12);
10152 
10153     if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10154       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10155       goto done;
10156     }
10157 
10158     /* we might allocate a bit too much, at least allocate 1 segment */
10159     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10160 
10161     /* segments always start from 0 */
10162     time = 0;
10163     stime = 0;
10164     buffer += 16;
10165     for (segment_number = 0; segment_number < n_segments; segment_number++) {
10166       guint64 duration;
10167       guint64 media_time;
10168       gboolean empty_edit = FALSE;
10169       QtDemuxSegment *segment;
10170       guint32 rate_int;
10171       GstClockTime media_start = GST_CLOCK_TIME_NONE;
10172 
10173       if (version == 1) {
10174         media_time = QT_UINT64 (buffer + 8);
10175         duration = QT_UINT64 (buffer);
10176         if (media_time == G_MAXUINT64)
10177           empty_edit = TRUE;
10178       } else {
10179         media_time = QT_UINT32 (buffer + 4);
10180         duration = QT_UINT32 (buffer);
10181         if (media_time == G_MAXUINT32)
10182           empty_edit = TRUE;
10183       }
10184 
10185       if (!empty_edit)
10186         media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10187 
10188       segment = &stream->segments[segment_number];
10189 
10190       /* time and duration expressed in global timescale */
10191       segment->time = stime;
10192       if (duration != 0 || empty_edit) {
10193         /* edge case: empty edits with duration=zero are treated here.
10194          * (files should not have these anyway). */
10195 
10196         /* add non scaled values so we don't cause roundoff errors */
10197         time += duration;
10198         stime = QTTIME_TO_GSTTIME (qtdemux, time);
10199         segment->duration = stime - segment->time;
10200       } else {
10201         /* zero duration does not imply media_start == media_stop
10202          * but, only specify media_start. The edit ends with the track. */
10203         stime = segment->duration = GST_CLOCK_TIME_NONE;
10204         /* Don't allow more edits after this one. */
10205         n_segments = segment_number + 1;
10206       }
10207       segment->stop_time = stime;
10208 
10209       segment->trak_media_start = media_time;
10210       /* media_time expressed in stream timescale */
10211       if (!empty_edit) {
10212         segment->media_start = media_start;
10213         segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10214             ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10215         media_segments_count++;
10216       } else {
10217         segment->media_start = GST_CLOCK_TIME_NONE;
10218         segment->media_stop = GST_CLOCK_TIME_NONE;
10219       }
10220       rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10221 
10222       if (rate_int <= 1) {
10223         /* 0 is not allowed, some programs write 1 instead of the floating point
10224          * value */
10225         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10226             rate_int);
10227         segment->rate = 1;
10228       } else {
10229         segment->rate = rate_int / 65536.0;
10230       }
10231 
10232       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10233           ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10234           " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10235           " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10236           segment_number, GST_TIME_ARGS (segment->time),
10237           GST_TIME_ARGS (segment->duration),
10238           GST_TIME_ARGS (segment->media_start), media_time,
10239           GST_TIME_ARGS (segment->media_stop),
10240           GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10241           stream->timescale);
10242       if (segment->stop_time > qtdemux->segment.stop &&
10243           !qtdemux->upstream_format_is_time) {
10244         GST_WARNING_OBJECT (qtdemux, "Segment %d "
10245             " extends to %" GST_TIME_FORMAT
10246             " past the end of the declared movie duration %" GST_TIME_FORMAT
10247             " movie segment will be extended", segment_number,
10248             GST_TIME_ARGS (segment->stop_time),
10249             GST_TIME_ARGS (qtdemux->segment.stop));
10250         qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10251       }
10252 
10253       buffer += entry_size;
10254     }
10255     GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10256     stream->n_segments = n_segments;
10257     if (media_segments_count != 1)
10258       allow_pushbased_edts = FALSE;
10259   }
10260 done:
10261 
10262   /* push based does not handle segments, so act accordingly here,
10263    * and warn if applicable */
10264   if (!qtdemux->pullbased && !allow_pushbased_edts) {
10265     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10266     /* remove and use default one below, we stream like it anyway */
10267     g_free (stream->segments);
10268     stream->segments = NULL;
10269     stream->n_segments = 0;
10270   }
10271 
10272   /* no segments, create one to play the complete trak */
10273   if (stream->n_segments == 0) {
10274     GstClockTime stream_duration =
10275         QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10276 
10277     if (stream->segments == NULL)
10278       stream->segments = g_new (QtDemuxSegment, 1);
10279 
10280     /* represent unknown our way */
10281     if (stream_duration == 0)
10282       stream_duration = GST_CLOCK_TIME_NONE;
10283 
10284     stream->segments[0].time = 0;
10285     stream->segments[0].stop_time = stream_duration;
10286     stream->segments[0].duration = stream_duration;
10287     stream->segments[0].media_start = 0;
10288     stream->segments[0].media_stop = stream_duration;
10289     stream->segments[0].rate = 1.0;
10290     stream->segments[0].trak_media_start = 0;
10291 
10292     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10293         GST_TIME_ARGS (stream_duration));
10294     stream->n_segments = 1;
10295     stream->dummy_segment = TRUE;
10296   }
10297   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10298 
10299   return TRUE;
10300 }
10301 
10302 /*
10303  * Parses the stsd atom of a svq3 trak looking for
10304  * the SMI and gama atoms.
10305  */
10306 static void
qtdemux_parse_svq3_stsd_data(GstQTDemux * qtdemux,const guint8 * stsd_entry_data,const guint8 ** gamma,GstBuffer ** seqh)10307 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10308     const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10309 {
10310   const guint8 *_gamma = NULL;
10311   GstBuffer *_seqh = NULL;
10312   const guint8 *stsd_data = stsd_entry_data;
10313   guint32 length = QT_UINT32 (stsd_data);
10314   guint16 version;
10315 
10316   if (length < 32) {
10317     GST_WARNING_OBJECT (qtdemux, "stsd too short");
10318     goto end;
10319   }
10320 
10321   stsd_data += 16;
10322   length -= 16;
10323   version = QT_UINT16 (stsd_data);
10324   if (version == 3) {
10325     if (length >= 70) {
10326       length -= 70;
10327       stsd_data += 70;
10328       while (length > 8) {
10329         guint32 fourcc, size;
10330         const guint8 *data;
10331         size = QT_UINT32 (stsd_data);
10332         fourcc = QT_FOURCC (stsd_data + 4);
10333         data = stsd_data + 8;
10334 
10335         if (size == 0) {
10336           GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10337               "svq3 atom parsing");
10338           goto end;
10339         }
10340 
10341         switch (fourcc) {
10342           case FOURCC_gama:{
10343             if (size == 12) {
10344               _gamma = data;
10345             } else {
10346               GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10347                   " for gama atom, expected 12", size);
10348             }
10349             break;
10350           }
10351           case FOURCC_SMI_:{
10352             if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10353               guint32 seqh_size;
10354               if (_seqh != NULL) {
10355                 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10356                     " found, ignoring");
10357               } else {
10358                 seqh_size = QT_UINT32 (data + 4);
10359                 if (seqh_size > 0) {
10360                   _seqh = gst_buffer_new_and_alloc (seqh_size);
10361                   gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10362                 }
10363               }
10364             }
10365             break;
10366           }
10367           default:{
10368             GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10369                 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10370           }
10371         }
10372 
10373         if (size <= length) {
10374           length -= size;
10375           stsd_data += size;
10376         }
10377       }
10378     } else {
10379       GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10380     }
10381   } else {
10382     GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10383         G_GUINT16_FORMAT, version);
10384     goto end;
10385   }
10386 
10387 end:
10388   if (gamma) {
10389     *gamma = _gamma;
10390   }
10391   if (seqh) {
10392     *seqh = _seqh;
10393   } else if (_seqh) {
10394     gst_buffer_unref (_seqh);
10395   }
10396 }
10397 
10398 static gchar *
qtdemux_get_rtsp_uri_from_hndl(GstQTDemux * qtdemux,GNode * minf)10399 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10400 {
10401   GNode *dinf;
10402   GstByteReader dref;
10403   gchar *uri = NULL;
10404 
10405   /*
10406    * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10407    * atom that might contain a 'data' atom with the rtsp uri.
10408    * This case was reported in bug #597497, some info about
10409    * the hndl atom can be found in TN1195
10410    */
10411   dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10412   GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10413 
10414   if (dinf) {
10415     guint32 dref_num_entries = 0;
10416     if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10417         gst_byte_reader_skip (&dref, 4) &&
10418         gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10419       gint i;
10420 
10421       /* search dref entries for hndl atom */
10422       for (i = 0; i < dref_num_entries; i++) {
10423         guint32 size = 0, type;
10424         guint8 string_len = 0;
10425         if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10426             qt_atom_parser_get_fourcc (&dref, &type)) {
10427           if (type == FOURCC_hndl) {
10428             GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10429 
10430             /* skip data reference handle bytes and the
10431              * following pascal string and some extra 4
10432              * bytes I have no idea what are */
10433             if (!gst_byte_reader_skip (&dref, 4) ||
10434                 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10435                 !gst_byte_reader_skip (&dref, string_len + 4)) {
10436               GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10437               break;
10438             }
10439 
10440             /* iterate over the atoms to find the data atom */
10441             while (gst_byte_reader_get_remaining (&dref) >= 8) {
10442               guint32 atom_size;
10443               guint32 atom_type;
10444 
10445               if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10446                   qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10447                 if (atom_type == FOURCC_data) {
10448                   const guint8 *uri_aux = NULL;
10449 
10450                   /* found the data atom that might contain the rtsp uri */
10451                   GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10452                       "hndl atom, interpreting it as an URI");
10453                   if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10454                           &uri_aux)) {
10455                     if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10456                       uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10457                     else
10458                       GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10459                           "didn't contain a rtsp address");
10460                   } else {
10461                     GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10462                         "atom contents");
10463                   }
10464                   break;
10465                 }
10466                 /* skipping to the next entry */
10467                 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10468                   break;
10469               } else {
10470                 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10471                     "atom header");
10472                 break;
10473               }
10474             }
10475             break;
10476           }
10477           /* skip to the next entry */
10478           if (!gst_byte_reader_skip (&dref, size - 8))
10479             break;
10480         } else {
10481           GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10482         }
10483       }
10484       GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10485     }
10486   }
10487   return uri;
10488 }
10489 
10490 #define AMR_NB_ALL_MODES        0x81ff
10491 #define AMR_WB_ALL_MODES        0x83ff
10492 static guint
qtdemux_parse_amr_bitrate(GstBuffer * buf,gboolean wb)10493 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10494 {
10495   /* The 'damr' atom is of the form:
10496    *
10497    * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10498    *    32 b       8 b          16 b           8 b                 8 b
10499    *
10500    * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10501    * represents the highest mode used in the stream (and thus the maximum
10502    * bitrate), with a couple of special cases as seen below.
10503    */
10504 
10505   /* Map of frame type ID -> bitrate */
10506   static const guint nb_bitrates[] = {
10507     4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10508   };
10509   static const guint wb_bitrates[] = {
10510     6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10511   };
10512   GstMapInfo map;
10513   gsize max_mode;
10514   guint16 mode_set;
10515 
10516   gst_buffer_map (buf, &map, GST_MAP_READ);
10517 
10518   if (map.size != 0x11) {
10519     GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10520     goto bad_data;
10521   }
10522 
10523   if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10524     GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10525         GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10526     goto bad_data;
10527   }
10528 
10529   mode_set = QT_UINT16 (map.data + 13);
10530 
10531   if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10532     max_mode = 7 + (wb ? 1 : 0);
10533   else
10534     /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10535     max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10536 
10537   if (max_mode == -1) {
10538     GST_DEBUG ("No mode indication was found (mode set) = %x",
10539         (guint) mode_set);
10540     goto bad_data;
10541   }
10542 
10543   gst_buffer_unmap (buf, &map);
10544   return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10545 
10546 bad_data:
10547   gst_buffer_unmap (buf, &map);
10548   return 0;
10549 }
10550 
10551 static gboolean
qtdemux_parse_transformation_matrix(GstQTDemux * qtdemux,GstByteReader * reader,guint32 * matrix,const gchar * atom)10552 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10553     GstByteReader * reader, guint32 * matrix, const gchar * atom)
10554 {
10555   /*
10556    * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10557    * [0 1 2]
10558    * [3 4 5]
10559    * [6 7 8]
10560    */
10561 
10562   if (gst_byte_reader_get_remaining (reader) < 36)
10563     return FALSE;
10564 
10565   matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10566   matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10567   matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10568   matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10569   matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10570   matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10571   matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10572   matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10573   matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10574 
10575   GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10576   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10577       matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10578       matrix[2] & 0xFF);
10579   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10580       matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10581       matrix[5] & 0xFF);
10582   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10583       matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10584       matrix[8] & 0xFF);
10585 
10586   return TRUE;
10587 }
10588 
10589 static void
qtdemux_inspect_transformation_matrix(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 * matrix,GstTagList ** taglist)10590 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10591     QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10592 {
10593 
10594 /* [a b c]
10595  * [d e f]
10596  * [g h i]
10597  *
10598  * This macro will only compare value abdegh, it expects cfi to have already
10599  * been checked
10600  */
10601 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10602                                    (m)[3] == (d << 16) && (m)[4] == (e << 16))
10603 
10604   /* only handle the cases where the last column has standard values */
10605   if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10606     const gchar *rotation_tag = NULL;
10607 
10608     /* no rotation needed */
10609     if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10610       /* NOP */
10611     } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10612       rotation_tag = "rotate-90";
10613     } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10614       rotation_tag = "rotate-180";
10615     } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10616       rotation_tag = "rotate-270";
10617     } else {
10618       GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10619     }
10620 
10621     GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10622         GST_STR_NULL (rotation_tag));
10623     if (rotation_tag != NULL) {
10624       if (*taglist == NULL)
10625         *taglist = gst_tag_list_new_empty ();
10626       gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10627           GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10628 #ifdef OHOS_EXT_FUNC
10629 // ohos.ext.func.0032
10630       GstMessage *msg_video_rotation = gst_message_new_video_rotation (GST_OBJECT (qtdemux), rotation_tag);
10631       if (msg_video_rotation != NULL) {
10632         gst_element_post_message (GST_ELEMENT (qtdemux), msg_video_rotation);
10633       }
10634 #endif
10635     }
10636   } else {
10637     GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10638   }
10639 }
10640 
10641 static gboolean
qtdemux_parse_protection_aavd(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * container,guint32 * original_fmt)10642 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10643     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10644 {
10645   GNode *adrm;
10646   guint32 adrm_size;
10647   GstBuffer *adrm_buf = NULL;
10648   QtDemuxAavdEncryptionInfo *info;
10649 
10650   adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10651   if (G_UNLIKELY (!adrm)) {
10652     GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10653     return FALSE;
10654   }
10655   adrm_size = QT_UINT32 (adrm->data);
10656   adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10657 
10658   stream->protection_scheme_type = FOURCC_aavd;
10659 
10660   if (!stream->protection_scheme_info)
10661     stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10662 
10663   info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10664 
10665   if (info->default_properties)
10666     gst_structure_free (info->default_properties);
10667   info->default_properties = gst_structure_new ("application/x-aavd",
10668       "encrypted", G_TYPE_BOOLEAN, TRUE,
10669       "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10670   gst_buffer_unref (adrm_buf);
10671 
10672   *original_fmt = FOURCC_mp4a;
10673   return TRUE;
10674 }
10675 
10676 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10677  * protected streams (sinf, frma, schm and schi); if the protection scheme is
10678  * Common Encryption (cenc), the function will also parse the tenc box (defined
10679  * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10680  * (typically an enc[v|a|t|s] sample entry); the function will set
10681  * @original_fmt to the fourcc of the original unencrypted stream format.
10682  * Returns TRUE if successful; FALSE otherwise. */
10683 static gboolean
qtdemux_parse_protection_scheme_info(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * container,guint32 * original_fmt)10684 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10685     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10686 {
10687   GNode *sinf;
10688   GNode *frma;
10689   GNode *schm;
10690   GNode *schi;
10691   QtDemuxCencSampleSetInfo *info;
10692   GNode *tenc;
10693   const guint8 *tenc_data;
10694 
10695   g_return_val_if_fail (qtdemux != NULL, FALSE);
10696   g_return_val_if_fail (stream != NULL, FALSE);
10697   g_return_val_if_fail (container != NULL, FALSE);
10698   g_return_val_if_fail (original_fmt != NULL, FALSE);
10699 
10700   sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10701   if (G_UNLIKELY (!sinf)) {
10702     if (stream->protection_scheme_type == FOURCC_cenc
10703         || stream->protection_scheme_type == FOURCC_cbcs) {
10704       GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10705           "mandatory for Common Encryption");
10706       return FALSE;
10707     }
10708     return TRUE;
10709   }
10710 
10711   frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10712   if (G_UNLIKELY (!frma)) {
10713     GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10714     return FALSE;
10715   }
10716 
10717   *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10718   GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10719       GST_FOURCC_ARGS (*original_fmt));
10720 
10721   schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10722   if (!schm) {
10723     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10724     return FALSE;
10725   }
10726   stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10727   stream->protection_scheme_version =
10728       QT_UINT32 ((const guint8 *) schm->data + 16);
10729 
10730   GST_DEBUG_OBJECT (qtdemux,
10731       "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10732       "protection_scheme_version: %#010x",
10733       GST_FOURCC_ARGS (stream->protection_scheme_type),
10734       stream->protection_scheme_version);
10735 
10736   schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10737   if (!schi) {
10738     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10739     return FALSE;
10740   }
10741   if (stream->protection_scheme_type != FOURCC_cenc &&
10742       stream->protection_scheme_type != FOURCC_piff &&
10743       stream->protection_scheme_type != FOURCC_cbcs) {
10744     GST_ERROR_OBJECT (qtdemux,
10745         "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10746         GST_FOURCC_ARGS (stream->protection_scheme_type));
10747     return FALSE;
10748   }
10749 
10750   if (G_UNLIKELY (!stream->protection_scheme_info))
10751     stream->protection_scheme_info =
10752         g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10753 
10754   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10755 
10756   if (stream->protection_scheme_type == FOURCC_cenc
10757       || stream->protection_scheme_type == FOURCC_cbcs) {
10758     guint8 is_encrypted;
10759     guint8 iv_size;
10760     guint8 constant_iv_size = 0;
10761     const guint8 *default_kid;
10762     guint8 crypt_byte_block = 0;
10763     guint8 skip_byte_block = 0;
10764     const guint8 *constant_iv = NULL;
10765 
10766     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10767     if (!tenc) {
10768       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10769           "which is mandatory for Common Encryption");
10770       return FALSE;
10771     }
10772     tenc_data = (const guint8 *) tenc->data + 12;
10773     is_encrypted = QT_UINT8 (tenc_data + 2);
10774     iv_size = QT_UINT8 (tenc_data + 3);
10775     default_kid = (tenc_data + 4);
10776     if (stream->protection_scheme_type == FOURCC_cbcs) {
10777       guint8 possible_pattern_info;
10778       if (iv_size == 0) {
10779         constant_iv_size = QT_UINT8 (tenc_data + 20);
10780         if (constant_iv_size != 8 && constant_iv_size != 16) {
10781           GST_ERROR_OBJECT (qtdemux,
10782               "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10783           return FALSE;
10784         }
10785         constant_iv = (tenc_data + 21);
10786       }
10787       possible_pattern_info = QT_UINT8 (tenc_data + 1);
10788       crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10789       skip_byte_block = possible_pattern_info & 0x0f;
10790     }
10791     qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10792         is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10793         crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10794   } else if (stream->protection_scheme_type == FOURCC_piff) {
10795     GstByteReader br;
10796     static const guint8 piff_track_encryption_uuid[] = {
10797       0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10798       0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10799     };
10800 
10801     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10802     if (!tenc) {
10803       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10804           "which is mandatory for Common Encryption");
10805       return FALSE;
10806     }
10807 
10808     tenc_data = (const guint8 *) tenc->data + 8;
10809     if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10810       gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10811       GST_ERROR_OBJECT (qtdemux,
10812           "Unsupported track encryption box with uuid: %s", box_uuid);
10813       g_free (box_uuid);
10814       return FALSE;
10815     }
10816     tenc_data = (const guint8 *) tenc->data + 16 + 12;
10817     gst_byte_reader_init (&br, tenc_data, 20);
10818     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10819       GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10820       return FALSE;
10821     }
10822     stream->protection_scheme_type = FOURCC_cenc;
10823   }
10824 
10825   return TRUE;
10826 }
10827 
10828 static gint
qtdemux_track_id_compare_func(QtDemuxStream ** stream1,QtDemuxStream ** stream2)10829 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10830     QtDemuxStream ** stream2)
10831 {
10832   return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10833 }
10834 
10835 static gboolean
qtdemux_parse_stereo_svmi_atom(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * stbl)10836 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10837     GNode * stbl)
10838 {
10839   GNode *svmi;
10840 
10841   /*parse svmi header if existing */
10842   svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10843   if (svmi) {
10844     guint len = QT_UINT32 ((guint8 *) svmi->data);
10845     guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10846     if (!version) {
10847       GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10848       GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10849       guint8 frame_type, frame_layout;
10850       guint32 stereo_mono_change_count;
10851 
10852       if (len < 18)
10853         return FALSE;
10854 
10855       /* MPEG-A stereo video */
10856       if (qtdemux->major_brand == FOURCC_ss02)
10857         flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10858 
10859       frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10860       frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10861       stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10862 
10863       switch (frame_type) {
10864         case 0:
10865           mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10866           break;
10867         case 1:
10868           mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10869           break;
10870         case 2:
10871           mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10872           break;
10873         case 3:
10874           /* mode 3 is primary/secondary view sequence, ie
10875            * left/right views in separate tracks. See section 7.2
10876            * of ISO/IEC 23000-11:2009 */
10877           /* In the future this might be supported using related
10878            * streams, like an enhancement track - if files like this
10879            * ever exist */
10880           GST_FIXME_OBJECT (qtdemux,
10881               "Implement stereo video in separate streams");
10882       }
10883 
10884       if ((frame_layout & 0x1) == 0)
10885         flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10886 
10887       GST_LOG_OBJECT (qtdemux,
10888           "StereoVideo: composition type: %u, is_left_first: %u",
10889           frame_type, frame_layout);
10890 
10891       if (stereo_mono_change_count > 1) {
10892         GST_FIXME_OBJECT (qtdemux,
10893             "Mixed-mono flags are not yet supported in qtdemux.");
10894       }
10895 
10896       stream->multiview_mode = mode;
10897       stream->multiview_flags = flags;
10898     }
10899   }
10900 
10901   return TRUE;
10902 }
10903 
10904 /* parse the traks.
10905  * With each track we associate a new QtDemuxStream that contains all the info
10906  * about the trak.
10907  * traks that do not decode to something (like strm traks) will not have a pad.
10908  */
10909 static gboolean
qtdemux_parse_trak(GstQTDemux * qtdemux,GNode * trak)10910 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10911 {
10912   GstByteReader tkhd;
10913   int offset;
10914   GNode *mdia;
10915   GNode *mdhd;
10916   GNode *hdlr;
10917   GNode *minf;
10918   GNode *stbl;
10919   GNode *stsd;
10920   GNode *mp4a;
10921   GNode *mp4v;
10922   GNode *esds;
10923   GNode *tref;
10924   GNode *udta;
10925 
10926   QtDemuxStream *stream = NULL;
10927   const guint8 *stsd_data;
10928   const guint8 *stsd_entry_data;
10929   guint remaining_stsd_len;
10930   guint stsd_entry_count;
10931   guint stsd_index;
10932   guint16 lang_code;            /* quicktime lang code or packed iso code */
10933   guint32 version;
10934   guint32 tkhd_flags = 0;
10935   guint8 tkhd_version = 0;
10936   guint32 w = 0, h = 0;
10937   guint value_size, stsd_len, len;
10938   guint32 track_id;
10939   guint32 dummy;
10940 
10941   GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10942 
10943   if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10944       || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10945       || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10946     goto corrupt_file;
10947 
10948   /* pick between 64 or 32 bits */
10949   value_size = tkhd_version == 1 ? 8 : 4;
10950   if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10951       !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10952     goto corrupt_file;
10953 
10954   /* Check if current moov has duplicated track_id */
10955   if (qtdemux_find_stream (qtdemux, track_id))
10956     goto existing_stream;
10957 
10958   stream = _create_stream (qtdemux, track_id);
10959   stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10960 
10961   /* need defaults for fragments */
10962   qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10963 
10964   if ((tkhd_flags & 1) == 0)
10965     stream->disabled = TRUE;
10966 
10967   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10968       tkhd_version, tkhd_flags, stream->track_id);
10969 
10970   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10971     goto corrupt_file;
10972 
10973   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10974     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10975     if (qtdemux->major_brand != FOURCC_mjp2 ||
10976         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10977       goto corrupt_file;
10978   }
10979 
10980   len = QT_UINT32 ((guint8 *) mdhd->data);
10981   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10982   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10983   if (version == 0x01000000) {
10984     if (len < 42)
10985       goto corrupt_file;
10986     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10987     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10988     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10989   } else {
10990     if (len < 30)
10991       goto corrupt_file;
10992     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10993     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10994     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10995   }
10996 
10997   if (lang_code < 0x400) {
10998     qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10999   } else if (lang_code == 0x7fff) {
11000     stream->lang_id[0] = 0;     /* unspecified */
11001   } else {
11002     stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11003     stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11004     stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11005     stream->lang_id[3] = 0;
11006   }
11007 
11008   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11009       stream->timescale);
11010   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11011       stream->duration);
11012   GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11013       lang_code, stream->lang_id);
11014 
11015   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11016     goto corrupt_file;
11017 
11018   if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11019     /* chapters track reference */
11020     GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11021     if (chap) {
11022       gsize length = GST_READ_UINT32_BE (chap->data);
11023       if (qtdemux->chapters_track_id)
11024         GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11025 
11026       if (length >= 12) {
11027         qtdemux->chapters_track_id =
11028             GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11029       }
11030     }
11031   }
11032 
11033   /* fragmented files may have bogus duration in moov */
11034   if (!qtdemux->fragmented &&
11035       qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11036     guint64 tdur1, tdur2;
11037 
11038     /* don't overflow */
11039     tdur1 = stream->timescale * (guint64) qtdemux->duration;
11040     tdur2 = qtdemux->timescale * (guint64) stream->duration;
11041 
11042     /* HACK:
11043      * some of those trailers, nowadays, have prologue images that are
11044      * themselves video tracks as well. I haven't really found a way to
11045      * identify those yet, except for just looking at their duration. */
11046     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11047       GST_WARNING_OBJECT (qtdemux,
11048           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11049           " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11050           "found, assuming preview image or something; skipping track",
11051           stream->duration, stream->timescale, qtdemux->duration,
11052           qtdemux->timescale);
11053       gst_qtdemux_stream_unref (stream);
11054       return TRUE;
11055     }
11056   }
11057 
11058   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11059     goto corrupt_file;
11060 
11061   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11062       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11063 
11064   len = QT_UINT32 ((guint8 *) hdlr->data);
11065   if (len >= 20)
11066     stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11067   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11068       GST_FOURCC_ARGS (stream->subtype));
11069 
11070   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11071     goto corrupt_file;
11072 
11073   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11074     goto corrupt_file;
11075 
11076   /* Parse out svmi (and later st3d/sv3d) atoms */
11077   if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11078     goto corrupt_file;
11079 
11080   /* parse rest of tkhd */
11081   if (stream->subtype == FOURCC_vide) {
11082     guint32 matrix[9];
11083 
11084     /* version 1 uses some 64-bit ints */
11085     if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11086       goto corrupt_file;
11087 
11088     if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11089       goto corrupt_file;
11090 
11091     if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11092         || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11093       goto corrupt_file;
11094 
11095     qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11096         &stream->stream_tags);
11097   }
11098 
11099   /* parse stsd */
11100   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11101     goto corrupt_file;
11102   stsd_data = (const guint8 *) stsd->data;
11103 
11104   /* stsd should at least have one entry */
11105   stsd_len = QT_UINT32 (stsd_data);
11106   if (stsd_len < 24) {
11107     /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11108     if (stream->subtype == FOURCC_vivo) {
11109       gst_qtdemux_stream_unref (stream);
11110       return TRUE;
11111     } else {
11112       goto corrupt_file;
11113     }
11114   }
11115 
11116   stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11117   /* each stsd entry must contain at least 8 bytes */
11118   if (stream->stsd_entries_length == 0
11119       || stream->stsd_entries_length > stsd_len / 8) {
11120     stream->stsd_entries_length = 0;
11121     goto corrupt_file;
11122   }
11123   stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11124   GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
11125   GST_LOG_OBJECT (qtdemux, "stsd entry count:   %u", stsd_entry_count);
11126 
11127   stsd_entry_data = stsd_data + 16;
11128   remaining_stsd_len = stsd_len - 16;
11129   for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11130     guint32 fourcc;
11131     gchar *codec = NULL;
11132     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11133 
11134     /* and that entry should fit within stsd */
11135     len = QT_UINT32 (stsd_entry_data);
11136     if (len > remaining_stsd_len)
11137       goto corrupt_file;
11138 
11139     entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11140     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
11141         GST_FOURCC_ARGS (entry->fourcc));
11142     GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
11143 
11144     if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11145       goto error_encrypted;
11146 
11147     if (fourcc == FOURCC_aavd) {
11148       if (stream->subtype != FOURCC_soun) {
11149         GST_ERROR_OBJECT (qtdemux,
11150             "Unexpeced stsd type 'aavd' outside 'soun' track");
11151       } else {
11152         /* encrypted audio with sound sample description v0 */
11153         GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11154         stream->protected = TRUE;
11155         if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11156           GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11157       }
11158     }
11159 
11160     if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11161       /* FIXME this looks wrong, there might be multiple children
11162        * with the same type */
11163       GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11164       stream->protected = TRUE;
11165       if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11166         GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11167     }
11168 
11169     if (stream->subtype == FOURCC_vide) {
11170       GNode *colr;
11171       GNode *fiel;
11172       GNode *pasp;
11173       gboolean gray;
11174       gint depth, palette_size, palette_count;
11175       guint32 *palette_data = NULL;
11176 
11177       entry->sampled = TRUE;
11178 
11179       stream->display_width = w >> 16;
11180       stream->display_height = h >> 16;
11181 
11182       offset = 16;
11183       if (len < 86)             /* TODO verify */
11184         goto corrupt_file;
11185 
11186       entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11187       entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11188       entry->fps_n = 0;         /* this is filled in later */
11189       entry->fps_d = 0;         /* this is filled in later */
11190       entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11191       entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11192 
11193       /* if color_table_id is 0, ctab atom must follow; however some files
11194        * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11195        * if color table is not present we'll correct the value */
11196       if (entry->color_table_id == 0 &&
11197           (len < 90
11198               || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11199         entry->color_table_id = -1;
11200       }
11201 
11202       GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11203           entry->width, entry->height, entry->bits_per_sample,
11204           entry->color_table_id);
11205 
11206       depth = entry->bits_per_sample;
11207 
11208       /* more than 32 bits means grayscale */
11209       gray = (depth > 32);
11210       /* low 32 bits specify the depth  */
11211       depth &= 0x1F;
11212 
11213       /* different number of palette entries is determined by depth. */
11214       palette_count = 0;
11215       if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11216         palette_count = (1 << depth);
11217       palette_size = palette_count * 4;
11218 
11219       if (entry->color_table_id) {
11220         switch (palette_count) {
11221           case 0:
11222             break;
11223           case 2:
11224             palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11225             break;
11226           case 4:
11227             palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11228             break;
11229           case 16:
11230             if (gray)
11231               palette_data =
11232                   g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11233             else
11234               palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11235             break;
11236           case 256:
11237             if (gray)
11238               palette_data =
11239                   g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11240             else
11241               palette_data =
11242                   g_memdup2 (ff_qt_default_palette_256, palette_size);
11243             break;
11244           default:
11245             GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11246                 (_("The video in this file might not play correctly.")),
11247                 ("unsupported palette depth %d", depth));
11248             break;
11249         }
11250       } else {
11251         gint i, j, start, end;
11252 
11253         if (len < 94)
11254           goto corrupt_file;
11255 
11256         /* read table */
11257         start = QT_UINT32 (stsd_entry_data + offset + 70);
11258         palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11259         end = QT_UINT16 (stsd_entry_data + offset + 76);
11260 
11261         GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11262             start, end, palette_count);
11263 
11264         if (end > 255)
11265           end = 255;
11266         if (start > end)
11267           start = end;
11268 
11269         if (len < 94 + (end - start) * 8)
11270           goto corrupt_file;
11271 
11272         /* palette is always the same size */
11273         palette_data = g_malloc0 (256 * 4);
11274         palette_size = 256 * 4;
11275 
11276         for (j = 0, i = start; i <= end; j++, i++) {
11277           guint32 a, r, g, b;
11278 
11279           a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11280           r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11281           g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11282           b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11283 
11284           palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11285               (g & 0xff00) | (b >> 8);
11286         }
11287       }
11288 
11289       if (entry->caps)
11290         gst_caps_unref (entry->caps);
11291 
11292       entry->caps =
11293           qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11294           &codec);
11295       if (G_UNLIKELY (!entry->caps)) {
11296         g_free (palette_data);
11297         goto unknown_stream;
11298       }
11299 
11300       if (codec) {
11301         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11302             GST_TAG_VIDEO_CODEC, codec, NULL);
11303         g_free (codec);
11304         codec = NULL;
11305       }
11306 
11307       if (palette_data) {
11308         GstStructure *s;
11309 
11310         if (entry->rgb8_palette)
11311           gst_memory_unref (entry->rgb8_palette);
11312         entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11313             palette_data, palette_size, 0, palette_size, palette_data, g_free);
11314 
11315         s = gst_caps_get_structure (entry->caps, 0);
11316 
11317         /* non-raw video has a palette_data property. raw video has the palette as
11318          * an extra plane that we append to the output buffers before we push
11319          * them*/
11320         if (!gst_structure_has_name (s, "video/x-raw")) {
11321           GstBuffer *palette;
11322 
11323           palette = gst_buffer_new ();
11324           gst_buffer_append_memory (palette, entry->rgb8_palette);
11325           entry->rgb8_palette = NULL;
11326 
11327           gst_caps_set_simple (entry->caps, "palette_data",
11328               GST_TYPE_BUFFER, palette, NULL);
11329           gst_buffer_unref (palette);
11330         }
11331       } else if (palette_count != 0) {
11332         GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11333             (NULL), ("Unsupported palette depth %d", depth));
11334       }
11335 
11336       GST_LOG_OBJECT (qtdemux, "frame count:   %u",
11337           QT_UINT16 (stsd_entry_data + offset + 32));
11338 
11339       esds = NULL;
11340       pasp = NULL;
11341       colr = NULL;
11342       fiel = NULL;
11343       /* pick 'the' stsd child */
11344       mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11345       // We should skip parsing the stsd for non-protected streams if
11346       // the entry doesn't match the fourcc, since they don't change
11347       // format. However, for protected streams we can have partial
11348       // encryption, where parts of the stream are encrypted and parts
11349       // not. For both parts of such streams, we should ensure the
11350       // esds overrides are parsed for both from the stsd.
11351       if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11352         if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11353           mp4v = NULL;
11354         else if (!stream->protected)
11355           mp4v = NULL;
11356       }
11357 
11358       if (mp4v) {
11359         esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11360         pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11361         colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11362         fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11363       }
11364 
11365       if (pasp) {
11366         const guint8 *pasp_data = (const guint8 *) pasp->data;
11367         gint len = QT_UINT32 (pasp_data);
11368 
11369         if (len == 16) {
11370           CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11371           CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11372         } else {
11373           CUR_STREAM (stream)->par_w = 0;
11374           CUR_STREAM (stream)->par_h = 0;
11375         }
11376       } else {
11377         CUR_STREAM (stream)->par_w = 0;
11378         CUR_STREAM (stream)->par_h = 0;
11379       }
11380 
11381       if (fiel) {
11382         const guint8 *fiel_data = (const guint8 *) fiel->data;
11383         gint len = QT_UINT32 (fiel_data);
11384 
11385         if (len == 10) {
11386           CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11387           CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11388         }
11389       }
11390 
11391       if (colr) {
11392         const guint8 *colr_data = (const guint8 *) colr->data;
11393         gint len = QT_UINT32 (colr_data);
11394 
11395         if (len == 19 || len == 18) {
11396           guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11397 
11398           if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11399             guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11400             guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11401             guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11402             gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11403 
11404             CUR_STREAM (stream)->colorimetry.primaries =
11405                 gst_video_color_primaries_from_iso (primaries);
11406             CUR_STREAM (stream)->colorimetry.transfer =
11407                 gst_video_transfer_function_from_iso (transfer_function);
11408             CUR_STREAM (stream)->colorimetry.matrix =
11409                 gst_video_color_matrix_from_iso (matrix);
11410             CUR_STREAM (stream)->colorimetry.range =
11411                 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11412                 GST_VIDEO_COLOR_RANGE_16_235;
11413           } else {
11414             GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11415           }
11416         } else {
11417           GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11418         }
11419       }
11420 
11421       if (esds) {
11422         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11423             stream->stream_tags);
11424       } else {
11425         switch (fourcc) {
11426           case FOURCC_H264:
11427           case FOURCC_avc1:
11428           case FOURCC_avc3:
11429           {
11430             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11431             const guint8 *avc_data = stsd_entry_data + 0x56;
11432 
11433             /* find avcC */
11434             while (len >= 0x8) {
11435               gint size;
11436 
11437               if (QT_UINT32 (avc_data) <= len)
11438                 size = QT_UINT32 (avc_data) - 0x8;
11439               else
11440                 size = len - 0x8;
11441 
11442               if (size < 1)
11443                 /* No real data, so break out */
11444                 break;
11445 
11446               switch (QT_FOURCC (avc_data + 0x4)) {
11447                 case FOURCC_avcC:
11448                 {
11449                   /* parse, if found */
11450                   GstBuffer *buf;
11451 
11452                   GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11453 
11454                   /* First 4 bytes are the length of the atom, the next 4 bytes
11455                    * are the fourcc, the next 1 byte is the version, and the
11456                    * subsequent bytes are profile_tier_level structure like data. */
11457                   gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11458                       avc_data + 8 + 1, size - 1);
11459                   buf = gst_buffer_new_and_alloc (size);
11460                   gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11461                   gst_caps_set_simple (entry->caps,
11462                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11463                   gst_buffer_unref (buf);
11464 
11465                   break;
11466                 }
11467                 case FOURCC_strf:
11468                 {
11469                   GstBuffer *buf;
11470 
11471                   GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11472 
11473                   /* First 4 bytes are the length of the atom, the next 4 bytes
11474                    * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11475                    * next 1 byte is the version, and the
11476                    * subsequent bytes are sequence parameter set like data. */
11477 
11478                   size -= 40;   /* we'll be skipping BITMAPINFOHEADER */
11479                   if (size > 1) {
11480                     gst_codec_utils_h264_caps_set_level_and_profile
11481                         (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11482 
11483                     buf = gst_buffer_new_and_alloc (size);
11484                     gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11485                     gst_caps_set_simple (entry->caps,
11486                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
11487                     gst_buffer_unref (buf);
11488                   }
11489                   break;
11490                 }
11491                 case FOURCC_btrt:
11492                 {
11493                   guint avg_bitrate, max_bitrate;
11494 
11495                   /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11496                   if (size < 12)
11497                     break;
11498 
11499                   max_bitrate = QT_UINT32 (avc_data + 0xc);
11500                   avg_bitrate = QT_UINT32 (avc_data + 0x10);
11501 
11502                   if (!max_bitrate && !avg_bitrate)
11503                     break;
11504 
11505                   /* Some muxers seem to swap the average and maximum bitrates
11506                    * (I'm looking at you, YouTube), so we swap for sanity. */
11507                   if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11508                     guint temp = avg_bitrate;
11509 
11510                     avg_bitrate = max_bitrate;
11511                     max_bitrate = temp;
11512                   }
11513 
11514                   if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11515                     gst_tag_list_add (stream->stream_tags,
11516                         GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11517                         max_bitrate, NULL);
11518                   }
11519                   if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11520                     gst_tag_list_add (stream->stream_tags,
11521                         GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11522                         NULL);
11523                   }
11524 
11525                   break;
11526                 }
11527 
11528                 default:
11529                   break;
11530               }
11531 
11532               len -= size + 8;
11533               avc_data += size + 8;
11534             }
11535 
11536             break;
11537           }
11538           case FOURCC_H265:
11539           case FOURCC_hvc1:
11540           case FOURCC_hev1:
11541           case FOURCC_dvh1:
11542           case FOURCC_dvhe:
11543           {
11544             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11545             const guint8 *hevc_data = stsd_entry_data + 0x56;
11546 
11547             /* find hevc */
11548             while (len >= 0x8) {
11549               gint size;
11550 
11551               if (QT_UINT32 (hevc_data) <= len)
11552                 size = QT_UINT32 (hevc_data) - 0x8;
11553               else
11554                 size = len - 0x8;
11555 
11556               if (size < 1)
11557                 /* No real data, so break out */
11558                 break;
11559 
11560               switch (QT_FOURCC (hevc_data + 0x4)) {
11561                 case FOURCC_hvcC:
11562                 {
11563                   /* parse, if found */
11564                   GstBuffer *buf;
11565 
11566                   GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11567 
11568                   /* First 4 bytes are the length of the atom, the next 4 bytes
11569                    * are the fourcc, the next 1 byte is the version, and the
11570                    * subsequent bytes are sequence parameter set like data. */
11571                   gst_codec_utils_h265_caps_set_level_tier_and_profile
11572                       (entry->caps, hevc_data + 8 + 1, size - 1);
11573 
11574                   buf = gst_buffer_new_and_alloc (size);
11575                   gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11576                   gst_caps_set_simple (entry->caps,
11577                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11578                   gst_buffer_unref (buf);
11579                   break;
11580                 }
11581                 default:
11582                   break;
11583               }
11584               len -= size + 8;
11585               hevc_data += size + 8;
11586             }
11587             break;
11588           }
11589           case FOURCC_mp4v:
11590           case FOURCC_MP4V:
11591           case FOURCC_fmp4:
11592           case FOURCC_FMP4:
11593           case FOURCC_xvid:
11594           case FOURCC_XVID:
11595           {
11596             GNode *glbl;
11597 
11598             GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11599                 GST_FOURCC_ARGS (fourcc));
11600 
11601             /* codec data might be in glbl extension atom */
11602             glbl = mp4v ?
11603                 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11604             if (glbl) {
11605               guint8 *data;
11606               GstBuffer *buf;
11607               gint len;
11608 
11609               GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11610               data = glbl->data;
11611               len = QT_UINT32 (data);
11612               if (len > 0x8) {
11613                 len -= 0x8;
11614                 buf = gst_buffer_new_and_alloc (len);
11615                 gst_buffer_fill (buf, 0, data + 8, len);
11616                 gst_caps_set_simple (entry->caps,
11617                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11618                 gst_buffer_unref (buf);
11619               }
11620             }
11621             break;
11622           }
11623           case FOURCC_mjp2:
11624           {
11625             /* see annex I of the jpeg2000 spec */
11626             GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11627             const guint8 *data;
11628             const gchar *colorspace = NULL;
11629             gint ncomp = 0;
11630             guint32 ncomp_map = 0;
11631             gint32 *comp_map = NULL;
11632             guint32 nchan_def = 0;
11633             gint32 *chan_def = NULL;
11634 
11635             GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11636             /* some required atoms */
11637             mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11638             if (!mjp2)
11639               break;
11640             jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11641             if (!jp2h)
11642               break;
11643 
11644             /* number of components; redundant with info in codestream, but useful
11645                to a muxer */
11646             ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11647             if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11648               break;
11649             ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11650 
11651             colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11652             if (!colr)
11653               break;
11654             GST_DEBUG_OBJECT (qtdemux, "found colr");
11655             /* extract colour space info */
11656             if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11657               switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11658                 case 16:
11659                   colorspace = "sRGB";
11660                   break;
11661                 case 17:
11662                   colorspace = "GRAY";
11663                   break;
11664                 case 18:
11665                   colorspace = "sYUV";
11666                   break;
11667                 default:
11668                   colorspace = NULL;
11669                   break;
11670               }
11671             }
11672             if (!colorspace)
11673               /* colr is required, and only values 16, 17, and 18 are specified,
11674                  so error if we have no colorspace */
11675               break;
11676 
11677             /* extract component mapping */
11678             cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11679             if (cmap) {
11680               guint32 cmap_len = 0;
11681               int i;
11682               cmap_len = QT_UINT32 (cmap->data);
11683               if (cmap_len >= 8) {
11684                 /* normal box, subtract off header */
11685                 cmap_len -= 8;
11686                 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11687                 if (cmap_len % 4 == 0) {
11688                   ncomp_map = (cmap_len / 4);
11689                   comp_map = g_new0 (gint32, ncomp_map);
11690                   for (i = 0; i < ncomp_map; i++) {
11691                     guint16 cmp;
11692                     guint8 mtyp, pcol;
11693                     cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11694                     mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11695                     pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11696                     comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11697                   }
11698                 }
11699               }
11700             }
11701             /* extract channel definitions */
11702             cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11703             if (cdef) {
11704               guint32 cdef_len = 0;
11705               int i;
11706               cdef_len = QT_UINT32 (cdef->data);
11707               if (cdef_len >= 10) {
11708                 /* normal box, subtract off header and len */
11709                 cdef_len -= 10;
11710                 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11711                 if (cdef_len % 6 == 0) {
11712                   nchan_def = (cdef_len / 6);
11713                   chan_def = g_new0 (gint32, nchan_def);
11714                   for (i = 0; i < nchan_def; i++)
11715                     chan_def[i] = -1;
11716                   for (i = 0; i < nchan_def; i++) {
11717                     guint16 cn, typ, asoc;
11718                     cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11719                     typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11720                     asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11721                     if (cn < nchan_def) {
11722                       switch (typ) {
11723                         case 0:
11724                           chan_def[cn] = asoc;
11725                           break;
11726                         case 1:
11727                           chan_def[cn] = 0;     /* alpha */
11728                           break;
11729                         default:
11730                           chan_def[cn] = -typ;
11731                       }
11732                     }
11733                   }
11734                 }
11735               }
11736             }
11737 
11738             gst_caps_set_simple (entry->caps,
11739                 "num-components", G_TYPE_INT, ncomp, NULL);
11740             gst_caps_set_simple (entry->caps,
11741                 "colorspace", G_TYPE_STRING, colorspace, NULL);
11742 
11743             if (comp_map) {
11744               GValue arr = { 0, };
11745               GValue elt = { 0, };
11746               int i;
11747               g_value_init (&arr, GST_TYPE_ARRAY);
11748               g_value_init (&elt, G_TYPE_INT);
11749               for (i = 0; i < ncomp_map; i++) {
11750                 g_value_set_int (&elt, comp_map[i]);
11751                 gst_value_array_append_value (&arr, &elt);
11752               }
11753               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11754                   "component-map", &arr);
11755               g_value_unset (&elt);
11756               g_value_unset (&arr);
11757               g_free (comp_map);
11758             }
11759 
11760             if (chan_def) {
11761               GValue arr = { 0, };
11762               GValue elt = { 0, };
11763               int i;
11764               g_value_init (&arr, GST_TYPE_ARRAY);
11765               g_value_init (&elt, G_TYPE_INT);
11766               for (i = 0; i < nchan_def; i++) {
11767                 g_value_set_int (&elt, chan_def[i]);
11768                 gst_value_array_append_value (&arr, &elt);
11769               }
11770               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11771                   "channel-definitions", &arr);
11772               g_value_unset (&elt);
11773               g_value_unset (&arr);
11774               g_free (chan_def);
11775             }
11776 
11777             /* some optional atoms */
11778             field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11779             prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11780 
11781             /* indicate possible fields in caps */
11782             if (field) {
11783               data = (guint8 *) field->data + 8;
11784               if (*data != 1)
11785                 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11786                     (gint) * data, NULL);
11787             }
11788             /* add codec_data if provided */
11789             if (prefix) {
11790               GstBuffer *buf;
11791               gint len;
11792 
11793               GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11794               data = prefix->data;
11795               len = QT_UINT32 (data);
11796               if (len > 0x8) {
11797                 len -= 0x8;
11798                 buf = gst_buffer_new_and_alloc (len);
11799                 gst_buffer_fill (buf, 0, data + 8, len);
11800                 gst_caps_set_simple (entry->caps,
11801                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11802                 gst_buffer_unref (buf);
11803               }
11804             }
11805             break;
11806           }
11807           case FOURCC_SVQ3:
11808           case FOURCC_VP31:
11809           {
11810             GstBuffer *buf;
11811             GstBuffer *seqh = NULL;
11812             const guint8 *gamma_data = NULL;
11813             gint len = QT_UINT32 (stsd_data);   /* FIXME review - why put the whole stsd in codec data? */
11814 
11815             qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11816                 &seqh);
11817             if (gamma_data) {
11818               gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11819                   QT_FP32 (gamma_data), NULL);
11820             }
11821             if (seqh) {
11822               /* sorry for the bad name, but we don't know what this is, other
11823                * than its own fourcc */
11824               gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11825                   NULL);
11826               gst_buffer_unref (seqh);
11827             }
11828 
11829             GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11830             buf = gst_buffer_new_and_alloc (len);
11831             gst_buffer_fill (buf, 0, stsd_data, len);
11832             gst_caps_set_simple (entry->caps,
11833                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11834             gst_buffer_unref (buf);
11835             break;
11836           }
11837           case FOURCC_jpeg:
11838           {
11839             /* https://developer.apple.com/standards/qtff-2001.pdf,
11840              * page 92, "Video Sample Description", under table 3.1 */
11841             GstByteReader br;
11842 
11843             const gint compressor_offset =
11844                 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11845             const gint min_size = compressor_offset + 32 + 2 + 2;
11846             GNode *jpeg;
11847             guint32 len;
11848             guint16 color_table_id = 0;
11849             gboolean ok;
11850 
11851             GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11852 
11853             /* recover information on interlaced/progressive */
11854             jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11855             if (!jpeg)
11856               break;
11857 
11858             len = QT_UINT32 (jpeg->data);
11859             GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11860                 min_size);
11861             if (len >= min_size) {
11862               gst_byte_reader_init (&br, jpeg->data, len);
11863 
11864               gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11865               gst_byte_reader_get_uint16_le (&br, &color_table_id);
11866               if (color_table_id != 0) {
11867                 /* the spec says there can be concatenated chunks in the data, and we want
11868                  * to find one called field. Walk through them. */
11869                 gint offset = min_size;
11870                 while (offset + 8 < len) {
11871                   guint32 size = 0, tag;
11872                   ok = gst_byte_reader_get_uint32_le (&br, &size);
11873                   ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11874                   if (!ok || size < 8) {
11875                     GST_WARNING_OBJECT (qtdemux,
11876                         "Failed to walk optional chunk list");
11877                     break;
11878                   }
11879                   GST_DEBUG_OBJECT (qtdemux,
11880                       "Found optional %4.4s chunk, size %u",
11881                       (const char *) &tag, size);
11882                   if (tag == FOURCC_fiel) {
11883                     guint8 n_fields = 0, ordering = 0;
11884                     gst_byte_reader_get_uint8 (&br, &n_fields);
11885                     gst_byte_reader_get_uint8 (&br, &ordering);
11886                     if (n_fields == 1 || n_fields == 2) {
11887                       GST_DEBUG_OBJECT (qtdemux,
11888                           "Found fiel tag with %u fields, ordering %u",
11889                           n_fields, ordering);
11890                       if (n_fields == 2)
11891                         gst_caps_set_simple (CUR_STREAM (stream)->caps,
11892                             "interlace-mode", G_TYPE_STRING, "interleaved",
11893                             NULL);
11894                     } else {
11895                       GST_WARNING_OBJECT (qtdemux,
11896                           "Found fiel tag with invalid fields (%u)", n_fields);
11897                     }
11898                   }
11899                   offset += size;
11900                 }
11901               } else {
11902                 GST_DEBUG_OBJECT (qtdemux,
11903                     "Color table ID is 0, not trying to get interlacedness");
11904               }
11905             } else {
11906               GST_WARNING_OBJECT (qtdemux,
11907                   "Length of jpeg chunk is too small, not trying to get interlacedness");
11908             }
11909 
11910             break;
11911           }
11912           case FOURCC_rle_:
11913           case FOURCC_WRLE:
11914           {
11915             gst_caps_set_simple (entry->caps,
11916                 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11917                 NULL);
11918             break;
11919           }
11920           case FOURCC_XiTh:
11921           {
11922             GNode *xith, *xdxt;
11923 
11924             GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11925             xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11926             if (!xith)
11927               break;
11928 
11929             xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11930             if (!xdxt)
11931               break;
11932 
11933             GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11934             /* collect the headers and store them in a stream list so that we can
11935              * send them out first */
11936             qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11937             break;
11938           }
11939           case FOURCC_ovc1:
11940           {
11941             GNode *ovc1;
11942             guint8 *ovc1_data;
11943             guint ovc1_len;
11944             GstBuffer *buf;
11945 
11946             GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11947             ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11948             if (!ovc1)
11949               break;
11950             ovc1_data = ovc1->data;
11951             ovc1_len = QT_UINT32 (ovc1_data);
11952             if (ovc1_len <= 198) {
11953               GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11954               break;
11955             }
11956             buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11957             gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11958             gst_caps_set_simple (entry->caps,
11959                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11960             gst_buffer_unref (buf);
11961             break;
11962           }
11963           case FOURCC_vc_1:
11964           {
11965             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11966             const guint8 *vc1_data = stsd_entry_data + 0x56;
11967 
11968             /* find dvc1 */
11969             while (len >= 8) {
11970               gint size;
11971 
11972               if (QT_UINT32 (vc1_data) <= len)
11973                 size = QT_UINT32 (vc1_data) - 8;
11974               else
11975                 size = len - 8;
11976 
11977               if (size < 1)
11978                 /* No real data, so break out */
11979                 break;
11980 
11981               switch (QT_FOURCC (vc1_data + 0x4)) {
11982                 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11983                 {
11984                   GstBuffer *buf;
11985 
11986                   GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11987                   buf = gst_buffer_new_and_alloc (size);
11988                   gst_buffer_fill (buf, 0, vc1_data + 8, size);
11989                   gst_caps_set_simple (entry->caps,
11990                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11991                   gst_buffer_unref (buf);
11992                   break;
11993                 }
11994                 default:
11995                   break;
11996               }
11997               len -= size + 8;
11998               vc1_data += size + 8;
11999             }
12000             break;
12001           }
12002           case FOURCC_av01:
12003           {
12004             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12005             const guint8 *av1_data = stsd_entry_data + 0x56;
12006 
12007             /* find av1C */
12008             while (len >= 0x8) {
12009               gint size;
12010 
12011               if (QT_UINT32 (av1_data) <= len)
12012                 size = QT_UINT32 (av1_data) - 0x8;
12013               else
12014                 size = len - 0x8;
12015 
12016               if (size < 1)
12017                 /* No real data, so break out */
12018                 break;
12019 
12020               switch (QT_FOURCC (av1_data + 0x4)) {
12021                 case FOURCC_av1C:
12022                 {
12023                   /* parse, if found */
12024                   GstBuffer *buf;
12025                   guint8 pres_delay_field;
12026 
12027                   GST_DEBUG_OBJECT (qtdemux,
12028                       "found av1C codec_data in stsd of size %d", size);
12029 
12030                   /* not enough data, just ignore and hope for the best */
12031                   if (size < 5)
12032                     break;
12033 
12034                   /* Content is:
12035                    * 4 bytes: atom length
12036                    * 4 bytes: fourcc
12037                    * 1 byte: version
12038                    * 3 bytes: flags
12039                    * 3 bits: reserved
12040                    * 1 bits:  initial_presentation_delay_present
12041                    * 4 bits: initial_presentation_delay (if present else reserved
12042                    * rest: OBUs.
12043                    */
12044 
12045                   if (av1_data[9] != 0) {
12046                     GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12047                     break;
12048                   }
12049 
12050                   /* We skip initial_presentation_delay* for now */
12051                   pres_delay_field = *(av1_data + 12);
12052                   if (pres_delay_field & (1 << 5)) {
12053                     gst_caps_set_simple (entry->caps,
12054                         "presentation-delay", G_TYPE_INT,
12055                         (gint) (pres_delay_field & 0x0F) + 1, NULL);
12056                   }
12057                   if (size > 5) {
12058                     buf = gst_buffer_new_and_alloc (size - 5);
12059                     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12060                     gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12061                     gst_caps_set_simple (entry->caps,
12062                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
12063                     gst_buffer_unref (buf);
12064                   }
12065                   break;
12066                 }
12067                 default:
12068                   break;
12069               }
12070 
12071               len -= size + 8;
12072               av1_data += size + 8;
12073             }
12074 
12075             break;
12076           }
12077 
12078             /* TODO: Need to parse vpcC for VP8 codec too.
12079              * Note that VPCodecConfigurationBox (vpcC) is defined for
12080              * vp08, vp09, and vp10 fourcc. */
12081           case FOURCC_vp09:
12082           {
12083             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12084             const guint8 *vpcc_data = stsd_entry_data + 0x56;
12085 
12086             /* find vpcC */
12087             while (len >= 0x8) {
12088               gint size;
12089 
12090               if (QT_UINT32 (vpcc_data) <= len)
12091                 size = QT_UINT32 (vpcc_data) - 0x8;
12092               else
12093                 size = len - 0x8;
12094 
12095               if (size < 1)
12096                 /* No real data, so break out */
12097                 break;
12098 
12099               switch (QT_FOURCC (vpcc_data + 0x4)) {
12100                 case FOURCC_vpcC:
12101                 {
12102                   const gchar *profile_str = NULL;
12103                   const gchar *chroma_format_str = NULL;
12104                   guint8 profile;
12105                   guint8 bitdepth;
12106                   guint8 chroma_format;
12107                   GstVideoColorimetry cinfo;
12108 
12109                   /* parse, if found */
12110                   GST_DEBUG_OBJECT (qtdemux,
12111                       "found vp codec_data in stsd of size %d", size);
12112 
12113                   /* the meaning of "size" is length of the atom body, excluding
12114                    * atom length and fourcc fields */
12115                   if (size < 12)
12116                     break;
12117 
12118                   /* Content is:
12119                    * 4 bytes: atom length
12120                    * 4 bytes: fourcc
12121                    * 1 byte: version
12122                    * 3 bytes: flags
12123                    * 1 byte: profile
12124                    * 1 byte: level
12125                    * 4 bits: bitDepth
12126                    * 3 bits: chromaSubsampling
12127                    * 1 bit: videoFullRangeFlag
12128                    * 1 byte: colourPrimaries
12129                    * 1 byte: transferCharacteristics
12130                    * 1 byte: matrixCoefficients
12131                    * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12132                    * rest: codecIntializationData (not used for vp8 and vp9)
12133                    */
12134 
12135                   if (vpcc_data[8] != 1) {
12136                     GST_WARNING_OBJECT (qtdemux,
12137                         "unknown vpcC version %d", vpcc_data[8]);
12138                     break;
12139                   }
12140 
12141                   profile = vpcc_data[12];
12142                   switch (profile) {
12143                     case 0:
12144                       profile_str = "0";
12145                       break;
12146                     case 1:
12147                       profile_str = "1";
12148                       break;
12149                     case 2:
12150                       profile_str = "2";
12151                       break;
12152                     case 3:
12153                       profile_str = "3";
12154                       break;
12155                     default:
12156                       break;
12157                   }
12158 
12159                   if (profile_str) {
12160                     gst_caps_set_simple (entry->caps,
12161                         "profile", G_TYPE_STRING, profile_str, NULL);
12162                   }
12163 
12164                   /* skip level, the VP9 spec v0.6 defines only one level atm,
12165                    * but webm spec define various ones. Add level to caps
12166                    * if we really need it then */
12167 
12168                   bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12169                   if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12170                     gst_caps_set_simple (entry->caps,
12171                         "bit-depth-luma", G_TYPE_UINT, bitdepth,
12172                         "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12173                   }
12174 
12175                   chroma_format = (vpcc_data[14] & 0xe) >> 1;
12176                   switch (chroma_format) {
12177                     case 0:
12178                     case 1:
12179                       chroma_format_str = "4:2:0";
12180                       break;
12181                     case 2:
12182                       chroma_format_str = "4:2:2";
12183                       break;
12184                     case 3:
12185                       chroma_format_str = "4:4:4";
12186                       break;
12187                     default:
12188                       break;
12189                   }
12190 
12191                   if (chroma_format_str) {
12192                     gst_caps_set_simple (entry->caps,
12193                         "chroma-format", G_TYPE_STRING, chroma_format_str,
12194                         NULL);
12195                   }
12196 
12197                   if ((vpcc_data[14] & 0x1) != 0)
12198                     cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12199                   else
12200                     cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12201                   cinfo.primaries =
12202                       gst_video_color_primaries_from_iso (vpcc_data[15]);
12203                   cinfo.transfer =
12204                       gst_video_transfer_function_from_iso (vpcc_data[16]);
12205                   cinfo.matrix =
12206                       gst_video_color_matrix_from_iso (vpcc_data[17]);
12207 
12208                   if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12209                       cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12210                       cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12211                     /* set this only if all values are known, otherwise this
12212                      * might overwrite valid ones parsed from other color box */
12213                     CUR_STREAM (stream)->colorimetry = cinfo;
12214                   }
12215                   break;
12216                 }
12217                 default:
12218                   break;
12219               }
12220 
12221               len -= size + 8;
12222               vpcc_data += size + 8;
12223             }
12224 
12225             break;
12226           }
12227           default:
12228             break;
12229         }
12230       }
12231 
12232       GST_INFO_OBJECT (qtdemux,
12233           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12234           GST_FOURCC_ARGS (fourcc), entry->caps);
12235 
12236     } else if (stream->subtype == FOURCC_soun) {
12237       GNode *wave;
12238       int version, samplesize;
12239       guint16 compression_id;
12240       gboolean amrwb = FALSE;
12241 
12242       offset = 16;
12243       /* sample description entry (16) + sound sample description v0 (20) */
12244       if (len < 36)
12245         goto corrupt_file;
12246 
12247       version = QT_UINT32 (stsd_entry_data + offset);
12248       entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12249       samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12250       compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12251       entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12252 
12253       GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
12254       GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
12255           QT_UINT32 (stsd_entry_data + offset + 4));
12256       GST_LOG_OBJECT (qtdemux, "n_channels:       %d", entry->n_channels);
12257       GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
12258       GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
12259       GST_LOG_OBJECT (qtdemux, "packet size:      %d",
12260           QT_UINT16 (stsd_entry_data + offset + 14));
12261       GST_LOG_OBJECT (qtdemux, "sample rate:      %g", entry->rate);
12262 
12263       if (compression_id == 0xfffe)
12264         entry->sampled = TRUE;
12265 
12266       /* first assume uncompressed audio */
12267       entry->bytes_per_sample = samplesize / 8;
12268       entry->samples_per_frame = entry->n_channels;
12269       entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12270       entry->samples_per_packet = entry->samples_per_frame;
12271       entry->bytes_per_packet = entry->bytes_per_sample;
12272 
12273       offset = 36;
12274 
12275       if (version == 0x00010000) {
12276         /* sample description entry (16) + sound sample description v1 (20+16) */
12277         if (len < 52)
12278           goto corrupt_file;
12279 
12280         /* take information from here over the normal sample description */
12281         entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12282         entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12283         entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12284         entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12285 
12286         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12287         GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
12288             entry->samples_per_packet);
12289         GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
12290             entry->bytes_per_packet);
12291         GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
12292             entry->bytes_per_frame);
12293         GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
12294             entry->bytes_per_sample);
12295 
12296         if (!entry->sampled && entry->bytes_per_packet) {
12297           entry->samples_per_frame = (entry->bytes_per_frame /
12298               entry->bytes_per_packet) * entry->samples_per_packet;
12299           GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
12300               entry->samples_per_frame);
12301         }
12302       } else if (version == 0x00020000) {
12303         /* sample description entry (16) + sound sample description v2 (56) */
12304         if (len < 72)
12305           goto corrupt_file;
12306 
12307         /* take information from here over the normal sample description */
12308         entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12309         entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12310         entry->samples_per_frame = entry->n_channels;
12311         entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12312         entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12313         entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12314         entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12315 
12316         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12317         GST_LOG_OBJECT (qtdemux, "sample rate:        %g", entry->rate);
12318         GST_LOG_OBJECT (qtdemux, "n_channels:         %d", entry->n_channels);
12319         GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
12320             entry->bytes_per_sample * 8);
12321         GST_LOG_OBJECT (qtdemux, "format flags:       %X",
12322             QT_UINT32 (stsd_entry_data + offset + 24));
12323         GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
12324             entry->bytes_per_packet);
12325         GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12326             entry->samples_per_packet);
12327       } else if (version != 0x00000) {
12328         GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12329             version);
12330       }
12331 
12332       switch (fourcc) {
12333           /* Yes, these have to be hard-coded */
12334         case FOURCC_MAC6:
12335         {
12336           entry->samples_per_packet = 6;
12337           entry->bytes_per_packet = 1;
12338           entry->bytes_per_frame = 1 * entry->n_channels;
12339           entry->bytes_per_sample = 1;
12340           entry->samples_per_frame = 6 * entry->n_channels;
12341           break;
12342         }
12343         case FOURCC_MAC3:
12344         {
12345           entry->samples_per_packet = 3;
12346           entry->bytes_per_packet = 1;
12347           entry->bytes_per_frame = 1 * entry->n_channels;
12348           entry->bytes_per_sample = 1;
12349           entry->samples_per_frame = 3 * entry->n_channels;
12350           break;
12351         }
12352         case FOURCC_ima4:
12353         {
12354           entry->samples_per_packet = 64;
12355           entry->bytes_per_packet = 34;
12356           entry->bytes_per_frame = 34 * entry->n_channels;
12357           entry->bytes_per_sample = 2;
12358           entry->samples_per_frame = 64 * entry->n_channels;
12359           break;
12360         }
12361         case FOURCC_ulaw:
12362         case FOURCC_alaw:
12363         {
12364           entry->samples_per_packet = 1;
12365           entry->bytes_per_packet = 1;
12366           entry->bytes_per_frame = 1 * entry->n_channels;
12367           entry->bytes_per_sample = 1;
12368           entry->samples_per_frame = 1 * entry->n_channels;
12369           break;
12370         }
12371         case FOURCC_agsm:
12372         {
12373           entry->samples_per_packet = 160;
12374           entry->bytes_per_packet = 33;
12375           entry->bytes_per_frame = 33 * entry->n_channels;
12376           entry->bytes_per_sample = 2;
12377           entry->samples_per_frame = 160 * entry->n_channels;
12378           break;
12379         }
12380           /* fix up any invalid header information from above */
12381         case FOURCC_twos:
12382         case FOURCC_sowt:
12383         case FOURCC_raw_:
12384         case FOURCC_lpcm:
12385           /* Sometimes these are set to 0 in the sound sample descriptions so
12386            * let's try to infer useful values from the other information we
12387            * have available */
12388           if (entry->bytes_per_sample == 0)
12389             entry->bytes_per_sample =
12390                 entry->bytes_per_frame / entry->n_channels;
12391           if (entry->bytes_per_sample == 0)
12392             entry->bytes_per_sample = samplesize / 8;
12393 
12394           if (entry->bytes_per_frame == 0)
12395             entry->bytes_per_frame =
12396                 entry->bytes_per_sample * entry->n_channels;
12397 
12398           if (entry->bytes_per_packet == 0)
12399             entry->bytes_per_packet = entry->bytes_per_sample;
12400 
12401           if (entry->samples_per_frame == 0)
12402             entry->samples_per_frame = entry->n_channels;
12403 
12404           if (entry->samples_per_packet == 0)
12405             entry->samples_per_packet = entry->samples_per_frame;
12406 
12407           break;
12408         case FOURCC_in24:
12409         case FOURCC_in32:
12410         case FOURCC_fl32:
12411         case FOURCC_fl64:
12412         case FOURCC_s16l:{
12413           switch (fourcc) {
12414             case FOURCC_in24:
12415               entry->bytes_per_sample = 3;
12416               break;
12417             case FOURCC_in32:
12418             case FOURCC_fl32:
12419               entry->bytes_per_sample = 4;
12420               break;
12421             case FOURCC_fl64:
12422               entry->bytes_per_sample = 8;
12423               break;
12424             case FOURCC_s16l:
12425               entry->bytes_per_sample = 2;
12426               break;
12427             default:
12428               g_assert_not_reached ();
12429               break;
12430           }
12431           entry->samples_per_frame = entry->n_channels;
12432           entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12433           entry->samples_per_packet = entry->samples_per_frame;
12434           entry->bytes_per_packet = entry->bytes_per_sample;
12435           break;
12436         }
12437         default:
12438           break;
12439       }
12440 
12441       if (entry->caps)
12442         gst_caps_unref (entry->caps);
12443 
12444       entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12445           stsd_entry_data + 32, len - 16, &codec);
12446 
12447       switch (fourcc) {
12448         case FOURCC_in24:
12449         case FOURCC_in32:
12450         case FOURCC_fl32:
12451         case FOURCC_fl64:
12452         {
12453           GNode *enda;
12454           GNode *fmt;
12455 
12456           fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12457 
12458           enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12459           if (!enda) {
12460             wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12461             if (wave)
12462               enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12463           }
12464           if (enda) {
12465             int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12466             const gchar *format_str;
12467 
12468             switch (fourcc) {
12469               case FOURCC_in24:
12470                 format_str = (enda_value) ? "S24LE" : "S24BE";
12471                 break;
12472               case FOURCC_in32:
12473                 format_str = (enda_value) ? "S32LE" : "S32BE";
12474                 break;
12475               case FOURCC_fl32:
12476                 format_str = (enda_value) ? "F32LE" : "F32BE";
12477                 break;
12478               case FOURCC_fl64:
12479                 format_str = (enda_value) ? "F64LE" : "F64BE";
12480                 break;
12481               default:
12482                 g_assert_not_reached ();
12483                 break;
12484             }
12485             gst_caps_set_simple (entry->caps,
12486                 "format", G_TYPE_STRING, format_str, NULL);
12487           }
12488           break;
12489         }
12490         case FOURCC_owma:
12491         {
12492           const guint8 *owma_data;
12493           const gchar *codec_name = NULL;
12494           guint owma_len;
12495           GstBuffer *buf;
12496           gint version = 1;
12497           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12498           /* FIXME this should also be gst_riff_strf_auds,
12499            * but the latter one is actually missing bits-per-sample :( */
12500           typedef struct
12501           {
12502             gint16 wFormatTag;
12503             gint16 nChannels;
12504             gint32 nSamplesPerSec;
12505             gint32 nAvgBytesPerSec;
12506             gint16 nBlockAlign;
12507             gint16 wBitsPerSample;
12508             gint16 cbSize;
12509           } WAVEFORMATEX;
12510           WAVEFORMATEX *wfex;
12511 
12512           GST_DEBUG_OBJECT (qtdemux, "parse owma");
12513           owma_data = stsd_entry_data;
12514           owma_len = QT_UINT32 (owma_data);
12515           if (owma_len <= 54) {
12516             GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12517             break;
12518           }
12519           wfex = (WAVEFORMATEX *) (owma_data + 36);
12520           buf = gst_buffer_new_and_alloc (owma_len - 54);
12521           gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12522           if (wfex->wFormatTag == 0x0161) {
12523             codec_name = "Windows Media Audio";
12524             version = 2;
12525           } else if (wfex->wFormatTag == 0x0162) {
12526             codec_name = "Windows Media Audio 9 Pro";
12527             version = 3;
12528           } else if (wfex->wFormatTag == 0x0163) {
12529             codec_name = "Windows Media Audio 9 Lossless";
12530             /* is that correct? gstffmpegcodecmap.c is missing it, but
12531              * fluendo codec seems to support it */
12532             version = 4;
12533           }
12534 
12535           gst_caps_set_simple (entry->caps,
12536               "codec_data", GST_TYPE_BUFFER, buf,
12537               "wmaversion", G_TYPE_INT, version,
12538               "block_align", G_TYPE_INT,
12539               GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12540               GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12541               GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12542               GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12543           gst_buffer_unref (buf);
12544 
12545           if (codec_name) {
12546             g_free (codec);
12547             codec = g_strdup (codec_name);
12548           }
12549           break;
12550         }
12551         case FOURCC_wma_:
12552         {
12553           gint len = QT_UINT32 (stsd_entry_data) - offset;
12554           const guint8 *wfex_data = stsd_entry_data + offset;
12555           const gchar *codec_name = NULL;
12556           gint version = 1;
12557           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12558           /* FIXME this should also be gst_riff_strf_auds,
12559            * but the latter one is actually missing bits-per-sample :( */
12560           typedef struct
12561           {
12562             gint16 wFormatTag;
12563             gint16 nChannels;
12564             gint32 nSamplesPerSec;
12565             gint32 nAvgBytesPerSec;
12566             gint16 nBlockAlign;
12567             gint16 wBitsPerSample;
12568             gint16 cbSize;
12569           } WAVEFORMATEX;
12570           WAVEFORMATEX wfex;
12571 
12572           /* FIXME: unify with similar wavformatex parsing code above */
12573           GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12574 
12575           /* find wfex */
12576           while (len >= 8) {
12577             gint size;
12578 
12579             if (QT_UINT32 (wfex_data) <= len)
12580               size = QT_UINT32 (wfex_data) - 8;
12581             else
12582               size = len - 8;
12583 
12584             if (size < 1)
12585               /* No real data, so break out */
12586               break;
12587 
12588             switch (QT_FOURCC (wfex_data + 4)) {
12589               case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12590               {
12591                 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12592 
12593                 if (size < 8 + 18)
12594                   break;
12595 
12596                 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12597                 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12598                 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12599                 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12600                 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12601                 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12602                 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12603 
12604                 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12605                 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12606                     "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12607                     "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12608                     wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12609                     wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12610 
12611                 if (wfex.wFormatTag == 0x0161) {
12612                   codec_name = "Windows Media Audio";
12613                   version = 2;
12614                 } else if (wfex.wFormatTag == 0x0162) {
12615                   codec_name = "Windows Media Audio 9 Pro";
12616                   version = 3;
12617                 } else if (wfex.wFormatTag == 0x0163) {
12618                   codec_name = "Windows Media Audio 9 Lossless";
12619                   /* is that correct? gstffmpegcodecmap.c is missing it, but
12620                    * fluendo codec seems to support it */
12621                   version = 4;
12622                 }
12623 
12624                 gst_caps_set_simple (entry->caps,
12625                     "wmaversion", G_TYPE_INT, version,
12626                     "block_align", G_TYPE_INT, wfex.nBlockAlign,
12627                     "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12628                     "width", G_TYPE_INT, wfex.wBitsPerSample,
12629                     "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12630 
12631                 if (size > wfex.cbSize) {
12632                   GstBuffer *buf;
12633 
12634                   buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12635                   gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12636                       size - wfex.cbSize);
12637                   gst_caps_set_simple (entry->caps,
12638                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12639                   gst_buffer_unref (buf);
12640                 } else {
12641                   GST_WARNING_OBJECT (qtdemux, "no codec data");
12642                 }
12643 
12644                 if (codec_name) {
12645                   g_free (codec);
12646                   codec = g_strdup (codec_name);
12647                 }
12648                 break;
12649               }
12650               default:
12651                 break;
12652             }
12653             len -= size + 8;
12654             wfex_data += size + 8;
12655           }
12656           break;
12657         }
12658         case FOURCC_opus:
12659         {
12660           const guint8 *dops_data;
12661           guint8 *channel_mapping = NULL;
12662           guint32 rate;
12663           guint8 channels;
12664           guint8 channel_mapping_family;
12665           guint8 stream_count;
12666           guint8 coupled_count;
12667           guint8 i;
12668 
12669           version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12670           if (version == 1)
12671             dops_data = stsd_entry_data + 51;
12672           else
12673             dops_data = stsd_entry_data + 35;
12674 
12675           channels = GST_READ_UINT8 (dops_data + 10);
12676           rate = GST_READ_UINT32_LE (dops_data + 13);
12677           channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12678           stream_count = GST_READ_UINT8 (dops_data + 20);
12679           coupled_count = GST_READ_UINT8 (dops_data + 21);
12680 
12681           if (channels > 0) {
12682             channel_mapping = g_malloc (channels * sizeof (guint8));
12683             for (i = 0; i < channels; i++)
12684               channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12685           }
12686 
12687           entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12688               channel_mapping_family, stream_count, coupled_count,
12689               channel_mapping);
12690           g_free (channel_mapping);
12691           break;
12692         }
12693         default:
12694           break;
12695       }
12696 
12697       if (codec) {
12698         GstStructure *s;
12699         gint bitrate = 0;
12700 
12701         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12702             GST_TAG_AUDIO_CODEC, codec, NULL);
12703         g_free (codec);
12704         codec = NULL;
12705 
12706         /* some bitrate info may have ended up in caps */
12707         s = gst_caps_get_structure (entry->caps, 0);
12708         gst_structure_get_int (s, "bitrate", &bitrate);
12709         if (bitrate > 0)
12710           gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12711               GST_TAG_BITRATE, bitrate, NULL);
12712       }
12713 
12714       esds = NULL;
12715       mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12716       if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12717         if (stream->protected) {
12718           if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12719             esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12720           }
12721           if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12722             mp4a = NULL;
12723           }
12724         } else {
12725           mp4a = NULL;
12726         }
12727       }
12728 
12729       wave = NULL;
12730       if (mp4a) {
12731         wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12732         if (wave)
12733           esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12734         if (!esds)
12735           esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12736       }
12737 
12738 
12739       /* If the fourcc's bottom 16 bits gives 'sm', then the top
12740          16 bits is a byte-swapped wave-style codec identifier,
12741          and we can find a WAVE header internally to a 'wave' atom here.
12742          This can more clearly be thought of as 'ms' as the top 16 bits, and a
12743          codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12744          is big-endian).
12745        */
12746       if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12747         if (len < offset + 20) {
12748           GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12749         } else {
12750           guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12751           const guint8 *data = stsd_entry_data + offset + 16;
12752           GNode *wavenode;
12753           GNode *waveheadernode;
12754 
12755           wavenode = g_node_new ((guint8 *) data);
12756           if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12757             const guint8 *waveheader;
12758             guint32 headerlen;
12759 
12760             waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12761             if (waveheadernode) {
12762               waveheader = (const guint8 *) waveheadernode->data;
12763               headerlen = QT_UINT32 (waveheader);
12764 
12765               if (headerlen > 8) {
12766                 gst_riff_strf_auds *header = NULL;
12767                 GstBuffer *headerbuf;
12768                 GstBuffer *extra;
12769 
12770                 waveheader += 8;
12771                 headerlen -= 8;
12772 
12773                 headerbuf = gst_buffer_new_and_alloc (headerlen);
12774                 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12775 
12776                 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12777                         headerbuf, &header, &extra)) {
12778                   gst_caps_unref (entry->caps);
12779                   /* FIXME: Need to do something with the channel reorder map */
12780                   entry->caps =
12781                       gst_riff_create_audio_caps (header->format, NULL, header,
12782                       extra, NULL, NULL, NULL);
12783 
12784                   if (extra)
12785                     gst_buffer_unref (extra);
12786                   g_free (header);
12787                 }
12788               }
12789             } else
12790               GST_DEBUG ("Didn't find waveheadernode for this codec");
12791           }
12792           g_node_destroy (wavenode);
12793         }
12794       } else if (esds) {
12795         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12796             stream->stream_tags);
12797       } else {
12798         switch (fourcc) {
12799 #if 0
12800             /* FIXME: what is in the chunk? */
12801           case FOURCC_QDMC:
12802           {
12803             gint len = QT_UINT32 (stsd_data);
12804 
12805             /* seems to be always = 116 = 0x74 */
12806             break;
12807           }
12808 #endif
12809           case FOURCC_QDM2:
12810           {
12811             gint len = QT_UINT32 (stsd_entry_data);
12812 
12813             if (len > 0x3C) {
12814               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12815 
12816               gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12817               gst_caps_set_simple (entry->caps,
12818                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12819               gst_buffer_unref (buf);
12820             }
12821             gst_caps_set_simple (entry->caps,
12822                 "samplesize", G_TYPE_INT, samplesize, NULL);
12823             break;
12824           }
12825           case FOURCC_alac:
12826           {
12827             GNode *alac, *wave = NULL;
12828 
12829             /* apparently, m4a has this atom appended directly in the stsd entry,
12830              * while mov has it in a wave atom */
12831             alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12832             if (alac) {
12833               /* alac now refers to stsd entry atom */
12834               wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12835               if (wave)
12836                 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12837               else
12838                 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12839             }
12840             if (alac) {
12841               const guint8 *alac_data = alac->data;
12842               gint len = QT_UINT32 (alac->data);
12843               GstBuffer *buf;
12844 
12845               if (len < 36) {
12846                 GST_DEBUG_OBJECT (qtdemux,
12847                     "discarding alac atom with unexpected len %d", len);
12848               } else {
12849                 /* codec-data contains alac atom size and prefix,
12850                  * ffmpeg likes it that way, not quite gst-ish though ...*/
12851                 buf = gst_buffer_new_and_alloc (len);
12852                 gst_buffer_fill (buf, 0, alac->data, len);
12853                 gst_caps_set_simple (entry->caps,
12854                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12855                 gst_buffer_unref (buf);
12856 
12857                 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12858                 entry->n_channels = QT_UINT8 (alac_data + 21);
12859                 entry->rate = QT_UINT32 (alac_data + 32);
12860                 samplesize = QT_UINT8 (alac_data + 16 + 1);
12861               }
12862             }
12863             gst_caps_set_simple (entry->caps,
12864                 "samplesize", G_TYPE_INT, samplesize, NULL);
12865             break;
12866           }
12867           case FOURCC_fLaC:
12868           {
12869             /* The codingname of the sample entry is 'fLaC' */
12870             GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12871 
12872             if (flac) {
12873               /* The 'dfLa' box is added to the sample entry to convey
12874                  initializing information for the decoder. */
12875               const GNode *dfla =
12876                   qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12877 
12878               if (dfla) {
12879                 const guint32 len = QT_UINT32 (dfla->data);
12880 
12881                 /* Must contain at least dfLa box header (12),
12882                  * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12883                 if (len < 50) {
12884                   GST_DEBUG_OBJECT (qtdemux,
12885                       "discarding dfla atom with unexpected len %d", len);
12886                 } else {
12887                   /* skip dfLa header to get the METADATA_BLOCKs */
12888                   const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12889                   const guint32 metadata_blocks_len = len - 12;
12890 
12891                   gchar *stream_marker = g_strdup ("fLaC");
12892                   GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12893                       strlen (stream_marker));
12894 
12895                   guint32 index = 0;
12896                   guint32 remainder = 0;
12897                   guint32 block_size = 0;
12898                   gboolean is_last = FALSE;
12899 
12900                   GValue array = G_VALUE_INIT;
12901                   GValue value = G_VALUE_INIT;
12902 
12903                   g_value_init (&array, GST_TYPE_ARRAY);
12904                   g_value_init (&value, GST_TYPE_BUFFER);
12905 
12906                   gst_value_set_buffer (&value, block);
12907                   gst_value_array_append_value (&array, &value);
12908                   g_value_reset (&value);
12909 
12910                   gst_buffer_unref (block);
12911 
12912                   /* check there's at least one METADATA_BLOCK_HEADER's worth
12913                    * of data, and we haven't already finished parsing */
12914                   while (!is_last && ((index + 3) < metadata_blocks_len)) {
12915                     remainder = metadata_blocks_len - index;
12916 
12917                     /* add the METADATA_BLOCK_HEADER size to the signalled size */
12918                     block_size = 4 +
12919                         (metadata_blocks[index + 1] << 16) +
12920                         (metadata_blocks[index + 2] << 8) +
12921                         metadata_blocks[index + 3];
12922 
12923                     /* be careful not to read off end of box */
12924                     if (block_size > remainder) {
12925                       break;
12926                     }
12927 
12928                     is_last = metadata_blocks[index] >> 7;
12929 
12930                     block = gst_buffer_new_and_alloc (block_size);
12931 
12932                     gst_buffer_fill (block, 0, &metadata_blocks[index],
12933                         block_size);
12934 
12935                     gst_value_set_buffer (&value, block);
12936                     gst_value_array_append_value (&array, &value);
12937                     g_value_reset (&value);
12938 
12939                     gst_buffer_unref (block);
12940 
12941                     index += block_size;
12942                   }
12943 
12944                   /* only append the metadata if we successfully read all of it */
12945                   if (is_last) {
12946                     gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12947                             (stream)->caps, 0), "streamheader", &array);
12948                   } else {
12949                     GST_WARNING_OBJECT (qtdemux,
12950                         "discarding all METADATA_BLOCKs due to invalid "
12951                         "block_size %d at idx %d, rem %d", block_size, index,
12952                         remainder);
12953                   }
12954 
12955                   g_value_unset (&value);
12956                   g_value_unset (&array);
12957 
12958                   /* The sample rate obtained from the stsd may not be accurate
12959                    * since it cannot represent rates greater than 65535Hz, so
12960                    * override that value with the sample rate from the
12961                    * METADATA_BLOCK_STREAMINFO block */
12962                   CUR_STREAM (stream)->rate =
12963                       (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12964                 }
12965               }
12966             }
12967             break;
12968           }
12969           case FOURCC_sawb:
12970             /* Fallthrough! */
12971             amrwb = TRUE;
12972           case FOURCC_samr:
12973           {
12974             gint len = QT_UINT32 (stsd_entry_data);
12975 
12976             if (len > 0x24) {
12977               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12978               guint bitrate;
12979 
12980               gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12981 
12982               /* If we have enough data, let's try to get the 'damr' atom. See
12983                * the 3GPP container spec (26.244) for more details. */
12984               if ((len - 0x34) > 8 &&
12985                   (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12986                 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12987                     GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12988               }
12989 
12990               gst_caps_set_simple (entry->caps,
12991                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12992               gst_buffer_unref (buf);
12993             }
12994             break;
12995           }
12996           case FOURCC_mp4a:
12997           {
12998             /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12999             gint len = QT_UINT32 (stsd_entry_data);
13000             guint16 sound_version = 0;
13001             /* FIXME: Can this be determined somehow? There doesn't seem to be
13002              * anything in mp4a atom that specifis compression */
13003             gint profile = 2;
13004             guint16 channels = entry->n_channels;
13005             guint32 time_scale = (guint32) entry->rate;
13006             gint sample_rate_index = -1;
13007 
13008             if (len >= 34) {
13009               sound_version = QT_UINT16 (stsd_entry_data + 16);
13010 
13011               if (sound_version == 1) {
13012                 channels = QT_UINT16 (stsd_entry_data + 24);
13013                 time_scale = QT_UINT32 (stsd_entry_data + 30);
13014               } else {
13015                 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
13016                     sound_version);
13017               }
13018             } else {
13019               GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
13020                   len);
13021             }
13022 
13023             sample_rate_index =
13024                 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13025             if (sample_rate_index >= 0 && channels > 0) {
13026               guint8 codec_data[2];
13027               GstBuffer *buf;
13028 
13029               /* build AAC codec data */
13030               codec_data[0] = profile << 3;
13031               codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13032               codec_data[1] = (sample_rate_index & 0x01) << 7;
13033               codec_data[1] |= (channels & 0xF) << 3;
13034 
13035               buf = gst_buffer_new_and_alloc (2);
13036               gst_buffer_fill (buf, 0, codec_data, 2);
13037               gst_caps_set_simple (entry->caps,
13038                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
13039               gst_buffer_unref (buf);
13040             }
13041             break;
13042           }
13043           case FOURCC_lpcm:
13044           case FOURCC_in24:
13045           case FOURCC_in32:
13046           case FOURCC_fl32:
13047           case FOURCC_fl64:
13048           case FOURCC_s16l:
13049             /* Fully handled elsewhere */
13050             break;
13051           default:
13052             GST_INFO_OBJECT (qtdemux,
13053                 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13054             break;
13055         }
13056       }
13057       GST_INFO_OBJECT (qtdemux,
13058           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13059           GST_FOURCC_ARGS (fourcc), entry->caps);
13060 
13061     } else if (stream->subtype == FOURCC_strm) {
13062       if (fourcc == FOURCC_rtsp) {
13063         stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13064       } else {
13065         GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13066             GST_FOURCC_ARGS (fourcc));
13067         goto unknown_stream;
13068       }
13069       entry->sampled = TRUE;
13070     } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13071         || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13072         || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13073 
13074       entry->sampled = TRUE;
13075       entry->sparse = TRUE;
13076 
13077       entry->caps =
13078           qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13079           &codec);
13080       if (codec) {
13081         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13082             GST_TAG_SUBTITLE_CODEC, codec, NULL);
13083         g_free (codec);
13084         codec = NULL;
13085       }
13086 
13087       /* hunt for sort-of codec data */
13088       switch (fourcc) {
13089         case FOURCC_mp4s:
13090         {
13091           GNode *mp4s = NULL;
13092           GNode *esds = NULL;
13093 
13094           /* look for palette in a stsd->mp4s->esds sub-atom */
13095           mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13096           if (mp4s)
13097             esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13098           if (esds == NULL) {
13099             /* Invalid STSD */
13100             GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13101             break;
13102           }
13103 
13104           gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13105               stream->stream_tags);
13106           break;
13107         }
13108         default:
13109           GST_INFO_OBJECT (qtdemux,
13110               "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13111           break;
13112       }
13113       GST_INFO_OBJECT (qtdemux,
13114           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13115           GST_FOURCC_ARGS (fourcc), entry->caps);
13116     } else {
13117       /* everything in 1 sample */
13118       entry->sampled = TRUE;
13119 
13120       entry->caps =
13121           qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13122           &codec);
13123 
13124       if (entry->caps == NULL)
13125         goto unknown_stream;
13126 
13127       if (codec) {
13128         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13129             GST_TAG_SUBTITLE_CODEC, codec, NULL);
13130         g_free (codec);
13131         codec = NULL;
13132       }
13133     }
13134 
13135     /* promote to sampled format */
13136     if (entry->fourcc == FOURCC_samr) {
13137       /* force mono 8000 Hz for AMR */
13138       entry->sampled = TRUE;
13139       entry->n_channels = 1;
13140       entry->rate = 8000;
13141     } else if (entry->fourcc == FOURCC_sawb) {
13142       /* force mono 16000 Hz for AMR-WB */
13143       entry->sampled = TRUE;
13144       entry->n_channels = 1;
13145       entry->rate = 16000;
13146     } else if (entry->fourcc == FOURCC_mp4a) {
13147       entry->sampled = TRUE;
13148     }
13149 
13150 
13151     stsd_entry_data += len;
13152     remaining_stsd_len -= len;
13153 
13154   }
13155 
13156   /* collect sample information */
13157   if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13158     goto samples_failed;
13159 
13160   if (qtdemux->fragmented) {
13161     guint64 offset;
13162 
13163     /* need all moov samples as basis; probably not many if any at all */
13164     /* prevent moof parsing taking of at this time */
13165     offset = qtdemux->moof_offset;
13166     qtdemux->moof_offset = 0;
13167     if (stream->n_samples &&
13168         !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13169       qtdemux->moof_offset = offset;
13170       goto samples_failed;
13171     }
13172     qtdemux->moof_offset = offset;
13173     /* movie duration more reliable in this case (e.g. mehd) */
13174     if (qtdemux->segment.duration &&
13175         GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13176       stream->duration =
13177           GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13178   }
13179 
13180   /* configure segments */
13181   if (!qtdemux_parse_segments (qtdemux, stream, trak))
13182     goto segments_failed;
13183 
13184   /* add some language tag, if useful */
13185   if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13186       strcmp (stream->lang_id, "und")) {
13187     const gchar *lang_code;
13188 
13189     /* convert ISO 639-2 code to ISO 639-1 */
13190     lang_code = gst_tag_get_language_code (stream->lang_id);
13191     gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13192         GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13193   }
13194 
13195   /* Check for UDTA tags */
13196   if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13197     qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13198   }
13199 
13200   /* Insert and sort new stream in track-id order.
13201    * This will help in comparing old/new streams during stream update check */
13202   g_ptr_array_add (qtdemux->active_streams, stream);
13203   g_ptr_array_sort (qtdemux->active_streams,
13204       (GCompareFunc) qtdemux_track_id_compare_func);
13205   GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13206       QTDEMUX_N_STREAMS (qtdemux));
13207 
13208   return TRUE;
13209 
13210 /* ERRORS */
13211 corrupt_file:
13212   {
13213     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13214         (_("This file is corrupt and cannot be played.")), (NULL));
13215     if (stream)
13216       gst_qtdemux_stream_unref (stream);
13217     return FALSE;
13218   }
13219 error_encrypted:
13220   {
13221     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13222     gst_qtdemux_stream_unref (stream);
13223     return FALSE;
13224   }
13225 samples_failed:
13226 segments_failed:
13227   {
13228     /* we posted an error already */
13229     /* free stbl sub-atoms */
13230     gst_qtdemux_stbl_free (stream);
13231     gst_qtdemux_stream_unref (stream);
13232     return FALSE;
13233   }
13234 existing_stream:
13235   {
13236     GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13237         track_id);
13238     return TRUE;
13239   }
13240 unknown_stream:
13241   {
13242     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13243         GST_FOURCC_ARGS (stream->subtype));
13244     gst_qtdemux_stream_unref (stream);
13245     return TRUE;
13246   }
13247 }
13248 
13249 /* If we can estimate the overall bitrate, and don't have information about the
13250  * stream bitrate for exactly one stream, this guesses the stream bitrate as
13251  * the overall bitrate minus the sum of the bitrates of all other streams. This
13252  * should be useful for the common case where we have one audio and one video
13253  * stream and can estimate the bitrate of one, but not the other. */
13254 static void
gst_qtdemux_guess_bitrate(GstQTDemux * qtdemux)13255 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13256 {
13257   QtDemuxStream *stream = NULL;
13258   gint64 size, sys_bitrate, sum_bitrate = 0;
13259   GstClockTime duration;
13260   guint bitrate;
13261   gint i;
13262 
13263   if (qtdemux->fragmented)
13264     return;
13265 
13266   GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13267 
13268   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13269       || size <= 0) {
13270     GST_DEBUG_OBJECT (qtdemux,
13271         "Size in bytes of the stream not known - bailing");
13272     return;
13273   }
13274 
13275   /* Subtract the header size */
13276   GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13277       size, qtdemux->header_size);
13278 
13279   if (size < qtdemux->header_size)
13280     return;
13281 
13282   size = size - qtdemux->header_size;
13283 
13284   if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13285     GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13286     return;
13287   }
13288 
13289   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13290     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13291     switch (str->subtype) {
13292       case FOURCC_soun:
13293       case FOURCC_vide:
13294         GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13295             CUR_STREAM (str)->caps);
13296         /* retrieve bitrate, prefer avg then max */
13297         bitrate = 0;
13298         if (str->stream_tags) {
13299           if (gst_tag_list_get_uint (str->stream_tags,
13300                   GST_TAG_MAXIMUM_BITRATE, &bitrate))
13301             GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13302           if (gst_tag_list_get_uint (str->stream_tags,
13303                   GST_TAG_NOMINAL_BITRATE, &bitrate))
13304             GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13305           if (gst_tag_list_get_uint (str->stream_tags,
13306                   GST_TAG_BITRATE, &bitrate))
13307             GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13308         }
13309         if (bitrate)
13310           sum_bitrate += bitrate;
13311         else {
13312           if (stream) {
13313             GST_DEBUG_OBJECT (qtdemux,
13314                 ">1 stream with unknown bitrate - bailing");
13315             return;
13316           } else
13317             stream = str;
13318         }
13319 
13320       default:
13321         /* For other subtypes, we assume no significant impact on bitrate */
13322         break;
13323     }
13324   }
13325 
13326   if (!stream) {
13327     GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13328     return;
13329   }
13330 
13331   sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13332 
13333   if (sys_bitrate < sum_bitrate) {
13334     /* This can happen, since sum_bitrate might be derived from maximum
13335      * bitrates and not average bitrates */
13336     GST_DEBUG_OBJECT (qtdemux,
13337         "System bitrate less than sum bitrate - bailing");
13338     return;
13339   }
13340 
13341   bitrate = sys_bitrate - sum_bitrate;
13342   GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13343       ", Stream bitrate = %u", sys_bitrate, bitrate);
13344 
13345   if (!stream->stream_tags)
13346     stream->stream_tags = gst_tag_list_new_empty ();
13347   else
13348     stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13349 
13350   gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13351       GST_TAG_BITRATE, bitrate, NULL);
13352 }
13353 
13354 static GstFlowReturn
qtdemux_prepare_streams(GstQTDemux * qtdemux)13355 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13356 {
13357   GstFlowReturn ret = GST_FLOW_OK;
13358   gint i;
13359 
13360   GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13361 
13362   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13363     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13364     guint32 sample_num = 0;
13365 
13366     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13367         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13368 
13369     if (qtdemux->fragmented && qtdemux->pullbased) {
13370       /* need all moov samples first */
13371       GST_OBJECT_LOCK (qtdemux);
13372       while (stream->n_samples == 0)
13373         if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13374           break;
13375       GST_OBJECT_UNLOCK (qtdemux);
13376     } else {
13377       /* discard any stray moof */
13378       qtdemux->moof_offset = 0;
13379     }
13380 
13381     /* prepare braking */
13382     if (ret != GST_FLOW_ERROR)
13383       ret = GST_FLOW_OK;
13384 
13385     /* in pull mode, we should have parsed some sample info by now;
13386      * and quite some code will not handle no samples.
13387      * in push mode, we'll just have to deal with it */
13388     if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13389       GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13390       g_ptr_array_remove_index (qtdemux->active_streams, i);
13391       i--;
13392       continue;
13393     } else if (stream->track_id == qtdemux->chapters_track_id &&
13394         (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13395       /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13396          so that it doesn't look like a subtitle track */
13397       g_ptr_array_remove_index (qtdemux->active_streams, i);
13398       i--;
13399       continue;
13400     }
13401 
13402     /* parse the initial sample for use in setting the frame rate cap */
13403     while (sample_num == 0 && sample_num < stream->n_samples) {
13404       if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13405         break;
13406       ++sample_num;
13407     }
13408   }
13409 
13410   return ret;
13411 }
13412 
13413 static gboolean
_stream_equal_func(const QtDemuxStream * stream,const gchar * stream_id)13414 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13415 {
13416   return g_strcmp0 (stream->stream_id, stream_id) == 0;
13417 }
13418 
13419 static gboolean
qtdemux_is_streams_update(GstQTDemux * qtdemux)13420 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13421 {
13422   gint i;
13423 
13424   /* Different length, updated */
13425   if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13426     return TRUE;
13427 
13428   /* streams in list are sorted in track-id order */
13429   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13430     /* Different stream-id, updated */
13431     if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13432             QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13433       return TRUE;
13434   }
13435 
13436   return FALSE;
13437 }
13438 
13439 static gboolean
qtdemux_reuse_and_configure_stream(GstQTDemux * qtdemux,QtDemuxStream * oldstream,QtDemuxStream * newstream)13440 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13441     QtDemuxStream * oldstream, QtDemuxStream * newstream)
13442 {
13443   /* Connect old stream's srcpad to new stream */
13444   newstream->pad = oldstream->pad;
13445   oldstream->pad = NULL;
13446 
13447   /* unset new_stream to prevent stream-start event, unless we are EOS in which
13448    * case we need to force one through */
13449   newstream->new_stream = GST_PAD_IS_EOS (newstream->pad);
13450 
13451   return gst_qtdemux_configure_stream (qtdemux, newstream);
13452 }
13453 
13454 static gboolean
qtdemux_update_streams(GstQTDemux * qtdemux)13455 qtdemux_update_streams (GstQTDemux * qtdemux)
13456 {
13457   gint i;
13458   g_assert (qtdemux->streams_aware);
13459 
13460   /* At below, figure out which stream in active_streams has identical stream-id
13461    * with that of in old_streams. If there is matching stream-id,
13462    * corresponding newstream will not be exposed again,
13463    * but demux will reuse srcpad of matched old stream
13464    *
13465    * active_streams : newly created streams from the latest moov
13466    * old_streams : existing streams (belong to previous moov)
13467    */
13468 
13469   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13470     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13471     QtDemuxStream *oldstream = NULL;
13472     guint target;
13473 
13474     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13475         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13476 
13477     if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13478             stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13479       oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13480 
13481       /* null pad stream cannot be reused */
13482       if (oldstream->pad == NULL)
13483         oldstream = NULL;
13484     }
13485 
13486     if (oldstream) {
13487       GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13488 
13489       if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13490         return FALSE;
13491 
13492       /* we don't need to preserve order of old streams */
13493       g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13494     } else {
13495       GstTagList *list;
13496 
13497       /* now we have all info and can expose */
13498       list = stream->stream_tags;
13499       stream->stream_tags = NULL;
13500       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13501         return FALSE;
13502     }
13503   }
13504 
13505   return TRUE;
13506 }
13507 
13508 /* Must be called with expose lock */
13509 static GstFlowReturn
qtdemux_expose_streams(GstQTDemux * qtdemux)13510 qtdemux_expose_streams (GstQTDemux * qtdemux)
13511 {
13512   gint i;
13513 
13514   GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13515 
13516   if (!qtdemux_is_streams_update (qtdemux)) {
13517     GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13518     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13519       QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13520       QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13521       if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13522         return GST_FLOW_ERROR;
13523     }
13524 
13525     g_ptr_array_set_size (qtdemux->old_streams, 0);
13526     qtdemux->need_segment = TRUE;
13527 
13528     return GST_FLOW_OK;
13529   }
13530 
13531   if (qtdemux->streams_aware) {
13532     if (!qtdemux_update_streams (qtdemux))
13533       return GST_FLOW_ERROR;
13534   } else {
13535     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13536       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13537       GstTagList *list;
13538 
13539       /* now we have all info and can expose */
13540       list = stream->stream_tags;
13541       stream->stream_tags = NULL;
13542       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13543         return GST_FLOW_ERROR;
13544 
13545     }
13546   }
13547 
13548   gst_qtdemux_guess_bitrate (qtdemux);
13549 
13550   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13551 
13552   /* If we have still old_streams, it's no more used stream */
13553   for (i = 0; i < qtdemux->old_streams->len; i++) {
13554     QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13555 
13556     if (stream->pad) {
13557       GstEvent *event;
13558 
13559       event = gst_event_new_eos ();
13560       if (qtdemux->segment_seqnum)
13561         gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13562 
13563       gst_pad_push_event (stream->pad, event);
13564     }
13565   }
13566 
13567   g_ptr_array_set_size (qtdemux->old_streams, 0);
13568 
13569   /* check if we should post a redirect in case there is a single trak
13570    * and it is a redirecting trak */
13571   if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13572       QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13573     GstMessage *m;
13574 
13575     GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13576         "an external content");
13577     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13578         gst_structure_new ("redirect",
13579             "new-location", G_TYPE_STRING,
13580             QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13581     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13582     g_free (qtdemux->redirect_location);
13583     qtdemux->redirect_location =
13584         g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13585   }
13586 
13587   g_ptr_array_foreach (qtdemux->active_streams,
13588       (GFunc) qtdemux_do_allocation, qtdemux);
13589 
13590   qtdemux->need_segment = TRUE;
13591 
13592   qtdemux->exposed = TRUE;
13593   return GST_FLOW_OK;
13594 }
13595 
13596 typedef struct
13597 {
13598   GstStructure *structure;      /* helper for sort function */
13599   gchar *location;
13600   guint min_req_bitrate;
13601   guint min_req_qt_version;
13602 } GstQtReference;
13603 
13604 static gint
qtdemux_redirects_sort_func(gconstpointer a,gconstpointer b)13605 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13606 {
13607   GstQtReference *ref_a = (GstQtReference *) a;
13608   GstQtReference *ref_b = (GstQtReference *) b;
13609 
13610   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13611     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13612 
13613   /* known bitrates go before unknown; higher bitrates go first */
13614   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13615 }
13616 
13617 /* sort the redirects and post a message for the application.
13618  */
13619 static void
qtdemux_process_redirects(GstQTDemux * qtdemux,GList * references)13620 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13621 {
13622   GstQtReference *best;
13623   GstStructure *s;
13624   GstMessage *msg;
13625   GValue list_val = { 0, };
13626   GList *l;
13627 
13628   g_assert (references != NULL);
13629 
13630   references = g_list_sort (references, qtdemux_redirects_sort_func);
13631 
13632   best = (GstQtReference *) references->data;
13633 
13634   g_value_init (&list_val, GST_TYPE_LIST);
13635 
13636   for (l = references; l != NULL; l = l->next) {
13637     GstQtReference *ref = (GstQtReference *) l->data;
13638     GValue struct_val = { 0, };
13639 
13640     ref->structure = gst_structure_new ("redirect",
13641         "new-location", G_TYPE_STRING, ref->location, NULL);
13642 
13643     if (ref->min_req_bitrate > 0) {
13644       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13645           ref->min_req_bitrate, NULL);
13646     }
13647 
13648     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13649     g_value_set_boxed (&struct_val, ref->structure);
13650     gst_value_list_append_value (&list_val, &struct_val);
13651     g_value_unset (&struct_val);
13652     /* don't free anything here yet, since we need best->structure below */
13653   }
13654 
13655   g_assert (best != NULL);
13656   s = gst_structure_copy (best->structure);
13657 
13658   if (g_list_length (references) > 1) {
13659     gst_structure_set_value (s, "locations", &list_val);
13660   }
13661 
13662   g_value_unset (&list_val);
13663 
13664   for (l = references; l != NULL; l = l->next) {
13665     GstQtReference *ref = (GstQtReference *) l->data;
13666 
13667     gst_structure_free (ref->structure);
13668     g_free (ref->location);
13669     g_free (ref);
13670   }
13671   g_list_free (references);
13672 
13673   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13674   g_free (qtdemux->redirect_location);
13675   qtdemux->redirect_location =
13676       g_strdup (gst_structure_get_string (s, "new-location"));
13677   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13678   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13679 }
13680 
13681 /* look for redirect nodes, collect all redirect information and
13682  * process it.
13683  */
13684 static gboolean
qtdemux_parse_redirects(GstQTDemux * qtdemux)13685 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13686 {
13687   GNode *rmra, *rmda, *rdrf;
13688 
13689   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13690   if (rmra) {
13691     GList *redirects = NULL;
13692 
13693     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13694     while (rmda) {
13695       GstQtReference ref = { NULL, NULL, 0, 0 };
13696       GNode *rmdr, *rmvc;
13697 
13698       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13699         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13700         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13701             ref.min_req_bitrate);
13702       }
13703 
13704       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13705         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13706         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13707 
13708 #ifndef GST_DISABLE_GST_DEBUG
13709         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13710 #endif
13711         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13712 
13713         GST_LOG_OBJECT (qtdemux,
13714             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13715             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13716             bitmask, check_type);
13717         if (package == FOURCC_qtim && check_type == 0) {
13718           ref.min_req_qt_version = version;
13719         }
13720       }
13721 
13722       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13723       if (rdrf) {
13724         guint32 ref_type;
13725         guint8 *ref_data;
13726         guint ref_len;
13727 
13728         ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13729         if (ref_len > 20) {
13730           ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13731           ref_data = (guint8 *) rdrf->data + 20;
13732           if (ref_type == FOURCC_alis) {
13733             guint record_len, record_version, fn_len;
13734 
13735             if (ref_len > 70) {
13736               /* MacOSX alias record, google for alias-layout.txt */
13737               record_len = QT_UINT16 (ref_data + 4);
13738               record_version = QT_UINT16 (ref_data + 4 + 2);
13739               fn_len = QT_UINT8 (ref_data + 50);
13740               if (record_len > 50 && record_version == 2 && fn_len > 0) {
13741                 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13742               }
13743             } else {
13744               GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13745                   ref_len);
13746             }
13747           } else if (ref_type == FOURCC_url_) {
13748             ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13749           } else {
13750             GST_DEBUG_OBJECT (qtdemux,
13751                 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13752                 GST_FOURCC_ARGS (ref_type));
13753           }
13754           if (ref.location != NULL) {
13755             GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13756             redirects =
13757                 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13758           } else {
13759             GST_WARNING_OBJECT (qtdemux,
13760                 "Failed to extract redirect location from rdrf atom");
13761           }
13762         } else {
13763           GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13764         }
13765       }
13766 
13767       /* look for others */
13768       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13769     }
13770 
13771     if (redirects != NULL) {
13772       qtdemux_process_redirects (qtdemux, redirects);
13773     }
13774   }
13775   return TRUE;
13776 }
13777 
13778 static GstTagList *
qtdemux_add_container_format(GstQTDemux * qtdemux,GstTagList * tags)13779 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13780 {
13781   const gchar *fmt;
13782 
13783   if (tags == NULL) {
13784     tags = gst_tag_list_new_empty ();
13785     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13786   }
13787 
13788   if (qtdemux->major_brand == FOURCC_mjp2)
13789     fmt = "Motion JPEG 2000";
13790   else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13791     fmt = "3GP";
13792   else if (qtdemux->major_brand == FOURCC_qt__)
13793     fmt = "Quicktime";
13794   else if (qtdemux->fragmented)
13795     fmt = "ISO fMP4";
13796   else
13797     fmt = "ISO MP4/M4A";
13798 
13799   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13800       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13801 
13802   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13803       fmt, NULL);
13804 
13805   return tags;
13806 }
13807 
13808 /* we have read the complete moov node now.
13809  * This function parses all of the relevant info, creates the traks and
13810  * prepares all data structures for playback
13811  */
13812 static gboolean
qtdemux_parse_tree(GstQTDemux * qtdemux)13813 qtdemux_parse_tree (GstQTDemux * qtdemux)
13814 {
13815   GNode *mvhd;
13816   GNode *trak;
13817   GNode *udta;
13818   GNode *mvex;
13819   GNode *pssh;
13820   guint64 creation_time;
13821   GstDateTime *datetime = NULL;
13822   gint version;
13823 
13824   /* make sure we have a usable taglist */
13825   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13826 
13827   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13828   if (mvhd == NULL) {
13829     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13830     return qtdemux_parse_redirects (qtdemux);
13831   }
13832 
13833   version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13834   if (version == 1) {
13835     creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13836     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13837     qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13838   } else if (version == 0) {
13839     creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13840     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13841     qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13842   } else {
13843     GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13844     return FALSE;
13845   }
13846 
13847   /* Moving qt creation time (secs since 1904) to unix time */
13848   if (creation_time != 0) {
13849     /* Try to use epoch first as it should be faster and more commonly found */
13850     if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13851       gint64 now_s;
13852 
13853       creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13854       /* some data cleansing sanity */
13855       now_s = g_get_real_time () / G_USEC_PER_SEC;
13856       if (now_s + 24 * 3600 < creation_time) {
13857         GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13858       } else {
13859         datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13860       }
13861     } else {
13862       GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13863       GDateTime *dt, *dt_local;
13864 
13865       dt = g_date_time_add_seconds (base_dt, creation_time);
13866       dt_local = g_date_time_to_local (dt);
13867       datetime = gst_date_time_new_from_g_date_time (dt_local);
13868 
13869       g_date_time_unref (base_dt);
13870       g_date_time_unref (dt);
13871     }
13872   }
13873   if (datetime) {
13874     /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13875     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13876         datetime, NULL);
13877     gst_date_time_unref (datetime);
13878   }
13879 
13880   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13881   GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13882 
13883   /* check for fragmented file and get some (default) data */
13884   mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13885   if (mvex) {
13886     GNode *mehd;
13887     GstByteReader mehd_data;
13888 
13889     /* let track parsing or anyone know weird stuff might happen ... */
13890     qtdemux->fragmented = TRUE;
13891 
13892     /* compensate for total duration */
13893     mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13894     if (mehd)
13895       qtdemux_parse_mehd (qtdemux, &mehd_data);
13896   }
13897 
13898   /* Update the movie segment duration, unless it was directly given to us
13899    * by upstream. Otherwise let it as is, as we don't want to mangle the
13900    * duration provided by upstream that may come e.g. from a MPD file. */
13901   if (!qtdemux->upstream_format_is_time) {
13902     GstClockTime duration;
13903     /* set duration in the segment info */
13904     gst_qtdemux_get_duration (qtdemux, &duration);
13905     qtdemux->segment.duration = duration;
13906     /* also do not exceed duration; stop is set that way post seek anyway,
13907      * and segment activation falls back to duration,
13908      * whereas loop only checks stop, so let's align this here as well */
13909     qtdemux->segment.stop = duration;
13910   }
13911 
13912   /* parse all traks */
13913   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13914   while (trak) {
13915     qtdemux_parse_trak (qtdemux, trak);
13916     /* iterate all siblings */
13917     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13918   }
13919 
13920   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13921 
13922   /* find tags */
13923   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13924   if (udta) {
13925     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13926   } else {
13927     GST_LOG_OBJECT (qtdemux, "No udta node found.");
13928   }
13929 
13930   /* maybe also some tags in meta box */
13931   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13932   if (udta) {
13933     GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13934     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13935   } else {
13936     GST_LOG_OBJECT (qtdemux, "No meta node found.");
13937   }
13938 
13939   /* parse any protection system info */
13940   pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13941   while (pssh) {
13942     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13943     qtdemux_parse_pssh (qtdemux, pssh);
13944     pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13945   }
13946 
13947   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13948 
13949   return TRUE;
13950 }
13951 
13952 /* taken from ffmpeg */
13953 static int
read_descr_size(guint8 * ptr,guint8 * end,guint8 ** end_out)13954 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13955 {
13956   int count = 4;
13957   int len = 0;
13958 
13959   while (count--) {
13960     int c;
13961 
13962     if (ptr >= end)
13963       return -1;
13964 
13965     c = *ptr++;
13966     len = (len << 7) | (c & 0x7f);
13967     if (!(c & 0x80))
13968       break;
13969   }
13970   *end_out = ptr;
13971   return len;
13972 }
13973 
13974 static GList *
parse_xiph_stream_headers(GstQTDemux * qtdemux,gpointer codec_data,gsize codec_data_size)13975 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13976     gsize codec_data_size)
13977 {
13978   GList *list = NULL;
13979   guint8 *p = codec_data;
13980   gint i, offset, num_packets;
13981   guint *length, last;
13982 
13983   GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13984 
13985   if (codec_data == NULL || codec_data_size == 0)
13986     goto error;
13987 
13988   /* start of the stream and vorbis audio or theora video, need to
13989    * send the codec_priv data as first three packets */
13990   num_packets = p[0] + 1;
13991   GST_DEBUG_OBJECT (qtdemux,
13992       "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13993       (guint) num_packets, codec_data_size);
13994 
13995   /* Let's put some limits, Don't think there even is a xiph codec
13996    * with more than 3-4 headers */
13997   if (G_UNLIKELY (num_packets > 16)) {
13998     GST_WARNING_OBJECT (qtdemux,
13999         "Unlikely number of xiph headers, most likely not valid");
14000     goto error;
14001   }
14002 
14003   length = g_alloca (num_packets * sizeof (guint));
14004   last = 0;
14005   offset = 1;
14006 
14007   /* first packets, read length values */
14008   for (i = 0; i < num_packets - 1; i++) {
14009     length[i] = 0;
14010     while (offset < codec_data_size) {
14011       length[i] += p[offset];
14012       if (p[offset++] != 0xff)
14013         break;
14014     }
14015     last += length[i];
14016   }
14017   if (offset + last > codec_data_size)
14018     goto error;
14019 
14020   /* last packet is the remaining size */
14021   length[i] = codec_data_size - offset - last;
14022 
14023   for (i = 0; i < num_packets; i++) {
14024     GstBuffer *hdr;
14025 
14026     GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14027 
14028     if (offset + length[i] > codec_data_size)
14029       goto error;
14030 
14031     hdr = gst_buffer_new_memdup (p + offset, length[i]);
14032     list = g_list_append (list, hdr);
14033 
14034     offset += length[i];
14035   }
14036 
14037   return list;
14038 
14039   /* ERRORS */
14040 error:
14041   {
14042     if (list != NULL)
14043       g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14044     return NULL;
14045   }
14046 
14047 }
14048 
14049 /* this can change the codec originally present in @list */
14050 static void
gst_qtdemux_handle_esds(GstQTDemux * qtdemux,QtDemuxStream * stream,QtDemuxStreamStsdEntry * entry,GNode * esds,GstTagList * list)14051 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14052     QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14053 {
14054   int len = QT_UINT32 (esds->data);
14055   guint8 *ptr = esds->data;
14056   guint8 *end = ptr + len;
14057   int tag;
14058   guint8 *data_ptr = NULL;
14059   int data_len = 0;
14060   guint8 object_type_id = 0;
14061   guint8 stream_type = 0;
14062   const char *codec_name = NULL;
14063   GstCaps *caps = NULL;
14064 
14065   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14066   ptr += 8;
14067   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14068   ptr += 4;
14069   while (ptr + 1 < end) {
14070     tag = QT_UINT8 (ptr);
14071     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14072     ptr++;
14073     len = read_descr_size (ptr, end, &ptr);
14074     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14075 
14076     /* Check the stated amount of data is available for reading */
14077     if (len < 0 || ptr + len > end)
14078       break;
14079 
14080     switch (tag) {
14081       case ES_DESCRIPTOR_TAG:
14082         GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14083         GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14084         ptr += 3;
14085         break;
14086       case DECODER_CONFIG_DESC_TAG:{
14087         guint max_bitrate, avg_bitrate;
14088 
14089         object_type_id = QT_UINT8 (ptr);
14090         stream_type = QT_UINT8 (ptr + 1) >> 2;
14091         max_bitrate = QT_UINT32 (ptr + 5);
14092         avg_bitrate = QT_UINT32 (ptr + 9);
14093         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14094         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14095         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14096         GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14097         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14098         if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14099           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14100               GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14101         }
14102         if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14103           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14104               avg_bitrate, NULL);
14105         }
14106         ptr += 13;
14107         break;
14108       }
14109       case DECODER_SPECIFIC_INFO_TAG:
14110         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14111         if (object_type_id == 0xe0 && len == 0x40) {
14112           guint8 *data;
14113           GstStructure *s;
14114           guint32 clut[16];
14115           gint i;
14116 
14117           GST_DEBUG_OBJECT (qtdemux,
14118               "Have VOBSUB palette. Creating palette event");
14119           /* move to decConfigDescr data and read palette */
14120           data = ptr;
14121           for (i = 0; i < 16; i++) {
14122             clut[i] = QT_UINT32 (data);
14123             data += 4;
14124           }
14125 
14126           s = gst_structure_new ("application/x-gst-dvd", "event",
14127               G_TYPE_STRING, "dvd-spu-clut-change",
14128               "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14129               "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14130               "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14131               "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14132               "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14133               "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14134               "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14135               "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14136               NULL);
14137 
14138           /* store event and trigger custom processing */
14139           stream->pending_event =
14140               gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14141         } else {
14142           /* Generic codec_data handler puts it on the caps */
14143           data_ptr = ptr;
14144           data_len = len;
14145         }
14146 
14147         ptr += len;
14148         break;
14149       case SL_CONFIG_DESC_TAG:
14150         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14151         ptr += 1;
14152         break;
14153       default:
14154         GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14155             tag);
14156         GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14157         ptr += len;
14158         break;
14159     }
14160   }
14161 
14162   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14163    * in use, and should also be used to override some other parameters for some
14164    * codecs. */
14165   switch (object_type_id) {
14166     case 0x20:                 /* MPEG-4 */
14167       /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14168        * profile_and_level_indication */
14169       if (data_ptr != NULL && data_len >= 5 &&
14170           GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14171         gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14172             data_ptr + 4, data_len - 4);
14173       }
14174       break;                    /* Nothing special needed here */
14175     case 0x21:                 /* H.264 */
14176       codec_name = "H.264 / AVC";
14177       caps = gst_caps_new_simple ("video/x-h264",
14178           "stream-format", G_TYPE_STRING, "avc",
14179           "alignment", G_TYPE_STRING, "au", NULL);
14180       break;
14181     case 0x40:                 /* AAC (any) */
14182     case 0x66:                 /* AAC Main */
14183     case 0x67:                 /* AAC LC */
14184     case 0x68:                 /* AAC SSR */
14185       /* Override channels and rate based on the codec_data, as it's often
14186        * wrong. */
14187       /* Only do so for basic setup without HE-AAC extension */
14188 #ifdef OHOS_OPT_COMPAT
14189       /*
14190        * ohos.opt.compat.0030
14191        * sampling rate is get wrong, in special code flow
14192        */
14193       if (data_ptr && data_len >= 2) {
14194 #else
14195       if (data_ptr && data_len == 2) {
14196 #endif
14197         guint channels, rate;
14198 
14199         channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14200         if (channels > 0)
14201           entry->n_channels = channels;
14202 
14203         rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14204         if (rate > 0)
14205           entry->rate = rate;
14206       }
14207 
14208       /* Set level and profile if possible */
14209       if (data_ptr != NULL && data_len >= 2) {
14210         gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14211             data_ptr, data_len);
14212       } else {
14213         const gchar *profile_str = NULL;
14214         GstBuffer *buffer;
14215         GstMapInfo map;
14216         guint8 *codec_data;
14217         gint rate_idx, profile;
14218 
14219         /* No codec_data, let's invent something.
14220          * FIXME: This is wrong for SBR! */
14221 
14222         GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14223 
14224         buffer = gst_buffer_new_and_alloc (2);
14225         gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14226         codec_data = map.data;
14227 
14228         rate_idx =
14229             gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14230             (stream)->rate);
14231 
14232         switch (object_type_id) {
14233           case 0x66:
14234             profile_str = "main";
14235             profile = 0;
14236             break;
14237           case 0x67:
14238             profile_str = "lc";
14239             profile = 1;
14240             break;
14241           case 0x68:
14242             profile_str = "ssr";
14243             profile = 2;
14244             break;
14245           default:
14246             profile = 3;
14247             break;
14248         }
14249 
14250         codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14251         codec_data[1] =
14252             ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14253 
14254         gst_buffer_unmap (buffer, &map);
14255         gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14256             GST_TYPE_BUFFER, buffer, NULL);
14257         gst_buffer_unref (buffer);
14258 
14259         if (profile_str) {
14260           gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14261               G_TYPE_STRING, profile_str, NULL);
14262         }
14263       }
14264       break;
14265     case 0x60:                 /* MPEG-2, various profiles */
14266     case 0x61:
14267     case 0x62:
14268     case 0x63:
14269     case 0x64:
14270     case 0x65:
14271       codec_name = "MPEG-2 video";
14272       caps = gst_caps_new_simple ("video/mpeg",
14273           "mpegversion", G_TYPE_INT, 2,
14274           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14275       break;
14276     case 0x69:                 /* MPEG-2 BC audio */
14277     case 0x6B:                 /* MPEG-1 audio */
14278       caps = gst_caps_new_simple ("audio/mpeg",
14279           "mpegversion", G_TYPE_INT, 1, NULL);
14280       codec_name = "MPEG-1 audio";
14281       break;
14282     case 0x6A:                 /* MPEG-1 */
14283       codec_name = "MPEG-1 video";
14284       caps = gst_caps_new_simple ("video/mpeg",
14285           "mpegversion", G_TYPE_INT, 1,
14286           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14287       break;
14288     case 0x6C:                 /* MJPEG */
14289       caps =
14290           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14291           NULL);
14292       codec_name = "Motion-JPEG";
14293       break;
14294     case 0x6D:                 /* PNG */
14295       caps =
14296           gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14297           NULL);
14298       codec_name = "PNG still images";
14299       break;
14300     case 0x6E:                 /* JPEG2000 */
14301       codec_name = "JPEG-2000";
14302       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14303       break;
14304     case 0xA4:                 /* Dirac */
14305       codec_name = "Dirac";
14306       caps = gst_caps_new_empty_simple ("video/x-dirac");
14307       break;
14308     case 0xA5:                 /* AC3 */
14309       codec_name = "AC-3 audio";
14310       caps = gst_caps_new_simple ("audio/x-ac3",
14311           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14312       break;
14313     case 0xA9:                 /* AC3 */
14314       codec_name = "DTS audio";
14315       caps = gst_caps_new_simple ("audio/x-dts",
14316           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14317       break;
14318     case 0xDD:
14319       if (stream_type == 0x05 && data_ptr) {
14320         GList *headers =
14321             parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14322         if (headers) {
14323           GList *tmp;
14324           GValue arr_val = G_VALUE_INIT;
14325           GValue buf_val = G_VALUE_INIT;
14326           GstStructure *s;
14327 
14328           /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14329           codec_name = "Vorbis";
14330           caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14331 #ifdef OHOS_OPT_COMPAT
14332           // ohos.opt.compat.0031. adapter for avdec_vorbis
14333           GstBuffer *codec_data = gst_buffer_new_allocate (NULL, data_len, NULL);
14334           if (codec_data != NULL) {
14335             gst_buffer_fill (codec_data, 0, data_ptr, data_len);
14336             gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
14337             gst_buffer_unref (codec_data);
14338           } else {
14339             GST_ERROR_OBJECT (qtdemux, "gst_buffer_new_wrapped failed");
14340           }
14341 #endif
14342           g_value_init (&arr_val, GST_TYPE_ARRAY);
14343           g_value_init (&buf_val, GST_TYPE_BUFFER);
14344           for (tmp = headers; tmp; tmp = tmp->next) {
14345             g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14346             gst_value_array_append_value (&arr_val, &buf_val);
14347           }
14348           s = gst_caps_get_structure (caps, 0);
14349           gst_structure_take_value (s, "streamheader", &arr_val);
14350           g_value_unset (&buf_val);
14351           g_list_free (headers);
14352 
14353           data_ptr = NULL;
14354           data_len = 0;
14355         }
14356       }
14357       break;
14358     case 0xE1:                 /* QCELP */
14359       /* QCELP, the codec_data is a riff tag (little endian) with
14360        * more info (http://ftp.3gpp2.org/TSGC/Working/2003/2003-05-SanDiego/TSG-C-2003-05-San%20Diego/WG1/SWG12/C12-20030512-006%20=%20C12-20030217-015_Draft_Baseline%20Text%20of%20FFMS_R2.doc). */
14361       caps = gst_caps_new_empty_simple ("audio/qcelp");
14362       codec_name = "QCELP";
14363       break;
14364     default:
14365       break;
14366   }
14367 
14368   /* If we have a replacement caps, then change our caps for this stream */
14369   if (caps) {
14370     gst_caps_unref (entry->caps);
14371     entry->caps = caps;
14372   }
14373 
14374   if (codec_name && list)
14375     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14376         GST_TAG_AUDIO_CODEC, codec_name, NULL);
14377 
14378   /* Add the codec_data attribute to caps, if we have it */
14379   if (data_ptr) {
14380     GstBuffer *buffer;
14381 
14382     buffer = gst_buffer_new_and_alloc (data_len);
14383     gst_buffer_fill (buffer, 0, data_ptr, data_len);
14384 
14385     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14386     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14387 
14388     gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14389         buffer, NULL);
14390     gst_buffer_unref (buffer);
14391   }
14392 
14393 }
14394 
14395 static inline GstCaps *
14396 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14397 {
14398   GstCaps *caps;
14399   guint i;
14400   char *s, fourstr[5];
14401 
14402   g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14403   for (i = 0; i < 4; i++) {
14404     if (!g_ascii_isalnum (fourstr[i]))
14405       fourstr[i] = '_';
14406   }
14407   s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14408   caps = gst_caps_new_empty_simple (s);
14409   g_free (s);
14410   return caps;
14411 }
14412 
14413 #define _codec(name) \
14414   do { \
14415     if (codec_name) { \
14416       *codec_name = g_strdup (name); \
14417     } \
14418   } while (0)
14419 
14420 static GstCaps *
14421 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14422     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14423     const guint8 * stsd_entry_data, gchar ** codec_name)
14424 {
14425   GstCaps *caps = NULL;
14426   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14427 
14428   switch (fourcc) {
14429     case FOURCC_png:
14430       _codec ("PNG still images");
14431       caps = gst_caps_new_empty_simple ("image/png");
14432       break;
14433     case FOURCC_jpeg:
14434       _codec ("JPEG still images");
14435       caps =
14436           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14437           NULL);
14438       break;
14439     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14440     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14441     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14442     case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14443       _codec ("Motion-JPEG");
14444       caps =
14445           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14446           NULL);
14447       break;
14448     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14449       _codec ("Motion-JPEG format B");
14450       caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14451       break;
14452     case FOURCC_mjp2:
14453       _codec ("JPEG-2000");
14454       /* override to what it should be according to spec, avoid palette_data */
14455       entry->bits_per_sample = 24;
14456       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14457       break;
14458     case FOURCC_SVQ3:
14459       _codec ("Sorensen video v.3");
14460       caps = gst_caps_new_simple ("video/x-svq",
14461           "svqversion", G_TYPE_INT, 3, NULL);
14462       break;
14463     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14464     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14465       _codec ("Sorensen video v.1");
14466       caps = gst_caps_new_simple ("video/x-svq",
14467           "svqversion", G_TYPE_INT, 1, NULL);
14468       break;
14469     case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14470       caps = gst_caps_new_empty_simple ("video/x-raw");
14471       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14472       _codec ("Windows Raw RGB");
14473       stream->alignment = 32;
14474       break;
14475     case FOURCC_raw_:
14476     {
14477       guint16 bps;
14478 
14479       bps = QT_UINT16 (stsd_entry_data + 82);
14480       switch (bps) {
14481         case 15:
14482           format = GST_VIDEO_FORMAT_RGB15;
14483           break;
14484         case 16:
14485           format = GST_VIDEO_FORMAT_RGB16;
14486           break;
14487         case 24:
14488           format = GST_VIDEO_FORMAT_RGB;
14489           break;
14490         case 32:
14491           format = GST_VIDEO_FORMAT_ARGB;
14492           break;
14493         default:
14494           /* unknown */
14495           break;
14496       }
14497       break;
14498     }
14499     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14500       format = GST_VIDEO_FORMAT_I420;
14501       break;
14502     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14503     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14504       format = GST_VIDEO_FORMAT_I420;
14505       break;
14506     case FOURCC_2vuy:
14507     case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14508       format = GST_VIDEO_FORMAT_UYVY;
14509       break;
14510     case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14511       format = GST_VIDEO_FORMAT_v308;
14512       break;
14513     case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14514       format = GST_VIDEO_FORMAT_v216;
14515       break;
14516     case FOURCC_v210:
14517       format = GST_VIDEO_FORMAT_v210;
14518       break;
14519     case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14520       format = GST_VIDEO_FORMAT_r210;
14521       break;
14522       /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14523          case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14524          format = GST_VIDEO_FORMAT_v410;
14525          break;
14526        */
14527       /* Packed YUV 4:4:4:4 8 bit in 32 bits
14528        * but different order than AYUV
14529        case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14530        format = GST_VIDEO_FORMAT_v408;
14531        break;
14532        */
14533     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14534     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14535       _codec ("MPEG-1 video");
14536       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14537           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14538       break;
14539     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14540     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14541     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14542     case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14543     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14544     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14545     case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14546     case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14547     case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14548     case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14549     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14550     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14551     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14552     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14553     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14554     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14555     case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14556     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14557     case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14558     case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14559     case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14560     case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14561     case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14562     case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14563     case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14564     case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14565     case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14566     case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14567     case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14568     case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14569     case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14570     case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14571     case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14572     case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14573     case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14574     case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14575     case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14576     case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14577     case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14578     case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14579     case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14580     case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14581     case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14582     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14583     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14584     case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14585     case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14586       _codec ("MPEG-2 video");
14587       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14588           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14589       break;
14590     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14591       _codec ("GIF still images");
14592       caps = gst_caps_new_empty_simple ("image/gif");
14593       break;
14594     case FOURCC_h263:
14595     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14596     case FOURCC_s263:
14597     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14598       _codec ("H.263");
14599       /* ffmpeg uses the height/width props, don't know why */
14600       caps = gst_caps_new_simple ("video/x-h263",
14601           "variant", G_TYPE_STRING, "itu", NULL);
14602       break;
14603     case FOURCC_mp4v:
14604     case FOURCC_MP4V:
14605       _codec ("MPEG-4 video");
14606       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14607           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14608       break;
14609     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14610     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14611       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
14612       caps = gst_caps_new_simple ("video/x-msmpeg",
14613           "msmpegversion", G_TYPE_INT, 43, NULL);
14614       break;
14615     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14616       _codec ("DivX 3");
14617       caps = gst_caps_new_simple ("video/x-divx",
14618           "divxversion", G_TYPE_INT, 3, NULL);
14619       break;
14620     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14621     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14622       _codec ("DivX 4");
14623       caps = gst_caps_new_simple ("video/x-divx",
14624           "divxversion", G_TYPE_INT, 4, NULL);
14625       break;
14626     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14627       _codec ("DivX 5");
14628       caps = gst_caps_new_simple ("video/x-divx",
14629           "divxversion", G_TYPE_INT, 5, NULL);
14630       break;
14631 
14632     case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14633       _codec ("FFV1");
14634       caps = gst_caps_new_simple ("video/x-ffv",
14635           "ffvversion", G_TYPE_INT, 1, NULL);
14636       break;
14637 
14638     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14639     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14640     case FOURCC_XVID:
14641     case FOURCC_xvid:
14642     case FOURCC_FMP4:
14643     case FOURCC_fmp4:
14644     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14645       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14646           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14647       _codec ("MPEG-4");
14648       break;
14649 
14650     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14651       _codec ("Cinepak");
14652       caps = gst_caps_new_empty_simple ("video/x-cinepak");
14653       break;
14654     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14655       _codec ("Apple QuickDraw");
14656       caps = gst_caps_new_empty_simple ("video/x-qdrw");
14657       break;
14658     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14659       _codec ("Apple video");
14660       caps = gst_caps_new_empty_simple ("video/x-apple-video");
14661       break;
14662     case FOURCC_H264:
14663     case FOURCC_avc1:
14664     case FOURCC_dva1:
14665       _codec ("H.264 / AVC");
14666       caps = gst_caps_new_simple ("video/x-h264",
14667           "stream-format", G_TYPE_STRING, "avc",
14668           "alignment", G_TYPE_STRING, "au", NULL);
14669       break;
14670     case FOURCC_avc3:
14671     case FOURCC_dvav:
14672       _codec ("H.264 / AVC");
14673       caps = gst_caps_new_simple ("video/x-h264",
14674           "stream-format", G_TYPE_STRING, "avc3",
14675           "alignment", G_TYPE_STRING, "au", NULL);
14676       break;
14677     case FOURCC_H265:
14678     case FOURCC_hvc1:
14679     case FOURCC_dvh1:
14680       _codec ("H.265 / HEVC");
14681       caps = gst_caps_new_simple ("video/x-h265",
14682           "stream-format", G_TYPE_STRING, "hvc1",
14683           "alignment", G_TYPE_STRING, "au", NULL);
14684       break;
14685     case FOURCC_hev1:
14686     case FOURCC_dvhe:
14687       _codec ("H.265 / HEVC");
14688       caps = gst_caps_new_simple ("video/x-h265",
14689           "stream-format", G_TYPE_STRING, "hev1",
14690           "alignment", G_TYPE_STRING, "au", NULL);
14691       break;
14692     case FOURCC_rle_:
14693       _codec ("Run-length encoding");
14694       caps = gst_caps_new_simple ("video/x-rle",
14695           "layout", G_TYPE_STRING, "quicktime", NULL);
14696       break;
14697     case FOURCC_WRLE:
14698       _codec ("Run-length encoding");
14699       caps = gst_caps_new_simple ("video/x-rle",
14700           "layout", G_TYPE_STRING, "microsoft", NULL);
14701       break;
14702     case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14703     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14704       _codec ("Indeo Video 3");
14705       caps = gst_caps_new_simple ("video/x-indeo",
14706           "indeoversion", G_TYPE_INT, 3, NULL);
14707       break;
14708     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14709     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14710       _codec ("Intel Video 4");
14711       caps = gst_caps_new_simple ("video/x-indeo",
14712           "indeoversion", G_TYPE_INT, 4, NULL);
14713       break;
14714     case FOURCC_dvcp:
14715     case FOURCC_dvc_:
14716     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14717     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14718     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14719     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14720     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14721     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14722       _codec ("DV Video");
14723       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14724           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14725       break;
14726     case FOURCC_dv5n:          /* DVCPRO50 NTSC */
14727     case FOURCC_dv5p:          /* DVCPRO50 PAL */
14728       _codec ("DVCPro50 Video");
14729       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14730           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14731       break;
14732     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14733     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14734       _codec ("DVCProHD Video");
14735       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14736           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14737       break;
14738     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14739       _codec ("Apple Graphics (SMC)");
14740       caps = gst_caps_new_empty_simple ("video/x-smc");
14741       break;
14742     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14743       _codec ("VP3");
14744       caps = gst_caps_new_empty_simple ("video/x-vp3");
14745       break;
14746     case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14747       _codec ("VP6 Flash");
14748       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14749       break;
14750     case FOURCC_XiTh:
14751       _codec ("Theora");
14752       caps = gst_caps_new_empty_simple ("video/x-theora");
14753       /* theora uses one byte of padding in the data stream because it does not
14754        * allow 0 sized packets while theora does */
14755       entry->padding = 1;
14756       break;
14757     case FOURCC_drac:
14758       _codec ("Dirac");
14759       caps = gst_caps_new_empty_simple ("video/x-dirac");
14760       break;
14761     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14762       _codec ("TIFF still images");
14763       caps = gst_caps_new_empty_simple ("image/tiff");
14764       break;
14765     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14766       _codec ("Apple Intermediate Codec");
14767       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14768       break;
14769     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14770       _codec ("AVID DNxHD");
14771       caps = gst_caps_from_string ("video/x-dnxhd");
14772       break;
14773     case FOURCC_VP80:
14774     case FOURCC_vp08:
14775       _codec ("On2 VP8");
14776       caps = gst_caps_from_string ("video/x-vp8");
14777       break;
14778     case FOURCC_vp09:
14779       _codec ("Google VP9");
14780       caps = gst_caps_from_string ("video/x-vp9");
14781       break;
14782     case FOURCC_apcs:
14783       _codec ("Apple ProRes LT");
14784       caps =
14785           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14786           NULL);
14787       break;
14788     case FOURCC_apch:
14789       _codec ("Apple ProRes HQ");
14790       caps =
14791           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14792           NULL);
14793       break;
14794     case FOURCC_apcn:
14795       _codec ("Apple ProRes");
14796       caps =
14797           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14798           "standard", NULL);
14799       break;
14800     case FOURCC_apco:
14801       _codec ("Apple ProRes Proxy");
14802       caps =
14803           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14804           "proxy", NULL);
14805       break;
14806     case FOURCC_ap4h:
14807       _codec ("Apple ProRes 4444");
14808       caps =
14809           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14810           "4444", NULL);
14811 
14812       /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14813       if (entry->bits_per_sample > 0) {
14814         gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14815             NULL);
14816       }
14817       break;
14818     case FOURCC_ap4x:
14819       _codec ("Apple ProRes 4444 XQ");
14820       caps =
14821           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14822           "4444xq", NULL);
14823 
14824       /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14825       if (entry->bits_per_sample > 0) {
14826         gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14827             NULL);
14828       }
14829       break;
14830     case FOURCC_cfhd:
14831       _codec ("GoPro CineForm");
14832       caps = gst_caps_from_string ("video/x-cineform");
14833       break;
14834     case FOURCC_vc_1:
14835     case FOURCC_ovc1:
14836       _codec ("VC-1");
14837       caps = gst_caps_new_simple ("video/x-wmv",
14838           "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14839       break;
14840     case FOURCC_av01:
14841       _codec ("AV1");
14842       caps = gst_caps_new_empty_simple ("video/x-av1");
14843       break;
14844     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14845     default:
14846     {
14847       caps = _get_unknown_codec_name ("video", fourcc);
14848       break;
14849     }
14850   }
14851 
14852   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14853     GstVideoInfo info;
14854 
14855     gst_video_info_init (&info);
14856     gst_video_info_set_format (&info, format, entry->width, entry->height);
14857 
14858     caps = gst_video_info_to_caps (&info);
14859     *codec_name = gst_pb_utils_get_codec_description (caps);
14860 
14861     /* enable clipping for raw video streams */
14862     stream->need_clip = TRUE;
14863     stream->alignment = 32;
14864   }
14865 
14866   return caps;
14867 }
14868 
14869 static guint
14870 round_up_pow2 (guint n)
14871 {
14872   n = n - 1;
14873   n = n | (n >> 1);
14874   n = n | (n >> 2);
14875   n = n | (n >> 4);
14876   n = n | (n >> 8);
14877   n = n | (n >> 16);
14878   return n + 1;
14879 }
14880 
14881 static GstCaps *
14882 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14883     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14884     int len, gchar ** codec_name)
14885 {
14886   GstCaps *caps;
14887   const GstStructure *s;
14888   const gchar *name;
14889   gint endian = 0;
14890   GstAudioFormat format = 0;
14891   gint depth;
14892 
14893   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14894 
14895   depth = entry->bytes_per_packet * 8;
14896 
14897   switch (fourcc) {
14898     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14899     case FOURCC_raw_:
14900       /* 8-bit audio is unsigned */
14901       if (depth == 8)
14902         format = GST_AUDIO_FORMAT_U8;
14903       /* otherwise it's signed and big-endian just like 'twos' */
14904     case FOURCC_twos:
14905       endian = G_BIG_ENDIAN;
14906       /* fall-through */
14907     case FOURCC_sowt:
14908     {
14909       gchar *str;
14910 
14911       if (!endian)
14912         endian = G_LITTLE_ENDIAN;
14913 
14914       if (!format)
14915         format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14916 
14917       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14918       _codec (str);
14919       g_free (str);
14920 
14921       caps = gst_caps_new_simple ("audio/x-raw",
14922           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14923           "layout", G_TYPE_STRING, "interleaved", NULL);
14924       stream->alignment = GST_ROUND_UP_8 (depth);
14925       stream->alignment = round_up_pow2 (stream->alignment);
14926       break;
14927     }
14928     case FOURCC_fl64:
14929       _codec ("Raw 64-bit floating-point audio");
14930       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14931        * endian later */
14932       caps = gst_caps_new_simple ("audio/x-raw",
14933           "format", G_TYPE_STRING, "F64BE",
14934           "layout", G_TYPE_STRING, "interleaved", NULL);
14935       stream->alignment = 8;
14936       break;
14937     case FOURCC_fl32:
14938       _codec ("Raw 32-bit floating-point audio");
14939       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14940        * endian later */
14941       caps = gst_caps_new_simple ("audio/x-raw",
14942           "format", G_TYPE_STRING, "F32BE",
14943           "layout", G_TYPE_STRING, "interleaved", NULL);
14944       stream->alignment = 4;
14945       break;
14946     case FOURCC_in24:
14947       _codec ("Raw 24-bit PCM audio");
14948       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14949        * endian later */
14950       caps = gst_caps_new_simple ("audio/x-raw",
14951           "format", G_TYPE_STRING, "S24BE",
14952           "layout", G_TYPE_STRING, "interleaved", NULL);
14953       stream->alignment = 4;
14954       break;
14955     case FOURCC_in32:
14956       _codec ("Raw 32-bit PCM audio");
14957       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14958        * endian later */
14959       caps = gst_caps_new_simple ("audio/x-raw",
14960           "format", G_TYPE_STRING, "S32BE",
14961           "layout", G_TYPE_STRING, "interleaved", NULL);
14962       stream->alignment = 4;
14963       break;
14964     case FOURCC_s16l:
14965       _codec ("Raw 16-bit PCM audio");
14966       caps = gst_caps_new_simple ("audio/x-raw",
14967           "format", G_TYPE_STRING, "S16LE",
14968           "layout", G_TYPE_STRING, "interleaved", NULL);
14969       stream->alignment = 2;
14970       break;
14971     case FOURCC_ulaw:
14972       _codec ("Mu-law audio");
14973       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14974       break;
14975     case FOURCC_alaw:
14976       _codec ("A-law audio");
14977       caps = gst_caps_new_empty_simple ("audio/x-alaw");
14978       break;
14979     case 0x0200736d:
14980     case 0x6d730002:
14981       _codec ("Microsoft ADPCM");
14982       /* Microsoft ADPCM-ACM code 2 */
14983       caps = gst_caps_new_simple ("audio/x-adpcm",
14984           "layout", G_TYPE_STRING, "microsoft", NULL);
14985       break;
14986     case 0x1100736d:
14987     case 0x6d730011:
14988       _codec ("DVI/IMA ADPCM");
14989       caps = gst_caps_new_simple ("audio/x-adpcm",
14990           "layout", G_TYPE_STRING, "dvi", NULL);
14991       break;
14992     case 0x1700736d:
14993     case 0x6d730017:
14994       _codec ("DVI/Intel IMA ADPCM");
14995       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14996       caps = gst_caps_new_simple ("audio/x-adpcm",
14997           "layout", G_TYPE_STRING, "quicktime", NULL);
14998       break;
14999     case 0x5500736d:
15000     case 0x6d730055:
15001       /* MPEG layer 3, CBR only (pre QT4.1) */
15002     case FOURCC__mp3:
15003     case FOURCC_mp3_:
15004       _codec ("MPEG-1 layer 3");
15005       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15006       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15007           "mpegversion", G_TYPE_INT, 1, NULL);
15008       break;
15009     case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15010       _codec ("MPEG-1 layer 2");
15011       /* MPEG layer 2 */
15012       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15013           "mpegversion", G_TYPE_INT, 1, NULL);
15014       break;
15015     case 0x20736d:
15016     case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15017       _codec ("EAC-3 audio");
15018       caps = gst_caps_new_simple ("audio/x-eac3",
15019           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15020       entry->sampled = TRUE;
15021       break;
15022     case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15023     case FOURCC_ac_3:
15024       _codec ("AC-3 audio");
15025       caps = gst_caps_new_simple ("audio/x-ac3",
15026           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15027       entry->sampled = TRUE;
15028       break;
15029     case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15030     case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15031       _codec ("DTS audio");
15032       caps = gst_caps_new_simple ("audio/x-dts",
15033           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15034       entry->sampled = TRUE;
15035       break;
15036     case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15037     case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15038       _codec ("DTS-HD audio");
15039       caps = gst_caps_new_simple ("audio/x-dts",
15040           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15041       entry->sampled = TRUE;
15042       break;
15043     case FOURCC_MAC3:
15044       _codec ("MACE-3");
15045       caps = gst_caps_new_simple ("audio/x-mace",
15046           "maceversion", G_TYPE_INT, 3, NULL);
15047       break;
15048     case FOURCC_MAC6:
15049       _codec ("MACE-6");
15050       caps = gst_caps_new_simple ("audio/x-mace",
15051           "maceversion", G_TYPE_INT, 6, NULL);
15052       break;
15053     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15054       /* ogg/vorbis */
15055       caps = gst_caps_new_empty_simple ("application/ogg");
15056       break;
15057     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15058       _codec ("DV audio");
15059       caps = gst_caps_new_empty_simple ("audio/x-dv");
15060       break;
15061     case FOURCC_mp4a:
15062       _codec ("MPEG-4 AAC audio");
15063       caps = gst_caps_new_simple ("audio/mpeg",
15064           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15065           "stream-format", G_TYPE_STRING, "raw", NULL);
15066       break;
15067     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15068       _codec ("QDesign Music");
15069       caps = gst_caps_new_empty_simple ("audio/x-qdm");
15070       break;
15071     case FOURCC_QDM2:
15072       _codec ("QDesign Music v.2");
15073       /* FIXME: QDesign music version 2 (no constant) */
15074       if (FALSE && data) {
15075         caps = gst_caps_new_simple ("audio/x-qdm2",
15076             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15077             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15078             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15079       } else {
15080         caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15081       }
15082       break;
15083     case FOURCC_agsm:
15084       _codec ("GSM audio");
15085       caps = gst_caps_new_empty_simple ("audio/x-gsm");
15086       break;
15087     case FOURCC_samr:
15088       _codec ("AMR audio");
15089       caps = gst_caps_new_empty_simple ("audio/AMR");
15090       break;
15091     case FOURCC_sawb:
15092       _codec ("AMR-WB audio");
15093       caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15094       break;
15095     case FOURCC_ima4:
15096       _codec ("Quicktime IMA ADPCM");
15097       caps = gst_caps_new_simple ("audio/x-adpcm",
15098           "layout", G_TYPE_STRING, "quicktime", NULL);
15099       break;
15100     case FOURCC_alac:
15101       _codec ("Apple lossless audio");
15102       caps = gst_caps_new_empty_simple ("audio/x-alac");
15103       break;
15104     case FOURCC_fLaC:
15105       _codec ("Free Lossless Audio Codec");
15106       caps = gst_caps_new_simple ("audio/x-flac",
15107           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15108       break;
15109     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15110       _codec ("QualComm PureVoice");
15111       caps = gst_caps_from_string ("audio/qcelp");
15112       break;
15113     case FOURCC_wma_:
15114     case FOURCC_owma:
15115       _codec ("WMA");
15116       caps = gst_caps_new_empty_simple ("audio/x-wma");
15117       break;
15118     case FOURCC_opus:
15119       _codec ("Opus");
15120       caps = gst_caps_new_empty_simple ("audio/x-opus");
15121       break;
15122     case FOURCC_lpcm:
15123     {
15124       guint32 flags = 0;
15125       guint32 depth = 0;
15126       guint32 width = 0;
15127       GstAudioFormat format;
15128       enum
15129       {
15130         FLAG_IS_FLOAT = 0x1,
15131         FLAG_IS_BIG_ENDIAN = 0x2,
15132         FLAG_IS_SIGNED = 0x4,
15133         FLAG_IS_PACKED = 0x8,
15134         FLAG_IS_ALIGNED_HIGH = 0x10,
15135         FLAG_IS_NON_INTERLEAVED = 0x20
15136       };
15137       _codec ("Raw LPCM audio");
15138 
15139       if (data && len >= 36) {
15140         depth = QT_UINT32 (data + 24);
15141         flags = QT_UINT32 (data + 28);
15142         width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15143       }
15144       if ((flags & FLAG_IS_FLOAT) == 0) {
15145         if (depth == 0)
15146           depth = 16;
15147         if (width == 0)
15148           width = 16;
15149         if ((flags & FLAG_IS_ALIGNED_HIGH))
15150           depth = width;
15151 
15152         format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15153             TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15154             G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15155         caps = gst_caps_new_simple ("audio/x-raw",
15156             "format", G_TYPE_STRING,
15157             format !=
15158             GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15159             "UNKNOWN", "layout", G_TYPE_STRING,
15160             (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15161             "interleaved", NULL);
15162         stream->alignment = GST_ROUND_UP_8 (depth);
15163         stream->alignment = round_up_pow2 (stream->alignment);
15164       } else {
15165         if (width == 0)
15166           width = 32;
15167         if (width == 64) {
15168           if (flags & FLAG_IS_BIG_ENDIAN)
15169             format = GST_AUDIO_FORMAT_F64BE;
15170           else
15171             format = GST_AUDIO_FORMAT_F64LE;
15172         } else {
15173           if (flags & FLAG_IS_BIG_ENDIAN)
15174             format = GST_AUDIO_FORMAT_F32BE;
15175           else
15176             format = GST_AUDIO_FORMAT_F32LE;
15177         }
15178         caps = gst_caps_new_simple ("audio/x-raw",
15179             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15180             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15181             "non-interleaved" : "interleaved", NULL);
15182         stream->alignment = width / 8;
15183       }
15184       break;
15185     }
15186     case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15187     {
15188       _codec ("AC4");
15189       caps = gst_caps_new_empty_simple ("audio/x-ac4");
15190       break;
15191     }
15192     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15193       /* ? */
15194     default:
15195     {
15196       caps = _get_unknown_codec_name ("audio", fourcc);
15197       break;
15198     }
15199   }
15200 
15201   if (caps) {
15202     GstCaps *templ_caps =
15203         gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15204     GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15205     gst_caps_unref (caps);
15206     gst_caps_unref (templ_caps);
15207     caps = intersection;
15208   }
15209 
15210   /* enable clipping for raw audio streams */
15211   s = gst_caps_get_structure (caps, 0);
15212   name = gst_structure_get_name (s);
15213   if (g_str_has_prefix (name, "audio/x-raw")) {
15214     stream->need_clip = TRUE;
15215     stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15216     stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15217     GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15218         stream->max_buffer_size);
15219   }
15220   return caps;
15221 }
15222 
15223 static GstCaps *
15224 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15225     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15226     const guint8 * stsd_entry_data, gchar ** codec_name)
15227 {
15228   GstCaps *caps;
15229 
15230   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15231 
15232   switch (fourcc) {
15233     case FOURCC_mp4s:
15234       _codec ("DVD subtitle");
15235       caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15236       stream->process_func = gst_qtdemux_process_buffer_dvd;
15237       break;
15238     case FOURCC_text:
15239       _codec ("Quicktime timed text");
15240       goto text;
15241     case FOURCC_tx3g:
15242       _codec ("3GPP timed text");
15243     text:
15244       caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15245           "utf8", NULL);
15246       /* actual text piece needs to be extracted */
15247       stream->process_func = gst_qtdemux_process_buffer_text;
15248       break;
15249     case FOURCC_stpp:
15250       _codec ("XML subtitles");
15251       caps = gst_caps_new_empty_simple ("application/ttml+xml");
15252       break;
15253     case FOURCC_wvtt:
15254     {
15255       GstBuffer *buffer;
15256       const gchar *buf = "WEBVTT\n\n";
15257 
15258       _codec ("WebVTT subtitles");
15259       caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15260       stream->process_func = gst_qtdemux_process_buffer_wvtt;
15261 
15262       /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15263       buffer = gst_buffer_new_and_alloc (8);
15264       gst_buffer_fill (buffer, 0, buf, 8);
15265       stream->buffers = g_slist_append (stream->buffers, buffer);
15266 
15267       break;
15268     }
15269     case FOURCC_c608:
15270       _codec ("CEA 608 Closed Caption");
15271       caps =
15272           gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15273           G_TYPE_STRING, "s334-1a", NULL);
15274       stream->process_func = gst_qtdemux_process_buffer_clcp;
15275       stream->need_split = TRUE;
15276       break;
15277     case FOURCC_c708:
15278       _codec ("CEA 708 Closed Caption");
15279       caps =
15280           gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15281           G_TYPE_STRING, "cdp", NULL);
15282       stream->process_func = gst_qtdemux_process_buffer_clcp;
15283       break;
15284 
15285     default:
15286     {
15287       caps = _get_unknown_codec_name ("text", fourcc);
15288       break;
15289     }
15290   }
15291   return caps;
15292 }
15293 
15294 static GstCaps *
15295 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15296     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15297     const guint8 * stsd_entry_data, gchar ** codec_name)
15298 {
15299   GstCaps *caps;
15300 
15301   switch (fourcc) {
15302     case FOURCC_m1v:
15303       _codec ("MPEG 1 video");
15304       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15305           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15306       break;
15307     default:
15308       caps = NULL;
15309       break;
15310   }
15311   return caps;
15312 }
15313 
15314 static void
15315 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15316     const gchar * system_id)
15317 {
15318   gint i;
15319 
15320   if (!qtdemux->protection_system_ids)
15321     qtdemux->protection_system_ids =
15322         g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15323   /* Check whether we already have an entry for this system ID. */
15324   for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15325     const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15326     if (g_ascii_strcasecmp (system_id, id) == 0) {
15327       return;
15328     }
15329   }
15330   GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15331   g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
15332           -1));
15333 }
15334