• 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 #ifdef OHOS_OPT_PERFORMANCE
86 // ohos.opt.performance.0005
87 // add trace
88 #include "gst_trace.h"
89 #endif
90 /* max. size considered 'sane' for non-mdat atoms */
91 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
92 
93 /* if the sample index is larger than this, something is likely wrong */
94 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
95 
96 /* For converting qt creation times to unix epoch times */
97 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
98 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
99 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
100     QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
101 
102 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
103 
104 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
105 
106 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
107 
108 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
109 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
110 #define QTDEMUX_NTH_STREAM(demux,idx) \
111    QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
112 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
113    QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
114 
115 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
116 
117 GST_DEBUG_CATEGORY (qtdemux_debug);
118 #define GST_CAT_DEFAULT qtdemux_debug
119 
120 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
121 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
122 
123 /* Macros for converting to/from timescale */
124 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
125 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
126 
127 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
128 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
129 
130 /* timestamp is the DTS */
131 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
132 /* timestamp + offset + cslg_shift is the outgoing PTS */
133 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
134 /* timestamp + offset is the PTS used for internal seek calculations */
135 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
136 /* timestamp + duration - dts is the duration */
137 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
138 
139 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
140 
141 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
142 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
143     GST_TRACE("Locking from thread %p", g_thread_self()); \
144     g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
145     GST_TRACE("Locked from thread %p", g_thread_self()); \
146  } G_STMT_END
147 
148 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
149     GST_TRACE("Unlocking from thread %p", g_thread_self()); \
150     g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
151  } G_STMT_END
152 
153 /*
154  * Quicktime has tracks and segments. A track is a continuous piece of
155  * multimedia content. The track is not always played from start to finish but
156  * instead, pieces of the track are 'cut out' and played in sequence. This is
157  * what the segments do.
158  *
159  * Inside the track we have keyframes (K) and delta frames. The track has its
160  * own timing, which starts from 0 and extends to end. The position in the track
161  * is called the media_time.
162  *
163  * The segments now describe the pieces that should be played from this track
164  * and are basically tuples of media_time/duration/rate entries. We can have
165  * multiple segments and they are all played after one another. An example:
166  *
167  * segment 1: media_time: 1 second, duration: 1 second, rate 1
168  * segment 2: media_time: 3 second, duration: 2 second, rate 2
169  *
170  * To correctly play back this track, one must play: 1 second of media starting
171  * from media_time 1 followed by 2 seconds of media starting from media_time 3
172  * at a rate of 2.
173  *
174  * Each of the segments will be played at a specific time, the first segment at
175  * time 0, the second one after the duration of the first one, etc.. Note that
176  * the time in resulting playback is not identical to the media_time of the
177  * track anymore.
178  *
179  * Visually, assuming the track has 4 second of media_time:
180  *
181  *                (a)                   (b)          (c)              (d)
182  *         .-----------------------------------------------------------.
183  * track:  | K.....K.........K........K.......K.......K...........K... |
184  *         '-----------------------------------------------------------'
185  *         0              1              2              3              4
186  *           .------------^              ^   .----------^              ^
187  *          /              .-------------'  /       .------------------'
188  *         /              /          .-----'       /
189  *         .--------------.         .--------------.
190  *         | segment 1    |         | segment 2    |
191  *         '--------------'         '--------------'
192  *
193  * The challenge here is to cut out the right pieces of the track for each of
194  * the playback segments. This fortunately can easily be done with the SEGMENT
195  * events of GStreamer.
196  *
197  * For playback of segment 1, we need to provide the decoder with the keyframe
198  * (a), in the above figure, but we must instruct it only to output the decoded
199  * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
200  * position set to the time of the segment: 0.
201  *
202  * We then proceed to push data from keyframe (a) to frame (b). The decoder
203  * decodes but clips all before media_time 1.
204  *
205  * After finishing a segment, we push out a new SEGMENT event with the clipping
206  * boundaries of the new data.
207  *
208  * This is a good usecase for the GStreamer accumulated SEGMENT events.
209  */
210 
211 struct _QtDemuxSegment
212 {
213   /* global time and duration, all gst time */
214   GstClockTime time;
215   GstClockTime stop_time;
216   GstClockTime duration;
217   /* media time of trak, all gst time */
218   GstClockTime media_start;
219   GstClockTime media_stop;
220   gdouble rate;
221   /* Media start time in trak timescale units */
222   guint32 trak_media_start;
223 };
224 
225 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
226 
227 /* Used with fragmented MP4 files (mfra atom) */
228 struct _QtDemuxRandomAccessEntry
229 {
230   GstClockTime ts;
231   guint64 moof_offset;
232 };
233 
234 
235 /* Contains properties and cryptographic info for a set of samples from a
236  * track protected using Common Encryption (cenc) */
237 struct _QtDemuxCencSampleSetInfo
238 {
239   GstStructure *default_properties;
240 
241   /* @crypto_info holds one GstStructure per sample */
242   GPtrArray *crypto_info;
243 };
244 
245 struct _QtDemuxAavdEncryptionInfo
246 {
247   GstStructure *default_properties;
248 };
249 
250 static const gchar *
qt_demux_state_string(enum QtDemuxState state)251 qt_demux_state_string (enum QtDemuxState state)
252 {
253   switch (state) {
254     case QTDEMUX_STATE_INITIAL:
255       return "<INITIAL>";
256     case QTDEMUX_STATE_HEADER:
257       return "<HEADER>";
258     case QTDEMUX_STATE_MOVIE:
259       return "<MOVIE>";
260     case QTDEMUX_STATE_BUFFER_MDAT:
261       return "<BUFFER_MDAT>";
262     default:
263       return "<UNKNOWN>";
264   }
265 }
266 
267 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
268 
269 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
270 
271 static GstStaticPadTemplate gst_qtdemux_sink_template =
272     GST_STATIC_PAD_TEMPLATE ("sink",
273     GST_PAD_SINK,
274     GST_PAD_ALWAYS,
275     GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
276         "application/x-3gp")
277     );
278 
279 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
280 GST_STATIC_PAD_TEMPLATE ("video_%u",
281     GST_PAD_SRC,
282     GST_PAD_SOMETIMES,
283     GST_STATIC_CAPS_ANY);
284 
285 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
286 GST_STATIC_PAD_TEMPLATE ("audio_%u",
287     GST_PAD_SRC,
288     GST_PAD_SOMETIMES,
289     GST_STATIC_CAPS_ANY);
290 
291 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
292 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
293     GST_PAD_SRC,
294     GST_PAD_SOMETIMES,
295     GST_STATIC_CAPS_ANY);
296 
297 #define gst_qtdemux_parent_class parent_class
298 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
299 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
300     GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
301 
302 static void gst_qtdemux_dispose (GObject * object);
303 static void gst_qtdemux_finalize (GObject * object);
304 
305 static guint32
306 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
307     GstClockTime media_time);
308 static guint32
309 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
310     QtDemuxStream * str, gint64 media_offset);
311 
312 #if 0
313 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
314 static GstIndex *gst_qtdemux_get_index (GstElement * element);
315 #endif
316 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
317     GstStateChange transition);
318 static void gst_qtdemux_set_context (GstElement * element,
319     GstContext * context);
320 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
321 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
322     GstObject * parent, GstPadMode mode, gboolean active);
323 
324 static void gst_qtdemux_loop (GstPad * pad);
325 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
326     GstBuffer * inbuf);
327 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
328     GstEvent * event);
329 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
330     GstQuery * query);
331 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
332 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
333     QtDemuxStream * stream);
334 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
335     QtDemuxStream * stream);
336 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
337     gboolean force);
338 
339 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
340 
341 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
342     const guint8 * buffer, guint length);
343 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
344     const guint8 * buffer, guint length);
345 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
346 
347 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
348     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
349     GstTagList * list);
350 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
351     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
352     const guint8 * stsd_entry_data, gchar ** codec_name);
353 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
354     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
355     const guint8 * data, int len, gchar ** codec_name);
356 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
357     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
358     gchar ** codec_name);
359 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
360     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
361     const guint8 * stsd_entry_data, gchar ** codec_name);
362 
363 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
364     QtDemuxStream * stream, guint32 n);
365 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
366 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
367 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
368 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
369 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
370 static void qtdemux_do_allocation (QtDemuxStream * stream,
371     GstQTDemux * qtdemux);
372 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
373     QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
374 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
375     QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
376     GstClockTime * _start, GstClockTime * _stop);
377 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
378     QtDemuxStream * stream, gint segment_index, GstClockTime pos);
379 
380 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
381 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
382 
383 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
384 
385 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
386     QtDemuxStream * stream, guint sample_index);
387 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
388     const gchar * id);
389 static void qtdemux_gst_structure_free (GstStructure * gststructure);
390 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
391 
392 static void
gst_qtdemux_class_init(GstQTDemuxClass * klass)393 gst_qtdemux_class_init (GstQTDemuxClass * klass)
394 {
395   GObjectClass *gobject_class;
396   GstElementClass *gstelement_class;
397 
398   gobject_class = (GObjectClass *) klass;
399   gstelement_class = (GstElementClass *) klass;
400 
401   parent_class = g_type_class_peek_parent (klass);
402 
403   gobject_class->dispose = gst_qtdemux_dispose;
404   gobject_class->finalize = gst_qtdemux_finalize;
405 
406   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
407 #if 0
408   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
409   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
410 #endif
411   gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
412 
413   gst_tag_register_musicbrainz_tags ();
414 
415   gst_element_class_add_static_pad_template (gstelement_class,
416       &gst_qtdemux_sink_template);
417   gst_element_class_add_static_pad_template (gstelement_class,
418       &gst_qtdemux_videosrc_template);
419   gst_element_class_add_static_pad_template (gstelement_class,
420       &gst_qtdemux_audiosrc_template);
421   gst_element_class_add_static_pad_template (gstelement_class,
422       &gst_qtdemux_subsrc_template);
423   gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
424       "Codec/Demuxer",
425       "Demultiplex a QuickTime file into audio and video streams",
426       "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
427 
428   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
429   gst_riff_init ();
430 }
431 
432 static void
gst_qtdemux_init(GstQTDemux * qtdemux)433 gst_qtdemux_init (GstQTDemux * qtdemux)
434 {
435   qtdemux->sinkpad =
436       gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
437   gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
438   gst_pad_set_activatemode_function (qtdemux->sinkpad,
439       qtdemux_sink_activate_mode);
440   gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
441   gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
442   gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
443   gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
444 
445   qtdemux->adapter = gst_adapter_new ();
446   g_queue_init (&qtdemux->protection_event_queue);
447   qtdemux->flowcombiner = gst_flow_combiner_new ();
448   g_mutex_init (&qtdemux->expose_lock);
449 
450   qtdemux->active_streams = g_ptr_array_new_with_free_func
451       ((GDestroyNotify) gst_qtdemux_stream_unref);
452   qtdemux->old_streams = g_ptr_array_new_with_free_func
453       ((GDestroyNotify) gst_qtdemux_stream_unref);
454 
455   GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
456 
457   gst_qtdemux_reset (qtdemux, TRUE);
458 }
459 
460 static void
gst_qtdemux_finalize(GObject * object)461 gst_qtdemux_finalize (GObject * object)
462 {
463   GstQTDemux *qtdemux = GST_QTDEMUX (object);
464 
465   g_free (qtdemux->redirect_location);
466 
467   G_OBJECT_CLASS (parent_class)->finalize (object);
468 }
469 
470 static void
gst_qtdemux_dispose(GObject * object)471 gst_qtdemux_dispose (GObject * object)
472 {
473   GstQTDemux *qtdemux = GST_QTDEMUX (object);
474 
475   if (qtdemux->adapter) {
476     g_object_unref (G_OBJECT (qtdemux->adapter));
477     qtdemux->adapter = NULL;
478   }
479   gst_tag_list_unref (qtdemux->tag_list);
480   gst_flow_combiner_free (qtdemux->flowcombiner);
481   g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
482       NULL);
483   g_queue_clear (&qtdemux->protection_event_queue);
484 
485   g_free (qtdemux->cenc_aux_info_sizes);
486   qtdemux->cenc_aux_info_sizes = NULL;
487   g_mutex_clear (&qtdemux->expose_lock);
488 
489   g_ptr_array_free (qtdemux->active_streams, TRUE);
490   g_ptr_array_free (qtdemux->old_streams, TRUE);
491 
492   G_OBJECT_CLASS (parent_class)->dispose (object);
493 }
494 
495 static void
gst_qtdemux_post_no_playable_stream_error(GstQTDemux * qtdemux)496 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
497 {
498   if (qtdemux->redirect_location) {
499     GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
500         (_("This file contains no playable streams.")),
501         ("no known streams found, a redirect message has been posted"),
502         ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
503   } else {
504     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
505         (_("This file contains no playable streams.")),
506         ("no known streams found"));
507   }
508 }
509 
510 static GstBuffer *
_gst_buffer_new_wrapped(gpointer mem,gsize size,GFreeFunc free_func)511 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
512 {
513   return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
514       mem, size, 0, size, mem, free_func);
515 }
516 
517 static GstFlowReturn
gst_qtdemux_pull_atom(GstQTDemux * qtdemux,guint64 offset,guint64 size,GstBuffer ** buf)518 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
519     GstBuffer ** buf)
520 {
521   GstFlowReturn flow;
522   GstMapInfo map;
523   gsize bsize;
524 
525   if (G_UNLIKELY (size == 0)) {
526     GstFlowReturn ret;
527     GstBuffer *tmp = NULL;
528 
529     ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
530     if (ret != GST_FLOW_OK)
531       return ret;
532 
533     gst_buffer_map (tmp, &map, GST_MAP_READ);
534     size = QT_UINT32 (map.data);
535     GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
536 
537     gst_buffer_unmap (tmp, &map);
538     gst_buffer_unref (tmp);
539   }
540 
541   /* Sanity check: catch bogus sizes (fuzzed/broken files) */
542   if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
543     if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
544       /* we're pulling header but already got most interesting bits,
545        * so never mind the rest (e.g. tags) (that much) */
546       GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
547           size);
548       return GST_FLOW_EOS;
549     } else {
550       GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
551           (_("This file is invalid and cannot be played.")),
552           ("atom has bogus size %" G_GUINT64_FORMAT, size));
553       return GST_FLOW_ERROR;
554     }
555   }
556 
557   flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
558 
559   if (G_UNLIKELY (flow != GST_FLOW_OK))
560     return flow;
561 
562   bsize = gst_buffer_get_size (*buf);
563   /* Catch short reads - we don't want any partial atoms */
564   if (G_UNLIKELY (bsize < size)) {
565     GST_WARNING_OBJECT (qtdemux,
566         "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
567     gst_buffer_unref (*buf);
568     *buf = NULL;
569     return GST_FLOW_EOS;
570   }
571 
572   return flow;
573 }
574 
575 #if 1
576 static gboolean
gst_qtdemux_src_convert(GstQTDemux * qtdemux,GstPad * pad,GstFormat src_format,gint64 src_value,GstFormat dest_format,gint64 * dest_value)577 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
578     GstFormat src_format, gint64 src_value, GstFormat dest_format,
579     gint64 * dest_value)
580 {
581   gboolean res = TRUE;
582   QtDemuxStream *stream = gst_pad_get_element_private (pad);
583   gint32 index;
584 
585   if (stream->subtype != FOURCC_vide) {
586     res = FALSE;
587     goto done;
588   }
589 
590   switch (src_format) {
591     case GST_FORMAT_TIME:
592       switch (dest_format) {
593         case GST_FORMAT_BYTES:{
594           index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
595           if (-1 == index) {
596             res = FALSE;
597             goto done;
598           }
599 
600           *dest_value = stream->samples[index].offset;
601 
602           GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
603               GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
604               GST_TIME_ARGS (src_value), *dest_value);
605           break;
606         }
607         default:
608           res = FALSE;
609           break;
610       }
611       break;
612     case GST_FORMAT_BYTES:
613       switch (dest_format) {
614         case GST_FORMAT_TIME:{
615           index =
616               gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
617               stream, src_value);
618 
619           if (-1 == index) {
620             res = FALSE;
621             goto done;
622           }
623 
624           *dest_value =
625               QTSTREAMTIME_TO_GSTTIME (stream,
626               stream->samples[index].timestamp);
627           GST_DEBUG_OBJECT (qtdemux,
628               "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
629               GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
630           break;
631         }
632         default:
633           res = FALSE;
634           break;
635       }
636       break;
637     default:
638       res = FALSE;
639       break;
640   }
641 
642 done:
643   return res;
644 }
645 #endif
646 
647 static gboolean
gst_qtdemux_get_duration(GstQTDemux * qtdemux,GstClockTime * duration)648 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
649 {
650   gboolean res = FALSE;
651 
652   *duration = GST_CLOCK_TIME_NONE;
653 
654   if (qtdemux->duration != 0 &&
655       qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
656     *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
657     res = TRUE;
658   } else {
659     *duration = GST_CLOCK_TIME_NONE;
660   }
661 
662   return res;
663 }
664 
665 static gboolean
gst_qtdemux_handle_src_query(GstPad * pad,GstObject * parent,GstQuery * query)666 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
667     GstQuery * query)
668 {
669   gboolean res = FALSE;
670   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
671 
672   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
673 
674   switch (GST_QUERY_TYPE (query)) {
675     case GST_QUERY_POSITION:{
676       GstFormat fmt;
677 
678       gst_query_parse_position (query, &fmt, NULL);
679       if (fmt == GST_FORMAT_TIME
680           && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
681         gst_query_set_position (query, GST_FORMAT_TIME,
682             qtdemux->segment.position);
683         res = TRUE;
684       }
685     }
686       break;
687     case GST_QUERY_DURATION:{
688       GstFormat fmt;
689 
690       gst_query_parse_duration (query, &fmt, NULL);
691       if (fmt == GST_FORMAT_TIME) {
692         /* First try to query upstream */
693         res = gst_pad_query_default (pad, parent, query);
694         if (!res) {
695           GstClockTime duration;
696           if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
697             gst_query_set_duration (query, GST_FORMAT_TIME, duration);
698             res = TRUE;
699           }
700         }
701       }
702       break;
703     }
704     case GST_QUERY_CONVERT:{
705       GstFormat src_fmt, dest_fmt;
706       gint64 src_value, dest_value = 0;
707 
708       gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
709 
710       res = gst_qtdemux_src_convert (qtdemux, pad,
711           src_fmt, src_value, dest_fmt, &dest_value);
712       if (res)
713         gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
714 
715       break;
716     }
717     case GST_QUERY_FORMATS:
718       gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
719       res = TRUE;
720       break;
721     case GST_QUERY_SEEKING:{
722       GstFormat fmt;
723       gboolean seekable;
724 
725       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
726 
727       if (fmt == GST_FORMAT_BYTES) {
728         /* We always refuse BYTES seeks from downstream */
729         break;
730       }
731 
732       /* try upstream first */
733       res = gst_pad_query_default (pad, parent, query);
734 
735       if (!res) {
736         gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
737         if (fmt == GST_FORMAT_TIME) {
738           GstClockTime duration;
739 
740           gst_qtdemux_get_duration (qtdemux, &duration);
741           seekable = TRUE;
742           if (!qtdemux->pullbased) {
743             GstQuery *q;
744 
745             /* we might be able with help from upstream */
746             seekable = FALSE;
747             q = gst_query_new_seeking (GST_FORMAT_BYTES);
748             if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
749               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
750               GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
751             }
752             gst_query_unref (q);
753           }
754           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
755           res = TRUE;
756         }
757       }
758       break;
759     }
760     case GST_QUERY_SEGMENT:
761     {
762       GstFormat format;
763       gint64 start, stop;
764 
765       format = qtdemux->segment.format;
766 
767       start =
768           gst_segment_to_stream_time (&qtdemux->segment, format,
769           qtdemux->segment.start);
770       if ((stop = qtdemux->segment.stop) == -1)
771         stop = qtdemux->segment.duration;
772       else
773         stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
774 
775       gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
776       res = TRUE;
777       break;
778     }
779     default:
780       res = gst_pad_query_default (pad, parent, query);
781       break;
782   }
783 
784   return res;
785 }
786 
787 static void
gst_qtdemux_push_tags(GstQTDemux * qtdemux,QtDemuxStream * stream)788 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
789 {
790   if (G_LIKELY (stream->pad)) {
791     GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
792         GST_DEBUG_PAD_NAME (stream->pad));
793 
794     if (!gst_tag_list_is_empty (stream->stream_tags)) {
795       GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
796           stream->stream_tags);
797       gst_pad_push_event (stream->pad,
798           gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
799     }
800 
801     if (G_UNLIKELY (stream->send_global_tags)) {
802       GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
803           qtdemux->tag_list);
804       gst_pad_push_event (stream->pad,
805           gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
806       stream->send_global_tags = FALSE;
807     }
808   }
809 }
810 
811 /* push event on all source pads; takes ownership of the event */
812 static void
gst_qtdemux_push_event(GstQTDemux * qtdemux,GstEvent * event)813 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
814 {
815   gboolean has_valid_stream = FALSE;
816   GstEventType etype = GST_EVENT_TYPE (event);
817   guint i;
818 
819   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
820       GST_EVENT_TYPE_NAME (event));
821 
822   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
823     GstPad *pad;
824     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
825     GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
826 
827     if ((pad = stream->pad)) {
828       has_valid_stream = TRUE;
829 
830       if (etype == GST_EVENT_EOS) {
831         /* let's not send twice */
832         if (stream->sent_eos)
833           continue;
834         stream->sent_eos = TRUE;
835       }
836 
837       gst_pad_push_event (pad, gst_event_ref (event));
838     }
839   }
840 
841   gst_event_unref (event);
842 
843   /* if it is EOS and there are no pads, post an error */
844   if (!has_valid_stream && etype == GST_EVENT_EOS) {
845     gst_qtdemux_post_no_playable_stream_error (qtdemux);
846   }
847 }
848 
849 typedef struct
850 {
851   guint64 media_time;
852 } FindData;
853 
854 static gint
find_func(QtDemuxSample * s1,gint64 * media_time,gpointer user_data)855 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
856 {
857   if ((gint64) s1->timestamp > *media_time)
858     return 1;
859   if ((gint64) s1->timestamp == *media_time)
860     return 0;
861 
862   return -1;
863 }
864 
865 /* find the index of the sample that includes the data for @media_time using a
866  * binary search.  Only to be called in optimized cases of linear search below.
867  *
868  * Returns the index of the sample with the corresponding *DTS*.
869  */
870 static guint32
gst_qtdemux_find_index(GstQTDemux * qtdemux,QtDemuxStream * str,guint64 media_time)871 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
872     guint64 media_time)
873 {
874   QtDemuxSample *result;
875   guint32 index;
876 
877   /* convert media_time to mov format */
878   media_time =
879       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
880 
881   result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
882       sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
883       GST_SEARCH_MODE_BEFORE, &media_time, NULL);
884 
885   if (G_LIKELY (result))
886     index = result - str->samples;
887   else
888     index = 0;
889 
890   return index;
891 }
892 
893 
894 
895 /* find the index of the sample that includes the data for @media_offset using a
896  * linear search
897  *
898  * Returns the index of the sample.
899  */
900 static guint32
gst_qtdemux_find_index_for_given_media_offset_linear(GstQTDemux * qtdemux,QtDemuxStream * str,gint64 media_offset)901 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
902     QtDemuxStream * str, gint64 media_offset)
903 {
904   QtDemuxSample *result = str->samples;
905   guint32 index = 0;
906 
907   if (result == NULL || str->n_samples == 0)
908     return -1;
909 
910   if (media_offset == result->offset)
911     return index;
912 
913   result++;
914   while (index < str->n_samples - 1) {
915     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
916       goto parse_failed;
917 
918     if (media_offset < result->offset)
919       break;
920 
921     index++;
922     result++;
923   }
924   return index;
925 
926   /* ERRORS */
927 parse_failed:
928   {
929     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
930     return -1;
931   }
932 }
933 
934 /* find the index of the sample that includes the data for @media_time using a
935  * linear search, and keeping in mind that not all samples may have been parsed
936  * yet.  If possible, it will delegate to binary search.
937  *
938  * Returns the index of the sample.
939  */
940 static guint32
gst_qtdemux_find_index_linear(GstQTDemux * qtdemux,QtDemuxStream * str,GstClockTime media_time)941 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
942     GstClockTime media_time)
943 {
944   guint32 index = 0;
945   guint64 mov_time;
946   QtDemuxSample *sample;
947 
948   /* convert media_time to mov format */
949   mov_time =
950       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
951 
952   sample = str->samples;
953   if (mov_time == sample->timestamp + sample->pts_offset)
954     return index;
955 
956   /* use faster search if requested time in already parsed range */
957   sample = str->samples + str->stbl_index;
958   if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
959     index = gst_qtdemux_find_index (qtdemux, str, media_time);
960     sample = str->samples + index;
961   } else {
962     while (index < str->n_samples - 1) {
963       if (!qtdemux_parse_samples (qtdemux, str, index + 1))
964         goto parse_failed;
965 
966       sample = str->samples + index + 1;
967       if (mov_time < sample->timestamp) {
968         sample = str->samples + index;
969         break;
970       }
971 
972       index++;
973     }
974   }
975 
976   /* sample->timestamp is now <= media_time, need to find the corresponding
977    * PTS now by looking backwards */
978   while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
979     index--;
980     sample = str->samples + index;
981   }
982 
983   return index;
984 
985   /* ERRORS */
986 parse_failed:
987   {
988     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
989     return -1;
990   }
991 }
992 
993 /* find the index of the keyframe needed to decode the sample at @index
994  * of stream @str, or of a subsequent keyframe (depending on @next)
995  *
996  * Returns the index of the keyframe.
997  */
998 static guint32
gst_qtdemux_find_keyframe(GstQTDemux * qtdemux,QtDemuxStream * str,guint32 index,gboolean next)999 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1000     guint32 index, gboolean next)
1001 {
1002   guint32 new_index = index;
1003 
1004   if (index >= str->n_samples) {
1005     new_index = str->n_samples;
1006     goto beach;
1007   }
1008 
1009   /* all keyframes, return index */
1010   if (str->all_keyframe) {
1011     new_index = index;
1012     goto beach;
1013   }
1014 
1015   /* else search until we have a keyframe */
1016   while (new_index < str->n_samples) {
1017     if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1018       goto parse_failed;
1019 
1020     if (str->samples[new_index].keyframe)
1021       break;
1022 
1023     if (new_index == 0)
1024       break;
1025 
1026     if (next)
1027       new_index++;
1028     else
1029       new_index--;
1030   }
1031 
1032   if (new_index == str->n_samples) {
1033     GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1034     new_index = -1;
1035   }
1036 
1037 beach:
1038   GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1039       "gave %u", next ? "after" : "before", index, new_index);
1040 
1041   return new_index;
1042 
1043   /* ERRORS */
1044 parse_failed:
1045   {
1046     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1047     return -1;
1048   }
1049 }
1050 
1051 /* find the segment for @time_position for @stream
1052  *
1053  * Returns the index of the segment containing @time_position.
1054  * Returns the last segment and sets the @eos variable to TRUE
1055  * if the time is beyond the end. @eos may be NULL
1056  */
1057 static guint32
gst_qtdemux_find_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime time_position)1058 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1059     GstClockTime time_position)
1060 {
1061   gint i;
1062   guint32 seg_idx;
1063 
1064   GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1065       GST_TIME_ARGS (time_position));
1066 
1067   seg_idx = -1;
1068   for (i = 0; i < stream->n_segments; i++) {
1069     QtDemuxSegment *segment = &stream->segments[i];
1070 
1071     GST_LOG_OBJECT (stream->pad,
1072         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1073         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1074 
1075     /* For the last segment we include stop_time in the last segment */
1076     if (i < stream->n_segments - 1) {
1077       if (segment->time <= time_position && time_position < segment->stop_time) {
1078         GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1079         seg_idx = i;
1080         break;
1081       }
1082     } else {
1083       /* Last segment always matches */
1084       seg_idx = i;
1085       break;
1086     }
1087   }
1088   return seg_idx;
1089 }
1090 
1091 /* move the stream @str to the sample position @index.
1092  *
1093  * Updates @str->sample_index and marks discontinuity if needed.
1094  */
1095 static void
gst_qtdemux_move_stream(GstQTDemux * qtdemux,QtDemuxStream * str,guint32 index)1096 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1097     guint32 index)
1098 {
1099   /* no change needed */
1100   if (index == str->sample_index)
1101     return;
1102 
1103   GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1104       str->n_samples);
1105 
1106   /* position changed, we have a discont */
1107   str->sample_index = index;
1108   str->offset_in_sample = 0;
1109   /* Each time we move in the stream we store the position where we are
1110    * starting from */
1111   str->from_sample = index;
1112   str->discont = TRUE;
1113 }
1114 
1115 #ifdef OHOS_OPT_COMPAT
1116 /* ohos.opt.compat.0055 */
gst_qtdemux_get_all_tracks_minimum_duration(GstQTDemux * qtdemux)1117 static gint64 gst_qtdemux_get_all_tracks_minimum_duration(GstQTDemux * qtdemux)
1118 {
1119   guint64 min_duration = G_MAXUINT64;
1120   for (guint i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1121     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
1122     if (str->duration < min_duration) {
1123       min_duration = str->duration;
1124     }
1125   }
1126   return min_duration;
1127 }
1128 #endif
1129 
1130 static void
gst_qtdemux_adjust_seek(GstQTDemux * qtdemux,gint64 desired_time,gboolean use_sparse,gboolean next,gint64 * key_time,gint64 * key_offset)1131 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1132     gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1133 {
1134   guint64 min_offset;
1135 #ifdef OHOS_OPT_COMPAT
1136   /* ohos.opt.compat.0055 */
1137   guint64 max_time = 0;
1138   guint64 min_duration = gst_qtdemux_get_all_tracks_minimum_duration(qtdemux);
1139 #endif
1140   gint64 min_byte_offset = -1;
1141   guint i;
1142 
1143   min_offset = desired_time;
1144 
1145   /* for each stream, find the index of the sample in the segment
1146    * and move back to the previous keyframe. */
1147   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1148     QtDemuxStream *str;
1149     guint32 index, kindex;
1150     guint32 seg_idx;
1151     GstClockTime media_start;
1152     GstClockTime media_time;
1153     GstClockTime seg_time;
1154     QtDemuxSegment *seg;
1155     gboolean empty_segment = FALSE;
1156 
1157     str = QTDEMUX_NTH_STREAM (qtdemux, i);
1158 
1159     if (CUR_STREAM (str)->sparse && !use_sparse)
1160       continue;
1161 
1162     seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1163     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1164 
1165     /* get segment and time in the segment */
1166     seg = &str->segments[seg_idx];
1167     seg_time = (desired_time - seg->time) * seg->rate;
1168 
1169     while (QTSEGMENT_IS_EMPTY (seg)) {
1170       seg_time = 0;
1171       empty_segment = TRUE;
1172       GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1173           seg_idx);
1174       seg_idx++;
1175       if (seg_idx == str->n_segments)
1176         break;
1177       seg = &str->segments[seg_idx];
1178     }
1179 
1180     if (seg_idx == str->n_segments) {
1181       /* FIXME track shouldn't have the last segment as empty, but if it
1182        * happens we better handle it */
1183       continue;
1184     }
1185 
1186     /* get the media time in the segment */
1187     media_start = seg->media_start + seg_time;
1188 
1189     /* get the index of the sample with media time */
1190     index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1191     GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1192         " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1193         GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1194         empty_segment);
1195 
1196     /* shift to next frame if we are looking for next keyframe */
1197     if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1198         && index < str->stbl_index)
1199       index++;
1200 
1201     if (!empty_segment) {
1202       /* find previous keyframe */
1203       kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1204 
1205       /* we will settle for one before if none found after */
1206       if (next && kindex == -1)
1207         kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1208 
1209       /* Update the requested time whenever a keyframe was found, to make it
1210        * accurate and avoid having the first buffer fall outside of the segment
1211        */
1212       if (kindex != -1) {
1213         index = kindex;
1214 
1215         /* get timestamp of keyframe */
1216         media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1217         GST_DEBUG_OBJECT (qtdemux,
1218             "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1219             G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1220             str->samples[kindex].offset);
1221 #ifdef OHOS_OPT_COMPAT
1222         /**
1223          * ohos.opt.compat.0055
1224          * when video stream and audio stream are different duration(edge. video duration is 01:50,
1225          * audio duration is 0:35), it will lead seek done offset has a huge gap with seek offset.
1226          * Thus, return a timestamp closest to the seek offset.
1227          */
1228         GST_DEBUG_OBJECT (qtdemux,
1229           "min_duration %" GST_TIME_FORMAT " desired_time %" GST_TIME_FORMAT " next %d max_time %" GST_TIME_FORMAT "",
1230           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME(str, min_duration)),
1231           GST_TIME_ARGS (desired_time), next, GST_TIME_ARGS (max_time));
1232         /**
1233          * diffent: compared with the original logic, forward seek may miss video key frames
1234          * forward seek, find all tracks the biggest key frames time
1235          */
1236         if ((min_duration < desired_time) && (!next && (max_time > media_time))) {
1237           continue;
1238         }
1239         max_time = media_time;
1240 #endif
1241         /* keyframes in the segment get a chance to change the
1242          * desired_offset. keyframes out of the segment are
1243          * ignored. */
1244         if (media_time >= seg->media_start) {
1245           GstClockTime seg_time;
1246 
1247           /* this keyframe is inside the segment, convert back to
1248            * segment time */
1249           seg_time = (media_time - seg->media_start) + seg->time;
1250           if ((!next && (seg_time < min_offset)) ||
1251               (next && (seg_time > min_offset)))
1252             min_offset = seg_time;
1253         }
1254       }
1255     }
1256 
1257     if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1258       min_byte_offset = str->samples[index].offset;
1259   }
1260 
1261   if (key_time)
1262     *key_time = min_offset;
1263   if (key_offset)
1264     *key_offset = min_byte_offset;
1265 }
1266 
1267 static gboolean
gst_qtdemux_convert_seek(GstPad * pad,GstFormat * format,GstSeekType cur_type,gint64 * cur,GstSeekType stop_type,gint64 * stop)1268 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1269     GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1270 {
1271   gboolean res;
1272 
1273   g_return_val_if_fail (format != NULL, FALSE);
1274   g_return_val_if_fail (cur != NULL, FALSE);
1275   g_return_val_if_fail (stop != NULL, FALSE);
1276 
1277   if (*format == GST_FORMAT_TIME)
1278     return TRUE;
1279 
1280   res = TRUE;
1281   if (cur_type != GST_SEEK_TYPE_NONE)
1282     res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1283   if (res && stop_type != GST_SEEK_TYPE_NONE)
1284     res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1285 
1286   if (res)
1287     *format = GST_FORMAT_TIME;
1288 
1289   return res;
1290 }
1291 
1292 /* perform seek in push based mode:
1293    find BYTE position to move to based on time and delegate to upstream
1294 */
1295 static gboolean
gst_qtdemux_do_push_seek(GstQTDemux * qtdemux,GstPad * pad,GstEvent * event)1296 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1297 {
1298   gdouble rate;
1299   GstFormat format;
1300   GstSeekFlags flags;
1301   GstSeekType cur_type, stop_type;
1302   gint64 cur, stop, key_cur;
1303   gboolean res;
1304   gint64 byte_cur;
1305   gint64 original_stop;
1306   guint32 seqnum;
1307 
1308   GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1309 
1310   gst_event_parse_seek (event, &rate, &format, &flags,
1311       &cur_type, &cur, &stop_type, &stop);
1312   seqnum = gst_event_get_seqnum (event);
1313 
1314   /* Directly send the instant-rate-change event here before taking the
1315    * stream-lock so that it can be applied as soon as possible */
1316   if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1317     GstEvent *ev;
1318 
1319     /* instant rate change only supported if direction does not change. All
1320      * other requirements are already checked before creating the seek event
1321      * but let's double-check here to be sure */
1322     if ((qtdemux->segment.rate > 0 && rate < 0) ||
1323         (qtdemux->segment.rate < 0 && rate > 0) ||
1324         cur_type != GST_SEEK_TYPE_NONE ||
1325         stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1326       GST_ERROR_OBJECT (qtdemux,
1327           "Instant rate change seeks only supported in the "
1328           "same direction, without flushing and position change");
1329       return FALSE;
1330     }
1331 
1332     ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1333         (GstSegmentFlags) flags);
1334     gst_event_set_seqnum (ev, seqnum);
1335     gst_qtdemux_push_event (qtdemux, ev);
1336     return TRUE;
1337   }
1338 
1339   /* only forward streaming and seeking is possible */
1340   if (rate <= 0)
1341     goto unsupported_seek;
1342 
1343   /* convert to TIME if needed and possible */
1344   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1345           stop_type, &stop))
1346     goto no_format;
1347 
1348   /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1349    * the original stop position to use when upstream pushes the new segment
1350    * for this seek */
1351   original_stop = stop;
1352   stop = -1;
1353 
1354   /* find reasonable corresponding BYTE position,
1355    * also try to mind about keyframes, since we can not go back a bit for them
1356    * later on */
1357   /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1358    * mostly just work, but let's not yet boldly go there  ... */
1359   gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1360 
1361   if (byte_cur == -1)
1362     goto abort_seek;
1363 
1364   GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1365       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1366       stop);
1367 
1368   GST_OBJECT_LOCK (qtdemux);
1369   qtdemux->seek_offset = byte_cur;
1370   if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1371     qtdemux->push_seek_start = cur;
1372   } else {
1373     qtdemux->push_seek_start = key_cur;
1374   }
1375 
1376   if (stop_type == GST_SEEK_TYPE_NONE) {
1377     qtdemux->push_seek_stop = qtdemux->segment.stop;
1378   } else {
1379     qtdemux->push_seek_stop = original_stop;
1380   }
1381   GST_OBJECT_UNLOCK (qtdemux);
1382 
1383   qtdemux->segment_seqnum = seqnum;
1384   /* BYTE seek event */
1385   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1386       stop_type, stop);
1387   gst_event_set_seqnum (event, seqnum);
1388   res = gst_pad_push_event (qtdemux->sinkpad, event);
1389 
1390   return res;
1391 
1392   /* ERRORS */
1393 abort_seek:
1394   {
1395     GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1396         "seek aborted.");
1397     return FALSE;
1398   }
1399 unsupported_seek:
1400   {
1401     GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1402     return FALSE;
1403   }
1404 no_format:
1405   {
1406     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1407     return FALSE;
1408   }
1409 }
1410 
1411 /* perform the seek.
1412  *
1413  * We set all segment_indexes in the streams to unknown and
1414  * adjust the time_position to the desired position. this is enough
1415  * to trigger a segment switch in the streaming thread to start
1416  * streaming from the desired position.
1417  *
1418  * Keyframe seeking is a little more complicated when dealing with
1419  * segments. Ideally we want to move to the previous keyframe in
1420  * the segment but there might not be a keyframe in the segment. In
1421  * fact, none of the segments could contain a keyframe. We take a
1422  * practical approach: seek to the previous keyframe in the segment,
1423  * if there is none, seek to the beginning of the segment.
1424  *
1425  * Called with STREAM_LOCK
1426  */
1427 static gboolean
gst_qtdemux_perform_seek(GstQTDemux * qtdemux,GstSegment * segment,guint32 seqnum,GstSeekFlags flags)1428 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1429     guint32 seqnum, GstSeekFlags flags)
1430 {
1431   gint64 desired_offset;
1432   guint i;
1433 
1434   desired_offset = segment->position;
1435 
1436   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1437       GST_TIME_ARGS (desired_offset));
1438 
1439   /* may not have enough fragmented info to do this adjustment,
1440    * and we can't scan (and probably should not) at this time with
1441    * possibly flushing upstream */
1442   if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1443     gint64 min_offset;
1444     gboolean next, before, after;
1445 
1446     before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1447     after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1448     next = after && !before;
1449     if (segment->rate < 0)
1450       next = !next;
1451 
1452     gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1453         NULL);
1454     GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1455         GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1456     desired_offset = min_offset;
1457   }
1458 
1459   /* and set all streams to the final position */
1460   GST_OBJECT_LOCK (qtdemux);
1461   gst_flow_combiner_reset (qtdemux->flowcombiner);
1462   GST_OBJECT_UNLOCK (qtdemux);
1463   qtdemux->segment_seqnum = seqnum;
1464   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1465     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1466 
1467     stream->time_position = desired_offset;
1468     stream->accumulated_base = 0;
1469     stream->sample_index = -1;
1470     stream->offset_in_sample = 0;
1471     stream->segment_index = -1;
1472     stream->sent_eos = FALSE;
1473     stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1474 
1475     if (segment->flags & GST_SEEK_FLAG_FLUSH)
1476       gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1477   }
1478   segment->position = desired_offset;
1479   if (segment->rate >= 0) {
1480     segment->start = desired_offset;
1481     /* We need to update time as we update start in that direction */
1482     segment->time = desired_offset;
1483 
1484     /* we stop at the end */
1485     if (segment->stop == -1)
1486       segment->stop = segment->duration;
1487   } else {
1488     segment->stop = desired_offset;
1489   }
1490 
1491   if (qtdemux->fragmented)
1492     qtdemux->fragmented_seek_pending = TRUE;
1493 
1494   return TRUE;
1495 }
1496 
1497 /* do a seek in pull based mode */
1498 static gboolean
gst_qtdemux_do_seek(GstQTDemux * qtdemux,GstPad * pad,GstEvent * event)1499 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1500 {
1501   gdouble rate = 1.0;
1502   GstFormat format;
1503   GstSeekFlags flags;
1504   GstSeekType cur_type, stop_type;
1505   gint64 cur, stop;
1506   gboolean flush, instant_rate_change;
1507   gboolean update;
1508   GstSegment seeksegment;
1509   guint32 seqnum = GST_SEQNUM_INVALID;
1510   GstEvent *flush_event;
1511   gboolean ret;
1512 
1513   GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1514 
1515   gst_event_parse_seek (event, &rate, &format, &flags,
1516       &cur_type, &cur, &stop_type, &stop);
1517   seqnum = gst_event_get_seqnum (event);
1518 
1519   /* we have to have a format as the segment format. Try to convert
1520    * if not. */
1521   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1522           stop_type, &stop))
1523     goto no_format;
1524 
1525   GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1526 
1527   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1528   instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1529 
1530   /* Directly send the instant-rate-change event here before taking the
1531    * stream-lock so that it can be applied as soon as possible */
1532   if (instant_rate_change) {
1533     GstEvent *ev;
1534 
1535     /* instant rate change only supported if direction does not change. All
1536      * other requirements are already checked before creating the seek event
1537      * but let's double-check here to be sure */
1538     if ((qtdemux->segment.rate > 0 && rate < 0) ||
1539         (qtdemux->segment.rate < 0 && rate > 0) ||
1540         cur_type != GST_SEEK_TYPE_NONE ||
1541         stop_type != GST_SEEK_TYPE_NONE || flush) {
1542       GST_ERROR_OBJECT (qtdemux,
1543           "Instant rate change seeks only supported in the "
1544           "same direction, without flushing and position change");
1545       return FALSE;
1546     }
1547 
1548     ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1549         (GstSegmentFlags) flags);
1550     gst_event_set_seqnum (ev, seqnum);
1551     gst_qtdemux_push_event (qtdemux, ev);
1552     return TRUE;
1553   }
1554 
1555   /* stop streaming, either by flushing or by pausing the task */
1556   if (flush) {
1557     flush_event = gst_event_new_flush_start ();
1558     if (seqnum != GST_SEQNUM_INVALID)
1559       gst_event_set_seqnum (flush_event, seqnum);
1560     /* unlock upstream pull_range */
1561     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1562     /* make sure out loop function exits */
1563     gst_qtdemux_push_event (qtdemux, flush_event);
1564   } else {
1565     /* non flushing seek, pause the task */
1566     gst_pad_pause_task (qtdemux->sinkpad);
1567   }
1568 
1569   /* wait for streaming to finish */
1570   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1571 
1572   /* copy segment, we need this because we still need the old
1573    * segment when we close the current segment. */
1574   memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1575 
1576   /* configure the segment with the seek variables */
1577   GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1578   if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1579           cur_type, cur, stop_type, stop, &update)) {
1580     ret = FALSE;
1581     GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1582   } else {
1583     /* now do the seek */
1584     ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1585   }
1586 
1587   /* prepare for streaming again */
1588   if (flush) {
1589     flush_event = gst_event_new_flush_stop (TRUE);
1590     if (seqnum != GST_SEQNUM_INVALID)
1591       gst_event_set_seqnum (flush_event, seqnum);
1592 
1593     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1594     gst_qtdemux_push_event (qtdemux, flush_event);
1595   }
1596 
1597   /* commit the new segment */
1598   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1599 
1600   if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1601     GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1602         qtdemux->segment.format, qtdemux->segment.position);
1603     if (seqnum != GST_SEQNUM_INVALID)
1604       gst_message_set_seqnum (msg, seqnum);
1605     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1606   }
1607 
1608   /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1609   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1610       qtdemux->sinkpad, NULL);
1611 
1612   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1613 
1614   return ret;
1615 
1616   /* ERRORS */
1617 no_format:
1618   {
1619     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1620     return FALSE;
1621   }
1622 }
1623 
1624 static gboolean
qtdemux_ensure_index(GstQTDemux * qtdemux)1625 qtdemux_ensure_index (GstQTDemux * qtdemux)
1626 {
1627   guint i;
1628 
1629   GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1630 
1631   /* Build complete index */
1632   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1633     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1634 
1635     if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1636       GST_LOG_OBJECT (qtdemux,
1637           "Building complete index of track-id %u for seeking failed!",
1638           stream->track_id);
1639       return FALSE;
1640     }
1641   }
1642 
1643   return TRUE;
1644 }
1645 
1646 static gboolean
gst_qtdemux_handle_src_event(GstPad * pad,GstObject * parent,GstEvent * event)1647 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1648     GstEvent * event)
1649 {
1650   gboolean res = TRUE;
1651   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1652 
1653   switch (GST_EVENT_TYPE (event)) {
1654     case GST_EVENT_RECONFIGURE:
1655       GST_OBJECT_LOCK (qtdemux);
1656       gst_flow_combiner_reset (qtdemux->flowcombiner);
1657       GST_OBJECT_UNLOCK (qtdemux);
1658       res = gst_pad_event_default (pad, parent, event);
1659       break;
1660     case GST_EVENT_SEEK:
1661     {
1662       GstSeekFlags flags = 0;
1663       GstFormat seek_format;
1664       gboolean instant_rate_change;
1665 
1666 #ifndef GST_DISABLE_GST_DEBUG
1667       GstClockTime ts = gst_util_get_timestamp ();
1668 #endif
1669       guint32 seqnum = gst_event_get_seqnum (event);
1670 
1671       qtdemux->received_seek = TRUE;
1672 
1673       gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1674           NULL);
1675       instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1676 
1677       if (seqnum == qtdemux->segment_seqnum) {
1678         GST_LOG_OBJECT (pad,
1679             "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1680         gst_event_unref (event);
1681         return TRUE;
1682       }
1683 
1684       if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1685         /* seek should be handled by upstream, we might need to re-download fragments */
1686         GST_DEBUG_OBJECT (qtdemux,
1687             "let upstream handle seek for fragmented playback");
1688         goto upstream;
1689       }
1690 
1691       if (seek_format == GST_FORMAT_BYTES) {
1692         GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1693         gst_event_unref (event);
1694         return FALSE;
1695       }
1696 
1697       gst_event_parse_seek_trickmode_interval (event,
1698           &qtdemux->trickmode_interval);
1699 
1700       /* Build complete index for seeking;
1701        * if not a fragmented file at least and we're really doing a seek,
1702        * not just an instant-rate-change */
1703       if (!qtdemux->fragmented && !instant_rate_change) {
1704         if (!qtdemux_ensure_index (qtdemux))
1705           goto index_failed;
1706       }
1707 #ifndef GST_DISABLE_GST_DEBUG
1708       ts = gst_util_get_timestamp () - ts;
1709       GST_INFO_OBJECT (qtdemux,
1710           "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1711 #endif
1712       if (qtdemux->pullbased) {
1713         res = gst_qtdemux_do_seek (qtdemux, pad, event);
1714       } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1715         GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1716         res = TRUE;
1717       } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1718           && QTDEMUX_N_STREAMS (qtdemux)
1719           && !qtdemux->fragmented) {
1720         res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1721       } else {
1722         GST_DEBUG_OBJECT (qtdemux,
1723             "ignoring seek in push mode in current state");
1724         res = FALSE;
1725       }
1726       gst_event_unref (event);
1727     }
1728       break;
1729     default:
1730     upstream:
1731       res = gst_pad_event_default (pad, parent, event);
1732       break;
1733   }
1734 
1735 done:
1736   return res;
1737 
1738   /* ERRORS */
1739 index_failed:
1740   {
1741     GST_ERROR_OBJECT (qtdemux, "Index failed");
1742     gst_event_unref (event);
1743     res = FALSE;
1744     goto done;
1745   }
1746 }
1747 
1748 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1749  *
1750  * If @fw is false, the coding order is explored backwards.
1751  *
1752  * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1753  * sample is found for that track.
1754  *
1755  * The stream and sample index of the sample with the minimum offset in the direction explored
1756  * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1757  *
1758  * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1759  * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1760  * @_stream and @_index. */
1761 static void
gst_qtdemux_find_sample(GstQTDemux * qtdemux,gint64 byte_pos,gboolean fw,gboolean set,QtDemuxStream ** _stream,gint * _index,gint64 * _time)1762 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1763     gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1764 {
1765   gint i, index;
1766   gint64 time, min_time;
1767   QtDemuxStream *stream;
1768   gint iter;
1769 
1770   min_time = -1;
1771   stream = NULL;
1772   index = -1;
1773 
1774   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1775     QtDemuxStream *str;
1776     gint inc;
1777     gboolean set_sample;
1778 
1779     str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1780     set_sample = !set;
1781 
1782     if (fw) {
1783       i = 0;
1784       inc = 1;
1785     } else {
1786       i = str->n_samples - 1;
1787       inc = -1;
1788     }
1789 
1790     for (; (i >= 0) && (i < str->n_samples); i += inc) {
1791       if (str->samples[i].size == 0)
1792         continue;
1793 
1794       if (fw && (str->samples[i].offset < byte_pos))
1795         continue;
1796 
1797       if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1798         continue;
1799 
1800       /* move stream to first available sample */
1801       if (set) {
1802         gst_qtdemux_move_stream (qtdemux, str, i);
1803         set_sample = TRUE;
1804       }
1805 
1806       /* avoid index from sparse streams since they might be far away */
1807       if (!CUR_STREAM (str)->sparse) {
1808         /* determine min/max time */
1809         time = QTSAMPLE_PTS (str, &str->samples[i]);
1810         if (min_time == -1 || (!fw && time > min_time) ||
1811             (fw && time < min_time)) {
1812           min_time = time;
1813         }
1814 
1815         /* determine stream with leading sample, to get its position */
1816         if (!stream ||
1817             (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1818             (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1819           stream = str;
1820           index = i;
1821         }
1822       }
1823       break;
1824     }
1825 
1826     /* no sample for this stream, mark eos */
1827     if (!set_sample)
1828       gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1829   }
1830 
1831   if (_time)
1832     *_time = min_time;
1833   if (_stream)
1834     *_stream = stream;
1835   if (_index)
1836     *_index = index;
1837 }
1838 
1839 /* Copied from mpegtsbase code */
1840 /* FIXME: replace this function when we add new util function for stream-id creation */
1841 static gchar *
_get_upstream_id(GstQTDemux * demux)1842 _get_upstream_id (GstQTDemux * demux)
1843 {
1844   gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1845 
1846   if (!upstream_id) {
1847     /* Try to create one from the upstream URI, else use a randome number */
1848     GstQuery *query;
1849     gchar *uri = NULL;
1850 
1851     /* Try to generate one from the URI query and
1852      * if it fails take a random number instead */
1853     query = gst_query_new_uri ();
1854     if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1855       gst_query_parse_uri (query, &uri);
1856     }
1857 
1858     if (uri) {
1859       GChecksum *cs;
1860 
1861       /* And then generate an SHA256 sum of the URI */
1862       cs = g_checksum_new (G_CHECKSUM_SHA256);
1863       g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1864       g_free (uri);
1865       upstream_id = g_strdup (g_checksum_get_string (cs));
1866       g_checksum_free (cs);
1867     } else {
1868       /* Just get some random number if the URI query fails */
1869       GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1870           "implementing a deterministic way of creating a stream-id");
1871       upstream_id =
1872           g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1873           g_random_int (), g_random_int ());
1874     }
1875 
1876     gst_query_unref (query);
1877   }
1878   return upstream_id;
1879 }
1880 
1881 static QtDemuxStream *
_create_stream(GstQTDemux * demux,guint32 track_id)1882 _create_stream (GstQTDemux * demux, guint32 track_id)
1883 {
1884   QtDemuxStream *stream;
1885   gchar *upstream_id;
1886 
1887   stream = g_new0 (QtDemuxStream, 1);
1888   stream->demux = demux;
1889   stream->track_id = track_id;
1890   upstream_id = _get_upstream_id (demux);
1891   stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1892   g_free (upstream_id);
1893   /* new streams always need a discont */
1894   stream->discont = TRUE;
1895   /* we enable clipping for raw audio/video streams */
1896   stream->need_clip = FALSE;
1897   stream->process_func = NULL;
1898   stream->segment_index = -1;
1899   stream->time_position = 0;
1900   stream->sample_index = -1;
1901   stream->offset_in_sample = 0;
1902   stream->new_stream = TRUE;
1903   stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1904   stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1905   stream->protected = FALSE;
1906   stream->protection_scheme_type = 0;
1907   stream->protection_scheme_version = 0;
1908   stream->protection_scheme_info = NULL;
1909   stream->n_samples_moof = 0;
1910   stream->duration_moof = 0;
1911   stream->duration_last_moof = 0;
1912   stream->alignment = 1;
1913   stream->stream_tags = gst_tag_list_new_empty ();
1914   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1915   g_queue_init (&stream->protection_scheme_event_queue);
1916   stream->ref_count = 1;
1917   /* consistent default for push based mode */
1918   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1919 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
1920   stream->has_push_first_frame = FALSE;
1921 #endif
1922   return stream;
1923 }
1924 
1925 static gboolean
gst_qtdemux_setcaps(GstQTDemux * demux,GstCaps * caps)1926 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1927 {
1928   GstStructure *structure;
1929   const gchar *variant;
1930   const GstCaps *mediacaps = NULL;
1931 
1932   GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1933 
1934   structure = gst_caps_get_structure (caps, 0);
1935   variant = gst_structure_get_string (structure, "variant");
1936 
1937   if (variant && strcmp (variant, "mss-fragmented") == 0) {
1938     QtDemuxStream *stream;
1939     const GValue *value;
1940 
1941     demux->fragmented = TRUE;
1942     demux->mss_mode = TRUE;
1943 
1944     if (QTDEMUX_N_STREAMS (demux) > 1) {
1945       /* can't do this, we can only renegotiate for another mss format */
1946       return FALSE;
1947     }
1948 
1949     value = gst_structure_get_value (structure, "media-caps");
1950     /* create stream */
1951     if (value) {
1952       const GValue *timescale_v;
1953 
1954       /* TODO update when stream changes during playback */
1955 
1956       if (QTDEMUX_N_STREAMS (demux) == 0) {
1957         stream = _create_stream (demux, 1);
1958         g_ptr_array_add (demux->active_streams, stream);
1959         /* mss has no stsd/stsd entry, use id 0 as default */
1960         stream->stsd_entries_length = 1;
1961         stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1962         stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1963       } else {
1964         stream = QTDEMUX_NTH_STREAM (demux, 0);
1965       }
1966 
1967       timescale_v = gst_structure_get_value (structure, "timescale");
1968       if (timescale_v) {
1969         stream->timescale = g_value_get_uint64 (timescale_v);
1970       } else {
1971         /* default mss timescale */
1972         stream->timescale = 10000000;
1973       }
1974       demux->timescale = stream->timescale;
1975 
1976       mediacaps = gst_value_get_caps (value);
1977       if (!CUR_STREAM (stream)->caps
1978           || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1979         GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1980             mediacaps);
1981         stream->new_caps = TRUE;
1982       }
1983       gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1984       structure = gst_caps_get_structure (mediacaps, 0);
1985       if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1986         stream->subtype = FOURCC_vide;
1987 
1988         gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1989         gst_structure_get_int (structure, "height",
1990             &CUR_STREAM (stream)->height);
1991         gst_structure_get_fraction (structure, "framerate",
1992             &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1993       } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1994         gint rate = 0;
1995         stream->subtype = FOURCC_soun;
1996         gst_structure_get_int (structure, "channels",
1997             &CUR_STREAM (stream)->n_channels);
1998         gst_structure_get_int (structure, "rate", &rate);
1999         CUR_STREAM (stream)->rate = rate;
2000       } else if (gst_structure_has_name (structure, "application/x-cenc")) {
2001         if (gst_structure_has_field (structure, "original-media-type")) {
2002           const gchar *media_type =
2003               gst_structure_get_string (structure, "original-media-type");
2004           if (g_str_has_prefix (media_type, "video")) {
2005             stream->subtype = FOURCC_vide;
2006           } else if (g_str_has_prefix (media_type, "audio")) {
2007             stream->subtype = FOURCC_soun;
2008           }
2009         }
2010       }
2011     }
2012     gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2013   } else {
2014     demux->mss_mode = FALSE;
2015   }
2016 
2017   return TRUE;
2018 }
2019 
2020 static void
gst_qtdemux_reset(GstQTDemux * qtdemux,gboolean hard)2021 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2022 {
2023   gint i;
2024 
2025   GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2026   gst_pad_stop_task (qtdemux->sinkpad);
2027 
2028   if (hard || qtdemux->upstream_format_is_time) {
2029     qtdemux->state = QTDEMUX_STATE_INITIAL;
2030     qtdemux->neededbytes = 16;
2031     qtdemux->todrop = 0;
2032     qtdemux->pullbased = FALSE;
2033     g_clear_pointer (&qtdemux->redirect_location, g_free);
2034     qtdemux->first_mdat = -1;
2035     qtdemux->header_size = 0;
2036     qtdemux->mdatoffset = -1;
2037     qtdemux->restoredata_offset = -1;
2038     if (qtdemux->mdatbuffer)
2039       gst_buffer_unref (qtdemux->mdatbuffer);
2040     if (qtdemux->restoredata_buffer)
2041       gst_buffer_unref (qtdemux->restoredata_buffer);
2042     qtdemux->mdatbuffer = NULL;
2043     qtdemux->restoredata_buffer = NULL;
2044     qtdemux->mdatleft = 0;
2045     qtdemux->mdatsize = 0;
2046     if (qtdemux->comp_brands)
2047       gst_buffer_unref (qtdemux->comp_brands);
2048     qtdemux->comp_brands = NULL;
2049     qtdemux->last_moov_offset = -1;
2050     if (qtdemux->moov_node_compressed) {
2051       g_node_destroy (qtdemux->moov_node_compressed);
2052       if (qtdemux->moov_node)
2053         g_free (qtdemux->moov_node->data);
2054     }
2055     qtdemux->moov_node_compressed = NULL;
2056     if (qtdemux->moov_node)
2057       g_node_destroy (qtdemux->moov_node);
2058     qtdemux->moov_node = NULL;
2059     if (qtdemux->tag_list)
2060       gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2061     qtdemux->tag_list = gst_tag_list_new_empty ();
2062     gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2063 #if 0
2064     if (qtdemux->element_index)
2065       gst_object_unref (qtdemux->element_index);
2066     qtdemux->element_index = NULL;
2067 #endif
2068     qtdemux->major_brand = 0;
2069     qtdemux->upstream_format_is_time = FALSE;
2070     qtdemux->upstream_seekable = FALSE;
2071     qtdemux->upstream_size = 0;
2072 
2073     qtdemux->fragment_start = -1;
2074     qtdemux->fragment_start_offset = -1;
2075     qtdemux->duration = 0;
2076     qtdemux->moof_offset = 0;
2077     qtdemux->chapters_track_id = 0;
2078     qtdemux->have_group_id = FALSE;
2079     qtdemux->group_id = G_MAXUINT;
2080 
2081     g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2082         NULL);
2083     g_queue_clear (&qtdemux->protection_event_queue);
2084 
2085     qtdemux->received_seek = FALSE;
2086     qtdemux->first_moof_already_parsed = FALSE;
2087   }
2088   qtdemux->offset = 0;
2089   gst_adapter_clear (qtdemux->adapter);
2090   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2091   qtdemux->need_segment = TRUE;
2092 
2093   if (hard) {
2094     qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2095     qtdemux->trickmode_interval = 0;
2096     g_ptr_array_set_size (qtdemux->active_streams, 0);
2097     g_ptr_array_set_size (qtdemux->old_streams, 0);
2098     qtdemux->n_video_streams = 0;
2099     qtdemux->n_audio_streams = 0;
2100     qtdemux->n_sub_streams = 0;
2101     qtdemux->exposed = FALSE;
2102     qtdemux->fragmented = FALSE;
2103     qtdemux->mss_mode = FALSE;
2104     gst_caps_replace (&qtdemux->media_caps, NULL);
2105     qtdemux->timescale = 0;
2106     qtdemux->got_moov = FALSE;
2107     qtdemux->cenc_aux_info_offset = 0;
2108     qtdemux->cenc_aux_info_sizes = NULL;
2109     qtdemux->cenc_aux_sample_count = 0;
2110     if (qtdemux->protection_system_ids) {
2111       g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2112       qtdemux->protection_system_ids = NULL;
2113     }
2114     qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2115         && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2116         GST_BIN_FLAG_STREAMS_AWARE);
2117 
2118     if (qtdemux->preferred_protection_system_id) {
2119       g_free (qtdemux->preferred_protection_system_id);
2120       qtdemux->preferred_protection_system_id = NULL;
2121     }
2122   } else if (qtdemux->mss_mode) {
2123     gst_flow_combiner_reset (qtdemux->flowcombiner);
2124     g_ptr_array_foreach (qtdemux->active_streams,
2125         (GFunc) gst_qtdemux_stream_clear, NULL);
2126   } else {
2127     gst_flow_combiner_reset (qtdemux->flowcombiner);
2128     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2129       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2130       stream->sent_eos = FALSE;
2131       stream->time_position = 0;
2132       stream->accumulated_base = 0;
2133       stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2134     }
2135   }
2136 }
2137 
2138 
2139 /* Maps the @segment to the qt edts internal segments and pushes
2140  * the corresponding segment event.
2141  *
2142  * If it ends up being at a empty segment, a gap will be pushed and the next
2143  * edts segment will be activated in sequence.
2144  *
2145  * To be used in push-mode only */
2146 static void
gst_qtdemux_map_and_push_segments(GstQTDemux * qtdemux,GstSegment * segment)2147 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2148 {
2149   gint i, iter;
2150 
2151   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2152     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2153 
2154     stream->time_position = segment->start;
2155 
2156     /* in push mode we should be guaranteed that we will have empty segments
2157      * at the beginning and then one segment after, other scenarios are not
2158      * supported and are discarded when parsing the edts */
2159     for (i = 0; i < stream->n_segments; i++) {
2160       if (stream->segments[i].stop_time > segment->start) {
2161         /* push the empty segment and move to the next one */
2162         gst_qtdemux_activate_segment (qtdemux, stream, i,
2163             stream->time_position);
2164         if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2165           gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2166               stream->time_position);
2167 
2168           /* accumulate previous segments */
2169           if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2170             stream->accumulated_base +=
2171                 (stream->segment.stop -
2172                 stream->segment.start) / ABS (stream->segment.rate);
2173           continue;
2174         }
2175 
2176         g_assert (i == stream->n_segments - 1);
2177       }
2178     }
2179   }
2180 }
2181 
2182 static void
gst_qtdemux_stream_concat(GstQTDemux * qtdemux,GPtrArray * dest,GPtrArray * src)2183 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2184     GPtrArray * src)
2185 {
2186   guint i;
2187   guint len;
2188 
2189   len = src->len;
2190 
2191   if (len == 0)
2192     return;
2193 
2194   for (i = 0; i < len; i++) {
2195     QtDemuxStream *stream = g_ptr_array_index (src, i);
2196 
2197 #ifndef GST_DISABLE_GST_DEBUG
2198     GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2199         stream, GST_STR_NULL (stream->stream_id), dest);
2200 #endif
2201     g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2202   }
2203 
2204   g_ptr_array_set_size (src, 0);
2205 }
2206 
2207 static gboolean
gst_qtdemux_handle_sink_event(GstPad * sinkpad,GstObject * parent,GstEvent * event)2208 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2209     GstEvent * event)
2210 {
2211   GstQTDemux *demux = GST_QTDEMUX (parent);
2212   gboolean res = TRUE;
2213 
2214   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2215 
2216   switch (GST_EVENT_TYPE (event)) {
2217     case GST_EVENT_SEGMENT:
2218     {
2219       gint64 offset = 0;
2220       QtDemuxStream *stream;
2221       gint idx;
2222       GstSegment segment;
2223 
2224       /* some debug output */
2225       gst_event_copy_segment (event, &segment);
2226       GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2227           &segment);
2228 
2229       if (segment.format == GST_FORMAT_TIME) {
2230         demux->upstream_format_is_time = TRUE;
2231         demux->segment_seqnum = gst_event_get_seqnum (event);
2232       } else {
2233         GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2234             "not in time format");
2235 
2236         /* chain will send initial newsegment after pads have been added */
2237         if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2238           GST_DEBUG_OBJECT (demux, "still starting, eating event");
2239           goto exit;
2240         }
2241       }
2242 
2243       /* check if this matches a time seek we received previously
2244        * FIXME for backwards compatibility reasons we use the
2245        * seek_offset here to compare. In the future we might want to
2246        * change this to use the seqnum as it uniquely should identify
2247        * the segment that corresponds to the seek. */
2248       GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2249           ", received segment offset %" G_GINT64_FORMAT,
2250           demux->seek_offset, segment.start);
2251       if (segment.format == GST_FORMAT_BYTES
2252           && demux->seek_offset == segment.start) {
2253         GST_OBJECT_LOCK (demux);
2254         offset = segment.start;
2255 
2256         segment.format = GST_FORMAT_TIME;
2257         segment.start = demux->push_seek_start;
2258         segment.stop = demux->push_seek_stop;
2259         GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2260             "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2261             GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2262         GST_OBJECT_UNLOCK (demux);
2263       }
2264 
2265       /* we only expect a BYTE segment, e.g. following a seek */
2266       if (segment.format == GST_FORMAT_BYTES) {
2267         if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2268           offset = segment.start;
2269 
2270           gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2271               NULL, (gint64 *) & segment.start);
2272           if ((gint64) segment.start < 0)
2273             segment.start = 0;
2274         }
2275         if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2276           gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2277               NULL, (gint64 *) & segment.stop);
2278           /* keyframe seeking should already arrange for start >= stop,
2279            * but make sure in other rare cases */
2280           segment.stop = MAX (segment.stop, segment.start);
2281         }
2282       } else if (segment.format == GST_FORMAT_TIME) {
2283         /* push all data on the adapter before starting this
2284          * new segment */
2285         gst_qtdemux_process_adapter (demux, TRUE);
2286       } else {
2287         GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2288         goto exit;
2289       }
2290 
2291       /* We shouldn't modify upstream driven TIME FORMAT segment */
2292       if (!demux->upstream_format_is_time) {
2293         /* accept upstream's notion of segment and distribute along */
2294         segment.format = GST_FORMAT_TIME;
2295         segment.position = segment.time = segment.start;
2296         segment.duration = demux->segment.duration;
2297         segment.base = gst_segment_to_running_time (&demux->segment,
2298             GST_FORMAT_TIME, demux->segment.position);
2299       }
2300 
2301       gst_segment_copy_into (&segment, &demux->segment);
2302       GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2303 
2304       /* map segment to internal qt segments and push on each stream */
2305       if (QTDEMUX_N_STREAMS (demux)) {
2306         demux->need_segment = TRUE;
2307         gst_qtdemux_check_send_pending_segment (demux);
2308       }
2309 
2310       /* clear leftover in current segment, if any */
2311       gst_adapter_clear (demux->adapter);
2312 
2313       /* set up streaming thread */
2314       demux->offset = offset;
2315       if (demux->upstream_format_is_time) {
2316         GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2317             "set values to restart reading from a new atom");
2318         demux->neededbytes = 16;
2319         demux->todrop = 0;
2320       } else {
2321         gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2322             NULL);
2323         if (stream) {
2324           demux->todrop = stream->samples[idx].offset - offset;
2325           demux->neededbytes = demux->todrop + stream->samples[idx].size;
2326         } else {
2327           /* set up for EOS */
2328           demux->neededbytes = -1;
2329           demux->todrop = 0;
2330         }
2331       }
2332     exit:
2333       gst_event_unref (event);
2334       res = TRUE;
2335       goto drop;
2336     }
2337     case GST_EVENT_FLUSH_START:
2338     {
2339       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2340         gst_event_unref (event);
2341         goto drop;
2342       }
2343       QTDEMUX_EXPOSE_LOCK (demux);
2344       res = gst_pad_event_default (demux->sinkpad, parent, event);
2345       QTDEMUX_EXPOSE_UNLOCK (demux);
2346       goto drop;
2347     }
2348     case GST_EVENT_FLUSH_STOP:
2349     {
2350       guint64 dur;
2351 
2352       dur = demux->segment.duration;
2353       gst_qtdemux_reset (demux, FALSE);
2354       demux->segment.duration = dur;
2355 
2356       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2357         gst_event_unref (event);
2358         goto drop;
2359       }
2360       break;
2361     }
2362     case GST_EVENT_EOS:
2363       /* If we are in push mode, and get an EOS before we've seen any streams,
2364        * then error out - we have nowhere to send the EOS */
2365       if (!demux->pullbased) {
2366         gint i;
2367         gboolean has_valid_stream = FALSE;
2368         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2369           if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2370             has_valid_stream = TRUE;
2371             break;
2372           }
2373         }
2374         if (!has_valid_stream)
2375           gst_qtdemux_post_no_playable_stream_error (demux);
2376         else {
2377           GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2378               (guint) gst_adapter_available (demux->adapter));
2379           if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2380             res = FALSE;
2381           }
2382         }
2383       }
2384       break;
2385     case GST_EVENT_CAPS:{
2386       GstCaps *caps = NULL;
2387 
2388       gst_event_parse_caps (event, &caps);
2389       gst_qtdemux_setcaps (demux, caps);
2390       res = TRUE;
2391       gst_event_unref (event);
2392       goto drop;
2393     }
2394     case GST_EVENT_PROTECTION:
2395     {
2396       const gchar *system_id = NULL;
2397 
2398       gst_event_parse_protection (event, &system_id, NULL, NULL);
2399       GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2400           system_id);
2401       gst_qtdemux_append_protection_system_id (demux, system_id);
2402       /* save the event for later, for source pads that have not been created */
2403       g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2404       /* send it to all pads that already exist */
2405       gst_qtdemux_push_event (demux, event);
2406       res = TRUE;
2407       goto drop;
2408     }
2409     case GST_EVENT_STREAM_START:
2410     {
2411       res = TRUE;
2412       gst_event_unref (event);
2413 
2414       /* Drain all the buffers */
2415       gst_qtdemux_process_adapter (demux, TRUE);
2416       gst_qtdemux_reset (demux, FALSE);
2417       /* We expect new moov box after new stream-start event */
2418       if (demux->exposed) {
2419         gst_qtdemux_stream_concat (demux,
2420             demux->old_streams, demux->active_streams);
2421       }
2422 
2423       goto drop;
2424     }
2425     default:
2426       break;
2427   }
2428 
2429   res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2430 
2431 drop:
2432   return res;
2433 }
2434 
2435 static gboolean
gst_qtdemux_handle_sink_query(GstPad * pad,GstObject * parent,GstQuery * query)2436 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2437     GstQuery * query)
2438 {
2439   GstQTDemux *demux = GST_QTDEMUX (parent);
2440   gboolean res = FALSE;
2441 
2442   switch (GST_QUERY_TYPE (query)) {
2443     case GST_QUERY_BITRATE:
2444     {
2445       GstClockTime duration;
2446 
2447       /* populate demux->upstream_size if not done yet */
2448       gst_qtdemux_check_seekability (demux);
2449 
2450       if (demux->upstream_size != -1
2451           && gst_qtdemux_get_duration (demux, &duration)) {
2452         guint bitrate =
2453             gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2454             duration);
2455 
2456         GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2457             " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2458             demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2459 
2460         /* TODO: better results based on ranges/index tables */
2461         gst_query_set_bitrate (query, bitrate);
2462         res = TRUE;
2463       }
2464       break;
2465     }
2466     default:
2467       res = gst_pad_query_default (pad, (GstObject *) demux, query);
2468       break;
2469   }
2470 
2471   return res;
2472 }
2473 
2474 
2475 #if 0
2476 static void
2477 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2478 {
2479   GstQTDemux *demux = GST_QTDEMUX (element);
2480 
2481   GST_OBJECT_LOCK (demux);
2482   if (demux->element_index)
2483     gst_object_unref (demux->element_index);
2484   if (index) {
2485     demux->element_index = gst_object_ref (index);
2486   } else {
2487     demux->element_index = NULL;
2488   }
2489   GST_OBJECT_UNLOCK (demux);
2490   /* object lock might be taken again */
2491   if (index)
2492     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2493   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2494       demux->element_index, demux->index_id);
2495 }
2496 
2497 static GstIndex *
2498 gst_qtdemux_get_index (GstElement * element)
2499 {
2500   GstIndex *result = NULL;
2501   GstQTDemux *demux = GST_QTDEMUX (element);
2502 
2503   GST_OBJECT_LOCK (demux);
2504   if (demux->element_index)
2505     result = gst_object_ref (demux->element_index);
2506   GST_OBJECT_UNLOCK (demux);
2507 
2508   GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2509 
2510   return result;
2511 }
2512 #endif
2513 
2514 static void
gst_qtdemux_stbl_free(QtDemuxStream * stream)2515 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2516 {
2517   g_free ((gpointer) stream->stco.data);
2518   stream->stco.data = NULL;
2519   g_free ((gpointer) stream->stsz.data);
2520   stream->stsz.data = NULL;
2521   g_free ((gpointer) stream->stsc.data);
2522   stream->stsc.data = NULL;
2523   g_free ((gpointer) stream->stts.data);
2524   stream->stts.data = NULL;
2525   g_free ((gpointer) stream->stss.data);
2526   stream->stss.data = NULL;
2527   g_free ((gpointer) stream->stps.data);
2528   stream->stps.data = NULL;
2529   g_free ((gpointer) stream->ctts.data);
2530   stream->ctts.data = NULL;
2531 }
2532 
2533 static void
gst_qtdemux_stream_flush_segments_data(QtDemuxStream * stream)2534 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2535 {
2536   g_free (stream->segments);
2537   stream->segments = NULL;
2538   stream->segment_index = -1;
2539   stream->accumulated_base = 0;
2540 }
2541 
2542 static void
gst_qtdemux_stream_flush_samples_data(QtDemuxStream * stream)2543 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2544 {
2545   g_free (stream->samples);
2546   stream->samples = NULL;
2547   gst_qtdemux_stbl_free (stream);
2548 
2549   /* fragments */
2550   g_free (stream->ra_entries);
2551   stream->ra_entries = NULL;
2552   stream->n_ra_entries = 0;
2553 
2554   stream->sample_index = -1;
2555   stream->stbl_index = -1;
2556   stream->n_samples = 0;
2557   stream->time_position = 0;
2558 
2559   stream->n_samples_moof = 0;
2560   stream->duration_moof = 0;
2561   stream->duration_last_moof = 0;
2562 }
2563 
2564 static void
gst_qtdemux_stream_clear(QtDemuxStream * stream)2565 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2566 {
2567   gint i;
2568   if (stream->allocator)
2569     gst_object_unref (stream->allocator);
2570   while (stream->buffers) {
2571     gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2572     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2573   }
2574   for (i = 0; i < stream->stsd_entries_length; i++) {
2575     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2576     if (entry->rgb8_palette) {
2577       gst_memory_unref (entry->rgb8_palette);
2578       entry->rgb8_palette = NULL;
2579     }
2580     entry->sparse = FALSE;
2581   }
2582 
2583   if (stream->stream_tags)
2584     gst_tag_list_unref (stream->stream_tags);
2585 
2586   stream->stream_tags = gst_tag_list_new_empty ();
2587   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2588   g_free (stream->redirect_uri);
2589   stream->redirect_uri = NULL;
2590   stream->sent_eos = FALSE;
2591   stream->protected = FALSE;
2592 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
2593   stream->has_push_first_frame = FALSE;
2594 #endif
2595   if (stream->protection_scheme_info) {
2596     if (stream->protection_scheme_type == FOURCC_cenc
2597         || stream->protection_scheme_type == FOURCC_cbcs) {
2598       QtDemuxCencSampleSetInfo *info =
2599           (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2600       if (info->default_properties)
2601         gst_structure_free (info->default_properties);
2602       if (info->crypto_info)
2603         g_ptr_array_free (info->crypto_info, TRUE);
2604     }
2605     if (stream->protection_scheme_type == FOURCC_aavd) {
2606       QtDemuxAavdEncryptionInfo *info =
2607           (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2608       if (info->default_properties)
2609         gst_structure_free (info->default_properties);
2610     }
2611     g_free (stream->protection_scheme_info);
2612     stream->protection_scheme_info = NULL;
2613   }
2614   stream->protection_scheme_type = 0;
2615   stream->protection_scheme_version = 0;
2616   g_queue_foreach (&stream->protection_scheme_event_queue,
2617       (GFunc) gst_event_unref, NULL);
2618   g_queue_clear (&stream->protection_scheme_event_queue);
2619   gst_qtdemux_stream_flush_segments_data (stream);
2620   gst_qtdemux_stream_flush_samples_data (stream);
2621 }
2622 
2623 static void
gst_qtdemux_stream_reset(QtDemuxStream * stream)2624 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2625 {
2626   gint i;
2627   gst_qtdemux_stream_clear (stream);
2628   for (i = 0; i < stream->stsd_entries_length; i++) {
2629     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2630     if (entry->caps) {
2631       gst_caps_unref (entry->caps);
2632       entry->caps = NULL;
2633     }
2634   }
2635   g_free (stream->stsd_entries);
2636   stream->stsd_entries = NULL;
2637   stream->stsd_entries_length = 0;
2638 }
2639 
2640 static QtDemuxStream *
gst_qtdemux_stream_ref(QtDemuxStream * stream)2641 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2642 {
2643   g_atomic_int_add (&stream->ref_count, 1);
2644 
2645   return stream;
2646 }
2647 
2648 static void
gst_qtdemux_stream_unref(QtDemuxStream * stream)2649 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2650 {
2651   if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2652     gst_qtdemux_stream_reset (stream);
2653     gst_tag_list_unref (stream->stream_tags);
2654     if (stream->pad) {
2655       GstQTDemux *demux = stream->demux;
2656       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2657       GST_OBJECT_LOCK (demux);
2658       gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2659       GST_OBJECT_UNLOCK (demux);
2660     }
2661     g_free (stream->stream_id);
2662     g_free (stream);
2663   }
2664 }
2665 
2666 static GstStateChangeReturn
gst_qtdemux_change_state(GstElement * element,GstStateChange transition)2667 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2668 {
2669   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2670   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2671 
2672   switch (transition) {
2673     case GST_STATE_CHANGE_READY_TO_PAUSED:
2674       gst_qtdemux_reset (qtdemux, TRUE);
2675       break;
2676     default:
2677       break;
2678   }
2679 
2680   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2681 
2682   switch (transition) {
2683     case GST_STATE_CHANGE_PAUSED_TO_READY:{
2684       gst_qtdemux_reset (qtdemux, TRUE);
2685       break;
2686     }
2687     default:
2688       break;
2689   }
2690 
2691   return result;
2692 }
2693 
2694 static void
gst_qtdemux_set_context(GstElement * element,GstContext * context)2695 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2696 {
2697   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2698 
2699   g_return_if_fail (GST_IS_CONTEXT (context));
2700 
2701   if (gst_context_has_context_type (context,
2702           "drm-preferred-decryption-system-id")) {
2703     const GstStructure *s;
2704 
2705     s = gst_context_get_structure (context);
2706     g_free (qtdemux->preferred_protection_system_id);
2707     qtdemux->preferred_protection_system_id =
2708         g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2709     GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2710         qtdemux->preferred_protection_system_id);
2711   }
2712 
2713   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2714 }
2715 
2716 static void
qtdemux_parse_ftyp(GstQTDemux * qtdemux,const guint8 * buffer,gint length)2717 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2718 {
2719   /* counts as header data */
2720   qtdemux->header_size += length;
2721 
2722   /* only consider at least a sufficiently complete ftyp atom */
2723   if (length >= 20) {
2724     GstBuffer *buf;
2725 
2726     qtdemux->major_brand = QT_FOURCC (buffer + 8);
2727     GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2728         GST_FOURCC_ARGS (qtdemux->major_brand));
2729     if (qtdemux->comp_brands)
2730       gst_buffer_unref (qtdemux->comp_brands);
2731     buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2732     gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2733   }
2734 }
2735 
2736 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)2737 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2738     QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2739     guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2740     guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2741     const guint8 * constant_iv)
2742 {
2743   GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2744   gst_buffer_fill (kid_buf, 0, kid, 16);
2745   if (info->default_properties)
2746     gst_structure_free (info->default_properties);
2747   info->default_properties =
2748       gst_structure_new ("application/x-cenc",
2749       "iv_size", G_TYPE_UINT, iv_size,
2750       "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2751       "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2752   GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2753       "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2754   gst_buffer_unref (kid_buf);
2755   if (protection_scheme_type == FOURCC_cbcs) {
2756     if (crypt_byte_block != 0 || skip_byte_block != 0) {
2757       gst_structure_set (info->default_properties, "crypt_byte_block",
2758           G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2759           skip_byte_block, NULL);
2760     }
2761     if (constant_iv != NULL) {
2762       GstBuffer *constant_iv_buf =
2763           gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2764       gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2765       gst_structure_set (info->default_properties, "constant_iv_size",
2766           G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2767           NULL);
2768       gst_buffer_unref (constant_iv_buf);
2769     }
2770     gst_structure_set (info->default_properties, "cipher-mode",
2771         G_TYPE_STRING, "cbcs", NULL);
2772   } else {
2773     gst_structure_set (info->default_properties, "cipher-mode",
2774         G_TYPE_STRING, "cenc", NULL);
2775   }
2776 }
2777 
2778 static gboolean
qtdemux_update_default_piff_encryption_settings(GstQTDemux * qtdemux,QtDemuxCencSampleSetInfo * info,GstByteReader * br)2779 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2780     QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2781 {
2782   guint32 algorithm_id = 0;
2783   const guint8 *kid;
2784   gboolean is_encrypted = TRUE;
2785   guint8 iv_size = 8;
2786 
2787   if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2788     GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2789     return FALSE;
2790   }
2791 
2792   algorithm_id >>= 8;
2793   if (algorithm_id == 0) {
2794     is_encrypted = FALSE;
2795   } else if (algorithm_id == 1) {
2796     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2797   } else if (algorithm_id == 2) {
2798     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2799   }
2800 
2801   if (!gst_byte_reader_get_uint8 (br, &iv_size))
2802     return FALSE;
2803 
2804   if (!gst_byte_reader_get_data (br, 16, &kid))
2805     return FALSE;
2806 
2807   qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2808       is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2809   gst_structure_set (info->default_properties, "piff_algorithm_id",
2810       G_TYPE_UINT, algorithm_id, NULL);
2811   return TRUE;
2812 }
2813 
2814 
2815 static void
qtdemux_parse_piff(GstQTDemux * qtdemux,const guint8 * buffer,gint length,guint offset)2816 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2817     guint offset)
2818 {
2819   GstByteReader br;
2820   guint8 version;
2821   guint32 flags = 0;
2822   guint i;
2823   guint iv_size = 8;
2824   QtDemuxStream *stream;
2825   GstStructure *structure;
2826   QtDemuxCencSampleSetInfo *ss_info = NULL;
2827   const gchar *system_id;
2828   gboolean uses_sub_sample_encryption = FALSE;
2829   guint32 sample_count;
2830 
2831   if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2832     return;
2833 
2834   stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2835 
2836   structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2837   if (!gst_structure_has_name (structure, "application/x-cenc")) {
2838     GST_WARNING_OBJECT (qtdemux,
2839         "Attempting PIFF box parsing on an unencrypted stream.");
2840     return;
2841   }
2842 
2843   gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2844       G_TYPE_STRING, &system_id, NULL);
2845   gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2846 
2847   stream->protected = TRUE;
2848   stream->protection_scheme_type = FOURCC_cenc;
2849 
2850   if (!stream->protection_scheme_info)
2851     stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2852 
2853   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2854   if (!ss_info->default_properties) {
2855     ss_info->default_properties =
2856         gst_structure_new ("application/x-cenc",
2857         "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2858         NULL);
2859 
2860   }
2861 
2862   if (ss_info->crypto_info) {
2863     GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2864     g_ptr_array_free (ss_info->crypto_info, TRUE);
2865     ss_info->crypto_info = NULL;
2866   }
2867 
2868   /* skip UUID */
2869   gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2870 
2871   if (!gst_byte_reader_get_uint8 (&br, &version)) {
2872     GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2873     return;
2874   }
2875 
2876   if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2877     GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2878     return;
2879   }
2880 
2881   if ((flags & 0x000001)) {
2882     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2883             &br))
2884       return;
2885   } else if ((flags & 0x000002)) {
2886     uses_sub_sample_encryption = TRUE;
2887   }
2888 
2889   if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2890           &iv_size)) {
2891     GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2892     return;
2893   }
2894 
2895   if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2896     GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2897     return;
2898   }
2899 
2900   ss_info->crypto_info =
2901       g_ptr_array_new_full (sample_count,
2902       (GDestroyNotify) qtdemux_gst_structure_free);
2903 
2904   for (i = 0; i < sample_count; ++i) {
2905     GstStructure *properties;
2906     guint8 *data;
2907     GstBuffer *buf;
2908 
2909     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2910     if (properties == NULL) {
2911       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2912       qtdemux->cenc_aux_sample_count = i;
2913       return;
2914     }
2915 
2916     if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2917       GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2918       gst_structure_free (properties);
2919       qtdemux->cenc_aux_sample_count = i;
2920       return;
2921     }
2922     buf = gst_buffer_new_wrapped (data, iv_size);
2923     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2924     gst_buffer_unref (buf);
2925 
2926     if (uses_sub_sample_encryption) {
2927       guint16 n_subsamples;
2928       const GValue *kid_buf_value;
2929 
2930       if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2931           || n_subsamples == 0) {
2932         GST_ERROR_OBJECT (qtdemux,
2933             "failed to get subsample count for sample %u", i);
2934         gst_structure_free (properties);
2935         qtdemux->cenc_aux_sample_count = i;
2936         return;
2937       }
2938       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2939       if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2940         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2941             i);
2942         gst_structure_free (properties);
2943         qtdemux->cenc_aux_sample_count = i;
2944         return;
2945       }
2946       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2947 
2948       kid_buf_value =
2949           gst_structure_get_value (ss_info->default_properties, "kid");
2950 
2951       gst_structure_set (properties,
2952           "subsample_count", G_TYPE_UINT, n_subsamples,
2953           "subsamples", GST_TYPE_BUFFER, buf, NULL);
2954       gst_structure_set_value (properties, "kid", kid_buf_value);
2955       gst_buffer_unref (buf);
2956     } else {
2957       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2958     }
2959 
2960     g_ptr_array_add (ss_info->crypto_info, properties);
2961   }
2962 
2963   qtdemux->cenc_aux_sample_count = sample_count;
2964 }
2965 
2966 static void
qtdemux_parse_uuid(GstQTDemux * qtdemux,const guint8 * buffer,gint length)2967 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2968 {
2969   static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2970     0x97, 0xA9, 0x42, 0xE8,
2971     0x9C, 0x71, 0x99, 0x94,
2972     0x91, 0xE3, 0xAF, 0xAC
2973   };
2974   static const guint8 playready_uuid[] = {
2975     0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2976     0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2977   };
2978 
2979   static const guint8 piff_sample_encryption_uuid[] = {
2980     0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2981     0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2982   };
2983 
2984   guint offset;
2985 
2986   /* counts as header data */
2987   qtdemux->header_size += length;
2988 
2989   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2990 
2991   if (length <= offset + 16) {
2992     GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2993     return;
2994   }
2995 
2996   if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2997     GstBuffer *buf;
2998     GstTagList *taglist;
2999 
3000     buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3001         length - offset - 16, NULL);
3002     taglist = gst_tag_list_from_xmp_buffer (buf);
3003     gst_buffer_unref (buf);
3004 
3005     /* make sure we have a usable taglist */
3006     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3007 
3008     qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3009 
3010   } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3011     int len;
3012     const gunichar2 *s_utf16;
3013     char *contents;
3014 
3015     len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3016     s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3017     contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3018     GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3019 
3020     g_free (contents);
3021 
3022     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3023         (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3024         (NULL));
3025   } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3026     qtdemux_parse_piff (qtdemux, buffer, length, offset);
3027   } else {
3028     GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3029         GST_READ_UINT32_LE (buffer + offset),
3030         GST_READ_UINT32_LE (buffer + offset + 4),
3031         GST_READ_UINT32_LE (buffer + offset + 8),
3032         GST_READ_UINT32_LE (buffer + offset + 12));
3033   }
3034 }
3035 
3036 static void
qtdemux_parse_sidx(GstQTDemux * qtdemux,const guint8 * buffer,gint length)3037 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3038 {
3039   GstSidxParser sidx_parser;
3040   GstIsoffParserResult res;
3041   guint consumed;
3042 
3043   gst_isoff_qt_sidx_parser_init (&sidx_parser);
3044 
3045   res =
3046       gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3047       &consumed);
3048   GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3049   if (res == GST_ISOFF_QT_PARSER_DONE) {
3050     check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3051   }
3052   gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3053 }
3054 
3055 /* caller verifies at least 8 bytes in buf */
3056 static void
extract_initial_length_and_fourcc(const guint8 * data,guint size,guint64 * plength,guint32 * pfourcc)3057 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3058     guint64 * plength, guint32 * pfourcc)
3059 {
3060   guint64 length;
3061   guint32 fourcc;
3062 
3063   length = QT_UINT32 (data);
3064   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3065   fourcc = QT_FOURCC (data + 4);
3066   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3067 
3068   if (length == 0) {
3069     length = G_MAXUINT64;
3070   } else if (length == 1 && size >= 16) {
3071     /* this means we have an extended size, which is the 64 bit value of
3072      * the next 8 bytes */
3073     length = QT_UINT64 (data + 8);
3074     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3075   }
3076 
3077   if (plength)
3078     *plength = length;
3079   if (pfourcc)
3080     *pfourcc = fourcc;
3081 }
3082 
3083 static gboolean
qtdemux_parse_mehd(GstQTDemux * qtdemux,GstByteReader * br)3084 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3085 {
3086   guint32 version = 0;
3087   GstClockTime duration = 0;
3088 
3089   if (!gst_byte_reader_get_uint32_be (br, &version))
3090     goto failed;
3091 
3092   version >>= 24;
3093   if (version == 1) {
3094     if (!gst_byte_reader_get_uint64_be (br, &duration))
3095       goto failed;
3096   } else {
3097     guint32 dur = 0;
3098 
3099     if (!gst_byte_reader_get_uint32_be (br, &dur))
3100       goto failed;
3101     duration = dur;
3102   }
3103 
3104   GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3105   qtdemux->duration = duration;
3106 
3107   return TRUE;
3108 
3109 failed:
3110   {
3111     GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3112     return FALSE;
3113   }
3114 }
3115 
3116 static gboolean
qtdemux_parse_trex(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 * ds_duration,guint32 * ds_size,guint32 * ds_flags)3117 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3118     guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3119 {
3120   if (!stream->parsed_trex && qtdemux->moov_node) {
3121     GNode *mvex, *trex;
3122     GstByteReader trex_data;
3123 
3124     mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3125     if (mvex) {
3126       trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3127           &trex_data);
3128       while (trex) {
3129         guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3130 
3131         /* skip version/flags */
3132         if (!gst_byte_reader_skip (&trex_data, 4))
3133           goto next;
3134         if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3135           goto next;
3136         if (id != stream->track_id)
3137           goto next;
3138         if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3139           goto next;
3140         if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3141           goto next;
3142         if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3143           goto next;
3144         if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3145           goto next;
3146 
3147         GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3148             "duration %d,  size %d, flags 0x%x", stream->track_id,
3149             dur, size, flags);
3150 
3151         stream->parsed_trex = TRUE;
3152         stream->def_sample_description_index = sdi;
3153         stream->def_sample_duration = dur;
3154         stream->def_sample_size = size;
3155         stream->def_sample_flags = flags;
3156 
3157       next:
3158         /* iterate all siblings */
3159         trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3160             &trex_data);
3161       }
3162     }
3163   }
3164 
3165   *ds_duration = stream->def_sample_duration;
3166   *ds_size = stream->def_sample_size;
3167   *ds_flags = stream->def_sample_flags;
3168 
3169   /* even then, above values are better than random ... */
3170   if (G_UNLIKELY (!stream->parsed_trex)) {
3171     GST_WARNING_OBJECT (qtdemux,
3172         "failed to find fragment defaults for stream %d", stream->track_id);
3173     return FALSE;
3174   }
3175 
3176   return TRUE;
3177 }
3178 
3179 /* This method should be called whenever a more accurate duration might
3180  * have been found. It will update all relevant variables if/where needed
3181  */
3182 static void
check_update_duration(GstQTDemux * qtdemux,GstClockTime duration)3183 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3184 {
3185   guint i;
3186   guint64 movdur;
3187   GstClockTime prevdur;
3188 
3189   movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3190 
3191   if (movdur > qtdemux->duration) {
3192     prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3193     GST_DEBUG_OBJECT (qtdemux,
3194         "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3195         GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3196     qtdemux->duration = movdur;
3197     GST_DEBUG_OBJECT (qtdemux,
3198         "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3199         GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3200         GST_TIME_ARGS (qtdemux->segment.stop));
3201     if (qtdemux->segment.duration == prevdur) {
3202       /* If the current segment has duration/stop identical to previous duration
3203        * update them also (because they were set at that point in time with
3204        * the wrong duration */
3205       /* We convert the value *from* the timescale version to avoid rounding errors */
3206       GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3207       GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3208       qtdemux->segment.duration = fixeddur;
3209       qtdemux->segment.stop = fixeddur;
3210     }
3211   }
3212 
3213   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3214     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3215 
3216     movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3217     if (movdur > stream->duration) {
3218       GST_DEBUG_OBJECT (qtdemux,
3219           "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3220           GST_TIME_ARGS (duration));
3221       stream->duration = movdur;
3222       /* internal duration tracking state has been updated above, so */
3223       /* preserve an open-ended dummy segment rather than repeatedly updating
3224        * it and spamming downstream accordingly with segment events */
3225       /* also mangle the edit list end time when fragmented with a single edit
3226        * list that may only cover any non-fragmented data */
3227       if ((stream->dummy_segment ||
3228               (qtdemux->fragmented && stream->n_segments == 1)) &&
3229           GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3230         /* Update all dummy values to new duration */
3231         stream->segments[0].stop_time = duration;
3232         stream->segments[0].duration = duration;
3233         stream->segments[0].media_stop = duration;
3234 
3235         /* let downstream know we possibly have a new stop time */
3236         if (stream->segment_index != -1) {
3237           GstClockTime pos;
3238 
3239           if (qtdemux->segment.rate >= 0) {
3240             pos = stream->segment.start;
3241           } else {
3242             pos = stream->segment.stop;
3243           }
3244 
3245           gst_qtdemux_stream_update_segment (qtdemux, stream,
3246               stream->segment_index, pos, NULL, NULL);
3247         }
3248       }
3249     }
3250   }
3251 }
3252 
3253 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)3254 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3255     QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3256     guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3257     gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3258     gboolean has_tfdt)
3259 {
3260   GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3261   guint64 timestamp;
3262   gint32 data_offset = 0;
3263   guint8 version;
3264   guint32 flags = 0, first_flags = 0, samples_count = 0;
3265   gint i;
3266   guint8 *data;
3267   guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3268   QtDemuxSample *sample;
3269   gboolean ismv = FALSE;
3270   gint64 initial_offset;
3271   gint32 min_ct = 0;
3272 
3273   GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3274       "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3275       "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3276       d_sample_size, d_sample_flags, *base_offset, decode_ts);
3277 
3278   if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3279     GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3280     return TRUE;
3281   }
3282 
3283   /* presence of stss or not can't really tell us much,
3284    * and flags and so on tend to be marginally reliable in these files */
3285   if (stream->subtype == FOURCC_soun) {
3286     GST_DEBUG_OBJECT (qtdemux,
3287         "sound track in fragmented file; marking all keyframes");
3288     stream->all_keyframe = TRUE;
3289   }
3290 
3291   if (!gst_byte_reader_get_uint8 (trun, &version) ||
3292       !gst_byte_reader_get_uint24_be (trun, &flags))
3293     goto fail;
3294 
3295   if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3296     goto fail;
3297 
3298   if (flags & TR_DATA_OFFSET) {
3299     /* note this is really signed */
3300     if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3301       goto fail;
3302     GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3303     /* default base offset = first byte of moof */
3304     if (*base_offset == -1) {
3305       GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3306       *base_offset = moof_offset;
3307     }
3308     *running_offset = *base_offset + data_offset;
3309   } else {
3310     /* if no offset at all, that would mean data starts at moof start,
3311      * which is a bit wrong and is ismv crappy way, so compensate
3312      * assuming data is in mdat following moof */
3313     if (*base_offset == -1) {
3314       *base_offset = moof_offset + moof_length + 8;
3315       GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3316       ismv = TRUE;
3317     }
3318     if (*running_offset == -1)
3319       *running_offset = *base_offset;
3320   }
3321 
3322   GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3323       *running_offset);
3324   GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3325       data_offset, flags, samples_count);
3326 
3327   if (flags & TR_FIRST_SAMPLE_FLAGS) {
3328     if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3329       GST_DEBUG_OBJECT (qtdemux,
3330           "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3331       flags ^= TR_FIRST_SAMPLE_FLAGS;
3332     } else {
3333       if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3334         goto fail;
3335       GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3336     }
3337   }
3338 
3339   /* FIXME ? spec says other bits should also be checked to determine
3340    * entry size (and prefix size for that matter) */
3341   entry_size = 0;
3342   dur_offset = size_offset = 0;
3343   if (flags & TR_SAMPLE_DURATION) {
3344     GST_LOG_OBJECT (qtdemux, "entry duration present");
3345     dur_offset = entry_size;
3346     entry_size += 4;
3347   }
3348   if (flags & TR_SAMPLE_SIZE) {
3349     GST_LOG_OBJECT (qtdemux, "entry size present");
3350     size_offset = entry_size;
3351     entry_size += 4;
3352   }
3353   if (flags & TR_SAMPLE_FLAGS) {
3354     GST_LOG_OBJECT (qtdemux, "entry flags present");
3355     flags_offset = entry_size;
3356     entry_size += 4;
3357   }
3358   if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3359     GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3360     ct_offset = entry_size;
3361     entry_size += 4;
3362   }
3363 
3364   if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3365     goto fail;
3366   data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3367 
3368   if (stream->n_samples + samples_count >=
3369       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3370     goto index_too_big;
3371 
3372   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3373       stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3374       (stream->n_samples + samples_count) *
3375       sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3376 
3377   /* create a new array of samples if it's the first sample parsed */
3378   if (stream->n_samples == 0) {
3379     g_assert (stream->samples == NULL);
3380     stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3381     /* or try to reallocate it with space enough to insert the new samples */
3382   } else
3383     stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3384         stream->n_samples + samples_count);
3385   if (stream->samples == NULL)
3386     goto out_of_memory;
3387 
3388   if (qtdemux->fragment_start != -1) {
3389     timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3390     qtdemux->fragment_start = -1;
3391   } else {
3392     if (stream->n_samples == 0) {
3393       if (decode_ts > 0) {
3394         timestamp = decode_ts;
3395       } else if (stream->pending_seek != NULL) {
3396         /* if we don't have a timestamp from a tfdt box, we'll use the one
3397          * from the mfra seek table */
3398         GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3399             GST_TIME_ARGS (stream->pending_seek->ts));
3400 
3401         /* FIXME: this is not fully correct, the timestamp refers to the random
3402          * access sample refered to in the tfra entry, which may not necessarily
3403          * be the first sample in the tfrag/trun (but hopefully/usually is) */
3404         timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3405       } else {
3406         timestamp = 0;
3407       }
3408 
3409       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3410       GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3411           GST_TIME_ARGS (gst_ts));
3412     } else {
3413       /* subsequent fragments extend stream */
3414       timestamp =
3415           stream->samples[stream->n_samples - 1].timestamp +
3416           stream->samples[stream->n_samples - 1].duration;
3417 
3418       /* If this is a GST_FORMAT_BYTES stream and there's a significant
3419        * difference (1 sec.) between decode_ts and timestamp, prefer the
3420        * former */
3421       if (has_tfdt && !qtdemux->upstream_format_is_time
3422           && ABSDIFF (decode_ts, timestamp) >
3423           MAX (stream->duration_last_moof / 2,
3424               GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3425         GST_INFO_OBJECT (qtdemux,
3426             "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3427             ") are significantly different (more than %" GST_TIME_FORMAT
3428             "), using decode_ts",
3429             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3430             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3431             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3432                     MAX (stream->duration_last_moof / 2,
3433                         GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3434         timestamp = decode_ts;
3435       }
3436 
3437       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3438       GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3439           " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3440     }
3441   }
3442 
3443   initial_offset = *running_offset;
3444 
3445   sample = stream->samples + stream->n_samples;
3446   for (i = 0; i < samples_count; i++) {
3447     guint32 dur, size, sflags;
3448     gint32 ct;
3449 
3450     /* first read sample data */
3451     if (flags & TR_SAMPLE_DURATION) {
3452       dur = QT_UINT32 (data + dur_offset);
3453     } else {
3454       dur = d_sample_duration;
3455     }
3456     if (flags & TR_SAMPLE_SIZE) {
3457       size = QT_UINT32 (data + size_offset);
3458     } else {
3459       size = d_sample_size;
3460     }
3461     if (flags & TR_FIRST_SAMPLE_FLAGS) {
3462       if (i == 0) {
3463         sflags = first_flags;
3464       } else {
3465         sflags = d_sample_flags;
3466       }
3467     } else if (flags & TR_SAMPLE_FLAGS) {
3468       sflags = QT_UINT32 (data + flags_offset);
3469     } else {
3470       sflags = d_sample_flags;
3471     }
3472 
3473     if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3474       /* Read offsets as signed numbers regardless of trun version as very
3475        * high offsets are unlikely and there are files out there that use
3476        * version=0 truns with negative offsets */
3477       ct = QT_UINT32 (data + ct_offset);
3478 
3479       /* FIXME: Set offset to 0 for "no decode samples". This needs
3480        * to be handled in a codec specific manner ideally. */
3481       if (ct == G_MININT32)
3482         ct = 0;
3483     } else {
3484       ct = 0;
3485     }
3486     data += entry_size;
3487 
3488     /* fill the sample information */
3489     sample->offset = *running_offset;
3490     sample->pts_offset = ct;
3491     sample->size = size;
3492     sample->timestamp = timestamp;
3493     sample->duration = dur;
3494     /* sample-is-difference-sample */
3495     /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3496      * now idea how it relates to bitfield other than massive LE/BE confusion */
3497     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3498     *running_offset += size;
3499     timestamp += dur;
3500     stream->duration_moof += dur;
3501     sample++;
3502 
3503     if (ct < min_ct)
3504       min_ct = ct;
3505   }
3506 
3507   /* Shift PTS/DTS to allow for negative composition offsets while keeping
3508    * A/V sync in place. This is similar to the code handling ctts/cslg in the
3509    * non-fragmented case.
3510    */
3511   if (min_ct < 0)
3512     stream->cslg_shift = -min_ct;
3513   else
3514     stream->cslg_shift = 0;
3515 
3516   GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3517       stream->cslg_shift);
3518 
3519   /* Update total duration if needed */
3520   check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3521 
3522   /* Pre-emptively figure out size of mdat based on trun information.
3523    * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3524    * size, else we will still be able to use this when dealing with gap'ed
3525    * input */
3526   qtdemux->mdatleft = *running_offset - initial_offset;
3527   qtdemux->mdatoffset = initial_offset;
3528   qtdemux->mdatsize = qtdemux->mdatleft;
3529 
3530   stream->n_samples += samples_count;
3531   stream->n_samples_moof += samples_count;
3532 
3533   if (stream->pending_seek != NULL)
3534     stream->pending_seek = NULL;
3535 
3536   return TRUE;
3537 
3538 fail:
3539   {
3540     GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3541     return FALSE;
3542   }
3543 out_of_memory:
3544   {
3545     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3546         stream->n_samples);
3547     return FALSE;
3548   }
3549 index_too_big:
3550   {
3551     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3552         "be larger than %uMB (broken file?)", stream->n_samples,
3553         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3554     return FALSE;
3555   }
3556 }
3557 
3558 /* find stream with @id */
3559 static inline QtDemuxStream *
qtdemux_find_stream(GstQTDemux * qtdemux,guint32 id)3560 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3561 {
3562   QtDemuxStream *stream;
3563   gint i;
3564 
3565   /* check */
3566   if (G_UNLIKELY (!id)) {
3567     GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3568     return NULL;
3569   }
3570 
3571   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3572     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3573     if (stream->track_id == id)
3574       return stream;
3575   }
3576   if (qtdemux->mss_mode) {
3577     /* mss should have only 1 stream anyway */
3578     return QTDEMUX_NTH_STREAM (qtdemux, 0);
3579   }
3580 
3581   return NULL;
3582 }
3583 
3584 static gboolean
qtdemux_parse_mfhd(GstQTDemux * qtdemux,GstByteReader * mfhd,guint32 * fragment_number)3585 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3586     guint32 * fragment_number)
3587 {
3588   if (!gst_byte_reader_skip (mfhd, 4))
3589     goto fail;
3590   if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3591     goto fail;
3592   return TRUE;
3593 fail:
3594   {
3595     GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3596     return FALSE;
3597   }
3598 }
3599 
3600 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)3601 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3602     QtDemuxStream ** stream, guint32 * default_sample_duration,
3603     guint32 * default_sample_size, guint32 * default_sample_flags,
3604     gint64 * base_offset)
3605 {
3606   guint32 flags = 0;
3607   guint32 track_id = 0;
3608 
3609   if (!gst_byte_reader_skip (tfhd, 1) ||
3610       !gst_byte_reader_get_uint24_be (tfhd, &flags))
3611     goto invalid_track;
3612 
3613   if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3614     goto invalid_track;
3615 
3616   *stream = qtdemux_find_stream (qtdemux, track_id);
3617   if (G_UNLIKELY (!*stream))
3618     goto unknown_stream;
3619 
3620   if (flags & TF_DEFAULT_BASE_IS_MOOF)
3621     *base_offset = qtdemux->moof_offset;
3622 
3623   if (flags & TF_BASE_DATA_OFFSET)
3624     if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3625       goto invalid_track;
3626 
3627   /* obtain stream defaults */
3628   qtdemux_parse_trex (qtdemux, *stream,
3629       default_sample_duration, default_sample_size, default_sample_flags);
3630 
3631   (*stream)->stsd_sample_description_id =
3632       (*stream)->def_sample_description_index - 1;
3633 
3634   if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3635     guint32 sample_description_index;
3636     if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3637       goto invalid_track;
3638     (*stream)->stsd_sample_description_id = sample_description_index - 1;
3639   }
3640 
3641   if (qtdemux->mss_mode) {
3642     /* mss has no stsd entry */
3643     (*stream)->stsd_sample_description_id = 0;
3644   }
3645 
3646   if (flags & TF_DEFAULT_SAMPLE_DURATION)
3647     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3648       goto invalid_track;
3649 
3650   if (flags & TF_DEFAULT_SAMPLE_SIZE)
3651     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3652       goto invalid_track;
3653 
3654   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3655     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3656       goto invalid_track;
3657 
3658   return TRUE;
3659 
3660 invalid_track:
3661   {
3662     GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3663     return FALSE;
3664   }
3665 unknown_stream:
3666   {
3667     GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3668     return TRUE;
3669   }
3670 }
3671 
3672 static gboolean
qtdemux_parse_tfdt(GstQTDemux * qtdemux,GstByteReader * br,guint64 * decode_time)3673 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3674     guint64 * decode_time)
3675 {
3676   guint32 version = 0;
3677 
3678   if (!gst_byte_reader_get_uint32_be (br, &version))
3679     return FALSE;
3680 
3681   version >>= 24;
3682   if (version == 1) {
3683     if (!gst_byte_reader_get_uint64_be (br, decode_time))
3684       goto failed;
3685   } else {
3686     guint32 dec_time = 0;
3687     if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3688       goto failed;
3689     *decode_time = dec_time;
3690   }
3691 
3692   GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3693       *decode_time);
3694 
3695   return TRUE;
3696 
3697 failed:
3698   {
3699     GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3700     return FALSE;
3701   }
3702 }
3703 
3704 /* Returns a pointer to a GstStructure containing the properties of
3705  * the stream sample identified by @sample_index. The caller must unref
3706  * the returned object after use. Returns NULL if unsuccessful. */
3707 static GstStructure *
qtdemux_get_cenc_sample_properties(GstQTDemux * qtdemux,QtDemuxStream * stream,guint sample_index)3708 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3709     QtDemuxStream * stream, guint sample_index)
3710 {
3711   QtDemuxCencSampleSetInfo *info = NULL;
3712 
3713   g_return_val_if_fail (stream != NULL, NULL);
3714   g_return_val_if_fail (stream->protected, NULL);
3715   g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3716 
3717   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3718 
3719   /* Currently, cenc properties for groups of samples are not supported, so
3720    * simply return a copy of the default sample properties */
3721   return gst_structure_copy (info->default_properties);
3722 }
3723 
3724 /* Parses the sizes of sample auxiliary information contained within a stream,
3725  * as given in a saiz box. Returns array of sample_count guint8 size values,
3726  * or NULL on failure */
3727 static guint8 *
qtdemux_parse_saiz(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint32 * sample_count)3728 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3729     GstByteReader * br, guint32 * sample_count)
3730 {
3731   guint32 flags = 0;
3732   guint8 *info_sizes;
3733   guint8 default_info_size;
3734 
3735   g_return_val_if_fail (qtdemux != NULL, NULL);
3736   g_return_val_if_fail (stream != NULL, NULL);
3737   g_return_val_if_fail (br != NULL, NULL);
3738   g_return_val_if_fail (sample_count != NULL, NULL);
3739 
3740   if (!gst_byte_reader_get_uint32_be (br, &flags))
3741     return NULL;
3742 
3743   if (flags & 0x1) {
3744     /* aux_info_type and aux_info_type_parameter are ignored */
3745     if (!gst_byte_reader_skip (br, 8))
3746       return NULL;
3747   }
3748 
3749   if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3750     return NULL;
3751   GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3752 
3753   if (!gst_byte_reader_get_uint32_be (br, sample_count))
3754     return NULL;
3755   GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3756 
3757 
3758   if (default_info_size == 0) {
3759     if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3760       return NULL;
3761     }
3762   } else {
3763     info_sizes = g_new (guint8, *sample_count);
3764     memset (info_sizes, default_info_size, *sample_count);
3765   }
3766 
3767   return info_sizes;
3768 }
3769 
3770 /* Parses the offset of sample auxiliary information contained within a stream,
3771  * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3772 static gboolean
qtdemux_parse_saio(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint32 * info_type,guint32 * info_type_parameter,guint64 * offset)3773 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3774     GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3775     guint64 * offset)
3776 {
3777   guint8 version = 0;
3778   guint32 flags = 0;
3779   guint32 aux_info_type = 0;
3780   guint32 aux_info_type_parameter = 0;
3781   guint32 entry_count;
3782   guint32 off_32;
3783   guint64 off_64;
3784   const guint8 *aux_info_type_data = NULL;
3785 
3786   g_return_val_if_fail (qtdemux != NULL, FALSE);
3787   g_return_val_if_fail (stream != NULL, FALSE);
3788   g_return_val_if_fail (br != NULL, FALSE);
3789   g_return_val_if_fail (offset != NULL, FALSE);
3790 
3791   if (!gst_byte_reader_get_uint8 (br, &version))
3792     return FALSE;
3793 
3794   if (!gst_byte_reader_get_uint24_be (br, &flags))
3795     return FALSE;
3796 
3797   if (flags & 0x1) {
3798 
3799     if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3800       return FALSE;
3801     aux_info_type = QT_FOURCC (aux_info_type_data);
3802 
3803     if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3804       return FALSE;
3805   } else if (stream->protected) {
3806     aux_info_type = stream->protection_scheme_type;
3807   } else {
3808     aux_info_type = CUR_STREAM (stream)->fourcc;
3809   }
3810 
3811   if (info_type)
3812     *info_type = aux_info_type;
3813   if (info_type_parameter)
3814     *info_type_parameter = aux_info_type_parameter;
3815 
3816   GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3817       "aux_info_type_parameter:  %#06x",
3818       GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3819 
3820   if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3821     return FALSE;
3822 
3823   if (entry_count != 1) {
3824     GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3825     return FALSE;
3826   }
3827 
3828   if (version == 0) {
3829     if (!gst_byte_reader_get_uint32_be (br, &off_32))
3830       return FALSE;
3831     *offset = (guint64) off_32;
3832   } else {
3833     if (!gst_byte_reader_get_uint64_be (br, &off_64))
3834       return FALSE;
3835     *offset = off_64;
3836   }
3837 
3838   GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3839   return TRUE;
3840 }
3841 
3842 static void
qtdemux_gst_structure_free(GstStructure * gststructure)3843 qtdemux_gst_structure_free (GstStructure * gststructure)
3844 {
3845   if (gststructure) {
3846     gst_structure_free (gststructure);
3847   }
3848 }
3849 
3850 /* Parses auxiliary information relating to samples protected using
3851  * Common Encryption (cenc); the format of this information
3852  * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3853  * otherwise. */
3854 static gboolean
qtdemux_parse_cenc_aux_info(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint8 * info_sizes,guint32 sample_count)3855 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3856     GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3857 {
3858   QtDemuxCencSampleSetInfo *ss_info = NULL;
3859   guint8 size;
3860   gint i;
3861   GPtrArray *old_crypto_info = NULL;
3862   guint old_entries = 0;
3863 
3864   g_return_val_if_fail (qtdemux != NULL, FALSE);
3865   g_return_val_if_fail (stream != NULL, FALSE);
3866   g_return_val_if_fail (br != NULL, FALSE);
3867   g_return_val_if_fail (stream->protected, FALSE);
3868   g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3869 
3870   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3871 
3872   if (ss_info->crypto_info) {
3873     old_crypto_info = ss_info->crypto_info;
3874     /* Count number of non-null entries remaining at the tail end */
3875     for (i = old_crypto_info->len - 1; i >= 0; i--) {
3876       if (g_ptr_array_index (old_crypto_info, i) == NULL)
3877         break;
3878       old_entries++;
3879     }
3880   }
3881 
3882   ss_info->crypto_info =
3883       g_ptr_array_new_full (sample_count + old_entries,
3884       (GDestroyNotify) qtdemux_gst_structure_free);
3885 
3886   /* We preserve old entries because we parse the next moof in advance
3887    * of consuming all samples from the previous moof, and otherwise
3888    * we'd discard the corresponding crypto info for the samples
3889    * from the previous fragment. */
3890   if (old_entries) {
3891     GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3892         old_entries);
3893     for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3894       g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3895               i));
3896       g_ptr_array_index (old_crypto_info, i) = NULL;
3897     }
3898   }
3899 
3900   if (old_crypto_info) {
3901     /* Everything now belongs to the new array */
3902     g_ptr_array_free (old_crypto_info, TRUE);
3903   }
3904 
3905   for (i = 0; i < sample_count; ++i) {
3906     GstStructure *properties;
3907     guint16 n_subsamples = 0;
3908     guint8 *data;
3909     guint iv_size;
3910     GstBuffer *buf;
3911     gboolean could_read_iv;
3912 
3913     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3914     if (properties == NULL) {
3915       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3916       return FALSE;
3917     }
3918     if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3919       GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3920       gst_structure_free (properties);
3921       return FALSE;
3922     }
3923     could_read_iv =
3924         iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3925     if (could_read_iv) {
3926       buf = gst_buffer_new_wrapped (data, iv_size);
3927       gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3928       gst_buffer_unref (buf);
3929     } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3930       const GValue *constant_iv_size_value =
3931           gst_structure_get_value (properties, "constant_iv_size");
3932       const GValue *constant_iv_value =
3933           gst_structure_get_value (properties, "iv");
3934       if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3935         GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3936         gst_structure_free (properties);
3937         return FALSE;
3938       }
3939       gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3940       gst_structure_remove_field (properties, "constant_iv_size");
3941     } else if (stream->protection_scheme_type == FOURCC_cenc) {
3942       GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3943       gst_structure_free (properties);
3944       return FALSE;
3945     }
3946     size = info_sizes[i];
3947     if (size > iv_size) {
3948       if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3949           || !(n_subsamples > 0)) {
3950         gst_structure_free (properties);
3951         GST_ERROR_OBJECT (qtdemux,
3952             "failed to get subsample count for sample %u", i);
3953         return FALSE;
3954       }
3955       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3956       if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3957         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3958             i);
3959         gst_structure_free (properties);
3960         return FALSE;
3961       }
3962       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3963       if (!buf) {
3964         gst_structure_free (properties);
3965         return FALSE;
3966       }
3967       gst_structure_set (properties,
3968           "subsample_count", G_TYPE_UINT, n_subsamples,
3969           "subsamples", GST_TYPE_BUFFER, buf, NULL);
3970       gst_buffer_unref (buf);
3971     } else {
3972       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3973     }
3974     g_ptr_array_add (ss_info->crypto_info, properties);
3975   }
3976   return TRUE;
3977 }
3978 
3979 /* Converts a UUID in raw byte form to a string representation, as defined in
3980  * RFC 4122. The caller takes ownership of the returned string and is
3981  * responsible for freeing it after use. */
3982 static gchar *
qtdemux_uuid_bytes_to_string(gconstpointer uuid_bytes)3983 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3984 {
3985   const guint8 *uuid = (const guint8 *) uuid_bytes;
3986 
3987   return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3988       "%02x%02x-%02x%02x%02x%02x%02x%02x",
3989       uuid[0], uuid[1], uuid[2], uuid[3],
3990       uuid[4], uuid[5], uuid[6], uuid[7],
3991       uuid[8], uuid[9], uuid[10], uuid[11],
3992       uuid[12], uuid[13], uuid[14], uuid[15]);
3993 }
3994 
3995 /* Parses a Protection System Specific Header box (pssh), as defined in the
3996  * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3997  * information needed by a specific content protection system in order to
3998  * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3999  * otherwise. */
4000 static gboolean
qtdemux_parse_pssh(GstQTDemux * qtdemux,GNode * node)4001 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4002 {
4003   gchar *sysid_string;
4004   guint32 pssh_size = QT_UINT32 (node->data);
4005   GstBuffer *pssh = NULL;
4006   GstEvent *event = NULL;
4007   guint32 parent_box_type;
4008   gint i;
4009 
4010   if (G_UNLIKELY (pssh_size < 32U)) {
4011     GST_ERROR_OBJECT (qtdemux, "invalid box size");
4012     return FALSE;
4013   }
4014 
4015   sysid_string =
4016       qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4017 
4018   gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4019 
4020   pssh = gst_buffer_new_memdup (node->data, pssh_size);
4021   GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4022       gst_buffer_get_size (pssh));
4023 
4024   parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4025 
4026   /* Push an event containing the pssh box onto the queues of all streams. */
4027   event = gst_event_new_protection (sysid_string, pssh,
4028       (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4029   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4030     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4031     GST_TRACE_OBJECT (qtdemux,
4032         "adding protection event for stream %s and system %s",
4033         stream->stream_id, sysid_string);
4034     g_queue_push_tail (&stream->protection_scheme_event_queue,
4035         gst_event_ref (event));
4036   }
4037   g_free (sysid_string);
4038   gst_event_unref (event);
4039   gst_buffer_unref (pssh);
4040   return TRUE;
4041 }
4042 
4043 static gboolean
qtdemux_parse_moof(GstQTDemux * qtdemux,const guint8 * buffer,guint length,guint64 moof_offset,QtDemuxStream * stream)4044 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4045     guint64 moof_offset, QtDemuxStream * stream)
4046 {
4047   GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4048   GNode *uuid_node;
4049   GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4050   GNode *saiz_node, *saio_node, *pssh_node;
4051   GstByteReader saiz_data, saio_data;
4052   guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4053   gint64 base_offset, running_offset;
4054   guint32 frag_num;
4055   GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4056 
4057   /* NOTE @stream ignored */
4058 
4059   moof_node = g_node_new ((guint8 *) buffer);
4060   qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4061   qtdemux_node_dump (qtdemux, moof_node);
4062 
4063   /* Get fragment number from mfhd and check it's valid */
4064   mfhd_node =
4065       qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4066   if (mfhd_node == NULL)
4067     goto missing_mfhd;
4068   if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4069     goto fail;
4070   GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4071 
4072   /* unknown base_offset to start with */
4073   base_offset = running_offset = -1;
4074   traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4075   while (traf_node) {
4076     guint64 decode_time = 0;
4077 
4078     /* Fragment Header node */
4079     tfhd_node =
4080         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4081         &tfhd_data);
4082     if (!tfhd_node)
4083       goto missing_tfhd;
4084     if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4085             &ds_size, &ds_flags, &base_offset))
4086       goto missing_tfhd;
4087 
4088     /* The following code assumes at most a single set of sample auxiliary
4089      * data in the fragment (consisting of a saiz box and a corresponding saio
4090      * box); in theory, however, there could be multiple sets of sample
4091      * auxiliary data in a fragment. */
4092     saiz_node =
4093         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4094         &saiz_data);
4095     if (saiz_node) {
4096       guint32 info_type = 0;
4097       guint64 offset = 0;
4098       guint32 info_type_parameter = 0;
4099 
4100       g_free (qtdemux->cenc_aux_info_sizes);
4101 
4102       qtdemux->cenc_aux_info_sizes =
4103           qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4104           &qtdemux->cenc_aux_sample_count);
4105       if (qtdemux->cenc_aux_info_sizes == NULL) {
4106         GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4107         goto fail;
4108       }
4109       saio_node =
4110           qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4111           &saio_data);
4112       if (!saio_node) {
4113         GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4114         g_free (qtdemux->cenc_aux_info_sizes);
4115         qtdemux->cenc_aux_info_sizes = NULL;
4116         goto fail;
4117       }
4118 
4119       if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4120                   &info_type, &info_type_parameter, &offset))) {
4121         GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4122         g_free (qtdemux->cenc_aux_info_sizes);
4123         qtdemux->cenc_aux_info_sizes = NULL;
4124         goto fail;
4125       }
4126       if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4127         offset += (guint64) (base_offset - qtdemux->moof_offset);
4128       if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4129           && info_type_parameter == 0U) {
4130         GstByteReader br;
4131         if (offset > length) {
4132           GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4133           qtdemux->cenc_aux_info_offset = offset;
4134         } else {
4135           gst_byte_reader_init (&br, buffer + offset, length - offset);
4136           if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4137                   qtdemux->cenc_aux_info_sizes,
4138                   qtdemux->cenc_aux_sample_count)) {
4139             GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4140             g_free (qtdemux->cenc_aux_info_sizes);
4141             qtdemux->cenc_aux_info_sizes = NULL;
4142             goto fail;
4143           }
4144         }
4145       }
4146     }
4147 
4148     tfdt_node =
4149         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4150         &tfdt_data);
4151     if (tfdt_node) {
4152       /* We'll use decode_time to interpolate timestamps
4153        * in case the input timestamps are missing */
4154       qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4155 
4156       GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4157           " (%" GST_TIME_FORMAT ")", decode_time,
4158           GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4159                   decode_time) : GST_CLOCK_TIME_NONE));
4160 
4161       /* Discard the fragment buffer timestamp info to avoid using it.
4162        * Rely on tfdt instead as it is more accurate than the timestamp
4163        * that is fetched from a manifest/playlist and is usually
4164        * less accurate. */
4165       qtdemux->fragment_start = -1;
4166     }
4167 
4168     if (G_UNLIKELY (!stream)) {
4169       /* we lost track of offset, we'll need to regain it,
4170        * but can delay complaining until later or avoid doing so altogether */
4171       base_offset = -2;
4172       goto next;
4173     }
4174     if (G_UNLIKELY (base_offset < -1))
4175       goto lost_offset;
4176 
4177     min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4178 
4179     if (!qtdemux->pullbased) {
4180       /* Sample tables can grow enough to be problematic if the system memory
4181        * is very low (e.g. embedded devices) and the videos very long
4182        * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4183        * Fortunately, we can easily discard them for each new fragment when
4184        * we know qtdemux will not receive seeks outside of the current fragment.
4185        * adaptivedemux honors this assumption.
4186        * This optimization is also useful for applications that use qtdemux as
4187        * a push-based simple demuxer, like Media Source Extensions. */
4188       gst_qtdemux_stream_flush_samples_data (stream);
4189     }
4190 
4191     /* initialise moof sample data */
4192     stream->n_samples_moof = 0;
4193     stream->duration_last_moof = stream->duration_moof;
4194     stream->duration_moof = 0;
4195 
4196     /* Track Run node */
4197     trun_node =
4198         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4199         &trun_data);
4200     while (trun_node) {
4201       qtdemux_parse_trun (qtdemux, &trun_data, stream,
4202           ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4203           &running_offset, decode_time, (tfdt_node != NULL));
4204       /* iterate all siblings */
4205       trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4206           &trun_data);
4207       /* don't use tfdt for subsequent trun as it only refers to the first */
4208       tfdt_node = NULL;
4209     }
4210 
4211     uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4212     if (uuid_node) {
4213       guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4214       guint32 box_length = QT_UINT32 (uuid_buffer);
4215 
4216       qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4217     }
4218 
4219     /* if no new base_offset provided for next traf,
4220      * base is end of current traf */
4221     base_offset = running_offset;
4222     running_offset = -1;
4223 
4224     if (stream->n_samples_moof && stream->duration_moof)
4225       stream->new_caps = TRUE;
4226 
4227   next:
4228     /* iterate all siblings */
4229     traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4230   }
4231 
4232   /* parse any protection system info */
4233   pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4234   while (pssh_node) {
4235     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4236     qtdemux_parse_pssh (qtdemux, pssh_node);
4237     pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4238   }
4239 
4240   if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4241       && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4242       && min_dts != 0) {
4243     /* Unless the user has explicitly requested another seek, perform an
4244      * internal seek to the time specified in the tfdt.
4245      *
4246      * This way if the user opens a file where the first tfdt is 1 hour
4247      * into the presentation, they will not have to wait 1 hour for run
4248      * time to catch up and actual playback to start. */
4249     gint i;
4250 
4251     GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4252         "performing an internal seek to %" GST_TIME_FORMAT,
4253         GST_TIME_ARGS (min_dts));
4254 
4255     qtdemux->segment.start = min_dts;
4256     qtdemux->segment.time = qtdemux->segment.position = min_dts;
4257 
4258     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4259       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4260       stream->time_position = min_dts;
4261     }
4262 
4263     /* Before this code was run a segment was already sent when the moov was
4264      * parsed... which is OK -- some apps (mostly tests) expect a segment to
4265      * be emitted after a moov, and we can emit a second segment anyway for
4266      * special cases like this. */
4267     qtdemux->need_segment = TRUE;
4268   }
4269 
4270   qtdemux->first_moof_already_parsed = TRUE;
4271 
4272   g_node_destroy (moof_node);
4273   return TRUE;
4274 
4275 missing_tfhd:
4276   {
4277     GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4278     goto fail;
4279   }
4280 missing_mfhd:
4281   {
4282     GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4283     goto fail;
4284   }
4285 lost_offset:
4286   {
4287     GST_DEBUG_OBJECT (qtdemux, "lost offset");
4288     goto fail;
4289   }
4290 fail:
4291   {
4292     g_node_destroy (moof_node);
4293     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4294         (_("This file is corrupt and cannot be played.")), (NULL));
4295     return FALSE;
4296   }
4297 }
4298 
4299 #if 0
4300 /* might be used if some day we actually use mfra & co
4301  * for random access to fragments,
4302  * but that will require quite some modifications and much less relying
4303  * on a sample array */
4304 #endif
4305 
4306 static gboolean
qtdemux_parse_tfra(GstQTDemux * qtdemux,GNode * tfra_node)4307 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4308 {
4309   QtDemuxStream *stream;
4310   guint32 ver_flags, track_id, len, num_entries, i;
4311   guint value_size, traf_size, trun_size, sample_size;
4312   guint64 time = 0, moof_offset = 0;
4313 #if 0
4314   GstBuffer *buf = NULL;
4315   GstFlowReturn ret;
4316 #endif
4317   GstByteReader tfra;
4318 
4319   gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4320 
4321   if (!gst_byte_reader_skip (&tfra, 8))
4322     return FALSE;
4323 
4324   if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4325     return FALSE;
4326 
4327   if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4328       || !gst_byte_reader_get_uint32_be (&tfra, &len)
4329       || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4330     return FALSE;
4331 
4332   GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4333 
4334   stream = qtdemux_find_stream (qtdemux, track_id);
4335   if (stream == NULL)
4336     goto unknown_trackid;
4337 
4338   value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4339   sample_size = (len & 3) + 1;
4340   trun_size = ((len & 12) >> 2) + 1;
4341   traf_size = ((len & 48) >> 4) + 1;
4342 
4343   GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4344       "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4345 
4346   if (num_entries == 0)
4347     goto no_samples;
4348 
4349   if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4350           value_size + value_size + traf_size + trun_size + sample_size))
4351     goto corrupt_file;
4352 
4353   g_free (stream->ra_entries);
4354   stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4355   stream->n_ra_entries = num_entries;
4356 
4357   for (i = 0; i < num_entries; i++) {
4358     qt_atom_parser_get_offset (&tfra, value_size, &time);
4359     qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4360     qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4361     qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4362     qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4363 
4364     time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4365 
4366     GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4367         " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4368 
4369     stream->ra_entries[i].ts = time;
4370     stream->ra_entries[i].moof_offset = moof_offset;
4371 
4372     /* don't want to go through the entire file and read all moofs at startup */
4373 #if 0
4374     ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4375     if (ret != GST_FLOW_OK)
4376       goto corrupt_file;
4377     qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4378         moof_offset, stream);
4379     gst_buffer_unref (buf);
4380 #endif
4381   }
4382 
4383   check_update_duration (qtdemux, time);
4384 
4385   return TRUE;
4386 
4387 /* ERRORS */
4388 unknown_trackid:
4389   {
4390     GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4391     return FALSE;
4392   }
4393 corrupt_file:
4394   {
4395     GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4396     return FALSE;
4397   }
4398 no_samples:
4399   {
4400     GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4401     return FALSE;
4402   }
4403 }
4404 
4405 static gboolean
qtdemux_pull_mfro_mfra(GstQTDemux * qtdemux)4406 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4407 {
4408   GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4409   GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4410   GstBuffer *mfro = NULL, *mfra = NULL;
4411   GstFlowReturn flow;
4412   gboolean ret = FALSE;
4413   GNode *mfra_node, *tfra_node;
4414   guint64 mfra_offset = 0;
4415   guint32 fourcc, mfra_size;
4416   gint64 len;
4417 
4418   /* query upstream size in bytes */
4419   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4420     goto size_query_failed;
4421 
4422   /* mfro box should be at the very end of the file */
4423   flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4424   if (flow != GST_FLOW_OK)
4425     goto exit;
4426 
4427   gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4428 
4429   fourcc = QT_FOURCC (mfro_map.data + 4);
4430   if (fourcc != FOURCC_mfro)
4431     goto exit;
4432 
4433   GST_INFO_OBJECT (qtdemux, "Found mfro box");
4434   if (mfro_map.size < 16)
4435     goto invalid_mfro_size;
4436 
4437   mfra_size = QT_UINT32 (mfro_map.data + 12);
4438   if (mfra_size >= len)
4439     goto invalid_mfra_size;
4440 
4441   mfra_offset = len - mfra_size;
4442 
4443   GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4444       mfra_offset, mfra_size);
4445 
4446   /* now get and parse mfra box */
4447   flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4448   if (flow != GST_FLOW_OK)
4449     goto broken_file;
4450 
4451   gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4452 
4453   mfra_node = g_node_new ((guint8 *) mfra_map.data);
4454   qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4455 
4456   tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4457 
4458   while (tfra_node) {
4459     qtdemux_parse_tfra (qtdemux, tfra_node);
4460     /* iterate all siblings */
4461     tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4462   }
4463   g_node_destroy (mfra_node);
4464 
4465   GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4466   ret = TRUE;
4467 
4468 exit:
4469 
4470   if (mfro) {
4471     if (mfro_map.memory != NULL)
4472       gst_buffer_unmap (mfro, &mfro_map);
4473     gst_buffer_unref (mfro);
4474   }
4475   if (mfra) {
4476     if (mfra_map.memory != NULL)
4477       gst_buffer_unmap (mfra, &mfra_map);
4478     gst_buffer_unref (mfra);
4479   }
4480   return ret;
4481 
4482 /* ERRORS */
4483 size_query_failed:
4484   {
4485     GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4486     goto exit;
4487   }
4488 invalid_mfro_size:
4489   {
4490     GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4491     goto exit;
4492   }
4493 invalid_mfra_size:
4494   {
4495     GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4496     goto exit;
4497   }
4498 broken_file:
4499   {
4500     GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4501     goto exit;
4502   }
4503 }
4504 
4505 static guint64
add_offset(guint64 offset,guint64 advance)4506 add_offset (guint64 offset, guint64 advance)
4507 {
4508   /* Avoid 64-bit overflow by clamping */
4509   if (offset > G_MAXUINT64 - advance)
4510     return G_MAXUINT64;
4511   return offset + advance;
4512 }
4513 
4514 static GstFlowReturn
gst_qtdemux_loop_state_header(GstQTDemux * qtdemux)4515 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4516 {
4517   guint64 length = 0;
4518   guint32 fourcc = 0;
4519   GstBuffer *buf = NULL;
4520   GstFlowReturn ret = GST_FLOW_OK;
4521   guint64 cur_offset = qtdemux->offset;
4522   GstMapInfo map;
4523 
4524   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4525   if (G_UNLIKELY (ret != GST_FLOW_OK))
4526     goto beach;
4527   gst_buffer_map (buf, &map, GST_MAP_READ);
4528   if (G_LIKELY (map.size >= 8))
4529     extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4530   gst_buffer_unmap (buf, &map);
4531   gst_buffer_unref (buf);
4532 
4533   /* maybe we already got most we needed, so only consider this eof */
4534   if (G_UNLIKELY (length == 0)) {
4535     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4536         (_("Invalid atom size.")),
4537         ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4538             GST_FOURCC_ARGS (fourcc)));
4539     ret = GST_FLOW_EOS;
4540     goto beach;
4541   }
4542 
4543   switch (fourcc) {
4544     case FOURCC_moof:
4545       /* record for later parsing when needed */
4546       if (!qtdemux->moof_offset) {
4547         qtdemux->moof_offset = qtdemux->offset;
4548       }
4549       if (qtdemux_pull_mfro_mfra (qtdemux)) {
4550         /* FIXME */
4551       } else {
4552         qtdemux->offset += length;      /* skip moof and keep going */
4553       }
4554       if (qtdemux->got_moov) {
4555         GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4556         ret = GST_FLOW_EOS;
4557         goto beach;
4558       }
4559       break;
4560     case FOURCC_mdat:
4561     case FOURCC_free:
4562     case FOURCC_skip:
4563     case FOURCC_wide:
4564     case FOURCC_PICT:
4565     case FOURCC_pnot:
4566     {
4567       GST_LOG_OBJECT (qtdemux,
4568           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4569           GST_FOURCC_ARGS (fourcc), cur_offset);
4570       qtdemux->offset = add_offset (qtdemux->offset, length);
4571       break;
4572     }
4573     case FOURCC_moov:
4574     {
4575       GstBuffer *moov = NULL;
4576 
4577       if (qtdemux->got_moov) {
4578         GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4579         qtdemux->offset = add_offset (qtdemux->offset, length);
4580         goto beach;
4581       }
4582 
4583       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4584       if (ret != GST_FLOW_OK)
4585         goto beach;
4586       gst_buffer_map (moov, &map, GST_MAP_READ);
4587 
4588       if (length != map.size) {
4589         /* Some files have a 'moov' atom at the end of the file which contains
4590          * a terminal 'free' atom where the body of the atom is missing.
4591          * Check for, and permit, this special case.
4592          */
4593         if (map.size >= 8) {
4594           guint8 *final_data = map.data + (map.size - 8);
4595           guint32 final_length = QT_UINT32 (final_data);
4596           guint32 final_fourcc = QT_FOURCC (final_data + 4);
4597 
4598           if (final_fourcc == FOURCC_free
4599               && map.size + final_length - 8 == length) {
4600             /* Ok, we've found that special case. Allocate a new buffer with
4601              * that free atom actually present. */
4602             GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4603             gst_buffer_fill (newmoov, 0, map.data, map.size);
4604             gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4605             gst_buffer_unmap (moov, &map);
4606             gst_buffer_unref (moov);
4607             moov = newmoov;
4608             gst_buffer_map (moov, &map, GST_MAP_READ);
4609           }
4610         }
4611       }
4612 
4613       if (length != map.size) {
4614         GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4615             (_("This file is incomplete and cannot be played.")),
4616             ("We got less than expected (received %" G_GSIZE_FORMAT
4617                 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4618                 (guint) length, cur_offset));
4619         gst_buffer_unmap (moov, &map);
4620         gst_buffer_unref (moov);
4621         ret = GST_FLOW_ERROR;
4622         goto beach;
4623       }
4624       qtdemux->offset += length;
4625 
4626       qtdemux_parse_moov (qtdemux, map.data, length);
4627       qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4628 
4629       qtdemux_parse_tree (qtdemux);
4630       if (qtdemux->moov_node_compressed) {
4631         g_node_destroy (qtdemux->moov_node_compressed);
4632         g_free (qtdemux->moov_node->data);
4633       }
4634       qtdemux->moov_node_compressed = NULL;
4635       g_node_destroy (qtdemux->moov_node);
4636       qtdemux->moov_node = NULL;
4637       gst_buffer_unmap (moov, &map);
4638       gst_buffer_unref (moov);
4639       qtdemux->got_moov = TRUE;
4640 
4641       break;
4642     }
4643     case FOURCC_ftyp:
4644     {
4645       GstBuffer *ftyp = NULL;
4646 
4647       /* extract major brand; might come in handy for ISO vs QT issues */
4648       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4649       if (ret != GST_FLOW_OK)
4650         goto beach;
4651       qtdemux->offset += length;
4652       gst_buffer_map (ftyp, &map, GST_MAP_READ);
4653       qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4654       gst_buffer_unmap (ftyp, &map);
4655       gst_buffer_unref (ftyp);
4656       break;
4657     }
4658     case FOURCC_uuid:
4659     {
4660       GstBuffer *uuid = NULL;
4661 
4662       /* uuid are extension atoms */
4663       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4664       if (ret != GST_FLOW_OK)
4665         goto beach;
4666       qtdemux->offset += length;
4667       gst_buffer_map (uuid, &map, GST_MAP_READ);
4668       qtdemux_parse_uuid (qtdemux, map.data, map.size);
4669       gst_buffer_unmap (uuid, &map);
4670       gst_buffer_unref (uuid);
4671       break;
4672     }
4673     case FOURCC_sidx:
4674     {
4675       GstBuffer *sidx = NULL;
4676       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4677       if (ret != GST_FLOW_OK)
4678         goto beach;
4679       qtdemux->offset += length;
4680       gst_buffer_map (sidx, &map, GST_MAP_READ);
4681       qtdemux_parse_sidx (qtdemux, map.data, map.size);
4682       gst_buffer_unmap (sidx, &map);
4683       gst_buffer_unref (sidx);
4684       break;
4685     }
4686     default:
4687     {
4688       GstBuffer *unknown = NULL;
4689 
4690       GST_LOG_OBJECT (qtdemux,
4691           "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4692           " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4693           cur_offset);
4694       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4695       if (ret != GST_FLOW_OK)
4696         goto beach;
4697       gst_buffer_map (unknown, &map, GST_MAP_READ);
4698       GST_MEMDUMP ("Unknown tag", map.data, map.size);
4699       gst_buffer_unmap (unknown, &map);
4700       gst_buffer_unref (unknown);
4701       qtdemux->offset += length;
4702       break;
4703     }
4704   }
4705 
4706 beach:
4707   if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4708     /* digested all data, show what we have */
4709     qtdemux_prepare_streams (qtdemux);
4710     QTDEMUX_EXPOSE_LOCK (qtdemux);
4711     ret = qtdemux_expose_streams (qtdemux);
4712     QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4713 
4714     qtdemux->state = QTDEMUX_STATE_MOVIE;
4715     GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4716         qtdemux->state);
4717     return ret;
4718   }
4719   return ret;
4720 }
4721 
4722 /* Seeks to the previous keyframe of the indexed stream and
4723  * aligns other streams with respect to the keyframe timestamp
4724  * of indexed stream. Only called in case of Reverse Playback
4725  */
4726 static GstFlowReturn
gst_qtdemux_seek_to_previous_keyframe(GstQTDemux * qtdemux)4727 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4728 {
4729   guint32 seg_idx = 0, k_index = 0;
4730   guint32 ref_seg_idx, ref_k_index;
4731   GstClockTime k_pos = 0, last_stop = 0;
4732   QtDemuxSegment *seg = NULL;
4733   QtDemuxStream *ref_str = NULL;
4734   guint64 seg_media_start_mov;  /* segment media start time in mov format */
4735   guint64 target_ts;
4736   gint i;
4737 
4738   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4739    * and finally align all the other streams on that timestamp with their
4740    * respective keyframes */
4741   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4742     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4743 
4744     /* No candidate yet, take the first stream */
4745     if (!ref_str) {
4746       ref_str = str;
4747       continue;
4748     }
4749 
4750     /* So that stream has a segment, we prefer video streams */
4751     if (str->subtype == FOURCC_vide) {
4752       ref_str = str;
4753       break;
4754     }
4755   }
4756 
4757   if (G_UNLIKELY (!ref_str)) {
4758     GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4759     goto eos;
4760   }
4761 
4762   if (G_UNLIKELY (!ref_str->from_sample)) {
4763     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4764     goto eos;
4765   }
4766 
4767   /* So that stream has been playing from from_sample to to_sample. We will
4768    * get the timestamp of the previous sample and search for a keyframe before
4769    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4770   if (ref_str->subtype == FOURCC_vide) {
4771     k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4772         ref_str->from_sample - 1, FALSE);
4773   } else {
4774     if (ref_str->from_sample >= 10)
4775       k_index = ref_str->from_sample - 10;
4776     else
4777       k_index = 0;
4778   }
4779 
4780   target_ts =
4781       ref_str->samples[k_index].timestamp +
4782       ref_str->samples[k_index].pts_offset;
4783 
4784   /* get current segment for that stream */
4785   seg = &ref_str->segments[ref_str->segment_index];
4786   /* Use segment start in original timescale for comparisons */
4787   seg_media_start_mov = seg->trak_media_start;
4788 
4789   GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4790       " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4791       k_index, target_ts, seg_media_start_mov,
4792       GST_TIME_ARGS (seg->media_start));
4793 
4794   /* Crawl back through segments to find the one containing this I frame */
4795   while (target_ts < seg_media_start_mov) {
4796     GST_DEBUG_OBJECT (qtdemux,
4797         "keyframe position (sample %u) is out of segment %u " " target %"
4798         G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4799         ref_str->segment_index, target_ts, seg_media_start_mov);
4800 
4801     if (G_UNLIKELY (!ref_str->segment_index)) {
4802       /* Reached first segment, let's consider it's EOS */
4803       goto eos;
4804     }
4805     ref_str->segment_index--;
4806     seg = &ref_str->segments[ref_str->segment_index];
4807     /* Use segment start in original timescale for comparisons */
4808     seg_media_start_mov = seg->trak_media_start;
4809   }
4810   /* Calculate time position of the keyframe and where we should stop */
4811   k_pos =
4812       QTSTREAMTIME_TO_GSTTIME (ref_str,
4813       target_ts - seg->trak_media_start) + seg->time;
4814   last_stop =
4815       QTSTREAMTIME_TO_GSTTIME (ref_str,
4816       ref_str->samples[ref_str->from_sample].timestamp -
4817       seg->trak_media_start) + seg->time;
4818 
4819   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4820       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4821       k_index, GST_TIME_ARGS (k_pos));
4822 
4823   /* Set last_stop with the keyframe timestamp we pushed of that stream */
4824   qtdemux->segment.position = last_stop;
4825   GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4826       GST_TIME_ARGS (last_stop));
4827 
4828   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4829     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4830     goto eos;
4831   }
4832 
4833   ref_seg_idx = ref_str->segment_index;
4834   ref_k_index = k_index;
4835 
4836   /* Align them all on this */
4837   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4838     guint32 index = 0;
4839     GstClockTime seg_time = 0;
4840     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4841 
4842     /* aligning reference stream again might lead to backing up to yet another
4843      * keyframe (due to timestamp rounding issues),
4844      * potentially putting more load on downstream; so let's try to avoid */
4845     if (str == ref_str) {
4846       seg_idx = ref_seg_idx;
4847       seg = &str->segments[seg_idx];
4848       k_index = ref_k_index;
4849       GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4850           "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4851     } else {
4852       seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4853       GST_DEBUG_OBJECT (qtdemux,
4854           "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4855           str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4856 
4857       /* get segment and time in the segment */
4858       seg = &str->segments[seg_idx];
4859       seg_time = k_pos - seg->time;
4860 
4861       /* get the media time in the segment.
4862        * No adjustment for empty "filler" segments */
4863       if (seg->media_start != GST_CLOCK_TIME_NONE)
4864         seg_time += seg->media_start;
4865 
4866       /* get the index of the sample with media time */
4867       index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4868       GST_DEBUG_OBJECT (qtdemux,
4869           "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4870           GST_TIME_ARGS (seg_time), index);
4871 
4872       /* find previous keyframe */
4873       k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4874     }
4875 
4876     /* Remember until where we want to go */
4877     str->to_sample = str->from_sample - 1;
4878     /* Define our time position */
4879     target_ts =
4880         str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4881     str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4882     if (seg->media_start != GST_CLOCK_TIME_NONE)
4883       str->time_position -= seg->media_start;
4884 
4885     /* Now seek back in time */
4886     gst_qtdemux_move_stream (qtdemux, str, k_index);
4887     GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4888         GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4889         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4890   }
4891 
4892   return GST_FLOW_OK;
4893 
4894 eos:
4895   return GST_FLOW_EOS;
4896 }
4897 
4898 /*
4899  * Gets the current qt segment start, stop and position for the
4900  * given time offset. This is used in update_segment()
4901  */
4902 static void
gst_qtdemux_stream_segment_get_boundaries(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime offset,GstClockTime * _start,GstClockTime * _stop,GstClockTime * _time)4903 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4904     QtDemuxStream * stream, GstClockTime offset,
4905     GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4906 {
4907   GstClockTime seg_time;
4908   GstClockTime start, stop, time;
4909   QtDemuxSegment *segment;
4910 
4911   segment = &stream->segments[stream->segment_index];
4912 
4913   /* get time in this segment */
4914   seg_time = (offset - segment->time) * segment->rate;
4915 
4916   GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4917       GST_TIME_ARGS (seg_time));
4918 
4919   if (G_UNLIKELY (seg_time > segment->duration)) {
4920     GST_LOG_OBJECT (stream->pad,
4921         "seg_time > segment->duration %" GST_TIME_FORMAT,
4922         GST_TIME_ARGS (segment->duration));
4923     seg_time = segment->duration;
4924   }
4925 
4926   /* qtdemux->segment.stop is in outside-time-realm, whereas
4927    * segment->media_stop is in track-time-realm.
4928    *
4929    * In order to compare the two, we need to bring segment.stop
4930    * into the track-time-realm
4931    *
4932    * FIXME - does this comment still hold? Don't see any conversion here */
4933 
4934   stop = qtdemux->segment.stop;
4935   if (stop == GST_CLOCK_TIME_NONE)
4936     stop = qtdemux->segment.duration;
4937   if (stop == GST_CLOCK_TIME_NONE)
4938     stop = segment->media_stop;
4939   else
4940     stop =
4941         MIN (segment->media_stop, stop - segment->time + segment->media_start);
4942 
4943   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4944     start = segment->time + seg_time;
4945     time = offset;
4946     stop = start - seg_time + segment->duration;
4947   } else if (qtdemux->segment.rate >= 0) {
4948     start = MIN (segment->media_start + seg_time, stop);
4949     time = offset;
4950   } else {
4951     if (segment->media_start >= qtdemux->segment.start) {
4952       time = segment->time;
4953     } else {
4954       time = segment->time + (qtdemux->segment.start - segment->media_start);
4955     }
4956 
4957     start = MAX (segment->media_start, qtdemux->segment.start);
4958     stop = MIN (segment->media_start + seg_time, stop);
4959   }
4960 
4961   *_start = start;
4962   *_stop = stop;
4963   *_time = time;
4964 }
4965 
4966 /*
4967  * Updates the qt segment used for the stream and pushes a new segment event
4968  * downstream on this stream's pad.
4969  */
4970 static gboolean
gst_qtdemux_stream_update_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,gint seg_idx,GstClockTime offset,GstClockTime * _start,GstClockTime * _stop)4971 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4972     gint seg_idx, GstClockTime offset, GstClockTime * _start,
4973     GstClockTime * _stop)
4974 {
4975   QtDemuxSegment *segment;
4976   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4977   gdouble rate;
4978   GstEvent *event;
4979 
4980   /* update the current segment */
4981   stream->segment_index = seg_idx;
4982 
4983   /* get the segment */
4984   segment = &stream->segments[seg_idx];
4985 
4986   if (G_UNLIKELY (offset < segment->time)) {
4987     GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4988         GST_TIME_ARGS (segment->time));
4989     return FALSE;
4990   }
4991 
4992   /* segment lies beyond total indicated duration */
4993   if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4994           segment->time > qtdemux->segment.duration)) {
4995     GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4996         " < segment->time %" GST_TIME_FORMAT,
4997         GST_TIME_ARGS (qtdemux->segment.duration),
4998         GST_TIME_ARGS (segment->time));
4999     return FALSE;
5000   }
5001 
5002   gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5003       &start, &stop, &time);
5004 
5005   GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5006       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5007       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5008 
5009   /* combine global rate with that of the segment */
5010   rate = segment->rate * qtdemux->segment.rate;
5011 
5012   /* Copy flags from main segment */
5013   stream->segment.flags = qtdemux->segment.flags;
5014 
5015   /* update the segment values used for clipping */
5016   stream->segment.offset = qtdemux->segment.offset;
5017   stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5018   stream->segment.applied_rate = qtdemux->segment.applied_rate;
5019   stream->segment.rate = rate;
5020   stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5021       stream->cslg_shift);
5022   if (stop != -1)
5023     stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5024         stream->cslg_shift);
5025   else
5026     stream->segment.stop = stop;
5027   stream->segment.time = time;
5028   stream->segment.position = stream->segment.start;
5029 
5030   GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5031       &stream->segment);
5032 
5033   /* now prepare and send the segment */
5034   if (stream->pad) {
5035     event = gst_event_new_segment (&stream->segment);
5036     if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5037       gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5038     }
5039     gst_pad_push_event (stream->pad, event);
5040     /* assume we can send more data now */
5041     GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5042     /* clear to send tags on this pad now */
5043     gst_qtdemux_push_tags (qtdemux, stream);
5044   }
5045 
5046   if (_start)
5047     *_start = start;
5048   if (_stop)
5049     *_stop = stop;
5050 
5051   return TRUE;
5052 }
5053 
5054 /* activate the given segment number @seg_idx of @stream at time @offset.
5055  * @offset is an absolute global position over all the segments.
5056  *
5057  * This will push out a NEWSEGMENT event with the right values and
5058  * position the stream index to the first decodable sample before
5059  * @offset.
5060  */
5061 static gboolean
gst_qtdemux_activate_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 seg_idx,GstClockTime offset)5062 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5063     guint32 seg_idx, GstClockTime offset)
5064 {
5065   QtDemuxSegment *segment;
5066   guint32 index, kf_index;
5067   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5068 
5069   GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5070       seg_idx, GST_TIME_ARGS (offset));
5071 
5072   if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5073           &start, &stop))
5074     return FALSE;
5075 
5076   segment = &stream->segments[stream->segment_index];
5077 
5078   /* in the fragmented case, we pick a fragment that starts before our
5079    * desired position and rely on downstream to wait for a keyframe
5080    * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5081    * tfra entries tells us which trun/sample the key unit is in, but we don't
5082    * make use of this additional information at the moment) */
5083   if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5084     stream->to_sample = G_MAXUINT32;
5085     return TRUE;
5086   } else {
5087     /* well, it will be taken care of below */
5088     qtdemux->fragmented_seek_pending = FALSE;
5089     /* FIXME ideally the do_fragmented_seek can be done right here,
5090      * rather than at loop level
5091      * (which might even allow handling edit lists in a fragmented file) */
5092   }
5093 
5094   /* We don't need to look for a sample in push-based */
5095   if (!qtdemux->pullbased)
5096     return TRUE;
5097 
5098   /* and move to the keyframe before the indicated media time of the
5099    * segment */
5100   if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5101     if (qtdemux->segment.rate >= 0) {
5102       index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5103       stream->to_sample = G_MAXUINT32;
5104       GST_DEBUG_OBJECT (stream->pad,
5105           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5106           GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5107           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5108     } else {
5109       index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5110       stream->to_sample = index;
5111       GST_DEBUG_OBJECT (stream->pad,
5112           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5113           GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5114           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5115     }
5116   } else {
5117     GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5118         "this is an empty segment");
5119     return TRUE;
5120   }
5121 
5122   /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5123    * encountered an error and printed a message so we return appropriately */
5124   if (index == -1)
5125     return FALSE;
5126 
5127   /* we're at the right spot */
5128   if (index == stream->sample_index) {
5129     GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5130     return TRUE;
5131   }
5132 
5133   /* find keyframe of the target index */
5134   kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5135 
5136   /* go back two frames to provide lead-in for non-raw audio decoders */
5137   if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5138     guint32 lead_in = 2;
5139     guint32 old_index = kf_index;
5140     GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5141 
5142     if (gst_structure_has_name (s, "audio/mpeg")) {
5143       gint mpegversion;
5144       if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5145           && mpegversion == 1) {
5146         /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5147         lead_in = 30;
5148       }
5149     }
5150 
5151     kf_index = MAX (kf_index, lead_in) - lead_in;
5152     if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5153       GST_DEBUG_OBJECT (stream->pad,
5154           "Moving backwards %u frames to ensure sufficient sound lead-in",
5155           old_index - kf_index);
5156     } else {
5157       kf_index = old_index;
5158     }
5159   }
5160 
5161   /* if we move forwards, we don't have to go back to the previous
5162    * keyframe since we already sent that. We can also just jump to
5163    * the keyframe right before the target index if there is one. */
5164   if (index > stream->sample_index) {
5165     /* moving forwards check if we move past a keyframe */
5166     if (kf_index > stream->sample_index) {
5167       GST_DEBUG_OBJECT (stream->pad,
5168           "moving forwards to keyframe at %u "
5169           "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5170           kf_index,
5171           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5172           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5173       gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5174     } else {
5175       GST_DEBUG_OBJECT (stream->pad,
5176           "moving forwards, keyframe at %u "
5177           "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5178           kf_index,
5179           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5180           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5181     }
5182   } else {
5183     GST_DEBUG_OBJECT (stream->pad,
5184         "moving backwards to %sframe at %u "
5185         "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5186         (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5187         GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5188         GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5189     gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5190   }
5191 
5192   return TRUE;
5193 }
5194 
5195 /* prepare to get the current sample of @stream, getting essential values.
5196  *
5197  * This function will also prepare and send the segment when needed.
5198  *
5199  * Return FALSE if the stream is EOS.
5200  *
5201  * PULL-BASED
5202  */
5203 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)5204 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5205     QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5206     GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5207     gboolean * keyframe)
5208 {
5209   QtDemuxSample *sample;
5210   GstClockTime time_position;
5211   guint32 seg_idx;
5212 
5213   g_return_val_if_fail (stream != NULL, FALSE);
5214 
5215   time_position = stream->time_position;
5216   if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5217     goto eos;
5218 
5219   seg_idx = stream->segment_index;
5220   if (G_UNLIKELY (seg_idx == -1)) {
5221     /* find segment corresponding to time_position if we are looking
5222      * for a segment. */
5223     seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5224   }
5225 
5226   /* different segment, activate it, sample_index will be set. */
5227   if (G_UNLIKELY (stream->segment_index != seg_idx))
5228     gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5229 
5230   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5231               segments[stream->segment_index]))) {
5232     QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5233 
5234     GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5235         " prepare empty sample");
5236 
5237     *empty = TRUE;
5238     *pts = *dts = time_position;
5239     *duration = seg->duration - (time_position - seg->time);
5240 
5241     return TRUE;
5242   }
5243 
5244   *empty = FALSE;
5245 
5246   if (stream->sample_index == -1)
5247     stream->sample_index = 0;
5248 
5249   GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5250       stream->sample_index, stream->n_samples);
5251 
5252   if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5253     if (!qtdemux->fragmented)
5254       goto eos;
5255 
5256     GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5257     do {
5258       GstFlowReturn flow;
5259 
5260       GST_OBJECT_LOCK (qtdemux);
5261       flow = qtdemux_add_fragmented_samples (qtdemux);
5262       GST_OBJECT_UNLOCK (qtdemux);
5263 
5264       if (flow != GST_FLOW_OK)
5265         goto eos;
5266     }
5267     while (stream->sample_index >= stream->n_samples);
5268   }
5269 
5270   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5271     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5272         stream->sample_index);
5273     return FALSE;
5274   }
5275 
5276   /* now get the info for the sample we're at */
5277   sample = &stream->samples[stream->sample_index];
5278 
5279   *dts = QTSAMPLE_DTS (stream, sample);
5280   *pts = QTSAMPLE_PTS (stream, sample);
5281   *offset = sample->offset;
5282   *size = sample->size;
5283   *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5284   *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5285 
5286   return TRUE;
5287 
5288   /* special cases */
5289 eos:
5290   {
5291     stream->time_position = GST_CLOCK_TIME_NONE;
5292     return FALSE;
5293   }
5294 }
5295 
5296 /* move to the next sample in @stream.
5297  *
5298  * Moves to the next segment when needed.
5299  */
5300 static void
gst_qtdemux_advance_sample(GstQTDemux * qtdemux,QtDemuxStream * stream)5301 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5302 {
5303   QtDemuxSample *sample;
5304   QtDemuxSegment *segment;
5305 
5306   /* get current segment */
5307   segment = &stream->segments[stream->segment_index];
5308 
5309   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5310     GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5311     goto next_segment;
5312   }
5313 
5314   if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5315     /* Mark the stream as EOS */
5316     GST_DEBUG_OBJECT (qtdemux,
5317         "reached max allowed sample %u, mark EOS", stream->to_sample);
5318     stream->time_position = GST_CLOCK_TIME_NONE;
5319     return;
5320   }
5321 
5322   /* move to next sample */
5323   stream->sample_index++;
5324   stream->offset_in_sample = 0;
5325 
5326   GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5327       stream->n_samples);
5328 
5329   /* reached the last sample, we need the next segment */
5330   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5331     goto next_segment;
5332 
5333   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5334     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5335         stream->sample_index);
5336     return;
5337   }
5338 
5339   /* get next sample */
5340   sample = &stream->samples[stream->sample_index];
5341 
5342   GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5343       GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5344       GST_TIME_ARGS (segment->media_stop));
5345 
5346   /* see if we are past the segment */
5347   if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5348     goto next_segment;
5349 
5350   if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5351     /* inside the segment, update time_position, looks very familiar to
5352      * GStreamer segments, doesn't it? */
5353     stream->time_position =
5354         QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5355   } else {
5356     /* not yet in segment, time does not yet increment. This means
5357      * that we are still prerolling keyframes to the decoder so it can
5358      * decode the first sample of the segment. */
5359     stream->time_position = segment->time;
5360   }
5361   return;
5362 
5363   /* move to the next segment */
5364 next_segment:
5365   {
5366     GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5367 
5368     if (stream->segment_index == stream->n_segments - 1) {
5369       /* are we at the end of the last segment, we're EOS */
5370       stream->time_position = GST_CLOCK_TIME_NONE;
5371     } else {
5372       /* else we're only at the end of the current segment */
5373       stream->time_position = segment->stop_time;
5374     }
5375     /* make sure we select a new segment */
5376 
5377     /* accumulate previous segments */
5378     if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5379       stream->accumulated_base +=
5380           (stream->segment.stop -
5381           stream->segment.start) / ABS (stream->segment.rate);
5382 
5383     stream->segment_index = -1;
5384   }
5385 }
5386 
5387 static void
gst_qtdemux_sync_streams(GstQTDemux * demux)5388 gst_qtdemux_sync_streams (GstQTDemux * demux)
5389 {
5390   gint i;
5391 
5392   if (QTDEMUX_N_STREAMS (demux) <= 1)
5393     return;
5394 
5395   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5396     QtDemuxStream *stream;
5397     GstClockTime end_time;
5398 
5399     stream = QTDEMUX_NTH_STREAM (demux, i);
5400 
5401     if (!stream->pad)
5402       continue;
5403 
5404     /* TODO advance time on subtitle streams here, if any some day */
5405 
5406     /* some clips/trailers may have unbalanced streams at the end,
5407      * so send EOS on shorter stream to prevent stalling others */
5408 
5409     /* do not mess with EOS if SEGMENT seeking */
5410     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5411       continue;
5412 
5413     if (demux->pullbased) {
5414       /* loop mode is sample time based */
5415       if (!STREAM_IS_EOS (stream))
5416         continue;
5417     } else {
5418       /* push mode is byte position based */
5419       if (stream->n_samples &&
5420           stream->samples[stream->n_samples - 1].offset >= demux->offset)
5421         continue;
5422     }
5423 
5424     if (stream->sent_eos)
5425       continue;
5426 
5427     /* only act if some gap */
5428     end_time = stream->segments[stream->n_segments - 1].stop_time;
5429     GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5430         ", stream end: %" GST_TIME_FORMAT,
5431         GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5432     if (GST_CLOCK_TIME_IS_VALID (end_time)
5433         && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5434       GstEvent *event;
5435 
5436       GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5437           GST_PAD_NAME (stream->pad));
5438       stream->sent_eos = TRUE;
5439       event = gst_event_new_eos ();
5440       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5441         gst_event_set_seqnum (event, demux->segment_seqnum);
5442       gst_pad_push_event (stream->pad, event);
5443     }
5444   }
5445 }
5446 
5447 /* EOS and NOT_LINKED need to be combined. This means that we return:
5448  *
5449  *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5450  *  GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5451  */
5452 static GstFlowReturn
gst_qtdemux_combine_flows(GstQTDemux * demux,QtDemuxStream * stream,GstFlowReturn ret)5453 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5454     GstFlowReturn ret)
5455 {
5456   GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5457 
5458   if (stream->pad)
5459     ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5460         ret);
5461   else
5462     ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5463 
5464   GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5465   return ret;
5466 }
5467 
5468 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5469  * completely clipped
5470  *
5471  * Should be used only with raw buffers */
5472 static GstBuffer *
gst_qtdemux_clip_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5473 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5474     GstBuffer * buf)
5475 {
5476   guint64 start, stop, cstart, cstop, diff;
5477   GstClockTime pts, duration;
5478   gsize size, osize;
5479   gint num_rate, denom_rate;
5480   gint frame_size;
5481   gboolean clip_data;
5482   guint offset;
5483 
5484   osize = size = gst_buffer_get_size (buf);
5485   offset = 0;
5486 
5487   /* depending on the type, setup the clip parameters */
5488   if (stream->subtype == FOURCC_soun) {
5489     frame_size = CUR_STREAM (stream)->bytes_per_frame;
5490     num_rate = GST_SECOND;
5491     denom_rate = (gint) CUR_STREAM (stream)->rate;
5492     clip_data = TRUE;
5493   } else if (stream->subtype == FOURCC_vide) {
5494     frame_size = size;
5495     num_rate = CUR_STREAM (stream)->fps_n;
5496     denom_rate = CUR_STREAM (stream)->fps_d;
5497     clip_data = FALSE;
5498   } else
5499     goto wrong_type;
5500 
5501   if (frame_size <= 0)
5502     goto bad_frame_size;
5503 
5504   /* we can only clip if we have a valid pts */
5505   pts = GST_BUFFER_PTS (buf);
5506   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5507     goto no_pts;
5508 
5509   duration = GST_BUFFER_DURATION (buf);
5510 
5511   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5512     duration =
5513         gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5514   }
5515 
5516   start = pts;
5517   stop = start + duration;
5518 
5519   if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5520               GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5521     goto clipped;
5522 
5523   /* see if some clipping happened */
5524   diff = cstart - start;
5525   if (diff > 0) {
5526     pts += diff;
5527     duration -= diff;
5528 
5529     if (clip_data) {
5530       /* bring clipped time to samples and to bytes */
5531       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5532       diff *= frame_size;
5533 
5534       GST_DEBUG_OBJECT (qtdemux,
5535           "clipping start to %" GST_TIME_FORMAT " %"
5536           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5537 
5538       offset = diff;
5539       size -= diff;
5540     }
5541   }
5542   diff = stop - cstop;
5543   if (diff > 0) {
5544     duration -= diff;
5545 
5546     if (clip_data) {
5547       /* bring clipped time to samples and then to bytes */
5548       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5549       diff *= frame_size;
5550       GST_DEBUG_OBJECT (qtdemux,
5551           "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5552           " bytes", GST_TIME_ARGS (cstop), diff);
5553       size -= diff;
5554     }
5555   }
5556 
5557   if (offset != 0 || size != osize)
5558     gst_buffer_resize (buf, offset, size);
5559 
5560   GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5561   GST_BUFFER_PTS (buf) = pts;
5562   GST_BUFFER_DURATION (buf) = duration;
5563 
5564   return buf;
5565 
5566   /* dropped buffer */
5567 wrong_type:
5568   {
5569     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5570     return buf;
5571   }
5572 bad_frame_size:
5573   {
5574     GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5575     return buf;
5576   }
5577 no_pts:
5578   {
5579     GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5580     return buf;
5581   }
5582 clipped:
5583   {
5584     GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5585     gst_buffer_unref (buf);
5586     return NULL;
5587   }
5588 }
5589 
5590 static GstBuffer *
gst_qtdemux_align_buffer(GstQTDemux * demux,GstBuffer * buffer,gsize alignment)5591 gst_qtdemux_align_buffer (GstQTDemux * demux,
5592     GstBuffer * buffer, gsize alignment)
5593 {
5594   GstMapInfo map;
5595 
5596   gst_buffer_map (buffer, &map, GST_MAP_READ);
5597 
5598   if (map.size < sizeof (guintptr)) {
5599     gst_buffer_unmap (buffer, &map);
5600     return buffer;
5601   }
5602 
5603   if (((guintptr) map.data) & (alignment - 1)) {
5604     GstBuffer *new_buffer;
5605     GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5606 
5607     new_buffer = gst_buffer_new_allocate (NULL,
5608         gst_buffer_get_size (buffer), &params);
5609 
5610     /* Copy data "by hand", so ensure alignment is kept: */
5611     gst_buffer_fill (new_buffer, 0, map.data, map.size);
5612 
5613     gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5614     GST_DEBUG_OBJECT (demux,
5615         "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5616         alignment);
5617 
5618     gst_buffer_unmap (buffer, &map);
5619     gst_buffer_unref (buffer);
5620 
5621     return new_buffer;
5622   }
5623 
5624   gst_buffer_unmap (buffer, &map);
5625   return buffer;
5626 }
5627 
5628 static guint8 *
convert_to_s334_1a(const guint8 * ccpair,guint8 ccpair_size,guint field,gsize * res)5629 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5630     gsize * res)
5631 {
5632   guint8 *storage;
5633   gsize i;
5634 
5635   /* We are converting from pairs to triplets */
5636   *res = ccpair_size / 2 * 3;
5637   storage = g_malloc (*res);
5638   for (i = 0; i * 2 < ccpair_size; i += 1) {
5639     /* FIXME: Use line offset 0 as we simply can't know here */
5640     if (field == 1)
5641       storage[i * 3] = 0x80 | 0x00;
5642     else
5643       storage[i * 3] = 0x00 | 0x00;
5644     storage[i * 3 + 1] = ccpair[i * 2];
5645     storage[i * 3 + 2] = ccpair[i * 2 + 1];
5646   }
5647 
5648   return storage;
5649 }
5650 
5651 static guint8 *
extract_cc_from_data(QtDemuxStream * stream,const guint8 * data,gsize size,gsize * cclen)5652 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5653     gsize * cclen)
5654 {
5655   guint8 *res = NULL;
5656   guint32 atom_length, fourcc;
5657   QtDemuxStreamStsdEntry *stsd_entry;
5658 
5659   GST_MEMDUMP ("caption atom", data, size);
5660 
5661   /* There might be multiple atoms */
5662 
5663   *cclen = 0;
5664   if (size < 8)
5665     goto invalid_cdat;
5666   atom_length = QT_UINT32 (data);
5667   fourcc = QT_FOURCC (data + 4);
5668   if (G_UNLIKELY (atom_length > size || atom_length == 8))
5669     goto invalid_cdat;
5670 
5671   GST_DEBUG_OBJECT (stream->pad, "here");
5672 
5673   /* Check if we have something compatible */
5674   stsd_entry = CUR_STREAM (stream);
5675   switch (stsd_entry->fourcc) {
5676     case FOURCC_c608:{
5677       guint8 *cdat = NULL, *cdt2 = NULL;
5678       gsize cdat_size = 0, cdt2_size = 0;
5679       /* Should be cdat or cdt2 */
5680       if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5681         GST_WARNING_OBJECT (stream->pad,
5682             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5683             GST_FOURCC_ARGS (fourcc));
5684         goto invalid_cdat;
5685       }
5686 
5687       /* Convert to S334-1 Annex A byte triplet */
5688       if (fourcc == FOURCC_cdat)
5689         cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5690       else
5691         cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5692       GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5693           size, atom_length);
5694 
5695       /* Check for another atom ? */
5696       if (size > atom_length + 8) {
5697         guint32 new_atom_length = QT_UINT32 (data + atom_length);
5698         if (size >= atom_length + new_atom_length) {
5699           fourcc = QT_FOURCC (data + atom_length + 4);
5700           if (fourcc == FOURCC_cdat) {
5701             if (cdat == NULL)
5702               cdat =
5703                   convert_to_s334_1a (data + atom_length + 8,
5704                   new_atom_length - 8, 1, &cdat_size);
5705             else
5706               GST_WARNING_OBJECT (stream->pad,
5707                   "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5708           } else {
5709             if (cdt2 == NULL)
5710               cdt2 =
5711                   convert_to_s334_1a (data + atom_length + 8,
5712                   new_atom_length - 8, 2, &cdt2_size);
5713             else
5714               GST_WARNING_OBJECT (stream->pad,
5715                   "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5716           }
5717         }
5718       }
5719 
5720       *cclen = cdat_size + cdt2_size;
5721       res = g_malloc (*cclen);
5722       if (cdat_size)
5723         memcpy (res, cdat, cdat_size);
5724       if (cdt2_size)
5725         memcpy (res + cdat_size, cdt2, cdt2_size);
5726       g_free (cdat);
5727       g_free (cdt2);
5728     }
5729       break;
5730     case FOURCC_c708:
5731       if (fourcc != FOURCC_ccdp) {
5732         GST_WARNING_OBJECT (stream->pad,
5733             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5734             GST_FOURCC_ARGS (fourcc));
5735         goto invalid_cdat;
5736       }
5737       *cclen = atom_length - 8;
5738       res = g_memdup2 (data + 8, *cclen);
5739       break;
5740     default:
5741       /* Keep this here in case other closed caption formats are added */
5742       g_assert_not_reached ();
5743       break;
5744   }
5745 
5746   GST_MEMDUMP ("Output", res, *cclen);
5747   return res;
5748 
5749   /* Errors */
5750 invalid_cdat:
5751   GST_WARNING ("[cdat] atom is too small or invalid");
5752   return NULL;
5753 }
5754 
5755 /* Handle Closed Caption sample buffers.
5756  * The input buffer metadata must be writable,
5757  * but time/duration etc not yet set and need not be preserved */
5758 static GstBuffer *
gst_qtdemux_process_buffer_clcp(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5759 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5760     GstBuffer * buf)
5761 {
5762   GstBuffer *outbuf = NULL;
5763   GstMapInfo map;
5764   guint8 *cc;
5765   gsize cclen = 0;
5766 
5767   gst_buffer_map (buf, &map, GST_MAP_READ);
5768 
5769   /* empty buffer is sent to terminate previous subtitle */
5770   if (map.size <= 2) {
5771     gst_buffer_unmap (buf, &map);
5772     gst_buffer_unref (buf);
5773     return NULL;
5774   }
5775 
5776   /* For closed caption, we need to extract the information from the
5777    * [cdat],[cdt2] or [ccdp] atom */
5778   cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5779   gst_buffer_unmap (buf, &map);
5780   if (cc) {
5781     outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5782     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5783   } else {
5784     /* Conversion failed or there's nothing */
5785   }
5786   gst_buffer_unref (buf);
5787 
5788   return outbuf;
5789 }
5790 
5791 /* DVD subpicture specific sample handling.
5792  * the input buffer metadata must be writable,
5793  * but time/duration etc not yet set and need not be preserved */
5794 static GstBuffer *
gst_qtdemux_process_buffer_dvd(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5795 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5796     GstBuffer * buf)
5797 {
5798   /* send a one time dvd clut event */
5799   if (stream->pending_event && stream->pad)
5800     gst_pad_push_event (stream->pad, stream->pending_event);
5801   stream->pending_event = NULL;
5802 
5803   /* empty buffer is sent to terminate previous subtitle */
5804   if (gst_buffer_get_size (buf) <= 2) {
5805     gst_buffer_unref (buf);
5806     return NULL;
5807   }
5808 
5809   /* That's all the processing needed for subpictures */
5810   return buf;
5811 }
5812 
5813 /* Timed text formats
5814  * the input buffer metadata must be writable,
5815  * but time/duration etc not yet set and need not be preserved */
5816 static GstBuffer *
gst_qtdemux_process_buffer_text(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5817 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5818     GstBuffer * buf)
5819 {
5820   GstBuffer *outbuf = NULL;
5821   GstMapInfo map;
5822   guint nsize = 0;
5823   gchar *str;
5824 
5825   /* not many cases for now */
5826   if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5827           stream->subtype != FOURCC_sbtl)) {
5828     return buf;
5829   }
5830 
5831   gst_buffer_map (buf, &map, GST_MAP_READ);
5832 
5833   /* empty buffer is sent to terminate previous subtitle */
5834   if (map.size <= 2) {
5835     gst_buffer_unmap (buf, &map);
5836     gst_buffer_unref (buf);
5837     return NULL;
5838   }
5839 
5840   nsize = GST_READ_UINT16_BE (map.data);
5841   nsize = MIN (nsize, map.size - 2);
5842 
5843   GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5844       nsize, map.size);
5845 
5846   /* takes care of UTF-8 validation or UTF-16 recognition,
5847    * no other encoding expected */
5848   str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5849   gst_buffer_unmap (buf, &map);
5850 
5851   if (str) {
5852     outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5853     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5854   } else {
5855     /* this should not really happen unless the subtitle is corrupted */
5856   }
5857   gst_buffer_unref (buf);
5858 
5859   /* FIXME ? convert optional subsequent style info to markup */
5860 
5861   return outbuf;
5862 }
5863 
5864 /* WebVTT sample handling according to 14496-30 */
5865 static GstBuffer *
gst_qtdemux_process_buffer_wvtt(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5866 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5867     GstBuffer * buf)
5868 {
5869   GstBuffer *outbuf = NULL;
5870   GstMapInfo map;
5871 
5872   if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5873     g_assert_not_reached ();    /* The buffer must be mappable */
5874   }
5875 
5876   if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5877     GstEvent *gap = NULL;
5878     /* Push a gap event */
5879     stream->segment.position = GST_BUFFER_PTS (buf);
5880     gap =
5881         gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5882     gst_pad_push_event (stream->pad, gap);
5883 
5884     if (GST_BUFFER_DURATION_IS_VALID (buf))
5885       stream->segment.position += GST_BUFFER_DURATION (buf);
5886   } else {
5887     outbuf =
5888         qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5889         GST_BUFFER_DURATION (buf), map.data, map.size);
5890     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5891   }
5892 
5893   gst_buffer_unmap (buf, &map);
5894   gst_buffer_unref (buf);
5895 
5896   return outbuf;
5897 }
5898 
5899 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
5900 static void
kpi_log_demux_push_first_frame(GstQTDemux * qtdemux,QtDemuxStream * stream)5901 kpi_log_demux_push_first_frame (GstQTDemux *qtdemux, QtDemuxStream *stream)
5902 {
5903   if (stream->has_push_first_frame) {
5904     return;
5905   }
5906 
5907   if (stream->subtype == FOURCC_vide && stream->on_keyframe) {
5908     stream->has_push_first_frame = TRUE;
5909     GST_WARNING_OBJECT(qtdemux, "KPI-TRACE: FIRST-VIDEO-FRAME demux push first video keyframe");
5910   } else if (stream->subtype == FOURCC_soun) {
5911     stream->has_push_first_frame = TRUE;
5912     GST_WARNING_OBJECT(qtdemux, "KPI-TRACE: demux push first audio frame");
5913   }
5914 }
5915 #endif
5916 
5917 static GstFlowReturn
gst_qtdemux_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5918 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5919     GstBuffer * buf)
5920 {
5921   GstFlowReturn ret = GST_FLOW_OK;
5922   GstClockTime pts, duration;
5923 
5924   if (stream->need_clip)
5925     buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5926 
5927   if (G_UNLIKELY (buf == NULL))
5928     goto exit;
5929 
5930   if (G_UNLIKELY (stream->discont)) {
5931     GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5932     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5933     stream->discont = FALSE;
5934   } else {
5935     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5936   }
5937 
5938   GST_LOG_OBJECT (qtdemux,
5939       "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5940       ", duration %" GST_TIME_FORMAT " on pad %s",
5941       GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5942       GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5943       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5944 
5945   if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5946     GstStructure *crypto_info;
5947     QtDemuxAavdEncryptionInfo *info =
5948         (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5949 
5950     crypto_info = gst_structure_copy (info->default_properties);
5951     if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5952       GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5953   }
5954 
5955   if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5956           || stream->protection_scheme_type == FOURCC_cbcs)) {
5957     GstStructure *crypto_info;
5958     QtDemuxCencSampleSetInfo *info =
5959         (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5960     gint index;
5961     GstEvent *event;
5962 
5963     while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5964       GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5965           GST_PTR_FORMAT, event);
5966       gst_pad_push_event (stream->pad, event);
5967     }
5968 
5969     if (info->crypto_info == NULL) {
5970       if (stream->protection_scheme_type == FOURCC_cbcs) {
5971         crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5972         if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5973           GST_ERROR_OBJECT (qtdemux,
5974               "failed to attach cbcs metadata to buffer");
5975           qtdemux_gst_structure_free (crypto_info);
5976         } else {
5977           GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5978         }
5979       } else {
5980         GST_DEBUG_OBJECT (qtdemux,
5981             "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5982       }
5983     } else {
5984       /* The end of the crypto_info array matches our n_samples position,
5985        * so count backward from there */
5986       index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5987       if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5988         /* steal structure from array */
5989         crypto_info = g_ptr_array_index (info->crypto_info, index);
5990         g_ptr_array_index (info->crypto_info, index) = NULL;
5991         GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5992             info->crypto_info->len);
5993         if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5994           GST_ERROR_OBJECT (qtdemux,
5995               "failed to attach cenc metadata to buffer");
5996       } else {
5997         GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5998             index, stream->sample_index);
5999       }
6000     }
6001   }
6002 
6003   if (stream->alignment > 1)
6004     buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6005 
6006   pts = GST_BUFFER_PTS (buf);
6007   duration = GST_BUFFER_DURATION (buf);
6008 
6009 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: add log for kpi
6010   kpi_log_demux_push_first_frame (qtdemux, stream);
6011 #endif
6012 #ifdef OHOS_OPT_PERFORMANCE
6013 // ohos.opt.performance.0005
6014 // add trace
6015   {
6016     GstStartTrace("Qtdemux:pad_push");
6017     ret = gst_pad_push (stream->pad, buf);
6018     GstFinishTrace();
6019   }
6020 #else
6021   ret = gst_pad_push (stream->pad, buf);
6022 #endif
6023 
6024   if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6025     /* mark position in stream, we'll need this to know when to send GAP event */
6026     stream->segment.position = pts + duration;
6027   }
6028 
6029 exit:
6030 
6031   return ret;
6032 }
6033 
6034 static GstFlowReturn
gst_qtdemux_split_and_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)6035 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6036     GstBuffer * buf)
6037 {
6038   GstFlowReturn ret = GST_FLOW_OK;
6039 
6040   if (stream->subtype == FOURCC_clcp
6041       && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6042     GstMapInfo map;
6043     guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6044     guint n_triplets, i;
6045     guint field1_off = 0, field2_off = 0;
6046 
6047     /* We have to split CEA608 buffers so that each outgoing buffer contains
6048      * one byte pair per field according to the framerate of the video track.
6049      *
6050      * If there is only a single byte pair per field we don't have to do
6051      * anything
6052      */
6053 
6054     gst_buffer_map (buf, &map, GST_MAP_READ);
6055 
6056     n_triplets = map.size / 3;
6057     for (i = 0; i < n_triplets; i++) {
6058       if (map.data[3 * i] & 0x80)
6059         n_field1++;
6060       else
6061         n_field2++;
6062     }
6063 
6064     g_assert (n_field1 || n_field2);
6065 
6066     /* If there's more than 1 frame we have to split, otherwise we can just
6067      * pass through */
6068     if (n_field1 > 1 || n_field2 > 1) {
6069       n_output_buffers =
6070           gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6071           CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6072 
6073       for (i = 0; i < n_output_buffers; i++) {
6074         GstBuffer *outbuf =
6075             gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6076         GstMapInfo outmap;
6077         guint8 *outptr;
6078 
6079         gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6080         outptr = outmap.data;
6081 
6082         if (n_field1) {
6083           gboolean found = FALSE;
6084 
6085           while (map.data + field1_off < map.data + map.size) {
6086             if (map.data[field1_off] & 0x80) {
6087               memcpy (outptr, &map.data[field1_off], 3);
6088               field1_off += 3;
6089               found = TRUE;
6090               break;
6091             }
6092             field1_off += 3;
6093           }
6094 
6095           if (!found) {
6096             const guint8 empty[] = { 0x80, 0x80, 0x80 };
6097 
6098             memcpy (outptr, empty, 3);
6099           }
6100 
6101           outptr += 3;
6102         }
6103 
6104         if (n_field2) {
6105           gboolean found = FALSE;
6106 
6107           while (map.data + field2_off < map.data + map.size) {
6108             if ((map.data[field2_off] & 0x80) == 0) {
6109               memcpy (outptr, &map.data[field2_off], 3);
6110               field2_off += 3;
6111               found = TRUE;
6112               break;
6113             }
6114             field2_off += 3;
6115           }
6116 
6117           if (!found) {
6118             const guint8 empty[] = { 0x00, 0x80, 0x80 };
6119 
6120             memcpy (outptr, empty, 3);
6121           }
6122 
6123           outptr += 3;
6124         }
6125 
6126         gst_buffer_unmap (outbuf, &outmap);
6127 
6128         GST_BUFFER_PTS (outbuf) =
6129             GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6130             GST_SECOND * CUR_STREAM (stream)->fps_d,
6131             CUR_STREAM (stream)->fps_n);
6132         GST_BUFFER_DURATION (outbuf) =
6133             gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6134             CUR_STREAM (stream)->fps_n);
6135         GST_BUFFER_OFFSET (outbuf) = -1;
6136         GST_BUFFER_OFFSET_END (outbuf) = -1;
6137 
6138         ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6139 
6140         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6141           break;
6142       }
6143       gst_buffer_unmap (buf, &map);
6144       gst_buffer_unref (buf);
6145     } else {
6146       gst_buffer_unmap (buf, &map);
6147       ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6148     }
6149   } else {
6150     ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6151   }
6152 
6153   return ret;
6154 }
6155 
6156 /* Sets a buffer's attributes properly and pushes it downstream.
6157  * Also checks for additional actions and custom processing that may
6158  * need to be done first.
6159  */
6160 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)6161 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6162     QtDemuxStream * stream, GstBuffer * buf,
6163     GstClockTime dts, GstClockTime pts, GstClockTime duration,
6164     gboolean keyframe, GstClockTime position, guint64 byte_position)
6165 {
6166   GstFlowReturn ret = GST_FLOW_OK;
6167 
6168   /* offset the timestamps according to the edit list */
6169 
6170   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6171     gchar *url;
6172     GstMapInfo map;
6173 
6174     gst_buffer_map (buf, &map, GST_MAP_READ);
6175     url = g_strndup ((gchar *) map.data, map.size);
6176     gst_buffer_unmap (buf, &map);
6177     if (url != NULL && strlen (url) != 0) {
6178       /* we have RTSP redirect now */
6179       g_free (qtdemux->redirect_location);
6180       qtdemux->redirect_location = g_strdup (url);
6181       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6182           gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6183               gst_structure_new ("redirect",
6184                   "new-location", G_TYPE_STRING, url, NULL)));
6185     } else {
6186       GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6187           "posting");
6188     }
6189     g_free (url);
6190   }
6191 
6192   /* position reporting */
6193   if (qtdemux->segment.rate >= 0) {
6194     qtdemux->segment.position = position;
6195     gst_qtdemux_sync_streams (qtdemux);
6196   }
6197 
6198   if (G_UNLIKELY (!stream->pad)) {
6199     GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6200     gst_buffer_unref (buf);
6201     goto exit;
6202   }
6203 
6204   /* send out pending buffers */
6205   while (stream->buffers) {
6206     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6207 
6208     if (G_UNLIKELY (stream->discont)) {
6209       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6210       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6211       stream->discont = FALSE;
6212     } else {
6213       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6214     }
6215 
6216     if (stream->alignment > 1)
6217       buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6218 #ifdef OHOS_OPT_PERFORMANCE
6219 // ohos.opt.performance.0005
6220 // add trace
6221   {
6222     GstStartTrace("Qtdemux:pad_push");
6223     gst_pad_push (stream->pad, buffer);
6224     GstFinishTrace();
6225   }
6226 #else
6227     gst_pad_push (stream->pad, buffer);
6228 #endif
6229 
6230     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6231   }
6232 
6233   /* we're going to modify the metadata */
6234   buf = gst_buffer_make_writable (buf);
6235 
6236   GST_BUFFER_DTS (buf) = dts;
6237   GST_BUFFER_PTS (buf) = pts;
6238   GST_BUFFER_DURATION (buf) = duration;
6239   GST_BUFFER_OFFSET (buf) = -1;
6240   GST_BUFFER_OFFSET_END (buf) = -1;
6241 
6242   if (G_UNLIKELY (stream->process_func))
6243     buf = stream->process_func (qtdemux, stream, buf);
6244 
6245   if (!buf) {
6246     goto exit;
6247   }
6248 
6249   if (!keyframe) {
6250     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6251     stream->on_keyframe = FALSE;
6252   } else {
6253     stream->on_keyframe = TRUE;
6254   }
6255 
6256   if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6257     gst_buffer_append_memory (buf,
6258         gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6259 
6260   if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6261     gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6262   }
6263 #if 0
6264   if (G_UNLIKELY (qtdemux->element_index)) {
6265     GstClockTime stream_time;
6266 
6267     stream_time =
6268         gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6269         timestamp);
6270     if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6271       GST_LOG_OBJECT (qtdemux,
6272           "adding association %" GST_TIME_FORMAT "-> %"
6273           G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6274       gst_index_add_association (qtdemux->element_index,
6275           qtdemux->index_id,
6276           keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6277           GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6278           GST_FORMAT_BYTES, byte_position, NULL);
6279     }
6280   }
6281 #endif
6282 
6283 #ifdef OHOS_OPT_PERFORMANCE
6284 // ohos.opt.performance.0005
6285 // add trace
6286   {
6287     GstStartTrace("Qtdemux:split_push");
6288     ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6289     GstFinishTrace();
6290   }
6291 #else
6292   ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6293 #endif
6294 
6295 exit:
6296   return ret;
6297 }
6298 
6299 static const QtDemuxRandomAccessEntry *
gst_qtdemux_stream_seek_fragment(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime pos,gboolean after)6300 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6301     GstClockTime pos, gboolean after)
6302 {
6303   QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6304   guint n_entries = stream->n_ra_entries;
6305   guint i;
6306 
6307   /* we assume the table is sorted */
6308   for (i = 0; i < n_entries; ++i) {
6309     if (entries[i].ts > pos)
6310       break;
6311   }
6312 
6313   /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6314    * probably okay to assume that the index lists the very first fragment */
6315   if (i == 0)
6316     return &entries[0];
6317 
6318   if (after)
6319     return &entries[i];
6320   else
6321     return &entries[i - 1];
6322 }
6323 
6324 static gboolean
gst_qtdemux_do_fragmented_seek(GstQTDemux * qtdemux)6325 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6326 {
6327   const QtDemuxRandomAccessEntry *best_entry = NULL;
6328   gint i;
6329 
6330   GST_OBJECT_LOCK (qtdemux);
6331 
6332   g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6333 
6334   /* first see if we can determine where to go to using mfra,
6335    * before we start clearing things */
6336   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6337     const QtDemuxRandomAccessEntry *entry;
6338     QtDemuxStream *stream;
6339     gboolean is_audio_or_video;
6340 
6341     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6342 
6343     if (stream->ra_entries == NULL)
6344       continue;
6345 
6346     if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6347       is_audio_or_video = TRUE;
6348     else
6349       is_audio_or_video = FALSE;
6350 
6351     entry =
6352         gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6353         stream->time_position, !is_audio_or_video);
6354 
6355     GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6356         "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6357 
6358     stream->pending_seek = entry;
6359 
6360     /* decide position to jump to just based on audio/video tracks, not subs */
6361     if (!is_audio_or_video)
6362       continue;
6363 
6364     if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6365       best_entry = entry;
6366   }
6367 
6368   /* no luck, will handle seek otherwise */
6369   if (best_entry == NULL) {
6370     GST_OBJECT_UNLOCK (qtdemux);
6371     return FALSE;
6372   }
6373 
6374   /* ok, now we can prepare for processing as of located moof */
6375   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6376     QtDemuxStream *stream;
6377 
6378     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6379 
6380     g_free (stream->samples);
6381     stream->samples = NULL;
6382     stream->n_samples = 0;
6383     stream->stbl_index = -1;    /* no samples have yet been parsed */
6384     stream->sample_index = -1;
6385 
6386     if (stream->protection_scheme_info) {
6387       /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6388       if (stream->protection_scheme_type == FOURCC_cenc
6389           || stream->protection_scheme_type == FOURCC_cbcs) {
6390         QtDemuxCencSampleSetInfo *info =
6391             (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6392         if (info->crypto_info) {
6393           g_ptr_array_free (info->crypto_info, TRUE);
6394           info->crypto_info = NULL;
6395         }
6396       }
6397     }
6398   }
6399 
6400   GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6401       "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6402       GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6403       best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6404 
6405   qtdemux->moof_offset = best_entry->moof_offset;
6406 
6407   qtdemux_add_fragmented_samples (qtdemux);
6408 
6409   GST_OBJECT_UNLOCK (qtdemux);
6410   return TRUE;
6411 }
6412 
6413 static GstFlowReturn
gst_qtdemux_loop_state_movie(GstQTDemux * qtdemux)6414 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6415 {
6416   GstFlowReturn ret = GST_FLOW_OK;
6417   GstBuffer *buf = NULL;
6418   QtDemuxStream *stream, *target_stream = NULL;
6419   GstClockTime min_time;
6420   guint64 offset = 0;
6421   GstClockTime dts = GST_CLOCK_TIME_NONE;
6422   GstClockTime pts = GST_CLOCK_TIME_NONE;
6423   GstClockTime duration = 0;
6424   gboolean keyframe = FALSE;
6425   guint sample_size = 0;
6426   guint num_samples = 1;
6427   gboolean empty = 0;
6428   guint size;
6429   gint i;
6430 
6431   if (qtdemux->fragmented_seek_pending) {
6432     GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6433     if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6434       GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6435       qtdemux->fragmented_seek_pending = FALSE;
6436     } else {
6437       GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6438     }
6439   }
6440 
6441   /* Figure out the next stream sample to output, min_time is expressed in
6442    * global time and runs over the edit list segments. */
6443   min_time = G_MAXUINT64;
6444   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6445     GstClockTime position;
6446 
6447     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6448     position = stream->time_position;
6449 
6450     if (!GST_CLOCK_TIME_IS_VALID (position))
6451       continue;
6452 
6453     if (stream->segment_index != -1) {
6454       QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6455       position += segment->media_start;
6456     }
6457 
6458     /* position of -1 is EOS */
6459     if (position < min_time) {
6460       min_time = position;
6461       target_stream = stream;
6462     }
6463   }
6464   /* all are EOS */
6465   if (G_UNLIKELY (target_stream == NULL)) {
6466     GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6467     goto eos;
6468   }
6469 
6470   /* check for segment end */
6471   if (G_UNLIKELY (qtdemux->segment.stop != -1
6472           && qtdemux->segment.rate >= 0
6473           && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6474     GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6475     target_stream->time_position = GST_CLOCK_TIME_NONE;
6476     goto eos_stream;
6477   }
6478 
6479   /* gap events for subtitle streams */
6480   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6481     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6482     if (stream->pad) {
6483       GstClockTime gap_threshold;
6484 
6485       /* Only send gap events on non-subtitle streams if lagging way behind. */
6486       if (stream->subtype == FOURCC_subp
6487           || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6488           stream->subtype == FOURCC_wvtt)
6489         gap_threshold = 1 * GST_SECOND;
6490       else
6491         gap_threshold = 3 * GST_SECOND;
6492 
6493       /* send gap events until the stream catches up */
6494       /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6495       while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6496           GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6497           stream->segment.position + gap_threshold < min_time) {
6498         GstEvent *gap =
6499             gst_event_new_gap (stream->segment.position, gap_threshold);
6500         gst_pad_push_event (stream->pad, gap);
6501         stream->segment.position += gap_threshold;
6502       }
6503     }
6504   }
6505 
6506   stream = target_stream;
6507   /* fetch info for the current sample of this stream */
6508   if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6509               &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6510     goto eos_stream;
6511 
6512   gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6513   if (stream->new_caps) {
6514     gst_qtdemux_configure_stream (qtdemux, stream);
6515     qtdemux_do_allocation (stream, qtdemux);
6516   }
6517 
6518   /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6519   if (G_UNLIKELY (qtdemux->segment.
6520           flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6521     if (stream->subtype == FOURCC_vide) {
6522       if (!keyframe) {
6523         GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6524             stream->track_id);
6525         goto next;
6526       } else if (qtdemux->trickmode_interval > 0) {
6527         GstClockTimeDiff interval;
6528 
6529         if (qtdemux->segment.rate > 0)
6530           interval = stream->time_position - stream->last_keyframe_dts;
6531         else
6532           interval = stream->last_keyframe_dts - stream->time_position;
6533 
6534         if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6535             && interval < qtdemux->trickmode_interval) {
6536           GST_LOG_OBJECT (qtdemux,
6537               "Skipping keyframe within interval on track-id %u",
6538               stream->track_id);
6539           goto next;
6540         } else {
6541           stream->last_keyframe_dts = stream->time_position;
6542         }
6543       }
6544     }
6545   }
6546 
6547   GST_DEBUG_OBJECT (qtdemux,
6548       "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6549       ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6550       ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6551       sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6552       GST_TIME_ARGS (duration));
6553 
6554   if (G_UNLIKELY (empty)) {
6555     /* empty segment, push a gap if there's a second or more
6556      * difference and move to the next one */
6557     if ((pts + duration - stream->segment.position) >= GST_SECOND)
6558       gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6559     stream->segment.position = pts + duration;
6560     goto next;
6561   }
6562 
6563   /* hmm, empty sample, skip and move to next sample */
6564   if (G_UNLIKELY (sample_size <= 0))
6565     goto next;
6566 
6567   /* last pushed sample was out of boundary, goto next sample */
6568   if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6569     goto next;
6570 
6571   if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6572     GST_DEBUG_OBJECT (qtdemux,
6573         "size %d larger than stream max_buffer_size %d, trimming",
6574         sample_size, stream->max_buffer_size);
6575     size =
6576         MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6577   } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6578       && sample_size < stream->min_buffer_size) {
6579     guint start_sample_index = stream->sample_index;
6580     guint accumulated_size = sample_size;
6581     guint64 expected_next_offset = offset + sample_size;
6582 
6583     GST_DEBUG_OBJECT (qtdemux,
6584         "size %d smaller than stream min_buffer_size %d, combining with the next",
6585         sample_size, stream->min_buffer_size);
6586 
6587     while (stream->sample_index < stream->to_sample
6588         && stream->sample_index + 1 < stream->n_samples) {
6589       const QtDemuxSample *next_sample;
6590 
6591       /* Increment temporarily */
6592       stream->sample_index++;
6593 
6594       /* Failed to parse sample so let's go back to the previous one that was
6595        * still successful */
6596       if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6597         stream->sample_index--;
6598         break;
6599       }
6600 
6601       next_sample = &stream->samples[stream->sample_index];
6602 
6603       /* Not contiguous with the previous sample so let's go back to the
6604        * previous one that was still successful */
6605       if (next_sample->offset != expected_next_offset) {
6606         stream->sample_index--;
6607         break;
6608       }
6609 
6610       accumulated_size += next_sample->size;
6611       expected_next_offset += next_sample->size;
6612       if (accumulated_size >= stream->min_buffer_size)
6613         break;
6614     }
6615 
6616     num_samples = stream->sample_index + 1 - start_sample_index;
6617     stream->sample_index = start_sample_index;
6618     GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6619         num_samples, accumulated_size);
6620     size = accumulated_size;
6621   } else {
6622     size = sample_size;
6623   }
6624 
6625   if (qtdemux->cenc_aux_info_offset > 0) {
6626     GstMapInfo map;
6627     GstByteReader br;
6628     GstBuffer *aux_info = NULL;
6629 
6630     /* pull the data stored before the sample */
6631     ret =
6632         gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6633         offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6634     if (G_UNLIKELY (ret != GST_FLOW_OK))
6635       goto beach;
6636     gst_buffer_map (aux_info, &map, GST_MAP_READ);
6637     GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6638     gst_byte_reader_init (&br, map.data + 8, map.size);
6639     if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6640             qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6641       GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6642       gst_buffer_unmap (aux_info, &map);
6643       gst_buffer_unref (aux_info);
6644       ret = GST_FLOW_ERROR;
6645       goto beach;
6646     }
6647     gst_buffer_unmap (aux_info, &map);
6648     gst_buffer_unref (aux_info);
6649   }
6650 
6651   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6652       offset);
6653 
6654   if (stream->use_allocator) {
6655     /* if we have a per-stream allocator, use it */
6656     buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6657   }
6658 
6659   ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6660       size, &buf);
6661   if (G_UNLIKELY (ret != GST_FLOW_OK))
6662     goto beach;
6663 
6664   /* Update for both splitting and combining of samples */
6665   if (size != sample_size) {
6666     pts += gst_util_uint64_scale_int (GST_SECOND,
6667         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6668         stream->timescale);
6669     dts +=
6670         gst_util_uint64_scale_int (GST_SECOND,
6671         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6672         stream->timescale);
6673     duration =
6674         gst_util_uint64_scale_int (GST_SECOND,
6675         size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6676   }
6677 
6678   ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6679       dts, pts, duration, keyframe, min_time, offset);
6680 
6681   if (size < sample_size) {
6682     QtDemuxSample *sample = &stream->samples[stream->sample_index];
6683     QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6684 
6685     GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6686         sample->timestamp +
6687         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6688     if (time_position >= segment->media_start) {
6689       /* inside the segment, update time_position, looks very familiar to
6690        * GStreamer segments, doesn't it? */
6691       stream->time_position = (time_position - segment->media_start) +
6692           segment->time;
6693     } else {
6694       /* not yet in segment, time does not yet increment. This means
6695        * that we are still prerolling keyframes to the decoder so it can
6696        * decode the first sample of the segment. */
6697       stream->time_position = segment->time;
6698     }
6699   } else if (size > sample_size) {
6700     /* Increase to the last sample we already pulled so that advancing
6701      * below brings us to the next sample we need to pull */
6702     stream->sample_index += num_samples - 1;
6703   }
6704 
6705   /* combine flows */
6706   GST_OBJECT_LOCK (qtdemux);
6707   ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6708   GST_OBJECT_UNLOCK (qtdemux);
6709   /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6710    * we have no more data for the pad to push */
6711   if (ret == GST_FLOW_EOS)
6712     ret = GST_FLOW_OK;
6713 
6714   stream->offset_in_sample += size;
6715   if (stream->offset_in_sample >= sample_size) {
6716     gst_qtdemux_advance_sample (qtdemux, stream);
6717   }
6718   goto beach;
6719 
6720 next:
6721   gst_qtdemux_advance_sample (qtdemux, stream);
6722 
6723 beach:
6724   return ret;
6725 
6726   /* special cases */
6727 eos:
6728   {
6729     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6730     ret = GST_FLOW_EOS;
6731     goto beach;
6732   }
6733 eos_stream:
6734   {
6735     GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6736     /* EOS will be raised if all are EOS */
6737     ret = GST_FLOW_OK;
6738     goto beach;
6739   }
6740 }
6741 
6742 static void
gst_qtdemux_loop(GstPad * pad)6743 gst_qtdemux_loop (GstPad * pad)
6744 {
6745   GstQTDemux *qtdemux;
6746   guint64 cur_offset;
6747   GstFlowReturn ret;
6748 
6749   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6750 
6751   cur_offset = qtdemux->offset;
6752   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6753       cur_offset, qt_demux_state_string (qtdemux->state));
6754 
6755   switch (qtdemux->state) {
6756     case QTDEMUX_STATE_INITIAL:
6757     case QTDEMUX_STATE_HEADER:
6758 #ifdef OHOS_OPT_PERFORMANCE
6759 // ohos.opt.performance.0005
6760 // add trace
6761       {
6762         GstStartTrace("Qtdemux:state_header");
6763         ret = gst_qtdemux_loop_state_header (qtdemux);
6764         GstFinishTrace();
6765       }
6766 #else
6767       ret = gst_qtdemux_loop_state_header (qtdemux);
6768 #endif
6769       break;
6770     case QTDEMUX_STATE_MOVIE:
6771       ret = gst_qtdemux_loop_state_movie (qtdemux);
6772       if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6773         ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6774       }
6775       break;
6776     default:
6777       /* ouch */
6778       goto invalid_state;
6779   }
6780 
6781   /* if something went wrong, pause */
6782   if (ret != GST_FLOW_OK)
6783     goto pause;
6784 
6785 done:
6786   gst_object_unref (qtdemux);
6787   return;
6788 
6789   /* ERRORS */
6790 invalid_state:
6791   {
6792     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6793         (NULL), ("streaming stopped, invalid state"));
6794     gst_pad_pause_task (pad);
6795     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6796     goto done;
6797   }
6798 pause:
6799   {
6800     const gchar *reason = gst_flow_get_name (ret);
6801 
6802     GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6803 
6804     gst_pad_pause_task (pad);
6805 
6806     /* fatal errors need special actions */
6807     /* check EOS */
6808     if (ret == GST_FLOW_EOS) {
6809       if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6810         /* we have no streams, post an error */
6811         gst_qtdemux_post_no_playable_stream_error (qtdemux);
6812       }
6813       if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6814         gint64 stop;
6815 
6816         if ((stop = qtdemux->segment.stop) == -1)
6817           stop = qtdemux->segment.duration;
6818 
6819         if (qtdemux->segment.rate >= 0) {
6820           GstMessage *message;
6821           GstEvent *event;
6822 
6823           GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6824           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6825               GST_FORMAT_TIME, stop);
6826           event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6827           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6828             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6829             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6830           }
6831           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6832           gst_qtdemux_push_event (qtdemux, event);
6833         } else {
6834           GstMessage *message;
6835           GstEvent *event;
6836 
6837           /*  For Reverse Playback */
6838           GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6839           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6840               GST_FORMAT_TIME, qtdemux->segment.start);
6841           event = gst_event_new_segment_done (GST_FORMAT_TIME,
6842               qtdemux->segment.start);
6843           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6844             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6845             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6846           }
6847           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6848           gst_qtdemux_push_event (qtdemux, event);
6849         }
6850       } else {
6851         GstEvent *event;
6852 
6853         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6854         event = gst_event_new_eos ();
6855         if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6856           gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6857         gst_qtdemux_push_event (qtdemux, event);
6858       }
6859     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6860       GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6861       gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6862     }
6863     goto done;
6864   }
6865 }
6866 
6867 /*
6868  * has_next_entry
6869  *
6870  * Returns if there are samples to be played.
6871  */
6872 static gboolean
has_next_entry(GstQTDemux * demux)6873 has_next_entry (GstQTDemux * demux)
6874 {
6875   QtDemuxStream *stream;
6876   gint i;
6877 
6878   GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6879 
6880   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6881     stream = QTDEMUX_NTH_STREAM (demux, i);
6882 
6883     if (stream->sample_index == -1) {
6884       stream->sample_index = 0;
6885       stream->offset_in_sample = 0;
6886     }
6887 
6888     if (stream->sample_index >= stream->n_samples) {
6889       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6890       continue;
6891     }
6892     GST_DEBUG_OBJECT (demux, "Found a sample");
6893     return TRUE;
6894   }
6895 
6896   GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6897   return FALSE;
6898 }
6899 
6900 /*
6901  * next_entry_size
6902  *
6903  * Returns the size of the first entry at the current offset.
6904  * If -1, there are none (which means EOS or empty file).
6905  */
6906 static guint64
next_entry_size(GstQTDemux * demux)6907 next_entry_size (GstQTDemux * demux)
6908 {
6909   QtDemuxStream *stream, *target_stream = NULL;
6910   guint64 smalloffs = (guint64) - 1;
6911   QtDemuxSample *sample;
6912   gint i;
6913 
6914   GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6915       demux->offset);
6916 
6917   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6918     stream = QTDEMUX_NTH_STREAM (demux, i);
6919 
6920     if (stream->sample_index == -1) {
6921       stream->sample_index = 0;
6922       stream->offset_in_sample = 0;
6923     }
6924 
6925     if (stream->sample_index >= stream->n_samples) {
6926       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6927       continue;
6928     }
6929 
6930     if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6931       GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6932           stream->sample_index);
6933       return -1;
6934     }
6935 
6936     sample = &stream->samples[stream->sample_index];
6937 
6938     GST_LOG_OBJECT (demux,
6939         "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6940         " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6941         stream->sample_index, sample->offset, sample->size);
6942 
6943     if (((smalloffs == -1)
6944             || (sample->offset < smalloffs)) && (sample->size)) {
6945       smalloffs = sample->offset;
6946       target_stream = stream;
6947     }
6948   }
6949 
6950   if (!target_stream)
6951     return -1;
6952 
6953   GST_LOG_OBJECT (demux,
6954       "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6955       G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6956 
6957   stream = target_stream;
6958   sample = &stream->samples[stream->sample_index];
6959 
6960   if (sample->offset >= demux->offset) {
6961     demux->todrop = sample->offset - demux->offset;
6962     return sample->size + demux->todrop;
6963   }
6964 
6965   GST_DEBUG_OBJECT (demux,
6966       "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6967   return -1;
6968 }
6969 
6970 static void
gst_qtdemux_post_progress(GstQTDemux * demux,gint num,gint denom)6971 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6972 {
6973   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6974 
6975   gst_element_post_message (GST_ELEMENT_CAST (demux),
6976       gst_message_new_element (GST_OBJECT_CAST (demux),
6977           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6978 }
6979 
6980 static gboolean
qtdemux_seek_offset(GstQTDemux * demux,guint64 offset)6981 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6982 {
6983   GstEvent *event;
6984   gboolean res = 0;
6985 
6986   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6987 
6988   event =
6989       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6990       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6991       GST_SEEK_TYPE_NONE, -1);
6992 
6993   /* store seqnum to drop flush events, they don't need to reach downstream */
6994   demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6995   res = gst_pad_push_event (demux->sinkpad, event);
6996   demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6997 
6998   return res;
6999 }
7000 
7001 /* check for seekable upstream, above and beyond a mere query */
7002 static void
gst_qtdemux_check_seekability(GstQTDemux * demux)7003 gst_qtdemux_check_seekability (GstQTDemux * demux)
7004 {
7005   GstQuery *query;
7006   gboolean seekable = FALSE;
7007   gint64 start = -1, stop = -1;
7008 
7009   if (demux->upstream_size)
7010     return;
7011 
7012   if (demux->upstream_format_is_time)
7013     return;
7014 
7015   query = gst_query_new_seeking (GST_FORMAT_BYTES);
7016   if (!gst_pad_peer_query (demux->sinkpad, query)) {
7017     GST_DEBUG_OBJECT (demux, "seeking query failed");
7018     goto done;
7019   }
7020 
7021   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
7022 
7023   /* try harder to query upstream size if we didn't get it the first time */
7024   if (seekable && stop == -1) {
7025     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
7026     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
7027   }
7028 
7029   /* if upstream doesn't know the size, it's likely that it's not seekable in
7030    * practice even if it technically may be seekable */
7031   if (seekable && (start != 0 || stop <= start)) {
7032     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
7033     seekable = FALSE;
7034   }
7035 
7036 done:
7037   gst_query_unref (query);
7038 
7039   GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
7040       G_GUINT64_FORMAT ")", seekable, start, stop);
7041   demux->upstream_seekable = seekable;
7042   demux->upstream_size = seekable ? stop : -1;
7043 }
7044 
7045 static void
gst_qtdemux_drop_data(GstQTDemux * demux,gint bytes)7046 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7047 {
7048   g_return_if_fail (bytes <= demux->todrop);
7049 
7050   GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7051   gst_adapter_flush (demux->adapter, bytes);
7052   demux->neededbytes -= bytes;
7053   demux->offset += bytes;
7054   demux->todrop -= bytes;
7055 }
7056 
7057 /* PUSH-MODE only: Send a segment, if not done already. */
7058 static void
gst_qtdemux_check_send_pending_segment(GstQTDemux * demux)7059 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7060 {
7061   if (G_UNLIKELY (demux->need_segment)) {
7062     gint i;
7063 
7064     if (!demux->upstream_format_is_time) {
7065       gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7066     } else {
7067       GstEvent *segment_event;
7068       segment_event = gst_event_new_segment (&demux->segment);
7069       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7070         gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7071       gst_qtdemux_push_event (demux, segment_event);
7072     }
7073 
7074     demux->need_segment = FALSE;
7075 
7076     /* clear to send tags on all streams */
7077     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7078       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7079       gst_qtdemux_push_tags (demux, stream);
7080       if (CUR_STREAM (stream)->sparse) {
7081         GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7082         gst_pad_push_event (stream->pad,
7083             gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7084       }
7085     }
7086   }
7087 }
7088 
7089 /* Used for push mode only. */
7090 static void
gst_qtdemux_send_gap_for_segment(GstQTDemux * demux,QtDemuxStream * stream,gint segment_index,GstClockTime pos)7091 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7092     QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7093 {
7094   GstClockTime ts, dur;
7095 
7096   ts = pos;
7097   dur =
7098       stream->segments[segment_index].duration - (pos -
7099       stream->segments[segment_index].time);
7100   stream->time_position += dur;
7101 
7102   /* Only gaps with a duration of at least one second are propagated.
7103    * Same workaround as in pull mode.
7104    * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7105   if (dur >= GST_SECOND) {
7106     GstEvent *gap;
7107     gap = gst_event_new_gap (ts, dur);
7108 
7109     GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7110         "segment: %" GST_PTR_FORMAT, gap);
7111     gst_pad_push_event (stream->pad, gap);
7112   }
7113 }
7114 
7115 static GstFlowReturn
gst_qtdemux_chain(GstPad * sinkpad,GstObject * parent,GstBuffer * inbuf)7116 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7117 {
7118   GstQTDemux *demux;
7119 
7120   demux = GST_QTDEMUX (parent);
7121 
7122   GST_DEBUG_OBJECT (demux,
7123       "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7124       " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7125       G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7126       GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7127       gst_buffer_get_size (inbuf), demux->offset);
7128 
7129   if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7130     gboolean is_gap_input = FALSE;
7131     gint i;
7132 
7133     GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7134 
7135     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7136       QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7137     }
7138 
7139     /* Check if we can land back on our feet in the case where upstream is
7140      * handling the seeking/pushing of samples with gaps in between (like
7141      * in the case of trick-mode DASH for example) */
7142     if (demux->upstream_format_is_time
7143         && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7144       for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7145         guint32 res;
7146         QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7147         GST_LOG_OBJECT (demux,
7148             "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7149             " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7150         res =
7151             gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7152             stream, GST_BUFFER_OFFSET (inbuf));
7153         if (res != -1) {
7154           QtDemuxSample *sample = &stream->samples[res];
7155           GST_LOG_OBJECT (demux,
7156               "Checking if sample %d from track-id %u is valid (offset:%"
7157               G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7158               stream->track_id, sample->offset, sample->size);
7159           if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7160             GST_LOG_OBJECT (demux,
7161                 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7162                 res);
7163             is_gap_input = TRUE;
7164             /* We can go back to standard playback mode */
7165             demux->state = QTDEMUX_STATE_MOVIE;
7166             /* Remember which sample this stream is at */
7167             stream->sample_index = res;
7168             /* Finally update all push-based values to the expected values */
7169             demux->neededbytes = stream->samples[res].size;
7170             demux->offset = GST_BUFFER_OFFSET (inbuf);
7171             demux->mdatleft =
7172                 demux->mdatsize - demux->offset + demux->mdatoffset;
7173             demux->todrop = 0;
7174           }
7175         }
7176       }
7177       if (!is_gap_input) {
7178         GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7179         /* Reset state if it's a real discont */
7180         demux->neededbytes = 16;
7181         demux->state = QTDEMUX_STATE_INITIAL;
7182         demux->offset = GST_BUFFER_OFFSET (inbuf);
7183         gst_adapter_clear (demux->adapter);
7184       }
7185     }
7186     /* Reverse fragmented playback, need to flush all we have before
7187      * consuming a new fragment.
7188      * The samples array have the timestamps calculated by accumulating the
7189      * durations but this won't work for reverse playback of fragments as
7190      * the timestamps of a subsequent fragment should be smaller than the
7191      * previously received one. */
7192     if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7193       gst_qtdemux_process_adapter (demux, TRUE);
7194       g_ptr_array_foreach (demux->active_streams,
7195           (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7196     }
7197   }
7198 
7199   gst_adapter_push (demux->adapter, inbuf);
7200 
7201   GST_DEBUG_OBJECT (demux,
7202       "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7203       demux->neededbytes, gst_adapter_available (demux->adapter));
7204 
7205   return gst_qtdemux_process_adapter (demux, FALSE);
7206 }
7207 
7208 static GstFlowReturn
gst_qtdemux_process_adapter(GstQTDemux * demux,gboolean force)7209 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7210 {
7211   GstFlowReturn ret = GST_FLOW_OK;
7212 
7213   /* we never really mean to buffer that much */
7214   if (demux->neededbytes == -1) {
7215     goto eos;
7216   }
7217 
7218   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7219       (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7220 
7221 #ifndef GST_DISABLE_GST_DEBUG
7222     {
7223       guint64 discont_offset, distance_from_discont;
7224 
7225       discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7226       distance_from_discont =
7227           gst_adapter_distance_from_discont (demux->adapter);
7228 
7229       GST_DEBUG_OBJECT (demux,
7230           "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7231           " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7232           " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7233           demux->offset, discont_offset, distance_from_discont);
7234     }
7235 #endif
7236 
7237     switch (demux->state) {
7238       case QTDEMUX_STATE_INITIAL:{
7239         const guint8 *data;
7240         guint32 fourcc;
7241         guint64 size;
7242 
7243         gst_qtdemux_check_seekability (demux);
7244 
7245         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7246 
7247         /* get fourcc/length, set neededbytes */
7248         extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7249             &size, &fourcc);
7250         gst_adapter_unmap (demux->adapter);
7251         data = NULL;
7252         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7253             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7254         if (size == 0) {
7255           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7256               (_("This file is invalid and cannot be played.")),
7257               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7258                   GST_FOURCC_ARGS (fourcc)));
7259           ret = GST_FLOW_ERROR;
7260           break;
7261         }
7262         if (fourcc == FOURCC_mdat) {
7263           gint next_entry = next_entry_size (demux);
7264           if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7265                   || !demux->fragmented)) {
7266             /* we have the headers, start playback */
7267             demux->state = QTDEMUX_STATE_MOVIE;
7268             demux->neededbytes = next_entry;
7269             demux->mdatleft = size;
7270             demux->mdatsize = demux->mdatleft;
7271           } else {
7272             /* no headers yet, try to get them */
7273             guint bs;
7274             gboolean res;
7275             guint64 old, target;
7276 
7277           buffer_data:
7278             old = demux->offset;
7279             target = old + size;
7280 
7281             /* try to jump over the atom with a seek */
7282             /* only bother if it seems worth doing so,
7283              * and avoids possible upstream/server problems */
7284             if (demux->upstream_seekable &&
7285                 demux->upstream_size > 4 * (1 << 20)) {
7286               res = qtdemux_seek_offset (demux, target);
7287             } else {
7288               GST_DEBUG_OBJECT (demux, "skipping seek");
7289               res = FALSE;
7290             }
7291 
7292             if (res) {
7293               GST_DEBUG_OBJECT (demux, "seek success");
7294               /* remember the offset fo the first mdat so we can seek back to it
7295                * after we have the headers */
7296               if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7297                 demux->first_mdat = old;
7298                 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7299                     demux->first_mdat);
7300               }
7301               /* seek worked, continue reading */
7302               demux->offset = target;
7303               demux->neededbytes = 16;
7304               demux->state = QTDEMUX_STATE_INITIAL;
7305             } else {
7306               /* seek failed, need to buffer */
7307               demux->offset = old;
7308               GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7309               /* there may be multiple mdat (or alike) buffers */
7310               /* sanity check */
7311               if (demux->mdatbuffer)
7312                 bs = gst_buffer_get_size (demux->mdatbuffer);
7313               else
7314                 bs = 0;
7315               if (size + bs > 10 * (1 << 20))
7316                 goto no_moov;
7317               demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7318               demux->neededbytes = size;
7319               if (!demux->mdatbuffer)
7320                 demux->mdatoffset = demux->offset;
7321             }
7322           }
7323         } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7324           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7325               (_("This file is invalid and cannot be played.")),
7326               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7327                   GST_FOURCC_ARGS (fourcc), size));
7328           ret = GST_FLOW_ERROR;
7329           break;
7330         } else {
7331           /* this means we already started buffering and still no moov header,
7332            * let's continue buffering everything till we get moov */
7333           if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7334                   || fourcc == FOURCC_moof))
7335             goto buffer_data;
7336           demux->neededbytes = size;
7337           demux->state = QTDEMUX_STATE_HEADER;
7338         }
7339         break;
7340       }
7341       case QTDEMUX_STATE_HEADER:{
7342         const guint8 *data;
7343         guint32 fourcc;
7344 
7345         GST_DEBUG_OBJECT (demux, "In header");
7346 
7347         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7348 
7349         /* parse the header */
7350         extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7351             &fourcc);
7352         if (fourcc == FOURCC_moov) {
7353           /* in usual fragmented setup we could try to scan for more
7354            * and end up at the the moov (after mdat) again */
7355           if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7356               (!demux->fragmented
7357                   || demux->last_moov_offset == demux->offset)) {
7358             GST_DEBUG_OBJECT (demux,
7359                 "Skipping moov atom as we have (this) one already");
7360           } else {
7361             GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7362 
7363             if (demux->got_moov && demux->fragmented) {
7364               GST_DEBUG_OBJECT (demux,
7365                   "Got a second moov, clean up data from old one");
7366               if (demux->moov_node_compressed) {
7367                 g_node_destroy (demux->moov_node_compressed);
7368                 if (demux->moov_node)
7369                   g_free (demux->moov_node->data);
7370               }
7371               demux->moov_node_compressed = NULL;
7372               if (demux->moov_node)
7373                 g_node_destroy (demux->moov_node);
7374               demux->moov_node = NULL;
7375             }
7376 
7377             demux->last_moov_offset = demux->offset;
7378 
7379             /* Update streams with new moov */
7380             gst_qtdemux_stream_concat (demux,
7381                 demux->old_streams, demux->active_streams);
7382 
7383             qtdemux_parse_moov (demux, data, demux->neededbytes);
7384             qtdemux_node_dump (demux, demux->moov_node);
7385             qtdemux_parse_tree (demux);
7386             qtdemux_prepare_streams (demux);
7387             QTDEMUX_EXPOSE_LOCK (demux);
7388             qtdemux_expose_streams (demux);
7389             QTDEMUX_EXPOSE_UNLOCK (demux);
7390 
7391             demux->got_moov = TRUE;
7392 
7393             gst_qtdemux_check_send_pending_segment (demux);
7394 
7395             if (demux->moov_node_compressed) {
7396               g_node_destroy (demux->moov_node_compressed);
7397               g_free (demux->moov_node->data);
7398             }
7399             demux->moov_node_compressed = NULL;
7400             g_node_destroy (demux->moov_node);
7401             demux->moov_node = NULL;
7402             GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7403           }
7404         } else if (fourcc == FOURCC_moof) {
7405           if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7406             guint64 dist = 0;
7407             GstClockTime prev_pts;
7408             guint64 prev_offset;
7409             guint64 adapter_discont_offset, adapter_discont_dist;
7410 
7411             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7412 
7413             /*
7414              * The timestamp of the moof buffer is relevant as some scenarios
7415              * won't have the initial timestamp in the atoms. Whenever a new
7416              * buffer has started, we get that buffer's PTS and use it as a base
7417              * timestamp for the trun entries.
7418              *
7419              * To keep track of the current buffer timestamp and starting point
7420              * we use gst_adapter_prev_pts that gives us the PTS and the distance
7421              * from the beginning of the buffer, with the distance and demux->offset
7422              * we know if it is still the same buffer or not.
7423              */
7424             prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7425             prev_offset = demux->offset - dist;
7426             if (demux->fragment_start_offset == -1
7427                 || prev_offset > demux->fragment_start_offset) {
7428               demux->fragment_start_offset = prev_offset;
7429               demux->fragment_start = prev_pts;
7430               GST_DEBUG_OBJECT (demux,
7431                   "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7432                   GST_TIME_FORMAT, demux->fragment_start_offset,
7433                   GST_TIME_ARGS (demux->fragment_start));
7434             }
7435 
7436             /* We can't use prev_offset() here because this would require
7437              * upstream to set consistent and correct offsets on all buffers
7438              * since the discont. Nothing ever did that in the past and we
7439              * would break backwards compatibility here then.
7440              * Instead take the offset we had at the last discont and count
7441              * the bytes from there. This works with old code as there would
7442              * be no discont between moov and moof, and also works with
7443              * adaptivedemux which correctly sets offset and will set the
7444              * DISCONT flag accordingly when needed.
7445              *
7446              * We also only do this for upstream TIME segments as otherwise
7447              * there are potential backwards compatibility problems with
7448              * seeking in PUSH mode and upstream providing inconsistent
7449              * timestamps. */
7450             adapter_discont_offset =
7451                 gst_adapter_offset_at_discont (demux->adapter);
7452             adapter_discont_dist =
7453                 gst_adapter_distance_from_discont (demux->adapter);
7454 
7455             GST_DEBUG_OBJECT (demux,
7456                 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7457                 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7458                 demux->offset, adapter_discont_offset, adapter_discont_dist);
7459 
7460             if (demux->upstream_format_is_time) {
7461               demux->moof_offset = adapter_discont_offset;
7462               if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7463                 demux->moof_offset += adapter_discont_dist;
7464               if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7465                 demux->moof_offset = demux->offset;
7466             } else {
7467               demux->moof_offset = demux->offset;
7468             }
7469 
7470             if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7471                     demux->moof_offset, NULL)) {
7472               gst_adapter_unmap (demux->adapter);
7473               ret = GST_FLOW_ERROR;
7474               goto done;
7475             }
7476 
7477             /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7478             if (demux->mss_mode && !demux->exposed) {
7479               QTDEMUX_EXPOSE_LOCK (demux);
7480               qtdemux_expose_streams (demux);
7481               QTDEMUX_EXPOSE_UNLOCK (demux);
7482             }
7483 
7484             gst_qtdemux_check_send_pending_segment (demux);
7485           } else {
7486             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7487           }
7488         } else if (fourcc == FOURCC_ftyp) {
7489           GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7490           qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7491         } else if (fourcc == FOURCC_uuid) {
7492           GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7493           qtdemux_parse_uuid (demux, data, demux->neededbytes);
7494         } else if (fourcc == FOURCC_sidx) {
7495           GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7496           qtdemux_parse_sidx (demux, data, demux->neededbytes);
7497         } else {
7498           switch (fourcc) {
7499             case FOURCC_styp:
7500               /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7501                * FALLTHROUGH */
7502             case FOURCC_skip:
7503             case FOURCC_free:
7504               /* [free] and [skip] are padding atoms */
7505               GST_DEBUG_OBJECT (demux,
7506                   "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7507                   GST_FOURCC_ARGS (fourcc));
7508               break;
7509             default:
7510               GST_WARNING_OBJECT (demux,
7511                   "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7512                   GST_FOURCC_ARGS (fourcc));
7513               /* Let's jump that one and go back to initial state */
7514               break;
7515           }
7516         }
7517         gst_adapter_unmap (demux->adapter);
7518         data = NULL;
7519 
7520         if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7521           gsize remaining_data_size = 0;
7522 
7523           /* the mdat was before the header */
7524           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7525               QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7526           /* restore our adapter/offset view of things with upstream;
7527            * put preceding buffered data ahead of current moov data.
7528            * This should also handle evil mdat, moov, mdat cases and alike */
7529           gst_adapter_flush (demux->adapter, demux->neededbytes);
7530 
7531           /* Store any remaining data after the mdat for later usage */
7532           remaining_data_size = gst_adapter_available (demux->adapter);
7533           if (remaining_data_size > 0) {
7534             g_assert (demux->restoredata_buffer == NULL);
7535             demux->restoredata_buffer =
7536                 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7537             demux->restoredata_offset = demux->offset + demux->neededbytes;
7538             GST_DEBUG_OBJECT (demux,
7539                 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7540                 G_GUINT64_FORMAT, remaining_data_size,
7541                 demux->restoredata_offset);
7542           }
7543 
7544           gst_adapter_push (demux->adapter, demux->mdatbuffer);
7545           demux->mdatbuffer = NULL;
7546           demux->offset = demux->mdatoffset;
7547           demux->neededbytes = next_entry_size (demux);
7548           demux->state = QTDEMUX_STATE_MOVIE;
7549           demux->mdatleft = gst_adapter_available (demux->adapter);
7550           demux->mdatsize = demux->mdatleft;
7551         } else {
7552           GST_DEBUG_OBJECT (demux, "Carrying on normally");
7553           gst_adapter_flush (demux->adapter, demux->neededbytes);
7554 
7555           /* only go back to the mdat if there are samples to play */
7556           if (demux->got_moov && demux->first_mdat != -1
7557               && has_next_entry (demux)) {
7558             gboolean res;
7559 
7560             /* we need to seek back */
7561             res = qtdemux_seek_offset (demux, demux->first_mdat);
7562             if (res) {
7563               demux->offset = demux->first_mdat;
7564             } else {
7565               GST_DEBUG_OBJECT (demux, "Seek back failed");
7566             }
7567           } else {
7568             demux->offset += demux->neededbytes;
7569           }
7570           demux->neededbytes = 16;
7571           demux->state = QTDEMUX_STATE_INITIAL;
7572         }
7573 
7574         break;
7575       }
7576       case QTDEMUX_STATE_BUFFER_MDAT:{
7577         GstBuffer *buf;
7578         guint8 fourcc[4];
7579 
7580         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7581             demux->offset);
7582         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7583         gst_buffer_extract (buf, 0, fourcc, 4);
7584         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7585             GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7586         if (demux->mdatbuffer)
7587           demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7588         else
7589           demux->mdatbuffer = buf;
7590         demux->offset += demux->neededbytes;
7591         demux->neededbytes = 16;
7592         demux->state = QTDEMUX_STATE_INITIAL;
7593         gst_qtdemux_post_progress (demux, 1, 1);
7594 
7595         break;
7596       }
7597       case QTDEMUX_STATE_MOVIE:{
7598         QtDemuxStream *stream = NULL;
7599         QtDemuxSample *sample;
7600         GstClockTime dts, pts, duration;
7601         gboolean keyframe;
7602         gint i;
7603 
7604         GST_DEBUG_OBJECT (demux,
7605             "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7606 
7607         if (demux->fragmented) {
7608           GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7609               demux->mdatleft);
7610           if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7611             /* if needed data starts within this atom,
7612              * then it should not exceed this atom */
7613             if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7614               GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7615                   (_("This file is invalid and cannot be played.")),
7616                   ("sample data crosses atom boundary"));
7617               ret = GST_FLOW_ERROR;
7618               break;
7619             }
7620             demux->mdatleft -= demux->neededbytes;
7621           } else {
7622             GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7623             /* so we are dropping more than left in this atom */
7624             gst_qtdemux_drop_data (demux, demux->mdatleft);
7625             demux->mdatleft = 0;
7626 
7627             /* need to resume atom parsing so we do not miss any other pieces */
7628             demux->state = QTDEMUX_STATE_INITIAL;
7629             demux->neededbytes = 16;
7630 
7631             /* check if there was any stored post mdat data from previous buffers */
7632             if (demux->restoredata_buffer) {
7633               g_assert (gst_adapter_available (demux->adapter) == 0);
7634 
7635               gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7636               demux->restoredata_buffer = NULL;
7637               demux->offset = demux->restoredata_offset;
7638             }
7639 
7640             break;
7641           }
7642         }
7643 
7644         if (demux->todrop) {
7645           if (demux->cenc_aux_info_offset > 0) {
7646             GstByteReader br;
7647             const guint8 *data;
7648 
7649             GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7650             data = gst_adapter_map (demux->adapter, demux->todrop);
7651             gst_byte_reader_init (&br, data + 8, demux->todrop);
7652             if (!qtdemux_parse_cenc_aux_info (demux,
7653                     QTDEMUX_NTH_STREAM (demux, 0), &br,
7654                     demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7655               GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7656               ret = GST_FLOW_ERROR;
7657               gst_adapter_unmap (demux->adapter);
7658               g_free (demux->cenc_aux_info_sizes);
7659               demux->cenc_aux_info_sizes = NULL;
7660               goto done;
7661             }
7662             demux->cenc_aux_info_offset = 0;
7663             g_free (demux->cenc_aux_info_sizes);
7664             demux->cenc_aux_info_sizes = NULL;
7665             gst_adapter_unmap (demux->adapter);
7666           }
7667           gst_qtdemux_drop_data (demux, demux->todrop);
7668         }
7669 
7670         /* first buffer? */
7671         /* initial newsegment sent here after having added pads,
7672          * possible others in sink_event */
7673         gst_qtdemux_check_send_pending_segment (demux);
7674 
7675         /* Figure out which stream this packet belongs to */
7676         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7677           stream = QTDEMUX_NTH_STREAM (demux, i);
7678           if (stream->sample_index >= stream->n_samples) {
7679             /* reset to be checked below G_UNLIKELY (stream == NULL) */
7680             stream = NULL;
7681             continue;
7682           }
7683           GST_LOG_OBJECT (demux,
7684               "Checking track-id %u (sample_index:%d / offset:%"
7685               G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7686               stream->sample_index,
7687               stream->samples[stream->sample_index].offset,
7688               stream->samples[stream->sample_index].size);
7689 
7690           if (stream->samples[stream->sample_index].offset == demux->offset)
7691             break;
7692         }
7693 
7694         if (G_UNLIKELY (stream == NULL))
7695           goto unknown_stream;
7696 
7697         gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7698 
7699         if (stream->new_caps) {
7700           gst_qtdemux_configure_stream (demux, stream);
7701         }
7702 
7703         /* Put data in a buffer, set timestamps, caps, ... */
7704         sample = &stream->samples[stream->sample_index];
7705 
7706         if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7707           GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7708               GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7709 
7710           dts = QTSAMPLE_DTS (stream, sample);
7711           pts = QTSAMPLE_PTS (stream, sample);
7712           duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7713           keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7714 
7715           /* check for segment end */
7716           if (G_UNLIKELY (demux->segment.stop != -1
7717                   && demux->segment.stop <= pts && stream->on_keyframe)
7718               && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7719             GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7720             stream->time_position = GST_CLOCK_TIME_NONE;        /* this means EOS */
7721 
7722             /* skip this data, stream is EOS */
7723             gst_adapter_flush (demux->adapter, demux->neededbytes);
7724             demux->offset += demux->neededbytes;
7725 
7726             /* check if all streams are eos */
7727             ret = GST_FLOW_EOS;
7728             for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7729               if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7730                 ret = GST_FLOW_OK;
7731                 break;
7732               }
7733             }
7734           } else {
7735             GstBuffer *outbuf;
7736 
7737             outbuf =
7738                 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7739 
7740             /* FIXME: should either be an assert or a plain check */
7741             g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7742 
7743             ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7744                 dts, pts, duration, keyframe, dts, demux->offset);
7745           }
7746 
7747           /* combine flows */
7748           GST_OBJECT_LOCK (demux);
7749           ret = gst_qtdemux_combine_flows (demux, stream, ret);
7750           GST_OBJECT_UNLOCK (demux);
7751         } else {
7752           /* skip this data, stream is EOS */
7753           gst_adapter_flush (demux->adapter, demux->neededbytes);
7754         }
7755 
7756         stream->sample_index++;
7757         stream->offset_in_sample = 0;
7758 
7759         /* update current offset and figure out size of next buffer */
7760         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7761             demux->offset, demux->neededbytes);
7762         demux->offset += demux->neededbytes;
7763         GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7764             demux->offset);
7765 
7766 
7767         if (ret == GST_FLOW_EOS) {
7768           GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7769           demux->neededbytes = -1;
7770           goto eos;
7771         }
7772 
7773         if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7774           if (demux->fragmented) {
7775             GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7776             /* there may be more to follow, only finish this atom */
7777             demux->todrop = demux->mdatleft;
7778             demux->neededbytes = demux->todrop;
7779             break;
7780           }
7781           goto eos;
7782         }
7783         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7784           goto non_ok_unlinked_flow;
7785         }
7786         break;
7787       }
7788       default:
7789         goto invalid_state;
7790     }
7791   }
7792 
7793   /* when buffering movie data, at least show user something is happening */
7794   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7795       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7796     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7797         demux->neededbytes);
7798   }
7799 done:
7800 
7801   return ret;
7802 
7803   /* ERRORS */
7804 non_ok_unlinked_flow:
7805   {
7806     GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7807         gst_flow_get_name (ret));
7808     return ret;
7809   }
7810 unknown_stream:
7811   {
7812     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7813     ret = GST_FLOW_ERROR;
7814     goto done;
7815   }
7816 eos:
7817   {
7818     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7819     ret = GST_FLOW_EOS;
7820     goto done;
7821   }
7822 invalid_state:
7823   {
7824     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7825         (NULL), ("qtdemuxer invalid state %d", demux->state));
7826     ret = GST_FLOW_ERROR;
7827     goto done;
7828   }
7829 no_moov:
7830   {
7831     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7832         (NULL), ("no 'moov' atom within the first 10 MB"));
7833     ret = GST_FLOW_ERROR;
7834     goto done;
7835   }
7836 }
7837 
7838 static gboolean
qtdemux_sink_activate(GstPad * sinkpad,GstObject * parent)7839 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7840 {
7841   GstQuery *query;
7842   gboolean pull_mode;
7843 
7844   query = gst_query_new_scheduling ();
7845 
7846   if (!gst_pad_peer_query (sinkpad, query)) {
7847     gst_query_unref (query);
7848     goto activate_push;
7849   }
7850 
7851   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7852       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7853   gst_query_unref (query);
7854 
7855   if (!pull_mode)
7856     goto activate_push;
7857 
7858   GST_DEBUG_OBJECT (sinkpad, "activating pull");
7859   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7860 
7861 activate_push:
7862   {
7863     GST_DEBUG_OBJECT (sinkpad, "activating push");
7864     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7865   }
7866 }
7867 
7868 static gboolean
qtdemux_sink_activate_mode(GstPad * sinkpad,GstObject * parent,GstPadMode mode,gboolean active)7869 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7870     GstPadMode mode, gboolean active)
7871 {
7872   gboolean res;
7873   GstQTDemux *demux = GST_QTDEMUX (parent);
7874 
7875   switch (mode) {
7876     case GST_PAD_MODE_PUSH:
7877       demux->pullbased = FALSE;
7878       res = TRUE;
7879       break;
7880     case GST_PAD_MODE_PULL:
7881       if (active) {
7882         demux->pullbased = TRUE;
7883         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7884             sinkpad, NULL);
7885       } else {
7886         res = gst_pad_stop_task (sinkpad);
7887       }
7888       break;
7889     default:
7890       res = FALSE;
7891       break;
7892   }
7893   return res;
7894 }
7895 
7896 #ifdef HAVE_ZLIB
7897 static void *
qtdemux_inflate(void * z_buffer,guint z_length,guint * length)7898 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7899 {
7900   guint8 *buffer;
7901   z_stream z;
7902   int ret;
7903 
7904   memset (&z, 0, sizeof (z));
7905   z.zalloc = NULL;
7906   z.zfree = NULL;
7907   z.opaque = NULL;
7908 
7909   if ((ret = inflateInit (&z)) != Z_OK) {
7910     GST_ERROR ("inflateInit() returned %d", ret);
7911     return NULL;
7912   }
7913 
7914   z.next_in = z_buffer;
7915   z.avail_in = z_length;
7916 
7917   buffer = (guint8 *) g_malloc (*length);
7918   z.avail_out = *length;
7919   z.next_out = (Bytef *) buffer;
7920   do {
7921     ret = inflate (&z, Z_NO_FLUSH);
7922     if (ret == Z_STREAM_END) {
7923       break;
7924     } else if (ret != Z_OK) {
7925       GST_WARNING ("inflate() returned %d", ret);
7926       break;
7927     }
7928 
7929     if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) {
7930       GST_WARNING ("too big decompressed data");
7931       ret = Z_MEM_ERROR;
7932       break;
7933     }
7934 
7935     *length += 4096;
7936     buffer = (guint8 *) g_realloc (buffer, *length);
7937     z.next_out = (Bytef *) (buffer + z.total_out);
7938     z.avail_out += *length - z.total_out;
7939   } while (z.avail_in > 0);
7940 
7941   if (ret != Z_STREAM_END) {
7942     g_free (buffer);
7943     buffer = NULL;
7944     *length = 0;
7945   } else {
7946     *length = z.total_out;
7947   }
7948 
7949   inflateEnd (&z);
7950 
7951   return buffer;
7952 }
7953 #endif /* HAVE_ZLIB */
7954 
7955 static gboolean
qtdemux_parse_moov(GstQTDemux * qtdemux,const guint8 * buffer,guint length)7956 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7957 {
7958   GNode *cmov;
7959 
7960   qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7961 
7962   /* counts as header data */
7963   qtdemux->header_size += length;
7964 
7965   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7966   qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7967 
7968   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7969   if (cmov) {
7970     guint32 method;
7971     GNode *dcom;
7972     GNode *cmvd;
7973     guint32 dcom_len;
7974 
7975     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7976     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7977     if (dcom == NULL || cmvd == NULL)
7978       goto invalid_compression;
7979 
7980     dcom_len = QT_UINT32 (dcom->data);
7981     if (dcom_len < 12)
7982       goto invalid_compression;
7983 
7984     method = QT_FOURCC ((guint8 *) dcom->data + 8);
7985     switch (method) {
7986 #ifdef HAVE_ZLIB
7987       case FOURCC_zlib:{
7988         guint uncompressed_length;
7989         guint compressed_length;
7990         guint8 *buf;
7991         guint32 cmvd_len;
7992 
7993         cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7994         if (cmvd_len < 12)
7995           goto invalid_compression;
7996 
7997         uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7998         compressed_length = cmvd_len - 12;
7999         GST_LOG ("length = %u", uncompressed_length);
8000 
8001         buf =
8002             (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
8003             compressed_length, &uncompressed_length);
8004 
8005         if (buf) {
8006           qtdemux->moov_node_compressed = qtdemux->moov_node;
8007           qtdemux->moov_node = g_node_new (buf);
8008 
8009           qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
8010               uncompressed_length);
8011         }
8012         break;
8013       }
8014 #endif /* HAVE_ZLIB */
8015       default:
8016         GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
8017             "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
8018         break;
8019     }
8020   }
8021   return TRUE;
8022 
8023   /* ERRORS */
8024 invalid_compression:
8025   {
8026     GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
8027     return FALSE;
8028   }
8029 }
8030 
8031 static gboolean
qtdemux_parse_container(GstQTDemux * qtdemux,GNode * node,const guint8 * buf,const guint8 * end)8032 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
8033     const guint8 * end)
8034 {
8035   while (G_UNLIKELY (buf < end)) {
8036     GNode *child;
8037     guint32 len;
8038 
8039     if (G_UNLIKELY (buf + 4 > end)) {
8040       GST_LOG_OBJECT (qtdemux, "buffer overrun");
8041       break;
8042     }
8043     len = QT_UINT32 (buf);
8044     if (G_UNLIKELY (len == 0)) {
8045       GST_LOG_OBJECT (qtdemux, "empty container");
8046       break;
8047     }
8048     if (G_UNLIKELY (len < 8)) {
8049       GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8050       break;
8051     }
8052     if (G_UNLIKELY (len > (end - buf))) {
8053       GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8054           (gint) (end - buf));
8055       break;
8056     }
8057 
8058     child = g_node_new ((guint8 *) buf);
8059     g_node_append (node, child);
8060     GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8061     qtdemux_parse_node (qtdemux, child, buf, len);
8062 
8063     buf += len;
8064   }
8065   return TRUE;
8066 }
8067 
8068 static gboolean
qtdemux_parse_theora_extension(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * xdxt)8069 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8070     GNode * xdxt)
8071 {
8072   int len = QT_UINT32 (xdxt->data);
8073   guint8 *buf = xdxt->data;
8074   guint8 *end = buf + len;
8075   GstBuffer *buffer;
8076 
8077   /* skip size and type */
8078   buf += 8;
8079   end -= 8;
8080 
8081   while (buf < end) {
8082     gint size;
8083     guint32 type;
8084 
8085     size = QT_UINT32 (buf);
8086     type = QT_FOURCC (buf + 4);
8087 
8088     GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8089 
8090     if (buf + size > end || size <= 0)
8091       break;
8092 
8093     buf += 8;
8094     size -= 8;
8095 
8096     GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8097         GST_FOURCC_ARGS (type));
8098 
8099     switch (type) {
8100       case FOURCC_tCtH:
8101         buffer = gst_buffer_new_and_alloc (size);
8102         gst_buffer_fill (buffer, 0, buf, size);
8103         stream->buffers = g_slist_append (stream->buffers, buffer);
8104         GST_LOG_OBJECT (qtdemux, "parsing theora header");
8105         break;
8106       case FOURCC_tCt_:
8107         buffer = gst_buffer_new_and_alloc (size);
8108         gst_buffer_fill (buffer, 0, buf, size);
8109         stream->buffers = g_slist_append (stream->buffers, buffer);
8110         GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8111         break;
8112       case FOURCC_tCtC:
8113         buffer = gst_buffer_new_and_alloc (size);
8114         gst_buffer_fill (buffer, 0, buf, size);
8115         stream->buffers = g_slist_append (stream->buffers, buffer);
8116         GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8117         break;
8118       default:
8119         GST_WARNING_OBJECT (qtdemux,
8120             "unknown theora cookie %" GST_FOURCC_FORMAT,
8121             GST_FOURCC_ARGS (type));
8122         break;
8123     }
8124     buf += size;
8125   }
8126   return TRUE;
8127 }
8128 
8129 static gboolean
qtdemux_parse_node(GstQTDemux * qtdemux,GNode * node,const guint8 * buffer,guint length)8130 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8131     guint length)
8132 {
8133   guint32 fourcc = 0;
8134   guint32 node_length = 0;
8135   const QtNodeType *type;
8136   const guint8 *end;
8137 
8138   GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8139 
8140   if (G_UNLIKELY (length < 8))
8141     goto not_enough_data;
8142 
8143   node_length = QT_UINT32 (buffer);
8144   fourcc = QT_FOURCC (buffer + 4);
8145 
8146   /* ignore empty nodes */
8147   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8148     return TRUE;
8149 
8150   type = qtdemux_type_get (fourcc);
8151 
8152   end = buffer + length;
8153 
8154   GST_LOG_OBJECT (qtdemux,
8155       "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8156       GST_FOURCC_ARGS (fourcc), node_length, type->name);
8157 
8158   if (node_length > length)
8159     goto broken_atom_size;
8160 
8161   if (type->flags & QT_FLAG_CONTAINER) {
8162     qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8163   } else {
8164     switch (fourcc) {
8165       case FOURCC_stsd:
8166       {
8167         if (node_length < 20) {
8168           GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8169           break;
8170         }
8171         GST_DEBUG_OBJECT (qtdemux,
8172             "parsing stsd (sample table, sample description) atom");
8173         /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8174         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8175         break;
8176       }
8177       case FOURCC_mp4a:
8178       case FOURCC_alac:
8179       case FOURCC_fLaC:
8180       case FOURCC_aavd:
8181       {
8182         guint32 version;
8183         guint32 offset;
8184         guint min_size;
8185 
8186         /* also read alac (or whatever) in stead of mp4a in the following,
8187          * since a similar layout is used in other cases as well */
8188         if (fourcc == FOURCC_mp4a)
8189           min_size = 20;
8190         else if (fourcc == FOURCC_fLaC)
8191           min_size = 86;
8192         else
8193           min_size = 40;
8194 
8195         /* There are two things we might encounter here: a true mp4a atom, and
8196            an mp4a entry in an stsd atom. The latter is what we're interested
8197            in, and it looks like an atom, but isn't really one. The true mp4a
8198            atom is short, so we detect it based on length here. */
8199         if (length < min_size) {
8200           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8201               GST_FOURCC_ARGS (fourcc));
8202           break;
8203         }
8204 
8205         /* 'version' here is the sound sample description version. Types 0 and
8206            1 are documented in the QTFF reference, but type 2 is not: it's
8207            described in Apple header files instead (struct SoundDescriptionV2
8208            in Movies.h) */
8209         version = QT_UINT16 (buffer + 16);
8210 
8211         GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8212             GST_FOURCC_ARGS (fourcc), version);
8213 
8214         /* parse any esds descriptors */
8215         switch (version) {
8216           case 0:
8217             offset = 0x24;
8218             break;
8219           case 1:
8220             offset = 0x34;
8221             break;
8222           case 2:
8223             offset = 0x48;
8224             break;
8225           default:
8226             GST_WARNING_OBJECT (qtdemux,
8227                 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8228                 GST_FOURCC_ARGS (fourcc), version);
8229             offset = 0;
8230             break;
8231         }
8232         if (offset)
8233           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8234         break;
8235       }
8236       case FOURCC_mp4v:
8237       case FOURCC_MP4V:
8238       case FOURCC_fmp4:
8239       case FOURCC_FMP4:
8240       case FOURCC_apcs:
8241       case FOURCC_apch:
8242       case FOURCC_apcn:
8243       case FOURCC_apco:
8244       case FOURCC_ap4h:
8245       case FOURCC_xvid:
8246       case FOURCC_XVID:
8247       case FOURCC_H264:
8248       case FOURCC_avc1:
8249       case FOURCC_avc3:
8250       case FOURCC_H265:
8251       case FOURCC_hvc1:
8252       case FOURCC_hev1:
8253       case FOURCC_dvh1:
8254       case FOURCC_dvhe:
8255       case FOURCC_mjp2:
8256       case FOURCC_encv:
8257       {
8258         guint32 version;
8259         guint32 str_len;
8260 
8261         /* codec_data is contained inside these atoms, which all have
8262          * the same format. */
8263         /* video sample description size is 86 bytes without extension.
8264          * node_length have to be bigger than 86 bytes because video sample
8265          * description can include extensions such as esds, fiel, glbl, etc. */
8266         if (node_length < 86) {
8267           GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8268               " sample description length too short (%u < 86)",
8269               GST_FOURCC_ARGS (fourcc), node_length);
8270           break;
8271         }
8272 
8273         GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8274             GST_FOURCC_ARGS (fourcc));
8275 
8276         /* version (2 bytes) : this is set to 0, unless a compressor has changed
8277          *              its data format.
8278          * revision level (2 bytes) : must be set to 0. */
8279         version = QT_UINT32 (buffer + 16);
8280         GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8281 
8282         /* compressor name : PASCAL string and informative purposes
8283          * first byte : the number of bytes to be displayed.
8284          *              it has to be less than 32 because it is reserved
8285          *              space of 32 bytes total including itself. */
8286         str_len = QT_UINT8 (buffer + 50);
8287         if (str_len < 32)
8288           GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8289               (char *) buffer + 51);
8290         else
8291           GST_WARNING_OBJECT (qtdemux,
8292               "compressorname length too big (%u > 31)", str_len);
8293 
8294         GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8295             end - buffer);
8296         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8297         break;
8298       }
8299       case FOURCC_meta:
8300       {
8301         GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8302 
8303         /* You are reading this correctly. QTFF specifies that the
8304          * metadata atom is a short atom, whereas ISO BMFF specifies
8305          * it's a full atom. But since so many people are doing things
8306          * differently, we actually peek into the atom to see which
8307          * variant it is */
8308         if (length < 16) {
8309           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8310               GST_FOURCC_ARGS (fourcc));
8311           break;
8312         }
8313         if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8314           /* Variant 1: What QTFF specifies. 'meta' is a short header which
8315            * starts with a 'hdlr' atom */
8316           qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8317         } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8318           /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8319            * with version/flags both set to zero */
8320           qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8321         } else
8322           GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8323         break;
8324       }
8325       case FOURCC_mp4s:
8326       {
8327         GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8328         /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8329         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8330         break;
8331       }
8332       case FOURCC_XiTh:
8333       {
8334         guint32 version;
8335         guint32 offset;
8336 
8337         if (length < 16) {
8338           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8339               GST_FOURCC_ARGS (fourcc));
8340           break;
8341         }
8342 
8343         version = QT_UINT32 (buffer + 12);
8344         GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8345 
8346         switch (version) {
8347           case 0x00000001:
8348             offset = 0x62;
8349             break;
8350           default:
8351             GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8352             offset = 0;
8353             break;
8354         }
8355         if (offset) {
8356           if (length < offset) {
8357             GST_WARNING_OBJECT (qtdemux,
8358                 "skipping too small %" GST_FOURCC_FORMAT " box",
8359                 GST_FOURCC_ARGS (fourcc));
8360             break;
8361           }
8362           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8363         }
8364         break;
8365       }
8366       case FOURCC_in24:
8367       {
8368         qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8369         break;
8370       }
8371       case FOURCC_uuid:
8372       {
8373         qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8374         break;
8375       }
8376       case FOURCC_enca:
8377       {
8378         qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8379         break;
8380       }
8381       default:
8382         if (!strcmp (type->name, "unknown"))
8383           GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8384         break;
8385     }
8386   }
8387   GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8388       GST_FOURCC_ARGS (fourcc));
8389   return TRUE;
8390 
8391 /* ERRORS */
8392 not_enough_data:
8393   {
8394     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8395         (_("This file is corrupt and cannot be played.")),
8396         ("Not enough data for an atom header, got only %u bytes", length));
8397     return FALSE;
8398   }
8399 broken_atom_size:
8400   {
8401     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8402         (_("This file is corrupt and cannot be played.")),
8403         ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8404             "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8405             length));
8406     return FALSE;
8407   }
8408 }
8409 
8410 static void
qtdemux_do_allocation(QtDemuxStream * stream,GstQTDemux * qtdemux)8411 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8412 {
8413 /* FIXME: This can only reliably work if demuxers have a
8414  * separate streaming thread per srcpad. This should be
8415  * done in a demuxer base class, which integrates parts
8416  * of multiqueue
8417  *
8418  * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8419  */
8420 #if 0
8421   GstQuery *query;
8422 
8423   query = gst_query_new_allocation (stream->caps, FALSE);
8424 
8425   if (!gst_pad_peer_query (stream->pad, query)) {
8426     /* not a problem, just debug a little */
8427     GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8428   }
8429 
8430   if (stream->allocator)
8431     gst_object_unref (stream->allocator);
8432 
8433   if (gst_query_get_n_allocation_params (query) > 0) {
8434     /* try the allocator */
8435     gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8436         &stream->params);
8437     stream->use_allocator = TRUE;
8438   } else {
8439     stream->allocator = NULL;
8440     gst_allocation_params_init (&stream->params);
8441     stream->use_allocator = FALSE;
8442   }
8443   gst_query_unref (query);
8444 #endif
8445 }
8446 
8447 static gboolean
pad_query(const GValue * item,GValue * value,gpointer user_data)8448 pad_query (const GValue * item, GValue * value, gpointer user_data)
8449 {
8450   GstPad *pad = g_value_get_object (item);
8451   GstQuery *query = user_data;
8452   gboolean res;
8453 
8454   res = gst_pad_peer_query (pad, query);
8455 
8456   if (res) {
8457     g_value_set_boolean (value, TRUE);
8458     return FALSE;
8459   }
8460 
8461   GST_INFO_OBJECT (pad, "pad peer query failed");
8462   return TRUE;
8463 }
8464 
8465 static gboolean
gst_qtdemux_run_query(GstElement * element,GstQuery * query,GstPadDirection direction)8466 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8467     GstPadDirection direction)
8468 {
8469   GstIterator *it;
8470   GstIteratorFoldFunction func = pad_query;
8471   GValue res = { 0, };
8472 
8473   g_value_init (&res, G_TYPE_BOOLEAN);
8474   g_value_set_boolean (&res, FALSE);
8475 
8476   /* Ask neighbor */
8477   if (direction == GST_PAD_SRC)
8478     it = gst_element_iterate_src_pads (element);
8479   else
8480     it = gst_element_iterate_sink_pads (element);
8481 
8482   while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8483     gst_iterator_resync (it);
8484 
8485   gst_iterator_free (it);
8486 
8487   return g_value_get_boolean (&res);
8488 }
8489 
8490 static void
gst_qtdemux_request_protection_context(GstQTDemux * qtdemux,QtDemuxStream * stream)8491 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8492     QtDemuxStream * stream)
8493 {
8494   GstQuery *query;
8495   GstContext *ctxt;
8496   GstElement *element = GST_ELEMENT (qtdemux);
8497   GstStructure *st;
8498   gchar **filtered_sys_ids;
8499   GValue event_list = G_VALUE_INIT;
8500   GList *walk;
8501 
8502   /* 1. Check if we already have the context. */
8503   if (qtdemux->preferred_protection_system_id != NULL) {
8504     GST_LOG_OBJECT (element,
8505         "already have the protection context, no need to request it again");
8506     return;
8507   }
8508 
8509   g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8510   filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8511       (const gchar **) qtdemux->protection_system_ids->pdata);
8512 
8513   g_ptr_array_remove_index (qtdemux->protection_system_ids,
8514       qtdemux->protection_system_ids->len - 1);
8515   GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8516       "decryptors for %u of them, running context request",
8517       qtdemux->protection_system_ids->len,
8518       filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8519 
8520 
8521   if (stream->protection_scheme_event_queue.length) {
8522     GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8523         stream->protection_scheme_event_queue.length);
8524     walk = stream->protection_scheme_event_queue.tail;
8525   } else {
8526     GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8527         qtdemux->protection_event_queue.length);
8528     walk = qtdemux->protection_event_queue.tail;
8529   }
8530 
8531   g_value_init (&event_list, GST_TYPE_LIST);
8532   for (; walk; walk = g_list_previous (walk)) {
8533     GValue *event_value = g_new0 (GValue, 1);
8534     g_value_init (event_value, GST_TYPE_EVENT);
8535     g_value_set_boxed (event_value, walk->data);
8536     gst_value_list_append_and_take_value (&event_list, event_value);
8537   }
8538 
8539   /*  2a) Query downstream with GST_QUERY_CONTEXT for the context and
8540    *      check if downstream already has a context of the specific type
8541    *  2b) Query upstream as above.
8542    */
8543   query = gst_query_new_context ("drm-preferred-decryption-system-id");
8544   st = gst_query_writable_structure (query);
8545   gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8546       "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8547       NULL);
8548   gst_structure_set_value (st, "stream-encryption-events", &event_list);
8549   if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8550     gst_query_parse_context (query, &ctxt);
8551     GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8552     gst_element_set_context (element, ctxt);
8553   } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8554     gst_query_parse_context (query, &ctxt);
8555     GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8556     gst_element_set_context (element, ctxt);
8557   } else {
8558     /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8559      *    the required context type and afterwards check if a
8560      *    usable context was set now as in 1). The message could
8561      *    be handled by the parent bins of the element and the
8562      *    application.
8563      */
8564     GstMessage *msg;
8565 
8566     GST_INFO_OBJECT (element, "posting need context message");
8567     msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8568         "drm-preferred-decryption-system-id");
8569     st = (GstStructure *) gst_message_get_structure (msg);
8570     gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8571         "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8572         NULL);
8573 
8574     gst_structure_set_value (st, "stream-encryption-events", &event_list);
8575     gst_element_post_message (element, msg);
8576   }
8577 
8578   g_strfreev (filtered_sys_ids);
8579   g_value_unset (&event_list);
8580   gst_query_unref (query);
8581 }
8582 
8583 static gboolean
gst_qtdemux_configure_protected_caps(GstQTDemux * qtdemux,QtDemuxStream * stream)8584 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8585     QtDemuxStream * stream)
8586 {
8587   GstStructure *s;
8588   const gchar *selected_system = NULL;
8589 
8590   g_return_val_if_fail (qtdemux != NULL, FALSE);
8591   g_return_val_if_fail (stream != NULL, FALSE);
8592   g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8593       FALSE);
8594 
8595   if (stream->protection_scheme_type == FOURCC_aavd) {
8596     s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8597     if (!gst_structure_has_name (s, "application/x-aavd")) {
8598       gst_structure_set (s,
8599           "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8600           NULL);
8601       gst_structure_set_name (s, "application/x-aavd");
8602     }
8603     return TRUE;
8604   }
8605 
8606   if (stream->protection_scheme_type != FOURCC_cenc
8607       && stream->protection_scheme_type != FOURCC_cbcs) {
8608     GST_ERROR_OBJECT (qtdemux,
8609         "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8610         GST_FOURCC_ARGS (stream->protection_scheme_type));
8611     return FALSE;
8612   }
8613 
8614   s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8615   if (!gst_structure_has_name (s, "application/x-cenc")) {
8616     gst_structure_set (s,
8617         "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8618     gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8619         (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8620         NULL);
8621     gst_structure_set_name (s, "application/x-cenc");
8622   }
8623 
8624   if (qtdemux->protection_system_ids == NULL) {
8625     GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8626         "cenc protection system information has been found, not setting a "
8627         "protection system UUID");
8628     return TRUE;
8629   }
8630 
8631   gst_qtdemux_request_protection_context (qtdemux, stream);
8632   if (qtdemux->preferred_protection_system_id != NULL) {
8633     const gchar *preferred_system_array[] =
8634         { qtdemux->preferred_protection_system_id, NULL };
8635 
8636     selected_system = gst_protection_select_system (preferred_system_array);
8637 
8638     if (selected_system) {
8639       GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8640           qtdemux->preferred_protection_system_id);
8641     } else {
8642       GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8643           "because there is no available decryptor",
8644           qtdemux->preferred_protection_system_id);
8645     }
8646   }
8647 
8648   if (!selected_system) {
8649     g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8650     selected_system = gst_protection_select_system ((const gchar **)
8651         qtdemux->protection_system_ids->pdata);
8652     g_ptr_array_remove_index (qtdemux->protection_system_ids,
8653         qtdemux->protection_system_ids->len - 1);
8654   }
8655 
8656   if (!selected_system) {
8657     GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8658         "suitable decryptor element has been found");
8659     return FALSE;
8660   }
8661 
8662   GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8663       selected_system);
8664 
8665   gst_structure_set (s,
8666       GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8667       NULL);
8668 
8669   return TRUE;
8670 }
8671 
8672 static gboolean
gst_qtdemux_guess_framerate(GstQTDemux * qtdemux,QtDemuxStream * stream)8673 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8674 {
8675   /* fps is calculated base on the duration of the average framerate since
8676    * qt does not have a fixed framerate. */
8677   gboolean fps_available = TRUE;
8678   guint32 first_duration = 0;
8679 
8680   if (stream->n_samples > 0)
8681     first_duration = stream->samples[0].duration;
8682 
8683   if ((stream->n_samples == 1 && first_duration == 0)
8684       || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8685     /* still frame */
8686     CUR_STREAM (stream)->fps_n = 0;
8687     CUR_STREAM (stream)->fps_d = 1;
8688   } else {
8689     if (stream->duration == 0 || stream->n_samples < 2) {
8690       CUR_STREAM (stream)->fps_n = stream->timescale;
8691       CUR_STREAM (stream)->fps_d = 1;
8692       fps_available = FALSE;
8693     } else {
8694       GstClockTime avg_duration;
8695       guint64 duration;
8696       guint32 n_samples;
8697 
8698       /* duration and n_samples can be updated for fragmented format
8699        * so, framerate of fragmented format is calculated using data in a moof */
8700       if (qtdemux->fragmented && stream->n_samples_moof > 0
8701           && stream->duration_moof > 0) {
8702         n_samples = stream->n_samples_moof;
8703         duration = stream->duration_moof;
8704       } else {
8705         n_samples = stream->n_samples;
8706         duration = stream->duration;
8707       }
8708 
8709       /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8710       /* stream->duration is guint64, timescale, n_samples are guint32 */
8711       avg_duration =
8712           gst_util_uint64_scale_round (duration -
8713           first_duration, GST_SECOND,
8714           (guint64) (stream->timescale) * (n_samples - 1));
8715 
8716       GST_LOG_OBJECT (qtdemux,
8717           "Calculating avg sample duration based on stream (or moof) duration %"
8718           G_GUINT64_FORMAT
8719           " minus first sample %u, leaving %d samples gives %"
8720           GST_TIME_FORMAT, duration, first_duration,
8721           n_samples - 1, GST_TIME_ARGS (avg_duration));
8722 #ifdef OHOS_OPT_COMPAT
8723       /**
8724        * ohos.opt.compat.0038
8725        * Solve the problem of correct frame rate not passing forward
8726        */
8727       if (avg_duration == 0) {
8728         fps_available = FALSE;
8729         GST_ERROR_OBJECT (qtdemux, "Calculating avg duration abnormal");
8730       } else {
8731         gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8732         GST_DEBUG_OBJECT (qtdemux, "Guess framerate fps_n %d fps_d %d",
8733             CUR_STREAM (stream)->fps_n, CUR_STREAM (stream)->fps_d);
8734       }
8735 #else
8736       fps_available =
8737           gst_video_guess_framerate (avg_duration,
8738           &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8739 #endif
8740       GST_DEBUG_OBJECT (qtdemux,
8741           "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8742           stream->timescale, CUR_STREAM (stream)->fps_n,
8743           CUR_STREAM (stream)->fps_d);
8744     }
8745   }
8746 
8747   return fps_available;
8748 }
8749 
8750 static gboolean
gst_qtdemux_configure_stream(GstQTDemux * qtdemux,QtDemuxStream * stream)8751 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8752 {
8753   if (stream->subtype == FOURCC_vide) {
8754     gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8755 
8756     if (CUR_STREAM (stream)->caps) {
8757       CUR_STREAM (stream)->caps =
8758           gst_caps_make_writable (CUR_STREAM (stream)->caps);
8759 
8760       if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8761         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8762             "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8763             "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8764 
8765       /* set framerate if calculated framerate is reliable */
8766       if (fps_available) {
8767         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8768             "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8769             CUR_STREAM (stream)->fps_d, NULL);
8770       }
8771 
8772       /* calculate pixel-aspect-ratio using display width and height */
8773       GST_DEBUG_OBJECT (qtdemux,
8774           "video size %dx%d, target display size %dx%d",
8775           CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8776           stream->display_width, stream->display_height);
8777       /* qt file might have pasp atom */
8778       if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8779         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8780             CUR_STREAM (stream)->par_h);
8781         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8782             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8783             CUR_STREAM (stream)->par_h, NULL);
8784       } else if (stream->display_width > 0 && stream->display_height > 0
8785           && CUR_STREAM (stream)->width > 0
8786           && CUR_STREAM (stream)->height > 0) {
8787         gint n, d;
8788 
8789         /* calculate the pixel aspect ratio using the display and pixel w/h */
8790         n = stream->display_width * CUR_STREAM (stream)->height;
8791         d = stream->display_height * CUR_STREAM (stream)->width;
8792         if (n == d)
8793           n = d = 1;
8794         GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8795         CUR_STREAM (stream)->par_w = n;
8796         CUR_STREAM (stream)->par_h = d;
8797         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8798             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8799             CUR_STREAM (stream)->par_h, NULL);
8800       }
8801 
8802       if (CUR_STREAM (stream)->interlace_mode > 0) {
8803         if (CUR_STREAM (stream)->interlace_mode == 1) {
8804           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8805               G_TYPE_STRING, "progressive", NULL);
8806         } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8807           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8808               G_TYPE_STRING, "interleaved", NULL);
8809           if (CUR_STREAM (stream)->field_order == 9) {
8810             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8811                 G_TYPE_STRING, "top-field-first", NULL);
8812           } else if (CUR_STREAM (stream)->field_order == 14) {
8813             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8814                 G_TYPE_STRING, "bottom-field-first", NULL);
8815           }
8816         }
8817       }
8818 
8819       /* Create incomplete colorimetry here if needed */
8820       if (CUR_STREAM (stream)->colorimetry.range ||
8821           CUR_STREAM (stream)->colorimetry.matrix ||
8822           CUR_STREAM (stream)->colorimetry.transfer
8823           || CUR_STREAM (stream)->colorimetry.primaries) {
8824         gchar *colorimetry =
8825             gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8826         gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8827             G_TYPE_STRING, colorimetry, NULL);
8828         g_free (colorimetry);
8829       }
8830 
8831       if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8832         guint par_w = 1, par_h = 1;
8833 
8834         if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8835           par_w = CUR_STREAM (stream)->par_w;
8836           par_h = CUR_STREAM (stream)->par_h;
8837         }
8838 
8839         if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8840                 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8841                 par_h)) {
8842           stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8843         }
8844 
8845         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8846             "multiview-mode", G_TYPE_STRING,
8847             gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8848             "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8849             stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8850       }
8851     }
8852   }
8853 
8854   else if (stream->subtype == FOURCC_soun) {
8855     if (CUR_STREAM (stream)->caps) {
8856       CUR_STREAM (stream)->caps =
8857           gst_caps_make_writable (CUR_STREAM (stream)->caps);
8858       if (CUR_STREAM (stream)->rate > 0)
8859         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8860             "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8861       if (CUR_STREAM (stream)->n_channels > 0)
8862         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8863             "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8864       if (CUR_STREAM (stream)->n_channels > 2) {
8865         /* FIXME: Need to parse the 'chan' atom to get channel layouts
8866          * correctly; this is just the minimum we can do - assume
8867          * we don't actually have any channel positions. */
8868         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8869             "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8870       }
8871     }
8872   }
8873 
8874   else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8875     const GstStructure *s;
8876     QtDemuxStream *fps_stream = NULL;
8877     gboolean fps_available = FALSE;
8878 
8879     /* CEA608 closed caption tracks are a bit special in that each sample
8880      * can contain CCs for multiple frames, and CCs can be omitted and have to
8881      * be inferred from the duration of the sample then.
8882      *
8883      * As such we take the framerate from the (first) video track here for
8884      * CEA608 as there must be one CC byte pair for every video frame
8885      * according to the spec.
8886      *
8887      * For CEA708 all is fine and there is one sample per frame.
8888      */
8889 
8890     s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8891     if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8892       gint i;
8893 
8894       for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8895         QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8896 
8897         if (tmp->subtype == FOURCC_vide) {
8898           fps_stream = tmp;
8899           break;
8900         }
8901       }
8902 
8903       if (fps_stream) {
8904         fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8905         CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8906         CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8907       }
8908     } else {
8909       fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8910       fps_stream = stream;
8911     }
8912 
8913     CUR_STREAM (stream)->caps =
8914         gst_caps_make_writable (CUR_STREAM (stream)->caps);
8915 
8916     /* set framerate if calculated framerate is reliable */
8917     if (fps_available) {
8918       gst_caps_set_simple (CUR_STREAM (stream)->caps,
8919           "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8920           CUR_STREAM (stream)->fps_d, NULL);
8921     }
8922   }
8923 
8924   if (stream->pad) {
8925     GstCaps *prev_caps = NULL;
8926 
8927     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8928     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8929     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8930     gst_pad_set_active (stream->pad, TRUE);
8931 
8932     gst_pad_use_fixed_caps (stream->pad);
8933 
8934     if (stream->protected) {
8935       if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8936         GST_ERROR_OBJECT (qtdemux,
8937             "Failed to configure protected stream caps.");
8938         return FALSE;
8939       }
8940     }
8941 
8942     GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8943         CUR_STREAM (stream)->caps);
8944     if (stream->new_stream) {
8945       GstEvent *event;
8946       GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8947 
8948       event =
8949           gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8950           0);
8951       if (event) {
8952         gst_event_parse_stream_flags (event, &stream_flags);
8953         if (gst_event_parse_group_id (event, &qtdemux->group_id))
8954           qtdemux->have_group_id = TRUE;
8955         else
8956           qtdemux->have_group_id = FALSE;
8957         gst_event_unref (event);
8958       } else if (!qtdemux->have_group_id) {
8959         qtdemux->have_group_id = TRUE;
8960         qtdemux->group_id = gst_util_group_id_next ();
8961       }
8962 
8963       stream->new_stream = FALSE;
8964       event = gst_event_new_stream_start (stream->stream_id);
8965       if (qtdemux->have_group_id)
8966         gst_event_set_group_id (event, qtdemux->group_id);
8967       if (stream->disabled)
8968         stream_flags |= GST_STREAM_FLAG_UNSELECT;
8969       if (CUR_STREAM (stream)->sparse) {
8970         stream_flags |= GST_STREAM_FLAG_SPARSE;
8971       } else {
8972         stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8973       }
8974       gst_event_set_stream_flags (event, stream_flags);
8975       gst_pad_push_event (stream->pad, event);
8976     }
8977 
8978     prev_caps = gst_pad_get_current_caps (stream->pad);
8979 
8980     if (CUR_STREAM (stream)->caps) {
8981       if (!prev_caps
8982           || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8983         GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8984             CUR_STREAM (stream)->caps);
8985         gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8986       } else {
8987         GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8988       }
8989     } else {
8990       GST_WARNING_OBJECT (qtdemux, "stream without caps");
8991     }
8992 
8993     if (prev_caps)
8994       gst_caps_unref (prev_caps);
8995     stream->new_caps = FALSE;
8996   }
8997   return TRUE;
8998 }
8999 
9000 static void
gst_qtdemux_stream_check_and_change_stsd_index(GstQTDemux * demux,QtDemuxStream * stream)9001 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
9002     QtDemuxStream * stream)
9003 {
9004   if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
9005     return;
9006 
9007   GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
9008       stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
9009   if (G_UNLIKELY (stream->stsd_sample_description_id >=
9010           stream->stsd_entries_length)) {
9011     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
9012         (_("This file is invalid and cannot be played.")),
9013         ("New sample description id is out of bounds (%d >= %d)",
9014             stream->stsd_sample_description_id, stream->stsd_entries_length));
9015   } else {
9016     stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
9017     stream->new_caps = TRUE;
9018   }
9019 }
9020 
9021 static gboolean
gst_qtdemux_add_stream(GstQTDemux * qtdemux,QtDemuxStream * stream,GstTagList * list)9022 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
9023     QtDemuxStream * stream, GstTagList * list)
9024 {
9025   gboolean ret = TRUE;
9026 
9027   if (stream->subtype == FOURCC_vide) {
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 
9034     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9035       gst_object_unref (stream->pad);
9036       stream->pad = NULL;
9037       ret = FALSE;
9038       goto done;
9039     }
9040 
9041     qtdemux->n_video_streams++;
9042   } else if (stream->subtype == FOURCC_soun) {
9043     gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9044 
9045     stream->pad =
9046         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9047     g_free (name);
9048     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9049       gst_object_unref (stream->pad);
9050       stream->pad = NULL;
9051       ret = FALSE;
9052       goto done;
9053     }
9054     qtdemux->n_audio_streams++;
9055   } else if (stream->subtype == FOURCC_strm) {
9056     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9057   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9058       || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9059       || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
9060     gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9061 
9062     stream->pad =
9063         gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9064     g_free (name);
9065     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9066       gst_object_unref (stream->pad);
9067       stream->pad = NULL;
9068       ret = FALSE;
9069       goto done;
9070     }
9071     qtdemux->n_sub_streams++;
9072   } else if (CUR_STREAM (stream)->caps) {
9073     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9074 
9075     stream->pad =
9076         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9077     g_free (name);
9078     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9079       gst_object_unref (stream->pad);
9080       stream->pad = NULL;
9081       ret = FALSE;
9082       goto done;
9083     }
9084     qtdemux->n_video_streams++;
9085   } else {
9086     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9087     goto done;
9088   }
9089 
9090   if (stream->pad) {
9091     GList *l;
9092 
9093     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9094         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9095     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9096     GST_OBJECT_LOCK (qtdemux);
9097     gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9098     GST_OBJECT_UNLOCK (qtdemux);
9099 
9100     if (stream->stream_tags)
9101       gst_tag_list_unref (stream->stream_tags);
9102     stream->stream_tags = list;
9103     list = NULL;
9104     /* global tags go on each pad anyway */
9105     stream->send_global_tags = TRUE;
9106     /* send upstream GST_EVENT_PROTECTION events that were received before
9107        this source pad was created */
9108     for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9109       gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9110   }
9111 done:
9112   if (list)
9113     gst_tag_list_unref (list);
9114   return ret;
9115 }
9116 
9117 /* find next atom with @fourcc starting at @offset */
9118 static GstFlowReturn
qtdemux_find_atom(GstQTDemux * qtdemux,guint64 * offset,guint64 * length,guint32 fourcc)9119 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9120     guint64 * length, guint32 fourcc)
9121 {
9122   GstFlowReturn ret;
9123   guint32 lfourcc;
9124   GstBuffer *buf;
9125 
9126   GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9127       G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9128 
9129   while (TRUE) {
9130     GstMapInfo map;
9131 
9132     buf = NULL;
9133     ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9134     if (G_UNLIKELY (ret != GST_FLOW_OK))
9135       goto locate_failed;
9136     if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9137       /* likely EOF */
9138       ret = GST_FLOW_EOS;
9139       gst_buffer_unref (buf);
9140       goto locate_failed;
9141     }
9142     gst_buffer_map (buf, &map, GST_MAP_READ);
9143     extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9144     gst_buffer_unmap (buf, &map);
9145     gst_buffer_unref (buf);
9146 
9147     if (G_UNLIKELY (*length == 0)) {
9148       GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9149       ret = GST_FLOW_ERROR;
9150       goto locate_failed;
9151     }
9152 
9153     if (lfourcc == fourcc) {
9154       GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9155           G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9156       break;
9157     } else {
9158       GST_LOG_OBJECT (qtdemux,
9159           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9160           GST_FOURCC_ARGS (lfourcc), *offset);
9161       if (*offset == G_MAXUINT64)
9162         goto locate_failed;
9163       *offset += *length;
9164     }
9165   }
9166 
9167   return GST_FLOW_OK;
9168 
9169 locate_failed:
9170   {
9171     /* might simply have had last one */
9172     GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9173     return ret;
9174   }
9175 }
9176 
9177 /* should only do something in pull mode */
9178 /* call with OBJECT lock */
9179 static GstFlowReturn
qtdemux_add_fragmented_samples(GstQTDemux * qtdemux)9180 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9181 {
9182   guint64 length, offset;
9183   GstBuffer *buf = NULL;
9184   GstFlowReturn ret = GST_FLOW_OK;
9185   GstFlowReturn res = GST_FLOW_OK;
9186   GstMapInfo map;
9187 
9188   offset = qtdemux->moof_offset;
9189   GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9190 
9191   if (!offset) {
9192     GST_DEBUG_OBJECT (qtdemux, "no next moof");
9193     return GST_FLOW_EOS;
9194   }
9195 
9196   /* best not do pull etc with lock held */
9197   GST_OBJECT_UNLOCK (qtdemux);
9198 
9199   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9200   if (ret != GST_FLOW_OK)
9201     goto flow_failed;
9202 
9203   ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9204   if (G_UNLIKELY (ret != GST_FLOW_OK))
9205     goto flow_failed;
9206   gst_buffer_map (buf, &map, GST_MAP_READ);
9207   if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9208     gst_buffer_unmap (buf, &map);
9209     gst_buffer_unref (buf);
9210     buf = NULL;
9211     goto parse_failed;
9212   }
9213 
9214   gst_buffer_unmap (buf, &map);
9215   gst_buffer_unref (buf);
9216   buf = NULL;
9217 
9218   offset += length;
9219   /* look for next moof */
9220   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9221   if (G_UNLIKELY (ret != GST_FLOW_OK))
9222     goto flow_failed;
9223 
9224 exit:
9225   GST_OBJECT_LOCK (qtdemux);
9226 
9227   qtdemux->moof_offset = offset;
9228 
9229   return res;
9230 
9231 parse_failed:
9232   {
9233     GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9234     offset = 0;
9235     res = GST_FLOW_ERROR;
9236     goto exit;
9237   }
9238 flow_failed:
9239   {
9240     /* maybe upstream temporarily flushing */
9241     if (ret != GST_FLOW_FLUSHING) {
9242       GST_DEBUG_OBJECT (qtdemux, "no next moof");
9243       offset = 0;
9244     } else {
9245       GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9246       /* resume at current position next time */
9247     }
9248     res = ret;
9249     goto exit;
9250   }
9251 }
9252 
9253 static void
qtdemux_merge_sample_table(GstQTDemux * qtdemux,QtDemuxStream * stream)9254 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9255 {
9256   guint i;
9257   guint32 num_chunks;
9258   gint32 stts_duration;
9259   GstByteWriter stsc, stts, stsz;
9260 
9261   /* Each sample has a different size, which we don't support for merging */
9262   if (stream->sample_size == 0) {
9263     GST_DEBUG_OBJECT (qtdemux,
9264         "Not all samples have the same size, not merging");
9265     return;
9266   }
9267 
9268   /* The stream has a ctts table, we don't support that */
9269   if (stream->ctts_present) {
9270     GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9271     return;
9272   }
9273 
9274   /* If there's a sync sample table also ignore this stream */
9275   if (stream->stps_present || stream->stss_present) {
9276     GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9277     return;
9278   }
9279 
9280   /* If chunks are considered samples already ignore this stream */
9281   if (stream->chunks_are_samples) {
9282     GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9283     return;
9284   }
9285 
9286   /* Require that all samples have the same duration */
9287   if (stream->n_sample_times > 1) {
9288     GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9289     return;
9290   }
9291 
9292   /* Parse the stts to get the sample duration and number of samples */
9293   gst_byte_reader_skip_unchecked (&stream->stts, 4);
9294   stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9295 
9296   /* Parse the number of chunks from the stco manually because the
9297    * reader is already behind that */
9298   num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9299 
9300   GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9301       num_chunks);
9302 
9303   /* Now parse stsc, convert chunks into single samples and generate a
9304    * new stsc, stts and stsz from this information */
9305   gst_byte_writer_init (&stsc);
9306   gst_byte_writer_init (&stts);
9307   gst_byte_writer_init (&stsz);
9308 
9309   /* Note: we skip fourccs, size, version, flags and other fields of the new
9310    * atoms as the byte readers with them are already behind that position
9311    * anyway and only update the values of those inside the stream directly.
9312    */
9313   stream->n_sample_times = 0;
9314   stream->n_samples = 0;
9315   for (i = 0; i < stream->n_samples_per_chunk; i++) {
9316     guint j;
9317     guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9318 
9319     first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9320     samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9321     sample_description_id =
9322         gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9323 
9324     if (i == stream->n_samples_per_chunk - 1) {
9325       /* +1 because first_chunk is 1-based */
9326       last_chunk = num_chunks + 1;
9327     } else {
9328       last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9329     }
9330 
9331     GST_DEBUG_OBJECT (qtdemux,
9332         "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9333         first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9334 
9335     gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9336     /* One sample in this chunk */
9337     gst_byte_writer_put_uint32_be (&stsc, 1);
9338     gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9339 
9340     /* For each chunk write a stts and stsz entry now */
9341     gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9342     gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9343     for (j = first_chunk; j < last_chunk; j++) {
9344       gst_byte_writer_put_uint32_be (&stsz,
9345           stream->sample_size * samples_per_chunk);
9346     }
9347 
9348     stream->n_sample_times += 1;
9349     stream->n_samples += last_chunk - first_chunk;
9350   }
9351 
9352   g_assert_cmpint (stream->n_samples, ==, num_chunks);
9353 
9354   GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9355       stream->n_samples, stream->n_sample_times);
9356 
9357   /* We don't have a fixed sample size anymore */
9358   stream->sample_size = 0;
9359 
9360   /* Free old data for the atoms */
9361   g_free ((gpointer) stream->stsz.data);
9362   stream->stsz.data = NULL;
9363   g_free ((gpointer) stream->stsc.data);
9364   stream->stsc.data = NULL;
9365   g_free ((gpointer) stream->stts.data);
9366   stream->stts.data = NULL;
9367 
9368   /* Store new data and replace byte readers */
9369   stream->stsz.size = gst_byte_writer_get_size (&stsz);
9370   stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9371   gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9372   stream->stts.size = gst_byte_writer_get_size (&stts);
9373   stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9374   gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9375   stream->stsc.size = gst_byte_writer_get_size (&stsc);
9376   stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9377   gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9378 }
9379 
9380 /* initialise bytereaders for stbl sub-atoms */
9381 static gboolean
qtdemux_stbl_init(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * stbl)9382 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9383 {
9384   stream->stbl_index = -1;      /* no samples have yet been parsed */
9385   stream->sample_index = -1;
9386 
9387   /* time-to-sample atom */
9388   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9389     goto corrupt_file;
9390 
9391   /* copy atom data into a new buffer for later use */
9392   stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9393 
9394   /* skip version + flags */
9395   if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9396       !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9397     goto corrupt_file;
9398   GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9399 
9400   /* make sure there's enough data */
9401   if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9402     stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9403     GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9404         stream->n_sample_times);
9405     if (!stream->n_sample_times)
9406       goto corrupt_file;
9407   }
9408 
9409   /* sync sample atom */
9410   stream->stps_present = FALSE;
9411   if ((stream->stss_present =
9412           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9413               &stream->stss) ? TRUE : FALSE) == TRUE) {
9414     /* copy atom data into a new buffer for later use */
9415     stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9416 
9417     /* skip version + flags */
9418     if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9419         !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9420       goto corrupt_file;
9421 
9422     if (stream->n_sample_syncs) {
9423       /* make sure there's enough data */
9424       if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9425         goto corrupt_file;
9426     }
9427 
9428     /* partial sync sample atom */
9429     if ((stream->stps_present =
9430             ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9431                 &stream->stps) ? TRUE : FALSE) == TRUE) {
9432       /* copy atom data into a new buffer for later use */
9433       stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9434 
9435       /* skip version + flags */
9436       if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9437           !gst_byte_reader_get_uint32_be (&stream->stps,
9438               &stream->n_sample_partial_syncs))
9439         goto corrupt_file;
9440 
9441       /* if there are no entries, the stss table contains the real
9442        * sync samples */
9443       if (stream->n_sample_partial_syncs) {
9444         /* make sure there's enough data */
9445         if (!qt_atom_parser_has_chunks (&stream->stps,
9446                 stream->n_sample_partial_syncs, 4))
9447           goto corrupt_file;
9448       }
9449     }
9450   }
9451 
9452   /* sample size */
9453   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9454     goto no_samples;
9455 
9456   /* copy atom data into a new buffer for later use */
9457   stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9458 
9459   /* skip version + flags */
9460   if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9461       !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9462     goto corrupt_file;
9463 
9464   if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9465     goto corrupt_file;
9466 
9467   if (!stream->n_samples)
9468     goto no_samples;
9469 
9470   /* sample-to-chunk atom */
9471   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9472     goto corrupt_file;
9473 
9474   /* copy atom data into a new buffer for later use */
9475   stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9476 
9477   /* skip version + flags */
9478   if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9479       !gst_byte_reader_get_uint32_be (&stream->stsc,
9480           &stream->n_samples_per_chunk))
9481     goto corrupt_file;
9482 
9483   GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9484       stream->n_samples_per_chunk);
9485 
9486   /* make sure there's enough data */
9487   if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9488           12))
9489     goto corrupt_file;
9490 
9491 
9492   /* chunk offset */
9493   if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9494     stream->co_size = sizeof (guint32);
9495   else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9496           &stream->stco))
9497     stream->co_size = sizeof (guint64);
9498   else
9499     goto corrupt_file;
9500 
9501   /* copy atom data into a new buffer for later use */
9502   stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9503 
9504   /* skip version + flags */
9505   if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9506     goto corrupt_file;
9507 
9508   /* chunks_are_samples == TRUE means treat chunks as samples */
9509   stream->chunks_are_samples = stream->sample_size
9510       && !CUR_STREAM (stream)->sampled;
9511   if (stream->chunks_are_samples) {
9512     /* treat chunks as samples */
9513     if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9514       goto corrupt_file;
9515   } else {
9516     /* skip number of entries */
9517     if (!gst_byte_reader_skip (&stream->stco, 4))
9518       goto corrupt_file;
9519 
9520     /* make sure there are enough data in the stsz atom */
9521     if (!stream->sample_size) {
9522       /* different sizes for each sample */
9523       if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9524         goto corrupt_file;
9525     }
9526   }
9527 
9528   /* composition time-to-sample */
9529   if ((stream->ctts_present =
9530           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9531               &stream->ctts) ? TRUE : FALSE) == TRUE) {
9532     GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9533     guint8 ctts_version;
9534     gboolean checked_ctts = FALSE;
9535 
9536     /* copy atom data into a new buffer for later use */
9537     stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9538 
9539     /* version 1 has signed offsets */
9540     if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9541       goto corrupt_file;
9542 
9543     /* flags */
9544     if (!gst_byte_reader_skip (&stream->ctts, 3)
9545         || !gst_byte_reader_get_uint32_be (&stream->ctts,
9546             &stream->n_composition_times))
9547       goto corrupt_file;
9548 
9549     /* make sure there's enough data */
9550     if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9551             4 + 4))
9552       goto corrupt_file;
9553 
9554     /* This is optional, if missing we iterate the ctts */
9555     if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9556       guint8 cslg_version;
9557 
9558       /* cslg version 1 has 64 bit fields */
9559       if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9560         goto corrupt_file;
9561 
9562       /* skip flags */
9563       if (!gst_byte_reader_skip (&cslg, 3))
9564         goto corrupt_file;
9565 
9566       if (cslg_version == 0) {
9567         gint32 composition_to_dts_shift;
9568 
9569         if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9570           goto corrupt_file;
9571 
9572         stream->cslg_shift = MAX (0, composition_to_dts_shift);
9573       } else {
9574         gint64 composition_to_dts_shift;
9575 
9576         if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9577           goto corrupt_file;
9578 
9579         stream->cslg_shift = MAX (0, composition_to_dts_shift);
9580       }
9581     } else {
9582       gint32 cslg_least = 0;
9583       guint num_entries, pos;
9584       gint i;
9585 
9586       pos = gst_byte_reader_get_pos (&stream->ctts);
9587       num_entries = stream->n_composition_times;
9588 
9589       checked_ctts = TRUE;
9590 
9591       stream->cslg_shift = 0;
9592 
9593       for (i = 0; i < num_entries; i++) {
9594         gint32 offset;
9595 
9596         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9597         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9598         /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9599          * slightly inaccurate PTS could be more usable than corrupted one */
9600         if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9601                 && ABS (offset) / 2 > stream->duration)) {
9602           GST_WARNING_OBJECT (qtdemux,
9603               "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9604               " larger than duration %" G_GUINT64_FORMAT, offset,
9605               stream->duration);
9606 
9607           stream->cslg_shift = 0;
9608           stream->ctts_present = FALSE;
9609           goto done;
9610         }
9611 
9612         /* Don't consider "no decode samples" with offset G_MININT32
9613          * for the DTS/PTS shift */
9614         if (offset != G_MININT32 && offset < cslg_least)
9615           cslg_least = offset;
9616       }
9617 
9618       if (cslg_least < 0)
9619         stream->cslg_shift = -cslg_least;
9620       else
9621         stream->cslg_shift = 0;
9622 
9623       /* reset the reader so we can generate sample table */
9624       gst_byte_reader_set_pos (&stream->ctts, pos);
9625     }
9626 
9627     /* Check if ctts values are looking reasonable if that didn't happen above */
9628     if (!checked_ctts) {
9629       guint num_entries, pos;
9630       gint i;
9631 
9632       pos = gst_byte_reader_get_pos (&stream->ctts);
9633       num_entries = stream->n_composition_times;
9634 
9635       for (i = 0; i < num_entries; i++) {
9636         gint32 offset;
9637 
9638         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9639         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9640         /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9641          * slightly inaccurate PTS could be more usable than corrupted one */
9642         if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9643                 && ABS (offset) / 2 > stream->duration)) {
9644           GST_WARNING_OBJECT (qtdemux,
9645               "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9646               " larger than duration %" G_GUINT64_FORMAT, offset,
9647               stream->duration);
9648 
9649           stream->cslg_shift = 0;
9650           stream->ctts_present = FALSE;
9651           goto done;
9652         }
9653       }
9654 
9655       /* reset the reader so we can generate sample table */
9656       gst_byte_reader_set_pos (&stream->ctts, pos);
9657     }
9658   } else {
9659     /* Ensure the cslg_shift value is consistent so we can use it
9660      * unconditionally to produce TS and Segment */
9661     stream->cslg_shift = 0;
9662   }
9663 
9664   GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9665       stream->cslg_shift);
9666 
9667   /* For raw audio streams especially we might want to merge the samples
9668    * to not output one audio sample per buffer. We're doing this here
9669    * before allocating the sample tables so that from this point onwards
9670    * the number of container samples are static */
9671   if (stream->min_buffer_size > 0) {
9672     qtdemux_merge_sample_table (qtdemux, stream);
9673   }
9674 
9675 done:
9676   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9677       stream->n_samples, (guint) sizeof (QtDemuxSample),
9678       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9679 
9680   if (stream->n_samples >=
9681       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9682     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9683         "be larger than %uMB (broken file?)", stream->n_samples,
9684         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9685     return FALSE;
9686   }
9687 
9688   g_assert (stream->samples == NULL);
9689   stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9690   if (!stream->samples) {
9691     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9692         stream->n_samples);
9693     return FALSE;
9694   }
9695 
9696   return TRUE;
9697 
9698 corrupt_file:
9699   {
9700     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9701         (_("This file is corrupt and cannot be played.")), (NULL));
9702     return FALSE;
9703   }
9704 no_samples:
9705   {
9706     gst_qtdemux_stbl_free (stream);
9707     if (!qtdemux->fragmented) {
9708       /* not quite good */
9709       GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9710       return FALSE;
9711     } else {
9712       /* may pick up samples elsewhere */
9713       return TRUE;
9714     }
9715   }
9716 }
9717 
9718 /* collect samples from the next sample to be parsed up to sample @n for @stream
9719  * by reading the info from @stbl
9720  *
9721  * This code can be executed from both the streaming thread and the seeking
9722  * thread so it takes the object lock to protect itself
9723  */
9724 static gboolean
qtdemux_parse_samples(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 n)9725 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9726 {
9727   gint i, j, k;
9728   QtDemuxSample *samples, *first, *cur, *last;
9729   guint32 n_samples_per_chunk;
9730   guint32 n_samples;
9731 
9732   GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9733       GST_FOURCC_FORMAT ", pad %s",
9734       GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9735       stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9736 
9737   n_samples = stream->n_samples;
9738 
9739   if (n >= n_samples)
9740     goto out_of_samples;
9741 
9742   GST_OBJECT_LOCK (qtdemux);
9743   if (n <= stream->stbl_index)
9744     goto already_parsed;
9745 
9746   GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9747 
9748   if (!stream->stsz.data) {
9749     /* so we already parsed and passed all the moov samples;
9750      * onto fragmented ones */
9751     g_assert (qtdemux->fragmented);
9752     goto done;
9753   }
9754 
9755   /* pointer to the sample table */
9756   samples = stream->samples;
9757 
9758   /* starts from -1, moves to the next sample index to parse */
9759   stream->stbl_index++;
9760 
9761   /* keep track of the first and last sample to fill */
9762   first = &samples[stream->stbl_index];
9763   last = &samples[n];
9764 
9765   if (!stream->chunks_are_samples) {
9766     /* set the sample sizes */
9767     if (stream->sample_size == 0) {
9768       /* different sizes for each sample */
9769       for (cur = first; cur <= last; cur++) {
9770         cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9771         GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9772             (guint) (cur - samples), cur->size);
9773       }
9774     } else {
9775       /* samples have the same size */
9776       GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9777       for (cur = first; cur <= last; cur++)
9778         cur->size = stream->sample_size;
9779     }
9780   }
9781 
9782   n_samples_per_chunk = stream->n_samples_per_chunk;
9783   cur = first;
9784 
9785   for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9786     guint32 last_chunk;
9787 
9788     if (stream->stsc_chunk_index >= stream->last_chunk
9789         || stream->stsc_chunk_index < stream->first_chunk) {
9790       stream->first_chunk =
9791           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9792       stream->samples_per_chunk =
9793           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9794       /* starts from 1 */
9795       stream->stsd_sample_description_id =
9796           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9797 
9798       /* chunk numbers are counted from 1 it seems */
9799       if (G_UNLIKELY (stream->first_chunk == 0))
9800         goto corrupt_file;
9801 
9802       --stream->first_chunk;
9803 
9804       /* the last chunk of each entry is calculated by taking the first chunk
9805        * of the next entry; except if there is no next, where we fake it with
9806        * INT_MAX */
9807       if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9808         stream->last_chunk = G_MAXUINT32;
9809       } else {
9810         stream->last_chunk =
9811             gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9812         if (G_UNLIKELY (stream->last_chunk == 0))
9813           goto corrupt_file;
9814 
9815         --stream->last_chunk;
9816       }
9817 
9818       GST_LOG_OBJECT (qtdemux,
9819           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9820           "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9821           stream->samples_per_chunk, stream->stsd_sample_description_id);
9822 
9823       if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9824         goto corrupt_file;
9825 
9826       if (stream->last_chunk != G_MAXUINT32) {
9827         if (!qt_atom_parser_peek_sub (&stream->stco,
9828                 stream->first_chunk * stream->co_size,
9829                 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9830                 &stream->co_chunk))
9831           goto corrupt_file;
9832 
9833       } else {
9834         stream->co_chunk = stream->stco;
9835         if (!gst_byte_reader_skip (&stream->co_chunk,
9836                 stream->first_chunk * stream->co_size))
9837           goto corrupt_file;
9838       }
9839 
9840       stream->stsc_chunk_index = stream->first_chunk;
9841     }
9842 
9843     last_chunk = stream->last_chunk;
9844 
9845     if (stream->chunks_are_samples) {
9846       cur = &samples[stream->stsc_chunk_index];
9847 
9848       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9849         if (j > n) {
9850           /* save state */
9851           stream->stsc_chunk_index = j;
9852           goto done;
9853         }
9854 
9855         cur->offset =
9856             qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9857             stream->co_size);
9858 
9859         GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9860             "%" G_GUINT64_FORMAT, j, cur->offset);
9861 
9862         if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9863             CUR_STREAM (stream)->bytes_per_frame > 0) {
9864           cur->size =
9865               (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9866               CUR_STREAM (stream)->samples_per_frame *
9867               CUR_STREAM (stream)->bytes_per_frame;
9868         } else {
9869           cur->size = stream->samples_per_chunk;
9870         }
9871 
9872         GST_DEBUG_OBJECT (qtdemux,
9873             "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9874             j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9875                     stream->stco_sample_index)), cur->size);
9876 
9877         cur->timestamp = stream->stco_sample_index;
9878         cur->duration = stream->samples_per_chunk;
9879         cur->keyframe = TRUE;
9880         cur++;
9881 
9882         stream->stco_sample_index += stream->samples_per_chunk;
9883       }
9884       stream->stsc_chunk_index = j;
9885     } else {
9886       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9887         guint32 samples_per_chunk;
9888         guint64 chunk_offset;
9889 
9890         if (!stream->stsc_sample_index
9891             && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9892                 &stream->chunk_offset))
9893           goto corrupt_file;
9894 
9895         samples_per_chunk = stream->samples_per_chunk;
9896         chunk_offset = stream->chunk_offset;
9897 
9898         for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9899           GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9900               G_GUINT64_FORMAT " and size %d",
9901               (guint) (cur - samples), chunk_offset, cur->size);
9902 
9903           cur->offset = chunk_offset;
9904           chunk_offset += cur->size;
9905           cur++;
9906 
9907           if (G_UNLIKELY (cur > last)) {
9908             /* save state */
9909             stream->stsc_sample_index = k + 1;
9910             stream->chunk_offset = chunk_offset;
9911             stream->stsc_chunk_index = j;
9912             goto done2;
9913           }
9914         }
9915         stream->stsc_sample_index = 0;
9916       }
9917       stream->stsc_chunk_index = j;
9918     }
9919     stream->stsc_index++;
9920   }
9921 
9922   if (stream->chunks_are_samples)
9923     goto ctts;
9924 done2:
9925   {
9926     guint32 n_sample_times;
9927 
9928     n_sample_times = stream->n_sample_times;
9929     cur = first;
9930 
9931     for (i = stream->stts_index; i < n_sample_times; i++) {
9932       guint32 stts_samples;
9933       gint32 stts_duration;
9934       gint64 stts_time;
9935 
9936       if (stream->stts_sample_index >= stream->stts_samples
9937           || !stream->stts_sample_index) {
9938 
9939         stream->stts_samples =
9940             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9941         stream->stts_duration =
9942             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9943 
9944         GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9945             i, stream->stts_samples, stream->stts_duration);
9946 
9947         stream->stts_sample_index = 0;
9948       }
9949 
9950       stts_samples = stream->stts_samples;
9951       stts_duration = stream->stts_duration;
9952       stts_time = stream->stts_time;
9953 
9954       for (j = stream->stts_sample_index; j < stts_samples; j++) {
9955         GST_DEBUG_OBJECT (qtdemux,
9956             "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9957             (guint) (cur - samples), j,
9958             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9959 
9960         cur->timestamp = stts_time;
9961         cur->duration = stts_duration;
9962 
9963         /* avoid 32-bit wrap-around,
9964          * but still mind possible 'negative' duration */
9965         stts_time += (gint64) stts_duration;
9966         cur++;
9967 
9968         if (G_UNLIKELY (cur > last)) {
9969           /* save values */
9970           stream->stts_time = stts_time;
9971           stream->stts_sample_index = j + 1;
9972           if (stream->stts_sample_index >= stream->stts_samples)
9973             stream->stts_index++;
9974           goto done3;
9975         }
9976       }
9977       stream->stts_sample_index = 0;
9978       stream->stts_time = stts_time;
9979       stream->stts_index++;
9980     }
9981     /* fill up empty timestamps with the last timestamp, this can happen when
9982      * the last samples do not decode and so we don't have timestamps for them.
9983      * We however look at the last timestamp to estimate the track length so we
9984      * need something in here. */
9985     for (; cur < last; cur++) {
9986       GST_DEBUG_OBJECT (qtdemux,
9987           "fill sample %d: timestamp %" GST_TIME_FORMAT,
9988           (guint) (cur - samples),
9989           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9990       cur->timestamp = stream->stts_time;
9991       cur->duration = -1;
9992     }
9993   }
9994 done3:
9995   {
9996     /* sample sync, can be NULL */
9997     if (stream->stss_present == TRUE) {
9998       guint32 n_sample_syncs;
9999 
10000       n_sample_syncs = stream->n_sample_syncs;
10001 
10002       if (!n_sample_syncs) {
10003         GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
10004         stream->all_keyframe = TRUE;
10005       } else {
10006         for (i = stream->stss_index; i < n_sample_syncs; i++) {
10007           /* note that the first sample is index 1, not 0 */
10008           guint32 index;
10009 
10010           index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
10011 
10012           if (G_LIKELY (index > 0 && index <= n_samples)) {
10013             index -= 1;
10014             samples[index].keyframe = TRUE;
10015             GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10016             /* and exit if we have enough samples */
10017             if (G_UNLIKELY (index >= n)) {
10018               i++;
10019               break;
10020             }
10021           }
10022         }
10023         /* save state */
10024         stream->stss_index = i;
10025       }
10026 
10027       /* stps marks partial sync frames like open GOP I-Frames */
10028       if (stream->stps_present == TRUE) {
10029         guint32 n_sample_partial_syncs;
10030 
10031         n_sample_partial_syncs = stream->n_sample_partial_syncs;
10032 
10033         /* if there are no entries, the stss table contains the real
10034          * sync samples */
10035         if (n_sample_partial_syncs) {
10036           for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
10037             /* note that the first sample is index 1, not 0 */
10038             guint32 index;
10039 
10040             index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10041 
10042             if (G_LIKELY (index > 0 && index <= n_samples)) {
10043               index -= 1;
10044               samples[index].keyframe = TRUE;
10045               GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10046               /* and exit if we have enough samples */
10047               if (G_UNLIKELY (index >= n)) {
10048                 i++;
10049                 break;
10050               }
10051             }
10052           }
10053           /* save state */
10054           stream->stps_index = i;
10055         }
10056       }
10057     } else {
10058       /* no stss, all samples are keyframes */
10059       stream->all_keyframe = TRUE;
10060       GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10061     }
10062   }
10063 
10064 ctts:
10065   /* composition time to sample */
10066   if (stream->ctts_present == TRUE) {
10067     guint32 n_composition_times;
10068     guint32 ctts_count;
10069     gint32 ctts_soffset;
10070 
10071     /* Fill in the pts_offsets */
10072     cur = first;
10073     n_composition_times = stream->n_composition_times;
10074 
10075     for (i = stream->ctts_index; i < n_composition_times; i++) {
10076       if (stream->ctts_sample_index >= stream->ctts_count
10077           || !stream->ctts_sample_index) {
10078         stream->ctts_count =
10079             gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10080         stream->ctts_soffset =
10081             gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10082         stream->ctts_sample_index = 0;
10083       }
10084 
10085       ctts_count = stream->ctts_count;
10086       ctts_soffset = stream->ctts_soffset;
10087 
10088       /* FIXME: Set offset to 0 for "no decode samples". This needs
10089        * to be handled in a codec specific manner ideally. */
10090       if (ctts_soffset == G_MININT32)
10091         ctts_soffset = 0;
10092 
10093       for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10094         cur->pts_offset = ctts_soffset;
10095         cur++;
10096 
10097         if (G_UNLIKELY (cur > last)) {
10098           /* save state */
10099           stream->ctts_sample_index = j + 1;
10100           goto done;
10101         }
10102       }
10103       stream->ctts_sample_index = 0;
10104       stream->ctts_index++;
10105     }
10106   }
10107 done:
10108   stream->stbl_index = n;
10109   /* if index has been completely parsed, free data that is no-longer needed */
10110   if (n + 1 == stream->n_samples) {
10111     gst_qtdemux_stbl_free (stream);
10112     GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10113     if (qtdemux->pullbased) {
10114       GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10115       while (n + 1 == stream->n_samples)
10116         if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10117           break;
10118     }
10119   }
10120   GST_OBJECT_UNLOCK (qtdemux);
10121 
10122   return TRUE;
10123 
10124   /* SUCCESS */
10125 already_parsed:
10126   {
10127     GST_LOG_OBJECT (qtdemux,
10128         "Tried to parse up to sample %u but this sample has already been parsed",
10129         n);
10130     /* if fragmented, there may be more */
10131     if (qtdemux->fragmented && n == stream->stbl_index)
10132       goto done;
10133     GST_OBJECT_UNLOCK (qtdemux);
10134     return TRUE;
10135   }
10136   /* ERRORS */
10137 out_of_samples:
10138   {
10139     GST_LOG_OBJECT (qtdemux,
10140         "Tried to parse up to sample %u but there are only %u samples", n + 1,
10141         stream->n_samples);
10142     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10143         (_("This file is corrupt and cannot be played.")), (NULL));
10144     return FALSE;
10145   }
10146 corrupt_file:
10147   {
10148     GST_OBJECT_UNLOCK (qtdemux);
10149     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10150         (_("This file is corrupt and cannot be played.")), (NULL));
10151     return FALSE;
10152   }
10153 }
10154 
10155 /* collect all segment info for @stream.
10156  */
10157 static gboolean
qtdemux_parse_segments(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * trak)10158 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10159     GNode * trak)
10160 {
10161   GNode *edts;
10162   /* accept edts if they contain gaps at start and there is only
10163    * one media segment */
10164   gboolean allow_pushbased_edts = TRUE;
10165   gint media_segments_count = 0;
10166 
10167   /* parse and prepare segment info from the edit list */
10168   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10169   stream->n_segments = 0;
10170   stream->segments = NULL;
10171   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10172     GNode *elst;
10173     gint n_segments;
10174     gint segment_number, entry_size;
10175     guint64 time;
10176     GstClockTime stime;
10177     const guint8 *buffer;
10178     guint8 version;
10179     guint32 size;
10180 
10181     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10182     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10183       goto done;
10184 
10185     buffer = elst->data;
10186 
10187     size = QT_UINT32 (buffer);
10188     /* version, flags, n_segments */
10189     if (size < 16) {
10190       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10191       goto done;
10192     }
10193     version = QT_UINT8 (buffer + 8);
10194     entry_size = (version == 1) ? 20 : 12;
10195 
10196     n_segments = QT_UINT32 (buffer + 12);
10197 
10198     if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10199       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10200       goto done;
10201     }
10202 
10203     /* we might allocate a bit too much, at least allocate 1 segment */
10204     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10205 
10206     /* segments always start from 0 */
10207     time = 0;
10208     stime = 0;
10209     buffer += 16;
10210     for (segment_number = 0; segment_number < n_segments; segment_number++) {
10211       guint64 duration;
10212       guint64 media_time;
10213       gboolean empty_edit = FALSE;
10214       QtDemuxSegment *segment;
10215       guint32 rate_int;
10216       GstClockTime media_start = GST_CLOCK_TIME_NONE;
10217 
10218       if (version == 1) {
10219         media_time = QT_UINT64 (buffer + 8);
10220         duration = QT_UINT64 (buffer);
10221         if (media_time == G_MAXUINT64)
10222           empty_edit = TRUE;
10223       } else {
10224         media_time = QT_UINT32 (buffer + 4);
10225         duration = QT_UINT32 (buffer);
10226         if (media_time == G_MAXUINT32)
10227           empty_edit = TRUE;
10228       }
10229 
10230       if (!empty_edit)
10231         media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10232 
10233       segment = &stream->segments[segment_number];
10234 
10235       /* time and duration expressed in global timescale */
10236       segment->time = stime;
10237       if (duration != 0 || empty_edit) {
10238         /* edge case: empty edits with duration=zero are treated here.
10239          * (files should not have these anyway). */
10240 
10241         /* add non scaled values so we don't cause roundoff errors */
10242         time += duration;
10243         stime = QTTIME_TO_GSTTIME (qtdemux, time);
10244         segment->duration = stime - segment->time;
10245       } else {
10246         /* zero duration does not imply media_start == media_stop
10247          * but, only specify media_start. The edit ends with the track. */
10248         stime = segment->duration = GST_CLOCK_TIME_NONE;
10249         /* Don't allow more edits after this one. */
10250         n_segments = segment_number + 1;
10251       }
10252       segment->stop_time = stime;
10253 
10254       segment->trak_media_start = media_time;
10255       /* media_time expressed in stream timescale */
10256       if (!empty_edit) {
10257         segment->media_start = media_start;
10258         segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10259             ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10260         media_segments_count++;
10261       } else {
10262         segment->media_start = GST_CLOCK_TIME_NONE;
10263         segment->media_stop = GST_CLOCK_TIME_NONE;
10264       }
10265       rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10266 
10267       if (rate_int <= 1) {
10268         /* 0 is not allowed, some programs write 1 instead of the floating point
10269          * value */
10270         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10271             rate_int);
10272         segment->rate = 1;
10273       } else {
10274         segment->rate = rate_int / 65536.0;
10275       }
10276 
10277       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10278           ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10279           " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10280           " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10281           segment_number, GST_TIME_ARGS (segment->time),
10282           GST_TIME_ARGS (segment->duration),
10283           GST_TIME_ARGS (segment->media_start), media_time,
10284           GST_TIME_ARGS (segment->media_stop),
10285           GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10286           stream->timescale);
10287       if (segment->stop_time > qtdemux->segment.stop &&
10288           !qtdemux->upstream_format_is_time) {
10289         GST_WARNING_OBJECT (qtdemux, "Segment %d "
10290             " extends to %" GST_TIME_FORMAT
10291             " past the end of the declared movie duration %" GST_TIME_FORMAT
10292             " movie segment will be extended", segment_number,
10293             GST_TIME_ARGS (segment->stop_time),
10294             GST_TIME_ARGS (qtdemux->segment.stop));
10295         qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10296       }
10297 
10298       buffer += entry_size;
10299     }
10300     GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10301     stream->n_segments = n_segments;
10302     if (media_segments_count != 1)
10303       allow_pushbased_edts = FALSE;
10304   }
10305 done:
10306 
10307   /* push based does not handle segments, so act accordingly here,
10308    * and warn if applicable */
10309   if (!qtdemux->pullbased && !allow_pushbased_edts) {
10310     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10311     /* remove and use default one below, we stream like it anyway */
10312     g_free (stream->segments);
10313     stream->segments = NULL;
10314     stream->n_segments = 0;
10315   }
10316 
10317   /* no segments, create one to play the complete trak */
10318   if (stream->n_segments == 0) {
10319     GstClockTime stream_duration =
10320         QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10321 
10322     if (stream->segments == NULL)
10323       stream->segments = g_new (QtDemuxSegment, 1);
10324 
10325     /* represent unknown our way */
10326     if (stream_duration == 0)
10327       stream_duration = GST_CLOCK_TIME_NONE;
10328 
10329     stream->segments[0].time = 0;
10330     stream->segments[0].stop_time = stream_duration;
10331     stream->segments[0].duration = stream_duration;
10332     stream->segments[0].media_start = 0;
10333     stream->segments[0].media_stop = stream_duration;
10334     stream->segments[0].rate = 1.0;
10335     stream->segments[0].trak_media_start = 0;
10336 
10337     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10338         GST_TIME_ARGS (stream_duration));
10339     stream->n_segments = 1;
10340     stream->dummy_segment = TRUE;
10341   }
10342   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10343 
10344   return TRUE;
10345 }
10346 
10347 /*
10348  * Parses the stsd atom of a svq3 trak looking for
10349  * the SMI and gama atoms.
10350  */
10351 static void
qtdemux_parse_svq3_stsd_data(GstQTDemux * qtdemux,const guint8 * stsd_entry_data,const guint8 ** gamma,GstBuffer ** seqh)10352 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10353     const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10354 {
10355   const guint8 *_gamma = NULL;
10356   GstBuffer *_seqh = NULL;
10357   const guint8 *stsd_data = stsd_entry_data;
10358   guint32 length = QT_UINT32 (stsd_data);
10359   guint16 version;
10360 
10361   if (length < 32) {
10362     GST_WARNING_OBJECT (qtdemux, "stsd too short");
10363     goto end;
10364   }
10365 
10366   stsd_data += 16;
10367   length -= 16;
10368   version = QT_UINT16 (stsd_data);
10369   if (version == 3) {
10370     if (length >= 70) {
10371       length -= 70;
10372       stsd_data += 70;
10373       while (length > 8) {
10374         guint32 fourcc, size;
10375         const guint8 *data;
10376         size = QT_UINT32 (stsd_data);
10377         fourcc = QT_FOURCC (stsd_data + 4);
10378         data = stsd_data + 8;
10379 
10380         if (size == 0) {
10381           GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10382               "svq3 atom parsing");
10383           goto end;
10384         }
10385 
10386         switch (fourcc) {
10387           case FOURCC_gama:{
10388             if (size == 12) {
10389               _gamma = data;
10390             } else {
10391               GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10392                   " for gama atom, expected 12", size);
10393             }
10394             break;
10395           }
10396           case FOURCC_SMI_:{
10397             if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10398               guint32 seqh_size;
10399               if (_seqh != NULL) {
10400                 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10401                     " found, ignoring");
10402               } else {
10403                 seqh_size = QT_UINT32 (data + 4);
10404                 if (seqh_size > 0) {
10405                   _seqh = gst_buffer_new_and_alloc (seqh_size);
10406                   gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10407                 }
10408               }
10409             }
10410             break;
10411           }
10412           default:{
10413             GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10414                 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10415           }
10416         }
10417 
10418         if (size <= length) {
10419           length -= size;
10420           stsd_data += size;
10421         }
10422       }
10423     } else {
10424       GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10425     }
10426   } else {
10427     GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10428         G_GUINT16_FORMAT, version);
10429     goto end;
10430   }
10431 
10432 end:
10433   if (gamma) {
10434     *gamma = _gamma;
10435   }
10436   if (seqh) {
10437     *seqh = _seqh;
10438   } else if (_seqh) {
10439     gst_buffer_unref (_seqh);
10440   }
10441 }
10442 
10443 static gchar *
qtdemux_get_rtsp_uri_from_hndl(GstQTDemux * qtdemux,GNode * minf)10444 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10445 {
10446   GNode *dinf;
10447   GstByteReader dref;
10448   gchar *uri = NULL;
10449 
10450   /*
10451    * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10452    * atom that might contain a 'data' atom with the rtsp uri.
10453    * This case was reported in bug #597497, some info about
10454    * the hndl atom can be found in TN1195
10455    */
10456   dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10457   GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10458 
10459   if (dinf) {
10460     guint32 dref_num_entries = 0;
10461     if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10462         gst_byte_reader_skip (&dref, 4) &&
10463         gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10464       gint i;
10465 
10466       /* search dref entries for hndl atom */
10467       for (i = 0; i < dref_num_entries; i++) {
10468         guint32 size = 0, type;
10469         guint8 string_len = 0;
10470         if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10471             qt_atom_parser_get_fourcc (&dref, &type)) {
10472           if (type == FOURCC_hndl) {
10473             GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10474 
10475             /* skip data reference handle bytes and the
10476              * following pascal string and some extra 4
10477              * bytes I have no idea what are */
10478             if (!gst_byte_reader_skip (&dref, 4) ||
10479                 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10480                 !gst_byte_reader_skip (&dref, string_len + 4)) {
10481               GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10482               break;
10483             }
10484 
10485             /* iterate over the atoms to find the data atom */
10486             while (gst_byte_reader_get_remaining (&dref) >= 8) {
10487               guint32 atom_size;
10488               guint32 atom_type;
10489 
10490               if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10491                   qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10492                 if (atom_type == FOURCC_data) {
10493                   const guint8 *uri_aux = NULL;
10494 
10495                   /* found the data atom that might contain the rtsp uri */
10496                   GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10497                       "hndl atom, interpreting it as an URI");
10498                   if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10499                           &uri_aux)) {
10500                     if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10501                       uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10502                     else
10503                       GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10504                           "didn't contain a rtsp address");
10505                   } else {
10506                     GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10507                         "atom contents");
10508                   }
10509                   break;
10510                 }
10511                 /* skipping to the next entry */
10512                 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10513                   break;
10514               } else {
10515                 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10516                     "atom header");
10517                 break;
10518               }
10519             }
10520             break;
10521           }
10522           /* skip to the next entry */
10523           if (!gst_byte_reader_skip (&dref, size - 8))
10524             break;
10525         } else {
10526           GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10527         }
10528       }
10529       GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10530     }
10531   }
10532   return uri;
10533 }
10534 
10535 #define AMR_NB_ALL_MODES        0x81ff
10536 #define AMR_WB_ALL_MODES        0x83ff
10537 static guint
qtdemux_parse_amr_bitrate(GstBuffer * buf,gboolean wb)10538 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10539 {
10540   /* The 'damr' atom is of the form:
10541    *
10542    * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10543    *    32 b       8 b          16 b           8 b                 8 b
10544    *
10545    * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10546    * represents the highest mode used in the stream (and thus the maximum
10547    * bitrate), with a couple of special cases as seen below.
10548    */
10549 
10550   /* Map of frame type ID -> bitrate */
10551   static const guint nb_bitrates[] = {
10552     4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10553   };
10554   static const guint wb_bitrates[] = {
10555     6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10556   };
10557   GstMapInfo map;
10558   gsize max_mode;
10559   guint16 mode_set;
10560 
10561   gst_buffer_map (buf, &map, GST_MAP_READ);
10562 
10563   if (map.size != 0x11) {
10564     GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10565     goto bad_data;
10566   }
10567 
10568   if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10569     GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10570         GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10571     goto bad_data;
10572   }
10573 
10574   mode_set = QT_UINT16 (map.data + 13);
10575 
10576   if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10577     max_mode = 7 + (wb ? 1 : 0);
10578   else
10579     /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10580     max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10581 
10582   if (max_mode == -1) {
10583     GST_DEBUG ("No mode indication was found (mode set) = %x",
10584         (guint) mode_set);
10585     goto bad_data;
10586   }
10587 
10588   gst_buffer_unmap (buf, &map);
10589   return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10590 
10591 bad_data:
10592   gst_buffer_unmap (buf, &map);
10593   return 0;
10594 }
10595 
10596 static gboolean
qtdemux_parse_transformation_matrix(GstQTDemux * qtdemux,GstByteReader * reader,guint32 * matrix,const gchar * atom)10597 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10598     GstByteReader * reader, guint32 * matrix, const gchar * atom)
10599 {
10600   /*
10601    * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10602    * [0 1 2]
10603    * [3 4 5]
10604    * [6 7 8]
10605    */
10606 
10607   if (gst_byte_reader_get_remaining (reader) < 36)
10608     return FALSE;
10609 
10610   matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10611   matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10612   matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10613   matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10614   matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10615   matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10616   matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10617   matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10618   matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10619 
10620   GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10621   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10622       matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10623       matrix[2] & 0xFF);
10624   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10625       matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10626       matrix[5] & 0xFF);
10627   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10628       matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10629       matrix[8] & 0xFF);
10630 
10631   return TRUE;
10632 }
10633 
10634 static void
qtdemux_inspect_transformation_matrix(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 * matrix,GstTagList ** taglist)10635 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10636     QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10637 {
10638 
10639 /* [a b c]
10640  * [d e f]
10641  * [g h i]
10642  *
10643  * This macro will only compare value abdegh, it expects cfi to have already
10644  * been checked
10645  */
10646 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10647                                    (m)[3] == (d << 16) && (m)[4] == (e << 16))
10648 
10649   /* only handle the cases where the last column has standard values */
10650   if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10651     const gchar *rotation_tag = NULL;
10652 
10653     /* no rotation needed */
10654     if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10655       /* NOP */
10656     } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10657       rotation_tag = "rotate-90";
10658     } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10659       rotation_tag = "rotate-180";
10660     } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10661       rotation_tag = "rotate-270";
10662     } else {
10663       GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10664     }
10665 
10666     GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10667         GST_STR_NULL (rotation_tag));
10668     if (rotation_tag != NULL) {
10669       if (*taglist == NULL)
10670         *taglist = gst_tag_list_new_empty ();
10671       gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10672           GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10673 #ifdef OHOS_EXT_FUNC
10674 // ohos.ext.func.0032
10675       GstMessage *msg_video_rotation = gst_message_new_video_rotation (GST_OBJECT (qtdemux), rotation_tag);
10676       if (msg_video_rotation != NULL) {
10677         gst_element_post_message (GST_ELEMENT (qtdemux), msg_video_rotation);
10678       }
10679 #endif
10680     }
10681   } else {
10682     GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10683   }
10684 }
10685 
10686 static gboolean
qtdemux_parse_protection_aavd(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * container,guint32 * original_fmt)10687 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10688     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10689 {
10690   GNode *adrm;
10691   guint32 adrm_size;
10692   GstBuffer *adrm_buf = NULL;
10693   QtDemuxAavdEncryptionInfo *info;
10694 
10695   adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10696   if (G_UNLIKELY (!adrm)) {
10697     GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10698     return FALSE;
10699   }
10700   adrm_size = QT_UINT32 (adrm->data);
10701   adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10702 
10703   stream->protection_scheme_type = FOURCC_aavd;
10704 
10705   if (!stream->protection_scheme_info)
10706     stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10707 
10708   info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10709 
10710   if (info->default_properties)
10711     gst_structure_free (info->default_properties);
10712   info->default_properties = gst_structure_new ("application/x-aavd",
10713       "encrypted", G_TYPE_BOOLEAN, TRUE,
10714       "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10715   gst_buffer_unref (adrm_buf);
10716 
10717   *original_fmt = FOURCC_mp4a;
10718   return TRUE;
10719 }
10720 
10721 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10722  * protected streams (sinf, frma, schm and schi); if the protection scheme is
10723  * Common Encryption (cenc), the function will also parse the tenc box (defined
10724  * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10725  * (typically an enc[v|a|t|s] sample entry); the function will set
10726  * @original_fmt to the fourcc of the original unencrypted stream format.
10727  * Returns TRUE if successful; FALSE otherwise. */
10728 static gboolean
qtdemux_parse_protection_scheme_info(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * container,guint32 * original_fmt)10729 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10730     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10731 {
10732   GNode *sinf;
10733   GNode *frma;
10734   GNode *schm;
10735   GNode *schi;
10736   QtDemuxCencSampleSetInfo *info;
10737   GNode *tenc;
10738   const guint8 *tenc_data;
10739 
10740   g_return_val_if_fail (qtdemux != NULL, FALSE);
10741   g_return_val_if_fail (stream != NULL, FALSE);
10742   g_return_val_if_fail (container != NULL, FALSE);
10743   g_return_val_if_fail (original_fmt != NULL, FALSE);
10744 
10745   sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10746   if (G_UNLIKELY (!sinf)) {
10747     if (stream->protection_scheme_type == FOURCC_cenc
10748         || stream->protection_scheme_type == FOURCC_cbcs) {
10749       GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10750           "mandatory for Common Encryption");
10751       return FALSE;
10752     }
10753     return TRUE;
10754   }
10755 
10756   frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10757   if (G_UNLIKELY (!frma)) {
10758     GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10759     return FALSE;
10760   }
10761 
10762   *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10763   GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10764       GST_FOURCC_ARGS (*original_fmt));
10765 
10766   schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10767   if (!schm) {
10768     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10769     return FALSE;
10770   }
10771   stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10772   stream->protection_scheme_version =
10773       QT_UINT32 ((const guint8 *) schm->data + 16);
10774 
10775   GST_DEBUG_OBJECT (qtdemux,
10776       "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10777       "protection_scheme_version: %#010x",
10778       GST_FOURCC_ARGS (stream->protection_scheme_type),
10779       stream->protection_scheme_version);
10780 
10781   schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10782   if (!schi) {
10783     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10784     return FALSE;
10785   }
10786   if (stream->protection_scheme_type != FOURCC_cenc &&
10787       stream->protection_scheme_type != FOURCC_piff &&
10788       stream->protection_scheme_type != FOURCC_cbcs) {
10789     GST_ERROR_OBJECT (qtdemux,
10790         "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10791         GST_FOURCC_ARGS (stream->protection_scheme_type));
10792     return FALSE;
10793   }
10794 
10795   if (G_UNLIKELY (!stream->protection_scheme_info))
10796     stream->protection_scheme_info =
10797         g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10798 
10799   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10800 
10801   if (stream->protection_scheme_type == FOURCC_cenc
10802       || stream->protection_scheme_type == FOURCC_cbcs) {
10803     guint8 is_encrypted;
10804     guint8 iv_size;
10805     guint8 constant_iv_size = 0;
10806     const guint8 *default_kid;
10807     guint8 crypt_byte_block = 0;
10808     guint8 skip_byte_block = 0;
10809     const guint8 *constant_iv = NULL;
10810 
10811     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10812     if (!tenc) {
10813       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10814           "which is mandatory for Common Encryption");
10815       return FALSE;
10816     }
10817     tenc_data = (const guint8 *) tenc->data + 12;
10818     is_encrypted = QT_UINT8 (tenc_data + 2);
10819     iv_size = QT_UINT8 (tenc_data + 3);
10820     default_kid = (tenc_data + 4);
10821     if (stream->protection_scheme_type == FOURCC_cbcs) {
10822       guint8 possible_pattern_info;
10823       if (iv_size == 0) {
10824         constant_iv_size = QT_UINT8 (tenc_data + 20);
10825         if (constant_iv_size != 8 && constant_iv_size != 16) {
10826           GST_ERROR_OBJECT (qtdemux,
10827               "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10828           return FALSE;
10829         }
10830         constant_iv = (tenc_data + 21);
10831       }
10832       possible_pattern_info = QT_UINT8 (tenc_data + 1);
10833       crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10834       skip_byte_block = possible_pattern_info & 0x0f;
10835     }
10836     qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10837         is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10838         crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10839   } else if (stream->protection_scheme_type == FOURCC_piff) {
10840     GstByteReader br;
10841     static const guint8 piff_track_encryption_uuid[] = {
10842       0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10843       0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10844     };
10845 
10846     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10847     if (!tenc) {
10848       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10849           "which is mandatory for Common Encryption");
10850       return FALSE;
10851     }
10852 
10853     tenc_data = (const guint8 *) tenc->data + 8;
10854     if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10855       gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10856       GST_ERROR_OBJECT (qtdemux,
10857           "Unsupported track encryption box with uuid: %s", box_uuid);
10858       g_free (box_uuid);
10859       return FALSE;
10860     }
10861     tenc_data = (const guint8 *) tenc->data + 16 + 12;
10862     gst_byte_reader_init (&br, tenc_data, 20);
10863     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10864       GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10865       return FALSE;
10866     }
10867     stream->protection_scheme_type = FOURCC_cenc;
10868   }
10869 
10870   return TRUE;
10871 }
10872 
10873 static gint
qtdemux_track_id_compare_func(QtDemuxStream ** stream1,QtDemuxStream ** stream2)10874 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10875     QtDemuxStream ** stream2)
10876 {
10877   return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10878 }
10879 
10880 static gboolean
qtdemux_parse_stereo_svmi_atom(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * stbl)10881 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10882     GNode * stbl)
10883 {
10884   GNode *svmi;
10885 
10886   /*parse svmi header if existing */
10887   svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10888   if (svmi) {
10889     guint len = QT_UINT32 ((guint8 *) svmi->data);
10890     guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10891     if (!version) {
10892       GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10893       GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10894       guint8 frame_type, frame_layout;
10895       guint32 stereo_mono_change_count;
10896 
10897       if (len < 18)
10898         return FALSE;
10899 
10900       /* MPEG-A stereo video */
10901       if (qtdemux->major_brand == FOURCC_ss02)
10902         flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10903 
10904       frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10905       frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10906       stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10907 
10908       switch (frame_type) {
10909         case 0:
10910           mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10911           break;
10912         case 1:
10913           mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10914           break;
10915         case 2:
10916           mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10917           break;
10918         case 3:
10919           /* mode 3 is primary/secondary view sequence, ie
10920            * left/right views in separate tracks. See section 7.2
10921            * of ISO/IEC 23000-11:2009 */
10922           /* In the future this might be supported using related
10923            * streams, like an enhancement track - if files like this
10924            * ever exist */
10925           GST_FIXME_OBJECT (qtdemux,
10926               "Implement stereo video in separate streams");
10927       }
10928 
10929       if ((frame_layout & 0x1) == 0)
10930         flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10931 
10932       GST_LOG_OBJECT (qtdemux,
10933           "StereoVideo: composition type: %u, is_left_first: %u",
10934           frame_type, frame_layout);
10935 
10936       if (stereo_mono_change_count > 1) {
10937         GST_FIXME_OBJECT (qtdemux,
10938             "Mixed-mono flags are not yet supported in qtdemux.");
10939       }
10940 
10941       stream->multiview_mode = mode;
10942       stream->multiview_flags = flags;
10943     }
10944   }
10945 
10946   return TRUE;
10947 }
10948 
10949 /* parse the traks.
10950  * With each track we associate a new QtDemuxStream that contains all the info
10951  * about the trak.
10952  * traks that do not decode to something (like strm traks) will not have a pad.
10953  */
10954 static gboolean
qtdemux_parse_trak(GstQTDemux * qtdemux,GNode * trak)10955 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10956 {
10957   GstByteReader tkhd;
10958   int offset;
10959   GNode *mdia;
10960   GNode *mdhd;
10961   GNode *hdlr;
10962   GNode *minf;
10963   GNode *stbl;
10964   GNode *stsd;
10965   GNode *mp4a;
10966   GNode *mp4v;
10967   GNode *esds;
10968   GNode *tref;
10969   GNode *udta;
10970 
10971   QtDemuxStream *stream = NULL;
10972   const guint8 *stsd_data;
10973   const guint8 *stsd_entry_data;
10974   guint remaining_stsd_len;
10975   guint stsd_entry_count;
10976   guint stsd_index;
10977   guint16 lang_code;            /* quicktime lang code or packed iso code */
10978   guint32 version;
10979   guint32 tkhd_flags = 0;
10980   guint8 tkhd_version = 0;
10981   guint32 w = 0, h = 0;
10982   guint value_size, stsd_len, len;
10983   guint32 track_id;
10984   guint32 dummy;
10985 
10986   GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10987 
10988   if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10989       || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10990       || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10991     goto corrupt_file;
10992 
10993   /* pick between 64 or 32 bits */
10994   value_size = tkhd_version == 1 ? 8 : 4;
10995   if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10996       !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10997     goto corrupt_file;
10998 
10999   /* Check if current moov has duplicated track_id */
11000   if (qtdemux_find_stream (qtdemux, track_id))
11001     goto existing_stream;
11002 
11003   stream = _create_stream (qtdemux, track_id);
11004   stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11005 
11006   /* need defaults for fragments */
11007   qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
11008 
11009   if ((tkhd_flags & 1) == 0)
11010     stream->disabled = TRUE;
11011 
11012   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
11013       tkhd_version, tkhd_flags, stream->track_id);
11014 
11015   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
11016     goto corrupt_file;
11017 
11018   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
11019     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
11020     if (qtdemux->major_brand != FOURCC_mjp2 ||
11021         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
11022       goto corrupt_file;
11023   }
11024 
11025   len = QT_UINT32 ((guint8 *) mdhd->data);
11026   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
11027   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
11028   if (version == 0x01000000) {
11029     if (len < 42)
11030       goto corrupt_file;
11031     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
11032     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
11033     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
11034   } else {
11035     if (len < 30)
11036       goto corrupt_file;
11037     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
11038     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
11039     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
11040   }
11041 
11042   if (lang_code < 0x400) {
11043     qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
11044   } else if (lang_code == 0x7fff) {
11045     stream->lang_id[0] = 0;     /* unspecified */
11046   } else {
11047     stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11048     stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11049     stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11050     stream->lang_id[3] = 0;
11051   }
11052 
11053   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11054       stream->timescale);
11055   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11056       stream->duration);
11057   GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11058       lang_code, stream->lang_id);
11059 
11060   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11061     goto corrupt_file;
11062 
11063   if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11064     /* chapters track reference */
11065     GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11066     if (chap) {
11067       gsize length = GST_READ_UINT32_BE (chap->data);
11068       if (qtdemux->chapters_track_id)
11069         GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11070 
11071       if (length >= 12) {
11072         qtdemux->chapters_track_id =
11073             GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11074       }
11075     }
11076   }
11077 
11078   /* fragmented files may have bogus duration in moov */
11079   if (!qtdemux->fragmented &&
11080       qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11081     guint64 tdur1, tdur2;
11082 
11083     /* don't overflow */
11084     tdur1 = stream->timescale * (guint64) qtdemux->duration;
11085     tdur2 = qtdemux->timescale * (guint64) stream->duration;
11086 
11087     /* HACK:
11088      * some of those trailers, nowadays, have prologue images that are
11089      * themselves video tracks as well. I haven't really found a way to
11090      * identify those yet, except for just looking at their duration. */
11091     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11092       GST_WARNING_OBJECT (qtdemux,
11093           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11094           " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11095           "found, assuming preview image or something; skipping track",
11096           stream->duration, stream->timescale, qtdemux->duration,
11097           qtdemux->timescale);
11098       gst_qtdemux_stream_unref (stream);
11099       return TRUE;
11100     }
11101   }
11102 
11103   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11104     goto corrupt_file;
11105 
11106   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11107       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11108 
11109   len = QT_UINT32 ((guint8 *) hdlr->data);
11110   if (len >= 20)
11111     stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11112   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11113       GST_FOURCC_ARGS (stream->subtype));
11114 
11115   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11116     goto corrupt_file;
11117 
11118   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11119     goto corrupt_file;
11120 
11121   /* Parse out svmi (and later st3d/sv3d) atoms */
11122   if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11123     goto corrupt_file;
11124 
11125   /* parse rest of tkhd */
11126   if (stream->subtype == FOURCC_vide) {
11127     guint32 matrix[9];
11128 
11129     /* version 1 uses some 64-bit ints */
11130     if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11131       goto corrupt_file;
11132 
11133     if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11134       goto corrupt_file;
11135 
11136     if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11137         || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11138       goto corrupt_file;
11139 
11140     qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11141         &stream->stream_tags);
11142   }
11143 
11144   /* parse stsd */
11145   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11146     goto corrupt_file;
11147   stsd_data = (const guint8 *) stsd->data;
11148 
11149   /* stsd should at least have one entry */
11150   stsd_len = QT_UINT32 (stsd_data);
11151   if (stsd_len < 24) {
11152     /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11153     if (stream->subtype == FOURCC_vivo) {
11154       gst_qtdemux_stream_unref (stream);
11155       return TRUE;
11156     } else {
11157       goto corrupt_file;
11158     }
11159   }
11160 
11161   stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11162   /* each stsd entry must contain at least 8 bytes */
11163   if (stream->stsd_entries_length == 0
11164       || stream->stsd_entries_length > stsd_len / 8) {
11165     stream->stsd_entries_length = 0;
11166     goto corrupt_file;
11167   }
11168   stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11169   GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
11170   GST_LOG_OBJECT (qtdemux, "stsd entry count:   %u", stsd_entry_count);
11171 
11172   stsd_entry_data = stsd_data + 16;
11173   remaining_stsd_len = stsd_len - 16;
11174   for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11175     guint32 fourcc;
11176     gchar *codec = NULL;
11177     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11178 
11179     /* and that entry should fit within stsd */
11180     len = QT_UINT32 (stsd_entry_data);
11181     if (len > remaining_stsd_len)
11182       goto corrupt_file;
11183 
11184     entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11185     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
11186         GST_FOURCC_ARGS (entry->fourcc));
11187     GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
11188 
11189     if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11190       goto error_encrypted;
11191 
11192     if (fourcc == FOURCC_aavd) {
11193       if (stream->subtype != FOURCC_soun) {
11194         GST_ERROR_OBJECT (qtdemux,
11195             "Unexpeced stsd type 'aavd' outside 'soun' track");
11196       } else {
11197         /* encrypted audio with sound sample description v0 */
11198         GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11199         stream->protected = TRUE;
11200         if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11201           GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11202       }
11203     }
11204 
11205     if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11206       /* FIXME this looks wrong, there might be multiple children
11207        * with the same type */
11208       GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11209       stream->protected = TRUE;
11210       if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11211         GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11212     }
11213 
11214     if (stream->subtype == FOURCC_vide) {
11215       GNode *colr;
11216       GNode *fiel;
11217       GNode *pasp;
11218       gboolean gray;
11219       gint depth, palette_size, palette_count;
11220       guint32 *palette_data = NULL;
11221 
11222       entry->sampled = TRUE;
11223 
11224       stream->display_width = w >> 16;
11225       stream->display_height = h >> 16;
11226 
11227       offset = 16;
11228       if (len < 86)             /* TODO verify */
11229         goto corrupt_file;
11230 
11231       entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11232       entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11233       entry->fps_n = 0;         /* this is filled in later */
11234       entry->fps_d = 0;         /* this is filled in later */
11235       entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11236       entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11237 
11238       /* if color_table_id is 0, ctab atom must follow; however some files
11239        * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11240        * if color table is not present we'll correct the value */
11241       if (entry->color_table_id == 0 &&
11242           (len < 90
11243               || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11244         entry->color_table_id = -1;
11245       }
11246 
11247       GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11248           entry->width, entry->height, entry->bits_per_sample,
11249           entry->color_table_id);
11250 
11251       depth = entry->bits_per_sample;
11252 
11253       /* more than 32 bits means grayscale */
11254       gray = (depth > 32);
11255       /* low 32 bits specify the depth  */
11256       depth &= 0x1F;
11257 
11258       /* different number of palette entries is determined by depth. */
11259       palette_count = 0;
11260       if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11261         palette_count = (1 << depth);
11262       palette_size = palette_count * 4;
11263 
11264       if (entry->color_table_id) {
11265         switch (palette_count) {
11266           case 0:
11267             break;
11268           case 2:
11269             palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11270             break;
11271           case 4:
11272             palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11273             break;
11274           case 16:
11275             if (gray)
11276               palette_data =
11277                   g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11278             else
11279               palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11280             break;
11281           case 256:
11282             if (gray)
11283               palette_data =
11284                   g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11285             else
11286               palette_data =
11287                   g_memdup2 (ff_qt_default_palette_256, palette_size);
11288             break;
11289           default:
11290             GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11291                 (_("The video in this file might not play correctly.")),
11292                 ("unsupported palette depth %d", depth));
11293             break;
11294         }
11295       } else {
11296         gint i, j, start, end;
11297 
11298         if (len < 94)
11299           goto corrupt_file;
11300 
11301         /* read table */
11302         start = QT_UINT32 (stsd_entry_data + offset + 70);
11303         palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11304         end = QT_UINT16 (stsd_entry_data + offset + 76);
11305 
11306         GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11307             start, end, palette_count);
11308 
11309         if (end > 255)
11310           end = 255;
11311         if (start > end)
11312           start = end;
11313 
11314         if (len < 94 + (end - start) * 8)
11315           goto corrupt_file;
11316 
11317         /* palette is always the same size */
11318         palette_data = g_malloc0 (256 * 4);
11319         palette_size = 256 * 4;
11320 
11321         for (j = 0, i = start; i <= end; j++, i++) {
11322           guint32 a, r, g, b;
11323 
11324           a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11325           r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11326           g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11327           b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11328 
11329           palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11330               (g & 0xff00) | (b >> 8);
11331         }
11332       }
11333 
11334       if (entry->caps)
11335         gst_caps_unref (entry->caps);
11336 
11337       entry->caps =
11338           qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11339           &codec);
11340       if (G_UNLIKELY (!entry->caps)) {
11341         g_free (palette_data);
11342         goto unknown_stream;
11343       }
11344 
11345       if (codec) {
11346         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11347             GST_TAG_VIDEO_CODEC, codec, NULL);
11348         g_free (codec);
11349         codec = NULL;
11350       }
11351 
11352       if (palette_data) {
11353         GstStructure *s;
11354 
11355         if (entry->rgb8_palette)
11356           gst_memory_unref (entry->rgb8_palette);
11357         entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11358             palette_data, palette_size, 0, palette_size, palette_data, g_free);
11359 
11360         s = gst_caps_get_structure (entry->caps, 0);
11361 
11362         /* non-raw video has a palette_data property. raw video has the palette as
11363          * an extra plane that we append to the output buffers before we push
11364          * them*/
11365         if (!gst_structure_has_name (s, "video/x-raw")) {
11366           GstBuffer *palette;
11367 
11368           palette = gst_buffer_new ();
11369           gst_buffer_append_memory (palette, entry->rgb8_palette);
11370           entry->rgb8_palette = NULL;
11371 
11372           gst_caps_set_simple (entry->caps, "palette_data",
11373               GST_TYPE_BUFFER, palette, NULL);
11374           gst_buffer_unref (palette);
11375         }
11376       } else if (palette_count != 0) {
11377         GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11378             (NULL), ("Unsupported palette depth %d", depth));
11379       }
11380 
11381       GST_LOG_OBJECT (qtdemux, "frame count:   %u",
11382           QT_UINT16 (stsd_entry_data + offset + 32));
11383 
11384       esds = NULL;
11385       pasp = NULL;
11386       colr = NULL;
11387       fiel = NULL;
11388       /* pick 'the' stsd child */
11389       mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11390       // We should skip parsing the stsd for non-protected streams if
11391       // the entry doesn't match the fourcc, since they don't change
11392       // format. However, for protected streams we can have partial
11393       // encryption, where parts of the stream are encrypted and parts
11394       // not. For both parts of such streams, we should ensure the
11395       // esds overrides are parsed for both from the stsd.
11396       if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11397         if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11398           mp4v = NULL;
11399         else if (!stream->protected)
11400           mp4v = NULL;
11401       }
11402 
11403       if (mp4v) {
11404         esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11405         pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11406         colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11407         fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11408       }
11409 
11410       if (pasp) {
11411         const guint8 *pasp_data = (const guint8 *) pasp->data;
11412         gint len = QT_UINT32 (pasp_data);
11413 
11414         if (len == 16) {
11415           CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11416           CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11417         } else {
11418           CUR_STREAM (stream)->par_w = 0;
11419           CUR_STREAM (stream)->par_h = 0;
11420         }
11421       } else {
11422         CUR_STREAM (stream)->par_w = 0;
11423         CUR_STREAM (stream)->par_h = 0;
11424       }
11425 
11426       if (fiel) {
11427         const guint8 *fiel_data = (const guint8 *) fiel->data;
11428         gint len = QT_UINT32 (fiel_data);
11429 
11430         if (len == 10) {
11431           CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11432           CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11433         }
11434       }
11435 
11436       if (colr) {
11437         const guint8 *colr_data = (const guint8 *) colr->data;
11438         gint len = QT_UINT32 (colr_data);
11439 
11440         if (len == 19 || len == 18) {
11441           guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11442 
11443           if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11444             guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11445             guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11446             guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11447             gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11448 
11449             CUR_STREAM (stream)->colorimetry.primaries =
11450                 gst_video_color_primaries_from_iso (primaries);
11451             CUR_STREAM (stream)->colorimetry.transfer =
11452                 gst_video_transfer_function_from_iso (transfer_function);
11453             CUR_STREAM (stream)->colorimetry.matrix =
11454                 gst_video_color_matrix_from_iso (matrix);
11455             CUR_STREAM (stream)->colorimetry.range =
11456                 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11457                 GST_VIDEO_COLOR_RANGE_16_235;
11458           } else {
11459             GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11460           }
11461         } else {
11462           GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11463         }
11464       }
11465 
11466       if (esds) {
11467         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11468             stream->stream_tags);
11469       } else {
11470         switch (fourcc) {
11471           case FOURCC_H264:
11472           case FOURCC_avc1:
11473           case FOURCC_avc3:
11474           {
11475             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11476             const guint8 *avc_data = stsd_entry_data + 0x56;
11477 
11478             /* find avcC */
11479             while (len >= 0x8) {
11480               gint size;
11481 
11482               if (QT_UINT32 (avc_data) <= len)
11483                 size = QT_UINT32 (avc_data) - 0x8;
11484               else
11485                 size = len - 0x8;
11486 
11487               if (size < 1)
11488                 /* No real data, so break out */
11489                 break;
11490 
11491               switch (QT_FOURCC (avc_data + 0x4)) {
11492                 case FOURCC_avcC:
11493                 {
11494                   /* parse, if found */
11495                   GstBuffer *buf;
11496 
11497                   GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11498 
11499                   /* First 4 bytes are the length of the atom, the next 4 bytes
11500                    * are the fourcc, the next 1 byte is the version, and the
11501                    * subsequent bytes are profile_tier_level structure like data. */
11502                   gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11503                       avc_data + 8 + 1, size - 1);
11504                   buf = gst_buffer_new_and_alloc (size);
11505                   gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11506                   gst_caps_set_simple (entry->caps,
11507                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11508                   gst_buffer_unref (buf);
11509 
11510                   break;
11511                 }
11512                 case FOURCC_strf:
11513                 {
11514                   GstBuffer *buf;
11515 
11516                   GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11517 
11518                   /* First 4 bytes are the length of the atom, the next 4 bytes
11519                    * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11520                    * next 1 byte is the version, and the
11521                    * subsequent bytes are sequence parameter set like data. */
11522 
11523                   size -= 40;   /* we'll be skipping BITMAPINFOHEADER */
11524                   if (size > 1) {
11525                     gst_codec_utils_h264_caps_set_level_and_profile
11526                         (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11527 
11528                     buf = gst_buffer_new_and_alloc (size);
11529                     gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11530                     gst_caps_set_simple (entry->caps,
11531                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
11532                     gst_buffer_unref (buf);
11533                   }
11534                   break;
11535                 }
11536                 case FOURCC_btrt:
11537                 {
11538                   guint avg_bitrate, max_bitrate;
11539 
11540                   /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11541                   if (size < 12)
11542                     break;
11543 
11544                   max_bitrate = QT_UINT32 (avc_data + 0xc);
11545                   avg_bitrate = QT_UINT32 (avc_data + 0x10);
11546 
11547                   if (!max_bitrate && !avg_bitrate)
11548                     break;
11549 
11550                   /* Some muxers seem to swap the average and maximum bitrates
11551                    * (I'm looking at you, YouTube), so we swap for sanity. */
11552                   if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11553                     guint temp = avg_bitrate;
11554 
11555                     avg_bitrate = max_bitrate;
11556                     max_bitrate = temp;
11557                   }
11558 
11559                   if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11560                     gst_tag_list_add (stream->stream_tags,
11561                         GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11562                         max_bitrate, NULL);
11563                   }
11564                   if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11565                     gst_tag_list_add (stream->stream_tags,
11566                         GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11567                         NULL);
11568                   }
11569 
11570                   break;
11571                 }
11572 
11573                 default:
11574                   break;
11575               }
11576 
11577               len -= size + 8;
11578               avc_data += size + 8;
11579             }
11580 
11581             break;
11582           }
11583           case FOURCC_H265:
11584           case FOURCC_hvc1:
11585           case FOURCC_hev1:
11586           case FOURCC_dvh1:
11587           case FOURCC_dvhe:
11588           {
11589             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11590             const guint8 *hevc_data = stsd_entry_data + 0x56;
11591 
11592             /* find hevc */
11593             while (len >= 0x8) {
11594               gint size;
11595 
11596               if (QT_UINT32 (hevc_data) <= len)
11597                 size = QT_UINT32 (hevc_data) - 0x8;
11598               else
11599                 size = len - 0x8;
11600 
11601               if (size < 1)
11602                 /* No real data, so break out */
11603                 break;
11604 
11605               switch (QT_FOURCC (hevc_data + 0x4)) {
11606                 case FOURCC_hvcC:
11607                 {
11608                   /* parse, if found */
11609                   GstBuffer *buf;
11610 
11611                   GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11612 
11613                   /* First 4 bytes are the length of the atom, the next 4 bytes
11614                    * are the fourcc, the next 1 byte is the version, and the
11615                    * subsequent bytes are sequence parameter set like data. */
11616                   gst_codec_utils_h265_caps_set_level_tier_and_profile
11617                       (entry->caps, hevc_data + 8 + 1, size - 1);
11618 
11619                   buf = gst_buffer_new_and_alloc (size);
11620                   gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11621                   gst_caps_set_simple (entry->caps,
11622                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11623                   gst_buffer_unref (buf);
11624                   break;
11625                 }
11626                 default:
11627                   break;
11628               }
11629               len -= size + 8;
11630               hevc_data += size + 8;
11631             }
11632             break;
11633           }
11634           case FOURCC_mp4v:
11635           case FOURCC_MP4V:
11636           case FOURCC_fmp4:
11637           case FOURCC_FMP4:
11638           case FOURCC_xvid:
11639           case FOURCC_XVID:
11640           {
11641             GNode *glbl;
11642 
11643             GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11644                 GST_FOURCC_ARGS (fourcc));
11645 
11646             /* codec data might be in glbl extension atom */
11647             glbl = mp4v ?
11648                 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11649             if (glbl) {
11650               guint8 *data;
11651               GstBuffer *buf;
11652               gint len;
11653 
11654               GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11655               data = glbl->data;
11656               len = QT_UINT32 (data);
11657               if (len > 0x8) {
11658                 len -= 0x8;
11659                 buf = gst_buffer_new_and_alloc (len);
11660                 gst_buffer_fill (buf, 0, data + 8, len);
11661                 gst_caps_set_simple (entry->caps,
11662                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11663                 gst_buffer_unref (buf);
11664               }
11665             }
11666             break;
11667           }
11668           case FOURCC_mjp2:
11669           {
11670             /* see annex I of the jpeg2000 spec */
11671             GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11672             const guint8 *data;
11673             const gchar *colorspace = NULL;
11674             gint ncomp = 0;
11675             guint32 ncomp_map = 0;
11676             gint32 *comp_map = NULL;
11677             guint32 nchan_def = 0;
11678             gint32 *chan_def = NULL;
11679 
11680             GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11681             /* some required atoms */
11682             mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11683             if (!mjp2)
11684               break;
11685             jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11686             if (!jp2h)
11687               break;
11688 
11689             /* number of components; redundant with info in codestream, but useful
11690                to a muxer */
11691             ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11692             if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11693               break;
11694             ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11695 
11696             colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11697             if (!colr)
11698               break;
11699             GST_DEBUG_OBJECT (qtdemux, "found colr");
11700             /* extract colour space info */
11701             if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11702               switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11703                 case 16:
11704                   colorspace = "sRGB";
11705                   break;
11706                 case 17:
11707                   colorspace = "GRAY";
11708                   break;
11709                 case 18:
11710                   colorspace = "sYUV";
11711                   break;
11712                 default:
11713                   colorspace = NULL;
11714                   break;
11715               }
11716             }
11717             if (!colorspace)
11718               /* colr is required, and only values 16, 17, and 18 are specified,
11719                  so error if we have no colorspace */
11720               break;
11721 
11722             /* extract component mapping */
11723             cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11724             if (cmap) {
11725               guint32 cmap_len = 0;
11726               int i;
11727               cmap_len = QT_UINT32 (cmap->data);
11728               if (cmap_len >= 8) {
11729                 /* normal box, subtract off header */
11730                 cmap_len -= 8;
11731                 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11732                 if (cmap_len % 4 == 0) {
11733                   ncomp_map = (cmap_len / 4);
11734                   comp_map = g_new0 (gint32, ncomp_map);
11735                   for (i = 0; i < ncomp_map; i++) {
11736                     guint16 cmp;
11737                     guint8 mtyp, pcol;
11738                     cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11739                     mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11740                     pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11741                     comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11742                   }
11743                 }
11744               }
11745             }
11746             /* extract channel definitions */
11747             cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11748             if (cdef) {
11749               guint32 cdef_len = 0;
11750               int i;
11751               cdef_len = QT_UINT32 (cdef->data);
11752               if (cdef_len >= 10) {
11753                 /* normal box, subtract off header and len */
11754                 cdef_len -= 10;
11755                 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11756                 if (cdef_len % 6 == 0) {
11757                   nchan_def = (cdef_len / 6);
11758                   chan_def = g_new0 (gint32, nchan_def);
11759                   for (i = 0; i < nchan_def; i++)
11760                     chan_def[i] = -1;
11761                   for (i = 0; i < nchan_def; i++) {
11762                     guint16 cn, typ, asoc;
11763                     cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11764                     typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11765                     asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11766                     if (cn < nchan_def) {
11767                       switch (typ) {
11768                         case 0:
11769                           chan_def[cn] = asoc;
11770                           break;
11771                         case 1:
11772                           chan_def[cn] = 0;     /* alpha */
11773                           break;
11774                         default:
11775                           chan_def[cn] = -typ;
11776                       }
11777                     }
11778                   }
11779                 }
11780               }
11781             }
11782 
11783             gst_caps_set_simple (entry->caps,
11784                 "num-components", G_TYPE_INT, ncomp, NULL);
11785             gst_caps_set_simple (entry->caps,
11786                 "colorspace", G_TYPE_STRING, colorspace, NULL);
11787 
11788             if (comp_map) {
11789               GValue arr = { 0, };
11790               GValue elt = { 0, };
11791               int i;
11792               g_value_init (&arr, GST_TYPE_ARRAY);
11793               g_value_init (&elt, G_TYPE_INT);
11794               for (i = 0; i < ncomp_map; i++) {
11795                 g_value_set_int (&elt, comp_map[i]);
11796                 gst_value_array_append_value (&arr, &elt);
11797               }
11798               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11799                   "component-map", &arr);
11800               g_value_unset (&elt);
11801               g_value_unset (&arr);
11802               g_free (comp_map);
11803             }
11804 
11805             if (chan_def) {
11806               GValue arr = { 0, };
11807               GValue elt = { 0, };
11808               int i;
11809               g_value_init (&arr, GST_TYPE_ARRAY);
11810               g_value_init (&elt, G_TYPE_INT);
11811               for (i = 0; i < nchan_def; i++) {
11812                 g_value_set_int (&elt, chan_def[i]);
11813                 gst_value_array_append_value (&arr, &elt);
11814               }
11815               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11816                   "channel-definitions", &arr);
11817               g_value_unset (&elt);
11818               g_value_unset (&arr);
11819               g_free (chan_def);
11820             }
11821 
11822             /* some optional atoms */
11823             field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11824             prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11825 
11826             /* indicate possible fields in caps */
11827             if (field) {
11828               data = (guint8 *) field->data + 8;
11829               if (*data != 1)
11830                 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11831                     (gint) * data, NULL);
11832             }
11833             /* add codec_data if provided */
11834             if (prefix) {
11835               GstBuffer *buf;
11836               gint len;
11837 
11838               GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11839               data = prefix->data;
11840               len = QT_UINT32 (data);
11841               if (len > 0x8) {
11842                 len -= 0x8;
11843                 buf = gst_buffer_new_and_alloc (len);
11844                 gst_buffer_fill (buf, 0, data + 8, len);
11845                 gst_caps_set_simple (entry->caps,
11846                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11847                 gst_buffer_unref (buf);
11848               }
11849             }
11850             break;
11851           }
11852           case FOURCC_SVQ3:
11853           case FOURCC_VP31:
11854           {
11855             GstBuffer *buf;
11856             GstBuffer *seqh = NULL;
11857             const guint8 *gamma_data = NULL;
11858             gint len = QT_UINT32 (stsd_data);   /* FIXME review - why put the whole stsd in codec data? */
11859 
11860             qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11861                 &seqh);
11862             if (gamma_data) {
11863               gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11864                   QT_FP32 (gamma_data), NULL);
11865             }
11866             if (seqh) {
11867               /* sorry for the bad name, but we don't know what this is, other
11868                * than its own fourcc */
11869               gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11870                   NULL);
11871               gst_buffer_unref (seqh);
11872             }
11873 
11874             GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11875             buf = gst_buffer_new_and_alloc (len);
11876             gst_buffer_fill (buf, 0, stsd_data, len);
11877             gst_caps_set_simple (entry->caps,
11878                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11879             gst_buffer_unref (buf);
11880             break;
11881           }
11882           case FOURCC_jpeg:
11883           {
11884             /* https://developer.apple.com/standards/qtff-2001.pdf,
11885              * page 92, "Video Sample Description", under table 3.1 */
11886             GstByteReader br;
11887 
11888             const gint compressor_offset =
11889                 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11890             const gint min_size = compressor_offset + 32 + 2 + 2;
11891             GNode *jpeg;
11892             guint32 len;
11893             guint16 color_table_id = 0;
11894             gboolean ok;
11895 
11896             GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11897 
11898             /* recover information on interlaced/progressive */
11899             jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11900             if (!jpeg)
11901               break;
11902 
11903             len = QT_UINT32 (jpeg->data);
11904             GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11905                 min_size);
11906             if (len >= min_size) {
11907               gst_byte_reader_init (&br, jpeg->data, len);
11908 
11909               gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11910               gst_byte_reader_get_uint16_le (&br, &color_table_id);
11911               if (color_table_id != 0) {
11912                 /* the spec says there can be concatenated chunks in the data, and we want
11913                  * to find one called field. Walk through them. */
11914                 gint offset = min_size;
11915                 while (offset + 8 < len) {
11916                   guint32 size = 0, tag;
11917                   ok = gst_byte_reader_get_uint32_le (&br, &size);
11918                   ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11919                   if (!ok || size < 8) {
11920                     GST_WARNING_OBJECT (qtdemux,
11921                         "Failed to walk optional chunk list");
11922                     break;
11923                   }
11924                   GST_DEBUG_OBJECT (qtdemux,
11925                       "Found optional %4.4s chunk, size %u",
11926                       (const char *) &tag, size);
11927                   if (tag == FOURCC_fiel) {
11928                     guint8 n_fields = 0, ordering = 0;
11929                     gst_byte_reader_get_uint8 (&br, &n_fields);
11930                     gst_byte_reader_get_uint8 (&br, &ordering);
11931                     if (n_fields == 1 || n_fields == 2) {
11932                       GST_DEBUG_OBJECT (qtdemux,
11933                           "Found fiel tag with %u fields, ordering %u",
11934                           n_fields, ordering);
11935                       if (n_fields == 2)
11936                         gst_caps_set_simple (CUR_STREAM (stream)->caps,
11937                             "interlace-mode", G_TYPE_STRING, "interleaved",
11938                             NULL);
11939                     } else {
11940                       GST_WARNING_OBJECT (qtdemux,
11941                           "Found fiel tag with invalid fields (%u)", n_fields);
11942                     }
11943                   }
11944                   offset += size;
11945                 }
11946               } else {
11947                 GST_DEBUG_OBJECT (qtdemux,
11948                     "Color table ID is 0, not trying to get interlacedness");
11949               }
11950             } else {
11951               GST_WARNING_OBJECT (qtdemux,
11952                   "Length of jpeg chunk is too small, not trying to get interlacedness");
11953             }
11954 
11955             break;
11956           }
11957           case FOURCC_rle_:
11958           case FOURCC_WRLE:
11959           {
11960             gst_caps_set_simple (entry->caps,
11961                 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11962                 NULL);
11963             break;
11964           }
11965           case FOURCC_XiTh:
11966           {
11967             GNode *xith, *xdxt;
11968 
11969             GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11970             xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11971             if (!xith)
11972               break;
11973 
11974             xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11975             if (!xdxt)
11976               break;
11977 
11978             GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11979             /* collect the headers and store them in a stream list so that we can
11980              * send them out first */
11981             qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11982             break;
11983           }
11984           case FOURCC_ovc1:
11985           {
11986             GNode *ovc1;
11987             guint8 *ovc1_data;
11988             guint ovc1_len;
11989             GstBuffer *buf;
11990 
11991             GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11992             ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11993             if (!ovc1)
11994               break;
11995             ovc1_data = ovc1->data;
11996             ovc1_len = QT_UINT32 (ovc1_data);
11997             if (ovc1_len <= 198) {
11998               GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11999               break;
12000             }
12001             buf = gst_buffer_new_and_alloc (ovc1_len - 198);
12002             gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
12003             gst_caps_set_simple (entry->caps,
12004                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12005             gst_buffer_unref (buf);
12006             break;
12007           }
12008           case FOURCC_vc_1:
12009           {
12010             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12011             const guint8 *vc1_data = stsd_entry_data + 0x56;
12012 
12013             /* find dvc1 */
12014             while (len >= 8) {
12015               gint size;
12016 
12017               if (QT_UINT32 (vc1_data) <= len)
12018                 size = QT_UINT32 (vc1_data) - 8;
12019               else
12020                 size = len - 8;
12021 
12022               if (size < 1)
12023                 /* No real data, so break out */
12024                 break;
12025 
12026               switch (QT_FOURCC (vc1_data + 0x4)) {
12027                 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
12028                 {
12029                   GstBuffer *buf;
12030 
12031                   GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
12032                   buf = gst_buffer_new_and_alloc (size);
12033                   gst_buffer_fill (buf, 0, vc1_data + 8, size);
12034                   gst_caps_set_simple (entry->caps,
12035                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12036                   gst_buffer_unref (buf);
12037                   break;
12038                 }
12039                 default:
12040                   break;
12041               }
12042               len -= size + 8;
12043               vc1_data += size + 8;
12044             }
12045             break;
12046           }
12047           case FOURCC_av01:
12048           {
12049             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12050             const guint8 *av1_data = stsd_entry_data + 0x56;
12051 
12052             /* find av1C */
12053             while (len >= 0x8) {
12054               gint size;
12055 
12056               if (QT_UINT32 (av1_data) <= len)
12057                 size = QT_UINT32 (av1_data) - 0x8;
12058               else
12059                 size = len - 0x8;
12060 
12061               if (size < 1)
12062                 /* No real data, so break out */
12063                 break;
12064 
12065               switch (QT_FOURCC (av1_data + 0x4)) {
12066                 case FOURCC_av1C:
12067                 {
12068                   /* parse, if found */
12069                   GstBuffer *buf;
12070                   guint8 pres_delay_field;
12071 
12072                   GST_DEBUG_OBJECT (qtdemux,
12073                       "found av1C codec_data in stsd of size %d", size);
12074 
12075                   /* not enough data, just ignore and hope for the best */
12076                   if (size < 5)
12077                     break;
12078 
12079                   /* Content is:
12080                    * 4 bytes: atom length
12081                    * 4 bytes: fourcc
12082                    * 1 byte: version
12083                    * 3 bytes: flags
12084                    * 3 bits: reserved
12085                    * 1 bits:  initial_presentation_delay_present
12086                    * 4 bits: initial_presentation_delay (if present else reserved
12087                    * rest: OBUs.
12088                    */
12089 
12090                   if (av1_data[9] != 0) {
12091                     GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12092                     break;
12093                   }
12094 
12095                   /* We skip initial_presentation_delay* for now */
12096                   pres_delay_field = *(av1_data + 12);
12097                   if (pres_delay_field & (1 << 5)) {
12098                     gst_caps_set_simple (entry->caps,
12099                         "presentation-delay", G_TYPE_INT,
12100                         (gint) (pres_delay_field & 0x0F) + 1, NULL);
12101                   }
12102                   if (size > 5) {
12103                     buf = gst_buffer_new_and_alloc (size - 5);
12104                     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12105                     gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12106                     gst_caps_set_simple (entry->caps,
12107                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
12108                     gst_buffer_unref (buf);
12109                   }
12110                   break;
12111                 }
12112                 default:
12113                   break;
12114               }
12115 
12116               len -= size + 8;
12117               av1_data += size + 8;
12118             }
12119 
12120             break;
12121           }
12122 
12123             /* TODO: Need to parse vpcC for VP8 codec too.
12124              * Note that VPCodecConfigurationBox (vpcC) is defined for
12125              * vp08, vp09, and vp10 fourcc. */
12126           case FOURCC_vp09:
12127           {
12128             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12129             const guint8 *vpcc_data = stsd_entry_data + 0x56;
12130 
12131             /* find vpcC */
12132             while (len >= 0x8) {
12133               gint size;
12134 
12135               if (QT_UINT32 (vpcc_data) <= len)
12136                 size = QT_UINT32 (vpcc_data) - 0x8;
12137               else
12138                 size = len - 0x8;
12139 
12140               if (size < 1)
12141                 /* No real data, so break out */
12142                 break;
12143 
12144               switch (QT_FOURCC (vpcc_data + 0x4)) {
12145                 case FOURCC_vpcC:
12146                 {
12147                   const gchar *profile_str = NULL;
12148                   const gchar *chroma_format_str = NULL;
12149                   guint8 profile;
12150                   guint8 bitdepth;
12151                   guint8 chroma_format;
12152                   GstVideoColorimetry cinfo;
12153 
12154                   /* parse, if found */
12155                   GST_DEBUG_OBJECT (qtdemux,
12156                       "found vp codec_data in stsd of size %d", size);
12157 
12158                   /* the meaning of "size" is length of the atom body, excluding
12159                    * atom length and fourcc fields */
12160                   if (size < 12)
12161                     break;
12162 
12163                   /* Content is:
12164                    * 4 bytes: atom length
12165                    * 4 bytes: fourcc
12166                    * 1 byte: version
12167                    * 3 bytes: flags
12168                    * 1 byte: profile
12169                    * 1 byte: level
12170                    * 4 bits: bitDepth
12171                    * 3 bits: chromaSubsampling
12172                    * 1 bit: videoFullRangeFlag
12173                    * 1 byte: colourPrimaries
12174                    * 1 byte: transferCharacteristics
12175                    * 1 byte: matrixCoefficients
12176                    * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12177                    * rest: codecIntializationData (not used for vp8 and vp9)
12178                    */
12179 
12180                   if (vpcc_data[8] != 1) {
12181                     GST_WARNING_OBJECT (qtdemux,
12182                         "unknown vpcC version %d", vpcc_data[8]);
12183                     break;
12184                   }
12185 
12186                   profile = vpcc_data[12];
12187                   switch (profile) {
12188                     case 0:
12189                       profile_str = "0";
12190                       break;
12191                     case 1:
12192                       profile_str = "1";
12193                       break;
12194                     case 2:
12195                       profile_str = "2";
12196                       break;
12197                     case 3:
12198                       profile_str = "3";
12199                       break;
12200                     default:
12201                       break;
12202                   }
12203 
12204                   if (profile_str) {
12205                     gst_caps_set_simple (entry->caps,
12206                         "profile", G_TYPE_STRING, profile_str, NULL);
12207                   }
12208 
12209                   /* skip level, the VP9 spec v0.6 defines only one level atm,
12210                    * but webm spec define various ones. Add level to caps
12211                    * if we really need it then */
12212 
12213                   bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12214                   if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12215                     gst_caps_set_simple (entry->caps,
12216                         "bit-depth-luma", G_TYPE_UINT, bitdepth,
12217                         "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12218                   }
12219 
12220                   chroma_format = (vpcc_data[14] & 0xe) >> 1;
12221                   switch (chroma_format) {
12222                     case 0:
12223                     case 1:
12224                       chroma_format_str = "4:2:0";
12225                       break;
12226                     case 2:
12227                       chroma_format_str = "4:2:2";
12228                       break;
12229                     case 3:
12230                       chroma_format_str = "4:4:4";
12231                       break;
12232                     default:
12233                       break;
12234                   }
12235 
12236                   if (chroma_format_str) {
12237                     gst_caps_set_simple (entry->caps,
12238                         "chroma-format", G_TYPE_STRING, chroma_format_str,
12239                         NULL);
12240                   }
12241 
12242                   if ((vpcc_data[14] & 0x1) != 0)
12243                     cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12244                   else
12245                     cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12246                   cinfo.primaries =
12247                       gst_video_color_primaries_from_iso (vpcc_data[15]);
12248                   cinfo.transfer =
12249                       gst_video_transfer_function_from_iso (vpcc_data[16]);
12250                   cinfo.matrix =
12251                       gst_video_color_matrix_from_iso (vpcc_data[17]);
12252 
12253                   if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12254                       cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12255                       cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12256                     /* set this only if all values are known, otherwise this
12257                      * might overwrite valid ones parsed from other color box */
12258                     CUR_STREAM (stream)->colorimetry = cinfo;
12259                   }
12260                   break;
12261                 }
12262                 default:
12263                   break;
12264               }
12265 
12266               len -= size + 8;
12267               vpcc_data += size + 8;
12268             }
12269 
12270             break;
12271           }
12272           default:
12273             break;
12274         }
12275       }
12276 
12277       GST_INFO_OBJECT (qtdemux,
12278           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12279           GST_FOURCC_ARGS (fourcc), entry->caps);
12280 
12281     } else if (stream->subtype == FOURCC_soun) {
12282       GNode *wave;
12283       int version, samplesize;
12284       guint16 compression_id;
12285       gboolean amrwb = FALSE;
12286 
12287       offset = 16;
12288       /* sample description entry (16) + sound sample description v0 (20) */
12289       if (len < 36)
12290         goto corrupt_file;
12291 
12292       version = QT_UINT32 (stsd_entry_data + offset);
12293       entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12294       samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12295       compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12296       entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12297 
12298       GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
12299       GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
12300           QT_UINT32 (stsd_entry_data + offset + 4));
12301       GST_LOG_OBJECT (qtdemux, "n_channels:       %d", entry->n_channels);
12302       GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
12303       GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
12304       GST_LOG_OBJECT (qtdemux, "packet size:      %d",
12305           QT_UINT16 (stsd_entry_data + offset + 14));
12306       GST_LOG_OBJECT (qtdemux, "sample rate:      %g", entry->rate);
12307 
12308       if (compression_id == 0xfffe)
12309         entry->sampled = TRUE;
12310 
12311       /* first assume uncompressed audio */
12312       entry->bytes_per_sample = samplesize / 8;
12313       entry->samples_per_frame = entry->n_channels;
12314       entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12315       entry->samples_per_packet = entry->samples_per_frame;
12316       entry->bytes_per_packet = entry->bytes_per_sample;
12317 
12318       offset = 36;
12319 
12320       if (version == 0x00010000) {
12321         /* sample description entry (16) + sound sample description v1 (20+16) */
12322         if (len < 52)
12323           goto corrupt_file;
12324 
12325         /* take information from here over the normal sample description */
12326         entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12327         entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12328         entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12329         entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12330 
12331         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12332         GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
12333             entry->samples_per_packet);
12334         GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
12335             entry->bytes_per_packet);
12336         GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
12337             entry->bytes_per_frame);
12338         GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
12339             entry->bytes_per_sample);
12340 
12341         if (!entry->sampled && entry->bytes_per_packet) {
12342           entry->samples_per_frame = (entry->bytes_per_frame /
12343               entry->bytes_per_packet) * entry->samples_per_packet;
12344           GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
12345               entry->samples_per_frame);
12346         }
12347       } else if (version == 0x00020000) {
12348         /* sample description entry (16) + sound sample description v2 (56) */
12349         if (len < 72)
12350           goto corrupt_file;
12351 
12352         /* take information from here over the normal sample description */
12353         entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12354         entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12355         entry->samples_per_frame = entry->n_channels;
12356         entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12357         entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12358         entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12359         entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12360 
12361         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12362         GST_LOG_OBJECT (qtdemux, "sample rate:        %g", entry->rate);
12363         GST_LOG_OBJECT (qtdemux, "n_channels:         %d", entry->n_channels);
12364         GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
12365             entry->bytes_per_sample * 8);
12366         GST_LOG_OBJECT (qtdemux, "format flags:       %X",
12367             QT_UINT32 (stsd_entry_data + offset + 24));
12368         GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
12369             entry->bytes_per_packet);
12370         GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12371             entry->samples_per_packet);
12372       } else if (version != 0x00000) {
12373         GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12374             version);
12375       }
12376 
12377       switch (fourcc) {
12378           /* Yes, these have to be hard-coded */
12379         case FOURCC_MAC6:
12380         {
12381           entry->samples_per_packet = 6;
12382           entry->bytes_per_packet = 1;
12383           entry->bytes_per_frame = 1 * entry->n_channels;
12384           entry->bytes_per_sample = 1;
12385           entry->samples_per_frame = 6 * entry->n_channels;
12386           break;
12387         }
12388         case FOURCC_MAC3:
12389         {
12390           entry->samples_per_packet = 3;
12391           entry->bytes_per_packet = 1;
12392           entry->bytes_per_frame = 1 * entry->n_channels;
12393           entry->bytes_per_sample = 1;
12394           entry->samples_per_frame = 3 * entry->n_channels;
12395           break;
12396         }
12397         case FOURCC_ima4:
12398         {
12399           entry->samples_per_packet = 64;
12400           entry->bytes_per_packet = 34;
12401           entry->bytes_per_frame = 34 * entry->n_channels;
12402           entry->bytes_per_sample = 2;
12403           entry->samples_per_frame = 64 * entry->n_channels;
12404           break;
12405         }
12406         case FOURCC_ulaw:
12407         case FOURCC_alaw:
12408         {
12409           entry->samples_per_packet = 1;
12410           entry->bytes_per_packet = 1;
12411           entry->bytes_per_frame = 1 * entry->n_channels;
12412           entry->bytes_per_sample = 1;
12413           entry->samples_per_frame = 1 * entry->n_channels;
12414           break;
12415         }
12416         case FOURCC_agsm:
12417         {
12418           entry->samples_per_packet = 160;
12419           entry->bytes_per_packet = 33;
12420           entry->bytes_per_frame = 33 * entry->n_channels;
12421           entry->bytes_per_sample = 2;
12422           entry->samples_per_frame = 160 * entry->n_channels;
12423           break;
12424         }
12425           /* fix up any invalid header information from above */
12426         case FOURCC_twos:
12427         case FOURCC_sowt:
12428         case FOURCC_raw_:
12429         case FOURCC_lpcm:
12430           /* Sometimes these are set to 0 in the sound sample descriptions so
12431            * let's try to infer useful values from the other information we
12432            * have available */
12433           if (entry->bytes_per_sample == 0)
12434             entry->bytes_per_sample =
12435                 entry->bytes_per_frame / entry->n_channels;
12436           if (entry->bytes_per_sample == 0)
12437             entry->bytes_per_sample = samplesize / 8;
12438 
12439           if (entry->bytes_per_frame == 0)
12440             entry->bytes_per_frame =
12441                 entry->bytes_per_sample * entry->n_channels;
12442 
12443           if (entry->bytes_per_packet == 0)
12444             entry->bytes_per_packet = entry->bytes_per_sample;
12445 
12446           if (entry->samples_per_frame == 0)
12447             entry->samples_per_frame = entry->n_channels;
12448 
12449           if (entry->samples_per_packet == 0)
12450             entry->samples_per_packet = entry->samples_per_frame;
12451 
12452           break;
12453         case FOURCC_in24:
12454         case FOURCC_in32:
12455         case FOURCC_fl32:
12456         case FOURCC_fl64:
12457         case FOURCC_s16l:{
12458           switch (fourcc) {
12459             case FOURCC_in24:
12460               entry->bytes_per_sample = 3;
12461               break;
12462             case FOURCC_in32:
12463             case FOURCC_fl32:
12464               entry->bytes_per_sample = 4;
12465               break;
12466             case FOURCC_fl64:
12467               entry->bytes_per_sample = 8;
12468               break;
12469             case FOURCC_s16l:
12470               entry->bytes_per_sample = 2;
12471               break;
12472             default:
12473               g_assert_not_reached ();
12474               break;
12475           }
12476           entry->samples_per_frame = entry->n_channels;
12477           entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12478           entry->samples_per_packet = entry->samples_per_frame;
12479           entry->bytes_per_packet = entry->bytes_per_sample;
12480           break;
12481         }
12482         default:
12483           break;
12484       }
12485 
12486       if (entry->caps)
12487         gst_caps_unref (entry->caps);
12488 
12489       entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12490           stsd_entry_data + 32, len - 16, &codec);
12491 
12492       switch (fourcc) {
12493         case FOURCC_in24:
12494         case FOURCC_in32:
12495         case FOURCC_fl32:
12496         case FOURCC_fl64:
12497         {
12498           GNode *enda;
12499           GNode *fmt;
12500 
12501           fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12502 
12503           enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12504           if (!enda) {
12505             wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12506             if (wave)
12507               enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12508           }
12509           if (enda) {
12510             int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12511             const gchar *format_str;
12512 
12513             switch (fourcc) {
12514               case FOURCC_in24:
12515                 format_str = (enda_value) ? "S24LE" : "S24BE";
12516                 break;
12517               case FOURCC_in32:
12518                 format_str = (enda_value) ? "S32LE" : "S32BE";
12519                 break;
12520               case FOURCC_fl32:
12521                 format_str = (enda_value) ? "F32LE" : "F32BE";
12522                 break;
12523               case FOURCC_fl64:
12524                 format_str = (enda_value) ? "F64LE" : "F64BE";
12525                 break;
12526               default:
12527                 g_assert_not_reached ();
12528                 break;
12529             }
12530             gst_caps_set_simple (entry->caps,
12531                 "format", G_TYPE_STRING, format_str, NULL);
12532           }
12533           break;
12534         }
12535         case FOURCC_owma:
12536         {
12537           const guint8 *owma_data;
12538           const gchar *codec_name = NULL;
12539           guint owma_len;
12540           GstBuffer *buf;
12541           gint version = 1;
12542           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12543           /* FIXME this should also be gst_riff_strf_auds,
12544            * but the latter one is actually missing bits-per-sample :( */
12545           typedef struct
12546           {
12547             gint16 wFormatTag;
12548             gint16 nChannels;
12549             gint32 nSamplesPerSec;
12550             gint32 nAvgBytesPerSec;
12551             gint16 nBlockAlign;
12552             gint16 wBitsPerSample;
12553             gint16 cbSize;
12554           } WAVEFORMATEX;
12555           WAVEFORMATEX *wfex;
12556 
12557           GST_DEBUG_OBJECT (qtdemux, "parse owma");
12558           owma_data = stsd_entry_data;
12559           owma_len = QT_UINT32 (owma_data);
12560           if (owma_len <= 54) {
12561             GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12562             break;
12563           }
12564           wfex = (WAVEFORMATEX *) (owma_data + 36);
12565           buf = gst_buffer_new_and_alloc (owma_len - 54);
12566           gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12567           if (wfex->wFormatTag == 0x0161) {
12568             codec_name = "Windows Media Audio";
12569             version = 2;
12570           } else if (wfex->wFormatTag == 0x0162) {
12571             codec_name = "Windows Media Audio 9 Pro";
12572             version = 3;
12573           } else if (wfex->wFormatTag == 0x0163) {
12574             codec_name = "Windows Media Audio 9 Lossless";
12575             /* is that correct? gstffmpegcodecmap.c is missing it, but
12576              * fluendo codec seems to support it */
12577             version = 4;
12578           }
12579 
12580           gst_caps_set_simple (entry->caps,
12581               "codec_data", GST_TYPE_BUFFER, buf,
12582               "wmaversion", G_TYPE_INT, version,
12583               "block_align", G_TYPE_INT,
12584               GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12585               GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12586               GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12587               GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12588           gst_buffer_unref (buf);
12589 
12590           if (codec_name) {
12591             g_free (codec);
12592             codec = g_strdup (codec_name);
12593           }
12594           break;
12595         }
12596         case FOURCC_wma_:
12597         {
12598           gint len = QT_UINT32 (stsd_entry_data) - offset;
12599           const guint8 *wfex_data = stsd_entry_data + offset;
12600           const gchar *codec_name = NULL;
12601           gint version = 1;
12602           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12603           /* FIXME this should also be gst_riff_strf_auds,
12604            * but the latter one is actually missing bits-per-sample :( */
12605           typedef struct
12606           {
12607             gint16 wFormatTag;
12608             gint16 nChannels;
12609             gint32 nSamplesPerSec;
12610             gint32 nAvgBytesPerSec;
12611             gint16 nBlockAlign;
12612             gint16 wBitsPerSample;
12613             gint16 cbSize;
12614           } WAVEFORMATEX;
12615           WAVEFORMATEX wfex;
12616 
12617           /* FIXME: unify with similar wavformatex parsing code above */
12618           GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12619 
12620           /* find wfex */
12621           while (len >= 8) {
12622             gint size;
12623 
12624             if (QT_UINT32 (wfex_data) <= len)
12625               size = QT_UINT32 (wfex_data) - 8;
12626             else
12627               size = len - 8;
12628 
12629             if (size < 1)
12630               /* No real data, so break out */
12631               break;
12632 
12633             switch (QT_FOURCC (wfex_data + 4)) {
12634               case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12635               {
12636                 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12637 
12638                 if (size < 8 + 18)
12639                   break;
12640 
12641                 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12642                 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12643                 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12644                 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12645                 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12646                 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12647                 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12648 
12649                 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12650                 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12651                     "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12652                     "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12653                     wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12654                     wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12655 
12656                 if (wfex.wFormatTag == 0x0161) {
12657                   codec_name = "Windows Media Audio";
12658                   version = 2;
12659                 } else if (wfex.wFormatTag == 0x0162) {
12660                   codec_name = "Windows Media Audio 9 Pro";
12661                   version = 3;
12662                 } else if (wfex.wFormatTag == 0x0163) {
12663                   codec_name = "Windows Media Audio 9 Lossless";
12664                   /* is that correct? gstffmpegcodecmap.c is missing it, but
12665                    * fluendo codec seems to support it */
12666                   version = 4;
12667                 }
12668 
12669                 gst_caps_set_simple (entry->caps,
12670                     "wmaversion", G_TYPE_INT, version,
12671                     "block_align", G_TYPE_INT, wfex.nBlockAlign,
12672                     "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12673                     "width", G_TYPE_INT, wfex.wBitsPerSample,
12674                     "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12675 
12676                 if (size > wfex.cbSize) {
12677                   GstBuffer *buf;
12678 
12679                   buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12680                   gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12681                       size - wfex.cbSize);
12682                   gst_caps_set_simple (entry->caps,
12683                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12684                   gst_buffer_unref (buf);
12685                 } else {
12686                   GST_WARNING_OBJECT (qtdemux, "no codec data");
12687                 }
12688 
12689                 if (codec_name) {
12690                   g_free (codec);
12691                   codec = g_strdup (codec_name);
12692                 }
12693                 break;
12694               }
12695               default:
12696                 break;
12697             }
12698             len -= size + 8;
12699             wfex_data += size + 8;
12700           }
12701           break;
12702         }
12703         case FOURCC_opus:
12704         {
12705           const guint8 *dops_data;
12706           guint8 *channel_mapping = NULL;
12707           guint32 rate;
12708           guint8 channels;
12709           guint8 channel_mapping_family;
12710           guint8 stream_count;
12711           guint8 coupled_count;
12712           guint8 i;
12713 
12714           version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12715           if (version == 1)
12716             dops_data = stsd_entry_data + 51;
12717           else
12718             dops_data = stsd_entry_data + 35;
12719 
12720           channels = GST_READ_UINT8 (dops_data + 10);
12721           rate = GST_READ_UINT32_LE (dops_data + 13);
12722           channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12723           stream_count = GST_READ_UINT8 (dops_data + 20);
12724           coupled_count = GST_READ_UINT8 (dops_data + 21);
12725 
12726           if (channels > 0) {
12727             channel_mapping = g_malloc (channels * sizeof (guint8));
12728             for (i = 0; i < channels; i++)
12729               channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12730           }
12731 
12732           entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12733               channel_mapping_family, stream_count, coupled_count,
12734               channel_mapping);
12735           g_free (channel_mapping);
12736           break;
12737         }
12738         default:
12739           break;
12740       }
12741 
12742       if (codec) {
12743         GstStructure *s;
12744         gint bitrate = 0;
12745 
12746         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12747             GST_TAG_AUDIO_CODEC, codec, NULL);
12748         g_free (codec);
12749         codec = NULL;
12750 
12751         /* some bitrate info may have ended up in caps */
12752         s = gst_caps_get_structure (entry->caps, 0);
12753         gst_structure_get_int (s, "bitrate", &bitrate);
12754         if (bitrate > 0)
12755           gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12756               GST_TAG_BITRATE, bitrate, NULL);
12757       }
12758 
12759       esds = NULL;
12760       mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12761       if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12762         if (stream->protected) {
12763           if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12764             esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12765           }
12766           if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12767             mp4a = NULL;
12768           }
12769         } else {
12770           mp4a = NULL;
12771         }
12772       }
12773 
12774       wave = NULL;
12775       if (mp4a) {
12776         wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12777         if (wave)
12778           esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12779         if (!esds)
12780           esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12781       }
12782 
12783 
12784       /* If the fourcc's bottom 16 bits gives 'sm', then the top
12785          16 bits is a byte-swapped wave-style codec identifier,
12786          and we can find a WAVE header internally to a 'wave' atom here.
12787          This can more clearly be thought of as 'ms' as the top 16 bits, and a
12788          codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12789          is big-endian).
12790        */
12791       if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12792         if (len < offset + 20) {
12793           GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12794         } else {
12795           guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12796           const guint8 *data = stsd_entry_data + offset + 16;
12797           GNode *wavenode;
12798           GNode *waveheadernode;
12799 
12800           wavenode = g_node_new ((guint8 *) data);
12801           if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12802             const guint8 *waveheader;
12803             guint32 headerlen;
12804 
12805             waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12806             if (waveheadernode) {
12807               waveheader = (const guint8 *) waveheadernode->data;
12808               headerlen = QT_UINT32 (waveheader);
12809 
12810               if (headerlen > 8) {
12811                 gst_riff_strf_auds *header = NULL;
12812                 GstBuffer *headerbuf;
12813                 GstBuffer *extra;
12814 
12815                 waveheader += 8;
12816                 headerlen -= 8;
12817 
12818                 headerbuf = gst_buffer_new_and_alloc (headerlen);
12819                 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12820 
12821                 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12822                         headerbuf, &header, &extra)) {
12823                   gst_caps_unref (entry->caps);
12824                   /* FIXME: Need to do something with the channel reorder map */
12825                   entry->caps =
12826                       gst_riff_create_audio_caps (header->format, NULL, header,
12827                       extra, NULL, NULL, NULL);
12828 
12829                   if (extra)
12830                     gst_buffer_unref (extra);
12831                   g_free (header);
12832                 }
12833               }
12834             } else
12835               GST_DEBUG ("Didn't find waveheadernode for this codec");
12836           }
12837           g_node_destroy (wavenode);
12838         }
12839       } else if (esds) {
12840         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12841             stream->stream_tags);
12842       } else {
12843         switch (fourcc) {
12844 #if 0
12845             /* FIXME: what is in the chunk? */
12846           case FOURCC_QDMC:
12847           {
12848             gint len = QT_UINT32 (stsd_data);
12849 
12850             /* seems to be always = 116 = 0x74 */
12851             break;
12852           }
12853 #endif
12854           case FOURCC_QDM2:
12855           {
12856             gint len = QT_UINT32 (stsd_entry_data);
12857 
12858             if (len > 0x3C) {
12859               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12860 
12861               gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12862               gst_caps_set_simple (entry->caps,
12863                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12864               gst_buffer_unref (buf);
12865             }
12866             gst_caps_set_simple (entry->caps,
12867                 "samplesize", G_TYPE_INT, samplesize, NULL);
12868             break;
12869           }
12870           case FOURCC_alac:
12871           {
12872             GNode *alac, *wave = NULL;
12873 
12874             /* apparently, m4a has this atom appended directly in the stsd entry,
12875              * while mov has it in a wave atom */
12876             alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12877             if (alac) {
12878               /* alac now refers to stsd entry atom */
12879               wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12880               if (wave)
12881                 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12882               else
12883                 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12884             }
12885             if (alac) {
12886               const guint8 *alac_data = alac->data;
12887               gint len = QT_UINT32 (alac->data);
12888               GstBuffer *buf;
12889 
12890               if (len < 36) {
12891                 GST_DEBUG_OBJECT (qtdemux,
12892                     "discarding alac atom with unexpected len %d", len);
12893               } else {
12894                 /* codec-data contains alac atom size and prefix,
12895                  * ffmpeg likes it that way, not quite gst-ish though ...*/
12896                 buf = gst_buffer_new_and_alloc (len);
12897                 gst_buffer_fill (buf, 0, alac->data, len);
12898                 gst_caps_set_simple (entry->caps,
12899                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12900                 gst_buffer_unref (buf);
12901 
12902                 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12903                 entry->n_channels = QT_UINT8 (alac_data + 21);
12904                 entry->rate = QT_UINT32 (alac_data + 32);
12905                 samplesize = QT_UINT8 (alac_data + 16 + 1);
12906               }
12907             }
12908             gst_caps_set_simple (entry->caps,
12909                 "samplesize", G_TYPE_INT, samplesize, NULL);
12910             break;
12911           }
12912           case FOURCC_fLaC:
12913           {
12914             /* The codingname of the sample entry is 'fLaC' */
12915             GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12916 
12917             if (flac) {
12918               /* The 'dfLa' box is added to the sample entry to convey
12919                  initializing information for the decoder. */
12920               const GNode *dfla =
12921                   qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12922 
12923               if (dfla) {
12924                 const guint32 len = QT_UINT32 (dfla->data);
12925 
12926                 /* Must contain at least dfLa box header (12),
12927                  * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12928                 if (len < 50) {
12929                   GST_DEBUG_OBJECT (qtdemux,
12930                       "discarding dfla atom with unexpected len %d", len);
12931                 } else {
12932                   /* skip dfLa header to get the METADATA_BLOCKs */
12933                   const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12934                   const guint32 metadata_blocks_len = len - 12;
12935 
12936                   gchar *stream_marker = g_strdup ("fLaC");
12937                   GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12938                       strlen (stream_marker));
12939 
12940                   guint32 index = 0;
12941                   guint32 remainder = 0;
12942                   guint32 block_size = 0;
12943                   gboolean is_last = FALSE;
12944 
12945                   GValue array = G_VALUE_INIT;
12946                   GValue value = G_VALUE_INIT;
12947 
12948                   g_value_init (&array, GST_TYPE_ARRAY);
12949                   g_value_init (&value, GST_TYPE_BUFFER);
12950 
12951                   gst_value_set_buffer (&value, block);
12952                   gst_value_array_append_value (&array, &value);
12953                   g_value_reset (&value);
12954 
12955                   gst_buffer_unref (block);
12956 
12957                   /* check there's at least one METADATA_BLOCK_HEADER's worth
12958                    * of data, and we haven't already finished parsing */
12959                   while (!is_last && ((index + 3) < metadata_blocks_len)) {
12960                     remainder = metadata_blocks_len - index;
12961 
12962                     /* add the METADATA_BLOCK_HEADER size to the signalled size */
12963                     block_size = 4 +
12964                         (metadata_blocks[index + 1] << 16) +
12965                         (metadata_blocks[index + 2] << 8) +
12966                         metadata_blocks[index + 3];
12967 
12968                     /* be careful not to read off end of box */
12969                     if (block_size > remainder) {
12970                       break;
12971                     }
12972 
12973                     is_last = metadata_blocks[index] >> 7;
12974 
12975                     block = gst_buffer_new_and_alloc (block_size);
12976 
12977                     gst_buffer_fill (block, 0, &metadata_blocks[index],
12978                         block_size);
12979 
12980                     gst_value_set_buffer (&value, block);
12981                     gst_value_array_append_value (&array, &value);
12982                     g_value_reset (&value);
12983 
12984                     gst_buffer_unref (block);
12985 
12986                     index += block_size;
12987                   }
12988 
12989                   /* only append the metadata if we successfully read all of it */
12990                   if (is_last) {
12991                     gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12992                             (stream)->caps, 0), "streamheader", &array);
12993                   } else {
12994                     GST_WARNING_OBJECT (qtdemux,
12995                         "discarding all METADATA_BLOCKs due to invalid "
12996                         "block_size %d at idx %d, rem %d", block_size, index,
12997                         remainder);
12998                   }
12999 
13000                   g_value_unset (&value);
13001                   g_value_unset (&array);
13002 
13003                   /* The sample rate obtained from the stsd may not be accurate
13004                    * since it cannot represent rates greater than 65535Hz, so
13005                    * override that value with the sample rate from the
13006                    * METADATA_BLOCK_STREAMINFO block */
13007                   CUR_STREAM (stream)->rate =
13008                       (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
13009                 }
13010               }
13011             }
13012             break;
13013           }
13014           case FOURCC_sawb:
13015             /* Fallthrough! */
13016             amrwb = TRUE;
13017           case FOURCC_samr:
13018           {
13019             gint len = QT_UINT32 (stsd_entry_data);
13020 
13021             if (len > 0x24) {
13022               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
13023               guint bitrate;
13024 
13025               gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
13026 
13027               /* If we have enough data, let's try to get the 'damr' atom. See
13028                * the 3GPP container spec (26.244) for more details. */
13029               if ((len - 0x34) > 8 &&
13030                   (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
13031                 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13032                     GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
13033               }
13034 
13035               gst_caps_set_simple (entry->caps,
13036                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
13037               gst_buffer_unref (buf);
13038             }
13039             break;
13040           }
13041           case FOURCC_mp4a:
13042           {
13043             /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
13044             gint len = QT_UINT32 (stsd_entry_data);
13045             guint16 sound_version = 0;
13046             /* FIXME: Can this be determined somehow? There doesn't seem to be
13047              * anything in mp4a atom that specifis compression */
13048             gint profile = 2;
13049             guint16 channels = entry->n_channels;
13050             guint32 time_scale = (guint32) entry->rate;
13051             gint sample_rate_index = -1;
13052 
13053             if (len >= 34) {
13054               sound_version = QT_UINT16 (stsd_entry_data + 16);
13055 
13056               if (sound_version == 1) {
13057                 channels = QT_UINT16 (stsd_entry_data + 24);
13058                 time_scale = QT_UINT32 (stsd_entry_data + 30);
13059               } else {
13060                 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
13061                     sound_version);
13062               }
13063             } else {
13064               GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
13065                   len);
13066             }
13067 
13068             sample_rate_index =
13069                 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13070             if (sample_rate_index >= 0 && channels > 0) {
13071               guint8 codec_data[2];
13072               GstBuffer *buf;
13073 
13074               /* build AAC codec data */
13075               codec_data[0] = profile << 3;
13076               codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13077               codec_data[1] = (sample_rate_index & 0x01) << 7;
13078               codec_data[1] |= (channels & 0xF) << 3;
13079 
13080               buf = gst_buffer_new_and_alloc (2);
13081               gst_buffer_fill (buf, 0, codec_data, 2);
13082               gst_caps_set_simple (entry->caps,
13083                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
13084               gst_buffer_unref (buf);
13085             }
13086             break;
13087           }
13088           case FOURCC_lpcm:
13089           case FOURCC_in24:
13090           case FOURCC_in32:
13091           case FOURCC_fl32:
13092           case FOURCC_fl64:
13093           case FOURCC_s16l:
13094             /* Fully handled elsewhere */
13095             break;
13096           default:
13097             GST_INFO_OBJECT (qtdemux,
13098                 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13099             break;
13100         }
13101       }
13102       GST_INFO_OBJECT (qtdemux,
13103           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13104           GST_FOURCC_ARGS (fourcc), entry->caps);
13105 
13106     } else if (stream->subtype == FOURCC_strm) {
13107       if (fourcc == FOURCC_rtsp) {
13108         stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13109       } else {
13110         GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13111             GST_FOURCC_ARGS (fourcc));
13112         goto unknown_stream;
13113       }
13114       entry->sampled = TRUE;
13115     } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13116         || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13117         || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13118 
13119       entry->sampled = TRUE;
13120       entry->sparse = TRUE;
13121 
13122       entry->caps =
13123           qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13124           &codec);
13125       if (codec) {
13126         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13127             GST_TAG_SUBTITLE_CODEC, codec, NULL);
13128         g_free (codec);
13129         codec = NULL;
13130       }
13131 
13132       /* hunt for sort-of codec data */
13133       switch (fourcc) {
13134         case FOURCC_mp4s:
13135         {
13136           GNode *mp4s = NULL;
13137           GNode *esds = NULL;
13138 
13139           /* look for palette in a stsd->mp4s->esds sub-atom */
13140           mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13141           if (mp4s)
13142             esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13143           if (esds == NULL) {
13144             /* Invalid STSD */
13145             GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13146             break;
13147           }
13148 
13149           gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13150               stream->stream_tags);
13151           break;
13152         }
13153         default:
13154           GST_INFO_OBJECT (qtdemux,
13155               "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13156           break;
13157       }
13158       GST_INFO_OBJECT (qtdemux,
13159           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13160           GST_FOURCC_ARGS (fourcc), entry->caps);
13161     } else {
13162       /* everything in 1 sample */
13163       entry->sampled = TRUE;
13164 
13165       entry->caps =
13166           qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13167           &codec);
13168 
13169       if (entry->caps == NULL)
13170         goto unknown_stream;
13171 
13172       if (codec) {
13173         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13174             GST_TAG_SUBTITLE_CODEC, codec, NULL);
13175         g_free (codec);
13176         codec = NULL;
13177       }
13178     }
13179 
13180     /* promote to sampled format */
13181     if (entry->fourcc == FOURCC_samr) {
13182       /* force mono 8000 Hz for AMR */
13183       entry->sampled = TRUE;
13184       entry->n_channels = 1;
13185       entry->rate = 8000;
13186     } else if (entry->fourcc == FOURCC_sawb) {
13187       /* force mono 16000 Hz for AMR-WB */
13188       entry->sampled = TRUE;
13189       entry->n_channels = 1;
13190       entry->rate = 16000;
13191     } else if (entry->fourcc == FOURCC_mp4a) {
13192       entry->sampled = TRUE;
13193     }
13194 
13195 
13196     stsd_entry_data += len;
13197     remaining_stsd_len -= len;
13198 
13199   }
13200 
13201   /* collect sample information */
13202   if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13203     goto samples_failed;
13204 
13205   if (qtdemux->fragmented) {
13206     guint64 offset;
13207 
13208     /* need all moov samples as basis; probably not many if any at all */
13209     /* prevent moof parsing taking of at this time */
13210     offset = qtdemux->moof_offset;
13211     qtdemux->moof_offset = 0;
13212     if (stream->n_samples &&
13213         !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13214       qtdemux->moof_offset = offset;
13215       goto samples_failed;
13216     }
13217     qtdemux->moof_offset = offset;
13218     /* movie duration more reliable in this case (e.g. mehd) */
13219     if (qtdemux->segment.duration &&
13220         GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13221       stream->duration =
13222           GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13223   }
13224 
13225   /* configure segments */
13226   if (!qtdemux_parse_segments (qtdemux, stream, trak))
13227     goto segments_failed;
13228 
13229   /* add some language tag, if useful */
13230   if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13231       strcmp (stream->lang_id, "und")) {
13232     const gchar *lang_code;
13233 
13234     /* convert ISO 639-2 code to ISO 639-1 */
13235     lang_code = gst_tag_get_language_code (stream->lang_id);
13236     gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13237         GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13238   }
13239 
13240   /* Check for UDTA tags */
13241   if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13242     qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13243   }
13244 
13245   /* Insert and sort new stream in track-id order.
13246    * This will help in comparing old/new streams during stream update check */
13247   g_ptr_array_add (qtdemux->active_streams, stream);
13248   g_ptr_array_sort (qtdemux->active_streams,
13249       (GCompareFunc) qtdemux_track_id_compare_func);
13250   GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13251       QTDEMUX_N_STREAMS (qtdemux));
13252 
13253   return TRUE;
13254 
13255 /* ERRORS */
13256 corrupt_file:
13257   {
13258     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13259         (_("This file is corrupt and cannot be played.")), (NULL));
13260     if (stream)
13261       gst_qtdemux_stream_unref (stream);
13262     return FALSE;
13263   }
13264 error_encrypted:
13265   {
13266     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13267     gst_qtdemux_stream_unref (stream);
13268     return FALSE;
13269   }
13270 samples_failed:
13271 segments_failed:
13272   {
13273     /* we posted an error already */
13274     /* free stbl sub-atoms */
13275     gst_qtdemux_stbl_free (stream);
13276     gst_qtdemux_stream_unref (stream);
13277     return FALSE;
13278   }
13279 existing_stream:
13280   {
13281     GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13282         track_id);
13283     return TRUE;
13284   }
13285 unknown_stream:
13286   {
13287     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13288         GST_FOURCC_ARGS (stream->subtype));
13289     gst_qtdemux_stream_unref (stream);
13290     return TRUE;
13291   }
13292 }
13293 
13294 /* If we can estimate the overall bitrate, and don't have information about the
13295  * stream bitrate for exactly one stream, this guesses the stream bitrate as
13296  * the overall bitrate minus the sum of the bitrates of all other streams. This
13297  * should be useful for the common case where we have one audio and one video
13298  * stream and can estimate the bitrate of one, but not the other. */
13299 static void
gst_qtdemux_guess_bitrate(GstQTDemux * qtdemux)13300 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13301 {
13302   QtDemuxStream *stream = NULL;
13303   gint64 size, sys_bitrate, sum_bitrate = 0;
13304   GstClockTime duration;
13305   guint bitrate;
13306   gint i;
13307 
13308   if (qtdemux->fragmented)
13309     return;
13310 
13311   GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13312 
13313   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13314       || size <= 0) {
13315     GST_DEBUG_OBJECT (qtdemux,
13316         "Size in bytes of the stream not known - bailing");
13317     return;
13318   }
13319 
13320   /* Subtract the header size */
13321   GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13322       size, qtdemux->header_size);
13323 
13324   if (size < qtdemux->header_size)
13325     return;
13326 
13327   size = size - qtdemux->header_size;
13328 
13329   if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13330     GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13331     return;
13332   }
13333 
13334   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13335     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13336     switch (str->subtype) {
13337       case FOURCC_soun:
13338       case FOURCC_vide:
13339         GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13340             CUR_STREAM (str)->caps);
13341         /* retrieve bitrate, prefer avg then max */
13342         bitrate = 0;
13343         if (str->stream_tags) {
13344           if (gst_tag_list_get_uint (str->stream_tags,
13345                   GST_TAG_MAXIMUM_BITRATE, &bitrate))
13346             GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13347           if (gst_tag_list_get_uint (str->stream_tags,
13348                   GST_TAG_NOMINAL_BITRATE, &bitrate))
13349             GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13350           if (gst_tag_list_get_uint (str->stream_tags,
13351                   GST_TAG_BITRATE, &bitrate))
13352             GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13353         }
13354         if (bitrate)
13355           sum_bitrate += bitrate;
13356         else {
13357           if (stream) {
13358             GST_DEBUG_OBJECT (qtdemux,
13359                 ">1 stream with unknown bitrate - bailing");
13360             return;
13361           } else
13362             stream = str;
13363         }
13364 
13365       default:
13366         /* For other subtypes, we assume no significant impact on bitrate */
13367         break;
13368     }
13369   }
13370 
13371   if (!stream) {
13372     GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13373     return;
13374   }
13375 
13376   sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13377 
13378   if (sys_bitrate < sum_bitrate) {
13379     /* This can happen, since sum_bitrate might be derived from maximum
13380      * bitrates and not average bitrates */
13381     GST_DEBUG_OBJECT (qtdemux,
13382         "System bitrate less than sum bitrate - bailing");
13383     return;
13384   }
13385 
13386   bitrate = sys_bitrate - sum_bitrate;
13387   GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13388       ", Stream bitrate = %u", sys_bitrate, bitrate);
13389 
13390   if (!stream->stream_tags)
13391     stream->stream_tags = gst_tag_list_new_empty ();
13392   else
13393     stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13394 
13395   gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13396       GST_TAG_BITRATE, bitrate, NULL);
13397 }
13398 
13399 static GstFlowReturn
qtdemux_prepare_streams(GstQTDemux * qtdemux)13400 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13401 {
13402   GstFlowReturn ret = GST_FLOW_OK;
13403   gint i;
13404 
13405   GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13406 
13407   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13408     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13409     guint32 sample_num = 0;
13410 
13411     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13412         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13413 
13414     if (qtdemux->fragmented && qtdemux->pullbased) {
13415       /* need all moov samples first */
13416       GST_OBJECT_LOCK (qtdemux);
13417       while (stream->n_samples == 0)
13418         if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13419           break;
13420       GST_OBJECT_UNLOCK (qtdemux);
13421     } else {
13422       /* discard any stray moof */
13423       qtdemux->moof_offset = 0;
13424     }
13425 
13426     /* prepare braking */
13427     if (ret != GST_FLOW_ERROR)
13428       ret = GST_FLOW_OK;
13429 
13430     /* in pull mode, we should have parsed some sample info by now;
13431      * and quite some code will not handle no samples.
13432      * in push mode, we'll just have to deal with it */
13433     if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13434       GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13435       g_ptr_array_remove_index (qtdemux->active_streams, i);
13436       i--;
13437       continue;
13438     } else if (stream->track_id == qtdemux->chapters_track_id &&
13439         (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13440       /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13441          so that it doesn't look like a subtitle track */
13442       g_ptr_array_remove_index (qtdemux->active_streams, i);
13443       i--;
13444       continue;
13445     }
13446 
13447     /* parse the initial sample for use in setting the frame rate cap */
13448     while (sample_num == 0 && sample_num < stream->n_samples) {
13449       if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13450         break;
13451       ++sample_num;
13452     }
13453   }
13454 
13455   return ret;
13456 }
13457 
13458 static gboolean
_stream_equal_func(const QtDemuxStream * stream,const gchar * stream_id)13459 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13460 {
13461   return g_strcmp0 (stream->stream_id, stream_id) == 0;
13462 }
13463 
13464 static gboolean
qtdemux_is_streams_update(GstQTDemux * qtdemux)13465 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13466 {
13467   gint i;
13468 
13469   /* Different length, updated */
13470   if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13471     return TRUE;
13472 
13473   /* streams in list are sorted in track-id order */
13474   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13475     /* Different stream-id, updated */
13476     if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13477             QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13478       return TRUE;
13479   }
13480 
13481   return FALSE;
13482 }
13483 
13484 static gboolean
qtdemux_reuse_and_configure_stream(GstQTDemux * qtdemux,QtDemuxStream * oldstream,QtDemuxStream * newstream)13485 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13486     QtDemuxStream * oldstream, QtDemuxStream * newstream)
13487 {
13488   /* Connect old stream's srcpad to new stream */
13489   newstream->pad = oldstream->pad;
13490   oldstream->pad = NULL;
13491 
13492   /* unset new_stream to prevent stream-start event, unless we are EOS in which
13493    * case we need to force one through */
13494   newstream->new_stream = GST_PAD_IS_EOS (newstream->pad);
13495 
13496   return gst_qtdemux_configure_stream (qtdemux, newstream);
13497 }
13498 
13499 static gboolean
qtdemux_update_streams(GstQTDemux * qtdemux)13500 qtdemux_update_streams (GstQTDemux * qtdemux)
13501 {
13502   gint i;
13503   g_assert (qtdemux->streams_aware);
13504 
13505   /* At below, figure out which stream in active_streams has identical stream-id
13506    * with that of in old_streams. If there is matching stream-id,
13507    * corresponding newstream will not be exposed again,
13508    * but demux will reuse srcpad of matched old stream
13509    *
13510    * active_streams : newly created streams from the latest moov
13511    * old_streams : existing streams (belong to previous moov)
13512    */
13513 
13514   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13515     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13516     QtDemuxStream *oldstream = NULL;
13517     guint target;
13518 
13519     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13520         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13521 
13522     if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13523             stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13524       oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13525 
13526       /* null pad stream cannot be reused */
13527       if (oldstream->pad == NULL)
13528         oldstream = NULL;
13529     }
13530 
13531     if (oldstream) {
13532       GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13533 
13534       if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13535         return FALSE;
13536 
13537       /* we don't need to preserve order of old streams */
13538       g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13539     } else {
13540       GstTagList *list;
13541 
13542       /* now we have all info and can expose */
13543       list = stream->stream_tags;
13544       stream->stream_tags = NULL;
13545       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13546         return FALSE;
13547     }
13548   }
13549 
13550   return TRUE;
13551 }
13552 
13553 /* Must be called with expose lock */
13554 static GstFlowReturn
qtdemux_expose_streams(GstQTDemux * qtdemux)13555 qtdemux_expose_streams (GstQTDemux * qtdemux)
13556 {
13557   gint i;
13558 
13559   GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13560 
13561   if (!qtdemux_is_streams_update (qtdemux)) {
13562     GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13563     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13564       QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13565       QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13566       if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13567         return GST_FLOW_ERROR;
13568     }
13569 
13570     g_ptr_array_set_size (qtdemux->old_streams, 0);
13571     qtdemux->need_segment = TRUE;
13572 
13573     return GST_FLOW_OK;
13574   }
13575 
13576   if (qtdemux->streams_aware) {
13577     if (!qtdemux_update_streams (qtdemux))
13578       return GST_FLOW_ERROR;
13579   } else {
13580     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13581       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13582       GstTagList *list;
13583 
13584       /* now we have all info and can expose */
13585       list = stream->stream_tags;
13586       stream->stream_tags = NULL;
13587       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13588         return GST_FLOW_ERROR;
13589 
13590     }
13591   }
13592 
13593   gst_qtdemux_guess_bitrate (qtdemux);
13594 
13595   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13596 
13597   /* If we have still old_streams, it's no more used stream */
13598   for (i = 0; i < qtdemux->old_streams->len; i++) {
13599     QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13600 
13601     if (stream->pad) {
13602       GstEvent *event;
13603 
13604       event = gst_event_new_eos ();
13605       if (qtdemux->segment_seqnum)
13606         gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13607 
13608       gst_pad_push_event (stream->pad, event);
13609     }
13610   }
13611 
13612   g_ptr_array_set_size (qtdemux->old_streams, 0);
13613 
13614   /* check if we should post a redirect in case there is a single trak
13615    * and it is a redirecting trak */
13616   if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13617       QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13618     GstMessage *m;
13619 
13620     GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13621         "an external content");
13622     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13623         gst_structure_new ("redirect",
13624             "new-location", G_TYPE_STRING,
13625             QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13626     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13627     g_free (qtdemux->redirect_location);
13628     qtdemux->redirect_location =
13629         g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13630   }
13631 
13632   g_ptr_array_foreach (qtdemux->active_streams,
13633       (GFunc) qtdemux_do_allocation, qtdemux);
13634 
13635   qtdemux->need_segment = TRUE;
13636 
13637   qtdemux->exposed = TRUE;
13638   return GST_FLOW_OK;
13639 }
13640 
13641 typedef struct
13642 {
13643   GstStructure *structure;      /* helper for sort function */
13644   gchar *location;
13645   guint min_req_bitrate;
13646   guint min_req_qt_version;
13647 } GstQtReference;
13648 
13649 static gint
qtdemux_redirects_sort_func(gconstpointer a,gconstpointer b)13650 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13651 {
13652   GstQtReference *ref_a = (GstQtReference *) a;
13653   GstQtReference *ref_b = (GstQtReference *) b;
13654 
13655   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13656     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13657 
13658   /* known bitrates go before unknown; higher bitrates go first */
13659   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13660 }
13661 
13662 /* sort the redirects and post a message for the application.
13663  */
13664 static void
qtdemux_process_redirects(GstQTDemux * qtdemux,GList * references)13665 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13666 {
13667   GstQtReference *best;
13668   GstStructure *s;
13669   GstMessage *msg;
13670   GValue list_val = { 0, };
13671   GList *l;
13672 
13673   g_assert (references != NULL);
13674 
13675   references = g_list_sort (references, qtdemux_redirects_sort_func);
13676 
13677   best = (GstQtReference *) references->data;
13678 
13679   g_value_init (&list_val, GST_TYPE_LIST);
13680 
13681   for (l = references; l != NULL; l = l->next) {
13682     GstQtReference *ref = (GstQtReference *) l->data;
13683     GValue struct_val = { 0, };
13684 
13685     ref->structure = gst_structure_new ("redirect",
13686         "new-location", G_TYPE_STRING, ref->location, NULL);
13687 
13688     if (ref->min_req_bitrate > 0) {
13689       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13690           ref->min_req_bitrate, NULL);
13691     }
13692 
13693     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13694     g_value_set_boxed (&struct_val, ref->structure);
13695     gst_value_list_append_value (&list_val, &struct_val);
13696     g_value_unset (&struct_val);
13697     /* don't free anything here yet, since we need best->structure below */
13698   }
13699 
13700   g_assert (best != NULL);
13701   s = gst_structure_copy (best->structure);
13702 
13703   if (g_list_length (references) > 1) {
13704     gst_structure_set_value (s, "locations", &list_val);
13705   }
13706 
13707   g_value_unset (&list_val);
13708 
13709   for (l = references; l != NULL; l = l->next) {
13710     GstQtReference *ref = (GstQtReference *) l->data;
13711 
13712     gst_structure_free (ref->structure);
13713     g_free (ref->location);
13714     g_free (ref);
13715   }
13716   g_list_free (references);
13717 
13718   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13719   g_free (qtdemux->redirect_location);
13720   qtdemux->redirect_location =
13721       g_strdup (gst_structure_get_string (s, "new-location"));
13722   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13723   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13724 }
13725 
13726 /* look for redirect nodes, collect all redirect information and
13727  * process it.
13728  */
13729 static gboolean
qtdemux_parse_redirects(GstQTDemux * qtdemux)13730 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13731 {
13732   GNode *rmra, *rmda, *rdrf;
13733 
13734   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13735   if (rmra) {
13736     GList *redirects = NULL;
13737 
13738     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13739     while (rmda) {
13740       GstQtReference ref = { NULL, NULL, 0, 0 };
13741       GNode *rmdr, *rmvc;
13742 
13743       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13744         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13745         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13746             ref.min_req_bitrate);
13747       }
13748 
13749       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13750         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13751         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13752 
13753 #ifndef GST_DISABLE_GST_DEBUG
13754         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13755 #endif
13756         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13757 
13758         GST_LOG_OBJECT (qtdemux,
13759             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13760             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13761             bitmask, check_type);
13762         if (package == FOURCC_qtim && check_type == 0) {
13763           ref.min_req_qt_version = version;
13764         }
13765       }
13766 
13767       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13768       if (rdrf) {
13769         guint32 ref_type;
13770         guint8 *ref_data;
13771         guint ref_len;
13772 
13773         ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13774         if (ref_len > 20) {
13775           ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13776           ref_data = (guint8 *) rdrf->data + 20;
13777           if (ref_type == FOURCC_alis) {
13778             guint record_len, record_version, fn_len;
13779 
13780             if (ref_len > 70) {
13781               /* MacOSX alias record, google for alias-layout.txt */
13782               record_len = QT_UINT16 (ref_data + 4);
13783               record_version = QT_UINT16 (ref_data + 4 + 2);
13784               fn_len = QT_UINT8 (ref_data + 50);
13785               if (record_len > 50 && record_version == 2 && fn_len > 0) {
13786                 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13787               }
13788             } else {
13789               GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13790                   ref_len);
13791             }
13792           } else if (ref_type == FOURCC_url_) {
13793             ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13794           } else {
13795             GST_DEBUG_OBJECT (qtdemux,
13796                 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13797                 GST_FOURCC_ARGS (ref_type));
13798           }
13799           if (ref.location != NULL) {
13800             GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13801             redirects =
13802                 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13803           } else {
13804             GST_WARNING_OBJECT (qtdemux,
13805                 "Failed to extract redirect location from rdrf atom");
13806           }
13807         } else {
13808           GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13809         }
13810       }
13811 
13812       /* look for others */
13813       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13814     }
13815 
13816     if (redirects != NULL) {
13817       qtdemux_process_redirects (qtdemux, redirects);
13818     }
13819   }
13820   return TRUE;
13821 }
13822 
13823 static GstTagList *
qtdemux_add_container_format(GstQTDemux * qtdemux,GstTagList * tags)13824 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13825 {
13826   const gchar *fmt;
13827 
13828   if (tags == NULL) {
13829     tags = gst_tag_list_new_empty ();
13830     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13831   }
13832 
13833   if (qtdemux->major_brand == FOURCC_mjp2)
13834     fmt = "Motion JPEG 2000";
13835   else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13836     fmt = "3GP";
13837   else if (qtdemux->major_brand == FOURCC_qt__)
13838     fmt = "Quicktime";
13839   else if (qtdemux->fragmented)
13840     fmt = "ISO fMP4";
13841   else
13842     fmt = "ISO MP4/M4A";
13843 
13844   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13845       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13846 
13847   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13848       fmt, NULL);
13849 
13850   return tags;
13851 }
13852 
13853 /* we have read the complete moov node now.
13854  * This function parses all of the relevant info, creates the traks and
13855  * prepares all data structures for playback
13856  */
13857 static gboolean
qtdemux_parse_tree(GstQTDemux * qtdemux)13858 qtdemux_parse_tree (GstQTDemux * qtdemux)
13859 {
13860   GNode *mvhd;
13861   GNode *trak;
13862   GNode *udta;
13863   GNode *mvex;
13864   GNode *pssh;
13865   guint64 creation_time;
13866   GstDateTime *datetime = NULL;
13867   gint version;
13868 
13869   /* make sure we have a usable taglist */
13870   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13871 
13872   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13873   if (mvhd == NULL) {
13874     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13875     return qtdemux_parse_redirects (qtdemux);
13876   }
13877 
13878   version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13879   if (version == 1) {
13880     creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13881     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13882     qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13883   } else if (version == 0) {
13884     creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13885     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13886     qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13887   } else {
13888     GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13889     return FALSE;
13890   }
13891 
13892   /* Moving qt creation time (secs since 1904) to unix time */
13893   if (creation_time != 0) {
13894     /* Try to use epoch first as it should be faster and more commonly found */
13895     if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13896       gint64 now_s;
13897 
13898       creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13899       /* some data cleansing sanity */
13900       now_s = g_get_real_time () / G_USEC_PER_SEC;
13901       if (now_s + 24 * 3600 < creation_time) {
13902         GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13903       } else {
13904         datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13905       }
13906     } else {
13907       GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13908       GDateTime *dt, *dt_local;
13909 
13910       dt = g_date_time_add_seconds (base_dt, creation_time);
13911       dt_local = g_date_time_to_local (dt);
13912       datetime = gst_date_time_new_from_g_date_time (dt_local);
13913 
13914       g_date_time_unref (base_dt);
13915       g_date_time_unref (dt);
13916     }
13917   }
13918   if (datetime) {
13919     /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13920     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13921         datetime, NULL);
13922     gst_date_time_unref (datetime);
13923   }
13924 
13925   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13926   GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13927 
13928   /* check for fragmented file and get some (default) data */
13929   mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13930   if (mvex) {
13931     GNode *mehd;
13932     GstByteReader mehd_data;
13933 
13934     /* let track parsing or anyone know weird stuff might happen ... */
13935     qtdemux->fragmented = TRUE;
13936 
13937     /* compensate for total duration */
13938     mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13939     if (mehd)
13940       qtdemux_parse_mehd (qtdemux, &mehd_data);
13941   }
13942 
13943   /* Update the movie segment duration, unless it was directly given to us
13944    * by upstream. Otherwise let it as is, as we don't want to mangle the
13945    * duration provided by upstream that may come e.g. from a MPD file. */
13946   if (!qtdemux->upstream_format_is_time) {
13947     GstClockTime duration;
13948     /* set duration in the segment info */
13949     gst_qtdemux_get_duration (qtdemux, &duration);
13950     qtdemux->segment.duration = duration;
13951     /* also do not exceed duration; stop is set that way post seek anyway,
13952      * and segment activation falls back to duration,
13953      * whereas loop only checks stop, so let's align this here as well */
13954     qtdemux->segment.stop = duration;
13955   }
13956 
13957   /* parse all traks */
13958   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13959   while (trak) {
13960     qtdemux_parse_trak (qtdemux, trak);
13961     /* iterate all siblings */
13962     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13963   }
13964 
13965   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13966 
13967   /* find tags */
13968   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13969   if (udta) {
13970     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13971   } else {
13972     GST_LOG_OBJECT (qtdemux, "No udta node found.");
13973   }
13974 
13975   /* maybe also some tags in meta box */
13976   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13977   if (udta) {
13978     GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13979     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13980   } else {
13981     GST_LOG_OBJECT (qtdemux, "No meta node found.");
13982   }
13983 
13984   /* parse any protection system info */
13985   pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13986   while (pssh) {
13987     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13988     qtdemux_parse_pssh (qtdemux, pssh);
13989     pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13990   }
13991 
13992   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13993 
13994   return TRUE;
13995 }
13996 
13997 /* taken from ffmpeg */
13998 static int
read_descr_size(guint8 * ptr,guint8 * end,guint8 ** end_out)13999 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14000 {
14001   int count = 4;
14002   int len = 0;
14003 
14004   while (count--) {
14005     int c;
14006 
14007     if (ptr >= end)
14008       return -1;
14009 
14010     c = *ptr++;
14011     len = (len << 7) | (c & 0x7f);
14012     if (!(c & 0x80))
14013       break;
14014   }
14015   *end_out = ptr;
14016   return len;
14017 }
14018 
14019 static GList *
parse_xiph_stream_headers(GstQTDemux * qtdemux,gpointer codec_data,gsize codec_data_size)14020 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14021     gsize codec_data_size)
14022 {
14023   GList *list = NULL;
14024   guint8 *p = codec_data;
14025   gint i, offset, num_packets;
14026   guint *length, last;
14027 
14028   GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14029 
14030   if (codec_data == NULL || codec_data_size == 0)
14031     goto error;
14032 
14033   /* start of the stream and vorbis audio or theora video, need to
14034    * send the codec_priv data as first three packets */
14035   num_packets = p[0] + 1;
14036   GST_DEBUG_OBJECT (qtdemux,
14037       "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14038       (guint) num_packets, codec_data_size);
14039 
14040   /* Let's put some limits, Don't think there even is a xiph codec
14041    * with more than 3-4 headers */
14042   if (G_UNLIKELY (num_packets > 16)) {
14043     GST_WARNING_OBJECT (qtdemux,
14044         "Unlikely number of xiph headers, most likely not valid");
14045     goto error;
14046   }
14047 
14048   length = g_alloca (num_packets * sizeof (guint));
14049   last = 0;
14050   offset = 1;
14051 
14052   /* first packets, read length values */
14053   for (i = 0; i < num_packets - 1; i++) {
14054     length[i] = 0;
14055     while (offset < codec_data_size) {
14056       length[i] += p[offset];
14057       if (p[offset++] != 0xff)
14058         break;
14059     }
14060     last += length[i];
14061   }
14062   if (offset + last > codec_data_size)
14063     goto error;
14064 
14065   /* last packet is the remaining size */
14066   length[i] = codec_data_size - offset - last;
14067 
14068   for (i = 0; i < num_packets; i++) {
14069     GstBuffer *hdr;
14070 
14071     GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14072 
14073     if (offset + length[i] > codec_data_size)
14074       goto error;
14075 
14076     hdr = gst_buffer_new_memdup (p + offset, length[i]);
14077     list = g_list_append (list, hdr);
14078 
14079     offset += length[i];
14080   }
14081 
14082   return list;
14083 
14084   /* ERRORS */
14085 error:
14086   {
14087     if (list != NULL)
14088       g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14089     return NULL;
14090   }
14091 
14092 }
14093 
14094 /* this can change the codec originally present in @list */
14095 static void
gst_qtdemux_handle_esds(GstQTDemux * qtdemux,QtDemuxStream * stream,QtDemuxStreamStsdEntry * entry,GNode * esds,GstTagList * list)14096 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14097     QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14098 {
14099   int len = QT_UINT32 (esds->data);
14100   guint8 *ptr = esds->data;
14101   guint8 *end = ptr + len;
14102   int tag;
14103   guint8 *data_ptr = NULL;
14104   int data_len = 0;
14105   guint8 object_type_id = 0;
14106   guint8 stream_type = 0;
14107   const char *codec_name = NULL;
14108   GstCaps *caps = NULL;
14109 
14110   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14111   ptr += 8;
14112   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14113   ptr += 4;
14114   while (ptr + 1 < end) {
14115     tag = QT_UINT8 (ptr);
14116     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14117     ptr++;
14118     len = read_descr_size (ptr, end, &ptr);
14119     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14120 
14121     /* Check the stated amount of data is available for reading */
14122     if (len < 0 || ptr + len > end)
14123       break;
14124 
14125     switch (tag) {
14126       case ES_DESCRIPTOR_TAG:
14127         GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14128         GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14129         ptr += 3;
14130         break;
14131       case DECODER_CONFIG_DESC_TAG:{
14132         guint max_bitrate, avg_bitrate;
14133 
14134         object_type_id = QT_UINT8 (ptr);
14135         stream_type = QT_UINT8 (ptr + 1) >> 2;
14136         max_bitrate = QT_UINT32 (ptr + 5);
14137         avg_bitrate = QT_UINT32 (ptr + 9);
14138         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14139         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14140         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14141         GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14142         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14143         if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14144           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14145               GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14146         }
14147         if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14148           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14149               avg_bitrate, NULL);
14150         }
14151         ptr += 13;
14152         break;
14153       }
14154       case DECODER_SPECIFIC_INFO_TAG:
14155         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14156         if (object_type_id == 0xe0 && len == 0x40) {
14157           guint8 *data;
14158           GstStructure *s;
14159           guint32 clut[16];
14160           gint i;
14161 
14162           GST_DEBUG_OBJECT (qtdemux,
14163               "Have VOBSUB palette. Creating palette event");
14164           /* move to decConfigDescr data and read palette */
14165           data = ptr;
14166           for (i = 0; i < 16; i++) {
14167             clut[i] = QT_UINT32 (data);
14168             data += 4;
14169           }
14170 
14171           s = gst_structure_new ("application/x-gst-dvd", "event",
14172               G_TYPE_STRING, "dvd-spu-clut-change",
14173               "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14174               "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14175               "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14176               "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14177               "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14178               "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14179               "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14180               "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14181               NULL);
14182 
14183           /* store event and trigger custom processing */
14184           stream->pending_event =
14185               gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14186         } else {
14187           /* Generic codec_data handler puts it on the caps */
14188           data_ptr = ptr;
14189           data_len = len;
14190         }
14191 
14192         ptr += len;
14193         break;
14194       case SL_CONFIG_DESC_TAG:
14195         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14196         ptr += 1;
14197         break;
14198       default:
14199         GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14200             tag);
14201         GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14202         ptr += len;
14203         break;
14204     }
14205   }
14206 
14207   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14208    * in use, and should also be used to override some other parameters for some
14209    * codecs. */
14210   switch (object_type_id) {
14211     case 0x20:                 /* MPEG-4 */
14212       /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14213        * profile_and_level_indication */
14214       if (data_ptr != NULL && data_len >= 5 &&
14215           GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14216         gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14217             data_ptr + 4, data_len - 4);
14218       }
14219       break;                    /* Nothing special needed here */
14220     case 0x21:                 /* H.264 */
14221       codec_name = "H.264 / AVC";
14222       caps = gst_caps_new_simple ("video/x-h264",
14223           "stream-format", G_TYPE_STRING, "avc",
14224           "alignment", G_TYPE_STRING, "au", NULL);
14225       break;
14226     case 0x40:                 /* AAC (any) */
14227     case 0x66:                 /* AAC Main */
14228     case 0x67:                 /* AAC LC */
14229     case 0x68:                 /* AAC SSR */
14230       /* Override channels and rate based on the codec_data, as it's often
14231        * wrong. */
14232       /* Only do so for basic setup without HE-AAC extension */
14233 #ifdef OHOS_OPT_COMPAT
14234       /*
14235        * ohos.opt.compat.0030
14236        * sampling rate is get wrong, in special code flow
14237        */
14238       if (data_ptr && data_len >= 2) {
14239 #else
14240       if (data_ptr && data_len == 2) {
14241 #endif
14242         guint channels, rate;
14243 
14244         channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14245         if (channels > 0)
14246           entry->n_channels = channels;
14247 
14248         rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14249         if (rate > 0)
14250           entry->rate = rate;
14251       }
14252 
14253       /* Set level and profile if possible */
14254       if (data_ptr != NULL && data_len >= 2) {
14255         gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14256             data_ptr, data_len);
14257       } else {
14258         const gchar *profile_str = NULL;
14259         GstBuffer *buffer;
14260         GstMapInfo map;
14261         guint8 *codec_data;
14262         gint rate_idx, profile;
14263 
14264         /* No codec_data, let's invent something.
14265          * FIXME: This is wrong for SBR! */
14266 
14267         GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14268 
14269         buffer = gst_buffer_new_and_alloc (2);
14270         gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14271         codec_data = map.data;
14272 
14273         rate_idx =
14274             gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14275             (stream)->rate);
14276 
14277         switch (object_type_id) {
14278           case 0x66:
14279             profile_str = "main";
14280             profile = 0;
14281             break;
14282           case 0x67:
14283             profile_str = "lc";
14284             profile = 1;
14285             break;
14286           case 0x68:
14287             profile_str = "ssr";
14288             profile = 2;
14289             break;
14290           default:
14291             profile = 3;
14292             break;
14293         }
14294 
14295         codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14296         codec_data[1] =
14297             ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14298 
14299         gst_buffer_unmap (buffer, &map);
14300         gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14301             GST_TYPE_BUFFER, buffer, NULL);
14302         gst_buffer_unref (buffer);
14303 
14304         if (profile_str) {
14305           gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14306               G_TYPE_STRING, profile_str, NULL);
14307         }
14308       }
14309       break;
14310     case 0x60:                 /* MPEG-2, various profiles */
14311     case 0x61:
14312     case 0x62:
14313     case 0x63:
14314     case 0x64:
14315     case 0x65:
14316       codec_name = "MPEG-2 video";
14317       caps = gst_caps_new_simple ("video/mpeg",
14318           "mpegversion", G_TYPE_INT, 2,
14319           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14320       break;
14321     case 0x69:                 /* MPEG-2 BC audio */
14322     case 0x6B:                 /* MPEG-1 audio */
14323       caps = gst_caps_new_simple ("audio/mpeg",
14324           "mpegversion", G_TYPE_INT, 1, NULL);
14325       codec_name = "MPEG-1 audio";
14326       break;
14327     case 0x6A:                 /* MPEG-1 */
14328       codec_name = "MPEG-1 video";
14329       caps = gst_caps_new_simple ("video/mpeg",
14330           "mpegversion", G_TYPE_INT, 1,
14331           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14332       break;
14333     case 0x6C:                 /* MJPEG */
14334       caps =
14335           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14336           NULL);
14337       codec_name = "Motion-JPEG";
14338       break;
14339     case 0x6D:                 /* PNG */
14340       caps =
14341           gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14342           NULL);
14343       codec_name = "PNG still images";
14344       break;
14345     case 0x6E:                 /* JPEG2000 */
14346       codec_name = "JPEG-2000";
14347       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14348       break;
14349     case 0xA4:                 /* Dirac */
14350       codec_name = "Dirac";
14351       caps = gst_caps_new_empty_simple ("video/x-dirac");
14352       break;
14353     case 0xA5:                 /* AC3 */
14354       codec_name = "AC-3 audio";
14355       caps = gst_caps_new_simple ("audio/x-ac3",
14356           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14357       break;
14358     case 0xA9:                 /* AC3 */
14359       codec_name = "DTS audio";
14360       caps = gst_caps_new_simple ("audio/x-dts",
14361           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14362       break;
14363     case 0xDD:
14364       if (stream_type == 0x05 && data_ptr) {
14365         GList *headers =
14366             parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14367         if (headers) {
14368           GList *tmp;
14369           GValue arr_val = G_VALUE_INIT;
14370           GValue buf_val = G_VALUE_INIT;
14371           GstStructure *s;
14372 
14373           /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14374           codec_name = "Vorbis";
14375           caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14376 #ifdef OHOS_OPT_COMPAT
14377           // ohos.opt.compat.0031. adapter for avdec_vorbis
14378           GstBuffer *codec_data = gst_buffer_new_allocate (NULL, data_len, NULL);
14379           if (codec_data != NULL) {
14380             gst_buffer_fill (codec_data, 0, data_ptr, data_len);
14381             gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
14382             gst_buffer_unref (codec_data);
14383           } else {
14384             GST_ERROR_OBJECT (qtdemux, "gst_buffer_new_wrapped failed");
14385           }
14386 #endif
14387           g_value_init (&arr_val, GST_TYPE_ARRAY);
14388           g_value_init (&buf_val, GST_TYPE_BUFFER);
14389           for (tmp = headers; tmp; tmp = tmp->next) {
14390             g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14391             gst_value_array_append_value (&arr_val, &buf_val);
14392           }
14393           s = gst_caps_get_structure (caps, 0);
14394           gst_structure_take_value (s, "streamheader", &arr_val);
14395           g_value_unset (&buf_val);
14396           g_list_free (headers);
14397 
14398           data_ptr = NULL;
14399           data_len = 0;
14400         }
14401       }
14402       break;
14403     case 0xE1:                 /* QCELP */
14404       /* QCELP, the codec_data is a riff tag (little endian) with
14405        * 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). */
14406       caps = gst_caps_new_empty_simple ("audio/qcelp");
14407       codec_name = "QCELP";
14408       break;
14409     default:
14410       break;
14411   }
14412 
14413   /* If we have a replacement caps, then change our caps for this stream */
14414   if (caps) {
14415     gst_caps_unref (entry->caps);
14416     entry->caps = caps;
14417   }
14418 
14419   if (codec_name && list)
14420     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14421         GST_TAG_AUDIO_CODEC, codec_name, NULL);
14422 
14423   /* Add the codec_data attribute to caps, if we have it */
14424   if (data_ptr) {
14425     GstBuffer *buffer;
14426 
14427     buffer = gst_buffer_new_and_alloc (data_len);
14428     gst_buffer_fill (buffer, 0, data_ptr, data_len);
14429 
14430     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14431     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14432 
14433     gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14434         buffer, NULL);
14435     gst_buffer_unref (buffer);
14436   }
14437 
14438 }
14439 
14440 static inline GstCaps *
14441 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14442 {
14443   GstCaps *caps;
14444   guint i;
14445   char *s, fourstr[5];
14446 
14447   g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14448   for (i = 0; i < 4; i++) {
14449     if (!g_ascii_isalnum (fourstr[i]))
14450       fourstr[i] = '_';
14451   }
14452   s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14453   caps = gst_caps_new_empty_simple (s);
14454   g_free (s);
14455   return caps;
14456 }
14457 
14458 #define _codec(name) \
14459   do { \
14460     if (codec_name) { \
14461       *codec_name = g_strdup (name); \
14462     } \
14463   } while (0)
14464 
14465 static GstCaps *
14466 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14467     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14468     const guint8 * stsd_entry_data, gchar ** codec_name)
14469 {
14470   GstCaps *caps = NULL;
14471   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14472 
14473   switch (fourcc) {
14474     case FOURCC_png:
14475       _codec ("PNG still images");
14476       caps = gst_caps_new_empty_simple ("image/png");
14477       break;
14478     case FOURCC_jpeg:
14479       _codec ("JPEG still images");
14480       caps =
14481           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14482           NULL);
14483       break;
14484     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14485     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14486     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14487     case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14488       _codec ("Motion-JPEG");
14489       caps =
14490           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14491           NULL);
14492       break;
14493     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14494       _codec ("Motion-JPEG format B");
14495       caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14496       break;
14497     case FOURCC_mjp2:
14498       _codec ("JPEG-2000");
14499       /* override to what it should be according to spec, avoid palette_data */
14500       entry->bits_per_sample = 24;
14501       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14502       break;
14503     case FOURCC_SVQ3:
14504       _codec ("Sorensen video v.3");
14505       caps = gst_caps_new_simple ("video/x-svq",
14506           "svqversion", G_TYPE_INT, 3, NULL);
14507       break;
14508     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14509     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14510       _codec ("Sorensen video v.1");
14511       caps = gst_caps_new_simple ("video/x-svq",
14512           "svqversion", G_TYPE_INT, 1, NULL);
14513       break;
14514     case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14515       caps = gst_caps_new_empty_simple ("video/x-raw");
14516       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14517       _codec ("Windows Raw RGB");
14518       stream->alignment = 32;
14519       break;
14520     case FOURCC_raw_:
14521     {
14522       guint16 bps;
14523 
14524       bps = QT_UINT16 (stsd_entry_data + 82);
14525       switch (bps) {
14526         case 15:
14527           format = GST_VIDEO_FORMAT_RGB15;
14528           break;
14529         case 16:
14530           format = GST_VIDEO_FORMAT_RGB16;
14531           break;
14532         case 24:
14533           format = GST_VIDEO_FORMAT_RGB;
14534           break;
14535         case 32:
14536           format = GST_VIDEO_FORMAT_ARGB;
14537           break;
14538         default:
14539           /* unknown */
14540           break;
14541       }
14542       break;
14543     }
14544     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14545       format = GST_VIDEO_FORMAT_I420;
14546       break;
14547     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14548     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14549       format = GST_VIDEO_FORMAT_I420;
14550       break;
14551     case FOURCC_2vuy:
14552     case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14553       format = GST_VIDEO_FORMAT_UYVY;
14554       break;
14555     case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14556       format = GST_VIDEO_FORMAT_v308;
14557       break;
14558     case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14559       format = GST_VIDEO_FORMAT_v216;
14560       break;
14561     case FOURCC_v210:
14562       format = GST_VIDEO_FORMAT_v210;
14563       break;
14564     case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14565       format = GST_VIDEO_FORMAT_r210;
14566       break;
14567       /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14568          case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14569          format = GST_VIDEO_FORMAT_v410;
14570          break;
14571        */
14572       /* Packed YUV 4:4:4:4 8 bit in 32 bits
14573        * but different order than AYUV
14574        case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14575        format = GST_VIDEO_FORMAT_v408;
14576        break;
14577        */
14578     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14579     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14580       _codec ("MPEG-1 video");
14581       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14582           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14583       break;
14584     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14585     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14586     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14587     case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14588     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14589     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14590     case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14591     case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14592     case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14593     case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14594     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14595     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14596     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14597     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14598     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14599     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14600     case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14601     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14602     case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14603     case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14604     case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14605     case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14606     case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14607     case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14608     case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14609     case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14610     case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14611     case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14612     case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14613     case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14614     case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14615     case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14616     case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14617     case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14618     case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14619     case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14620     case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14621     case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14622     case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14623     case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14624     case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14625     case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14626     case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14627     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14628     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14629     case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14630     case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14631       _codec ("MPEG-2 video");
14632       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14633           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14634       break;
14635     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14636       _codec ("GIF still images");
14637       caps = gst_caps_new_empty_simple ("image/gif");
14638       break;
14639     case FOURCC_h263:
14640     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14641     case FOURCC_s263:
14642     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14643       _codec ("H.263");
14644       /* ffmpeg uses the height/width props, don't know why */
14645       caps = gst_caps_new_simple ("video/x-h263",
14646           "variant", G_TYPE_STRING, "itu", NULL);
14647       break;
14648     case FOURCC_mp4v:
14649     case FOURCC_MP4V:
14650       _codec ("MPEG-4 video");
14651       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14652           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14653       break;
14654     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14655     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14656       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
14657       caps = gst_caps_new_simple ("video/x-msmpeg",
14658           "msmpegversion", G_TYPE_INT, 43, NULL);
14659       break;
14660     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14661       _codec ("DivX 3");
14662       caps = gst_caps_new_simple ("video/x-divx",
14663           "divxversion", G_TYPE_INT, 3, NULL);
14664       break;
14665     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14666     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14667       _codec ("DivX 4");
14668       caps = gst_caps_new_simple ("video/x-divx",
14669           "divxversion", G_TYPE_INT, 4, NULL);
14670       break;
14671     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14672       _codec ("DivX 5");
14673       caps = gst_caps_new_simple ("video/x-divx",
14674           "divxversion", G_TYPE_INT, 5, NULL);
14675       break;
14676 
14677     case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14678       _codec ("FFV1");
14679       caps = gst_caps_new_simple ("video/x-ffv",
14680           "ffvversion", G_TYPE_INT, 1, NULL);
14681       break;
14682 
14683     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14684     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14685     case FOURCC_XVID:
14686     case FOURCC_xvid:
14687     case FOURCC_FMP4:
14688     case FOURCC_fmp4:
14689     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14690       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14691           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14692       _codec ("MPEG-4");
14693       break;
14694 
14695     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14696       _codec ("Cinepak");
14697       caps = gst_caps_new_empty_simple ("video/x-cinepak");
14698       break;
14699     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14700       _codec ("Apple QuickDraw");
14701       caps = gst_caps_new_empty_simple ("video/x-qdrw");
14702       break;
14703     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14704       _codec ("Apple video");
14705       caps = gst_caps_new_empty_simple ("video/x-apple-video");
14706       break;
14707     case FOURCC_H264:
14708     case FOURCC_avc1:
14709     case FOURCC_dva1:
14710       _codec ("H.264 / AVC");
14711       caps = gst_caps_new_simple ("video/x-h264",
14712           "stream-format", G_TYPE_STRING, "avc",
14713           "alignment", G_TYPE_STRING, "au", NULL);
14714       break;
14715     case FOURCC_avc3:
14716     case FOURCC_dvav:
14717       _codec ("H.264 / AVC");
14718       caps = gst_caps_new_simple ("video/x-h264",
14719           "stream-format", G_TYPE_STRING, "avc3",
14720           "alignment", G_TYPE_STRING, "au", NULL);
14721       break;
14722     case FOURCC_H265:
14723     case FOURCC_hvc1:
14724     case FOURCC_dvh1:
14725       _codec ("H.265 / HEVC");
14726       caps = gst_caps_new_simple ("video/x-h265",
14727           "stream-format", G_TYPE_STRING, "hvc1",
14728           "alignment", G_TYPE_STRING, "au", NULL);
14729       break;
14730     case FOURCC_hev1:
14731     case FOURCC_dvhe:
14732       _codec ("H.265 / HEVC");
14733       caps = gst_caps_new_simple ("video/x-h265",
14734           "stream-format", G_TYPE_STRING, "hev1",
14735           "alignment", G_TYPE_STRING, "au", NULL);
14736       break;
14737     case FOURCC_rle_:
14738       _codec ("Run-length encoding");
14739       caps = gst_caps_new_simple ("video/x-rle",
14740           "layout", G_TYPE_STRING, "quicktime", NULL);
14741       break;
14742     case FOURCC_WRLE:
14743       _codec ("Run-length encoding");
14744       caps = gst_caps_new_simple ("video/x-rle",
14745           "layout", G_TYPE_STRING, "microsoft", NULL);
14746       break;
14747     case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14748     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14749       _codec ("Indeo Video 3");
14750       caps = gst_caps_new_simple ("video/x-indeo",
14751           "indeoversion", G_TYPE_INT, 3, NULL);
14752       break;
14753     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14754     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14755       _codec ("Intel Video 4");
14756       caps = gst_caps_new_simple ("video/x-indeo",
14757           "indeoversion", G_TYPE_INT, 4, NULL);
14758       break;
14759     case FOURCC_dvcp:
14760     case FOURCC_dvc_:
14761     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14762     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14763     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14764     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14765     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14766     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14767       _codec ("DV Video");
14768       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14769           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14770       break;
14771     case FOURCC_dv5n:          /* DVCPRO50 NTSC */
14772     case FOURCC_dv5p:          /* DVCPRO50 PAL */
14773       _codec ("DVCPro50 Video");
14774       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14775           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14776       break;
14777     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14778     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14779       _codec ("DVCProHD Video");
14780       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14781           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14782       break;
14783     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14784       _codec ("Apple Graphics (SMC)");
14785       caps = gst_caps_new_empty_simple ("video/x-smc");
14786       break;
14787     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14788       _codec ("VP3");
14789       caps = gst_caps_new_empty_simple ("video/x-vp3");
14790       break;
14791     case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14792       _codec ("VP6 Flash");
14793       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14794       break;
14795     case FOURCC_XiTh:
14796       _codec ("Theora");
14797       caps = gst_caps_new_empty_simple ("video/x-theora");
14798       /* theora uses one byte of padding in the data stream because it does not
14799        * allow 0 sized packets while theora does */
14800       entry->padding = 1;
14801       break;
14802     case FOURCC_drac:
14803       _codec ("Dirac");
14804       caps = gst_caps_new_empty_simple ("video/x-dirac");
14805       break;
14806     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14807       _codec ("TIFF still images");
14808       caps = gst_caps_new_empty_simple ("image/tiff");
14809       break;
14810     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14811       _codec ("Apple Intermediate Codec");
14812       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14813       break;
14814     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14815       _codec ("AVID DNxHD");
14816       caps = gst_caps_from_string ("video/x-dnxhd");
14817       break;
14818     case FOURCC_VP80:
14819     case FOURCC_vp08:
14820       _codec ("On2 VP8");
14821       caps = gst_caps_from_string ("video/x-vp8");
14822       break;
14823     case FOURCC_vp09:
14824       _codec ("Google VP9");
14825       caps = gst_caps_from_string ("video/x-vp9");
14826       break;
14827     case FOURCC_apcs:
14828       _codec ("Apple ProRes LT");
14829       caps =
14830           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14831           NULL);
14832       break;
14833     case FOURCC_apch:
14834       _codec ("Apple ProRes HQ");
14835       caps =
14836           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14837           NULL);
14838       break;
14839     case FOURCC_apcn:
14840       _codec ("Apple ProRes");
14841       caps =
14842           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14843           "standard", NULL);
14844       break;
14845     case FOURCC_apco:
14846       _codec ("Apple ProRes Proxy");
14847       caps =
14848           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14849           "proxy", NULL);
14850       break;
14851     case FOURCC_ap4h:
14852       _codec ("Apple ProRes 4444");
14853       caps =
14854           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14855           "4444", NULL);
14856 
14857       /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14858       if (entry->bits_per_sample > 0) {
14859         gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14860             NULL);
14861       }
14862       break;
14863     case FOURCC_ap4x:
14864       _codec ("Apple ProRes 4444 XQ");
14865       caps =
14866           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14867           "4444xq", NULL);
14868 
14869       /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14870       if (entry->bits_per_sample > 0) {
14871         gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14872             NULL);
14873       }
14874       break;
14875     case FOURCC_cfhd:
14876       _codec ("GoPro CineForm");
14877       caps = gst_caps_from_string ("video/x-cineform");
14878       break;
14879     case FOURCC_vc_1:
14880     case FOURCC_ovc1:
14881       _codec ("VC-1");
14882       caps = gst_caps_new_simple ("video/x-wmv",
14883           "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14884       break;
14885     case FOURCC_av01:
14886       _codec ("AV1");
14887       caps = gst_caps_new_empty_simple ("video/x-av1");
14888       break;
14889     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14890     default:
14891     {
14892       caps = _get_unknown_codec_name ("video", fourcc);
14893       break;
14894     }
14895   }
14896 
14897   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14898     GstVideoInfo info;
14899 
14900     gst_video_info_init (&info);
14901     gst_video_info_set_format (&info, format, entry->width, entry->height);
14902 
14903     caps = gst_video_info_to_caps (&info);
14904     *codec_name = gst_pb_utils_get_codec_description (caps);
14905 
14906     /* enable clipping for raw video streams */
14907     stream->need_clip = TRUE;
14908     stream->alignment = 32;
14909   }
14910 
14911   return caps;
14912 }
14913 
14914 static guint
14915 round_up_pow2 (guint n)
14916 {
14917   n = n - 1;
14918   n = n | (n >> 1);
14919   n = n | (n >> 2);
14920   n = n | (n >> 4);
14921   n = n | (n >> 8);
14922   n = n | (n >> 16);
14923   return n + 1;
14924 }
14925 
14926 static GstCaps *
14927 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14928     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14929     int len, gchar ** codec_name)
14930 {
14931   GstCaps *caps;
14932   const GstStructure *s;
14933   const gchar *name;
14934   gint endian = 0;
14935   GstAudioFormat format = 0;
14936   gint depth;
14937 
14938   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14939 
14940   depth = entry->bytes_per_packet * 8;
14941 
14942   switch (fourcc) {
14943     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14944     case FOURCC_raw_:
14945       /* 8-bit audio is unsigned */
14946       if (depth == 8)
14947         format = GST_AUDIO_FORMAT_U8;
14948       /* otherwise it's signed and big-endian just like 'twos' */
14949     case FOURCC_twos:
14950       endian = G_BIG_ENDIAN;
14951       /* fall-through */
14952     case FOURCC_sowt:
14953     {
14954       gchar *str;
14955 
14956       if (!endian)
14957         endian = G_LITTLE_ENDIAN;
14958 
14959       if (!format)
14960         format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14961 
14962       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14963       _codec (str);
14964       g_free (str);
14965 
14966       caps = gst_caps_new_simple ("audio/x-raw",
14967           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14968           "layout", G_TYPE_STRING, "interleaved", NULL);
14969       stream->alignment = GST_ROUND_UP_8 (depth);
14970       stream->alignment = round_up_pow2 (stream->alignment);
14971       break;
14972     }
14973     case FOURCC_fl64:
14974       _codec ("Raw 64-bit floating-point audio");
14975       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14976        * endian later */
14977       caps = gst_caps_new_simple ("audio/x-raw",
14978           "format", G_TYPE_STRING, "F64BE",
14979           "layout", G_TYPE_STRING, "interleaved", NULL);
14980       stream->alignment = 8;
14981       break;
14982     case FOURCC_fl32:
14983       _codec ("Raw 32-bit floating-point audio");
14984       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14985        * endian later */
14986       caps = gst_caps_new_simple ("audio/x-raw",
14987           "format", G_TYPE_STRING, "F32BE",
14988           "layout", G_TYPE_STRING, "interleaved", NULL);
14989       stream->alignment = 4;
14990       break;
14991     case FOURCC_in24:
14992       _codec ("Raw 24-bit PCM audio");
14993       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14994        * endian later */
14995       caps = gst_caps_new_simple ("audio/x-raw",
14996           "format", G_TYPE_STRING, "S24BE",
14997           "layout", G_TYPE_STRING, "interleaved", NULL);
14998       stream->alignment = 4;
14999       break;
15000     case FOURCC_in32:
15001       _codec ("Raw 32-bit PCM audio");
15002       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15003        * endian later */
15004       caps = gst_caps_new_simple ("audio/x-raw",
15005           "format", G_TYPE_STRING, "S32BE",
15006           "layout", G_TYPE_STRING, "interleaved", NULL);
15007       stream->alignment = 4;
15008       break;
15009     case FOURCC_s16l:
15010       _codec ("Raw 16-bit PCM audio");
15011       caps = gst_caps_new_simple ("audio/x-raw",
15012           "format", G_TYPE_STRING, "S16LE",
15013           "layout", G_TYPE_STRING, "interleaved", NULL);
15014       stream->alignment = 2;
15015       break;
15016     case FOURCC_ulaw:
15017       _codec ("Mu-law audio");
15018       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15019       break;
15020     case FOURCC_alaw:
15021       _codec ("A-law audio");
15022       caps = gst_caps_new_empty_simple ("audio/x-alaw");
15023       break;
15024     case 0x0200736d:
15025     case 0x6d730002:
15026       _codec ("Microsoft ADPCM");
15027       /* Microsoft ADPCM-ACM code 2 */
15028       caps = gst_caps_new_simple ("audio/x-adpcm",
15029           "layout", G_TYPE_STRING, "microsoft", NULL);
15030       break;
15031     case 0x1100736d:
15032     case 0x6d730011:
15033       _codec ("DVI/IMA ADPCM");
15034       caps = gst_caps_new_simple ("audio/x-adpcm",
15035           "layout", G_TYPE_STRING, "dvi", NULL);
15036       break;
15037     case 0x1700736d:
15038     case 0x6d730017:
15039       _codec ("DVI/Intel IMA ADPCM");
15040       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15041       caps = gst_caps_new_simple ("audio/x-adpcm",
15042           "layout", G_TYPE_STRING, "quicktime", NULL);
15043       break;
15044     case 0x5500736d:
15045     case 0x6d730055:
15046       /* MPEG layer 3, CBR only (pre QT4.1) */
15047     case FOURCC__mp3:
15048     case FOURCC_mp3_:
15049       _codec ("MPEG-1 layer 3");
15050       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15051       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15052           "mpegversion", G_TYPE_INT, 1, NULL);
15053       break;
15054     case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15055       _codec ("MPEG-1 layer 2");
15056       /* MPEG layer 2 */
15057       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15058           "mpegversion", G_TYPE_INT, 1, NULL);
15059       break;
15060     case 0x20736d:
15061     case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15062       _codec ("EAC-3 audio");
15063       caps = gst_caps_new_simple ("audio/x-eac3",
15064           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15065       entry->sampled = TRUE;
15066       break;
15067     case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15068     case FOURCC_ac_3:
15069       _codec ("AC-3 audio");
15070       caps = gst_caps_new_simple ("audio/x-ac3",
15071           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15072       entry->sampled = TRUE;
15073       break;
15074     case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15075     case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15076       _codec ("DTS audio");
15077       caps = gst_caps_new_simple ("audio/x-dts",
15078           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15079       entry->sampled = TRUE;
15080       break;
15081     case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15082     case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15083       _codec ("DTS-HD audio");
15084       caps = gst_caps_new_simple ("audio/x-dts",
15085           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15086       entry->sampled = TRUE;
15087       break;
15088     case FOURCC_MAC3:
15089       _codec ("MACE-3");
15090       caps = gst_caps_new_simple ("audio/x-mace",
15091           "maceversion", G_TYPE_INT, 3, NULL);
15092       break;
15093     case FOURCC_MAC6:
15094       _codec ("MACE-6");
15095       caps = gst_caps_new_simple ("audio/x-mace",
15096           "maceversion", G_TYPE_INT, 6, NULL);
15097       break;
15098     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15099       /* ogg/vorbis */
15100       caps = gst_caps_new_empty_simple ("application/ogg");
15101       break;
15102     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15103       _codec ("DV audio");
15104       caps = gst_caps_new_empty_simple ("audio/x-dv");
15105       break;
15106     case FOURCC_mp4a:
15107       _codec ("MPEG-4 AAC audio");
15108       caps = gst_caps_new_simple ("audio/mpeg",
15109           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15110           "stream-format", G_TYPE_STRING, "raw", NULL);
15111       break;
15112     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15113       _codec ("QDesign Music");
15114       caps = gst_caps_new_empty_simple ("audio/x-qdm");
15115       break;
15116     case FOURCC_QDM2:
15117       _codec ("QDesign Music v.2");
15118       /* FIXME: QDesign music version 2 (no constant) */
15119       if (FALSE && data) {
15120         caps = gst_caps_new_simple ("audio/x-qdm2",
15121             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15122             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15123             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15124       } else {
15125         caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15126       }
15127       break;
15128     case FOURCC_agsm:
15129       _codec ("GSM audio");
15130       caps = gst_caps_new_empty_simple ("audio/x-gsm");
15131       break;
15132     case FOURCC_samr:
15133       _codec ("AMR audio");
15134       caps = gst_caps_new_empty_simple ("audio/AMR");
15135       break;
15136     case FOURCC_sawb:
15137       _codec ("AMR-WB audio");
15138       caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15139       break;
15140     case FOURCC_ima4:
15141       _codec ("Quicktime IMA ADPCM");
15142       caps = gst_caps_new_simple ("audio/x-adpcm",
15143           "layout", G_TYPE_STRING, "quicktime", NULL);
15144       break;
15145     case FOURCC_alac:
15146       _codec ("Apple lossless audio");
15147       caps = gst_caps_new_empty_simple ("audio/x-alac");
15148       break;
15149     case FOURCC_fLaC:
15150       _codec ("Free Lossless Audio Codec");
15151       caps = gst_caps_new_simple ("audio/x-flac",
15152           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15153       break;
15154     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15155       _codec ("QualComm PureVoice");
15156       caps = gst_caps_from_string ("audio/qcelp");
15157       break;
15158     case FOURCC_wma_:
15159     case FOURCC_owma:
15160       _codec ("WMA");
15161       caps = gst_caps_new_empty_simple ("audio/x-wma");
15162       break;
15163     case FOURCC_opus:
15164       _codec ("Opus");
15165       caps = gst_caps_new_empty_simple ("audio/x-opus");
15166       break;
15167     case FOURCC_lpcm:
15168     {
15169       guint32 flags = 0;
15170       guint32 depth = 0;
15171       guint32 width = 0;
15172       GstAudioFormat format;
15173       enum
15174       {
15175         FLAG_IS_FLOAT = 0x1,
15176         FLAG_IS_BIG_ENDIAN = 0x2,
15177         FLAG_IS_SIGNED = 0x4,
15178         FLAG_IS_PACKED = 0x8,
15179         FLAG_IS_ALIGNED_HIGH = 0x10,
15180         FLAG_IS_NON_INTERLEAVED = 0x20
15181       };
15182       _codec ("Raw LPCM audio");
15183 
15184       if (data && len >= 36) {
15185         depth = QT_UINT32 (data + 24);
15186         flags = QT_UINT32 (data + 28);
15187         width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15188       }
15189       if ((flags & FLAG_IS_FLOAT) == 0) {
15190         if (depth == 0)
15191           depth = 16;
15192         if (width == 0)
15193           width = 16;
15194         if ((flags & FLAG_IS_ALIGNED_HIGH))
15195           depth = width;
15196 
15197         format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15198             TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15199             G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15200         caps = gst_caps_new_simple ("audio/x-raw",
15201             "format", G_TYPE_STRING,
15202             format !=
15203             GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15204             "UNKNOWN", "layout", G_TYPE_STRING,
15205             (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15206             "interleaved", NULL);
15207         stream->alignment = GST_ROUND_UP_8 (depth);
15208         stream->alignment = round_up_pow2 (stream->alignment);
15209       } else {
15210         if (width == 0)
15211           width = 32;
15212         if (width == 64) {
15213           if (flags & FLAG_IS_BIG_ENDIAN)
15214             format = GST_AUDIO_FORMAT_F64BE;
15215           else
15216             format = GST_AUDIO_FORMAT_F64LE;
15217         } else {
15218           if (flags & FLAG_IS_BIG_ENDIAN)
15219             format = GST_AUDIO_FORMAT_F32BE;
15220           else
15221             format = GST_AUDIO_FORMAT_F32LE;
15222         }
15223         caps = gst_caps_new_simple ("audio/x-raw",
15224             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15225             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15226             "non-interleaved" : "interleaved", NULL);
15227         stream->alignment = width / 8;
15228       }
15229       break;
15230     }
15231     case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15232     {
15233       _codec ("AC4");
15234       caps = gst_caps_new_empty_simple ("audio/x-ac4");
15235       break;
15236     }
15237     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15238       /* ? */
15239     default:
15240     {
15241       caps = _get_unknown_codec_name ("audio", fourcc);
15242       break;
15243     }
15244   }
15245 
15246   if (caps) {
15247     GstCaps *templ_caps =
15248         gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15249     GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15250     gst_caps_unref (caps);
15251     gst_caps_unref (templ_caps);
15252     caps = intersection;
15253   }
15254 
15255   /* enable clipping for raw audio streams */
15256   s = gst_caps_get_structure (caps, 0);
15257   name = gst_structure_get_name (s);
15258   if (g_str_has_prefix (name, "audio/x-raw")) {
15259     stream->need_clip = TRUE;
15260     stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15261     stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15262     GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15263         stream->max_buffer_size);
15264   }
15265   return caps;
15266 }
15267 
15268 static GstCaps *
15269 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15270     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15271     const guint8 * stsd_entry_data, gchar ** codec_name)
15272 {
15273   GstCaps *caps;
15274 
15275   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15276 
15277   switch (fourcc) {
15278     case FOURCC_mp4s:
15279       _codec ("DVD subtitle");
15280       caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15281       stream->process_func = gst_qtdemux_process_buffer_dvd;
15282       break;
15283     case FOURCC_text:
15284       _codec ("Quicktime timed text");
15285       goto text;
15286     case FOURCC_tx3g:
15287       _codec ("3GPP timed text");
15288     text:
15289       caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15290           "utf8", NULL);
15291       /* actual text piece needs to be extracted */
15292       stream->process_func = gst_qtdemux_process_buffer_text;
15293       break;
15294     case FOURCC_stpp:
15295       _codec ("XML subtitles");
15296       caps = gst_caps_new_empty_simple ("application/ttml+xml");
15297       break;
15298     case FOURCC_wvtt:
15299     {
15300       GstBuffer *buffer;
15301       const gchar *buf = "WEBVTT\n\n";
15302 
15303       _codec ("WebVTT subtitles");
15304       caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15305       stream->process_func = gst_qtdemux_process_buffer_wvtt;
15306 
15307       /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15308       buffer = gst_buffer_new_and_alloc (8);
15309       gst_buffer_fill (buffer, 0, buf, 8);
15310       stream->buffers = g_slist_append (stream->buffers, buffer);
15311 
15312       break;
15313     }
15314     case FOURCC_c608:
15315       _codec ("CEA 608 Closed Caption");
15316       caps =
15317           gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15318           G_TYPE_STRING, "s334-1a", NULL);
15319       stream->process_func = gst_qtdemux_process_buffer_clcp;
15320       stream->need_split = TRUE;
15321       break;
15322     case FOURCC_c708:
15323       _codec ("CEA 708 Closed Caption");
15324       caps =
15325           gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15326           G_TYPE_STRING, "cdp", NULL);
15327       stream->process_func = gst_qtdemux_process_buffer_clcp;
15328       break;
15329 
15330     default:
15331     {
15332       caps = _get_unknown_codec_name ("text", fourcc);
15333       break;
15334     }
15335   }
15336   return caps;
15337 }
15338 
15339 static GstCaps *
15340 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15341     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15342     const guint8 * stsd_entry_data, gchar ** codec_name)
15343 {
15344   GstCaps *caps;
15345 
15346   switch (fourcc) {
15347     case FOURCC_m1v:
15348       _codec ("MPEG 1 video");
15349       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15350           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15351       break;
15352     default:
15353       caps = NULL;
15354       break;
15355   }
15356   return caps;
15357 }
15358 
15359 static void
15360 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15361     const gchar * system_id)
15362 {
15363   gint i;
15364 
15365   if (!qtdemux->protection_system_ids)
15366     qtdemux->protection_system_ids =
15367         g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15368   /* Check whether we already have an entry for this system ID. */
15369   for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15370     const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15371     if (g_ascii_strcasecmp (system_id, id) == 0) {
15372       return;
15373     }
15374   }
15375   GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15376   g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
15377           -1));
15378 }
15379