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  *
33  * Demuxes a .mov file into raw or compressed audio and/or video streams.
34  *
35  * This element supports both push and pull-based scheduling, depending on the
36  * capabilities of the upstream elements.
37  *
38  * <refsect2>
39  * <title>Example launch line</title>
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  * </refsect2>
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/tag/tag.h>
57 #include <gst/audio/audio.h>
58 #include <gst/video/video.h>
59 #include <gst/riff/riff.h>
60 #include <gst/pbutils/pbutils.h>
61 
62 #include "qtatomparser.h"
63 #include "qtdemux_types.h"
64 #include "qtdemux_dump.h"
65 #include "fourcc.h"
66 #include "descriptors.h"
67 #include "qtdemux_lang.h"
68 #include "qtdemux.h"
69 #include "qtpalette.h"
70 
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 
75 #include <math.h>
76 #include <gst/math-compat.h>
77 
78 #ifdef HAVE_ZLIB
79 # include <zlib.h>
80 #endif
81 
82 /* max. size considered 'sane' for non-mdat atoms */
83 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
84 
85 /* if the sample index is larger than this, something is likely wrong */
86 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
87 
88 /* For converting qt creation times to unix epoch times */
89 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
90 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
91 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
92     QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
93 
94 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
95 
96 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
97 
98 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
99 
100 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
101 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
102 #define QTDEMUX_NTH_STREAM(demux,idx) \
103    QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
104 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
105    QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
106 
107 GST_DEBUG_CATEGORY (qtdemux_debug);
108 #define GST_CAT_DEFAULT qtdemux_debug
109 
110 typedef struct _QtDemuxSegment QtDemuxSegment;
111 typedef struct _QtDemuxSample QtDemuxSample;
112 
113 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
114 
115 struct _QtDemuxSample
116 {
117   guint32 size;
118   gint32 pts_offset;            /* Add this value to timestamp to get the pts */
119   guint64 offset;
120   guint64 timestamp;            /* DTS In mov time */
121   guint32 duration;             /* In mov time */
122   gboolean keyframe;            /* TRUE when this packet is a keyframe */
123 };
124 
125 /* Macros for converting to/from timescale */
126 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
127 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
128 
129 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
130 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
131 
132 /* timestamp is the DTS */
133 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
134 /* timestamp + offset + cslg_shift is the outgoing PTS */
135 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
136 /* timestamp + offset is the PTS used for internal seek calcuations */
137 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
138 /* timestamp + duration - dts is the duration */
139 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
140 
141 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
142 
143 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
144 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
145     GST_TRACE("Locking from thread %p", g_thread_self()); \
146     g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
147     GST_TRACE("Locked from thread %p", g_thread_self()); \
148  } G_STMT_END
149 
150 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
151     GST_TRACE("Unlocking from thread %p", g_thread_self()); \
152     g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
153  } G_STMT_END
154 
155 /*
156  * Quicktime has tracks and segments. A track is a continuous piece of
157  * multimedia content. The track is not always played from start to finish but
158  * instead, pieces of the track are 'cut out' and played in sequence. This is
159  * what the segments do.
160  *
161  * Inside the track we have keyframes (K) and delta frames. The track has its
162  * own timing, which starts from 0 and extends to end. The position in the track
163  * is called the media_time.
164  *
165  * The segments now describe the pieces that should be played from this track
166  * and are basically tuples of media_time/duration/rate entries. We can have
167  * multiple segments and they are all played after one another. An example:
168  *
169  * segment 1: media_time: 1 second, duration: 1 second, rate 1
170  * segment 2: media_time: 3 second, duration: 2 second, rate 2
171  *
172  * To correctly play back this track, one must play: 1 second of media starting
173  * from media_time 1 followed by 2 seconds of media starting from media_time 3
174  * at a rate of 2.
175  *
176  * Each of the segments will be played at a specific time, the first segment at
177  * time 0, the second one after the duration of the first one, etc.. Note that
178  * the time in resulting playback is not identical to the media_time of the
179  * track anymore.
180  *
181  * Visually, assuming the track has 4 second of media_time:
182  *
183  *                (a)                   (b)          (c)              (d)
184  *         .-----------------------------------------------------------.
185  * track:  | K.....K.........K........K.......K.......K...........K... |
186  *         '-----------------------------------------------------------'
187  *         0              1              2              3              4
188  *           .------------^              ^   .----------^              ^
189  *          /              .-------------'  /       .------------------'
190  *         /              /          .-----'       /
191  *         .--------------.         .--------------.
192  *         | segment 1    |         | segment 2    |
193  *         '--------------'         '--------------'
194  *
195  * The challenge here is to cut out the right pieces of the track for each of
196  * the playback segments. This fortunately can easily be done with the SEGMENT
197  * events of GStreamer.
198  *
199  * For playback of segment 1, we need to provide the decoder with the keyframe
200  * (a), in the above figure, but we must instruct it only to output the decoded
201  * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
202  * position set to the time of the segment: 0.
203  *
204  * We then proceed to push data from keyframe (a) to frame (b). The decoder
205  * decodes but clips all before media_time 1.
206  *
207  * After finishing a segment, we push out a new SEGMENT event with the clipping
208  * boundaries of the new data.
209  *
210  * This is a good usecase for the GStreamer accumulated SEGMENT events.
211  */
212 
213 struct _QtDemuxSegment
214 {
215   /* global time and duration, all gst time */
216   GstClockTime time;
217   GstClockTime stop_time;
218   GstClockTime duration;
219   /* media time of trak, all gst time */
220   GstClockTime media_start;
221   GstClockTime media_stop;
222   gdouble rate;
223   /* Media start time in trak timescale units */
224   guint32 trak_media_start;
225 };
226 
227 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
228 
229 /* Used with fragmented MP4 files (mfra atom) */
230 typedef struct
231 {
232   GstClockTime ts;
233   guint64 moof_offset;
234 } QtDemuxRandomAccessEntry;
235 
236 typedef struct _QtDemuxStreamStsdEntry
237 {
238   GstCaps *caps;
239   guint32 fourcc;
240   gboolean sparse;
241 
242   /* video info */
243   gint width;
244   gint height;
245   gint par_w;
246   gint par_h;
247   /* Numerator/denominator framerate */
248   gint fps_n;
249   gint fps_d;
250   GstVideoColorimetry colorimetry;
251   guint16 bits_per_sample;
252   guint16 color_table_id;
253   GstMemory *rgb8_palette;
254   guint interlace_mode;
255   guint field_order;
256 
257   /* audio info */
258   gdouble rate;
259   gint n_channels;
260   guint samples_per_packet;
261   guint samples_per_frame;
262   guint bytes_per_packet;
263   guint bytes_per_sample;
264   guint bytes_per_frame;
265   guint compression;
266 
267   /* if we use chunks or samples */
268   gboolean sampled;
269   guint padding;
270 
271 } QtDemuxStreamStsdEntry;
272 
273 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
274 
275 struct _QtDemuxStream
276 {
277   GstPad *pad;
278 
279   GstQTDemux *demux;
280   gchar *stream_id;
281 
282   QtDemuxStreamStsdEntry *stsd_entries;
283   guint stsd_entries_length;
284   guint cur_stsd_entry_index;
285 
286   /* stream type */
287   guint32 subtype;
288 
289   gboolean new_caps;            /* If TRUE, caps need to be generated (by
290                                  * calling _configure_stream()) This happens
291                                  * for MSS and fragmented streams */
292 
293   gboolean new_stream;          /* signals that a stream_start is required */
294   gboolean on_keyframe;         /* if this stream last pushed buffer was a
295                                  * keyframe. This is important to identify
296                                  * where to stop pushing buffers after a
297                                  * segment stop time */
298 
299   /* if the stream has a redirect URI in its headers, we store it here */
300   gchar *redirect_uri;
301 
302   /* track id */
303   guint track_id;
304 
305   /* duration/scale */
306   guint64 duration;             /* in timescale units */
307   guint32 timescale;
308 
309   /* language */
310   gchar lang_id[4];             /* ISO 639-2T language code */
311 
312   /* our samples */
313   guint32 n_samples;
314   QtDemuxSample *samples;
315   gboolean all_keyframe;        /* TRUE when all samples are keyframes (no stss) */
316   guint32 n_samples_moof;       /* sample count in a moof */
317   guint64 duration_moof;        /* duration in timescale of a moof, used for figure out
318                                  * the framerate of fragmented format stream */
319   guint64 duration_last_moof;
320 
321   guint32 offset_in_sample;     /* Offset in the current sample, used for
322                                  * streams which have got exceedingly big
323                                  * sample size (such as 24s of raw audio).
324                                  * Only used when max_buffer_size is non-NULL */
325   guint32 max_buffer_size;      /* Maximum allowed size for output buffers.
326                                  * Currently only set for raw audio streams*/
327 
328   /* video info */
329   /* aspect ratio */
330   gint display_width;
331   gint display_height;
332 
333   /* allocation */
334   gboolean use_allocator;
335   GstAllocator *allocator;
336   GstAllocationParams params;
337 
338   gsize alignment;
339 
340   /* when a discontinuity is pending */
341   gboolean discont;
342 
343   /* list of buffers to push first */
344   GSList *buffers;
345 
346   /* if we need to clip this buffer. This is only needed for uncompressed
347    * data */
348   gboolean need_clip;
349 
350   /* buffer needs some custom processing, e.g. subtitles */
351   gboolean need_process;
352   /* buffer needs potentially be split, e.g. CEA608 subtitles */
353   gboolean need_split;
354 
355   /* current position */
356   guint32 segment_index;
357   guint32 sample_index;
358   GstClockTime time_position;   /* in gst time */
359   guint64 accumulated_base;
360 
361   /* the Gst segment we are processing out, used for clipping */
362   GstSegment segment;
363 
364   /* quicktime segments */
365   guint32 n_segments;
366   QtDemuxSegment *segments;
367   gboolean dummy_segment;
368   guint32 from_sample;
369   guint32 to_sample;
370 
371   gboolean sent_eos;
372   GstTagList *stream_tags;
373   gboolean send_global_tags;
374 
375   GstEvent *pending_event;
376 
377   GstByteReader stco;
378   GstByteReader stsz;
379   GstByteReader stsc;
380   GstByteReader stts;
381   GstByteReader stss;
382   GstByteReader stps;
383   GstByteReader ctts;
384 
385   gboolean chunks_are_samples;  /* TRUE means treat chunks as samples */
386   gint64 stbl_index;
387   /* stco */
388   guint co_size;
389   GstByteReader co_chunk;
390   guint32 first_chunk;
391   guint32 current_chunk;
392   guint32 last_chunk;
393   guint32 samples_per_chunk;
394   guint32 stsd_sample_description_id;
395   guint32 stco_sample_index;
396   /* stsz */
397   guint32 sample_size;          /* 0 means variable sizes are stored in stsz */
398   /* stsc */
399   guint32 stsc_index;
400   guint32 n_samples_per_chunk;
401   guint32 stsc_chunk_index;
402   guint32 stsc_sample_index;
403   guint64 chunk_offset;
404   /* stts */
405   guint32 stts_index;
406   guint32 stts_samples;
407   guint32 n_sample_times;
408   guint32 stts_sample_index;
409   guint64 stts_time;
410   guint32 stts_duration;
411   /* stss */
412   gboolean stss_present;
413   guint32 n_sample_syncs;
414   guint32 stss_index;
415   /* stps */
416   gboolean stps_present;
417   guint32 n_sample_partial_syncs;
418   guint32 stps_index;
419   QtDemuxRandomAccessEntry *ra_entries;
420   guint n_ra_entries;
421 
422   const QtDemuxRandomAccessEntry *pending_seek;
423 
424   /* ctts */
425   gboolean ctts_present;
426   guint32 n_composition_times;
427   guint32 ctts_index;
428   guint32 ctts_sample_index;
429   guint32 ctts_count;
430   gint32 ctts_soffset;
431 
432   /* cslg */
433   guint32 cslg_shift;
434 
435   /* fragmented */
436   gboolean parsed_trex;
437   guint32 def_sample_description_index; /* index is 1-based */
438   guint32 def_sample_duration;
439   guint32 def_sample_size;
440   guint32 def_sample_flags;
441 
442   gboolean disabled;
443 
444   /* stereoscopic video streams */
445   GstVideoMultiviewMode multiview_mode;
446   GstVideoMultiviewFlags multiview_flags;
447 
448   /* protected streams */
449   gboolean protected;
450   guint32 protection_scheme_type;
451   guint32 protection_scheme_version;
452   gpointer protection_scheme_info;      /* specific to the protection scheme */
453   GQueue protection_scheme_event_queue;
454 
455   gint ref_count;               /* atomic */
456 };
457 
458 /* Contains properties and cryptographic info for a set of samples from a
459  * track protected using Common Encryption (cenc) */
460 struct _QtDemuxCencSampleSetInfo
461 {
462   GstStructure *default_properties;
463 
464   /* @crypto_info holds one GstStructure per sample */
465   GPtrArray *crypto_info;
466 };
467 
468 static const gchar *
qt_demux_state_string(enum QtDemuxState state)469 qt_demux_state_string (enum QtDemuxState state)
470 {
471   switch (state) {
472     case QTDEMUX_STATE_INITIAL:
473       return "<INITIAL>";
474     case QTDEMUX_STATE_HEADER:
475       return "<HEADER>";
476     case QTDEMUX_STATE_MOVIE:
477       return "<MOVIE>";
478     case QTDEMUX_STATE_BUFFER_MDAT:
479       return "<BUFFER_MDAT>";
480     default:
481       return "<UNKNOWN>";
482   }
483 }
484 
485 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
486 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
487     guint32 fourcc, GstByteReader * parser);
488 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
489 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
490     guint32 fourcc, GstByteReader * parser);
491 
492 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
493 
494 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
495 
496 static GstStaticPadTemplate gst_qtdemux_sink_template =
497     GST_STATIC_PAD_TEMPLATE ("sink",
498     GST_PAD_SINK,
499     GST_PAD_ALWAYS,
500     GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
501         "application/x-3gp")
502     );
503 
504 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
505 GST_STATIC_PAD_TEMPLATE ("video_%u",
506     GST_PAD_SRC,
507     GST_PAD_SOMETIMES,
508     GST_STATIC_CAPS_ANY);
509 
510 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
511 GST_STATIC_PAD_TEMPLATE ("audio_%u",
512     GST_PAD_SRC,
513     GST_PAD_SOMETIMES,
514     GST_STATIC_CAPS_ANY);
515 
516 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
517 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
518     GST_PAD_SRC,
519     GST_PAD_SOMETIMES,
520     GST_STATIC_CAPS_ANY);
521 
522 #define gst_qtdemux_parent_class parent_class
523 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
524 
525 static void gst_qtdemux_dispose (GObject * object);
526 
527 static guint32
528 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
529     GstClockTime media_time);
530 static guint32
531 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
532     QtDemuxStream * str, gint64 media_offset);
533 
534 #if 0
535 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
536 static GstIndex *gst_qtdemux_get_index (GstElement * element);
537 #endif
538 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
539     GstStateChange transition);
540 static void gst_qtdemux_set_context (GstElement * element,
541     GstContext * context);
542 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
543 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
544     GstObject * parent, GstPadMode mode, gboolean active);
545 
546 static void gst_qtdemux_loop (GstPad * pad);
547 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
548     GstBuffer * inbuf);
549 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
550     GstEvent * event);
551 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
552     GstQuery * query);
553 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
554 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
555     QtDemuxStream * stream);
556 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
557     QtDemuxStream * stream);
558 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
559     gboolean force);
560 
561 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
562 
563 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
564     const guint8 * buffer, guint length);
565 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
566     const guint8 * buffer, guint length);
567 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
568 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
569     GNode * udta);
570 
571 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
572     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
573     GstTagList * list);
574 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
575     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
576     const guint8 * stsd_entry_data, gchar ** codec_name);
577 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
578     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
579     const guint8 * data, int len, gchar ** codec_name);
580 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
581     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
582     gchar ** codec_name);
583 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
584     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
585     const guint8 * stsd_entry_data, gchar ** codec_name);
586 
587 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
588     QtDemuxStream * stream, guint32 n);
589 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
590 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
591 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
592 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
593 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
594 static void qtdemux_do_allocation (QtDemuxStream * stream,
595     GstQTDemux * qtdemux);
596 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
597     QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
598 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
599     QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
600     GstClockTime * _start, GstClockTime * _stop);
601 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
602     QtDemuxStream * stream, gint segment_index, GstClockTime pos);
603 
604 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
605 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
606 
607 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
608 
609 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
610     QtDemuxStream * stream, guint sample_index);
611 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
612     const gchar * id);
613 static void qtdemux_gst_structure_free (GstStructure * gststructure);
614 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
615 
616 static void
gst_qtdemux_class_init(GstQTDemuxClass * klass)617 gst_qtdemux_class_init (GstQTDemuxClass * klass)
618 {
619   GObjectClass *gobject_class;
620   GstElementClass *gstelement_class;
621 
622   gobject_class = (GObjectClass *) klass;
623   gstelement_class = (GstElementClass *) klass;
624 
625   parent_class = g_type_class_peek_parent (klass);
626 
627   gobject_class->dispose = gst_qtdemux_dispose;
628 
629   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
630 #if 0
631   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
632   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
633 #endif
634   gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
635 
636   gst_tag_register_musicbrainz_tags ();
637 
638   gst_element_class_add_static_pad_template (gstelement_class,
639       &gst_qtdemux_sink_template);
640   gst_element_class_add_static_pad_template (gstelement_class,
641       &gst_qtdemux_videosrc_template);
642   gst_element_class_add_static_pad_template (gstelement_class,
643       &gst_qtdemux_audiosrc_template);
644   gst_element_class_add_static_pad_template (gstelement_class,
645       &gst_qtdemux_subsrc_template);
646   gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
647       "Codec/Demuxer",
648       "Demultiplex a QuickTime file into audio and video streams",
649       "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
650 
651   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
652   gst_riff_init ();
653 }
654 
655 static void
gst_qtdemux_init(GstQTDemux * qtdemux)656 gst_qtdemux_init (GstQTDemux * qtdemux)
657 {
658   qtdemux->sinkpad =
659       gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
660   gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
661   gst_pad_set_activatemode_function (qtdemux->sinkpad,
662       qtdemux_sink_activate_mode);
663   gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
664   gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
665   gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
666   gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
667 
668   qtdemux->adapter = gst_adapter_new ();
669   g_queue_init (&qtdemux->protection_event_queue);
670   qtdemux->flowcombiner = gst_flow_combiner_new ();
671   g_mutex_init (&qtdemux->expose_lock);
672 
673   qtdemux->active_streams = g_ptr_array_new_with_free_func
674       ((GDestroyNotify) gst_qtdemux_stream_unref);
675   qtdemux->old_streams = g_ptr_array_new_with_free_func
676       ((GDestroyNotify) gst_qtdemux_stream_unref);
677 
678   GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
679 
680   gst_qtdemux_reset (qtdemux, TRUE);
681 }
682 
683 static void
gst_qtdemux_dispose(GObject * object)684 gst_qtdemux_dispose (GObject * object)
685 {
686   GstQTDemux *qtdemux = GST_QTDEMUX (object);
687 
688   if (qtdemux->adapter) {
689     g_object_unref (G_OBJECT (qtdemux->adapter));
690     qtdemux->adapter = NULL;
691   }
692   gst_tag_list_unref (qtdemux->tag_list);
693   gst_flow_combiner_free (qtdemux->flowcombiner);
694   g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
695       NULL);
696   g_queue_clear (&qtdemux->protection_event_queue);
697 
698   g_free (qtdemux->cenc_aux_info_sizes);
699   qtdemux->cenc_aux_info_sizes = NULL;
700   g_mutex_clear (&qtdemux->expose_lock);
701 
702   g_ptr_array_free (qtdemux->active_streams, TRUE);
703   g_ptr_array_free (qtdemux->old_streams, TRUE);
704 
705   G_OBJECT_CLASS (parent_class)->dispose (object);
706 }
707 
708 static void
gst_qtdemux_post_no_playable_stream_error(GstQTDemux * qtdemux)709 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
710 {
711   if (qtdemux->posted_redirect) {
712     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
713         (_("This file contains no playable streams.")),
714         ("no known streams found, a redirect message has been posted"));
715   } else {
716     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
717         (_("This file contains no playable streams.")),
718         ("no known streams found"));
719   }
720 }
721 
722 static GstBuffer *
_gst_buffer_new_wrapped(gpointer mem,gsize size,GFreeFunc free_func)723 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
724 {
725   return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
726       mem, size, 0, size, mem, free_func);
727 }
728 
729 static GstFlowReturn
gst_qtdemux_pull_atom(GstQTDemux * qtdemux,guint64 offset,guint64 size,GstBuffer ** buf)730 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
731     GstBuffer ** buf)
732 {
733   GstFlowReturn flow;
734   GstMapInfo map;
735   gsize bsize;
736 
737   if (G_UNLIKELY (size == 0)) {
738     GstFlowReturn ret;
739     GstBuffer *tmp = NULL;
740 
741     ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
742     if (ret != GST_FLOW_OK)
743       return ret;
744 
745     gst_buffer_map (tmp, &map, GST_MAP_READ);
746     size = QT_UINT32 (map.data);
747     GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
748 
749     gst_buffer_unmap (tmp, &map);
750     gst_buffer_unref (tmp);
751   }
752 
753   /* Sanity check: catch bogus sizes (fuzzed/broken files) */
754   if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
755     if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
756       /* we're pulling header but already got most interesting bits,
757        * so never mind the rest (e.g. tags) (that much) */
758       GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
759           size);
760       return GST_FLOW_EOS;
761     } else {
762       GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
763           (_("This file is invalid and cannot be played.")),
764           ("atom has bogus size %" G_GUINT64_FORMAT, size));
765       return GST_FLOW_ERROR;
766     }
767   }
768 
769   flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
770 
771   if (G_UNLIKELY (flow != GST_FLOW_OK))
772     return flow;
773 
774   bsize = gst_buffer_get_size (*buf);
775   /* Catch short reads - we don't want any partial atoms */
776   if (G_UNLIKELY (bsize < size)) {
777     GST_WARNING_OBJECT (qtdemux,
778         "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
779     gst_buffer_unref (*buf);
780     *buf = NULL;
781     return GST_FLOW_EOS;
782   }
783 
784   return flow;
785 }
786 
787 #if 1
788 static gboolean
gst_qtdemux_src_convert(GstQTDemux * qtdemux,GstPad * pad,GstFormat src_format,gint64 src_value,GstFormat dest_format,gint64 * dest_value)789 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
790     GstFormat src_format, gint64 src_value, GstFormat dest_format,
791     gint64 * dest_value)
792 {
793   gboolean res = TRUE;
794   QtDemuxStream *stream = gst_pad_get_element_private (pad);
795   gint32 index;
796 
797   if (stream->subtype != FOURCC_vide) {
798     res = FALSE;
799     goto done;
800   }
801 
802   switch (src_format) {
803     case GST_FORMAT_TIME:
804       switch (dest_format) {
805         case GST_FORMAT_BYTES:{
806           index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
807           if (-1 == index) {
808             res = FALSE;
809             goto done;
810           }
811 
812           *dest_value = stream->samples[index].offset;
813 
814           GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
815               GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
816               GST_TIME_ARGS (src_value), *dest_value);
817           break;
818         }
819         default:
820           res = FALSE;
821           break;
822       }
823       break;
824     case GST_FORMAT_BYTES:
825       switch (dest_format) {
826         case GST_FORMAT_TIME:{
827           index =
828               gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
829               stream, src_value);
830 
831           if (-1 == index) {
832             res = FALSE;
833             goto done;
834           }
835 
836           *dest_value =
837               QTSTREAMTIME_TO_GSTTIME (stream,
838               stream->samples[index].timestamp);
839           GST_DEBUG_OBJECT (qtdemux,
840               "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
841               GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
842           break;
843         }
844         default:
845           res = FALSE;
846           break;
847       }
848       break;
849     default:
850       res = FALSE;
851       break;
852   }
853 
854 done:
855   return res;
856 }
857 #endif
858 
859 static gboolean
gst_qtdemux_get_duration(GstQTDemux * qtdemux,GstClockTime * duration)860 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
861 {
862   gboolean res = FALSE;
863 
864   *duration = GST_CLOCK_TIME_NONE;
865 
866   if (qtdemux->duration != 0 &&
867       qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
868     *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
869     res = TRUE;
870   } else {
871     *duration = GST_CLOCK_TIME_NONE;
872   }
873 
874   return res;
875 }
876 
877 static gboolean
gst_qtdemux_handle_src_query(GstPad * pad,GstObject * parent,GstQuery * query)878 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
879     GstQuery * query)
880 {
881   gboolean res = FALSE;
882   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
883 
884   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
885 
886   switch (GST_QUERY_TYPE (query)) {
887     case GST_QUERY_POSITION:{
888       GstFormat fmt;
889 
890       gst_query_parse_position (query, &fmt, NULL);
891       if (fmt == GST_FORMAT_TIME
892           && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
893         gst_query_set_position (query, GST_FORMAT_TIME,
894             qtdemux->segment.position);
895         res = TRUE;
896       }
897     }
898       break;
899     case GST_QUERY_DURATION:{
900       GstFormat fmt;
901 
902       gst_query_parse_duration (query, &fmt, NULL);
903       if (fmt == GST_FORMAT_TIME) {
904         /* First try to query upstream */
905         res = gst_pad_query_default (pad, parent, query);
906         if (!res) {
907           GstClockTime duration;
908           if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
909             gst_query_set_duration (query, GST_FORMAT_TIME, duration);
910             res = TRUE;
911           }
912         }
913       }
914       break;
915     }
916     case GST_QUERY_CONVERT:{
917       GstFormat src_fmt, dest_fmt;
918       gint64 src_value, dest_value = 0;
919 
920       gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
921 
922       res = gst_qtdemux_src_convert (qtdemux, pad,
923           src_fmt, src_value, dest_fmt, &dest_value);
924       if (res)
925         gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
926 
927       break;
928     }
929     case GST_QUERY_FORMATS:
930       gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
931       res = TRUE;
932       break;
933     case GST_QUERY_SEEKING:{
934       GstFormat fmt;
935       gboolean seekable;
936 
937       /* try upstream first */
938       res = gst_pad_query_default (pad, parent, query);
939 
940       if (!res) {
941         gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
942         if (fmt == GST_FORMAT_TIME) {
943           GstClockTime duration;
944 
945           gst_qtdemux_get_duration (qtdemux, &duration);
946           seekable = TRUE;
947           if (!qtdemux->pullbased) {
948             GstQuery *q;
949 
950             /* we might be able with help from upstream */
951             seekable = FALSE;
952             q = gst_query_new_seeking (GST_FORMAT_BYTES);
953             if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
954               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
955               GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
956             }
957             gst_query_unref (q);
958           }
959           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
960           res = TRUE;
961         }
962       }
963       break;
964     }
965     case GST_QUERY_SEGMENT:
966     {
967       GstFormat format;
968       gint64 start, stop;
969 
970       format = qtdemux->segment.format;
971 
972       start =
973           gst_segment_to_stream_time (&qtdemux->segment, format,
974           qtdemux->segment.start);
975       if ((stop = qtdemux->segment.stop) == -1)
976         stop = qtdemux->segment.duration;
977       else
978         stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
979 
980       gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
981       res = TRUE;
982       break;
983     }
984     default:
985       res = gst_pad_query_default (pad, parent, query);
986       break;
987   }
988 
989   return res;
990 }
991 
992 static void
gst_qtdemux_push_tags(GstQTDemux * qtdemux,QtDemuxStream * stream)993 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
994 {
995   if (G_LIKELY (stream->pad)) {
996     GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
997         GST_DEBUG_PAD_NAME (stream->pad));
998 
999     if (!gst_tag_list_is_empty (stream->stream_tags)) {
1000       GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
1001           stream->stream_tags);
1002       gst_pad_push_event (stream->pad,
1003           gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
1004     }
1005 
1006     if (G_UNLIKELY (stream->send_global_tags)) {
1007       GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
1008           qtdemux->tag_list);
1009       gst_pad_push_event (stream->pad,
1010           gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
1011       stream->send_global_tags = FALSE;
1012     }
1013   }
1014 }
1015 
1016 /* push event on all source pads; takes ownership of the event */
1017 static void
gst_qtdemux_push_event(GstQTDemux * qtdemux,GstEvent * event)1018 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1019 {
1020   gboolean has_valid_stream = FALSE;
1021   GstEventType etype = GST_EVENT_TYPE (event);
1022   guint i;
1023 
1024   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1025       GST_EVENT_TYPE_NAME (event));
1026 
1027   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1028     GstPad *pad;
1029     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1030     GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
1031 
1032     if ((pad = stream->pad)) {
1033       has_valid_stream = TRUE;
1034 
1035       if (etype == GST_EVENT_EOS) {
1036         /* let's not send twice */
1037         if (stream->sent_eos)
1038           continue;
1039         stream->sent_eos = TRUE;
1040       }
1041 
1042       gst_pad_push_event (pad, gst_event_ref (event));
1043     }
1044   }
1045 
1046   gst_event_unref (event);
1047 
1048   /* if it is EOS and there are no pads, post an error */
1049   if (!has_valid_stream && etype == GST_EVENT_EOS) {
1050     gst_qtdemux_post_no_playable_stream_error (qtdemux);
1051   }
1052 }
1053 
1054 typedef struct
1055 {
1056   guint64 media_time;
1057 } FindData;
1058 
1059 static gint
find_func(QtDemuxSample * s1,gint64 * media_time,gpointer user_data)1060 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1061 {
1062   if ((gint64) s1->timestamp > *media_time)
1063     return 1;
1064   if ((gint64) s1->timestamp == *media_time)
1065     return 0;
1066 
1067   return -1;
1068 }
1069 
1070 /* find the index of the sample that includes the data for @media_time using a
1071  * binary search.  Only to be called in optimized cases of linear search below.
1072  *
1073  * Returns the index of the sample with the corresponding *DTS*.
1074  */
1075 static guint32
gst_qtdemux_find_index(GstQTDemux * qtdemux,QtDemuxStream * str,guint64 media_time)1076 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1077     guint64 media_time)
1078 {
1079   QtDemuxSample *result;
1080   guint32 index;
1081 
1082   /* convert media_time to mov format */
1083   media_time =
1084       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1085 
1086   result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1087       sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1088       GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1089 
1090   if (G_LIKELY (result))
1091     index = result - str->samples;
1092   else
1093     index = 0;
1094 
1095   return index;
1096 }
1097 
1098 
1099 
1100 /* find the index of the sample that includes the data for @media_offset using a
1101  * linear search
1102  *
1103  * Returns the index of the sample.
1104  */
1105 static guint32
gst_qtdemux_find_index_for_given_media_offset_linear(GstQTDemux * qtdemux,QtDemuxStream * str,gint64 media_offset)1106 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1107     QtDemuxStream * str, gint64 media_offset)
1108 {
1109   QtDemuxSample *result = str->samples;
1110   guint32 index = 0;
1111 
1112   if (result == NULL || str->n_samples == 0)
1113     return -1;
1114 
1115   if (media_offset == result->offset)
1116     return index;
1117 
1118   result++;
1119   while (index < str->n_samples - 1) {
1120     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1121       goto parse_failed;
1122 
1123     if (media_offset < result->offset)
1124       break;
1125 
1126     index++;
1127     result++;
1128   }
1129   return index;
1130 
1131   /* ERRORS */
1132 parse_failed:
1133   {
1134     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1135     return -1;
1136   }
1137 }
1138 
1139 /* find the index of the sample that includes the data for @media_time using a
1140  * linear search, and keeping in mind that not all samples may have been parsed
1141  * yet.  If possible, it will delegate to binary search.
1142  *
1143  * Returns the index of the sample.
1144  */
1145 static guint32
gst_qtdemux_find_index_linear(GstQTDemux * qtdemux,QtDemuxStream * str,GstClockTime media_time)1146 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1147     GstClockTime media_time)
1148 {
1149   guint32 index = 0;
1150   guint64 mov_time;
1151   QtDemuxSample *sample;
1152 
1153   /* convert media_time to mov format */
1154   mov_time =
1155       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1156 
1157   sample = str->samples;
1158   if (mov_time == sample->timestamp + sample->pts_offset)
1159     return index;
1160 
1161   /* use faster search if requested time in already parsed range */
1162   sample = str->samples + str->stbl_index;
1163   if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
1164     index = gst_qtdemux_find_index (qtdemux, str, media_time);
1165     sample = str->samples + index;
1166   } else {
1167     while (index < str->n_samples - 1) {
1168       if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1169         goto parse_failed;
1170 
1171       sample = str->samples + index + 1;
1172       if (mov_time < sample->timestamp) {
1173         sample = str->samples + index;
1174         break;
1175       }
1176 
1177       index++;
1178     }
1179   }
1180 
1181   /* sample->timestamp is now <= media_time, need to find the corresponding
1182    * PTS now by looking backwards */
1183   while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
1184     index--;
1185     sample = str->samples + index;
1186   }
1187 
1188   return index;
1189 
1190   /* ERRORS */
1191 parse_failed:
1192   {
1193     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1194     return -1;
1195   }
1196 }
1197 
1198 /* find the index of the keyframe needed to decode the sample at @index
1199  * of stream @str, or of a subsequent keyframe (depending on @next)
1200  *
1201  * Returns the index of the keyframe.
1202  */
1203 static guint32
gst_qtdemux_find_keyframe(GstQTDemux * qtdemux,QtDemuxStream * str,guint32 index,gboolean next)1204 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1205     guint32 index, gboolean next)
1206 {
1207   guint32 new_index = index;
1208 
1209   if (index >= str->n_samples) {
1210     new_index = str->n_samples;
1211     goto beach;
1212   }
1213 
1214   /* all keyframes, return index */
1215   if (str->all_keyframe) {
1216     new_index = index;
1217     goto beach;
1218   }
1219 
1220   /* else search until we have a keyframe */
1221   while (new_index < str->n_samples) {
1222     if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1223       goto parse_failed;
1224 
1225     if (str->samples[new_index].keyframe)
1226       break;
1227 
1228     if (new_index == 0)
1229       break;
1230 
1231     if (next)
1232       new_index++;
1233     else
1234       new_index--;
1235   }
1236 
1237   if (new_index == str->n_samples) {
1238     GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1239     new_index = -1;
1240   }
1241 
1242 beach:
1243   GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1244       "gave %u", next ? "after" : "before", index, new_index);
1245 
1246   return new_index;
1247 
1248   /* ERRORS */
1249 parse_failed:
1250   {
1251     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1252     return -1;
1253   }
1254 }
1255 
1256 /* find the segment for @time_position for @stream
1257  *
1258  * Returns the index of the segment containing @time_position.
1259  * Returns the last segment and sets the @eos variable to TRUE
1260  * if the time is beyond the end. @eos may be NULL
1261  */
1262 static guint32
gst_qtdemux_find_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime time_position)1263 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1264     GstClockTime time_position)
1265 {
1266   gint i;
1267   guint32 seg_idx;
1268 
1269   GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1270       GST_TIME_ARGS (time_position));
1271 
1272   seg_idx = -1;
1273   for (i = 0; i < stream->n_segments; i++) {
1274     QtDemuxSegment *segment = &stream->segments[i];
1275 
1276     GST_LOG_OBJECT (stream->pad,
1277         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1278         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1279 
1280     /* For the last segment we include stop_time in the last segment */
1281     if (i < stream->n_segments - 1) {
1282       if (segment->time <= time_position && time_position < segment->stop_time) {
1283         GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1284         seg_idx = i;
1285         break;
1286       }
1287     } else {
1288       /* Last segment always matches */
1289       seg_idx = i;
1290       break;
1291     }
1292   }
1293   return seg_idx;
1294 }
1295 
1296 /* move the stream @str to the sample position @index.
1297  *
1298  * Updates @str->sample_index and marks discontinuity if needed.
1299  */
1300 static void
gst_qtdemux_move_stream(GstQTDemux * qtdemux,QtDemuxStream * str,guint32 index)1301 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1302     guint32 index)
1303 {
1304   /* no change needed */
1305   if (index == str->sample_index)
1306     return;
1307 
1308   GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1309       str->n_samples);
1310 
1311   /* position changed, we have a discont */
1312   str->sample_index = index;
1313   str->offset_in_sample = 0;
1314   /* Each time we move in the stream we store the position where we are
1315    * starting from */
1316   str->from_sample = index;
1317   str->discont = TRUE;
1318 }
1319 
1320 static void
gst_qtdemux_adjust_seek(GstQTDemux * qtdemux,gint64 desired_time,gboolean use_sparse,gboolean next,gint64 * key_time,gint64 * key_offset)1321 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1322     gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1323 {
1324   guint64 min_offset;
1325   gint64 min_byte_offset = -1;
1326   guint i;
1327 
1328   min_offset = desired_time;
1329 
1330   /* for each stream, find the index of the sample in the segment
1331    * and move back to the previous keyframe. */
1332   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1333     QtDemuxStream *str;
1334     guint32 index, kindex;
1335     guint32 seg_idx;
1336     GstClockTime media_start;
1337     GstClockTime media_time;
1338     GstClockTime seg_time;
1339     QtDemuxSegment *seg;
1340     gboolean empty_segment = FALSE;
1341 
1342     str = QTDEMUX_NTH_STREAM (qtdemux, i);
1343 
1344     if (CUR_STREAM (str)->sparse && !use_sparse)
1345       continue;
1346 
1347     seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1348     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1349 
1350     /* get segment and time in the segment */
1351     seg = &str->segments[seg_idx];
1352     seg_time = (desired_time - seg->time) * seg->rate;
1353 
1354     while (QTSEGMENT_IS_EMPTY (seg)) {
1355       seg_time = 0;
1356       empty_segment = TRUE;
1357       GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1358           seg_idx);
1359       seg_idx++;
1360       if (seg_idx == str->n_segments)
1361         break;
1362       seg = &str->segments[seg_idx];
1363     }
1364 
1365     if (seg_idx == str->n_segments) {
1366       /* FIXME track shouldn't have the last segment as empty, but if it
1367        * happens we better handle it */
1368       continue;
1369     }
1370 
1371     /* get the media time in the segment */
1372     media_start = seg->media_start + seg_time;
1373 
1374     /* get the index of the sample with media time */
1375     index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1376     GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1377         " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1378         GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1379         empty_segment);
1380 
1381     /* shift to next frame if we are looking for next keyframe */
1382     if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1383         && index < str->stbl_index)
1384       index++;
1385 
1386     if (!empty_segment) {
1387       /* find previous keyframe */
1388       kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1389 
1390       /* we will settle for one before if none found after */
1391       if (next && kindex == -1)
1392         kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1393 
1394       /* if the keyframe is at a different position, we need to update the
1395        * requested seek time */
1396       if (index != kindex) {
1397         index = kindex;
1398 
1399         /* get timestamp of keyframe */
1400         media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1401         GST_DEBUG_OBJECT (qtdemux,
1402             "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1403             G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1404             str->samples[kindex].offset);
1405 
1406         /* keyframes in the segment get a chance to change the
1407          * desired_offset. keyframes out of the segment are
1408          * ignored. */
1409         if (media_time >= seg->media_start) {
1410           GstClockTime seg_time;
1411 
1412           /* this keyframe is inside the segment, convert back to
1413            * segment time */
1414           seg_time = (media_time - seg->media_start) + seg->time;
1415           if ((!next && (seg_time < min_offset)) ||
1416               (next && (seg_time > min_offset)))
1417             min_offset = seg_time;
1418         }
1419       }
1420     }
1421 
1422     if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1423       min_byte_offset = str->samples[index].offset;
1424   }
1425 
1426   if (key_time)
1427     *key_time = min_offset;
1428   if (key_offset)
1429     *key_offset = min_byte_offset;
1430 }
1431 
1432 static gboolean
gst_qtdemux_convert_seek(GstPad * pad,GstFormat * format,GstSeekType cur_type,gint64 * cur,GstSeekType stop_type,gint64 * stop)1433 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1434     GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1435 {
1436   gboolean res;
1437 
1438   g_return_val_if_fail (format != NULL, FALSE);
1439   g_return_val_if_fail (cur != NULL, FALSE);
1440   g_return_val_if_fail (stop != NULL, FALSE);
1441 
1442   if (*format == GST_FORMAT_TIME)
1443     return TRUE;
1444 
1445   res = TRUE;
1446   if (cur_type != GST_SEEK_TYPE_NONE)
1447     res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1448   if (res && stop_type != GST_SEEK_TYPE_NONE)
1449     res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1450 
1451   if (res)
1452     *format = GST_FORMAT_TIME;
1453 
1454   return res;
1455 }
1456 
1457 /* perform seek in push based mode:
1458    find BYTE position to move to based on time and delegate to upstream
1459 */
1460 static gboolean
gst_qtdemux_do_push_seek(GstQTDemux * qtdemux,GstPad * pad,GstEvent * event)1461 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1462 {
1463   gdouble rate;
1464   GstFormat format;
1465   GstSeekFlags flags;
1466   GstSeekType cur_type, stop_type;
1467   gint64 cur, stop, key_cur;
1468   gboolean res;
1469   gint64 byte_cur;
1470   gint64 original_stop;
1471   guint32 seqnum;
1472 
1473   GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1474 
1475   gst_event_parse_seek (event, &rate, &format, &flags,
1476       &cur_type, &cur, &stop_type, &stop);
1477   seqnum = gst_event_get_seqnum (event);
1478 
1479   /* only forward streaming and seeking is possible */
1480   if (rate <= 0)
1481     goto unsupported_seek;
1482 
1483   /* convert to TIME if needed and possible */
1484   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1485           stop_type, &stop))
1486     goto no_format;
1487 
1488   /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1489    * the original stop position to use when upstream pushes the new segment
1490    * for this seek */
1491   original_stop = stop;
1492   stop = -1;
1493 
1494   /* find reasonable corresponding BYTE position,
1495    * also try to mind about keyframes, since we can not go back a bit for them
1496    * later on */
1497   /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1498    * mostly just work, but let's not yet boldly go there  ... */
1499   gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1500 
1501   if (byte_cur == -1)
1502     goto abort_seek;
1503 
1504   GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1505       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1506       stop);
1507 
1508   GST_OBJECT_LOCK (qtdemux);
1509   qtdemux->seek_offset = byte_cur;
1510   if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1511     qtdemux->push_seek_start = cur;
1512   } else {
1513     qtdemux->push_seek_start = key_cur;
1514   }
1515 
1516   if (stop_type == GST_SEEK_TYPE_NONE) {
1517     qtdemux->push_seek_stop = qtdemux->segment.stop;
1518   } else {
1519     qtdemux->push_seek_stop = original_stop;
1520   }
1521   GST_OBJECT_UNLOCK (qtdemux);
1522 
1523   qtdemux->segment_seqnum = seqnum;
1524   /* BYTE seek event */
1525   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1526       stop_type, stop);
1527   gst_event_set_seqnum (event, seqnum);
1528   res = gst_pad_push_event (qtdemux->sinkpad, event);
1529 
1530   return res;
1531 
1532   /* ERRORS */
1533 abort_seek:
1534   {
1535     GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1536         "seek aborted.");
1537     return FALSE;
1538   }
1539 unsupported_seek:
1540   {
1541     GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1542     return FALSE;
1543   }
1544 no_format:
1545   {
1546     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1547     return FALSE;
1548   }
1549 }
1550 
1551 /* perform the seek.
1552  *
1553  * We set all segment_indexes in the streams to unknown and
1554  * adjust the time_position to the desired position. this is enough
1555  * to trigger a segment switch in the streaming thread to start
1556  * streaming from the desired position.
1557  *
1558  * Keyframe seeking is a little more complicated when dealing with
1559  * segments. Ideally we want to move to the previous keyframe in
1560  * the segment but there might not be a keyframe in the segment. In
1561  * fact, none of the segments could contain a keyframe. We take a
1562  * practical approach: seek to the previous keyframe in the segment,
1563  * if there is none, seek to the beginning of the segment.
1564  *
1565  * Called with STREAM_LOCK
1566  */
1567 static gboolean
gst_qtdemux_perform_seek(GstQTDemux * qtdemux,GstSegment * segment,guint32 seqnum,GstSeekFlags flags)1568 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1569     guint32 seqnum, GstSeekFlags flags)
1570 {
1571   gint64 desired_offset;
1572   guint i;
1573 
1574   desired_offset = segment->position;
1575 
1576   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1577       GST_TIME_ARGS (desired_offset));
1578 
1579   /* may not have enough fragmented info to do this adjustment,
1580    * and we can't scan (and probably should not) at this time with
1581    * possibly flushing upstream */
1582   if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1583     gint64 min_offset;
1584     gboolean next, before, after;
1585 
1586     before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1587     after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1588     next = after && !before;
1589     if (segment->rate < 0)
1590       next = !next;
1591 
1592     gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1593         NULL);
1594     GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1595         GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1596     desired_offset = min_offset;
1597   }
1598 
1599   /* and set all streams to the final position */
1600   gst_flow_combiner_reset (qtdemux->flowcombiner);
1601   qtdemux->segment_seqnum = seqnum;
1602   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1603     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1604 
1605     stream->time_position = desired_offset;
1606     stream->accumulated_base = 0;
1607     stream->sample_index = -1;
1608     stream->offset_in_sample = 0;
1609     stream->segment_index = -1;
1610     stream->sent_eos = FALSE;
1611 
1612     if (segment->flags & GST_SEEK_FLAG_FLUSH)
1613       gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1614   }
1615   segment->position = desired_offset;
1616   segment->time = desired_offset;
1617   if (segment->rate >= 0) {
1618     segment->start = desired_offset;
1619 
1620     /* we stop at the end */
1621     if (segment->stop == -1)
1622       segment->stop = segment->duration;
1623   } else {
1624     segment->stop = desired_offset;
1625   }
1626 
1627   if (qtdemux->fragmented)
1628     qtdemux->fragmented_seek_pending = TRUE;
1629 
1630   return TRUE;
1631 }
1632 
1633 /* do a seek in pull based mode */
1634 static gboolean
gst_qtdemux_do_seek(GstQTDemux * qtdemux,GstPad * pad,GstEvent * event)1635 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1636 {
1637   gdouble rate;
1638   GstFormat format;
1639   GstSeekFlags flags;
1640   GstSeekType cur_type, stop_type;
1641   gint64 cur, stop;
1642   gboolean flush;
1643   gboolean update;
1644   GstSegment seeksegment;
1645   guint32 seqnum = GST_SEQNUM_INVALID;
1646   GstEvent *flush_event;
1647   gboolean ret;
1648 
1649   if (event) {
1650     GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1651 
1652     gst_event_parse_seek (event, &rate, &format, &flags,
1653         &cur_type, &cur, &stop_type, &stop);
1654     seqnum = gst_event_get_seqnum (event);
1655 
1656     /* we have to have a format as the segment format. Try to convert
1657      * if not. */
1658     if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1659             stop_type, &stop))
1660       goto no_format;
1661 
1662     GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1663   } else {
1664     GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1665     flags = 0;
1666   }
1667 
1668   flush = flags & GST_SEEK_FLAG_FLUSH;
1669 
1670   /* stop streaming, either by flushing or by pausing the task */
1671   if (flush) {
1672     flush_event = gst_event_new_flush_start ();
1673     if (seqnum != GST_SEQNUM_INVALID)
1674       gst_event_set_seqnum (flush_event, seqnum);
1675     /* unlock upstream pull_range */
1676     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1677     /* make sure out loop function exits */
1678     gst_qtdemux_push_event (qtdemux, flush_event);
1679   } else {
1680     /* non flushing seek, pause the task */
1681     gst_pad_pause_task (qtdemux->sinkpad);
1682   }
1683 
1684   /* wait for streaming to finish */
1685   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1686 
1687   /* copy segment, we need this because we still need the old
1688    * segment when we close the current segment. */
1689   memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1690 
1691   if (event) {
1692     /* configure the segment with the seek variables */
1693     GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1694     if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1695             cur_type, cur, stop_type, stop, &update)) {
1696       ret = FALSE;
1697       GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1698     } else {
1699       /* now do the seek */
1700       ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1701     }
1702   } else {
1703     /* now do the seek */
1704     ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1705   }
1706 
1707   /* prepare for streaming again */
1708   if (flush) {
1709     flush_event = gst_event_new_flush_stop (TRUE);
1710     if (seqnum != GST_SEQNUM_INVALID)
1711       gst_event_set_seqnum (flush_event, seqnum);
1712 
1713     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1714     gst_qtdemux_push_event (qtdemux, flush_event);
1715   }
1716 
1717   /* commit the new segment */
1718   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1719 
1720   if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1721     GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1722         qtdemux->segment.format, qtdemux->segment.position);
1723     if (seqnum != GST_SEQNUM_INVALID)
1724       gst_message_set_seqnum (msg, seqnum);
1725     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1726   }
1727 
1728   /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1729   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1730       qtdemux->sinkpad, NULL);
1731 
1732   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1733 
1734   return ret;
1735 
1736   /* ERRORS */
1737 no_format:
1738   {
1739     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1740     return FALSE;
1741   }
1742 }
1743 
1744 static gboolean
qtdemux_ensure_index(GstQTDemux * qtdemux)1745 qtdemux_ensure_index (GstQTDemux * qtdemux)
1746 {
1747   guint i;
1748 
1749   GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1750 
1751   /* Build complete index */
1752   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1753     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1754 
1755     if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1756       GST_LOG_OBJECT (qtdemux,
1757           "Building complete index of track-id %u for seeking failed!",
1758           stream->track_id);
1759       return FALSE;
1760     }
1761   }
1762 
1763   return TRUE;
1764 }
1765 
1766 static gboolean
gst_qtdemux_handle_src_event(GstPad * pad,GstObject * parent,GstEvent * event)1767 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1768     GstEvent * event)
1769 {
1770   gboolean res = TRUE;
1771   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1772 
1773   switch (GST_EVENT_TYPE (event)) {
1774     case GST_EVENT_SEEK:
1775     {
1776 #ifndef GST_DISABLE_GST_DEBUG
1777       GstClockTime ts = gst_util_get_timestamp ();
1778 #endif
1779       guint32 seqnum = gst_event_get_seqnum (event);
1780 
1781       qtdemux->received_seek = TRUE;
1782 
1783       if (seqnum == qtdemux->segment_seqnum) {
1784         GST_LOG_OBJECT (pad,
1785             "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1786         gst_event_unref (event);
1787         return TRUE;
1788       }
1789 
1790       if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1791         /* seek should be handled by upstream, we might need to re-download fragments */
1792         GST_DEBUG_OBJECT (qtdemux,
1793             "let upstream handle seek for fragmented playback");
1794         goto upstream;
1795       }
1796 
1797       /* Build complete index for seeking;
1798        * if not a fragmented file at least */
1799       if (!qtdemux->fragmented)
1800         if (!qtdemux_ensure_index (qtdemux))
1801           goto index_failed;
1802 #ifndef GST_DISABLE_GST_DEBUG
1803       ts = gst_util_get_timestamp () - ts;
1804       GST_INFO_OBJECT (qtdemux,
1805           "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1806 #endif
1807     }
1808       if (qtdemux->pullbased) {
1809         res = gst_qtdemux_do_seek (qtdemux, pad, event);
1810       } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1811         GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1812         res = TRUE;
1813       } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1814           && QTDEMUX_N_STREAMS (qtdemux)
1815           && !qtdemux->fragmented) {
1816         res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1817       } else {
1818         GST_DEBUG_OBJECT (qtdemux,
1819             "ignoring seek in push mode in current state");
1820         res = FALSE;
1821       }
1822       gst_event_unref (event);
1823       break;
1824     default:
1825     upstream:
1826       res = gst_pad_event_default (pad, parent, event);
1827       break;
1828   }
1829 
1830 done:
1831   return res;
1832 
1833   /* ERRORS */
1834 index_failed:
1835   {
1836     GST_ERROR_OBJECT (qtdemux, "Index failed");
1837     gst_event_unref (event);
1838     res = FALSE;
1839     goto done;
1840   }
1841 }
1842 
1843 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1844  *
1845  * If @fw is false, the coding order is explored backwards.
1846  *
1847  * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1848  * sample is found for that track.
1849  *
1850  * The stream and sample index of the sample with the minimum offset in the direction explored
1851  * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1852  *
1853  * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1854  * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1855  * @_stream and @_index. */
1856 static void
gst_qtdemux_find_sample(GstQTDemux * qtdemux,gint64 byte_pos,gboolean fw,gboolean set,QtDemuxStream ** _stream,gint * _index,gint64 * _time)1857 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1858     gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1859 {
1860   gint i, index;
1861   gint64 time, min_time;
1862   QtDemuxStream *stream;
1863   gint iter;
1864 
1865   min_time = -1;
1866   stream = NULL;
1867   index = -1;
1868 
1869   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1870     QtDemuxStream *str;
1871     gint inc;
1872     gboolean set_sample;
1873 
1874     str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1875     set_sample = !set;
1876 
1877     if (fw) {
1878       i = 0;
1879       inc = 1;
1880     } else {
1881       i = str->n_samples - 1;
1882       inc = -1;
1883     }
1884 
1885     for (; (i >= 0) && (i < str->n_samples); i += inc) {
1886       if (str->samples[i].size == 0)
1887         continue;
1888 
1889       if (fw && (str->samples[i].offset < byte_pos))
1890         continue;
1891 
1892       if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1893         continue;
1894 
1895       /* move stream to first available sample */
1896       if (set) {
1897         gst_qtdemux_move_stream (qtdemux, str, i);
1898         set_sample = TRUE;
1899       }
1900 
1901       /* avoid index from sparse streams since they might be far away */
1902       if (!CUR_STREAM (str)->sparse) {
1903         /* determine min/max time */
1904         time = QTSAMPLE_PTS (str, &str->samples[i]);
1905         if (min_time == -1 || (!fw && time > min_time) ||
1906             (fw && time < min_time)) {
1907           min_time = time;
1908         }
1909 
1910         /* determine stream with leading sample, to get its position */
1911         if (!stream ||
1912             (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1913             (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1914           stream = str;
1915           index = i;
1916         }
1917       }
1918       break;
1919     }
1920 
1921     /* no sample for this stream, mark eos */
1922     if (!set_sample)
1923       gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1924   }
1925 
1926   if (_time)
1927     *_time = min_time;
1928   if (_stream)
1929     *_stream = stream;
1930   if (_index)
1931     *_index = index;
1932 }
1933 
1934 /* Copied from mpegtsbase code */
1935 /* FIXME: replace this function when we add new util function for stream-id creation */
1936 static gchar *
_get_upstream_id(GstQTDemux * demux)1937 _get_upstream_id (GstQTDemux * demux)
1938 {
1939   gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1940 
1941   if (!upstream_id) {
1942     /* Try to create one from the upstream URI, else use a randome number */
1943     GstQuery *query;
1944     gchar *uri = NULL;
1945 
1946     /* Try to generate one from the URI query and
1947      * if it fails take a random number instead */
1948     query = gst_query_new_uri ();
1949     if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1950       gst_query_parse_uri (query, &uri);
1951     }
1952 
1953     if (uri) {
1954       GChecksum *cs;
1955 
1956       /* And then generate an SHA256 sum of the URI */
1957       cs = g_checksum_new (G_CHECKSUM_SHA256);
1958       g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1959       g_free (uri);
1960       upstream_id = g_strdup (g_checksum_get_string (cs));
1961       g_checksum_free (cs);
1962     } else {
1963       /* Just get some random number if the URI query fails */
1964       GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1965           "implementing a deterministic way of creating a stream-id");
1966       upstream_id =
1967           g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1968           g_random_int (), g_random_int ());
1969     }
1970 
1971     gst_query_unref (query);
1972   }
1973   return upstream_id;
1974 }
1975 
1976 static QtDemuxStream *
_create_stream(GstQTDemux * demux,guint32 track_id)1977 _create_stream (GstQTDemux * demux, guint32 track_id)
1978 {
1979   QtDemuxStream *stream;
1980   gchar *upstream_id;
1981 
1982   stream = g_new0 (QtDemuxStream, 1);
1983   stream->demux = demux;
1984   stream->track_id = track_id;
1985   upstream_id = _get_upstream_id (demux);
1986   stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1987   g_free (upstream_id);
1988   /* new streams always need a discont */
1989   stream->discont = TRUE;
1990   /* we enable clipping for raw audio/video streams */
1991   stream->need_clip = FALSE;
1992   stream->need_process = FALSE;
1993   stream->segment_index = -1;
1994   stream->time_position = 0;
1995   stream->sample_index = -1;
1996   stream->offset_in_sample = 0;
1997   stream->new_stream = TRUE;
1998   stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1999   stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2000   stream->protected = FALSE;
2001   stream->protection_scheme_type = 0;
2002   stream->protection_scheme_version = 0;
2003   stream->protection_scheme_info = NULL;
2004   stream->n_samples_moof = 0;
2005   stream->duration_moof = 0;
2006   stream->duration_last_moof = 0;
2007   stream->alignment = 1;
2008   stream->stream_tags = gst_tag_list_new_empty ();
2009   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2010   g_queue_init (&stream->protection_scheme_event_queue);
2011   stream->ref_count = 1;
2012   /* consistent default for push based mode */
2013   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
2014   return stream;
2015 }
2016 
2017 static gboolean
gst_qtdemux_setcaps(GstQTDemux * demux,GstCaps * caps)2018 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
2019 {
2020   GstStructure *structure;
2021   const gchar *variant;
2022   const GstCaps *mediacaps = NULL;
2023 
2024   GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
2025 
2026   structure = gst_caps_get_structure (caps, 0);
2027   variant = gst_structure_get_string (structure, "variant");
2028 
2029   if (variant && strcmp (variant, "mss-fragmented") == 0) {
2030     QtDemuxStream *stream;
2031     const GValue *value;
2032 
2033     demux->fragmented = TRUE;
2034     demux->mss_mode = TRUE;
2035 
2036     if (QTDEMUX_N_STREAMS (demux) > 1) {
2037       /* can't do this, we can only renegotiate for another mss format */
2038       return FALSE;
2039     }
2040 
2041     value = gst_structure_get_value (structure, "media-caps");
2042     /* create stream */
2043     if (value) {
2044       const GValue *timescale_v;
2045 
2046       /* TODO update when stream changes during playback */
2047 
2048       if (QTDEMUX_N_STREAMS (demux) == 0) {
2049         stream = _create_stream (demux, 1);
2050         g_ptr_array_add (demux->active_streams, stream);
2051         /* mss has no stsd/stsd entry, use id 0 as default */
2052         stream->stsd_entries_length = 1;
2053         stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
2054         stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
2055       } else {
2056         stream = QTDEMUX_NTH_STREAM (demux, 0);
2057       }
2058 
2059       timescale_v = gst_structure_get_value (structure, "timescale");
2060       if (timescale_v) {
2061         stream->timescale = g_value_get_uint64 (timescale_v);
2062       } else {
2063         /* default mss timescale */
2064         stream->timescale = 10000000;
2065       }
2066       demux->timescale = stream->timescale;
2067 
2068       mediacaps = gst_value_get_caps (value);
2069       if (!CUR_STREAM (stream)->caps
2070           || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2071         GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2072             mediacaps);
2073         stream->new_caps = TRUE;
2074       }
2075       gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2076       structure = gst_caps_get_structure (mediacaps, 0);
2077       if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2078         stream->subtype = FOURCC_vide;
2079 
2080         gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2081         gst_structure_get_int (structure, "height",
2082             &CUR_STREAM (stream)->height);
2083         gst_structure_get_fraction (structure, "framerate",
2084             &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2085       } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2086         gint rate = 0;
2087         stream->subtype = FOURCC_soun;
2088         gst_structure_get_int (structure, "channels",
2089             &CUR_STREAM (stream)->n_channels);
2090         gst_structure_get_int (structure, "rate", &rate);
2091         CUR_STREAM (stream)->rate = rate;
2092       }
2093     }
2094     gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2095   } else {
2096     demux->mss_mode = FALSE;
2097   }
2098 
2099   return TRUE;
2100 }
2101 
2102 static void
gst_qtdemux_reset(GstQTDemux * qtdemux,gboolean hard)2103 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2104 {
2105   gint i;
2106 
2107   GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2108   gst_pad_stop_task (qtdemux->sinkpad);
2109 
2110   if (hard || qtdemux->upstream_format_is_time) {
2111     qtdemux->state = QTDEMUX_STATE_INITIAL;
2112     qtdemux->neededbytes = 16;
2113     qtdemux->todrop = 0;
2114     qtdemux->pullbased = FALSE;
2115     qtdemux->posted_redirect = FALSE;
2116     qtdemux->first_mdat = -1;
2117     qtdemux->header_size = 0;
2118     qtdemux->mdatoffset = -1;
2119     qtdemux->restoredata_offset = -1;
2120     if (qtdemux->mdatbuffer)
2121       gst_buffer_unref (qtdemux->mdatbuffer);
2122     if (qtdemux->restoredata_buffer)
2123       gst_buffer_unref (qtdemux->restoredata_buffer);
2124     qtdemux->mdatbuffer = NULL;
2125     qtdemux->restoredata_buffer = NULL;
2126     qtdemux->mdatleft = 0;
2127     qtdemux->mdatsize = 0;
2128     if (qtdemux->comp_brands)
2129       gst_buffer_unref (qtdemux->comp_brands);
2130     qtdemux->comp_brands = NULL;
2131     qtdemux->last_moov_offset = -1;
2132     if (qtdemux->moov_node_compressed) {
2133       g_node_destroy (qtdemux->moov_node_compressed);
2134       if (qtdemux->moov_node)
2135         g_free (qtdemux->moov_node->data);
2136     }
2137     qtdemux->moov_node_compressed = NULL;
2138     if (qtdemux->moov_node)
2139       g_node_destroy (qtdemux->moov_node);
2140     qtdemux->moov_node = NULL;
2141     if (qtdemux->tag_list)
2142       gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2143     qtdemux->tag_list = gst_tag_list_new_empty ();
2144     gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2145 #if 0
2146     if (qtdemux->element_index)
2147       gst_object_unref (qtdemux->element_index);
2148     qtdemux->element_index = NULL;
2149 #endif
2150     qtdemux->major_brand = 0;
2151     qtdemux->upstream_format_is_time = FALSE;
2152     qtdemux->upstream_seekable = FALSE;
2153     qtdemux->upstream_size = 0;
2154 
2155     qtdemux->fragment_start = -1;
2156     qtdemux->fragment_start_offset = -1;
2157     qtdemux->duration = 0;
2158     qtdemux->moof_offset = 0;
2159     qtdemux->chapters_track_id = 0;
2160     qtdemux->have_group_id = FALSE;
2161     qtdemux->group_id = G_MAXUINT;
2162 
2163     g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2164         NULL);
2165     g_queue_clear (&qtdemux->protection_event_queue);
2166 
2167     qtdemux->received_seek = FALSE;
2168     qtdemux->first_moof_already_parsed = FALSE;
2169   }
2170   qtdemux->offset = 0;
2171   gst_adapter_clear (qtdemux->adapter);
2172   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2173   qtdemux->need_segment = TRUE;
2174 
2175   if (hard) {
2176     qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2177     g_ptr_array_set_size (qtdemux->active_streams, 0);
2178     g_ptr_array_set_size (qtdemux->old_streams, 0);
2179     qtdemux->n_video_streams = 0;
2180     qtdemux->n_audio_streams = 0;
2181     qtdemux->n_sub_streams = 0;
2182     qtdemux->exposed = FALSE;
2183     qtdemux->fragmented = FALSE;
2184     qtdemux->mss_mode = FALSE;
2185     gst_caps_replace (&qtdemux->media_caps, NULL);
2186     qtdemux->timescale = 0;
2187     qtdemux->got_moov = FALSE;
2188     qtdemux->cenc_aux_info_offset = 0;
2189     qtdemux->cenc_aux_info_sizes = NULL;
2190     qtdemux->cenc_aux_sample_count = 0;
2191     if (qtdemux->protection_system_ids) {
2192       g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2193       qtdemux->protection_system_ids = NULL;
2194     }
2195     qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2196         && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2197         GST_BIN_FLAG_STREAMS_AWARE);
2198 
2199     if (qtdemux->preferred_protection_system_id) {
2200       g_free (qtdemux->preferred_protection_system_id);
2201       qtdemux->preferred_protection_system_id = NULL;
2202     }
2203   } else if (qtdemux->mss_mode) {
2204     gst_flow_combiner_reset (qtdemux->flowcombiner);
2205     g_ptr_array_foreach (qtdemux->active_streams,
2206         (GFunc) gst_qtdemux_stream_clear, NULL);
2207   } else {
2208     gst_flow_combiner_reset (qtdemux->flowcombiner);
2209     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2210       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2211       stream->sent_eos = FALSE;
2212       stream->time_position = 0;
2213       stream->accumulated_base = 0;
2214     }
2215   }
2216 }
2217 
2218 
2219 /* Maps the @segment to the qt edts internal segments and pushes
2220  * the correspnding segment event.
2221  *
2222  * If it ends up being at a empty segment, a gap will be pushed and the next
2223  * edts segment will be activated in sequence.
2224  *
2225  * To be used in push-mode only */
2226 static void
gst_qtdemux_map_and_push_segments(GstQTDemux * qtdemux,GstSegment * segment)2227 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2228 {
2229   gint i, iter;
2230 
2231   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2232     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2233 
2234     stream->time_position = segment->start;
2235 
2236     /* in push mode we should be guaranteed that we will have empty segments
2237      * at the beginning and then one segment after, other scenarios are not
2238      * supported and are discarded when parsing the edts */
2239     for (i = 0; i < stream->n_segments; i++) {
2240       if (stream->segments[i].stop_time > segment->start) {
2241         /* push the empty segment and move to the next one */
2242         gst_qtdemux_activate_segment (qtdemux, stream, i,
2243             stream->time_position);
2244         if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2245           gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2246               stream->time_position);
2247 
2248           /* accumulate previous segments */
2249           if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2250             stream->accumulated_base +=
2251                 (stream->segment.stop -
2252                 stream->segment.start) / ABS (stream->segment.rate);
2253           continue;
2254         }
2255 
2256         g_assert (i == stream->n_segments - 1);
2257       }
2258     }
2259   }
2260 }
2261 
2262 static void
gst_qtdemux_stream_concat(GstQTDemux * qtdemux,GPtrArray * dest,GPtrArray * src)2263 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2264     GPtrArray * src)
2265 {
2266   guint i;
2267   guint len;
2268 
2269   len = src->len;
2270 
2271   if (len == 0)
2272     return;
2273 
2274   for (i = 0; i < len; i++) {
2275     QtDemuxStream *stream = g_ptr_array_index (src, i);
2276 
2277 #ifndef GST_DISABLE_GST_DEBUG
2278     GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2279         stream, GST_STR_NULL (stream->stream_id), dest);
2280 #endif
2281     g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2282   }
2283 
2284   g_ptr_array_set_size (src, 0);
2285 }
2286 
2287 static gboolean
gst_qtdemux_handle_sink_event(GstPad * sinkpad,GstObject * parent,GstEvent * event)2288 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2289     GstEvent * event)
2290 {
2291   GstQTDemux *demux = GST_QTDEMUX (parent);
2292   gboolean res = TRUE;
2293 
2294   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2295 
2296   switch (GST_EVENT_TYPE (event)) {
2297     case GST_EVENT_SEGMENT:
2298     {
2299       gint64 offset = 0;
2300       QtDemuxStream *stream;
2301       gint idx;
2302       GstSegment segment;
2303 
2304       /* some debug output */
2305       gst_event_copy_segment (event, &segment);
2306       GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2307           &segment);
2308 
2309       if (segment.format == GST_FORMAT_TIME) {
2310         demux->upstream_format_is_time = TRUE;
2311         demux->segment_seqnum = gst_event_get_seqnum (event);
2312       } else {
2313         GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2314             "not in time format");
2315 
2316         /* chain will send initial newsegment after pads have been added */
2317         if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2318           GST_DEBUG_OBJECT (demux, "still starting, eating event");
2319           goto exit;
2320         }
2321       }
2322 
2323       /* check if this matches a time seek we received previously
2324        * FIXME for backwards compatibility reasons we use the
2325        * seek_offset here to compare. In the future we might want to
2326        * change this to use the seqnum as it uniquely should identify
2327        * the segment that corresponds to the seek. */
2328       GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2329           ", received segment offset %" G_GINT64_FORMAT,
2330           demux->seek_offset, segment.start);
2331       if (segment.format == GST_FORMAT_BYTES
2332           && demux->seek_offset == segment.start) {
2333         GST_OBJECT_LOCK (demux);
2334         offset = segment.start;
2335 
2336         segment.format = GST_FORMAT_TIME;
2337         segment.start = demux->push_seek_start;
2338         segment.stop = demux->push_seek_stop;
2339         GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2340             "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2341             GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2342         GST_OBJECT_UNLOCK (demux);
2343       }
2344 
2345       /* we only expect a BYTE segment, e.g. following a seek */
2346       if (segment.format == GST_FORMAT_BYTES) {
2347         if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2348           offset = segment.start;
2349 
2350           gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2351               NULL, (gint64 *) & segment.start);
2352           if ((gint64) segment.start < 0)
2353             segment.start = 0;
2354         }
2355         if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2356           gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2357               NULL, (gint64 *) & segment.stop);
2358           /* keyframe seeking should already arrange for start >= stop,
2359            * but make sure in other rare cases */
2360           segment.stop = MAX (segment.stop, segment.start);
2361         }
2362       } else if (segment.format == GST_FORMAT_TIME) {
2363         /* push all data on the adapter before starting this
2364          * new segment */
2365         gst_qtdemux_process_adapter (demux, TRUE);
2366       } else {
2367         GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2368         goto exit;
2369       }
2370 
2371       /* We shouldn't modify upstream driven TIME FORMAT segment */
2372       if (!demux->upstream_format_is_time) {
2373         /* accept upstream's notion of segment and distribute along */
2374         segment.format = GST_FORMAT_TIME;
2375         segment.position = segment.time = segment.start;
2376         segment.duration = demux->segment.duration;
2377         segment.base = gst_segment_to_running_time (&demux->segment,
2378             GST_FORMAT_TIME, demux->segment.position);
2379       }
2380 
2381       gst_segment_copy_into (&segment, &demux->segment);
2382       GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2383 
2384       /* map segment to internal qt segments and push on each stream */
2385       if (QTDEMUX_N_STREAMS (demux)) {
2386         demux->need_segment = TRUE;
2387         gst_qtdemux_check_send_pending_segment (demux);
2388       }
2389 
2390       /* clear leftover in current segment, if any */
2391       gst_adapter_clear (demux->adapter);
2392 
2393       /* set up streaming thread */
2394       demux->offset = offset;
2395       if (demux->upstream_format_is_time) {
2396         GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2397             "set values to restart reading from a new atom");
2398         demux->neededbytes = 16;
2399         demux->todrop = 0;
2400       } else {
2401         gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2402             NULL);
2403         if (stream) {
2404           demux->todrop = stream->samples[idx].offset - offset;
2405           demux->neededbytes = demux->todrop + stream->samples[idx].size;
2406         } else {
2407           /* set up for EOS */
2408           demux->neededbytes = -1;
2409           demux->todrop = 0;
2410         }
2411       }
2412     exit:
2413       gst_event_unref (event);
2414       res = TRUE;
2415       goto drop;
2416     }
2417     case GST_EVENT_FLUSH_START:
2418     {
2419       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2420         gst_event_unref (event);
2421         goto drop;
2422       }
2423       QTDEMUX_EXPOSE_LOCK (demux);
2424       res = gst_pad_event_default (demux->sinkpad, parent, event);
2425       QTDEMUX_EXPOSE_UNLOCK (demux);
2426       goto drop;
2427     }
2428     case GST_EVENT_FLUSH_STOP:
2429     {
2430       guint64 dur;
2431 
2432       dur = demux->segment.duration;
2433       gst_qtdemux_reset (demux, FALSE);
2434       demux->segment.duration = dur;
2435 
2436       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2437         gst_event_unref (event);
2438         goto drop;
2439       }
2440       break;
2441     }
2442     case GST_EVENT_EOS:
2443       /* If we are in push mode, and get an EOS before we've seen any streams,
2444        * then error out - we have nowhere to send the EOS */
2445       if (!demux->pullbased) {
2446         gint i;
2447         gboolean has_valid_stream = FALSE;
2448         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2449           if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2450             has_valid_stream = TRUE;
2451             break;
2452           }
2453         }
2454         if (!has_valid_stream)
2455           gst_qtdemux_post_no_playable_stream_error (demux);
2456         else {
2457           GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2458               (guint) gst_adapter_available (demux->adapter));
2459           if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2460             res = FALSE;
2461           }
2462         }
2463       }
2464       break;
2465     case GST_EVENT_CAPS:{
2466       GstCaps *caps = NULL;
2467 
2468       gst_event_parse_caps (event, &caps);
2469       gst_qtdemux_setcaps (demux, caps);
2470       res = TRUE;
2471       gst_event_unref (event);
2472       goto drop;
2473     }
2474     case GST_EVENT_PROTECTION:
2475     {
2476       const gchar *system_id = NULL;
2477 
2478       gst_event_parse_protection (event, &system_id, NULL, NULL);
2479       GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2480           system_id);
2481       gst_qtdemux_append_protection_system_id (demux, system_id);
2482       /* save the event for later, for source pads that have not been created */
2483       g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2484       /* send it to all pads that already exist */
2485       gst_qtdemux_push_event (demux, event);
2486       res = TRUE;
2487       goto drop;
2488     }
2489     case GST_EVENT_STREAM_START:
2490     {
2491       res = TRUE;
2492       gst_event_unref (event);
2493 
2494       /* Drain all the buffers */
2495       gst_qtdemux_process_adapter (demux, TRUE);
2496       gst_qtdemux_reset (demux, FALSE);
2497       /* We expect new moov box after new stream-start event */
2498       if (demux->exposed) {
2499         gst_qtdemux_stream_concat (demux,
2500             demux->old_streams, demux->active_streams);
2501       }
2502 
2503       goto drop;
2504     }
2505     default:
2506       break;
2507   }
2508 
2509   res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2510 
2511 drop:
2512   return res;
2513 }
2514 
2515 static gboolean
gst_qtdemux_handle_sink_query(GstPad * pad,GstObject * parent,GstQuery * query)2516 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2517     GstQuery * query)
2518 {
2519   GstQTDemux *demux = GST_QTDEMUX (parent);
2520   gboolean res = FALSE;
2521 
2522   switch (GST_QUERY_TYPE (query)) {
2523     case GST_QUERY_BITRATE:
2524     {
2525       GstClockTime duration;
2526 
2527       /* populate demux->upstream_size if not done yet */
2528       gst_qtdemux_check_seekability (demux);
2529 
2530       if (demux->upstream_size != -1
2531           && gst_qtdemux_get_duration (demux, &duration)) {
2532         guint bitrate =
2533             gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2534             duration);
2535 
2536         GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2537             " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2538             demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2539 
2540         /* TODO: better results based on ranges/index tables */
2541         gst_query_set_bitrate (query, bitrate);
2542         res = TRUE;
2543       }
2544       break;
2545     }
2546     default:
2547       res = gst_pad_query_default (pad, (GstObject *) demux, query);
2548       break;
2549   }
2550 
2551   return res;
2552 }
2553 
2554 
2555 #if 0
2556 static void
2557 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2558 {
2559   GstQTDemux *demux = GST_QTDEMUX (element);
2560 
2561   GST_OBJECT_LOCK (demux);
2562   if (demux->element_index)
2563     gst_object_unref (demux->element_index);
2564   if (index) {
2565     demux->element_index = gst_object_ref (index);
2566   } else {
2567     demux->element_index = NULL;
2568   }
2569   GST_OBJECT_UNLOCK (demux);
2570   /* object lock might be taken again */
2571   if (index)
2572     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2573   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2574       demux->element_index, demux->index_id);
2575 }
2576 
2577 static GstIndex *
2578 gst_qtdemux_get_index (GstElement * element)
2579 {
2580   GstIndex *result = NULL;
2581   GstQTDemux *demux = GST_QTDEMUX (element);
2582 
2583   GST_OBJECT_LOCK (demux);
2584   if (demux->element_index)
2585     result = gst_object_ref (demux->element_index);
2586   GST_OBJECT_UNLOCK (demux);
2587 
2588   GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2589 
2590   return result;
2591 }
2592 #endif
2593 
2594 static void
gst_qtdemux_stbl_free(QtDemuxStream * stream)2595 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2596 {
2597   g_free ((gpointer) stream->stco.data);
2598   stream->stco.data = NULL;
2599   g_free ((gpointer) stream->stsz.data);
2600   stream->stsz.data = NULL;
2601   g_free ((gpointer) stream->stsc.data);
2602   stream->stsc.data = NULL;
2603   g_free ((gpointer) stream->stts.data);
2604   stream->stts.data = NULL;
2605   g_free ((gpointer) stream->stss.data);
2606   stream->stss.data = NULL;
2607   g_free ((gpointer) stream->stps.data);
2608   stream->stps.data = NULL;
2609   g_free ((gpointer) stream->ctts.data);
2610   stream->ctts.data = NULL;
2611 }
2612 
2613 static void
gst_qtdemux_stream_flush_segments_data(QtDemuxStream * stream)2614 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2615 {
2616   g_free (stream->segments);
2617   stream->segments = NULL;
2618   stream->segment_index = -1;
2619   stream->accumulated_base = 0;
2620 }
2621 
2622 static void
gst_qtdemux_stream_flush_samples_data(QtDemuxStream * stream)2623 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2624 {
2625   g_free (stream->samples);
2626   stream->samples = NULL;
2627   gst_qtdemux_stbl_free (stream);
2628 
2629   /* fragments */
2630   g_free (stream->ra_entries);
2631   stream->ra_entries = NULL;
2632   stream->n_ra_entries = 0;
2633 
2634   stream->sample_index = -1;
2635   stream->stbl_index = -1;
2636   stream->n_samples = 0;
2637   stream->time_position = 0;
2638 
2639   stream->n_samples_moof = 0;
2640   stream->duration_moof = 0;
2641   stream->duration_last_moof = 0;
2642 }
2643 
2644 static void
gst_qtdemux_stream_clear(QtDemuxStream * stream)2645 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2646 {
2647   gint i;
2648   if (stream->allocator)
2649     gst_object_unref (stream->allocator);
2650   while (stream->buffers) {
2651     gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2652     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2653   }
2654   for (i = 0; i < stream->stsd_entries_length; i++) {
2655     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2656     if (entry->rgb8_palette) {
2657       gst_memory_unref (entry->rgb8_palette);
2658       entry->rgb8_palette = NULL;
2659     }
2660     entry->sparse = FALSE;
2661   }
2662 
2663   if (stream->stream_tags)
2664     gst_tag_list_unref (stream->stream_tags);
2665 
2666   stream->stream_tags = gst_tag_list_new_empty ();
2667   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2668   g_free (stream->redirect_uri);
2669   stream->redirect_uri = NULL;
2670   stream->sent_eos = FALSE;
2671   stream->protected = FALSE;
2672   if (stream->protection_scheme_info) {
2673     if (stream->protection_scheme_type == FOURCC_cenc) {
2674       QtDemuxCencSampleSetInfo *info =
2675           (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2676       if (info->default_properties)
2677         gst_structure_free (info->default_properties);
2678       if (info->crypto_info)
2679         g_ptr_array_free (info->crypto_info, TRUE);
2680     }
2681     g_free (stream->protection_scheme_info);
2682     stream->protection_scheme_info = NULL;
2683   }
2684   stream->protection_scheme_type = 0;
2685   stream->protection_scheme_version = 0;
2686   g_queue_foreach (&stream->protection_scheme_event_queue,
2687       (GFunc) gst_event_unref, NULL);
2688   g_queue_clear (&stream->protection_scheme_event_queue);
2689   gst_qtdemux_stream_flush_segments_data (stream);
2690   gst_qtdemux_stream_flush_samples_data (stream);
2691 }
2692 
2693 static void
gst_qtdemux_stream_reset(QtDemuxStream * stream)2694 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2695 {
2696   gint i;
2697   gst_qtdemux_stream_clear (stream);
2698   for (i = 0; i < stream->stsd_entries_length; i++) {
2699     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2700     if (entry->caps) {
2701       gst_caps_unref (entry->caps);
2702       entry->caps = NULL;
2703     }
2704   }
2705   g_free (stream->stsd_entries);
2706   stream->stsd_entries = NULL;
2707   stream->stsd_entries_length = 0;
2708 }
2709 
2710 static QtDemuxStream *
gst_qtdemux_stream_ref(QtDemuxStream * stream)2711 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2712 {
2713   g_atomic_int_add (&stream->ref_count, 1);
2714 
2715   return stream;
2716 }
2717 
2718 static void
gst_qtdemux_stream_unref(QtDemuxStream * stream)2719 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2720 {
2721   if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2722     gst_qtdemux_stream_reset (stream);
2723     gst_tag_list_unref (stream->stream_tags);
2724     if (stream->pad) {
2725       GstQTDemux *demux = stream->demux;
2726       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2727       gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2728     }
2729     g_free (stream->stream_id);
2730     g_free (stream);
2731   }
2732 }
2733 
2734 static GstStateChangeReturn
gst_qtdemux_change_state(GstElement * element,GstStateChange transition)2735 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2736 {
2737   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2738   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2739 
2740   switch (transition) {
2741     case GST_STATE_CHANGE_READY_TO_PAUSED:
2742       gst_qtdemux_reset (qtdemux, TRUE);
2743       break;
2744     default:
2745       break;
2746   }
2747 
2748   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2749 
2750   switch (transition) {
2751     case GST_STATE_CHANGE_PAUSED_TO_READY:{
2752       gst_qtdemux_reset (qtdemux, TRUE);
2753       break;
2754     }
2755     default:
2756       break;
2757   }
2758 
2759   return result;
2760 }
2761 
2762 static void
gst_qtdemux_set_context(GstElement * element,GstContext * context)2763 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2764 {
2765   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2766 
2767   g_return_if_fail (GST_IS_CONTEXT (context));
2768 
2769   if (gst_context_has_context_type (context,
2770           "drm-preferred-decryption-system-id")) {
2771     const GstStructure *s;
2772 
2773     s = gst_context_get_structure (context);
2774     g_free (qtdemux->preferred_protection_system_id);
2775     qtdemux->preferred_protection_system_id =
2776         g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2777     GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2778         qtdemux->preferred_protection_system_id);
2779   }
2780 
2781   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2782 }
2783 
2784 static void
qtdemux_parse_ftyp(GstQTDemux * qtdemux,const guint8 * buffer,gint length)2785 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2786 {
2787   /* counts as header data */
2788   qtdemux->header_size += length;
2789 
2790   /* only consider at least a sufficiently complete ftyp atom */
2791   if (length >= 20) {
2792     GstBuffer *buf;
2793 
2794     qtdemux->major_brand = QT_FOURCC (buffer + 8);
2795     GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2796         GST_FOURCC_ARGS (qtdemux->major_brand));
2797     if (qtdemux->comp_brands)
2798       gst_buffer_unref (qtdemux->comp_brands);
2799     buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2800     gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2801   }
2802 }
2803 
2804 static void
qtdemux_handle_xmp_taglist(GstQTDemux * qtdemux,GstTagList * taglist,GstTagList * xmptaglist)2805 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2806     GstTagList * xmptaglist)
2807 {
2808   /* Strip out bogus fields */
2809   if (xmptaglist) {
2810     if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2811       gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2812       gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2813     } else {
2814       gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2815     }
2816 
2817     GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2818 
2819     /* prioritize native tags using _KEEP mode */
2820     gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2821     gst_tag_list_unref (xmptaglist);
2822   }
2823 }
2824 
2825 static void
qtdemux_update_default_sample_encryption_settings(GstQTDemux * qtdemux,QtDemuxCencSampleSetInfo * info,guint32 is_encrypted,guint8 iv_size,const guint8 * kid)2826 qtdemux_update_default_sample_encryption_settings (GstQTDemux * qtdemux,
2827     QtDemuxCencSampleSetInfo * info, guint32 is_encrypted, guint8 iv_size,
2828     const guint8 * kid)
2829 {
2830   GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2831   gst_buffer_fill (kid_buf, 0, kid, 16);
2832   if (info->default_properties)
2833     gst_structure_free (info->default_properties);
2834   info->default_properties =
2835       gst_structure_new ("application/x-cenc",
2836       "iv_size", G_TYPE_UINT, iv_size,
2837       "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2838       "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2839   GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2840       "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2841   gst_buffer_unref (kid_buf);
2842 }
2843 
2844 static gboolean
qtdemux_update_default_piff_encryption_settings(GstQTDemux * qtdemux,QtDemuxCencSampleSetInfo * info,GstByteReader * br)2845 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2846     QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2847 {
2848   guint32 algorithm_id = 0;
2849   const guint8 *kid;
2850   gboolean is_encrypted = TRUE;
2851   guint8 iv_size = 8;
2852 
2853   if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2854     GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2855     return FALSE;
2856   }
2857 
2858   algorithm_id >>= 8;
2859   if (algorithm_id == 0) {
2860     is_encrypted = FALSE;
2861   } else if (algorithm_id == 1) {
2862     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2863   } else if (algorithm_id == 2) {
2864     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2865   }
2866 
2867   if (!gst_byte_reader_get_uint8 (br, &iv_size))
2868     return FALSE;
2869 
2870   if (!gst_byte_reader_get_data (br, 16, &kid))
2871     return FALSE;
2872 
2873   qtdemux_update_default_sample_encryption_settings (qtdemux, info,
2874       is_encrypted, iv_size, kid);
2875   gst_structure_set (info->default_properties, "piff_algorithm_id",
2876       G_TYPE_UINT, algorithm_id, NULL);
2877   return TRUE;
2878 }
2879 
2880 
2881 static void
qtdemux_parse_piff(GstQTDemux * qtdemux,const guint8 * buffer,gint length,guint offset)2882 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2883     guint offset)
2884 {
2885   GstByteReader br;
2886   guint8 version;
2887   guint32 flags = 0;
2888   guint i;
2889   guint iv_size = 8;
2890   QtDemuxStream *stream;
2891   GstStructure *structure;
2892   QtDemuxCencSampleSetInfo *ss_info = NULL;
2893   const gchar *system_id;
2894   gboolean uses_sub_sample_encryption = FALSE;
2895   guint32 sample_count;
2896 
2897   if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2898     return;
2899 
2900   stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2901 
2902   structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2903   if (!gst_structure_has_name (structure, "application/x-cenc")) {
2904     GST_WARNING_OBJECT (qtdemux,
2905         "Attempting PIFF box parsing on an unencrypted stream.");
2906     return;
2907   }
2908 
2909   gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2910       G_TYPE_STRING, &system_id, NULL);
2911   gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2912 
2913   stream->protected = TRUE;
2914   stream->protection_scheme_type = FOURCC_cenc;
2915 
2916   if (!stream->protection_scheme_info)
2917     stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2918 
2919   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2920   if (!ss_info->default_properties) {
2921     ss_info->default_properties =
2922         gst_structure_new ("application/x-cenc",
2923         "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2924         NULL);
2925 
2926   }
2927 
2928   if (ss_info->crypto_info) {
2929     GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2930     g_ptr_array_free (ss_info->crypto_info, TRUE);
2931     ss_info->crypto_info = NULL;
2932   }
2933 
2934   /* skip UUID */
2935   gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2936 
2937   if (!gst_byte_reader_get_uint8 (&br, &version)) {
2938     GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2939     return;
2940   }
2941 
2942   if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2943     GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2944     return;
2945   }
2946 
2947   if ((flags & 0x000001)) {
2948     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2949             &br))
2950       return;
2951   } else if ((flags & 0x000002)) {
2952     uses_sub_sample_encryption = TRUE;
2953   }
2954 
2955   if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2956           &iv_size)) {
2957     GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2958     return;
2959   }
2960 
2961   if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2962     GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2963     return;
2964   }
2965 
2966   ss_info->crypto_info =
2967       g_ptr_array_new_full (sample_count,
2968       (GDestroyNotify) qtdemux_gst_structure_free);
2969 
2970   for (i = 0; i < sample_count; ++i) {
2971     GstStructure *properties;
2972     guint8 *data;
2973     GstBuffer *buf;
2974 
2975     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2976     if (properties == NULL) {
2977       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2978       qtdemux->cenc_aux_sample_count = i;
2979       return;
2980     }
2981 
2982     if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2983       GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2984       gst_structure_free (properties);
2985       qtdemux->cenc_aux_sample_count = i;
2986       return;
2987     }
2988     buf = gst_buffer_new_wrapped (data, iv_size);
2989     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2990     gst_buffer_unref (buf);
2991 
2992     if (uses_sub_sample_encryption) {
2993       guint16 n_subsamples;
2994       const GValue *kid_buf_value;
2995 
2996       if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2997           || n_subsamples == 0) {
2998         GST_ERROR_OBJECT (qtdemux,
2999             "failed to get subsample count for sample %u", i);
3000         gst_structure_free (properties);
3001         qtdemux->cenc_aux_sample_count = i;
3002         return;
3003       }
3004       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3005       if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
3006         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3007             i);
3008         gst_structure_free (properties);
3009         qtdemux->cenc_aux_sample_count = i;
3010         return;
3011       }
3012       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3013 
3014       kid_buf_value =
3015           gst_structure_get_value (ss_info->default_properties, "kid");
3016 
3017       gst_structure_set (properties,
3018           "subsample_count", G_TYPE_UINT, n_subsamples,
3019           "subsamples", GST_TYPE_BUFFER, buf, NULL);
3020       gst_structure_set_value (properties, "kid", kid_buf_value);
3021       gst_buffer_unref (buf);
3022     } else {
3023       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3024     }
3025 
3026     g_ptr_array_add (ss_info->crypto_info, properties);
3027   }
3028 
3029   qtdemux->cenc_aux_sample_count = sample_count;
3030 }
3031 
3032 static void
qtdemux_parse_uuid(GstQTDemux * qtdemux,const guint8 * buffer,gint length)3033 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3034 {
3035   static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
3036     0x97, 0xA9, 0x42, 0xE8,
3037     0x9C, 0x71, 0x99, 0x94,
3038     0x91, 0xE3, 0xAF, 0xAC
3039   };
3040   static const guint8 playready_uuid[] = {
3041     0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
3042     0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
3043   };
3044 
3045   static const guint8 piff_sample_encryption_uuid[] = {
3046     0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
3047     0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
3048   };
3049 
3050   guint offset;
3051 
3052   /* counts as header data */
3053   qtdemux->header_size += length;
3054 
3055   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3056 
3057   if (length <= offset + 16) {
3058     GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
3059     return;
3060   }
3061 
3062   if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3063     GstBuffer *buf;
3064     GstTagList *taglist;
3065 
3066     buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3067         length - offset - 16, NULL);
3068     taglist = gst_tag_list_from_xmp_buffer (buf);
3069     gst_buffer_unref (buf);
3070 
3071     /* make sure we have a usable taglist */
3072     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3073 
3074     qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3075 
3076   } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3077     int len;
3078     const gunichar2 *s_utf16;
3079     char *contents;
3080 
3081     len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3082     s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3083     contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3084     GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3085 
3086     g_free (contents);
3087 
3088     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3089         (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3090         (NULL));
3091   } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3092     qtdemux_parse_piff (qtdemux, buffer, length, offset);
3093   } else {
3094     GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3095         GST_READ_UINT32_LE (buffer + offset),
3096         GST_READ_UINT32_LE (buffer + offset + 4),
3097         GST_READ_UINT32_LE (buffer + offset + 8),
3098         GST_READ_UINT32_LE (buffer + offset + 12));
3099   }
3100 }
3101 
3102 static void
qtdemux_parse_sidx(GstQTDemux * qtdemux,const guint8 * buffer,gint length)3103 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3104 {
3105   GstSidxParser sidx_parser;
3106   GstIsoffParserResult res;
3107   guint consumed;
3108 
3109   gst_isoff_qt_sidx_parser_init (&sidx_parser);
3110 
3111   res =
3112       gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3113       &consumed);
3114   GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3115   if (res == GST_ISOFF_QT_PARSER_DONE) {
3116     check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3117   }
3118   gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3119 }
3120 
3121 /* caller verifies at least 8 bytes in buf */
3122 static void
extract_initial_length_and_fourcc(const guint8 * data,guint size,guint64 * plength,guint32 * pfourcc)3123 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3124     guint64 * plength, guint32 * pfourcc)
3125 {
3126   guint64 length;
3127   guint32 fourcc;
3128 
3129   length = QT_UINT32 (data);
3130   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3131   fourcc = QT_FOURCC (data + 4);
3132   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3133 
3134   if (length == 0) {
3135     length = G_MAXUINT64;
3136   } else if (length == 1 && size >= 16) {
3137     /* this means we have an extended size, which is the 64 bit value of
3138      * the next 8 bytes */
3139     length = QT_UINT64 (data + 8);
3140     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3141   }
3142 
3143   if (plength)
3144     *plength = length;
3145   if (pfourcc)
3146     *pfourcc = fourcc;
3147 }
3148 
3149 static gboolean
qtdemux_parse_mehd(GstQTDemux * qtdemux,GstByteReader * br)3150 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3151 {
3152   guint32 version = 0;
3153   GstClockTime duration = 0;
3154 
3155   if (!gst_byte_reader_get_uint32_be (br, &version))
3156     goto failed;
3157 
3158   version >>= 24;
3159   if (version == 1) {
3160     if (!gst_byte_reader_get_uint64_be (br, &duration))
3161       goto failed;
3162   } else {
3163     guint32 dur = 0;
3164 
3165     if (!gst_byte_reader_get_uint32_be (br, &dur))
3166       goto failed;
3167     duration = dur;
3168   }
3169 
3170   GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3171   qtdemux->duration = duration;
3172 
3173   return TRUE;
3174 
3175 failed:
3176   {
3177     GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3178     return FALSE;
3179   }
3180 }
3181 
3182 static gboolean
qtdemux_parse_trex(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 * ds_duration,guint32 * ds_size,guint32 * ds_flags)3183 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3184     guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3185 {
3186   if (!stream->parsed_trex && qtdemux->moov_node) {
3187     GNode *mvex, *trex;
3188     GstByteReader trex_data;
3189 
3190     mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3191     if (mvex) {
3192       trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3193           &trex_data);
3194       while (trex) {
3195         guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3196 
3197         /* skip version/flags */
3198         if (!gst_byte_reader_skip (&trex_data, 4))
3199           goto next;
3200         if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3201           goto next;
3202         if (id != stream->track_id)
3203           goto next;
3204         if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3205           goto next;
3206         if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3207           goto next;
3208         if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3209           goto next;
3210         if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3211           goto next;
3212 
3213         GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3214             "duration %d,  size %d, flags 0x%x", stream->track_id,
3215             dur, size, flags);
3216 
3217         stream->parsed_trex = TRUE;
3218         stream->def_sample_description_index = sdi;
3219         stream->def_sample_duration = dur;
3220         stream->def_sample_size = size;
3221         stream->def_sample_flags = flags;
3222 
3223       next:
3224         /* iterate all siblings */
3225         trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3226             &trex_data);
3227       }
3228     }
3229   }
3230 
3231   *ds_duration = stream->def_sample_duration;
3232   *ds_size = stream->def_sample_size;
3233   *ds_flags = stream->def_sample_flags;
3234 
3235   /* even then, above values are better than random ... */
3236   if (G_UNLIKELY (!stream->parsed_trex)) {
3237     GST_WARNING_OBJECT (qtdemux,
3238         "failed to find fragment defaults for stream %d", stream->track_id);
3239     return FALSE;
3240   }
3241 
3242   return TRUE;
3243 }
3244 
3245 /* This method should be called whenever a more accurate duration might
3246  * have been found. It will update all relevant variables if/where needed
3247  */
3248 static void
check_update_duration(GstQTDemux * qtdemux,GstClockTime duration)3249 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3250 {
3251   guint i;
3252   guint64 movdur;
3253   GstClockTime prevdur;
3254 
3255   movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3256 
3257   if (movdur > qtdemux->duration) {
3258     prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3259     GST_DEBUG_OBJECT (qtdemux,
3260         "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3261         GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3262     qtdemux->duration = movdur;
3263     GST_DEBUG_OBJECT (qtdemux,
3264         "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3265         GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3266         GST_TIME_ARGS (qtdemux->segment.stop));
3267     if (qtdemux->segment.duration == prevdur) {
3268       /* If the current segment has duration/stop identical to previous duration
3269        * update them also (because they were set at that point in time with
3270        * the wrong duration */
3271       /* We convert the value *from* the timescale version to avoid rounding errors */
3272       GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3273       GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3274       qtdemux->segment.duration = fixeddur;
3275       qtdemux->segment.stop = fixeddur;
3276     }
3277   }
3278 
3279   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3280     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3281 
3282     movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3283     if (movdur > stream->duration) {
3284       GST_DEBUG_OBJECT (qtdemux,
3285           "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3286           GST_TIME_ARGS (duration));
3287       stream->duration = movdur;
3288       /* internal duration tracking state has been updated above, so */
3289       /* preserve an open-ended dummy segment rather than repeatedly updating
3290        * it and spamming downstream accordingly with segment events */
3291       if (stream->dummy_segment &&
3292           GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3293         /* Update all dummy values to new duration */
3294         stream->segments[0].stop_time = duration;
3295         stream->segments[0].duration = duration;
3296         stream->segments[0].media_stop = duration;
3297 
3298         /* let downstream know we possibly have a new stop time */
3299         if (stream->segment_index != -1) {
3300           GstClockTime pos;
3301 
3302           if (qtdemux->segment.rate >= 0) {
3303             pos = stream->segment.start;
3304           } else {
3305             pos = stream->segment.stop;
3306           }
3307 
3308           gst_qtdemux_stream_update_segment (qtdemux, stream,
3309               stream->segment_index, pos, NULL, NULL);
3310         }
3311       }
3312     }
3313   }
3314 }
3315 
3316 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)3317 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3318     QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3319     guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3320     gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3321     gboolean has_tfdt)
3322 {
3323   GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3324   guint64 timestamp;
3325   gint32 data_offset = 0;
3326   guint32 flags = 0, first_flags = 0, samples_count = 0;
3327   gint i;
3328   guint8 *data;
3329   guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3330   QtDemuxSample *sample;
3331   gboolean ismv = FALSE;
3332   gint64 initial_offset;
3333 
3334   GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3335       "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3336       "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3337       d_sample_size, d_sample_flags, *base_offset, decode_ts);
3338 
3339   if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3340     GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3341     return TRUE;
3342   }
3343 
3344   /* presence of stss or not can't really tell us much,
3345    * and flags and so on tend to be marginally reliable in these files */
3346   if (stream->subtype == FOURCC_soun) {
3347     GST_DEBUG_OBJECT (qtdemux,
3348         "sound track in fragmented file; marking all keyframes");
3349     stream->all_keyframe = TRUE;
3350   }
3351 
3352   if (!gst_byte_reader_skip (trun, 1) ||
3353       !gst_byte_reader_get_uint24_be (trun, &flags))
3354     goto fail;
3355 
3356   if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3357     goto fail;
3358 
3359   if (flags & TR_DATA_OFFSET) {
3360     /* note this is really signed */
3361     if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3362       goto fail;
3363     GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3364     /* default base offset = first byte of moof */
3365     if (*base_offset == -1) {
3366       GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3367       *base_offset = moof_offset;
3368     }
3369     *running_offset = *base_offset + data_offset;
3370   } else {
3371     /* if no offset at all, that would mean data starts at moof start,
3372      * which is a bit wrong and is ismv crappy way, so compensate
3373      * assuming data is in mdat following moof */
3374     if (*base_offset == -1) {
3375       *base_offset = moof_offset + moof_length + 8;
3376       GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3377       ismv = TRUE;
3378     }
3379     if (*running_offset == -1)
3380       *running_offset = *base_offset;
3381   }
3382 
3383   GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3384       *running_offset);
3385   GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3386       data_offset, flags, samples_count);
3387 
3388   if (flags & TR_FIRST_SAMPLE_FLAGS) {
3389     if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3390       GST_DEBUG_OBJECT (qtdemux,
3391           "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3392       flags ^= TR_FIRST_SAMPLE_FLAGS;
3393     } else {
3394       if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3395         goto fail;
3396       GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3397     }
3398   }
3399 
3400   /* FIXME ? spec says other bits should also be checked to determine
3401    * entry size (and prefix size for that matter) */
3402   entry_size = 0;
3403   dur_offset = size_offset = 0;
3404   if (flags & TR_SAMPLE_DURATION) {
3405     GST_LOG_OBJECT (qtdemux, "entry duration present");
3406     dur_offset = entry_size;
3407     entry_size += 4;
3408   }
3409   if (flags & TR_SAMPLE_SIZE) {
3410     GST_LOG_OBJECT (qtdemux, "entry size present");
3411     size_offset = entry_size;
3412     entry_size += 4;
3413   }
3414   if (flags & TR_SAMPLE_FLAGS) {
3415     GST_LOG_OBJECT (qtdemux, "entry flags present");
3416     flags_offset = entry_size;
3417     entry_size += 4;
3418   }
3419   if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3420     GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3421     ct_offset = entry_size;
3422     entry_size += 4;
3423   }
3424 
3425   if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3426     goto fail;
3427   data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3428 
3429   if (stream->n_samples + samples_count >=
3430       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3431     goto index_too_big;
3432 
3433   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3434       stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3435       (stream->n_samples + samples_count) *
3436       sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3437 
3438   /* create a new array of samples if it's the first sample parsed */
3439   if (stream->n_samples == 0) {
3440     g_assert (stream->samples == NULL);
3441     stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3442     /* or try to reallocate it with space enough to insert the new samples */
3443   } else
3444     stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3445         stream->n_samples + samples_count);
3446   if (stream->samples == NULL)
3447     goto out_of_memory;
3448 
3449   if (qtdemux->fragment_start != -1) {
3450     timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3451     qtdemux->fragment_start = -1;
3452   } else {
3453     if (stream->n_samples == 0) {
3454       if (decode_ts > 0) {
3455         timestamp = decode_ts;
3456       } else if (stream->pending_seek != NULL) {
3457         /* if we don't have a timestamp from a tfdt box, we'll use the one
3458          * from the mfra seek table */
3459         GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3460             GST_TIME_ARGS (stream->pending_seek->ts));
3461 
3462         /* FIXME: this is not fully correct, the timestamp refers to the random
3463          * access sample refered to in the tfra entry, which may not necessarily
3464          * be the first sample in the tfrag/trun (but hopefully/usually is) */
3465         timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3466       } else {
3467         timestamp = 0;
3468       }
3469 
3470       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3471       GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3472           GST_TIME_ARGS (gst_ts));
3473     } else {
3474       /* subsequent fragments extend stream */
3475       timestamp =
3476           stream->samples[stream->n_samples - 1].timestamp +
3477           stream->samples[stream->n_samples - 1].duration;
3478 
3479       /* If this is a GST_FORMAT_BYTES stream and there's a significant
3480        * difference (1 sec.) between decode_ts and timestamp, prefer the
3481        * former */
3482       if (has_tfdt && !qtdemux->upstream_format_is_time
3483           && ABSDIFF (decode_ts, timestamp) >
3484           MAX (stream->duration_last_moof / 2,
3485               GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3486         GST_INFO_OBJECT (qtdemux,
3487             "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3488             ") are significantly different (more than %" GST_TIME_FORMAT
3489             "), using decode_ts",
3490             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3491             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3492             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3493                     MAX (stream->duration_last_moof / 2,
3494                         GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3495         timestamp = decode_ts;
3496       }
3497 
3498       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3499       GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3500           " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3501     }
3502   }
3503 
3504   initial_offset = *running_offset;
3505 
3506   sample = stream->samples + stream->n_samples;
3507   for (i = 0; i < samples_count; i++) {
3508     guint32 dur, size, sflags, ct;
3509 
3510     /* first read sample data */
3511     if (flags & TR_SAMPLE_DURATION) {
3512       dur = QT_UINT32 (data + dur_offset);
3513     } else {
3514       dur = d_sample_duration;
3515     }
3516     if (flags & TR_SAMPLE_SIZE) {
3517       size = QT_UINT32 (data + size_offset);
3518     } else {
3519       size = d_sample_size;
3520     }
3521     if (flags & TR_FIRST_SAMPLE_FLAGS) {
3522       if (i == 0) {
3523         sflags = first_flags;
3524       } else {
3525         sflags = d_sample_flags;
3526       }
3527     } else if (flags & TR_SAMPLE_FLAGS) {
3528       sflags = QT_UINT32 (data + flags_offset);
3529     } else {
3530       sflags = d_sample_flags;
3531     }
3532     if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3533       ct = QT_UINT32 (data + ct_offset);
3534     } else {
3535       ct = 0;
3536     }
3537     data += entry_size;
3538 
3539     /* fill the sample information */
3540     sample->offset = *running_offset;
3541     sample->pts_offset = ct;
3542     sample->size = size;
3543     sample->timestamp = timestamp;
3544     sample->duration = dur;
3545     /* sample-is-difference-sample */
3546     /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3547      * now idea how it relates to bitfield other than massive LE/BE confusion */
3548     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3549     *running_offset += size;
3550     timestamp += dur;
3551     stream->duration_moof += dur;
3552     sample++;
3553   }
3554 
3555   /* Update total duration if needed */
3556   check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3557 
3558   /* Pre-emptively figure out size of mdat based on trun information.
3559    * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3560    * size, else we will still be able to use this when dealing with gap'ed
3561    * input */
3562   qtdemux->mdatleft = *running_offset - initial_offset;
3563   qtdemux->mdatoffset = initial_offset;
3564   qtdemux->mdatsize = qtdemux->mdatleft;
3565 
3566   stream->n_samples += samples_count;
3567   stream->n_samples_moof += samples_count;
3568 
3569   if (stream->pending_seek != NULL)
3570     stream->pending_seek = NULL;
3571 
3572   return TRUE;
3573 
3574 fail:
3575   {
3576     GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3577     return FALSE;
3578   }
3579 out_of_memory:
3580   {
3581     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3582         stream->n_samples);
3583     return FALSE;
3584   }
3585 index_too_big:
3586   {
3587     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3588         "be larger than %uMB (broken file?)", stream->n_samples,
3589         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3590     return FALSE;
3591   }
3592 }
3593 
3594 /* find stream with @id */
3595 static inline QtDemuxStream *
qtdemux_find_stream(GstQTDemux * qtdemux,guint32 id)3596 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3597 {
3598   QtDemuxStream *stream;
3599   gint i;
3600 
3601   /* check */
3602   if (G_UNLIKELY (!id)) {
3603     GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3604     return NULL;
3605   }
3606 
3607   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3608     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3609     if (stream->track_id == id)
3610       return stream;
3611   }
3612   if (qtdemux->mss_mode) {
3613     /* mss should have only 1 stream anyway */
3614     return QTDEMUX_NTH_STREAM (qtdemux, 0);
3615   }
3616 
3617   return NULL;
3618 }
3619 
3620 static gboolean
qtdemux_parse_mfhd(GstQTDemux * qtdemux,GstByteReader * mfhd,guint32 * fragment_number)3621 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3622     guint32 * fragment_number)
3623 {
3624   if (!gst_byte_reader_skip (mfhd, 4))
3625     goto fail;
3626   if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3627     goto fail;
3628   return TRUE;
3629 fail:
3630   {
3631     GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3632     return FALSE;
3633   }
3634 }
3635 
3636 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)3637 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3638     QtDemuxStream ** stream, guint32 * default_sample_duration,
3639     guint32 * default_sample_size, guint32 * default_sample_flags,
3640     gint64 * base_offset)
3641 {
3642   guint32 flags = 0;
3643   guint32 track_id = 0;
3644 
3645   if (!gst_byte_reader_skip (tfhd, 1) ||
3646       !gst_byte_reader_get_uint24_be (tfhd, &flags))
3647     goto invalid_track;
3648 
3649   if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3650     goto invalid_track;
3651 
3652   *stream = qtdemux_find_stream (qtdemux, track_id);
3653   if (G_UNLIKELY (!*stream))
3654     goto unknown_stream;
3655 
3656   if (flags & TF_DEFAULT_BASE_IS_MOOF)
3657     *base_offset = qtdemux->moof_offset;
3658 
3659   if (flags & TF_BASE_DATA_OFFSET)
3660     if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3661       goto invalid_track;
3662 
3663   /* obtain stream defaults */
3664   qtdemux_parse_trex (qtdemux, *stream,
3665       default_sample_duration, default_sample_size, default_sample_flags);
3666 
3667   (*stream)->stsd_sample_description_id =
3668       (*stream)->def_sample_description_index - 1;
3669 
3670   if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3671     guint32 sample_description_index;
3672     if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3673       goto invalid_track;
3674     (*stream)->stsd_sample_description_id = sample_description_index - 1;
3675   }
3676 
3677   if (qtdemux->mss_mode) {
3678     /* mss has no stsd entry */
3679     (*stream)->stsd_sample_description_id = 0;
3680   }
3681 
3682   if (flags & TF_DEFAULT_SAMPLE_DURATION)
3683     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3684       goto invalid_track;
3685 
3686   if (flags & TF_DEFAULT_SAMPLE_SIZE)
3687     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3688       goto invalid_track;
3689 
3690   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3691     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3692       goto invalid_track;
3693 
3694   return TRUE;
3695 
3696 invalid_track:
3697   {
3698     GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3699     return FALSE;
3700   }
3701 unknown_stream:
3702   {
3703     GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3704     return TRUE;
3705   }
3706 }
3707 
3708 static gboolean
qtdemux_parse_tfdt(GstQTDemux * qtdemux,GstByteReader * br,guint64 * decode_time)3709 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3710     guint64 * decode_time)
3711 {
3712   guint32 version = 0;
3713 
3714   if (!gst_byte_reader_get_uint32_be (br, &version))
3715     return FALSE;
3716 
3717   version >>= 24;
3718   if (version == 1) {
3719     if (!gst_byte_reader_get_uint64_be (br, decode_time))
3720       goto failed;
3721   } else {
3722     guint32 dec_time = 0;
3723     if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3724       goto failed;
3725     *decode_time = dec_time;
3726   }
3727 
3728   GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3729       *decode_time);
3730 
3731   return TRUE;
3732 
3733 failed:
3734   {
3735     GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3736     return FALSE;
3737   }
3738 }
3739 
3740 /* Returns a pointer to a GstStructure containing the properties of
3741  * the stream sample identified by @sample_index. The caller must unref
3742  * the returned object after use. Returns NULL if unsuccessful. */
3743 static GstStructure *
qtdemux_get_cenc_sample_properties(GstQTDemux * qtdemux,QtDemuxStream * stream,guint sample_index)3744 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3745     QtDemuxStream * stream, guint sample_index)
3746 {
3747   QtDemuxCencSampleSetInfo *info = NULL;
3748 
3749   g_return_val_if_fail (stream != NULL, NULL);
3750   g_return_val_if_fail (stream->protected, NULL);
3751   g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3752 
3753   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3754 
3755   /* Currently, cenc properties for groups of samples are not supported, so
3756    * simply return a copy of the default sample properties */
3757   return gst_structure_copy (info->default_properties);
3758 }
3759 
3760 /* Parses the sizes of sample auxiliary information contained within a stream,
3761  * as given in a saiz box. Returns array of sample_count guint8 size values,
3762  * or NULL on failure */
3763 static guint8 *
qtdemux_parse_saiz(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint32 * sample_count)3764 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3765     GstByteReader * br, guint32 * sample_count)
3766 {
3767   guint32 flags = 0;
3768   guint8 *info_sizes;
3769   guint8 default_info_size;
3770 
3771   g_return_val_if_fail (qtdemux != NULL, NULL);
3772   g_return_val_if_fail (stream != NULL, NULL);
3773   g_return_val_if_fail (br != NULL, NULL);
3774   g_return_val_if_fail (sample_count != NULL, NULL);
3775 
3776   if (!gst_byte_reader_get_uint32_be (br, &flags))
3777     return NULL;
3778 
3779   if (flags & 0x1) {
3780     /* aux_info_type and aux_info_type_parameter are ignored */
3781     if (!gst_byte_reader_skip (br, 8))
3782       return NULL;
3783   }
3784 
3785   if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3786     return NULL;
3787   GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3788 
3789   if (!gst_byte_reader_get_uint32_be (br, sample_count))
3790     return NULL;
3791   GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3792 
3793 
3794   if (default_info_size == 0) {
3795     if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3796       return NULL;
3797     }
3798   } else {
3799     info_sizes = g_new (guint8, *sample_count);
3800     memset (info_sizes, default_info_size, *sample_count);
3801   }
3802 
3803   return info_sizes;
3804 }
3805 
3806 /* Parses the offset of sample auxiliary information contained within a stream,
3807  * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3808 static gboolean
qtdemux_parse_saio(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint32 * info_type,guint32 * info_type_parameter,guint64 * offset)3809 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3810     GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3811     guint64 * offset)
3812 {
3813   guint8 version = 0;
3814   guint32 flags = 0;
3815   guint32 aux_info_type = 0;
3816   guint32 aux_info_type_parameter = 0;
3817   guint32 entry_count;
3818   guint32 off_32;
3819   guint64 off_64;
3820   const guint8 *aux_info_type_data = NULL;
3821 
3822   g_return_val_if_fail (qtdemux != NULL, FALSE);
3823   g_return_val_if_fail (stream != NULL, FALSE);
3824   g_return_val_if_fail (br != NULL, FALSE);
3825   g_return_val_if_fail (offset != NULL, FALSE);
3826 
3827   if (!gst_byte_reader_get_uint8 (br, &version))
3828     return FALSE;
3829 
3830   if (!gst_byte_reader_get_uint24_be (br, &flags))
3831     return FALSE;
3832 
3833   if (flags & 0x1) {
3834 
3835     if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3836       return FALSE;
3837     aux_info_type = QT_FOURCC (aux_info_type_data);
3838 
3839     if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3840       return FALSE;
3841   } else if (stream->protected) {
3842     aux_info_type = stream->protection_scheme_type;
3843   } else {
3844     aux_info_type = CUR_STREAM (stream)->fourcc;
3845   }
3846 
3847   if (info_type)
3848     *info_type = aux_info_type;
3849   if (info_type_parameter)
3850     *info_type_parameter = aux_info_type_parameter;
3851 
3852   GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3853       "aux_info_type_parameter:  %#06x",
3854       GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3855 
3856   if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3857     return FALSE;
3858 
3859   if (entry_count != 1) {
3860     GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3861     return FALSE;
3862   }
3863 
3864   if (version == 0) {
3865     if (!gst_byte_reader_get_uint32_be (br, &off_32))
3866       return FALSE;
3867     *offset = (guint64) off_32;
3868   } else {
3869     if (!gst_byte_reader_get_uint64_be (br, &off_64))
3870       return FALSE;
3871     *offset = off_64;
3872   }
3873 
3874   GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3875   return TRUE;
3876 }
3877 
3878 static void
qtdemux_gst_structure_free(GstStructure * gststructure)3879 qtdemux_gst_structure_free (GstStructure * gststructure)
3880 {
3881   if (gststructure) {
3882     gst_structure_free (gststructure);
3883   }
3884 }
3885 
3886 /* Parses auxiliary information relating to samples protected using Common
3887  * Encryption (cenc); the format of this information is defined in
3888  * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3889 static gboolean
qtdemux_parse_cenc_aux_info(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint8 * info_sizes,guint32 sample_count)3890 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3891     GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3892 {
3893   QtDemuxCencSampleSetInfo *ss_info = NULL;
3894   guint8 size;
3895   gint i;
3896   GPtrArray *old_crypto_info = NULL;
3897   guint old_entries = 0;
3898 
3899   g_return_val_if_fail (qtdemux != NULL, FALSE);
3900   g_return_val_if_fail (stream != NULL, FALSE);
3901   g_return_val_if_fail (br != NULL, FALSE);
3902   g_return_val_if_fail (stream->protected, FALSE);
3903   g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3904 
3905   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3906 
3907   if (ss_info->crypto_info) {
3908     old_crypto_info = ss_info->crypto_info;
3909     /* Count number of non-null entries remaining at the tail end */
3910     for (i = old_crypto_info->len - 1; i >= 0; i--) {
3911       if (g_ptr_array_index (old_crypto_info, i) == NULL)
3912         break;
3913       old_entries++;
3914     }
3915   }
3916 
3917   ss_info->crypto_info =
3918       g_ptr_array_new_full (sample_count + old_entries,
3919       (GDestroyNotify) qtdemux_gst_structure_free);
3920 
3921   /* We preserve old entries because we parse the next moof in advance
3922    * of consuming all samples from the previous moof, and otherwise
3923    * we'd discard the corresponding crypto info for the samples
3924    * from the previous fragment. */
3925   if (old_entries) {
3926     GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3927         old_entries);
3928     for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3929       g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3930               i));
3931       g_ptr_array_index (old_crypto_info, i) = NULL;
3932     }
3933   }
3934 
3935   if (old_crypto_info) {
3936     /* Everything now belongs to the new array */
3937     g_ptr_array_free (old_crypto_info, TRUE);
3938   }
3939 
3940   for (i = 0; i < sample_count; ++i) {
3941     GstStructure *properties;
3942     guint16 n_subsamples = 0;
3943     guint8 *data;
3944     guint iv_size;
3945     GstBuffer *buf;
3946 
3947     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3948     if (properties == NULL) {
3949       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3950       return FALSE;
3951     }
3952     if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3953       GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3954       gst_structure_free (properties);
3955       return FALSE;
3956     }
3957     if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3958       GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3959       gst_structure_free (properties);
3960       return FALSE;
3961     }
3962     buf = gst_buffer_new_wrapped (data, iv_size);
3963     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3964     gst_buffer_unref (buf);
3965     size = info_sizes[i];
3966     if (size > iv_size) {
3967       if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3968           || !(n_subsamples > 0)) {
3969         gst_structure_free (properties);
3970         GST_ERROR_OBJECT (qtdemux,
3971             "failed to get subsample count for sample %u", i);
3972         return FALSE;
3973       }
3974       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3975       if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3976         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3977             i);
3978         gst_structure_free (properties);
3979         return FALSE;
3980       }
3981       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3982       if (!buf) {
3983         gst_structure_free (properties);
3984         return FALSE;
3985       }
3986       gst_structure_set (properties,
3987           "subsample_count", G_TYPE_UINT, n_subsamples,
3988           "subsamples", GST_TYPE_BUFFER, buf, NULL);
3989       gst_buffer_unref (buf);
3990     } else {
3991       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3992     }
3993     g_ptr_array_add (ss_info->crypto_info, properties);
3994   }
3995   return TRUE;
3996 }
3997 
3998 /* Converts a UUID in raw byte form to a string representation, as defined in
3999  * RFC 4122. The caller takes ownership of the returned string and is
4000  * responsible for freeing it after use. */
4001 static gchar *
qtdemux_uuid_bytes_to_string(gconstpointer uuid_bytes)4002 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4003 {
4004   const guint8 *uuid = (const guint8 *) uuid_bytes;
4005 
4006   return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4007       "%02x%02x-%02x%02x%02x%02x%02x%02x",
4008       uuid[0], uuid[1], uuid[2], uuid[3],
4009       uuid[4], uuid[5], uuid[6], uuid[7],
4010       uuid[8], uuid[9], uuid[10], uuid[11],
4011       uuid[12], uuid[13], uuid[14], uuid[15]);
4012 }
4013 
4014 /* Parses a Protection System Specific Header box (pssh), as defined in the
4015  * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4016  * information needed by a specific content protection system in order to
4017  * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4018  * otherwise. */
4019 static gboolean
qtdemux_parse_pssh(GstQTDemux * qtdemux,GNode * node)4020 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4021 {
4022   gchar *sysid_string;
4023   guint32 pssh_size = QT_UINT32 (node->data);
4024   GstBuffer *pssh = NULL;
4025   GstEvent *event = NULL;
4026   guint32 parent_box_type;
4027   gint i;
4028 
4029   if (G_UNLIKELY (pssh_size < 32U)) {
4030     GST_ERROR_OBJECT (qtdemux, "invalid box size");
4031     return FALSE;
4032   }
4033 
4034   sysid_string =
4035       qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4036 
4037   gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4038 
4039   pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
4040   GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4041       gst_buffer_get_size (pssh));
4042 
4043   parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4044 
4045   /* Push an event containing the pssh box onto the queues of all streams. */
4046   event = gst_event_new_protection (sysid_string, pssh,
4047       (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4048   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4049     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4050     GST_TRACE_OBJECT (qtdemux,
4051         "adding protection event for stream %s and system %s",
4052         stream->stream_id, sysid_string);
4053     g_queue_push_tail (&stream->protection_scheme_event_queue,
4054         gst_event_ref (event));
4055   }
4056   g_free (sysid_string);
4057   gst_event_unref (event);
4058   gst_buffer_unref (pssh);
4059   return TRUE;
4060 }
4061 
4062 static gboolean
qtdemux_parse_moof(GstQTDemux * qtdemux,const guint8 * buffer,guint length,guint64 moof_offset,QtDemuxStream * stream)4063 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4064     guint64 moof_offset, QtDemuxStream * stream)
4065 {
4066   GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4067   GNode *uuid_node;
4068   GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4069   GNode *saiz_node, *saio_node, *pssh_node;
4070   GstByteReader saiz_data, saio_data;
4071   guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4072   gint64 base_offset, running_offset;
4073   guint32 frag_num;
4074   GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4075 
4076   /* NOTE @stream ignored */
4077 
4078   moof_node = g_node_new ((guint8 *) buffer);
4079   qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4080   qtdemux_node_dump (qtdemux, moof_node);
4081 
4082   /* Get fragment number from mfhd and check it's valid */
4083   mfhd_node =
4084       qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4085   if (mfhd_node == NULL)
4086     goto missing_mfhd;
4087   if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4088     goto fail;
4089   GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4090 
4091   /* unknown base_offset to start with */
4092   base_offset = running_offset = -1;
4093   traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4094   while (traf_node) {
4095     guint64 decode_time = 0;
4096 
4097     /* Fragment Header node */
4098     tfhd_node =
4099         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4100         &tfhd_data);
4101     if (!tfhd_node)
4102       goto missing_tfhd;
4103     if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4104             &ds_size, &ds_flags, &base_offset))
4105       goto missing_tfhd;
4106 
4107     /* The following code assumes at most a single set of sample auxiliary
4108      * data in the fragment (consisting of a saiz box and a corresponding saio
4109      * box); in theory, however, there could be multiple sets of sample
4110      * auxiliary data in a fragment. */
4111     saiz_node =
4112         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4113         &saiz_data);
4114     if (saiz_node) {
4115       guint32 info_type = 0;
4116       guint64 offset = 0;
4117       guint32 info_type_parameter = 0;
4118 
4119       g_free (qtdemux->cenc_aux_info_sizes);
4120 
4121       qtdemux->cenc_aux_info_sizes =
4122           qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4123           &qtdemux->cenc_aux_sample_count);
4124       if (qtdemux->cenc_aux_info_sizes == NULL) {
4125         GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4126         goto fail;
4127       }
4128       saio_node =
4129           qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4130           &saio_data);
4131       if (!saio_node) {
4132         GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4133         g_free (qtdemux->cenc_aux_info_sizes);
4134         qtdemux->cenc_aux_info_sizes = NULL;
4135         goto fail;
4136       }
4137 
4138       if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4139                   &info_type, &info_type_parameter, &offset))) {
4140         GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4141         g_free (qtdemux->cenc_aux_info_sizes);
4142         qtdemux->cenc_aux_info_sizes = NULL;
4143         goto fail;
4144       }
4145       if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4146         offset += (guint64) (base_offset - qtdemux->moof_offset);
4147       if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4148         GstByteReader br;
4149         if (offset > length) {
4150           GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4151           qtdemux->cenc_aux_info_offset = offset;
4152         } else {
4153           gst_byte_reader_init (&br, buffer + offset, length - offset);
4154           if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4155                   qtdemux->cenc_aux_info_sizes,
4156                   qtdemux->cenc_aux_sample_count)) {
4157             GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4158             g_free (qtdemux->cenc_aux_info_sizes);
4159             qtdemux->cenc_aux_info_sizes = NULL;
4160             goto fail;
4161           }
4162         }
4163       }
4164     }
4165 
4166     tfdt_node =
4167         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4168         &tfdt_data);
4169     if (tfdt_node) {
4170       /* We'll use decode_time to interpolate timestamps
4171        * in case the input timestamps are missing */
4172       qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4173 
4174       GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4175           " (%" GST_TIME_FORMAT ")", decode_time,
4176           GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4177                   decode_time) : GST_CLOCK_TIME_NONE));
4178 
4179       /* Discard the fragment buffer timestamp info to avoid using it.
4180        * Rely on tfdt instead as it is more accurate than the timestamp
4181        * that is fetched from a manifest/playlist and is usually
4182        * less accurate. */
4183       qtdemux->fragment_start = -1;
4184     }
4185 
4186     if (G_UNLIKELY (!stream)) {
4187       /* we lost track of offset, we'll need to regain it,
4188        * but can delay complaining until later or avoid doing so altogether */
4189       base_offset = -2;
4190       goto next;
4191     }
4192     if (G_UNLIKELY (base_offset < -1))
4193       goto lost_offset;
4194 
4195     min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4196 
4197     if (!qtdemux->pullbased) {
4198       /* Sample tables can grow enough to be problematic if the system memory
4199        * is very low (e.g. embedded devices) and the videos very long
4200        * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4201        * Fortunately, we can easily discard them for each new fragment when
4202        * we know qtdemux will not receive seeks outside of the current fragment.
4203        * adaptivedemux honors this assumption.
4204        * This optimization is also useful for applications that use qtdemux as
4205        * a push-based simple demuxer, like Media Source Extensions. */
4206       gst_qtdemux_stream_flush_samples_data (stream);
4207     }
4208 
4209     /* initialise moof sample data */
4210     stream->n_samples_moof = 0;
4211     stream->duration_last_moof = stream->duration_moof;
4212     stream->duration_moof = 0;
4213 
4214     /* Track Run node */
4215     trun_node =
4216         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4217         &trun_data);
4218     while (trun_node) {
4219       qtdemux_parse_trun (qtdemux, &trun_data, stream,
4220           ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4221           &running_offset, decode_time, (tfdt_node != NULL));
4222       /* iterate all siblings */
4223       trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4224           &trun_data);
4225     }
4226 
4227     uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4228     if (uuid_node) {
4229       guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4230       guint32 box_length = QT_UINT32 (uuid_buffer);
4231 
4232       qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4233     }
4234 
4235     /* if no new base_offset provided for next traf,
4236      * base is end of current traf */
4237     base_offset = running_offset;
4238     running_offset = -1;
4239 
4240     if (stream->n_samples_moof && stream->duration_moof)
4241       stream->new_caps = TRUE;
4242 
4243   next:
4244     /* iterate all siblings */
4245     traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4246   }
4247 
4248   /* parse any protection system info */
4249   pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4250   while (pssh_node) {
4251     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4252     qtdemux_parse_pssh (qtdemux, pssh_node);
4253     pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4254   }
4255 
4256   if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4257       && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4258       && min_dts != 0) {
4259     /* Unless the user has explictly requested another seek, perform an
4260      * internal seek to the time specified in the tfdt.
4261      *
4262      * This way if the user opens a file where the first tfdt is 1 hour
4263      * into the presentation, they will not have to wait 1 hour for run
4264      * time to catch up and actual playback to start. */
4265     gint i;
4266 
4267     GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4268         "performing an internal seek to %" GST_TIME_FORMAT,
4269         GST_TIME_ARGS (min_dts));
4270 
4271     qtdemux->segment.start = min_dts;
4272     qtdemux->segment.time = qtdemux->segment.position = min_dts;
4273 
4274     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4275       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4276       stream->time_position = min_dts;
4277     }
4278 
4279     /* Before this code was run a segment was already sent when the moov was
4280      * parsed... which is OK -- some apps (mostly tests) expect a segment to
4281      * be emitted after a moov, and we can emit a second segment anyway for
4282      * special cases like this. */
4283     qtdemux->need_segment = TRUE;
4284   }
4285 
4286   qtdemux->first_moof_already_parsed = TRUE;
4287 
4288   g_node_destroy (moof_node);
4289   return TRUE;
4290 
4291 missing_tfhd:
4292   {
4293     GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4294     goto fail;
4295   }
4296 missing_mfhd:
4297   {
4298     GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4299     goto fail;
4300   }
4301 lost_offset:
4302   {
4303     GST_DEBUG_OBJECT (qtdemux, "lost offset");
4304     goto fail;
4305   }
4306 fail:
4307   {
4308     g_node_destroy (moof_node);
4309     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4310         (_("This file is corrupt and cannot be played.")), (NULL));
4311     return FALSE;
4312   }
4313 }
4314 
4315 #if 0
4316 /* might be used if some day we actually use mfra & co
4317  * for random access to fragments,
4318  * but that will require quite some modifications and much less relying
4319  * on a sample array */
4320 #endif
4321 
4322 static gboolean
qtdemux_parse_tfra(GstQTDemux * qtdemux,GNode * tfra_node)4323 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4324 {
4325   QtDemuxStream *stream;
4326   guint32 ver_flags, track_id, len, num_entries, i;
4327   guint value_size, traf_size, trun_size, sample_size;
4328   guint64 time = 0, moof_offset = 0;
4329 #if 0
4330   GstBuffer *buf = NULL;
4331   GstFlowReturn ret;
4332 #endif
4333   GstByteReader tfra;
4334 
4335   gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4336 
4337   if (!gst_byte_reader_skip (&tfra, 8))
4338     return FALSE;
4339 
4340   if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4341     return FALSE;
4342 
4343   if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4344       || !gst_byte_reader_get_uint32_be (&tfra, &len)
4345       || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4346     return FALSE;
4347 
4348   GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4349 
4350   stream = qtdemux_find_stream (qtdemux, track_id);
4351   if (stream == NULL)
4352     goto unknown_trackid;
4353 
4354   value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4355   sample_size = (len & 3) + 1;
4356   trun_size = ((len & 12) >> 2) + 1;
4357   traf_size = ((len & 48) >> 4) + 1;
4358 
4359   GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4360       "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4361 
4362   if (num_entries == 0)
4363     goto no_samples;
4364 
4365   if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4366           value_size + value_size + traf_size + trun_size + sample_size))
4367     goto corrupt_file;
4368 
4369   g_free (stream->ra_entries);
4370   stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4371   stream->n_ra_entries = num_entries;
4372 
4373   for (i = 0; i < num_entries; i++) {
4374     qt_atom_parser_get_offset (&tfra, value_size, &time);
4375     qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4376     qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4377     qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4378     qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4379 
4380     time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4381 
4382     GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4383         " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4384 
4385     stream->ra_entries[i].ts = time;
4386     stream->ra_entries[i].moof_offset = moof_offset;
4387 
4388     /* don't want to go through the entire file and read all moofs at startup */
4389 #if 0
4390     ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4391     if (ret != GST_FLOW_OK)
4392       goto corrupt_file;
4393     qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4394         moof_offset, stream);
4395     gst_buffer_unref (buf);
4396 #endif
4397   }
4398 
4399   check_update_duration (qtdemux, time);
4400 
4401   return TRUE;
4402 
4403 /* ERRORS */
4404 unknown_trackid:
4405   {
4406     GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4407     return FALSE;
4408   }
4409 corrupt_file:
4410   {
4411     GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4412     return FALSE;
4413   }
4414 no_samples:
4415   {
4416     GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4417     return FALSE;
4418   }
4419 }
4420 
4421 static gboolean
qtdemux_pull_mfro_mfra(GstQTDemux * qtdemux)4422 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4423 {
4424   GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4425   GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4426   GstBuffer *mfro = NULL, *mfra = NULL;
4427   GstFlowReturn flow;
4428   gboolean ret = FALSE;
4429   GNode *mfra_node, *tfra_node;
4430   guint64 mfra_offset = 0;
4431   guint32 fourcc, mfra_size;
4432   gint64 len;
4433 
4434   /* query upstream size in bytes */
4435   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4436     goto size_query_failed;
4437 
4438   /* mfro box should be at the very end of the file */
4439   flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4440   if (flow != GST_FLOW_OK)
4441     goto exit;
4442 
4443   gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4444 
4445   fourcc = QT_FOURCC (mfro_map.data + 4);
4446   if (fourcc != FOURCC_mfro)
4447     goto exit;
4448 
4449   GST_INFO_OBJECT (qtdemux, "Found mfro box");
4450   if (mfro_map.size < 16)
4451     goto invalid_mfro_size;
4452 
4453   mfra_size = QT_UINT32 (mfro_map.data + 12);
4454   if (mfra_size >= len)
4455     goto invalid_mfra_size;
4456 
4457   mfra_offset = len - mfra_size;
4458 
4459   GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4460       mfra_offset, mfra_size);
4461 
4462   /* now get and parse mfra box */
4463   flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4464   if (flow != GST_FLOW_OK)
4465     goto broken_file;
4466 
4467   gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4468 
4469   mfra_node = g_node_new ((guint8 *) mfra_map.data);
4470   qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4471 
4472   tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4473 
4474   while (tfra_node) {
4475     qtdemux_parse_tfra (qtdemux, tfra_node);
4476     /* iterate all siblings */
4477     tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4478   }
4479   g_node_destroy (mfra_node);
4480 
4481   GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4482   ret = TRUE;
4483 
4484 exit:
4485 
4486   if (mfro) {
4487     if (mfro_map.memory != NULL)
4488       gst_buffer_unmap (mfro, &mfro_map);
4489     gst_buffer_unref (mfro);
4490   }
4491   if (mfra) {
4492     if (mfra_map.memory != NULL)
4493       gst_buffer_unmap (mfra, &mfra_map);
4494     gst_buffer_unref (mfra);
4495   }
4496   return ret;
4497 
4498 /* ERRORS */
4499 size_query_failed:
4500   {
4501     GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4502     goto exit;
4503   }
4504 invalid_mfro_size:
4505   {
4506     GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4507     goto exit;
4508   }
4509 invalid_mfra_size:
4510   {
4511     GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4512     goto exit;
4513   }
4514 broken_file:
4515   {
4516     GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4517     goto exit;
4518   }
4519 }
4520 
4521 static guint64
add_offset(guint64 offset,guint64 advance)4522 add_offset (guint64 offset, guint64 advance)
4523 {
4524   /* Avoid 64-bit overflow by clamping */
4525   if (offset > G_MAXUINT64 - advance)
4526     return G_MAXUINT64;
4527   return offset + advance;
4528 }
4529 
4530 static GstFlowReturn
gst_qtdemux_loop_state_header(GstQTDemux * qtdemux)4531 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4532 {
4533   guint64 length = 0;
4534   guint32 fourcc = 0;
4535   GstBuffer *buf = NULL;
4536   GstFlowReturn ret = GST_FLOW_OK;
4537   guint64 cur_offset = qtdemux->offset;
4538   GstMapInfo map;
4539 
4540   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4541   if (G_UNLIKELY (ret != GST_FLOW_OK))
4542     goto beach;
4543   gst_buffer_map (buf, &map, GST_MAP_READ);
4544   if (G_LIKELY (map.size >= 8))
4545     extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4546   gst_buffer_unmap (buf, &map);
4547   gst_buffer_unref (buf);
4548 
4549   /* maybe we already got most we needed, so only consider this eof */
4550   if (G_UNLIKELY (length == 0)) {
4551     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4552         (_("Invalid atom size.")),
4553         ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4554             GST_FOURCC_ARGS (fourcc)));
4555     ret = GST_FLOW_EOS;
4556     goto beach;
4557   }
4558 
4559   switch (fourcc) {
4560     case FOURCC_moof:
4561       /* record for later parsing when needed */
4562       if (!qtdemux->moof_offset) {
4563         qtdemux->moof_offset = qtdemux->offset;
4564       }
4565       if (qtdemux_pull_mfro_mfra (qtdemux)) {
4566         /* FIXME */
4567       } else {
4568         qtdemux->offset += length;      /* skip moof and keep going */
4569       }
4570       if (qtdemux->got_moov) {
4571         GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4572         ret = GST_FLOW_EOS;
4573         goto beach;
4574       }
4575       break;
4576     case FOURCC_mdat:
4577     case FOURCC_free:
4578     case FOURCC_skip:
4579     case FOURCC_wide:
4580     case FOURCC_PICT:
4581     case FOURCC_pnot:
4582     {
4583       GST_LOG_OBJECT (qtdemux,
4584           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4585           GST_FOURCC_ARGS (fourcc), cur_offset);
4586       qtdemux->offset = add_offset (qtdemux->offset, length);
4587       break;
4588     }
4589     case FOURCC_moov:
4590     {
4591       GstBuffer *moov = NULL;
4592 
4593       if (qtdemux->got_moov) {
4594         GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4595         qtdemux->offset = add_offset (qtdemux->offset, length);
4596         goto beach;
4597       }
4598 
4599       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4600       if (ret != GST_FLOW_OK)
4601         goto beach;
4602       gst_buffer_map (moov, &map, GST_MAP_READ);
4603 
4604       if (length != map.size) {
4605         /* Some files have a 'moov' atom at the end of the file which contains
4606          * a terminal 'free' atom where the body of the atom is missing.
4607          * Check for, and permit, this special case.
4608          */
4609         if (map.size >= 8) {
4610           guint8 *final_data = map.data + (map.size - 8);
4611           guint32 final_length = QT_UINT32 (final_data);
4612           guint32 final_fourcc = QT_FOURCC (final_data + 4);
4613 
4614           if (final_fourcc == FOURCC_free
4615               && map.size + final_length - 8 == length) {
4616             /* Ok, we've found that special case. Allocate a new buffer with
4617              * that free atom actually present. */
4618             GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4619             gst_buffer_fill (newmoov, 0, map.data, map.size);
4620             gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4621             gst_buffer_unmap (moov, &map);
4622             gst_buffer_unref (moov);
4623             moov = newmoov;
4624             gst_buffer_map (moov, &map, GST_MAP_READ);
4625           }
4626         }
4627       }
4628 
4629       if (length != map.size) {
4630         GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4631             (_("This file is incomplete and cannot be played.")),
4632             ("We got less than expected (received %" G_GSIZE_FORMAT
4633                 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4634                 (guint) length, cur_offset));
4635         gst_buffer_unmap (moov, &map);
4636         gst_buffer_unref (moov);
4637         ret = GST_FLOW_ERROR;
4638         goto beach;
4639       }
4640       qtdemux->offset += length;
4641 
4642       qtdemux_parse_moov (qtdemux, map.data, length);
4643       qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4644 
4645       qtdemux_parse_tree (qtdemux);
4646       if (qtdemux->moov_node_compressed) {
4647         g_node_destroy (qtdemux->moov_node_compressed);
4648         g_free (qtdemux->moov_node->data);
4649       }
4650       qtdemux->moov_node_compressed = NULL;
4651       g_node_destroy (qtdemux->moov_node);
4652       qtdemux->moov_node = NULL;
4653       gst_buffer_unmap (moov, &map);
4654       gst_buffer_unref (moov);
4655       qtdemux->got_moov = TRUE;
4656 
4657       break;
4658     }
4659     case FOURCC_ftyp:
4660     {
4661       GstBuffer *ftyp = NULL;
4662 
4663       /* extract major brand; might come in handy for ISO vs QT issues */
4664       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4665       if (ret != GST_FLOW_OK)
4666         goto beach;
4667       qtdemux->offset += length;
4668       gst_buffer_map (ftyp, &map, GST_MAP_READ);
4669       qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4670       gst_buffer_unmap (ftyp, &map);
4671       gst_buffer_unref (ftyp);
4672       break;
4673     }
4674     case FOURCC_uuid:
4675     {
4676       GstBuffer *uuid = NULL;
4677 
4678       /* uuid are extension atoms */
4679       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4680       if (ret != GST_FLOW_OK)
4681         goto beach;
4682       qtdemux->offset += length;
4683       gst_buffer_map (uuid, &map, GST_MAP_READ);
4684       qtdemux_parse_uuid (qtdemux, map.data, map.size);
4685       gst_buffer_unmap (uuid, &map);
4686       gst_buffer_unref (uuid);
4687       break;
4688     }
4689     case FOURCC_sidx:
4690     {
4691       GstBuffer *sidx = NULL;
4692       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4693       if (ret != GST_FLOW_OK)
4694         goto beach;
4695       qtdemux->offset += length;
4696       gst_buffer_map (sidx, &map, GST_MAP_READ);
4697       qtdemux_parse_sidx (qtdemux, map.data, map.size);
4698       gst_buffer_unmap (sidx, &map);
4699       gst_buffer_unref (sidx);
4700       break;
4701     }
4702     default:
4703     {
4704       GstBuffer *unknown = NULL;
4705 
4706       GST_LOG_OBJECT (qtdemux,
4707           "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4708           " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4709           cur_offset);
4710       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4711       if (ret != GST_FLOW_OK)
4712         goto beach;
4713       gst_buffer_map (unknown, &map, GST_MAP_READ);
4714       GST_MEMDUMP ("Unknown tag", map.data, map.size);
4715       gst_buffer_unmap (unknown, &map);
4716       gst_buffer_unref (unknown);
4717       qtdemux->offset += length;
4718       break;
4719     }
4720   }
4721 
4722 beach:
4723   if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4724     /* digested all data, show what we have */
4725     qtdemux_prepare_streams (qtdemux);
4726     QTDEMUX_EXPOSE_LOCK (qtdemux);
4727     ret = qtdemux_expose_streams (qtdemux);
4728     QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4729 
4730     qtdemux->state = QTDEMUX_STATE_MOVIE;
4731     GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4732         qtdemux->state);
4733     return ret;
4734   }
4735   return ret;
4736 }
4737 
4738 /* Seeks to the previous keyframe of the indexed stream and
4739  * aligns other streams with respect to the keyframe timestamp
4740  * of indexed stream. Only called in case of Reverse Playback
4741  */
4742 static GstFlowReturn
gst_qtdemux_seek_to_previous_keyframe(GstQTDemux * qtdemux)4743 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4744 {
4745   guint32 seg_idx = 0, k_index = 0;
4746   guint32 ref_seg_idx, ref_k_index;
4747   GstClockTime k_pos = 0, last_stop = 0;
4748   QtDemuxSegment *seg = NULL;
4749   QtDemuxStream *ref_str = NULL;
4750   guint64 seg_media_start_mov;  /* segment media start time in mov format */
4751   guint64 target_ts;
4752   gint i;
4753 
4754   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4755    * and finally align all the other streams on that timestamp with their
4756    * respective keyframes */
4757   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4758     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4759 
4760     /* No candidate yet, take the first stream */
4761     if (!ref_str) {
4762       ref_str = str;
4763       continue;
4764     }
4765 
4766     /* So that stream has a segment, we prefer video streams */
4767     if (str->subtype == FOURCC_vide) {
4768       ref_str = str;
4769       break;
4770     }
4771   }
4772 
4773   if (G_UNLIKELY (!ref_str)) {
4774     GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4775     goto eos;
4776   }
4777 
4778   if (G_UNLIKELY (!ref_str->from_sample)) {
4779     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4780     goto eos;
4781   }
4782 
4783   /* So that stream has been playing from from_sample to to_sample. We will
4784    * get the timestamp of the previous sample and search for a keyframe before
4785    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4786   if (ref_str->subtype == FOURCC_vide) {
4787     k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4788         ref_str->from_sample - 1, FALSE);
4789   } else {
4790     if (ref_str->from_sample >= 10)
4791       k_index = ref_str->from_sample - 10;
4792     else
4793       k_index = 0;
4794   }
4795 
4796   target_ts =
4797       ref_str->samples[k_index].timestamp +
4798       ref_str->samples[k_index].pts_offset;
4799 
4800   /* get current segment for that stream */
4801   seg = &ref_str->segments[ref_str->segment_index];
4802   /* Use segment start in original timescale for comparisons */
4803   seg_media_start_mov = seg->trak_media_start;
4804 
4805   GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4806       " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4807       k_index, target_ts, seg_media_start_mov,
4808       GST_TIME_ARGS (seg->media_start));
4809 
4810   /* Crawl back through segments to find the one containing this I frame */
4811   while (target_ts < seg_media_start_mov) {
4812     GST_DEBUG_OBJECT (qtdemux,
4813         "keyframe position (sample %u) is out of segment %u " " target %"
4814         G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4815         ref_str->segment_index, target_ts, seg_media_start_mov);
4816 
4817     if (G_UNLIKELY (!ref_str->segment_index)) {
4818       /* Reached first segment, let's consider it's EOS */
4819       goto eos;
4820     }
4821     ref_str->segment_index--;
4822     seg = &ref_str->segments[ref_str->segment_index];
4823     /* Use segment start in original timescale for comparisons */
4824     seg_media_start_mov = seg->trak_media_start;
4825   }
4826   /* Calculate time position of the keyframe and where we should stop */
4827   k_pos =
4828       QTSTREAMTIME_TO_GSTTIME (ref_str,
4829       target_ts - seg->trak_media_start) + seg->time;
4830   last_stop =
4831       QTSTREAMTIME_TO_GSTTIME (ref_str,
4832       ref_str->samples[ref_str->from_sample].timestamp -
4833       seg->trak_media_start) + seg->time;
4834 
4835   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4836       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4837       k_index, GST_TIME_ARGS (k_pos));
4838 
4839   /* Set last_stop with the keyframe timestamp we pushed of that stream */
4840   qtdemux->segment.position = last_stop;
4841   GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4842       GST_TIME_ARGS (last_stop));
4843 
4844   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4845     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4846     goto eos;
4847   }
4848 
4849   ref_seg_idx = ref_str->segment_index;
4850   ref_k_index = k_index;
4851 
4852   /* Align them all on this */
4853   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4854     guint32 index = 0;
4855     GstClockTime seg_time = 0;
4856     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4857 
4858     /* aligning reference stream again might lead to backing up to yet another
4859      * keyframe (due to timestamp rounding issues),
4860      * potentially putting more load on downstream; so let's try to avoid */
4861     if (str == ref_str) {
4862       seg_idx = ref_seg_idx;
4863       seg = &str->segments[seg_idx];
4864       k_index = ref_k_index;
4865       GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4866           "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4867     } else {
4868       seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4869       GST_DEBUG_OBJECT (qtdemux,
4870           "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4871           str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4872 
4873       /* get segment and time in the segment */
4874       seg = &str->segments[seg_idx];
4875       seg_time = k_pos - seg->time;
4876 
4877       /* get the media time in the segment.
4878        * No adjustment for empty "filler" segments */
4879       if (seg->media_start != GST_CLOCK_TIME_NONE)
4880         seg_time += seg->media_start;
4881 
4882       /* get the index of the sample with media time */
4883       index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4884       GST_DEBUG_OBJECT (qtdemux,
4885           "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4886           GST_TIME_ARGS (seg_time), index);
4887 
4888       /* find previous keyframe */
4889       k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4890     }
4891 
4892     /* Remember until where we want to go */
4893     str->to_sample = str->from_sample - 1;
4894     /* Define our time position */
4895     target_ts =
4896         str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4897     str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4898     if (seg->media_start != GST_CLOCK_TIME_NONE)
4899       str->time_position -= seg->media_start;
4900 
4901     /* Now seek back in time */
4902     gst_qtdemux_move_stream (qtdemux, str, k_index);
4903     GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4904         GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4905         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4906   }
4907 
4908   return GST_FLOW_OK;
4909 
4910 eos:
4911   return GST_FLOW_EOS;
4912 }
4913 
4914 /*
4915  * Gets the current qt segment start, stop and position for the
4916  * given time offset. This is used in update_segment()
4917  */
4918 static void
gst_qtdemux_stream_segment_get_boundaries(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime offset,GstClockTime * _start,GstClockTime * _stop,GstClockTime * _time)4919 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4920     QtDemuxStream * stream, GstClockTime offset,
4921     GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4922 {
4923   GstClockTime seg_time;
4924   GstClockTime start, stop, time;
4925   QtDemuxSegment *segment;
4926 
4927   segment = &stream->segments[stream->segment_index];
4928 
4929   /* get time in this segment */
4930   seg_time = (offset - segment->time) * segment->rate;
4931 
4932   GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4933       GST_TIME_ARGS (seg_time));
4934 
4935   if (G_UNLIKELY (seg_time > segment->duration)) {
4936     GST_LOG_OBJECT (stream->pad,
4937         "seg_time > segment->duration %" GST_TIME_FORMAT,
4938         GST_TIME_ARGS (segment->duration));
4939     seg_time = segment->duration;
4940   }
4941 
4942   /* qtdemux->segment.stop is in outside-time-realm, whereas
4943    * segment->media_stop is in track-time-realm.
4944    *
4945    * In order to compare the two, we need to bring segment.stop
4946    * into the track-time-realm
4947    *
4948    * FIXME - does this comment still hold? Don't see any conversion here */
4949 
4950   stop = qtdemux->segment.stop;
4951   if (stop == GST_CLOCK_TIME_NONE)
4952     stop = qtdemux->segment.duration;
4953   if (stop == GST_CLOCK_TIME_NONE)
4954     stop = segment->media_stop;
4955   else
4956     stop =
4957         MIN (segment->media_stop, stop - segment->time + segment->media_start);
4958 
4959   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4960     start = segment->time + seg_time;
4961     time = offset;
4962     stop = start - seg_time + segment->duration;
4963   } else if (qtdemux->segment.rate >= 0) {
4964     start = MIN (segment->media_start + seg_time, stop);
4965     time = offset;
4966   } else {
4967     if (segment->media_start >= qtdemux->segment.start) {
4968       time = segment->time;
4969     } else {
4970       time = segment->time + (qtdemux->segment.start - segment->media_start);
4971     }
4972 
4973     start = MAX (segment->media_start, qtdemux->segment.start);
4974     stop = MIN (segment->media_start + seg_time, stop);
4975   }
4976 
4977   *_start = start;
4978   *_stop = stop;
4979   *_time = time;
4980 }
4981 
4982 /*
4983  * Updates the qt segment used for the stream and pushes a new segment event
4984  * downstream on this stream's pad.
4985  */
4986 static gboolean
gst_qtdemux_stream_update_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,gint seg_idx,GstClockTime offset,GstClockTime * _start,GstClockTime * _stop)4987 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4988     gint seg_idx, GstClockTime offset, GstClockTime * _start,
4989     GstClockTime * _stop)
4990 {
4991   QtDemuxSegment *segment;
4992   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4993   gdouble rate;
4994   GstEvent *event;
4995 
4996   /* update the current segment */
4997   stream->segment_index = seg_idx;
4998 
4999   /* get the segment */
5000   segment = &stream->segments[seg_idx];
5001 
5002   if (G_UNLIKELY (offset < segment->time)) {
5003     GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5004         GST_TIME_ARGS (segment->time));
5005     return FALSE;
5006   }
5007 
5008   /* segment lies beyond total indicated duration */
5009   if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5010           segment->time > qtdemux->segment.duration)) {
5011     GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5012         " < segment->time %" GST_TIME_FORMAT,
5013         GST_TIME_ARGS (qtdemux->segment.duration),
5014         GST_TIME_ARGS (segment->time));
5015     return FALSE;
5016   }
5017 
5018   gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5019       &start, &stop, &time);
5020 
5021   GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5022       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5023       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5024 
5025   /* combine global rate with that of the segment */
5026   rate = segment->rate * qtdemux->segment.rate;
5027 
5028   /* Copy flags from main segment */
5029   stream->segment.flags = qtdemux->segment.flags;
5030 
5031   /* update the segment values used for clipping */
5032   stream->segment.offset = qtdemux->segment.offset;
5033   stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5034   stream->segment.applied_rate = qtdemux->segment.applied_rate;
5035   stream->segment.rate = rate;
5036   stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5037       stream->cslg_shift);
5038   stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5039       stream->cslg_shift);
5040   stream->segment.time = time;
5041   stream->segment.position = stream->segment.start;
5042 
5043   GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5044       &stream->segment);
5045 
5046   /* now prepare and send the segment */
5047   if (stream->pad) {
5048     event = gst_event_new_segment (&stream->segment);
5049     if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5050       gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5051     }
5052     gst_pad_push_event (stream->pad, event);
5053     /* assume we can send more data now */
5054     GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5055     /* clear to send tags on this pad now */
5056     gst_qtdemux_push_tags (qtdemux, stream);
5057   }
5058 
5059   if (_start)
5060     *_start = start;
5061   if (_stop)
5062     *_stop = stop;
5063 
5064   return TRUE;
5065 }
5066 
5067 /* activate the given segment number @seg_idx of @stream at time @offset.
5068  * @offset is an absolute global position over all the segments.
5069  *
5070  * This will push out a NEWSEGMENT event with the right values and
5071  * position the stream index to the first decodable sample before
5072  * @offset.
5073  */
5074 static gboolean
gst_qtdemux_activate_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 seg_idx,GstClockTime offset)5075 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5076     guint32 seg_idx, GstClockTime offset)
5077 {
5078   QtDemuxSegment *segment;
5079   guint32 index, kf_index;
5080   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5081 
5082   GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5083       seg_idx, GST_TIME_ARGS (offset));
5084 
5085   if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5086           &start, &stop))
5087     return FALSE;
5088 
5089   segment = &stream->segments[stream->segment_index];
5090 
5091   /* in the fragmented case, we pick a fragment that starts before our
5092    * desired position and rely on downstream to wait for a keyframe
5093    * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5094    * tfra entries tells us which trun/sample the key unit is in, but we don't
5095    * make use of this additional information at the moment) */
5096   if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5097     stream->to_sample = G_MAXUINT32;
5098     return TRUE;
5099   } else {
5100     /* well, it will be taken care of below */
5101     qtdemux->fragmented_seek_pending = FALSE;
5102     /* FIXME ideally the do_fragmented_seek can be done right here,
5103      * rather than at loop level
5104      * (which might even allow handling edit lists in a fragmented file) */
5105   }
5106 
5107   /* We don't need to look for a sample in push-based */
5108   if (!qtdemux->pullbased)
5109     return TRUE;
5110 
5111   /* and move to the keyframe before the indicated media time of the
5112    * segment */
5113   if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5114     if (qtdemux->segment.rate >= 0) {
5115       index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5116       stream->to_sample = G_MAXUINT32;
5117       GST_DEBUG_OBJECT (stream->pad,
5118           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5119           GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5120           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5121     } else {
5122       index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5123       stream->to_sample = index;
5124       GST_DEBUG_OBJECT (stream->pad,
5125           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5126           GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5127           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5128     }
5129   } else {
5130     GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5131         "this is an empty segment");
5132     return TRUE;
5133   }
5134 
5135   /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5136    * encountered an error and printed a message so we return appropriately */
5137   if (index == -1)
5138     return FALSE;
5139 
5140   /* we're at the right spot */
5141   if (index == stream->sample_index) {
5142     GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5143     return TRUE;
5144   }
5145 
5146   /* find keyframe of the target index */
5147   kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5148 
5149 /* *INDENT-OFF* */
5150 /* indent does stupid stuff with stream->samples[].timestamp */
5151 
5152   /* if we move forwards, we don't have to go back to the previous
5153    * keyframe since we already sent that. We can also just jump to
5154    * the keyframe right before the target index if there is one. */
5155   if (index > stream->sample_index) {
5156     /* moving forwards check if we move past a keyframe */
5157     if (kf_index > stream->sample_index) {
5158       GST_DEBUG_OBJECT (stream->pad,
5159            "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5160            GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5161            GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5162       gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5163     } else {
5164       GST_DEBUG_OBJECT (stream->pad,
5165           "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5166           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5167           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5168     }
5169   } else {
5170     GST_DEBUG_OBJECT (stream->pad,
5171         "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5172         GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5173         GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5174     gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5175   }
5176 
5177 /* *INDENT-ON* */
5178 
5179   return TRUE;
5180 }
5181 
5182 /* prepare to get the current sample of @stream, getting essential values.
5183  *
5184  * This function will also prepare and send the segment when needed.
5185  *
5186  * Return FALSE if the stream is EOS.
5187  *
5188  * PULL-BASED
5189  */
5190 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)5191 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5192     QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5193     GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5194     gboolean * keyframe)
5195 {
5196   QtDemuxSample *sample;
5197   GstClockTime time_position;
5198   guint32 seg_idx;
5199 
5200   g_return_val_if_fail (stream != NULL, FALSE);
5201 
5202   time_position = stream->time_position;
5203   if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5204     goto eos;
5205 
5206   seg_idx = stream->segment_index;
5207   if (G_UNLIKELY (seg_idx == -1)) {
5208     /* find segment corresponding to time_position if we are looking
5209      * for a segment. */
5210     seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5211   }
5212 
5213   /* different segment, activate it, sample_index will be set. */
5214   if (G_UNLIKELY (stream->segment_index != seg_idx))
5215     gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5216 
5217   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5218               segments[stream->segment_index]))) {
5219     QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5220 
5221     GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5222         " prepare empty sample");
5223 
5224     *empty = TRUE;
5225     *pts = *dts = time_position;
5226     *duration = seg->duration - (time_position - seg->time);
5227 
5228     return TRUE;
5229   }
5230 
5231   *empty = FALSE;
5232 
5233   if (stream->sample_index == -1)
5234     stream->sample_index = 0;
5235 
5236   GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5237       stream->sample_index, stream->n_samples);
5238 
5239   if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5240     if (!qtdemux->fragmented)
5241       goto eos;
5242 
5243     GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5244     do {
5245       GstFlowReturn flow;
5246 
5247       GST_OBJECT_LOCK (qtdemux);
5248       flow = qtdemux_add_fragmented_samples (qtdemux);
5249       GST_OBJECT_UNLOCK (qtdemux);
5250 
5251       if (flow != GST_FLOW_OK)
5252         goto eos;
5253     }
5254     while (stream->sample_index >= stream->n_samples);
5255   }
5256 
5257   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5258     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5259         stream->sample_index);
5260     return FALSE;
5261   }
5262 
5263   /* now get the info for the sample we're at */
5264   sample = &stream->samples[stream->sample_index];
5265 
5266   *dts = QTSAMPLE_DTS (stream, sample);
5267   *pts = QTSAMPLE_PTS (stream, sample);
5268   *offset = sample->offset;
5269   *size = sample->size;
5270   *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5271   *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5272 
5273   return TRUE;
5274 
5275   /* special cases */
5276 eos:
5277   {
5278     stream->time_position = GST_CLOCK_TIME_NONE;
5279     return FALSE;
5280   }
5281 }
5282 
5283 /* move to the next sample in @stream.
5284  *
5285  * Moves to the next segment when needed.
5286  */
5287 static void
gst_qtdemux_advance_sample(GstQTDemux * qtdemux,QtDemuxStream * stream)5288 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5289 {
5290   QtDemuxSample *sample;
5291   QtDemuxSegment *segment;
5292 
5293   /* get current segment */
5294   segment = &stream->segments[stream->segment_index];
5295 
5296   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5297     GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5298     goto next_segment;
5299   }
5300 
5301   if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5302     /* Mark the stream as EOS */
5303     GST_DEBUG_OBJECT (qtdemux,
5304         "reached max allowed sample %u, mark EOS", stream->to_sample);
5305     stream->time_position = GST_CLOCK_TIME_NONE;
5306     return;
5307   }
5308 
5309   /* move to next sample */
5310   stream->sample_index++;
5311   stream->offset_in_sample = 0;
5312 
5313   /* reached the last sample, we need the next segment */
5314   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5315     goto next_segment;
5316 
5317   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5318     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5319         stream->sample_index);
5320     return;
5321   }
5322 
5323   /* get next sample */
5324   sample = &stream->samples[stream->sample_index];
5325 
5326   /* see if we are past the segment */
5327   if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5328     goto next_segment;
5329 
5330   if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5331     /* inside the segment, update time_position, looks very familiar to
5332      * GStreamer segments, doesn't it? */
5333     stream->time_position =
5334         QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5335   } else {
5336     /* not yet in segment, time does not yet increment. This means
5337      * that we are still prerolling keyframes to the decoder so it can
5338      * decode the first sample of the segment. */
5339     stream->time_position = segment->time;
5340   }
5341   return;
5342 
5343   /* move to the next segment */
5344 next_segment:
5345   {
5346     GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5347 
5348     if (stream->segment_index == stream->n_segments - 1) {
5349       /* are we at the end of the last segment, we're EOS */
5350       stream->time_position = GST_CLOCK_TIME_NONE;
5351     } else {
5352       /* else we're only at the end of the current segment */
5353       stream->time_position = segment->stop_time;
5354     }
5355     /* make sure we select a new segment */
5356 
5357     /* accumulate previous segments */
5358     if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5359       stream->accumulated_base +=
5360           (stream->segment.stop -
5361           stream->segment.start) / ABS (stream->segment.rate);
5362 
5363     stream->segment_index = -1;
5364   }
5365 }
5366 
5367 static void
gst_qtdemux_sync_streams(GstQTDemux * demux)5368 gst_qtdemux_sync_streams (GstQTDemux * demux)
5369 {
5370   gint i;
5371 
5372   if (QTDEMUX_N_STREAMS (demux) <= 1)
5373     return;
5374 
5375   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5376     QtDemuxStream *stream;
5377     GstClockTime end_time;
5378 
5379     stream = QTDEMUX_NTH_STREAM (demux, i);
5380 
5381     if (!stream->pad)
5382       continue;
5383 
5384     /* TODO advance time on subtitle streams here, if any some day */
5385 
5386     /* some clips/trailers may have unbalanced streams at the end,
5387      * so send EOS on shorter stream to prevent stalling others */
5388 
5389     /* do not mess with EOS if SEGMENT seeking */
5390     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5391       continue;
5392 
5393     if (demux->pullbased) {
5394       /* loop mode is sample time based */
5395       if (!STREAM_IS_EOS (stream))
5396         continue;
5397     } else {
5398       /* push mode is byte position based */
5399       if (stream->n_samples &&
5400           stream->samples[stream->n_samples - 1].offset >= demux->offset)
5401         continue;
5402     }
5403 
5404     if (stream->sent_eos)
5405       continue;
5406 
5407     /* only act if some gap */
5408     end_time = stream->segments[stream->n_segments - 1].stop_time;
5409     GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5410         ", stream end: %" GST_TIME_FORMAT,
5411         GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5412     if (GST_CLOCK_TIME_IS_VALID (end_time)
5413         && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5414       GstEvent *event;
5415 
5416       GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5417           GST_PAD_NAME (stream->pad));
5418       stream->sent_eos = TRUE;
5419       event = gst_event_new_eos ();
5420       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5421         gst_event_set_seqnum (event, demux->segment_seqnum);
5422       gst_pad_push_event (stream->pad, event);
5423     }
5424   }
5425 }
5426 
5427 /* EOS and NOT_LINKED need to be combined. This means that we return:
5428  *
5429  *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5430  *  GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5431  */
5432 static GstFlowReturn
gst_qtdemux_combine_flows(GstQTDemux * demux,QtDemuxStream * stream,GstFlowReturn ret)5433 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5434     GstFlowReturn ret)
5435 {
5436   GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5437 
5438   if (stream->pad)
5439     ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5440         ret);
5441   else
5442     ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5443 
5444   GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5445   return ret;
5446 }
5447 
5448 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5449  * completely clipped
5450  *
5451  * Should be used only with raw buffers */
5452 static GstBuffer *
gst_qtdemux_clip_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5453 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5454     GstBuffer * buf)
5455 {
5456   guint64 start, stop, cstart, cstop, diff;
5457   GstClockTime pts, duration;
5458   gsize size, osize;
5459   gint num_rate, denom_rate;
5460   gint frame_size;
5461   gboolean clip_data;
5462   guint offset;
5463 
5464   osize = size = gst_buffer_get_size (buf);
5465   offset = 0;
5466 
5467   /* depending on the type, setup the clip parameters */
5468   if (stream->subtype == FOURCC_soun) {
5469     frame_size = CUR_STREAM (stream)->bytes_per_frame;
5470     num_rate = GST_SECOND;
5471     denom_rate = (gint) CUR_STREAM (stream)->rate;
5472     clip_data = TRUE;
5473   } else if (stream->subtype == FOURCC_vide) {
5474     frame_size = size;
5475     num_rate = CUR_STREAM (stream)->fps_n;
5476     denom_rate = CUR_STREAM (stream)->fps_d;
5477     clip_data = FALSE;
5478   } else
5479     goto wrong_type;
5480 
5481   if (frame_size <= 0)
5482     goto bad_frame_size;
5483 
5484   /* we can only clip if we have a valid pts */
5485   pts = GST_BUFFER_PTS (buf);
5486   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5487     goto no_pts;
5488 
5489   duration = GST_BUFFER_DURATION (buf);
5490 
5491   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5492     duration =
5493         gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5494   }
5495 
5496   start = pts;
5497   stop = start + duration;
5498 
5499   if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5500               GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5501     goto clipped;
5502 
5503   /* see if some clipping happened */
5504   diff = cstart - start;
5505   if (diff > 0) {
5506     pts += diff;
5507     duration -= diff;
5508 
5509     if (clip_data) {
5510       /* bring clipped time to samples and to bytes */
5511       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5512       diff *= frame_size;
5513 
5514       GST_DEBUG_OBJECT (qtdemux,
5515           "clipping start to %" GST_TIME_FORMAT " %"
5516           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5517 
5518       offset = diff;
5519       size -= diff;
5520     }
5521   }
5522   diff = stop - cstop;
5523   if (diff > 0) {
5524     duration -= diff;
5525 
5526     if (clip_data) {
5527       /* bring clipped time to samples and then to bytes */
5528       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5529       diff *= frame_size;
5530       GST_DEBUG_OBJECT (qtdemux,
5531           "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5532           " bytes", GST_TIME_ARGS (cstop), diff);
5533       size -= diff;
5534     }
5535   }
5536 
5537   if (offset != 0 || size != osize)
5538     gst_buffer_resize (buf, offset, size);
5539 
5540   GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5541   GST_BUFFER_PTS (buf) = pts;
5542   GST_BUFFER_DURATION (buf) = duration;
5543 
5544   return buf;
5545 
5546   /* dropped buffer */
5547 wrong_type:
5548   {
5549     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5550     return buf;
5551   }
5552 bad_frame_size:
5553   {
5554     GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5555     return buf;
5556   }
5557 no_pts:
5558   {
5559     GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5560     return buf;
5561   }
5562 clipped:
5563   {
5564     GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5565     gst_buffer_unref (buf);
5566     return NULL;
5567   }
5568 }
5569 
5570 static GstBuffer *
gst_qtdemux_align_buffer(GstQTDemux * demux,GstBuffer * buffer,gsize alignment)5571 gst_qtdemux_align_buffer (GstQTDemux * demux,
5572     GstBuffer * buffer, gsize alignment)
5573 {
5574   GstMapInfo map;
5575 
5576   gst_buffer_map (buffer, &map, GST_MAP_READ);
5577 
5578   if (map.size < sizeof (guintptr)) {
5579     gst_buffer_unmap (buffer, &map);
5580     return buffer;
5581   }
5582 
5583   if (((guintptr) map.data) & (alignment - 1)) {
5584     GstBuffer *new_buffer;
5585     GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5586 
5587     new_buffer = gst_buffer_new_allocate (NULL,
5588         gst_buffer_get_size (buffer), &params);
5589 
5590     /* Copy data "by hand", so ensure alignment is kept: */
5591     gst_buffer_fill (new_buffer, 0, map.data, map.size);
5592 
5593     gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5594     GST_DEBUG_OBJECT (demux,
5595         "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5596         alignment);
5597 
5598     gst_buffer_unmap (buffer, &map);
5599     gst_buffer_unref (buffer);
5600 
5601     return new_buffer;
5602   }
5603 
5604   gst_buffer_unmap (buffer, &map);
5605   return buffer;
5606 }
5607 
5608 static guint8 *
convert_to_s334_1a(const guint8 * ccpair,guint8 ccpair_size,guint field,gsize * res)5609 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5610     gsize * res)
5611 {
5612   guint8 *storage;
5613   gsize i;
5614 
5615   /* We are converting from pairs to triplets */
5616   *res = ccpair_size / 2 * 3;
5617   storage = g_malloc (*res);
5618   for (i = 0; i * 2 < ccpair_size; i += 1) {
5619     /* FIXME: Use line offset 0 as we simply can't know here */
5620     if (field == 1)
5621       storage[i * 3] = 0x80 | 0x00;
5622     else
5623       storage[i * 3] = 0x00 | 0x00;
5624     storage[i * 3 + 1] = ccpair[i * 2];
5625     storage[i * 3 + 2] = ccpair[i * 2 + 1];
5626   }
5627 
5628   return storage;
5629 }
5630 
5631 static guint8 *
extract_cc_from_data(QtDemuxStream * stream,const guint8 * data,gsize size,gsize * cclen)5632 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5633     gsize * cclen)
5634 {
5635   guint8 *res = NULL;
5636   guint32 atom_length, fourcc;
5637   QtDemuxStreamStsdEntry *stsd_entry;
5638 
5639   GST_MEMDUMP ("caption atom", data, size);
5640 
5641   /* There might be multiple atoms */
5642 
5643   *cclen = 0;
5644   if (size < 8)
5645     goto invalid_cdat;
5646   atom_length = QT_UINT32 (data);
5647   fourcc = QT_FOURCC (data + 4);
5648   if (G_UNLIKELY (atom_length > size || atom_length == 8))
5649     goto invalid_cdat;
5650 
5651   GST_DEBUG_OBJECT (stream->pad, "here");
5652 
5653   /* Check if we have somethig compatible */
5654   stsd_entry = CUR_STREAM (stream);
5655   switch (stsd_entry->fourcc) {
5656     case FOURCC_c608:{
5657       guint8 *cdat = NULL, *cdt2 = NULL;
5658       gsize cdat_size = 0, cdt2_size = 0;
5659       /* Should be cdat or cdt2 */
5660       if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5661         GST_WARNING_OBJECT (stream->pad,
5662             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5663             GST_FOURCC_ARGS (fourcc));
5664         goto invalid_cdat;
5665       }
5666 
5667       /* Convert to S334-1 Annex A byte triplet */
5668       if (fourcc == FOURCC_cdat)
5669         cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5670       else
5671         cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5672       GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5673           size, atom_length);
5674 
5675       /* Check for another atom ? */
5676       if (size > atom_length + 8) {
5677         guint32 new_atom_length = QT_UINT32 (data + atom_length);
5678         if (size >= atom_length + new_atom_length) {
5679           fourcc = QT_FOURCC (data + atom_length + 4);
5680           if (fourcc == FOURCC_cdat) {
5681             if (cdat == NULL)
5682               cdat =
5683                   convert_to_s334_1a (data + atom_length + 8,
5684                   new_atom_length - 8, 1, &cdat_size);
5685             else
5686               GST_WARNING_OBJECT (stream->pad,
5687                   "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5688           } else {
5689             if (cdt2 == NULL)
5690               cdt2 =
5691                   convert_to_s334_1a (data + atom_length + 8,
5692                   new_atom_length - 8, 2, &cdt2_size);
5693             else
5694               GST_WARNING_OBJECT (stream->pad,
5695                   "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5696           }
5697         }
5698       }
5699 
5700       *cclen = cdat_size + cdt2_size;
5701       res = g_malloc (*cclen);
5702       if (cdat_size)
5703         memcpy (res, cdat, cdat_size);
5704       if (cdt2_size)
5705         memcpy (res + cdat_size, cdt2, cdt2_size);
5706       g_free (cdat);
5707       g_free (cdt2);
5708     }
5709       break;
5710     case FOURCC_c708:
5711       if (fourcc != FOURCC_ccdp) {
5712         GST_WARNING_OBJECT (stream->pad,
5713             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5714             GST_FOURCC_ARGS (fourcc));
5715         goto invalid_cdat;
5716       }
5717       *cclen = atom_length - 8;
5718       res = g_memdup (data + 8, *cclen);
5719       break;
5720     default:
5721       /* Keep this here in case other closed caption formats are added */
5722       g_assert_not_reached ();
5723       break;
5724   }
5725 
5726   GST_MEMDUMP ("Output", res, *cclen);
5727   return res;
5728 
5729   /* Errors */
5730 invalid_cdat:
5731   GST_WARNING ("[cdat] atom is too small or invalid");
5732   return NULL;
5733 }
5734 
5735 /* the input buffer metadata must be writable,
5736  * but time/duration etc not yet set and need not be preserved */
5737 static GstBuffer *
gst_qtdemux_process_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5738 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5739     GstBuffer * buf)
5740 {
5741   GstMapInfo map;
5742   guint nsize = 0;
5743   gchar *str;
5744 
5745   /* not many cases for now */
5746   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5747     /* send a one time dvd clut event */
5748     if (stream->pending_event && stream->pad)
5749       gst_pad_push_event (stream->pad, stream->pending_event);
5750     stream->pending_event = NULL;
5751   }
5752 
5753   if (G_UNLIKELY (stream->subtype != FOURCC_text
5754           && stream->subtype != FOURCC_sbtl &&
5755           stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5756     return buf;
5757   }
5758 
5759   gst_buffer_map (buf, &map, GST_MAP_READ);
5760 
5761   /* empty buffer is sent to terminate previous subtitle */
5762   if (map.size <= 2) {
5763     gst_buffer_unmap (buf, &map);
5764     gst_buffer_unref (buf);
5765     return NULL;
5766   }
5767   if (stream->subtype == FOURCC_subp) {
5768     /* That's all the processing needed for subpictures */
5769     gst_buffer_unmap (buf, &map);
5770     return buf;
5771   }
5772 
5773   if (stream->subtype == FOURCC_clcp) {
5774     guint8 *cc;
5775     gsize cclen = 0;
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     gst_buffer_unref (buf);
5781     if (cc) {
5782       buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5783     } else {
5784       /* Conversion failed or there's nothing */
5785       buf = NULL;
5786     }
5787     return buf;
5788   }
5789 
5790   nsize = GST_READ_UINT16_BE (map.data);
5791   nsize = MIN (nsize, map.size - 2);
5792 
5793   GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5794       nsize, map.size);
5795 
5796   /* takes care of UTF-8 validation or UTF-16 recognition,
5797    * no other encoding expected */
5798   str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5799   gst_buffer_unmap (buf, &map);
5800   if (str) {
5801     gst_buffer_unref (buf);
5802     buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5803   } else {
5804     /* this should not really happen unless the subtitle is corrupted */
5805     gst_buffer_unref (buf);
5806     buf = NULL;
5807   }
5808 
5809   /* FIXME ? convert optional subsequent style info to markup */
5810 
5811   return buf;
5812 }
5813 
5814 static GstFlowReturn
gst_qtdemux_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5815 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5816     GstBuffer * buf)
5817 {
5818   GstFlowReturn ret = GST_FLOW_OK;
5819   GstClockTime pts, duration;
5820 
5821   if (stream->need_clip)
5822     buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5823 
5824   if (G_UNLIKELY (buf == NULL))
5825     goto exit;
5826 
5827   if (G_UNLIKELY (stream->discont)) {
5828     GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5829     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5830     stream->discont = FALSE;
5831   } else {
5832     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5833   }
5834 
5835   GST_LOG_OBJECT (qtdemux,
5836       "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5837       ", duration %" GST_TIME_FORMAT " on pad %s",
5838       GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5839       GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5840       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5841 
5842   if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5843     GstStructure *crypto_info;
5844     QtDemuxCencSampleSetInfo *info =
5845         (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5846     gint index;
5847     GstEvent *event;
5848 
5849     while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5850       GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5851           GST_PTR_FORMAT, event);
5852       gst_pad_push_event (stream->pad, event);
5853     }
5854 
5855     if (info->crypto_info == NULL) {
5856       GST_DEBUG_OBJECT (qtdemux,
5857           "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5858     } else {
5859       /* The end of the crypto_info array matches our n_samples position,
5860        * so count backward from there */
5861       index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5862       if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5863         /* steal structure from array */
5864         crypto_info = g_ptr_array_index (info->crypto_info, index);
5865         g_ptr_array_index (info->crypto_info, index) = NULL;
5866         GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5867             info->crypto_info->len);
5868         if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5869           GST_ERROR_OBJECT (qtdemux,
5870               "failed to attach cenc metadata to buffer");
5871       } else {
5872         GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5873             index, stream->sample_index);
5874       }
5875     }
5876   }
5877 
5878   if (stream->alignment > 1)
5879     buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5880 
5881   pts = GST_BUFFER_PTS (buf);
5882   duration = GST_BUFFER_DURATION (buf);
5883 
5884   ret = gst_pad_push (stream->pad, buf);
5885 
5886   if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5887     /* mark position in stream, we'll need this to know when to send GAP event */
5888     stream->segment.position = pts + duration;
5889   }
5890 
5891 exit:
5892 
5893   return ret;
5894 }
5895 
5896 static GstFlowReturn
gst_qtdemux_split_and_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5897 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5898     GstBuffer * buf)
5899 {
5900   GstFlowReturn ret = GST_FLOW_OK;
5901 
5902   if (stream->subtype == FOURCC_clcp
5903       && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
5904     GstMapInfo map;
5905     guint n_output_buffers, n_field1 = 0, n_field2 = 0;
5906     guint n_triplets, i;
5907     guint field1_off = 0, field2_off = 0;
5908 
5909     /* We have to split CEA608 buffers so that each outgoing buffer contains
5910      * one byte pair per field according to the framerate of the video track.
5911      *
5912      * If there is only a single byte pair per field we don't have to do
5913      * anything
5914      */
5915 
5916     gst_buffer_map (buf, &map, GST_MAP_READ);
5917 
5918     n_triplets = map.size / 3;
5919     for (i = 0; i < n_triplets; i++) {
5920       if (map.data[3 * i] & 0x80)
5921         n_field1++;
5922       else
5923         n_field2++;
5924     }
5925 
5926     g_assert (n_field1 || n_field2);
5927 
5928     /* If there's more than 1 frame we have to split, otherwise we can just
5929      * pass through */
5930     if (n_field1 > 1 || n_field2 > 1) {
5931       n_output_buffers =
5932           gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
5933           CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
5934 
5935       for (i = 0; i < n_output_buffers; i++) {
5936         GstBuffer *outbuf =
5937             gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
5938         GstMapInfo outmap;
5939         guint8 *outptr;
5940 
5941         gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
5942         outptr = outmap.data;
5943 
5944         if (n_field1) {
5945           gboolean found = FALSE;
5946 
5947           while (map.data + field1_off < map.data + map.size) {
5948             if (map.data[field1_off] & 0x80) {
5949               memcpy (outptr, &map.data[field1_off], 3);
5950               field1_off += 3;
5951               found = TRUE;
5952               break;
5953             }
5954             field1_off += 3;
5955           }
5956 
5957           if (!found) {
5958             const guint8 empty[] = { 0x80, 0x80, 0x80 };
5959 
5960             memcpy (outptr, empty, 3);
5961           }
5962 
5963           outptr += 3;
5964         }
5965 
5966         if (n_field2) {
5967           gboolean found = FALSE;
5968 
5969           while (map.data + field2_off < map.data + map.size) {
5970             if ((map.data[field2_off] & 0x80) == 0) {
5971               memcpy (outptr, &map.data[field2_off], 3);
5972               field2_off += 3;
5973               found = TRUE;
5974               break;
5975             }
5976             field2_off += 3;
5977           }
5978 
5979           if (!found) {
5980             const guint8 empty[] = { 0x00, 0x80, 0x80 };
5981 
5982             memcpy (outptr, empty, 3);
5983           }
5984 
5985           outptr += 3;
5986         }
5987 
5988         gst_buffer_unmap (outbuf, &outmap);
5989 
5990         GST_BUFFER_PTS (outbuf) =
5991             GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
5992             GST_SECOND * CUR_STREAM (stream)->fps_d,
5993             CUR_STREAM (stream)->fps_n);
5994         GST_BUFFER_DURATION (outbuf) =
5995             gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
5996             CUR_STREAM (stream)->fps_n);
5997         GST_BUFFER_OFFSET (outbuf) = -1;
5998         GST_BUFFER_OFFSET_END (outbuf) = -1;
5999 
6000         ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6001 
6002         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6003           break;
6004       }
6005       gst_buffer_unmap (buf, &map);
6006       gst_buffer_unref (buf);
6007     } else {
6008       gst_buffer_unmap (buf, &map);
6009       ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6010     }
6011   } else {
6012     ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6013   }
6014 
6015   return ret;
6016 }
6017 
6018 /* Sets a buffer's attributes properly and pushes it downstream.
6019  * Also checks for additional actions and custom processing that may
6020  * need to be done first.
6021  */
6022 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)6023 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6024     QtDemuxStream * stream, GstBuffer * buf,
6025     GstClockTime dts, GstClockTime pts, GstClockTime duration,
6026     gboolean keyframe, GstClockTime position, guint64 byte_position)
6027 {
6028   GstFlowReturn ret = GST_FLOW_OK;
6029 
6030   /* offset the timestamps according to the edit list */
6031 
6032   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6033     gchar *url;
6034     GstMapInfo map;
6035 
6036     gst_buffer_map (buf, &map, GST_MAP_READ);
6037     url = g_strndup ((gchar *) map.data, map.size);
6038     gst_buffer_unmap (buf, &map);
6039     if (url != NULL && strlen (url) != 0) {
6040       /* we have RTSP redirect now */
6041       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6042           gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6043               gst_structure_new ("redirect",
6044                   "new-location", G_TYPE_STRING, url, NULL)));
6045       qtdemux->posted_redirect = TRUE;
6046     } else {
6047       GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6048           "posting");
6049     }
6050     g_free (url);
6051   }
6052 
6053   /* position reporting */
6054   if (qtdemux->segment.rate >= 0) {
6055     qtdemux->segment.position = position;
6056     gst_qtdemux_sync_streams (qtdemux);
6057   }
6058 
6059   if (G_UNLIKELY (!stream->pad)) {
6060     GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6061     gst_buffer_unref (buf);
6062     goto exit;
6063   }
6064 
6065   /* send out pending buffers */
6066   while (stream->buffers) {
6067     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6068 
6069     if (G_UNLIKELY (stream->discont)) {
6070       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6071       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6072       stream->discont = FALSE;
6073     } else {
6074       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6075     }
6076 
6077     if (stream->alignment > 1)
6078       buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6079     gst_pad_push (stream->pad, buffer);
6080 
6081     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6082   }
6083 
6084   /* we're going to modify the metadata */
6085   buf = gst_buffer_make_writable (buf);
6086 
6087   if (G_UNLIKELY (stream->need_process))
6088     buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
6089 
6090   if (!buf) {
6091     goto exit;
6092   }
6093 
6094   GST_BUFFER_DTS (buf) = dts;
6095   GST_BUFFER_PTS (buf) = pts;
6096   GST_BUFFER_DURATION (buf) = duration;
6097   GST_BUFFER_OFFSET (buf) = -1;
6098   GST_BUFFER_OFFSET_END (buf) = -1;
6099 
6100   if (!keyframe) {
6101     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6102     stream->on_keyframe = FALSE;
6103   } else {
6104     stream->on_keyframe = TRUE;
6105   }
6106 
6107   if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6108     gst_buffer_append_memory (buf,
6109         gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6110 
6111   if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6112     gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6113   }
6114 #if 0
6115   if (G_UNLIKELY (qtdemux->element_index)) {
6116     GstClockTime stream_time;
6117 
6118     stream_time =
6119         gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6120         timestamp);
6121     if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6122       GST_LOG_OBJECT (qtdemux,
6123           "adding association %" GST_TIME_FORMAT "-> %"
6124           G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6125       gst_index_add_association (qtdemux->element_index,
6126           qtdemux->index_id,
6127           keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6128           GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6129           GST_FORMAT_BYTES, byte_position, NULL);
6130     }
6131   }
6132 #endif
6133 
6134   ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6135 
6136 exit:
6137   return ret;
6138 }
6139 
6140 static const QtDemuxRandomAccessEntry *
gst_qtdemux_stream_seek_fragment(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime pos,gboolean after)6141 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6142     GstClockTime pos, gboolean after)
6143 {
6144   QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6145   guint n_entries = stream->n_ra_entries;
6146   guint i;
6147 
6148   /* we assume the table is sorted */
6149   for (i = 0; i < n_entries; ++i) {
6150     if (entries[i].ts > pos)
6151       break;
6152   }
6153 
6154   /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6155    * probably okay to assume that the index lists the very first fragment */
6156   if (i == 0)
6157     return &entries[0];
6158 
6159   if (after)
6160     return &entries[i];
6161   else
6162     return &entries[i - 1];
6163 }
6164 
6165 static gboolean
gst_qtdemux_do_fragmented_seek(GstQTDemux * qtdemux)6166 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6167 {
6168   const QtDemuxRandomAccessEntry *best_entry = NULL;
6169   gint i;
6170 
6171   GST_OBJECT_LOCK (qtdemux);
6172 
6173   g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6174 
6175   /* first see if we can determine where to go to using mfra,
6176    * before we start clearing things */
6177   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6178     const QtDemuxRandomAccessEntry *entry;
6179     QtDemuxStream *stream;
6180     gboolean is_audio_or_video;
6181 
6182     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6183 
6184     if (stream->ra_entries == NULL)
6185       continue;
6186 
6187     if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6188       is_audio_or_video = TRUE;
6189     else
6190       is_audio_or_video = FALSE;
6191 
6192     entry =
6193         gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6194         stream->time_position, !is_audio_or_video);
6195 
6196     GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6197         "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6198 
6199     stream->pending_seek = entry;
6200 
6201     /* decide position to jump to just based on audio/video tracks, not subs */
6202     if (!is_audio_or_video)
6203       continue;
6204 
6205     if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6206       best_entry = entry;
6207   }
6208 
6209   /* no luck, will handle seek otherwise */
6210   if (best_entry == NULL) {
6211     GST_OBJECT_UNLOCK (qtdemux);
6212     return FALSE;
6213   }
6214 
6215   /* ok, now we can prepare for processing as of located moof */
6216   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6217     QtDemuxStream *stream;
6218 
6219     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6220 
6221     g_free (stream->samples);
6222     stream->samples = NULL;
6223     stream->n_samples = 0;
6224     stream->stbl_index = -1;    /* no samples have yet been parsed */
6225     stream->sample_index = -1;
6226 
6227     if (stream->protection_scheme_info) {
6228       /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6229       if (stream->protection_scheme_type == FOURCC_cenc) {
6230         QtDemuxCencSampleSetInfo *info =
6231             (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6232         if (info->crypto_info) {
6233           g_ptr_array_free (info->crypto_info, TRUE);
6234           info->crypto_info = NULL;
6235         }
6236       }
6237     }
6238   }
6239 
6240   GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6241       "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6242       GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6243       best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6244 
6245   qtdemux->moof_offset = best_entry->moof_offset;
6246 
6247   qtdemux_add_fragmented_samples (qtdemux);
6248 
6249   GST_OBJECT_UNLOCK (qtdemux);
6250   return TRUE;
6251 }
6252 
6253 static GstFlowReturn
gst_qtdemux_loop_state_movie(GstQTDemux * qtdemux)6254 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6255 {
6256   GstFlowReturn ret = GST_FLOW_OK;
6257   GstBuffer *buf = NULL;
6258   QtDemuxStream *stream, *target_stream = NULL;
6259   GstClockTime min_time;
6260   guint64 offset = 0;
6261   GstClockTime dts = GST_CLOCK_TIME_NONE;
6262   GstClockTime pts = GST_CLOCK_TIME_NONE;
6263   GstClockTime duration = 0;
6264   gboolean keyframe = FALSE;
6265   guint sample_size = 0;
6266   gboolean empty = 0;
6267   guint size;
6268   gint i;
6269 
6270   if (qtdemux->fragmented_seek_pending) {
6271     GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6272     if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6273       GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6274       qtdemux->fragmented_seek_pending = FALSE;
6275     } else {
6276       GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6277     }
6278   }
6279 
6280   /* Figure out the next stream sample to output, min_time is expressed in
6281    * global time and runs over the edit list segments. */
6282   min_time = G_MAXUINT64;
6283   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6284     GstClockTime position;
6285 
6286     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6287     position = stream->time_position;
6288 
6289     /* position of -1 is EOS */
6290     if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6291       min_time = position;
6292       target_stream = stream;
6293     }
6294   }
6295   /* all are EOS */
6296   if (G_UNLIKELY (target_stream == NULL)) {
6297     GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6298     goto eos;
6299   }
6300 
6301   /* check for segment end */
6302   if (G_UNLIKELY (qtdemux->segment.stop != -1
6303           && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6304               || (qtdemux->segment.rate < 0
6305                   && qtdemux->segment.start > min_time))
6306           && target_stream->on_keyframe)) {
6307     GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6308     target_stream->time_position = GST_CLOCK_TIME_NONE;
6309     goto eos_stream;
6310   }
6311 
6312   /* gap events for subtitle streams */
6313   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6314     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6315     if (stream->pad && (stream->subtype == FOURCC_subp
6316             || stream->subtype == FOURCC_text
6317             || stream->subtype == FOURCC_sbtl)) {
6318       /* send one second gap events until the stream catches up */
6319       /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6320       while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6321           GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6322           stream->segment.position + GST_SECOND < min_time) {
6323         GstEvent *gap =
6324             gst_event_new_gap (stream->segment.position, GST_SECOND);
6325         gst_pad_push_event (stream->pad, gap);
6326         stream->segment.position += GST_SECOND;
6327       }
6328     }
6329   }
6330 
6331   stream = target_stream;
6332   /* fetch info for the current sample of this stream */
6333   if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6334               &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6335     goto eos_stream;
6336 
6337   gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6338   if (stream->new_caps) {
6339     gst_qtdemux_configure_stream (qtdemux, stream);
6340     qtdemux_do_allocation (stream, qtdemux);
6341   }
6342 
6343   /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6344   if (G_UNLIKELY (qtdemux->segment.
6345           flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6346     if (stream->subtype == FOURCC_vide && !keyframe) {
6347       GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6348           stream->track_id);
6349       goto next;
6350     }
6351   }
6352 
6353   GST_DEBUG_OBJECT (qtdemux,
6354       "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6355       ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6356       ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6357       sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6358       GST_TIME_ARGS (duration));
6359 
6360   if (G_UNLIKELY (empty)) {
6361     /* empty segment, push a gap if there's a second or more
6362      * difference and move to the next one */
6363     if ((pts + duration - stream->segment.position) >= GST_SECOND)
6364       gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6365     stream->segment.position = pts + duration;
6366     goto next;
6367   }
6368 
6369   /* hmm, empty sample, skip and move to next sample */
6370   if (G_UNLIKELY (sample_size <= 0))
6371     goto next;
6372 
6373   /* last pushed sample was out of boundary, goto next sample */
6374   if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6375     goto next;
6376 
6377   if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6378     size = sample_size;
6379   } else {
6380     GST_DEBUG_OBJECT (qtdemux,
6381         "size %d larger than stream max_buffer_size %d, trimming",
6382         sample_size, stream->max_buffer_size);
6383     size =
6384         MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6385   }
6386 
6387   if (qtdemux->cenc_aux_info_offset > 0) {
6388     GstMapInfo map;
6389     GstByteReader br;
6390     GstBuffer *aux_info = NULL;
6391 
6392     /* pull the data stored before the sample */
6393     ret =
6394         gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6395         offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6396     if (G_UNLIKELY (ret != GST_FLOW_OK))
6397       goto beach;
6398     gst_buffer_map (aux_info, &map, GST_MAP_READ);
6399     GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6400     gst_byte_reader_init (&br, map.data + 8, map.size);
6401     if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6402             qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6403       GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6404       gst_buffer_unmap (aux_info, &map);
6405       gst_buffer_unref (aux_info);
6406       ret = GST_FLOW_ERROR;
6407       goto beach;
6408     }
6409     gst_buffer_unmap (aux_info, &map);
6410     gst_buffer_unref (aux_info);
6411   }
6412 
6413   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6414       offset);
6415 
6416   if (stream->use_allocator) {
6417     /* if we have a per-stream allocator, use it */
6418     buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6419   }
6420 
6421   ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6422       size, &buf);
6423   if (G_UNLIKELY (ret != GST_FLOW_OK))
6424     goto beach;
6425 
6426   if (size != sample_size) {
6427     pts += gst_util_uint64_scale_int (GST_SECOND,
6428         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6429         stream->timescale);
6430     dts +=
6431         gst_util_uint64_scale_int (GST_SECOND,
6432         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6433         stream->timescale);
6434     duration =
6435         gst_util_uint64_scale_int (GST_SECOND,
6436         size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6437   }
6438 
6439   ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6440       dts, pts, duration, keyframe, min_time, offset);
6441 
6442   if (size != sample_size) {
6443     QtDemuxSample *sample = &stream->samples[stream->sample_index];
6444     QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6445 
6446     GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6447         sample->timestamp +
6448         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6449     if (time_position >= segment->media_start) {
6450       /* inside the segment, update time_position, looks very familiar to
6451        * GStreamer segments, doesn't it? */
6452       stream->time_position = (time_position - segment->media_start) +
6453           segment->time;
6454     } else {
6455       /* not yet in segment, time does not yet increment. This means
6456        * that we are still prerolling keyframes to the decoder so it can
6457        * decode the first sample of the segment. */
6458       stream->time_position = segment->time;
6459     }
6460   }
6461 
6462   /* combine flows */
6463   ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6464   /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6465    * we have no more data for the pad to push */
6466   if (ret == GST_FLOW_EOS)
6467     ret = GST_FLOW_OK;
6468 
6469   stream->offset_in_sample += size;
6470   if (stream->offset_in_sample >= sample_size) {
6471     gst_qtdemux_advance_sample (qtdemux, stream);
6472   }
6473   goto beach;
6474 
6475 next:
6476   gst_qtdemux_advance_sample (qtdemux, stream);
6477 
6478 beach:
6479   return ret;
6480 
6481   /* special cases */
6482 eos:
6483   {
6484     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6485     ret = GST_FLOW_EOS;
6486     goto beach;
6487   }
6488 eos_stream:
6489   {
6490     GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6491     /* EOS will be raised if all are EOS */
6492     ret = GST_FLOW_OK;
6493     goto beach;
6494   }
6495 }
6496 
6497 static void
gst_qtdemux_loop(GstPad * pad)6498 gst_qtdemux_loop (GstPad * pad)
6499 {
6500   GstQTDemux *qtdemux;
6501   guint64 cur_offset;
6502   GstFlowReturn ret;
6503 
6504   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6505 
6506   cur_offset = qtdemux->offset;
6507   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6508       cur_offset, qt_demux_state_string (qtdemux->state));
6509 
6510   switch (qtdemux->state) {
6511     case QTDEMUX_STATE_INITIAL:
6512     case QTDEMUX_STATE_HEADER:
6513       ret = gst_qtdemux_loop_state_header (qtdemux);
6514       break;
6515     case QTDEMUX_STATE_MOVIE:
6516       ret = gst_qtdemux_loop_state_movie (qtdemux);
6517       if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6518         ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6519       }
6520       break;
6521     default:
6522       /* ouch */
6523       goto invalid_state;
6524   }
6525 
6526   /* if something went wrong, pause */
6527   if (ret != GST_FLOW_OK)
6528     goto pause;
6529 
6530 done:
6531   gst_object_unref (qtdemux);
6532   return;
6533 
6534   /* ERRORS */
6535 invalid_state:
6536   {
6537     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6538         (NULL), ("streaming stopped, invalid state"));
6539     gst_pad_pause_task (pad);
6540     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6541     goto done;
6542   }
6543 pause:
6544   {
6545     const gchar *reason = gst_flow_get_name (ret);
6546 
6547     GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6548 
6549     gst_pad_pause_task (pad);
6550 
6551     /* fatal errors need special actions */
6552     /* check EOS */
6553     if (ret == GST_FLOW_EOS) {
6554       if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6555         /* we have no streams, post an error */
6556         gst_qtdemux_post_no_playable_stream_error (qtdemux);
6557       }
6558       if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6559         gint64 stop;
6560 
6561         if ((stop = qtdemux->segment.stop) == -1)
6562           stop = qtdemux->segment.duration;
6563 
6564         if (qtdemux->segment.rate >= 0) {
6565           GstMessage *message;
6566           GstEvent *event;
6567 
6568           GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6569           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6570               GST_FORMAT_TIME, stop);
6571           event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6572           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6573             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6574             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6575           }
6576           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6577           gst_qtdemux_push_event (qtdemux, event);
6578         } else {
6579           GstMessage *message;
6580           GstEvent *event;
6581 
6582           /*  For Reverse Playback */
6583           GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6584           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6585               GST_FORMAT_TIME, qtdemux->segment.start);
6586           event = gst_event_new_segment_done (GST_FORMAT_TIME,
6587               qtdemux->segment.start);
6588           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6589             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6590             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6591           }
6592           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6593           gst_qtdemux_push_event (qtdemux, event);
6594         }
6595       } else {
6596         GstEvent *event;
6597 
6598         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6599         event = gst_event_new_eos ();
6600         if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6601           gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6602         gst_qtdemux_push_event (qtdemux, event);
6603       }
6604     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6605       GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6606       gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6607     }
6608     goto done;
6609   }
6610 }
6611 
6612 /*
6613  * has_next_entry
6614  *
6615  * Returns if there are samples to be played.
6616  */
6617 static gboolean
has_next_entry(GstQTDemux * demux)6618 has_next_entry (GstQTDemux * demux)
6619 {
6620   QtDemuxStream *stream;
6621   gint i;
6622 
6623   GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6624 
6625   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6626     stream = QTDEMUX_NTH_STREAM (demux, i);
6627 
6628     if (stream->sample_index == -1) {
6629       stream->sample_index = 0;
6630       stream->offset_in_sample = 0;
6631     }
6632 
6633     if (stream->sample_index >= stream->n_samples) {
6634       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6635       continue;
6636     }
6637     GST_DEBUG_OBJECT (demux, "Found a sample");
6638     return TRUE;
6639   }
6640 
6641   GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6642   return FALSE;
6643 }
6644 
6645 /*
6646  * next_entry_size
6647  *
6648  * Returns the size of the first entry at the current offset.
6649  * If -1, there are none (which means EOS or empty file).
6650  */
6651 static guint64
next_entry_size(GstQTDemux * demux)6652 next_entry_size (GstQTDemux * demux)
6653 {
6654   QtDemuxStream *stream, *target_stream = NULL;
6655   guint64 smalloffs = (guint64) - 1;
6656   QtDemuxSample *sample;
6657   gint i;
6658 
6659   GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6660       demux->offset);
6661 
6662   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6663     stream = QTDEMUX_NTH_STREAM (demux, i);
6664 
6665     if (stream->sample_index == -1) {
6666       stream->sample_index = 0;
6667       stream->offset_in_sample = 0;
6668     }
6669 
6670     if (stream->sample_index >= stream->n_samples) {
6671       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6672       continue;
6673     }
6674 
6675     if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6676       GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6677           stream->sample_index);
6678       return -1;
6679     }
6680 
6681     sample = &stream->samples[stream->sample_index];
6682 
6683     GST_LOG_OBJECT (demux,
6684         "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6685         " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6686         stream->sample_index, sample->offset, sample->size);
6687 
6688     if (((smalloffs == -1)
6689             || (sample->offset < smalloffs)) && (sample->size)) {
6690       smalloffs = sample->offset;
6691       target_stream = stream;
6692     }
6693   }
6694 
6695   if (!target_stream)
6696     return -1;
6697 
6698   GST_LOG_OBJECT (demux,
6699       "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6700       G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6701 
6702   stream = target_stream;
6703   sample = &stream->samples[stream->sample_index];
6704 
6705   if (sample->offset >= demux->offset) {
6706     demux->todrop = sample->offset - demux->offset;
6707     return sample->size + demux->todrop;
6708   }
6709 
6710   GST_DEBUG_OBJECT (demux,
6711       "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6712   return -1;
6713 }
6714 
6715 static void
gst_qtdemux_post_progress(GstQTDemux * demux,gint num,gint denom)6716 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6717 {
6718   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6719 
6720   gst_element_post_message (GST_ELEMENT_CAST (demux),
6721       gst_message_new_element (GST_OBJECT_CAST (demux),
6722           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6723 }
6724 
6725 static gboolean
qtdemux_seek_offset(GstQTDemux * demux,guint64 offset)6726 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6727 {
6728   GstEvent *event;
6729   gboolean res = 0;
6730 
6731   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6732 
6733   event =
6734       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6735       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6736       GST_SEEK_TYPE_NONE, -1);
6737 
6738   /* store seqnum to drop flush events, they don't need to reach downstream */
6739   demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6740   res = gst_pad_push_event (demux->sinkpad, event);
6741   demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6742 
6743   return res;
6744 }
6745 
6746 /* check for seekable upstream, above and beyond a mere query */
6747 static void
gst_qtdemux_check_seekability(GstQTDemux * demux)6748 gst_qtdemux_check_seekability (GstQTDemux * demux)
6749 {
6750   GstQuery *query;
6751   gboolean seekable = FALSE;
6752   gint64 start = -1, stop = -1;
6753 
6754   if (demux->upstream_size)
6755     return;
6756 
6757   if (demux->upstream_format_is_time)
6758     return;
6759 
6760   query = gst_query_new_seeking (GST_FORMAT_BYTES);
6761   if (!gst_pad_peer_query (demux->sinkpad, query)) {
6762     GST_DEBUG_OBJECT (demux, "seeking query failed");
6763     goto done;
6764   }
6765 
6766   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6767 
6768   /* try harder to query upstream size if we didn't get it the first time */
6769   if (seekable && stop == -1) {
6770     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6771     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6772   }
6773 
6774   /* if upstream doesn't know the size, it's likely that it's not seekable in
6775    * practice even if it technically may be seekable */
6776   if (seekable && (start != 0 || stop <= start)) {
6777     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6778     seekable = FALSE;
6779   }
6780 
6781 done:
6782   gst_query_unref (query);
6783 
6784   GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6785       G_GUINT64_FORMAT ")", seekable, start, stop);
6786   demux->upstream_seekable = seekable;
6787   demux->upstream_size = seekable ? stop : -1;
6788 }
6789 
6790 static void
gst_qtdemux_drop_data(GstQTDemux * demux,gint bytes)6791 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6792 {
6793   g_return_if_fail (bytes <= demux->todrop);
6794 
6795   GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6796   gst_adapter_flush (demux->adapter, bytes);
6797   demux->neededbytes -= bytes;
6798   demux->offset += bytes;
6799   demux->todrop -= bytes;
6800 }
6801 
6802 /* PUSH-MODE only: Send a segment, if not done already. */
6803 static void
gst_qtdemux_check_send_pending_segment(GstQTDemux * demux)6804 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6805 {
6806   if (G_UNLIKELY (demux->need_segment)) {
6807     gint i;
6808 
6809     if (!demux->upstream_format_is_time) {
6810       gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6811     } else {
6812       GstEvent *segment_event;
6813       segment_event = gst_event_new_segment (&demux->segment);
6814       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6815         gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6816       gst_qtdemux_push_event (demux, segment_event);
6817     }
6818 
6819     demux->need_segment = FALSE;
6820 
6821     /* clear to send tags on all streams */
6822     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6823       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6824       gst_qtdemux_push_tags (demux, stream);
6825       if (CUR_STREAM (stream)->sparse) {
6826         GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6827         gst_pad_push_event (stream->pad,
6828             gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6829       }
6830     }
6831   }
6832 }
6833 
6834 /* Used for push mode only. */
6835 static void
gst_qtdemux_send_gap_for_segment(GstQTDemux * demux,QtDemuxStream * stream,gint segment_index,GstClockTime pos)6836 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6837     QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6838 {
6839   GstClockTime ts, dur;
6840 
6841   ts = pos;
6842   dur =
6843       stream->segments[segment_index].duration - (pos -
6844       stream->segments[segment_index].time);
6845   stream->time_position += dur;
6846 
6847   /* Only gaps with a duration of at least one second are propagated.
6848    * Same workaround as in pull mode.
6849    * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6850   if (dur >= GST_SECOND) {
6851     GstEvent *gap;
6852     gap = gst_event_new_gap (ts, dur);
6853 
6854     GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6855         "segment: %" GST_PTR_FORMAT, gap);
6856     gst_pad_push_event (stream->pad, gap);
6857   }
6858 }
6859 
6860 static GstFlowReturn
gst_qtdemux_chain(GstPad * sinkpad,GstObject * parent,GstBuffer * inbuf)6861 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6862 {
6863   GstQTDemux *demux;
6864 
6865   demux = GST_QTDEMUX (parent);
6866 
6867   GST_DEBUG_OBJECT (demux,
6868       "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6869       " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6870       G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6871       GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6872       gst_buffer_get_size (inbuf), demux->offset);
6873 
6874   if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6875     gboolean is_gap_input = FALSE;
6876     gint i;
6877 
6878     GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6879 
6880     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6881       QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
6882     }
6883 
6884     /* Check if we can land back on our feet in the case where upstream is
6885      * handling the seeking/pushing of samples with gaps in between (like
6886      * in the case of trick-mode DASH for example) */
6887     if (demux->upstream_format_is_time
6888         && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6889       for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6890         guint32 res;
6891         QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6892         GST_LOG_OBJECT (demux,
6893             "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6894             " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6895         res =
6896             gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6897             stream, GST_BUFFER_OFFSET (inbuf));
6898         if (res != -1) {
6899           QtDemuxSample *sample = &stream->samples[res];
6900           GST_LOG_OBJECT (demux,
6901               "Checking if sample %d from track-id %u is valid (offset:%"
6902               G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6903               stream->track_id, sample->offset, sample->size);
6904           if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6905             GST_LOG_OBJECT (demux,
6906                 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6907                 res);
6908             is_gap_input = TRUE;
6909             /* We can go back to standard playback mode */
6910             demux->state = QTDEMUX_STATE_MOVIE;
6911             /* Remember which sample this stream is at */
6912             stream->sample_index = res;
6913             /* Finally update all push-based values to the expected values */
6914             demux->neededbytes = stream->samples[res].size;
6915             demux->offset = GST_BUFFER_OFFSET (inbuf);
6916             demux->mdatleft =
6917                 demux->mdatsize - demux->offset + demux->mdatoffset;
6918             demux->todrop = 0;
6919           }
6920         }
6921       }
6922       if (!is_gap_input) {
6923         GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6924         /* Reset state if it's a real discont */
6925         demux->neededbytes = 16;
6926         demux->state = QTDEMUX_STATE_INITIAL;
6927         demux->offset = GST_BUFFER_OFFSET (inbuf);
6928         gst_adapter_clear (demux->adapter);
6929       }
6930     }
6931     /* Reverse fragmented playback, need to flush all we have before
6932      * consuming a new fragment.
6933      * The samples array have the timestamps calculated by accumulating the
6934      * durations but this won't work for reverse playback of fragments as
6935      * the timestamps of a subsequent fragment should be smaller than the
6936      * previously received one. */
6937     if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6938       gst_qtdemux_process_adapter (demux, TRUE);
6939       g_ptr_array_foreach (demux->active_streams,
6940           (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6941     }
6942   }
6943 
6944   gst_adapter_push (demux->adapter, inbuf);
6945 
6946   GST_DEBUG_OBJECT (demux,
6947       "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6948       demux->neededbytes, gst_adapter_available (demux->adapter));
6949 
6950   return gst_qtdemux_process_adapter (demux, FALSE);
6951 }
6952 
6953 static GstFlowReturn
gst_qtdemux_process_adapter(GstQTDemux * demux,gboolean force)6954 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6955 {
6956   GstFlowReturn ret = GST_FLOW_OK;
6957 
6958   /* we never really mean to buffer that much */
6959   if (demux->neededbytes == -1) {
6960     goto eos;
6961   }
6962 
6963   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6964       (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6965 
6966 #ifndef GST_DISABLE_GST_DEBUG
6967     {
6968       guint64 discont_offset, distance_from_discont;
6969 
6970       discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6971       distance_from_discont =
6972           gst_adapter_distance_from_discont (demux->adapter);
6973 
6974       GST_DEBUG_OBJECT (demux,
6975           "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6976           " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6977           " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6978           demux->offset, discont_offset, distance_from_discont);
6979     }
6980 #endif
6981 
6982     switch (demux->state) {
6983       case QTDEMUX_STATE_INITIAL:{
6984         const guint8 *data;
6985         guint32 fourcc;
6986         guint64 size;
6987 
6988         gst_qtdemux_check_seekability (demux);
6989 
6990         data = gst_adapter_map (demux->adapter, demux->neededbytes);
6991 
6992         /* get fourcc/length, set neededbytes */
6993         extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6994             &size, &fourcc);
6995         gst_adapter_unmap (demux->adapter);
6996         data = NULL;
6997         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6998             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6999         if (size == 0) {
7000           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7001               (_("This file is invalid and cannot be played.")),
7002               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7003                   GST_FOURCC_ARGS (fourcc)));
7004           ret = GST_FLOW_ERROR;
7005           break;
7006         }
7007         if (fourcc == FOURCC_mdat) {
7008           gint next_entry = next_entry_size (demux);
7009           if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7010                   || !demux->fragmented)) {
7011             /* we have the headers, start playback */
7012             demux->state = QTDEMUX_STATE_MOVIE;
7013             demux->neededbytes = next_entry;
7014             demux->mdatleft = size;
7015             demux->mdatsize = demux->mdatleft;
7016           } else {
7017             /* no headers yet, try to get them */
7018             guint bs;
7019             gboolean res;
7020             guint64 old, target;
7021 
7022           buffer_data:
7023             old = demux->offset;
7024             target = old + size;
7025 
7026             /* try to jump over the atom with a seek */
7027             /* only bother if it seems worth doing so,
7028              * and avoids possible upstream/server problems */
7029             if (demux->upstream_seekable &&
7030                 demux->upstream_size > 4 * (1 << 20)) {
7031               res = qtdemux_seek_offset (demux, target);
7032             } else {
7033               GST_DEBUG_OBJECT (demux, "skipping seek");
7034               res = FALSE;
7035             }
7036 
7037             if (res) {
7038               GST_DEBUG_OBJECT (demux, "seek success");
7039               /* remember the offset fo the first mdat so we can seek back to it
7040                * after we have the headers */
7041               if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7042                 demux->first_mdat = old;
7043                 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7044                     demux->first_mdat);
7045               }
7046               /* seek worked, continue reading */
7047               demux->offset = target;
7048               demux->neededbytes = 16;
7049               demux->state = QTDEMUX_STATE_INITIAL;
7050             } else {
7051               /* seek failed, need to buffer */
7052               demux->offset = old;
7053               GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7054               /* there may be multiple mdat (or alike) buffers */
7055               /* sanity check */
7056               if (demux->mdatbuffer)
7057                 bs = gst_buffer_get_size (demux->mdatbuffer);
7058               else
7059                 bs = 0;
7060               if (size + bs > 10 * (1 << 20))
7061                 goto no_moov;
7062               demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7063               demux->neededbytes = size;
7064               if (!demux->mdatbuffer)
7065                 demux->mdatoffset = demux->offset;
7066             }
7067           }
7068         } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7069           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7070               (_("This file is invalid and cannot be played.")),
7071               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7072                   GST_FOURCC_ARGS (fourcc), size));
7073           ret = GST_FLOW_ERROR;
7074           break;
7075         } else {
7076           /* this means we already started buffering and still no moov header,
7077            * let's continue buffering everything till we get moov */
7078           if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7079                   || fourcc == FOURCC_moof))
7080             goto buffer_data;
7081           demux->neededbytes = size;
7082           demux->state = QTDEMUX_STATE_HEADER;
7083         }
7084         break;
7085       }
7086       case QTDEMUX_STATE_HEADER:{
7087         const guint8 *data;
7088         guint32 fourcc;
7089 
7090         GST_DEBUG_OBJECT (demux, "In header");
7091 
7092         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7093 
7094         /* parse the header */
7095         extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7096             &fourcc);
7097         if (fourcc == FOURCC_moov) {
7098           /* in usual fragmented setup we could try to scan for more
7099            * and end up at the the moov (after mdat) again */
7100           if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7101               (!demux->fragmented
7102                   || demux->last_moov_offset == demux->offset)) {
7103             GST_DEBUG_OBJECT (demux,
7104                 "Skipping moov atom as we have (this) one already");
7105           } else {
7106             GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7107 
7108             if (demux->got_moov && demux->fragmented) {
7109               GST_DEBUG_OBJECT (demux,
7110                   "Got a second moov, clean up data from old one");
7111               if (demux->moov_node_compressed) {
7112                 g_node_destroy (demux->moov_node_compressed);
7113                 if (demux->moov_node)
7114                   g_free (demux->moov_node->data);
7115               }
7116               demux->moov_node_compressed = NULL;
7117               if (demux->moov_node)
7118                 g_node_destroy (demux->moov_node);
7119               demux->moov_node = NULL;
7120             }
7121 
7122             demux->last_moov_offset = demux->offset;
7123 
7124             /* Update streams with new moov */
7125             gst_qtdemux_stream_concat (demux,
7126                 demux->old_streams, demux->active_streams);
7127 
7128             qtdemux_parse_moov (demux, data, demux->neededbytes);
7129             qtdemux_node_dump (demux, demux->moov_node);
7130             qtdemux_parse_tree (demux);
7131             qtdemux_prepare_streams (demux);
7132             QTDEMUX_EXPOSE_LOCK (demux);
7133             qtdemux_expose_streams (demux);
7134             QTDEMUX_EXPOSE_UNLOCK (demux);
7135 
7136             demux->got_moov = TRUE;
7137 
7138             gst_qtdemux_check_send_pending_segment (demux);
7139 
7140             if (demux->moov_node_compressed) {
7141               g_node_destroy (demux->moov_node_compressed);
7142               g_free (demux->moov_node->data);
7143             }
7144             demux->moov_node_compressed = NULL;
7145             g_node_destroy (demux->moov_node);
7146             demux->moov_node = NULL;
7147             GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7148           }
7149         } else if (fourcc == FOURCC_moof) {
7150           if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7151             guint64 dist = 0;
7152             GstClockTime prev_pts;
7153             guint64 prev_offset;
7154             guint64 adapter_discont_offset, adapter_discont_dist;
7155 
7156             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7157 
7158             /*
7159              * The timestamp of the moof buffer is relevant as some scenarios
7160              * won't have the initial timestamp in the atoms. Whenever a new
7161              * buffer has started, we get that buffer's PTS and use it as a base
7162              * timestamp for the trun entries.
7163              *
7164              * To keep track of the current buffer timestamp and starting point
7165              * we use gst_adapter_prev_pts that gives us the PTS and the distance
7166              * from the beggining of the buffer, with the distance and demux->offset
7167              * we know if it is still the same buffer or not.
7168              */
7169             prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7170             prev_offset = demux->offset - dist;
7171             if (demux->fragment_start_offset == -1
7172                 || prev_offset > demux->fragment_start_offset) {
7173               demux->fragment_start_offset = prev_offset;
7174               demux->fragment_start = prev_pts;
7175               GST_DEBUG_OBJECT (demux,
7176                   "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7177                   GST_TIME_FORMAT, demux->fragment_start_offset,
7178                   GST_TIME_ARGS (demux->fragment_start));
7179             }
7180 
7181             /* We can't use prev_offset() here because this would require
7182              * upstream to set consistent and correct offsets on all buffers
7183              * since the discont. Nothing ever did that in the past and we
7184              * would break backwards compatibility here then.
7185              * Instead take the offset we had at the last discont and count
7186              * the bytes from there. This works with old code as there would
7187              * be no discont between moov and moof, and also works with
7188              * adaptivedemux which correctly sets offset and will set the
7189              * DISCONT flag accordingly when needed.
7190              *
7191              * We also only do this for upstream TIME segments as otherwise
7192              * there are potential backwards compatibility problems with
7193              * seeking in PUSH mode and upstream providing inconsistent
7194              * timestamps. */
7195             adapter_discont_offset =
7196                 gst_adapter_offset_at_discont (demux->adapter);
7197             adapter_discont_dist =
7198                 gst_adapter_distance_from_discont (demux->adapter);
7199 
7200             GST_DEBUG_OBJECT (demux,
7201                 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7202                 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7203                 demux->offset, adapter_discont_offset, adapter_discont_dist);
7204 
7205             if (demux->upstream_format_is_time) {
7206               demux->moof_offset = adapter_discont_offset;
7207               if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7208                 demux->moof_offset += adapter_discont_dist;
7209               if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7210                 demux->moof_offset = demux->offset;
7211             } else {
7212               demux->moof_offset = demux->offset;
7213             }
7214 
7215             if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7216                     demux->moof_offset, NULL)) {
7217               gst_adapter_unmap (demux->adapter);
7218               ret = GST_FLOW_ERROR;
7219               goto done;
7220             }
7221 
7222             /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7223             if (demux->mss_mode && !demux->exposed) {
7224               QTDEMUX_EXPOSE_LOCK (demux);
7225               qtdemux_expose_streams (demux);
7226               QTDEMUX_EXPOSE_UNLOCK (demux);
7227             }
7228 
7229             gst_qtdemux_check_send_pending_segment (demux);
7230           } else {
7231             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7232           }
7233         } else if (fourcc == FOURCC_ftyp) {
7234           GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7235           qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7236         } else if (fourcc == FOURCC_uuid) {
7237           GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7238           qtdemux_parse_uuid (demux, data, demux->neededbytes);
7239         } else if (fourcc == FOURCC_sidx) {
7240           GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7241           qtdemux_parse_sidx (demux, data, demux->neededbytes);
7242         } else {
7243           switch (fourcc) {
7244             case FOURCC_styp:
7245               /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7246                * FALLTHROUGH */
7247             case FOURCC_skip:
7248             case FOURCC_free:
7249               /* [free] and [skip] are padding atoms */
7250               GST_DEBUG_OBJECT (demux,
7251                   "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7252                   GST_FOURCC_ARGS (fourcc));
7253               break;
7254             default:
7255               GST_WARNING_OBJECT (demux,
7256                   "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7257                   GST_FOURCC_ARGS (fourcc));
7258               /* Let's jump that one and go back to initial state */
7259               break;
7260           }
7261         }
7262         gst_adapter_unmap (demux->adapter);
7263         data = NULL;
7264 
7265         if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7266           gsize remaining_data_size = 0;
7267 
7268           /* the mdat was before the header */
7269           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7270               QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7271           /* restore our adapter/offset view of things with upstream;
7272            * put preceding buffered data ahead of current moov data.
7273            * This should also handle evil mdat, moov, mdat cases and alike */
7274           gst_adapter_flush (demux->adapter, demux->neededbytes);
7275 
7276           /* Store any remaining data after the mdat for later usage */
7277           remaining_data_size = gst_adapter_available (demux->adapter);
7278           if (remaining_data_size > 0) {
7279             g_assert (demux->restoredata_buffer == NULL);
7280             demux->restoredata_buffer =
7281                 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7282             demux->restoredata_offset = demux->offset + demux->neededbytes;
7283             GST_DEBUG_OBJECT (demux,
7284                 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7285                 G_GUINT64_FORMAT, remaining_data_size,
7286                 demux->restoredata_offset);
7287           }
7288 
7289           gst_adapter_push (demux->adapter, demux->mdatbuffer);
7290           demux->mdatbuffer = NULL;
7291           demux->offset = demux->mdatoffset;
7292           demux->neededbytes = next_entry_size (demux);
7293           demux->state = QTDEMUX_STATE_MOVIE;
7294           demux->mdatleft = gst_adapter_available (demux->adapter);
7295           demux->mdatsize = demux->mdatleft;
7296         } else {
7297           GST_DEBUG_OBJECT (demux, "Carrying on normally");
7298           gst_adapter_flush (demux->adapter, demux->neededbytes);
7299 
7300           /* only go back to the mdat if there are samples to play */
7301           if (demux->got_moov && demux->first_mdat != -1
7302               && has_next_entry (demux)) {
7303             gboolean res;
7304 
7305             /* we need to seek back */
7306             res = qtdemux_seek_offset (demux, demux->first_mdat);
7307             if (res) {
7308               demux->offset = demux->first_mdat;
7309             } else {
7310               GST_DEBUG_OBJECT (demux, "Seek back failed");
7311             }
7312           } else {
7313             demux->offset += demux->neededbytes;
7314           }
7315           demux->neededbytes = 16;
7316           demux->state = QTDEMUX_STATE_INITIAL;
7317         }
7318 
7319         break;
7320       }
7321       case QTDEMUX_STATE_BUFFER_MDAT:{
7322         GstBuffer *buf;
7323         guint8 fourcc[4];
7324 
7325         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7326             demux->offset);
7327         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7328         gst_buffer_extract (buf, 0, fourcc, 4);
7329         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7330             GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7331         if (demux->mdatbuffer)
7332           demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7333         else
7334           demux->mdatbuffer = buf;
7335         demux->offset += demux->neededbytes;
7336         demux->neededbytes = 16;
7337         demux->state = QTDEMUX_STATE_INITIAL;
7338         gst_qtdemux_post_progress (demux, 1, 1);
7339 
7340         break;
7341       }
7342       case QTDEMUX_STATE_MOVIE:{
7343         QtDemuxStream *stream = NULL;
7344         QtDemuxSample *sample;
7345         GstClockTime dts, pts, duration;
7346         gboolean keyframe;
7347         gint i;
7348 
7349         GST_DEBUG_OBJECT (demux,
7350             "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7351 
7352         if (demux->fragmented) {
7353           GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7354               demux->mdatleft);
7355           if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7356             /* if needed data starts within this atom,
7357              * then it should not exceed this atom */
7358             if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7359               GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7360                   (_("This file is invalid and cannot be played.")),
7361                   ("sample data crosses atom boundary"));
7362               ret = GST_FLOW_ERROR;
7363               break;
7364             }
7365             demux->mdatleft -= demux->neededbytes;
7366           } else {
7367             GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7368             /* so we are dropping more than left in this atom */
7369             gst_qtdemux_drop_data (demux, demux->mdatleft);
7370             demux->mdatleft = 0;
7371 
7372             /* need to resume atom parsing so we do not miss any other pieces */
7373             demux->state = QTDEMUX_STATE_INITIAL;
7374             demux->neededbytes = 16;
7375 
7376             /* check if there was any stored post mdat data from previous buffers */
7377             if (demux->restoredata_buffer) {
7378               g_assert (gst_adapter_available (demux->adapter) == 0);
7379 
7380               gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7381               demux->restoredata_buffer = NULL;
7382               demux->offset = demux->restoredata_offset;
7383             }
7384 
7385             break;
7386           }
7387         }
7388 
7389         if (demux->todrop) {
7390           if (demux->cenc_aux_info_offset > 0) {
7391             GstByteReader br;
7392             const guint8 *data;
7393 
7394             GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7395             data = gst_adapter_map (demux->adapter, demux->todrop);
7396             gst_byte_reader_init (&br, data + 8, demux->todrop);
7397             if (!qtdemux_parse_cenc_aux_info (demux,
7398                     QTDEMUX_NTH_STREAM (demux, 0), &br,
7399                     demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7400               GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7401               ret = GST_FLOW_ERROR;
7402               gst_adapter_unmap (demux->adapter);
7403               g_free (demux->cenc_aux_info_sizes);
7404               demux->cenc_aux_info_sizes = NULL;
7405               goto done;
7406             }
7407             demux->cenc_aux_info_offset = 0;
7408             g_free (demux->cenc_aux_info_sizes);
7409             demux->cenc_aux_info_sizes = NULL;
7410             gst_adapter_unmap (demux->adapter);
7411           }
7412           gst_qtdemux_drop_data (demux, demux->todrop);
7413         }
7414 
7415         /* first buffer? */
7416         /* initial newsegment sent here after having added pads,
7417          * possible others in sink_event */
7418         gst_qtdemux_check_send_pending_segment (demux);
7419 
7420         /* Figure out which stream this packet belongs to */
7421         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7422           stream = QTDEMUX_NTH_STREAM (demux, i);
7423           if (stream->sample_index >= stream->n_samples) {
7424             /* reset to be checked below G_UNLIKELY (stream == NULL) */
7425             stream = NULL;
7426             continue;
7427           }
7428           GST_LOG_OBJECT (demux,
7429               "Checking track-id %u (sample_index:%d / offset:%"
7430               G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7431               stream->sample_index,
7432               stream->samples[stream->sample_index].offset,
7433               stream->samples[stream->sample_index].size);
7434 
7435           if (stream->samples[stream->sample_index].offset == demux->offset)
7436             break;
7437         }
7438 
7439         if (G_UNLIKELY (stream == NULL))
7440           goto unknown_stream;
7441 
7442         gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7443 
7444         if (stream->new_caps) {
7445           gst_qtdemux_configure_stream (demux, stream);
7446         }
7447 
7448         /* Put data in a buffer, set timestamps, caps, ... */
7449         sample = &stream->samples[stream->sample_index];
7450 
7451         if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7452           GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7453               GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7454 
7455           dts = QTSAMPLE_DTS (stream, sample);
7456           pts = QTSAMPLE_PTS (stream, sample);
7457           duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7458           keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7459 
7460           /* check for segment end */
7461           if (G_UNLIKELY (demux->segment.stop != -1
7462                   && demux->segment.stop <= pts && stream->on_keyframe)
7463               && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7464             GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7465             stream->time_position = GST_CLOCK_TIME_NONE;        /* this means EOS */
7466 
7467             /* skip this data, stream is EOS */
7468             gst_adapter_flush (demux->adapter, demux->neededbytes);
7469             demux->offset += demux->neededbytes;
7470 
7471             /* check if all streams are eos */
7472             ret = GST_FLOW_EOS;
7473             for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7474               if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7475                 ret = GST_FLOW_OK;
7476                 break;
7477               }
7478             }
7479           } else {
7480             GstBuffer *outbuf;
7481 
7482             outbuf =
7483                 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7484 
7485             /* FIXME: should either be an assert or a plain check */
7486             g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7487 
7488             ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7489                 dts, pts, duration, keyframe, dts, demux->offset);
7490           }
7491 
7492           /* combine flows */
7493           ret = gst_qtdemux_combine_flows (demux, stream, ret);
7494         } else {
7495           /* skip this data, stream is EOS */
7496           gst_adapter_flush (demux->adapter, demux->neededbytes);
7497         }
7498 
7499         stream->sample_index++;
7500         stream->offset_in_sample = 0;
7501 
7502         /* update current offset and figure out size of next buffer */
7503         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7504             demux->offset, demux->neededbytes);
7505         demux->offset += demux->neededbytes;
7506         GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7507             demux->offset);
7508 
7509 
7510         if (ret == GST_FLOW_EOS) {
7511           GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7512           demux->neededbytes = -1;
7513           goto eos;
7514         }
7515 
7516         if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7517           if (demux->fragmented) {
7518             GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7519             /* there may be more to follow, only finish this atom */
7520             demux->todrop = demux->mdatleft;
7521             demux->neededbytes = demux->todrop;
7522             break;
7523           }
7524           goto eos;
7525         }
7526         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7527           goto non_ok_unlinked_flow;
7528         }
7529         break;
7530       }
7531       default:
7532         goto invalid_state;
7533     }
7534   }
7535 
7536   /* when buffering movie data, at least show user something is happening */
7537   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7538       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7539     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7540         demux->neededbytes);
7541   }
7542 done:
7543 
7544   return ret;
7545 
7546   /* ERRORS */
7547 non_ok_unlinked_flow:
7548   {
7549     GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7550         gst_flow_get_name (ret));
7551     return ret;
7552   }
7553 unknown_stream:
7554   {
7555     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7556     ret = GST_FLOW_ERROR;
7557     goto done;
7558   }
7559 eos:
7560   {
7561     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7562     ret = GST_FLOW_EOS;
7563     goto done;
7564   }
7565 invalid_state:
7566   {
7567     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7568         (NULL), ("qtdemuxer invalid state %d", demux->state));
7569     ret = GST_FLOW_ERROR;
7570     goto done;
7571   }
7572 no_moov:
7573   {
7574     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7575         (NULL), ("no 'moov' atom within the first 10 MB"));
7576     ret = GST_FLOW_ERROR;
7577     goto done;
7578   }
7579 }
7580 
7581 static gboolean
qtdemux_sink_activate(GstPad * sinkpad,GstObject * parent)7582 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7583 {
7584   GstQuery *query;
7585   gboolean pull_mode;
7586 
7587   query = gst_query_new_scheduling ();
7588 
7589   if (!gst_pad_peer_query (sinkpad, query)) {
7590     gst_query_unref (query);
7591     goto activate_push;
7592   }
7593 
7594   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7595       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7596   gst_query_unref (query);
7597 
7598   if (!pull_mode)
7599     goto activate_push;
7600 
7601   GST_DEBUG_OBJECT (sinkpad, "activating pull");
7602   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7603 
7604 activate_push:
7605   {
7606     GST_DEBUG_OBJECT (sinkpad, "activating push");
7607     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7608   }
7609 }
7610 
7611 static gboolean
qtdemux_sink_activate_mode(GstPad * sinkpad,GstObject * parent,GstPadMode mode,gboolean active)7612 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7613     GstPadMode mode, gboolean active)
7614 {
7615   gboolean res;
7616   GstQTDemux *demux = GST_QTDEMUX (parent);
7617 
7618   switch (mode) {
7619     case GST_PAD_MODE_PUSH:
7620       demux->pullbased = FALSE;
7621       res = TRUE;
7622       break;
7623     case GST_PAD_MODE_PULL:
7624       if (active) {
7625         demux->pullbased = TRUE;
7626         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7627             sinkpad, NULL);
7628       } else {
7629         res = gst_pad_stop_task (sinkpad);
7630       }
7631       break;
7632     default:
7633       res = FALSE;
7634       break;
7635   }
7636   return res;
7637 }
7638 
7639 #ifdef HAVE_ZLIB
7640 static void *
qtdemux_inflate(void * z_buffer,guint z_length,guint * length)7641 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7642 {
7643   guint8 *buffer;
7644   z_stream z;
7645   int ret;
7646 
7647   memset (&z, 0, sizeof (z));
7648   z.zalloc = NULL;
7649   z.zfree = NULL;
7650   z.opaque = NULL;
7651 
7652   if ((ret = inflateInit (&z)) != Z_OK) {
7653     GST_ERROR ("inflateInit() returned %d", ret);
7654     return NULL;
7655   }
7656 
7657   z.next_in = z_buffer;
7658   z.avail_in = z_length;
7659 
7660   buffer = (guint8 *) g_malloc (*length);
7661   z.avail_out = *length;
7662   z.next_out = (Bytef *) buffer;
7663   do {
7664     ret = inflate (&z, Z_NO_FLUSH);
7665     if (ret == Z_STREAM_END) {
7666       break;
7667     } else if (ret != Z_OK) {
7668       GST_WARNING ("inflate() returned %d", ret);
7669       break;
7670     }
7671 
7672     *length += 4096;
7673     buffer = (guint8 *) g_realloc (buffer, *length);
7674     z.next_out = (Bytef *) (buffer + z.total_out);
7675     z.avail_out += 4096;
7676   } while (z.avail_in > 0);
7677 
7678   if (ret != Z_STREAM_END) {
7679     g_free (buffer);
7680     buffer = NULL;
7681     *length = 0;
7682   } else {
7683     *length = z.total_out;
7684   }
7685 
7686   inflateEnd (&z);
7687 
7688   return buffer;
7689 }
7690 #endif /* HAVE_ZLIB */
7691 
7692 static gboolean
qtdemux_parse_moov(GstQTDemux * qtdemux,const guint8 * buffer,guint length)7693 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7694 {
7695   GNode *cmov;
7696 
7697   qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7698 
7699   /* counts as header data */
7700   qtdemux->header_size += length;
7701 
7702   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7703   qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7704 
7705   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7706   if (cmov) {
7707     guint32 method;
7708     GNode *dcom;
7709     GNode *cmvd;
7710     guint32 dcom_len;
7711 
7712     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7713     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7714     if (dcom == NULL || cmvd == NULL)
7715       goto invalid_compression;
7716 
7717     dcom_len = QT_UINT32 (dcom->data);
7718     if (dcom_len < 12)
7719       goto invalid_compression;
7720 
7721     method = QT_FOURCC ((guint8 *) dcom->data + 8);
7722     switch (method) {
7723 #ifdef HAVE_ZLIB
7724       case FOURCC_zlib:{
7725         guint uncompressed_length;
7726         guint compressed_length;
7727         guint8 *buf;
7728         guint32 cmvd_len;
7729 
7730         cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7731         if (cmvd_len < 12)
7732           goto invalid_compression;
7733 
7734         uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7735         compressed_length = cmvd_len - 12;
7736         GST_LOG ("length = %u", uncompressed_length);
7737 
7738         buf =
7739             (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7740             compressed_length, &uncompressed_length);
7741 
7742         if (buf) {
7743           qtdemux->moov_node_compressed = qtdemux->moov_node;
7744           qtdemux->moov_node = g_node_new (buf);
7745 
7746           qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7747               uncompressed_length);
7748         }
7749         break;
7750       }
7751 #endif /* HAVE_ZLIB */
7752       default:
7753         GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7754             "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7755         break;
7756     }
7757   }
7758   return TRUE;
7759 
7760   /* ERRORS */
7761 invalid_compression:
7762   {
7763     GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7764     return FALSE;
7765   }
7766 }
7767 
7768 static gboolean
qtdemux_parse_container(GstQTDemux * qtdemux,GNode * node,const guint8 * buf,const guint8 * end)7769 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7770     const guint8 * end)
7771 {
7772   while (G_UNLIKELY (buf < end)) {
7773     GNode *child;
7774     guint32 len;
7775 
7776     if (G_UNLIKELY (buf + 4 > end)) {
7777       GST_LOG_OBJECT (qtdemux, "buffer overrun");
7778       break;
7779     }
7780     len = QT_UINT32 (buf);
7781     if (G_UNLIKELY (len == 0)) {
7782       GST_LOG_OBJECT (qtdemux, "empty container");
7783       break;
7784     }
7785     if (G_UNLIKELY (len < 8)) {
7786       GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7787       break;
7788     }
7789     if (G_UNLIKELY (len > (end - buf))) {
7790       GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7791           (gint) (end - buf));
7792       break;
7793     }
7794 
7795     child = g_node_new ((guint8 *) buf);
7796     g_node_append (node, child);
7797     GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7798     qtdemux_parse_node (qtdemux, child, buf, len);
7799 
7800     buf += len;
7801   }
7802   return TRUE;
7803 }
7804 
7805 static gboolean
qtdemux_parse_theora_extension(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * xdxt)7806 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7807     GNode * xdxt)
7808 {
7809   int len = QT_UINT32 (xdxt->data);
7810   guint8 *buf = xdxt->data;
7811   guint8 *end = buf + len;
7812   GstBuffer *buffer;
7813 
7814   /* skip size and type */
7815   buf += 8;
7816   end -= 8;
7817 
7818   while (buf < end) {
7819     gint size;
7820     guint32 type;
7821 
7822     size = QT_UINT32 (buf);
7823     type = QT_FOURCC (buf + 4);
7824 
7825     GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7826 
7827     if (buf + size > end || size <= 0)
7828       break;
7829 
7830     buf += 8;
7831     size -= 8;
7832 
7833     GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7834         GST_FOURCC_ARGS (type));
7835 
7836     switch (type) {
7837       case FOURCC_tCtH:
7838         buffer = gst_buffer_new_and_alloc (size);
7839         gst_buffer_fill (buffer, 0, buf, size);
7840         stream->buffers = g_slist_append (stream->buffers, buffer);
7841         GST_LOG_OBJECT (qtdemux, "parsing theora header");
7842         break;
7843       case FOURCC_tCt_:
7844         buffer = gst_buffer_new_and_alloc (size);
7845         gst_buffer_fill (buffer, 0, buf, size);
7846         stream->buffers = g_slist_append (stream->buffers, buffer);
7847         GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7848         break;
7849       case FOURCC_tCtC:
7850         buffer = gst_buffer_new_and_alloc (size);
7851         gst_buffer_fill (buffer, 0, buf, size);
7852         stream->buffers = g_slist_append (stream->buffers, buffer);
7853         GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7854         break;
7855       default:
7856         GST_WARNING_OBJECT (qtdemux,
7857             "unknown theora cookie %" GST_FOURCC_FORMAT,
7858             GST_FOURCC_ARGS (type));
7859         break;
7860     }
7861     buf += size;
7862   }
7863   return TRUE;
7864 }
7865 
7866 static gboolean
qtdemux_parse_node(GstQTDemux * qtdemux,GNode * node,const guint8 * buffer,guint length)7867 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7868     guint length)
7869 {
7870   guint32 fourcc = 0;
7871   guint32 node_length = 0;
7872   const QtNodeType *type;
7873   const guint8 *end;
7874 
7875   GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7876 
7877   if (G_UNLIKELY (length < 8))
7878     goto not_enough_data;
7879 
7880   node_length = QT_UINT32 (buffer);
7881   fourcc = QT_FOURCC (buffer + 4);
7882 
7883   /* ignore empty nodes */
7884   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7885     return TRUE;
7886 
7887   type = qtdemux_type_get (fourcc);
7888 
7889   end = buffer + length;
7890 
7891   GST_LOG_OBJECT (qtdemux,
7892       "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7893       GST_FOURCC_ARGS (fourcc), node_length, type->name);
7894 
7895   if (node_length > length)
7896     goto broken_atom_size;
7897 
7898   if (type->flags & QT_FLAG_CONTAINER) {
7899     qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7900   } else {
7901     switch (fourcc) {
7902       case FOURCC_stsd:
7903       {
7904         if (node_length < 20) {
7905           GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7906           break;
7907         }
7908         GST_DEBUG_OBJECT (qtdemux,
7909             "parsing stsd (sample table, sample description) atom");
7910         /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7911         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7912         break;
7913       }
7914       case FOURCC_mp4a:
7915       case FOURCC_alac:
7916       case FOURCC_fLaC:
7917       {
7918         guint32 version;
7919         guint32 offset;
7920         guint min_size;
7921 
7922         /* also read alac (or whatever) in stead of mp4a in the following,
7923          * since a similar layout is used in other cases as well */
7924         if (fourcc == FOURCC_mp4a)
7925           min_size = 20;
7926         else if (fourcc == FOURCC_fLaC)
7927           min_size = 86;
7928         else
7929           min_size = 40;
7930 
7931         /* There are two things we might encounter here: a true mp4a atom, and
7932            an mp4a entry in an stsd atom. The latter is what we're interested
7933            in, and it looks like an atom, but isn't really one. The true mp4a
7934            atom is short, so we detect it based on length here. */
7935         if (length < min_size) {
7936           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7937               GST_FOURCC_ARGS (fourcc));
7938           break;
7939         }
7940 
7941         /* 'version' here is the sound sample description version. Types 0 and
7942            1 are documented in the QTFF reference, but type 2 is not: it's
7943            described in Apple header files instead (struct SoundDescriptionV2
7944            in Movies.h) */
7945         version = QT_UINT16 (buffer + 16);
7946 
7947         GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7948             GST_FOURCC_ARGS (fourcc), version);
7949 
7950         /* parse any esds descriptors */
7951         switch (version) {
7952           case 0:
7953             offset = 0x24;
7954             break;
7955           case 1:
7956             offset = 0x34;
7957             break;
7958           case 2:
7959             offset = 0x48;
7960             break;
7961           default:
7962             GST_WARNING_OBJECT (qtdemux,
7963                 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7964                 GST_FOURCC_ARGS (fourcc), version);
7965             offset = 0;
7966             break;
7967         }
7968         if (offset)
7969           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7970         break;
7971       }
7972       case FOURCC_mp4v:
7973       case FOURCC_MP4V:
7974       case FOURCC_fmp4:
7975       case FOURCC_FMP4:
7976       case FOURCC_apcs:
7977       case FOURCC_apch:
7978       case FOURCC_apcn:
7979       case FOURCC_apco:
7980       case FOURCC_ap4h:
7981       case FOURCC_xvid:
7982       case FOURCC_XVID:
7983       case FOURCC_H264:
7984       case FOURCC_avc1:
7985       case FOURCC_avc3:
7986       case FOURCC_H265:
7987       case FOURCC_hvc1:
7988       case FOURCC_hev1:
7989       case FOURCC_mjp2:
7990       case FOURCC_encv:
7991       {
7992         guint32 version;
7993         guint32 str_len;
7994 
7995         /* codec_data is contained inside these atoms, which all have
7996          * the same format. */
7997         /* video sample description size is 86 bytes without extension.
7998          * node_length have to be bigger than 86 bytes because video sample
7999          * description can include extenstions such as esds, fiel, glbl, etc. */
8000         if (node_length < 86) {
8001           GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8002               " sample description length too short (%u < 86)",
8003               GST_FOURCC_ARGS (fourcc), node_length);
8004           break;
8005         }
8006 
8007         GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8008             GST_FOURCC_ARGS (fourcc));
8009 
8010         /* version (2 bytes) : this is set to 0, unless a compressor has changed
8011          *              its data format.
8012          * revision level (2 bytes) : must be set to 0. */
8013         version = QT_UINT32 (buffer + 16);
8014         GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8015 
8016         /* compressor name : PASCAL string and informative purposes
8017          * first byte : the number of bytes to be displayed.
8018          *              it has to be less than 32 because it is reserved
8019          *              space of 32 bytes total including itself. */
8020         str_len = QT_UINT8 (buffer + 50);
8021         if (str_len < 32)
8022           GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8023               (char *) buffer + 51);
8024         else
8025           GST_WARNING_OBJECT (qtdemux,
8026               "compressorname length too big (%u > 31)", str_len);
8027 
8028         GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8029             end - buffer);
8030         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8031         break;
8032       }
8033       case FOURCC_meta:
8034       {
8035         GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8036 
8037         /* You are reading this correctly. QTFF specifies that the
8038          * metadata atom is a short atom, whereas ISO BMFF specifies
8039          * it's a full atom. But since so many people are doing things
8040          * differently, we actually peek into the atom to see which
8041          * variant it is */
8042         if (length < 16) {
8043           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8044               GST_FOURCC_ARGS (fourcc));
8045           break;
8046         }
8047         if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8048           /* Variant 1: What QTFF specifies. 'meta' is a short header which
8049            * starts with a 'hdlr' atom */
8050           qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8051         } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8052           /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8053            * with version/flags both set to zero */
8054           qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8055         } else
8056           GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8057         break;
8058       }
8059       case FOURCC_mp4s:
8060       {
8061         GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8062         /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8063         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8064         break;
8065       }
8066       case FOURCC_XiTh:
8067       {
8068         guint32 version;
8069         guint32 offset;
8070 
8071         if (length < 16) {
8072           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8073               GST_FOURCC_ARGS (fourcc));
8074           break;
8075         }
8076 
8077         version = QT_UINT32 (buffer + 12);
8078         GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8079 
8080         switch (version) {
8081           case 0x00000001:
8082             offset = 0x62;
8083             break;
8084           default:
8085             GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8086             offset = 0;
8087             break;
8088         }
8089         if (offset) {
8090           if (length < offset) {
8091             GST_WARNING_OBJECT (qtdemux,
8092                 "skipping too small %" GST_FOURCC_FORMAT " box",
8093                 GST_FOURCC_ARGS (fourcc));
8094             break;
8095           }
8096           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8097         }
8098         break;
8099       }
8100       case FOURCC_in24:
8101       {
8102         qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8103         break;
8104       }
8105       case FOURCC_uuid:
8106       {
8107         qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8108         break;
8109       }
8110       case FOURCC_enca:
8111       {
8112         qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8113         break;
8114       }
8115       default:
8116         if (!strcmp (type->name, "unknown"))
8117           GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8118         break;
8119     }
8120   }
8121   GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8122       GST_FOURCC_ARGS (fourcc));
8123   return TRUE;
8124 
8125 /* ERRORS */
8126 not_enough_data:
8127   {
8128     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8129         (_("This file is corrupt and cannot be played.")),
8130         ("Not enough data for an atom header, got only %u bytes", length));
8131     return FALSE;
8132   }
8133 broken_atom_size:
8134   {
8135     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8136         (_("This file is corrupt and cannot be played.")),
8137         ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8138             "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8139             length));
8140     return FALSE;
8141   }
8142 }
8143 
8144 static GNode *
qtdemux_tree_get_child_by_type(GNode * node,guint32 fourcc)8145 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
8146 {
8147   GNode *child;
8148   guint8 *buffer;
8149   guint32 child_fourcc;
8150 
8151   for (child = g_node_first_child (node); child;
8152       child = g_node_next_sibling (child)) {
8153     buffer = (guint8 *) child->data;
8154 
8155     child_fourcc = QT_FOURCC (buffer + 4);
8156 
8157     if (G_UNLIKELY (child_fourcc == fourcc)) {
8158       return child;
8159     }
8160   }
8161   return NULL;
8162 }
8163 
8164 static GNode *
qtdemux_tree_get_child_by_type_full(GNode * node,guint32 fourcc,GstByteReader * parser)8165 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
8166     GstByteReader * parser)
8167 {
8168   GNode *child;
8169   guint8 *buffer;
8170   guint32 child_fourcc, child_len;
8171 
8172   for (child = g_node_first_child (node); child;
8173       child = g_node_next_sibling (child)) {
8174     buffer = (guint8 *) child->data;
8175 
8176     child_len = QT_UINT32 (buffer);
8177     child_fourcc = QT_FOURCC (buffer + 4);
8178 
8179     if (G_UNLIKELY (child_fourcc == fourcc)) {
8180       if (G_UNLIKELY (child_len < (4 + 4)))
8181         return NULL;
8182       /* FIXME: must verify if atom length < parent atom length */
8183       gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8184       return child;
8185     }
8186   }
8187   return NULL;
8188 }
8189 
8190 static GNode *
qtdemux_tree_get_child_by_index(GNode * node,guint index)8191 qtdemux_tree_get_child_by_index (GNode * node, guint index)
8192 {
8193   return g_node_nth_child (node, index);
8194 }
8195 
8196 static GNode *
qtdemux_tree_get_sibling_by_type_full(GNode * node,guint32 fourcc,GstByteReader * parser)8197 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
8198     GstByteReader * parser)
8199 {
8200   GNode *child;
8201   guint8 *buffer;
8202   guint32 child_fourcc, child_len;
8203 
8204   for (child = g_node_next_sibling (node); child;
8205       child = g_node_next_sibling (child)) {
8206     buffer = (guint8 *) child->data;
8207 
8208     child_fourcc = QT_FOURCC (buffer + 4);
8209 
8210     if (child_fourcc == fourcc) {
8211       if (parser) {
8212         child_len = QT_UINT32 (buffer);
8213         if (G_UNLIKELY (child_len < (4 + 4)))
8214           return NULL;
8215         /* FIXME: must verify if atom length < parent atom length */
8216         gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8217       }
8218       return child;
8219     }
8220   }
8221   return NULL;
8222 }
8223 
8224 static GNode *
qtdemux_tree_get_sibling_by_type(GNode * node,guint32 fourcc)8225 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
8226 {
8227   return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
8228 }
8229 
8230 static void
qtdemux_do_allocation(QtDemuxStream * stream,GstQTDemux * qtdemux)8231 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8232 {
8233 /* FIXME: This can only reliably work if demuxers have a
8234  * separate streaming thread per srcpad. This should be
8235  * done in a demuxer base class, which integrates parts
8236  * of multiqueue
8237  *
8238  * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8239  */
8240 #if 0
8241   GstQuery *query;
8242 
8243   query = gst_query_new_allocation (stream->caps, FALSE);
8244 
8245   if (!gst_pad_peer_query (stream->pad, query)) {
8246     /* not a problem, just debug a little */
8247     GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8248   }
8249 
8250   if (stream->allocator)
8251     gst_object_unref (stream->allocator);
8252 
8253   if (gst_query_get_n_allocation_params (query) > 0) {
8254     /* try the allocator */
8255     gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8256         &stream->params);
8257     stream->use_allocator = TRUE;
8258   } else {
8259     stream->allocator = NULL;
8260     gst_allocation_params_init (&stream->params);
8261     stream->use_allocator = FALSE;
8262   }
8263   gst_query_unref (query);
8264 #endif
8265 }
8266 
8267 static gboolean
pad_query(const GValue * item,GValue * value,gpointer user_data)8268 pad_query (const GValue * item, GValue * value, gpointer user_data)
8269 {
8270   GstPad *pad = g_value_get_object (item);
8271   GstQuery *query = user_data;
8272   gboolean res;
8273 
8274   res = gst_pad_peer_query (pad, query);
8275 
8276   if (res) {
8277     g_value_set_boolean (value, TRUE);
8278     return FALSE;
8279   }
8280 
8281   GST_INFO_OBJECT (pad, "pad peer query failed");
8282   return TRUE;
8283 }
8284 
8285 static gboolean
gst_qtdemux_run_query(GstElement * element,GstQuery * query,GstPadDirection direction)8286 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8287     GstPadDirection direction)
8288 {
8289   GstIterator *it;
8290   GstIteratorFoldFunction func = pad_query;
8291   GValue res = { 0, };
8292 
8293   g_value_init (&res, G_TYPE_BOOLEAN);
8294   g_value_set_boolean (&res, FALSE);
8295 
8296   /* Ask neighbor */
8297   if (direction == GST_PAD_SRC)
8298     it = gst_element_iterate_src_pads (element);
8299   else
8300     it = gst_element_iterate_sink_pads (element);
8301 
8302   while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8303     gst_iterator_resync (it);
8304 
8305   gst_iterator_free (it);
8306 
8307   return g_value_get_boolean (&res);
8308 }
8309 
8310 static void
gst_qtdemux_request_protection_context(GstQTDemux * qtdemux,QtDemuxStream * stream)8311 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8312     QtDemuxStream * stream)
8313 {
8314   GstQuery *query;
8315   GstContext *ctxt;
8316   GstElement *element = GST_ELEMENT (qtdemux);
8317   GstStructure *st;
8318   gchar **filtered_sys_ids;
8319   GValue event_list = G_VALUE_INIT;
8320   GList *walk;
8321 
8322   /* 1. Check if we already have the context. */
8323   if (qtdemux->preferred_protection_system_id != NULL) {
8324     GST_LOG_OBJECT (element,
8325         "already have the protection context, no need to request it again");
8326     return;
8327   }
8328 
8329   g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8330   filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8331       (const gchar **) qtdemux->protection_system_ids->pdata);
8332 
8333   g_ptr_array_remove_index (qtdemux->protection_system_ids,
8334       qtdemux->protection_system_ids->len - 1);
8335   GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8336       "decryptors for %u of them, running context request",
8337       qtdemux->protection_system_ids->len,
8338       filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8339 
8340 
8341   if (stream->protection_scheme_event_queue.length) {
8342     GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8343         stream->protection_scheme_event_queue.length);
8344     walk = stream->protection_scheme_event_queue.tail;
8345   } else {
8346     GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8347         qtdemux->protection_event_queue.length);
8348     walk = qtdemux->protection_event_queue.tail;
8349   }
8350 
8351   g_value_init (&event_list, GST_TYPE_LIST);
8352   for (; walk; walk = g_list_previous (walk)) {
8353     GValue *event_value = g_new0 (GValue, 1);
8354     g_value_init (event_value, GST_TYPE_EVENT);
8355     g_value_set_boxed (event_value, walk->data);
8356     gst_value_list_append_and_take_value (&event_list, event_value);
8357   }
8358 
8359   /*  2a) Query downstream with GST_QUERY_CONTEXT for the context and
8360    *      check if downstream already has a context of the specific type
8361    *  2b) Query upstream as above.
8362    */
8363   query = gst_query_new_context ("drm-preferred-decryption-system-id");
8364   st = gst_query_writable_structure (query);
8365   gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8366       "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8367       NULL);
8368   gst_structure_set_value (st, "stream-encryption-events", &event_list);
8369   if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8370     gst_query_parse_context (query, &ctxt);
8371     GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8372     gst_element_set_context (element, ctxt);
8373   } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8374     gst_query_parse_context (query, &ctxt);
8375     GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8376     gst_element_set_context (element, ctxt);
8377   } else {
8378     /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8379      *    the required context type and afterwards check if a
8380      *    usable context was set now as in 1). The message could
8381      *    be handled by the parent bins of the element and the
8382      *    application.
8383      */
8384     GstMessage *msg;
8385 
8386     GST_INFO_OBJECT (element, "posting need context message");
8387     msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8388         "drm-preferred-decryption-system-id");
8389     st = (GstStructure *) gst_message_get_structure (msg);
8390     gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8391         "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8392         NULL);
8393 
8394     gst_structure_set_value (st, "stream-encryption-events", &event_list);
8395     gst_element_post_message (element, msg);
8396   }
8397 
8398   g_strfreev (filtered_sys_ids);
8399   g_value_unset (&event_list);
8400   gst_query_unref (query);
8401 }
8402 
8403 static gboolean
gst_qtdemux_configure_protected_caps(GstQTDemux * qtdemux,QtDemuxStream * stream)8404 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8405     QtDemuxStream * stream)
8406 {
8407   GstStructure *s;
8408   const gchar *selected_system = NULL;
8409 
8410   g_return_val_if_fail (qtdemux != NULL, FALSE);
8411   g_return_val_if_fail (stream != NULL, FALSE);
8412   g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8413       FALSE);
8414 
8415   if (stream->protection_scheme_type != FOURCC_cenc) {
8416     GST_ERROR_OBJECT (qtdemux,
8417         "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8418         GST_FOURCC_ARGS (stream->protection_scheme_type));
8419     return FALSE;
8420   }
8421   if (qtdemux->protection_system_ids == NULL) {
8422     GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
8423         "cenc protection system information has been found");
8424     return FALSE;
8425   }
8426 
8427   gst_qtdemux_request_protection_context (qtdemux, stream);
8428   if (qtdemux->preferred_protection_system_id != NULL) {
8429     const gchar *preferred_system_array[] =
8430         { qtdemux->preferred_protection_system_id, NULL };
8431 
8432     selected_system = gst_protection_select_system (preferred_system_array);
8433 
8434     if (selected_system) {
8435       GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8436           qtdemux->preferred_protection_system_id);
8437     } else {
8438       GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8439           "because there is no available decryptor",
8440           qtdemux->preferred_protection_system_id);
8441     }
8442   }
8443 
8444   if (!selected_system) {
8445     g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8446     selected_system = gst_protection_select_system ((const gchar **)
8447         qtdemux->protection_system_ids->pdata);
8448     g_ptr_array_remove_index (qtdemux->protection_system_ids,
8449         qtdemux->protection_system_ids->len - 1);
8450   }
8451 
8452   if (!selected_system) {
8453     GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8454         "suitable decryptor element has been found");
8455     return FALSE;
8456   }
8457 
8458   GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8459       selected_system);
8460 
8461   s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8462   if (!gst_structure_has_name (s, "application/x-cenc")) {
8463     gst_structure_set (s,
8464         "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8465         GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8466         NULL);
8467     gst_structure_set_name (s, "application/x-cenc");
8468   }
8469   return TRUE;
8470 }
8471 
8472 static gboolean
gst_qtdemux_guess_framerate(GstQTDemux * qtdemux,QtDemuxStream * stream)8473 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8474 {
8475   /* fps is calculated base on the duration of the average framerate since
8476    * qt does not have a fixed framerate. */
8477   gboolean fps_available = TRUE;
8478   guint32 first_duration = 0;
8479 
8480   if (stream->n_samples > 0)
8481     first_duration = stream->samples[0].duration;
8482 
8483   if ((stream->n_samples == 1 && first_duration == 0)
8484       || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8485     /* still frame */
8486     CUR_STREAM (stream)->fps_n = 0;
8487     CUR_STREAM (stream)->fps_d = 1;
8488   } else {
8489     if (stream->duration == 0 || stream->n_samples < 2) {
8490       CUR_STREAM (stream)->fps_n = stream->timescale;
8491       CUR_STREAM (stream)->fps_d = 1;
8492       fps_available = FALSE;
8493     } else {
8494       GstClockTime avg_duration;
8495       guint64 duration;
8496       guint32 n_samples;
8497 
8498       /* duration and n_samples can be updated for fragmented format
8499        * so, framerate of fragmented format is calculated using data in a moof */
8500       if (qtdemux->fragmented && stream->n_samples_moof > 0
8501           && stream->duration_moof > 0) {
8502         n_samples = stream->n_samples_moof;
8503         duration = stream->duration_moof;
8504       } else {
8505         n_samples = stream->n_samples;
8506         duration = stream->duration;
8507       }
8508 
8509       /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8510       /* stream->duration is guint64, timescale, n_samples are guint32 */
8511       avg_duration =
8512           gst_util_uint64_scale_round (duration -
8513           first_duration, GST_SECOND,
8514           (guint64) (stream->timescale) * (n_samples - 1));
8515 
8516       GST_LOG_OBJECT (qtdemux,
8517           "Calculating avg sample duration based on stream (or moof) duration %"
8518           G_GUINT64_FORMAT
8519           " minus first sample %u, leaving %d samples gives %"
8520           GST_TIME_FORMAT, duration, first_duration,
8521           n_samples - 1, GST_TIME_ARGS (avg_duration));
8522 
8523       fps_available =
8524           gst_video_guess_framerate (avg_duration,
8525           &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8526 
8527       GST_DEBUG_OBJECT (qtdemux,
8528           "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8529           stream->timescale, CUR_STREAM (stream)->fps_n,
8530           CUR_STREAM (stream)->fps_d);
8531     }
8532   }
8533 
8534   return fps_available;
8535 }
8536 
8537 static gboolean
gst_qtdemux_configure_stream(GstQTDemux * qtdemux,QtDemuxStream * stream)8538 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8539 {
8540   if (stream->subtype == FOURCC_vide) {
8541     gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8542 
8543     if (CUR_STREAM (stream)->caps) {
8544       CUR_STREAM (stream)->caps =
8545           gst_caps_make_writable (CUR_STREAM (stream)->caps);
8546 
8547       if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8548         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8549             "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8550             "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8551 
8552       /* set framerate if calculated framerate is reliable */
8553       if (fps_available) {
8554         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8555             "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8556             CUR_STREAM (stream)->fps_d, NULL);
8557       }
8558 
8559       /* calculate pixel-aspect-ratio using display width and height */
8560       GST_DEBUG_OBJECT (qtdemux,
8561           "video size %dx%d, target display size %dx%d",
8562           CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8563           stream->display_width, stream->display_height);
8564       /* qt file might have pasp atom */
8565       if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8566         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8567             CUR_STREAM (stream)->par_h);
8568         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8569             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8570             CUR_STREAM (stream)->par_h, NULL);
8571       } else if (stream->display_width > 0 && stream->display_height > 0
8572           && CUR_STREAM (stream)->width > 0
8573           && CUR_STREAM (stream)->height > 0) {
8574         gint n, d;
8575 
8576         /* calculate the pixel aspect ratio using the display and pixel w/h */
8577         n = stream->display_width * CUR_STREAM (stream)->height;
8578         d = stream->display_height * CUR_STREAM (stream)->width;
8579         if (n == d)
8580           n = d = 1;
8581         GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8582         CUR_STREAM (stream)->par_w = n;
8583         CUR_STREAM (stream)->par_h = d;
8584         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8585             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8586             CUR_STREAM (stream)->par_h, NULL);
8587       }
8588 
8589       if (CUR_STREAM (stream)->interlace_mode > 0) {
8590         if (CUR_STREAM (stream)->interlace_mode == 1) {
8591           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8592               G_TYPE_STRING, "progressive", NULL);
8593         } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8594           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8595               G_TYPE_STRING, "interleaved", NULL);
8596           if (CUR_STREAM (stream)->field_order == 9) {
8597             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8598                 G_TYPE_STRING, "top-field-first", NULL);
8599           } else if (CUR_STREAM (stream)->field_order == 14) {
8600             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8601                 G_TYPE_STRING, "bottom-field-first", NULL);
8602           }
8603         }
8604       }
8605 
8606       /* Create incomplete colorimetry here if needed */
8607       if (CUR_STREAM (stream)->colorimetry.range ||
8608           CUR_STREAM (stream)->colorimetry.matrix ||
8609           CUR_STREAM (stream)->colorimetry.transfer
8610           || CUR_STREAM (stream)->colorimetry.primaries) {
8611         gchar *colorimetry =
8612             gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8613         gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8614             G_TYPE_STRING, colorimetry, NULL);
8615         g_free (colorimetry);
8616       }
8617 
8618       if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8619         guint par_w = 1, par_h = 1;
8620 
8621         if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8622           par_w = CUR_STREAM (stream)->par_w;
8623           par_h = CUR_STREAM (stream)->par_h;
8624         }
8625 
8626         if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8627                 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8628                 par_h)) {
8629           stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8630         }
8631 
8632         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8633             "multiview-mode", G_TYPE_STRING,
8634             gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8635             "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8636             stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8637       }
8638     }
8639   }
8640 
8641   else if (stream->subtype == FOURCC_soun) {
8642     if (CUR_STREAM (stream)->caps) {
8643       CUR_STREAM (stream)->caps =
8644           gst_caps_make_writable (CUR_STREAM (stream)->caps);
8645       if (CUR_STREAM (stream)->rate > 0)
8646         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8647             "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8648       if (CUR_STREAM (stream)->n_channels > 0)
8649         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8650             "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8651       if (CUR_STREAM (stream)->n_channels > 2) {
8652         /* FIXME: Need to parse the 'chan' atom to get channel layouts
8653          * correctly; this is just the minimum we can do - assume
8654          * we don't actually have any channel positions. */
8655         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8656             "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8657       }
8658     }
8659   }
8660 
8661   else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8662     const GstStructure *s;
8663     QtDemuxStream *fps_stream = NULL;
8664     gboolean fps_available = FALSE;
8665 
8666     /* CEA608 closed caption tracks are a bit special in that each sample
8667      * can contain CCs for multiple frames, and CCs can be omitted and have to
8668      * be inferred from the duration of the sample then.
8669      *
8670      * As such we take the framerate from the (first) video track here for
8671      * CEA608 as there must be one CC byte pair for every video frame
8672      * according to the spec.
8673      *
8674      * For CEA708 all is fine and there is one sample per frame.
8675      */
8676 
8677     s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8678     if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8679       gint i;
8680 
8681       for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8682         QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8683 
8684         if (tmp->subtype == FOURCC_vide) {
8685           fps_stream = tmp;
8686           break;
8687         }
8688       }
8689 
8690       if (fps_stream) {
8691         fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8692         CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8693         CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8694       }
8695     } else {
8696       fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8697       fps_stream = stream;
8698     }
8699 
8700     CUR_STREAM (stream)->caps =
8701         gst_caps_make_writable (CUR_STREAM (stream)->caps);
8702 
8703     /* set framerate if calculated framerate is reliable */
8704     if (fps_available) {
8705       gst_caps_set_simple (CUR_STREAM (stream)->caps,
8706           "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8707           CUR_STREAM (stream)->fps_d, NULL);
8708     }
8709   }
8710 
8711   if (stream->pad) {
8712     GstCaps *prev_caps = NULL;
8713 
8714     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8715     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8716     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8717     gst_pad_set_active (stream->pad, TRUE);
8718 
8719     gst_pad_use_fixed_caps (stream->pad);
8720 
8721     if (stream->protected) {
8722       if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8723         GST_ERROR_OBJECT (qtdemux,
8724             "Failed to configure protected stream caps.");
8725         return FALSE;
8726       }
8727     }
8728 
8729     GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8730         CUR_STREAM (stream)->caps);
8731     if (stream->new_stream) {
8732       GstEvent *event;
8733       GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8734 
8735       event =
8736           gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8737           0);
8738       if (event) {
8739         gst_event_parse_stream_flags (event, &stream_flags);
8740         if (gst_event_parse_group_id (event, &qtdemux->group_id))
8741           qtdemux->have_group_id = TRUE;
8742         else
8743           qtdemux->have_group_id = FALSE;
8744         gst_event_unref (event);
8745       } else if (!qtdemux->have_group_id) {
8746         qtdemux->have_group_id = TRUE;
8747         qtdemux->group_id = gst_util_group_id_next ();
8748       }
8749 
8750       stream->new_stream = FALSE;
8751       event = gst_event_new_stream_start (stream->stream_id);
8752       if (qtdemux->have_group_id)
8753         gst_event_set_group_id (event, qtdemux->group_id);
8754       if (stream->disabled)
8755         stream_flags |= GST_STREAM_FLAG_UNSELECT;
8756       if (CUR_STREAM (stream)->sparse) {
8757         stream_flags |= GST_STREAM_FLAG_SPARSE;
8758       } else {
8759         stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8760       }
8761       gst_event_set_stream_flags (event, stream_flags);
8762       gst_pad_push_event (stream->pad, event);
8763     }
8764 
8765     prev_caps = gst_pad_get_current_caps (stream->pad);
8766 
8767     if (CUR_STREAM (stream)->caps) {
8768       if (!prev_caps
8769           || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8770         GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8771             CUR_STREAM (stream)->caps);
8772         gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8773       } else {
8774         GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8775       }
8776     } else {
8777       GST_WARNING_OBJECT (qtdemux, "stream without caps");
8778     }
8779 
8780     if (prev_caps)
8781       gst_caps_unref (prev_caps);
8782     stream->new_caps = FALSE;
8783   }
8784   return TRUE;
8785 }
8786 
8787 static void
gst_qtdemux_stream_check_and_change_stsd_index(GstQTDemux * demux,QtDemuxStream * stream)8788 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8789     QtDemuxStream * stream)
8790 {
8791   if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8792     return;
8793 
8794   GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8795       stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8796   if (G_UNLIKELY (stream->stsd_sample_description_id >=
8797           stream->stsd_entries_length)) {
8798     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8799         (_("This file is invalid and cannot be played.")),
8800         ("New sample description id is out of bounds (%d >= %d)",
8801             stream->stsd_sample_description_id, stream->stsd_entries_length));
8802   } else {
8803     stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8804     stream->new_caps = TRUE;
8805   }
8806 }
8807 
8808 static gboolean
gst_qtdemux_add_stream(GstQTDemux * qtdemux,QtDemuxStream * stream,GstTagList * list)8809 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8810     QtDemuxStream * stream, GstTagList * list)
8811 {
8812   gboolean ret = TRUE;
8813 
8814   if (stream->subtype == FOURCC_vide) {
8815     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8816 
8817     stream->pad =
8818         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8819     g_free (name);
8820 
8821     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8822       gst_object_unref (stream->pad);
8823       stream->pad = NULL;
8824       ret = FALSE;
8825       goto done;
8826     }
8827 
8828     qtdemux->n_video_streams++;
8829   } else if (stream->subtype == FOURCC_soun) {
8830     gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8831 
8832     stream->pad =
8833         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8834     g_free (name);
8835     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8836       gst_object_unref (stream->pad);
8837       stream->pad = NULL;
8838       ret = FALSE;
8839       goto done;
8840     }
8841     qtdemux->n_audio_streams++;
8842   } else if (stream->subtype == FOURCC_strm) {
8843     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8844   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8845       || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8846       || stream->subtype == FOURCC_clcp) {
8847     gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8848 
8849     stream->pad =
8850         gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8851     g_free (name);
8852     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8853       gst_object_unref (stream->pad);
8854       stream->pad = NULL;
8855       ret = FALSE;
8856       goto done;
8857     }
8858     qtdemux->n_sub_streams++;
8859   } else if (CUR_STREAM (stream)->caps) {
8860     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8861 
8862     stream->pad =
8863         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8864     g_free (name);
8865     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8866       gst_object_unref (stream->pad);
8867       stream->pad = NULL;
8868       ret = FALSE;
8869       goto done;
8870     }
8871     qtdemux->n_video_streams++;
8872   } else {
8873     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8874     goto done;
8875   }
8876 
8877   if (stream->pad) {
8878     GList *l;
8879 
8880     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8881         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8882     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8883     gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8884 
8885     if (stream->stream_tags)
8886       gst_tag_list_unref (stream->stream_tags);
8887     stream->stream_tags = list;
8888     list = NULL;
8889     /* global tags go on each pad anyway */
8890     stream->send_global_tags = TRUE;
8891     /* send upstream GST_EVENT_PROTECTION events that were received before
8892        this source pad was created */
8893     for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8894       gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8895   }
8896 done:
8897   if (list)
8898     gst_tag_list_unref (list);
8899   return ret;
8900 }
8901 
8902 /* find next atom with @fourcc starting at @offset */
8903 static GstFlowReturn
qtdemux_find_atom(GstQTDemux * qtdemux,guint64 * offset,guint64 * length,guint32 fourcc)8904 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8905     guint64 * length, guint32 fourcc)
8906 {
8907   GstFlowReturn ret;
8908   guint32 lfourcc;
8909   GstBuffer *buf;
8910 
8911   GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8912       G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8913 
8914   while (TRUE) {
8915     GstMapInfo map;
8916 
8917     buf = NULL;
8918     ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8919     if (G_UNLIKELY (ret != GST_FLOW_OK))
8920       goto locate_failed;
8921     if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8922       /* likely EOF */
8923       ret = GST_FLOW_EOS;
8924       gst_buffer_unref (buf);
8925       goto locate_failed;
8926     }
8927     gst_buffer_map (buf, &map, GST_MAP_READ);
8928     extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8929     gst_buffer_unmap (buf, &map);
8930     gst_buffer_unref (buf);
8931 
8932     if (G_UNLIKELY (*length == 0)) {
8933       GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8934       ret = GST_FLOW_ERROR;
8935       goto locate_failed;
8936     }
8937 
8938     if (lfourcc == fourcc) {
8939       GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8940           *offset);
8941       break;
8942     } else {
8943       GST_LOG_OBJECT (qtdemux,
8944           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8945           GST_FOURCC_ARGS (fourcc), *offset);
8946       *offset += *length;
8947     }
8948   }
8949 
8950   return GST_FLOW_OK;
8951 
8952 locate_failed:
8953   {
8954     /* might simply have had last one */
8955     GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8956     return ret;
8957   }
8958 }
8959 
8960 /* should only do something in pull mode */
8961 /* call with OBJECT lock */
8962 static GstFlowReturn
qtdemux_add_fragmented_samples(GstQTDemux * qtdemux)8963 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8964 {
8965   guint64 length, offset;
8966   GstBuffer *buf = NULL;
8967   GstFlowReturn ret = GST_FLOW_OK;
8968   GstFlowReturn res = GST_FLOW_OK;
8969   GstMapInfo map;
8970 
8971   offset = qtdemux->moof_offset;
8972   GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8973 
8974   if (!offset) {
8975     GST_DEBUG_OBJECT (qtdemux, "no next moof");
8976     return GST_FLOW_EOS;
8977   }
8978 
8979   /* best not do pull etc with lock held */
8980   GST_OBJECT_UNLOCK (qtdemux);
8981 
8982   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8983   if (ret != GST_FLOW_OK)
8984     goto flow_failed;
8985 
8986   ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8987   if (G_UNLIKELY (ret != GST_FLOW_OK))
8988     goto flow_failed;
8989   gst_buffer_map (buf, &map, GST_MAP_READ);
8990   if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8991     gst_buffer_unmap (buf, &map);
8992     gst_buffer_unref (buf);
8993     buf = NULL;
8994     goto parse_failed;
8995   }
8996 
8997   gst_buffer_unmap (buf, &map);
8998   gst_buffer_unref (buf);
8999   buf = NULL;
9000 
9001   offset += length;
9002   /* look for next moof */
9003   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9004   if (G_UNLIKELY (ret != GST_FLOW_OK))
9005     goto flow_failed;
9006 
9007 exit:
9008   GST_OBJECT_LOCK (qtdemux);
9009 
9010   qtdemux->moof_offset = offset;
9011 
9012   return res;
9013 
9014 parse_failed:
9015   {
9016     GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9017     offset = 0;
9018     res = GST_FLOW_ERROR;
9019     goto exit;
9020   }
9021 flow_failed:
9022   {
9023     /* maybe upstream temporarily flushing */
9024     if (ret != GST_FLOW_FLUSHING) {
9025       GST_DEBUG_OBJECT (qtdemux, "no next moof");
9026       offset = 0;
9027     } else {
9028       GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9029       /* resume at current position next time */
9030     }
9031     res = ret;
9032     goto exit;
9033   }
9034 }
9035 
9036 /* initialise bytereaders for stbl sub-atoms */
9037 static gboolean
qtdemux_stbl_init(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * stbl)9038 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9039 {
9040   stream->stbl_index = -1;      /* no samples have yet been parsed */
9041   stream->sample_index = -1;
9042 
9043   /* time-to-sample atom */
9044   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9045     goto corrupt_file;
9046 
9047   /* copy atom data into a new buffer for later use */
9048   stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
9049 
9050   /* skip version + flags */
9051   if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9052       !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9053     goto corrupt_file;
9054   GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9055 
9056   /* make sure there's enough data */
9057   if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9058     stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9059     GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9060         stream->n_sample_times);
9061     if (!stream->n_sample_times)
9062       goto corrupt_file;
9063   }
9064 
9065   /* sync sample atom */
9066   stream->stps_present = FALSE;
9067   if ((stream->stss_present =
9068           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9069               &stream->stss) ? TRUE : FALSE) == TRUE) {
9070     /* copy atom data into a new buffer for later use */
9071     stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
9072 
9073     /* skip version + flags */
9074     if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9075         !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9076       goto corrupt_file;
9077 
9078     if (stream->n_sample_syncs) {
9079       /* make sure there's enough data */
9080       if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9081         goto corrupt_file;
9082     }
9083 
9084     /* partial sync sample atom */
9085     if ((stream->stps_present =
9086             ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9087                 &stream->stps) ? TRUE : FALSE) == TRUE) {
9088       /* copy atom data into a new buffer for later use */
9089       stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
9090 
9091       /* skip version + flags */
9092       if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9093           !gst_byte_reader_get_uint32_be (&stream->stps,
9094               &stream->n_sample_partial_syncs))
9095         goto corrupt_file;
9096 
9097       /* if there are no entries, the stss table contains the real
9098        * sync samples */
9099       if (stream->n_sample_partial_syncs) {
9100         /* make sure there's enough data */
9101         if (!qt_atom_parser_has_chunks (&stream->stps,
9102                 stream->n_sample_partial_syncs, 4))
9103           goto corrupt_file;
9104       }
9105     }
9106   }
9107 
9108   /* sample size */
9109   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9110     goto no_samples;
9111 
9112   /* copy atom data into a new buffer for later use */
9113   stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
9114 
9115   /* skip version + flags */
9116   if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9117       !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9118     goto corrupt_file;
9119 
9120   if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9121     goto corrupt_file;
9122 
9123   if (!stream->n_samples)
9124     goto no_samples;
9125 
9126   /* sample-to-chunk atom */
9127   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9128     goto corrupt_file;
9129 
9130   /* copy atom data into a new buffer for later use */
9131   stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
9132 
9133   /* skip version + flags */
9134   if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9135       !gst_byte_reader_get_uint32_be (&stream->stsc,
9136           &stream->n_samples_per_chunk))
9137     goto corrupt_file;
9138 
9139   GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9140       stream->n_samples_per_chunk);
9141 
9142   /* make sure there's enough data */
9143   if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9144           12))
9145     goto corrupt_file;
9146 
9147 
9148   /* chunk offset */
9149   if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9150     stream->co_size = sizeof (guint32);
9151   else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9152           &stream->stco))
9153     stream->co_size = sizeof (guint64);
9154   else
9155     goto corrupt_file;
9156 
9157   /* copy atom data into a new buffer for later use */
9158   stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
9159 
9160   /* skip version + flags */
9161   if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9162     goto corrupt_file;
9163 
9164   /* chunks_are_samples == TRUE means treat chunks as samples */
9165   stream->chunks_are_samples = stream->sample_size
9166       && !CUR_STREAM (stream)->sampled;
9167   if (stream->chunks_are_samples) {
9168     /* treat chunks as samples */
9169     if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9170       goto corrupt_file;
9171   } else {
9172     /* skip number of entries */
9173     if (!gst_byte_reader_skip (&stream->stco, 4))
9174       goto corrupt_file;
9175 
9176     /* make sure there are enough data in the stsz atom */
9177     if (!stream->sample_size) {
9178       /* different sizes for each sample */
9179       if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9180         goto corrupt_file;
9181     }
9182   }
9183 
9184   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9185       stream->n_samples, (guint) sizeof (QtDemuxSample),
9186       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9187 
9188   if (stream->n_samples >=
9189       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9190     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9191         "be larger than %uMB (broken file?)", stream->n_samples,
9192         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9193     return FALSE;
9194   }
9195 
9196   g_assert (stream->samples == NULL);
9197   stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9198   if (!stream->samples) {
9199     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9200         stream->n_samples);
9201     return FALSE;
9202   }
9203 
9204   /* composition time-to-sample */
9205   if ((stream->ctts_present =
9206           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9207               &stream->ctts) ? TRUE : FALSE) == TRUE) {
9208     GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9209 
9210     /* copy atom data into a new buffer for later use */
9211     stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
9212 
9213     /* skip version + flags */
9214     if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9215         || !gst_byte_reader_get_uint32_be (&stream->ctts,
9216             &stream->n_composition_times))
9217       goto corrupt_file;
9218 
9219     /* make sure there's enough data */
9220     if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9221             4 + 4))
9222       goto corrupt_file;
9223 
9224     /* This is optional, if missing we iterate the ctts */
9225     if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9226       if (!gst_byte_reader_skip (&cslg, 1 + 3)
9227           || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
9228         g_free ((gpointer) cslg.data);
9229         goto corrupt_file;
9230       }
9231     } else {
9232       gint32 cslg_least = 0;
9233       guint num_entries, pos;
9234       gint i;
9235 
9236       pos = gst_byte_reader_get_pos (&stream->ctts);
9237       num_entries = stream->n_composition_times;
9238 
9239       stream->cslg_shift = 0;
9240 
9241       for (i = 0; i < num_entries; i++) {
9242         gint32 offset;
9243 
9244         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9245         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9246         /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9247          * slightly inaccurate PTS could be more usable than corrupted one */
9248         if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9249           GST_WARNING_OBJECT (qtdemux,
9250               "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9251               " larger than duration %" G_GUINT64_FORMAT,
9252               offset, stream->duration);
9253 
9254           stream->cslg_shift = 0;
9255           stream->ctts_present = FALSE;
9256           return TRUE;
9257         }
9258 
9259         if (offset < cslg_least)
9260           cslg_least = offset;
9261       }
9262 
9263       if (cslg_least < 0)
9264         stream->cslg_shift = ABS (cslg_least);
9265       else
9266         stream->cslg_shift = 0;
9267 
9268       /* reset the reader so we can generate sample table */
9269       gst_byte_reader_set_pos (&stream->ctts, pos);
9270     }
9271   } else {
9272     /* Ensure the cslg_shift value is consistent so we can use it
9273      * unconditionnally to produce TS and Segment */
9274     stream->cslg_shift = 0;
9275   }
9276 
9277   return TRUE;
9278 
9279 corrupt_file:
9280   {
9281     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9282         (_("This file is corrupt and cannot be played.")), (NULL));
9283     return FALSE;
9284   }
9285 no_samples:
9286   {
9287     gst_qtdemux_stbl_free (stream);
9288     if (!qtdemux->fragmented) {
9289       /* not quite good */
9290       GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9291       return FALSE;
9292     } else {
9293       /* may pick up samples elsewhere */
9294       return TRUE;
9295     }
9296   }
9297 }
9298 
9299 /* collect samples from the next sample to be parsed up to sample @n for @stream
9300  * by reading the info from @stbl
9301  *
9302  * This code can be executed from both the streaming thread and the seeking
9303  * thread so it takes the object lock to protect itself
9304  */
9305 static gboolean
qtdemux_parse_samples(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 n)9306 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9307 {
9308   gint i, j, k;
9309   QtDemuxSample *samples, *first, *cur, *last;
9310   guint32 n_samples_per_chunk;
9311   guint32 n_samples;
9312 
9313   GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9314       GST_FOURCC_FORMAT ", pad %s",
9315       GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9316       stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9317 
9318   n_samples = stream->n_samples;
9319 
9320   if (n >= n_samples)
9321     goto out_of_samples;
9322 
9323   GST_OBJECT_LOCK (qtdemux);
9324   if (n <= stream->stbl_index)
9325     goto already_parsed;
9326 
9327   GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9328 
9329   if (!stream->stsz.data) {
9330     /* so we already parsed and passed all the moov samples;
9331      * onto fragmented ones */
9332     g_assert (qtdemux->fragmented);
9333     goto done;
9334   }
9335 
9336   /* pointer to the sample table */
9337   samples = stream->samples;
9338 
9339   /* starts from -1, moves to the next sample index to parse */
9340   stream->stbl_index++;
9341 
9342   /* keep track of the first and last sample to fill */
9343   first = &samples[stream->stbl_index];
9344   last = &samples[n];
9345 
9346   if (!stream->chunks_are_samples) {
9347     /* set the sample sizes */
9348     if (stream->sample_size == 0) {
9349       /* different sizes for each sample */
9350       for (cur = first; cur <= last; cur++) {
9351         cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9352         GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9353             (guint) (cur - samples), cur->size);
9354       }
9355     } else {
9356       /* samples have the same size */
9357       GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9358       for (cur = first; cur <= last; cur++)
9359         cur->size = stream->sample_size;
9360     }
9361   }
9362 
9363   n_samples_per_chunk = stream->n_samples_per_chunk;
9364   cur = first;
9365 
9366   for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9367     guint32 last_chunk;
9368 
9369     if (stream->stsc_chunk_index >= stream->last_chunk
9370         || stream->stsc_chunk_index < stream->first_chunk) {
9371       stream->first_chunk =
9372           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9373       stream->samples_per_chunk =
9374           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9375       /* starts from 1 */
9376       stream->stsd_sample_description_id =
9377           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9378 
9379       /* chunk numbers are counted from 1 it seems */
9380       if (G_UNLIKELY (stream->first_chunk == 0))
9381         goto corrupt_file;
9382 
9383       --stream->first_chunk;
9384 
9385       /* the last chunk of each entry is calculated by taking the first chunk
9386        * of the next entry; except if there is no next, where we fake it with
9387        * INT_MAX */
9388       if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9389         stream->last_chunk = G_MAXUINT32;
9390       } else {
9391         stream->last_chunk =
9392             gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9393         if (G_UNLIKELY (stream->last_chunk == 0))
9394           goto corrupt_file;
9395 
9396         --stream->last_chunk;
9397       }
9398 
9399       GST_LOG_OBJECT (qtdemux,
9400           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9401           "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9402           stream->samples_per_chunk, stream->stsd_sample_description_id);
9403 
9404       if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9405         goto corrupt_file;
9406 
9407       if (stream->last_chunk != G_MAXUINT32) {
9408         if (!qt_atom_parser_peek_sub (&stream->stco,
9409                 stream->first_chunk * stream->co_size,
9410                 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9411                 &stream->co_chunk))
9412           goto corrupt_file;
9413 
9414       } else {
9415         stream->co_chunk = stream->stco;
9416         if (!gst_byte_reader_skip (&stream->co_chunk,
9417                 stream->first_chunk * stream->co_size))
9418           goto corrupt_file;
9419       }
9420 
9421       stream->stsc_chunk_index = stream->first_chunk;
9422     }
9423 
9424     last_chunk = stream->last_chunk;
9425 
9426     if (stream->chunks_are_samples) {
9427       cur = &samples[stream->stsc_chunk_index];
9428 
9429       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9430         if (j > n) {
9431           /* save state */
9432           stream->stsc_chunk_index = j;
9433           goto done;
9434         }
9435 
9436         cur->offset =
9437             qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9438             stream->co_size);
9439 
9440         GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9441             "%" G_GUINT64_FORMAT, j, cur->offset);
9442 
9443         if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9444             CUR_STREAM (stream)->bytes_per_frame > 0) {
9445           cur->size =
9446               (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9447               CUR_STREAM (stream)->samples_per_frame *
9448               CUR_STREAM (stream)->bytes_per_frame;
9449         } else {
9450           cur->size = stream->samples_per_chunk;
9451         }
9452 
9453         GST_DEBUG_OBJECT (qtdemux,
9454             "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9455             j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9456                     stream->stco_sample_index)), cur->size);
9457 
9458         cur->timestamp = stream->stco_sample_index;
9459         cur->duration = stream->samples_per_chunk;
9460         cur->keyframe = TRUE;
9461         cur++;
9462 
9463         stream->stco_sample_index += stream->samples_per_chunk;
9464       }
9465       stream->stsc_chunk_index = j;
9466     } else {
9467       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9468         guint32 samples_per_chunk;
9469         guint64 chunk_offset;
9470 
9471         if (!stream->stsc_sample_index
9472             && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9473                 &stream->chunk_offset))
9474           goto corrupt_file;
9475 
9476         samples_per_chunk = stream->samples_per_chunk;
9477         chunk_offset = stream->chunk_offset;
9478 
9479         for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9480           GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9481               G_GUINT64_FORMAT " and size %d",
9482               (guint) (cur - samples), chunk_offset, cur->size);
9483 
9484           cur->offset = chunk_offset;
9485           chunk_offset += cur->size;
9486           cur++;
9487 
9488           if (G_UNLIKELY (cur > last)) {
9489             /* save state */
9490             stream->stsc_sample_index = k + 1;
9491             stream->chunk_offset = chunk_offset;
9492             stream->stsc_chunk_index = j;
9493             goto done2;
9494           }
9495         }
9496         stream->stsc_sample_index = 0;
9497       }
9498       stream->stsc_chunk_index = j;
9499     }
9500     stream->stsc_index++;
9501   }
9502 
9503   if (stream->chunks_are_samples)
9504     goto ctts;
9505 done2:
9506   {
9507     guint32 n_sample_times;
9508 
9509     n_sample_times = stream->n_sample_times;
9510     cur = first;
9511 
9512     for (i = stream->stts_index; i < n_sample_times; i++) {
9513       guint32 stts_samples;
9514       gint32 stts_duration;
9515       gint64 stts_time;
9516 
9517       if (stream->stts_sample_index >= stream->stts_samples
9518           || !stream->stts_sample_index) {
9519 
9520         stream->stts_samples =
9521             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9522         stream->stts_duration =
9523             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9524 
9525         GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9526             i, stream->stts_samples, stream->stts_duration);
9527 
9528         stream->stts_sample_index = 0;
9529       }
9530 
9531       stts_samples = stream->stts_samples;
9532       stts_duration = stream->stts_duration;
9533       stts_time = stream->stts_time;
9534 
9535       for (j = stream->stts_sample_index; j < stts_samples; j++) {
9536         GST_DEBUG_OBJECT (qtdemux,
9537             "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9538             (guint) (cur - samples), j,
9539             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9540 
9541         cur->timestamp = stts_time;
9542         cur->duration = stts_duration;
9543 
9544         /* avoid 32-bit wrap-around,
9545          * but still mind possible 'negative' duration */
9546         stts_time += (gint64) stts_duration;
9547         cur++;
9548 
9549         if (G_UNLIKELY (cur > last)) {
9550           /* save values */
9551           stream->stts_time = stts_time;
9552           stream->stts_sample_index = j + 1;
9553           if (stream->stts_sample_index >= stream->stts_samples)
9554             stream->stts_index++;
9555           goto done3;
9556         }
9557       }
9558       stream->stts_sample_index = 0;
9559       stream->stts_time = stts_time;
9560       stream->stts_index++;
9561     }
9562     /* fill up empty timestamps with the last timestamp, this can happen when
9563      * the last samples do not decode and so we don't have timestamps for them.
9564      * We however look at the last timestamp to estimate the track length so we
9565      * need something in here. */
9566     for (; cur < last; cur++) {
9567       GST_DEBUG_OBJECT (qtdemux,
9568           "fill sample %d: timestamp %" GST_TIME_FORMAT,
9569           (guint) (cur - samples),
9570           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9571       cur->timestamp = stream->stts_time;
9572       cur->duration = -1;
9573     }
9574   }
9575 done3:
9576   {
9577     /* sample sync, can be NULL */
9578     if (stream->stss_present == TRUE) {
9579       guint32 n_sample_syncs;
9580 
9581       n_sample_syncs = stream->n_sample_syncs;
9582 
9583       if (!n_sample_syncs) {
9584         GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9585         stream->all_keyframe = TRUE;
9586       } else {
9587         for (i = stream->stss_index; i < n_sample_syncs; i++) {
9588           /* note that the first sample is index 1, not 0 */
9589           guint32 index;
9590 
9591           index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9592 
9593           if (G_LIKELY (index > 0 && index <= n_samples)) {
9594             index -= 1;
9595             samples[index].keyframe = TRUE;
9596             GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9597             /* and exit if we have enough samples */
9598             if (G_UNLIKELY (index >= n)) {
9599               i++;
9600               break;
9601             }
9602           }
9603         }
9604         /* save state */
9605         stream->stss_index = i;
9606       }
9607 
9608       /* stps marks partial sync frames like open GOP I-Frames */
9609       if (stream->stps_present == TRUE) {
9610         guint32 n_sample_partial_syncs;
9611 
9612         n_sample_partial_syncs = stream->n_sample_partial_syncs;
9613 
9614         /* if there are no entries, the stss table contains the real
9615          * sync samples */
9616         if (n_sample_partial_syncs) {
9617           for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9618             /* note that the first sample is index 1, not 0 */
9619             guint32 index;
9620 
9621             index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9622 
9623             if (G_LIKELY (index > 0 && index <= n_samples)) {
9624               index -= 1;
9625               samples[index].keyframe = TRUE;
9626               GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9627               /* and exit if we have enough samples */
9628               if (G_UNLIKELY (index >= n)) {
9629                 i++;
9630                 break;
9631               }
9632             }
9633           }
9634           /* save state */
9635           stream->stps_index = i;
9636         }
9637       }
9638     } else {
9639       /* no stss, all samples are keyframes */
9640       stream->all_keyframe = TRUE;
9641       GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9642     }
9643   }
9644 
9645 ctts:
9646   /* composition time to sample */
9647   if (stream->ctts_present == TRUE) {
9648     guint32 n_composition_times;
9649     guint32 ctts_count;
9650     gint32 ctts_soffset;
9651 
9652     /* Fill in the pts_offsets */
9653     cur = first;
9654     n_composition_times = stream->n_composition_times;
9655 
9656     for (i = stream->ctts_index; i < n_composition_times; i++) {
9657       if (stream->ctts_sample_index >= stream->ctts_count
9658           || !stream->ctts_sample_index) {
9659         stream->ctts_count =
9660             gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9661         stream->ctts_soffset =
9662             gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9663         stream->ctts_sample_index = 0;
9664       }
9665 
9666       ctts_count = stream->ctts_count;
9667       ctts_soffset = stream->ctts_soffset;
9668 
9669       for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9670         cur->pts_offset = ctts_soffset;
9671         cur++;
9672 
9673         if (G_UNLIKELY (cur > last)) {
9674           /* save state */
9675           stream->ctts_sample_index = j + 1;
9676           goto done;
9677         }
9678       }
9679       stream->ctts_sample_index = 0;
9680       stream->ctts_index++;
9681     }
9682   }
9683 done:
9684   stream->stbl_index = n;
9685   /* if index has been completely parsed, free data that is no-longer needed */
9686   if (n + 1 == stream->n_samples) {
9687     gst_qtdemux_stbl_free (stream);
9688     GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9689     if (qtdemux->pullbased) {
9690       GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9691       while (n + 1 == stream->n_samples)
9692         if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9693           break;
9694     }
9695   }
9696   GST_OBJECT_UNLOCK (qtdemux);
9697 
9698   return TRUE;
9699 
9700   /* SUCCESS */
9701 already_parsed:
9702   {
9703     GST_LOG_OBJECT (qtdemux,
9704         "Tried to parse up to sample %u but this sample has already been parsed",
9705         n);
9706     /* if fragmented, there may be more */
9707     if (qtdemux->fragmented && n == stream->stbl_index)
9708       goto done;
9709     GST_OBJECT_UNLOCK (qtdemux);
9710     return TRUE;
9711   }
9712   /* ERRORS */
9713 out_of_samples:
9714   {
9715     GST_LOG_OBJECT (qtdemux,
9716         "Tried to parse up to sample %u but there are only %u samples", n + 1,
9717         stream->n_samples);
9718     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9719         (_("This file is corrupt and cannot be played.")), (NULL));
9720     return FALSE;
9721   }
9722 corrupt_file:
9723   {
9724     GST_OBJECT_UNLOCK (qtdemux);
9725     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9726         (_("This file is corrupt and cannot be played.")), (NULL));
9727     return FALSE;
9728   }
9729 }
9730 
9731 /* collect all segment info for @stream.
9732  */
9733 static gboolean
qtdemux_parse_segments(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * trak)9734 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9735     GNode * trak)
9736 {
9737   GNode *edts;
9738   /* accept edts if they contain gaps at start and there is only
9739    * one media segment */
9740   gboolean allow_pushbased_edts = TRUE;
9741   gint media_segments_count = 0;
9742 
9743   /* parse and prepare segment info from the edit list */
9744   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9745   stream->n_segments = 0;
9746   stream->segments = NULL;
9747   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9748     GNode *elst;
9749     gint n_segments;
9750     gint segment_number, entry_size;
9751     guint64 time;
9752     GstClockTime stime;
9753     const guint8 *buffer;
9754     guint8 version;
9755     guint32 size;
9756 
9757     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9758     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9759       goto done;
9760 
9761     buffer = elst->data;
9762 
9763     size = QT_UINT32 (buffer);
9764     /* version, flags, n_segments */
9765     if (size < 16) {
9766       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9767       goto done;
9768     }
9769     version = QT_UINT8 (buffer + 8);
9770     entry_size = (version == 1) ? 20 : 12;
9771 
9772     n_segments = QT_UINT32 (buffer + 12);
9773 
9774     if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9775       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9776       goto done;
9777     }
9778 
9779     /* we might allocate a bit too much, at least allocate 1 segment */
9780     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9781 
9782     /* segments always start from 0 */
9783     time = 0;
9784     stime = 0;
9785     buffer += 16;
9786     for (segment_number = 0; segment_number < n_segments; segment_number++) {
9787       guint64 duration;
9788       guint64 media_time;
9789       gboolean empty_edit = FALSE;
9790       QtDemuxSegment *segment;
9791       guint32 rate_int;
9792       GstClockTime media_start = GST_CLOCK_TIME_NONE;
9793 
9794       if (version == 1) {
9795         media_time = QT_UINT64 (buffer + 8);
9796         duration = QT_UINT64 (buffer);
9797         if (media_time == G_MAXUINT64)
9798           empty_edit = TRUE;
9799       } else {
9800         media_time = QT_UINT32 (buffer + 4);
9801         duration = QT_UINT32 (buffer);
9802         if (media_time == G_MAXUINT32)
9803           empty_edit = TRUE;
9804       }
9805 
9806       if (!empty_edit)
9807         media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9808 
9809       segment = &stream->segments[segment_number];
9810 
9811       /* time and duration expressed in global timescale */
9812       segment->time = stime;
9813       if (duration != 0 || empty_edit) {
9814         /* edge case: empty edits with duration=zero are treated here.
9815          * (files should not have these anyway). */
9816 
9817         /* add non scaled values so we don't cause roundoff errors */
9818         time += duration;
9819         stime = QTTIME_TO_GSTTIME (qtdemux, time);
9820         segment->duration = stime - segment->time;
9821       } else {
9822         /* zero duration does not imply media_start == media_stop
9823          * but, only specify media_start. The edit ends with the track. */
9824         stime = segment->duration = GST_CLOCK_TIME_NONE;
9825         /* Don't allow more edits after this one. */
9826         n_segments = segment_number + 1;
9827       }
9828       segment->stop_time = stime;
9829 
9830       segment->trak_media_start = media_time;
9831       /* media_time expressed in stream timescale */
9832       if (!empty_edit) {
9833         segment->media_start = media_start;
9834         segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9835             ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9836         media_segments_count++;
9837       } else {
9838         segment->media_start = GST_CLOCK_TIME_NONE;
9839         segment->media_stop = GST_CLOCK_TIME_NONE;
9840       }
9841       rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9842 
9843       if (rate_int <= 1) {
9844         /* 0 is not allowed, some programs write 1 instead of the floating point
9845          * value */
9846         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9847             rate_int);
9848         segment->rate = 1;
9849       } else {
9850         segment->rate = rate_int / 65536.0;
9851       }
9852 
9853       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9854           ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9855           " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9856           " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9857           segment_number, GST_TIME_ARGS (segment->time),
9858           GST_TIME_ARGS (segment->duration),
9859           GST_TIME_ARGS (segment->media_start), media_time,
9860           GST_TIME_ARGS (segment->media_stop),
9861           GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9862           stream->timescale);
9863       if (segment->stop_time > qtdemux->segment.stop &&
9864           !qtdemux->upstream_format_is_time) {
9865         GST_WARNING_OBJECT (qtdemux, "Segment %d "
9866             " extends to %" GST_TIME_FORMAT
9867             " past the end of the declared movie duration %" GST_TIME_FORMAT
9868             " movie segment will be extended", segment_number,
9869             GST_TIME_ARGS (segment->stop_time),
9870             GST_TIME_ARGS (qtdemux->segment.stop));
9871         qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
9872       }
9873 
9874       buffer += entry_size;
9875     }
9876     GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
9877     stream->n_segments = n_segments;
9878     if (media_segments_count != 1)
9879       allow_pushbased_edts = FALSE;
9880   }
9881 done:
9882 
9883   /* push based does not handle segments, so act accordingly here,
9884    * and warn if applicable */
9885   if (!qtdemux->pullbased && !allow_pushbased_edts) {
9886     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9887     /* remove and use default one below, we stream like it anyway */
9888     g_free (stream->segments);
9889     stream->segments = NULL;
9890     stream->n_segments = 0;
9891   }
9892 
9893   /* no segments, create one to play the complete trak */
9894   if (stream->n_segments == 0) {
9895     GstClockTime stream_duration =
9896         QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9897 
9898     if (stream->segments == NULL)
9899       stream->segments = g_new (QtDemuxSegment, 1);
9900 
9901     /* represent unknown our way */
9902     if (stream_duration == 0)
9903       stream_duration = GST_CLOCK_TIME_NONE;
9904 
9905     stream->segments[0].time = 0;
9906     stream->segments[0].stop_time = stream_duration;
9907     stream->segments[0].duration = stream_duration;
9908     stream->segments[0].media_start = 0;
9909     stream->segments[0].media_stop = stream_duration;
9910     stream->segments[0].rate = 1.0;
9911     stream->segments[0].trak_media_start = 0;
9912 
9913     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9914         GST_TIME_ARGS (stream_duration));
9915     stream->n_segments = 1;
9916     stream->dummy_segment = TRUE;
9917   }
9918   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9919 
9920   return TRUE;
9921 }
9922 
9923 /*
9924  * Parses the stsd atom of a svq3 trak looking for
9925  * the SMI and gama atoms.
9926  */
9927 static void
qtdemux_parse_svq3_stsd_data(GstQTDemux * qtdemux,const guint8 * stsd_entry_data,const guint8 ** gamma,GstBuffer ** seqh)9928 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9929     const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9930 {
9931   const guint8 *_gamma = NULL;
9932   GstBuffer *_seqh = NULL;
9933   const guint8 *stsd_data = stsd_entry_data;
9934   guint32 length = QT_UINT32 (stsd_data);
9935   guint16 version;
9936 
9937   if (length < 32) {
9938     GST_WARNING_OBJECT (qtdemux, "stsd too short");
9939     goto end;
9940   }
9941 
9942   stsd_data += 16;
9943   length -= 16;
9944   version = QT_UINT16 (stsd_data);
9945   if (version == 3) {
9946     if (length >= 70) {
9947       length -= 70;
9948       stsd_data += 70;
9949       while (length > 8) {
9950         guint32 fourcc, size;
9951         const guint8 *data;
9952         size = QT_UINT32 (stsd_data);
9953         fourcc = QT_FOURCC (stsd_data + 4);
9954         data = stsd_data + 8;
9955 
9956         if (size == 0) {
9957           GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9958               "svq3 atom parsing");
9959           goto end;
9960         }
9961 
9962         switch (fourcc) {
9963           case FOURCC_gama:{
9964             if (size == 12) {
9965               _gamma = data;
9966             } else {
9967               GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9968                   " for gama atom, expected 12", size);
9969             }
9970             break;
9971           }
9972           case FOURCC_SMI_:{
9973             if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9974               guint32 seqh_size;
9975               if (_seqh != NULL) {
9976                 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9977                     " found, ignoring");
9978               } else {
9979                 seqh_size = QT_UINT32 (data + 4);
9980                 if (seqh_size > 0) {
9981                   _seqh = gst_buffer_new_and_alloc (seqh_size);
9982                   gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9983                 }
9984               }
9985             }
9986             break;
9987           }
9988           default:{
9989             GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9990                 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9991           }
9992         }
9993 
9994         if (size <= length) {
9995           length -= size;
9996           stsd_data += size;
9997         }
9998       }
9999     } else {
10000       GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10001     }
10002   } else {
10003     GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10004         G_GUINT16_FORMAT, version);
10005     goto end;
10006   }
10007 
10008 end:
10009   if (gamma) {
10010     *gamma = _gamma;
10011   }
10012   if (seqh) {
10013     *seqh = _seqh;
10014   } else if (_seqh) {
10015     gst_buffer_unref (_seqh);
10016   }
10017 }
10018 
10019 static gchar *
qtdemux_get_rtsp_uri_from_hndl(GstQTDemux * qtdemux,GNode * minf)10020 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10021 {
10022   GNode *dinf;
10023   GstByteReader dref;
10024   gchar *uri = NULL;
10025 
10026   /*
10027    * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10028    * atom that might contain a 'data' atom with the rtsp uri.
10029    * This case was reported in bug #597497, some info about
10030    * the hndl atom can be found in TN1195
10031    */
10032   dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10033   GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10034 
10035   if (dinf) {
10036     guint32 dref_num_entries = 0;
10037     if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10038         gst_byte_reader_skip (&dref, 4) &&
10039         gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10040       gint i;
10041 
10042       /* search dref entries for hndl atom */
10043       for (i = 0; i < dref_num_entries; i++) {
10044         guint32 size = 0, type;
10045         guint8 string_len = 0;
10046         if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10047             qt_atom_parser_get_fourcc (&dref, &type)) {
10048           if (type == FOURCC_hndl) {
10049             GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10050 
10051             /* skip data reference handle bytes and the
10052              * following pascal string and some extra 4
10053              * bytes I have no idea what are */
10054             if (!gst_byte_reader_skip (&dref, 4) ||
10055                 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10056                 !gst_byte_reader_skip (&dref, string_len + 4)) {
10057               GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10058               break;
10059             }
10060 
10061             /* iterate over the atoms to find the data atom */
10062             while (gst_byte_reader_get_remaining (&dref) >= 8) {
10063               guint32 atom_size;
10064               guint32 atom_type;
10065 
10066               if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10067                   qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10068                 if (atom_type == FOURCC_data) {
10069                   const guint8 *uri_aux = NULL;
10070 
10071                   /* found the data atom that might contain the rtsp uri */
10072                   GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10073                       "hndl atom, interpreting it as an URI");
10074                   if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10075                           &uri_aux)) {
10076                     if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10077                       uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10078                     else
10079                       GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10080                           "didn't contain a rtsp address");
10081                   } else {
10082                     GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10083                         "atom contents");
10084                   }
10085                   break;
10086                 }
10087                 /* skipping to the next entry */
10088                 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10089                   break;
10090               } else {
10091                 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10092                     "atom header");
10093                 break;
10094               }
10095             }
10096             break;
10097           }
10098           /* skip to the next entry */
10099           if (!gst_byte_reader_skip (&dref, size - 8))
10100             break;
10101         } else {
10102           GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10103         }
10104       }
10105       GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10106     }
10107   }
10108   return uri;
10109 }
10110 
10111 #define AMR_NB_ALL_MODES        0x81ff
10112 #define AMR_WB_ALL_MODES        0x83ff
10113 static guint
qtdemux_parse_amr_bitrate(GstBuffer * buf,gboolean wb)10114 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10115 {
10116   /* The 'damr' atom is of the form:
10117    *
10118    * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10119    *    32 b       8 b          16 b           8 b                 8 b
10120    *
10121    * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10122    * represents the highest mode used in the stream (and thus the maximum
10123    * bitrate), with a couple of special cases as seen below.
10124    */
10125 
10126   /* Map of frame type ID -> bitrate */
10127   static const guint nb_bitrates[] = {
10128     4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10129   };
10130   static const guint wb_bitrates[] = {
10131     6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10132   };
10133   GstMapInfo map;
10134   gsize max_mode;
10135   guint16 mode_set;
10136 
10137   gst_buffer_map (buf, &map, GST_MAP_READ);
10138 
10139   if (map.size != 0x11) {
10140     GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10141     goto bad_data;
10142   }
10143 
10144   if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10145     GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10146         GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10147     goto bad_data;
10148   }
10149 
10150   mode_set = QT_UINT16 (map.data + 13);
10151 
10152   if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10153     max_mode = 7 + (wb ? 1 : 0);
10154   else
10155     /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10156     max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10157 
10158   if (max_mode == -1) {
10159     GST_DEBUG ("No mode indication was found (mode set) = %x",
10160         (guint) mode_set);
10161     goto bad_data;
10162   }
10163 
10164   gst_buffer_unmap (buf, &map);
10165   return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10166 
10167 bad_data:
10168   gst_buffer_unmap (buf, &map);
10169   return 0;
10170 }
10171 
10172 static gboolean
qtdemux_parse_transformation_matrix(GstQTDemux * qtdemux,GstByteReader * reader,guint32 * matrix,const gchar * atom)10173 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10174     GstByteReader * reader, guint32 * matrix, const gchar * atom)
10175 {
10176   /*
10177    * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10178    * [0 1 2]
10179    * [3 4 5]
10180    * [6 7 8]
10181    */
10182 
10183   if (gst_byte_reader_get_remaining (reader) < 36)
10184     return FALSE;
10185 
10186   matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10187   matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10188   matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10189   matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10190   matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10191   matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10192   matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10193   matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10194   matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10195 
10196   GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10197   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10198       matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10199       matrix[2] & 0xFF);
10200   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10201       matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10202       matrix[5] & 0xFF);
10203   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10204       matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10205       matrix[8] & 0xFF);
10206 
10207   return TRUE;
10208 }
10209 
10210 static void
qtdemux_inspect_transformation_matrix(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 * matrix,GstTagList ** taglist)10211 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10212     QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10213 {
10214 
10215 /* [a b c]
10216  * [d e f]
10217  * [g h i]
10218  *
10219  * This macro will only compare value abdegh, it expects cfi to have already
10220  * been checked
10221  */
10222 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10223                                    (m)[3] == (d << 16) && (m)[4] == (e << 16))
10224 
10225   /* only handle the cases where the last column has standard values */
10226   if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10227     const gchar *rotation_tag = NULL;
10228 
10229     /* no rotation needed */
10230     if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10231       /* NOP */
10232     } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10233       rotation_tag = "rotate-90";
10234     } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10235       rotation_tag = "rotate-180";
10236     } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10237       rotation_tag = "rotate-270";
10238     } else {
10239       GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10240     }
10241 
10242     GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10243         rotation_tag);
10244     if (rotation_tag != NULL) {
10245       if (*taglist == NULL)
10246         *taglist = gst_tag_list_new_empty ();
10247       gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10248           GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10249     }
10250   } else {
10251     GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10252   }
10253 }
10254 
10255 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10256  * protected streams (sinf, frma, schm and schi); if the protection scheme is
10257  * Common Encryption (cenc), the function will also parse the tenc box (defined
10258  * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10259  * (typically an enc[v|a|t|s] sample entry); the function will set
10260  * @original_fmt to the fourcc of the original unencrypted stream format.
10261  * Returns TRUE if successful; FALSE otherwise. */
10262 static gboolean
qtdemux_parse_protection_scheme_info(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * container,guint32 * original_fmt)10263 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10264     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10265 {
10266   GNode *sinf;
10267   GNode *frma;
10268   GNode *schm;
10269   GNode *schi;
10270   QtDemuxCencSampleSetInfo *info;
10271   GNode *tenc;
10272   const guint8 *tenc_data;
10273 
10274   g_return_val_if_fail (qtdemux != NULL, FALSE);
10275   g_return_val_if_fail (stream != NULL, FALSE);
10276   g_return_val_if_fail (container != NULL, FALSE);
10277   g_return_val_if_fail (original_fmt != NULL, FALSE);
10278 
10279   sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10280   if (G_UNLIKELY (!sinf)) {
10281     if (stream->protection_scheme_type == FOURCC_cenc) {
10282       GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10283           "mandatory for Common Encryption");
10284       return FALSE;
10285     }
10286     return TRUE;
10287   }
10288 
10289   frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10290   if (G_UNLIKELY (!frma)) {
10291     GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10292     return FALSE;
10293   }
10294 
10295   *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10296   GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10297       GST_FOURCC_ARGS (*original_fmt));
10298 
10299   schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10300   if (!schm) {
10301     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10302     return FALSE;
10303   }
10304   stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10305   stream->protection_scheme_version =
10306       QT_UINT32 ((const guint8 *) schm->data + 16);
10307 
10308   GST_DEBUG_OBJECT (qtdemux,
10309       "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10310       "protection_scheme_version: %#010x",
10311       GST_FOURCC_ARGS (stream->protection_scheme_type),
10312       stream->protection_scheme_version);
10313 
10314   schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10315   if (!schi) {
10316     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10317     return FALSE;
10318   }
10319   if (stream->protection_scheme_type != FOURCC_cenc &&
10320       stream->protection_scheme_type != FOURCC_piff) {
10321     GST_ERROR_OBJECT (qtdemux,
10322         "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10323         GST_FOURCC_ARGS (stream->protection_scheme_type));
10324     return FALSE;
10325   }
10326 
10327   if (G_UNLIKELY (!stream->protection_scheme_info))
10328     stream->protection_scheme_info =
10329         g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10330 
10331   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10332 
10333   if (stream->protection_scheme_type == FOURCC_cenc) {
10334     guint32 is_encrypted;
10335     guint8 iv_size;
10336     const guint8 *default_kid;
10337 
10338     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10339     if (!tenc) {
10340       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10341           "which is mandatory for Common Encryption");
10342       return FALSE;
10343     }
10344     tenc_data = (const guint8 *) tenc->data + 12;
10345     is_encrypted = QT_UINT24 (tenc_data);
10346     iv_size = QT_UINT8 (tenc_data + 3);
10347     default_kid = (tenc_data + 4);
10348     qtdemux_update_default_sample_encryption_settings (qtdemux, info,
10349         is_encrypted, iv_size, default_kid);
10350   } else if (stream->protection_scheme_type == FOURCC_piff) {
10351     GstByteReader br;
10352     static const guint8 piff_track_encryption_uuid[] = {
10353       0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10354       0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10355     };
10356 
10357     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10358     if (!tenc) {
10359       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10360           "which is mandatory for Common Encryption");
10361       return FALSE;
10362     }
10363 
10364     tenc_data = (const guint8 *) tenc->data + 8;
10365     if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10366       gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10367       GST_ERROR_OBJECT (qtdemux,
10368           "Unsupported track encryption box with uuid: %s", box_uuid);
10369       g_free (box_uuid);
10370       return FALSE;
10371     }
10372     tenc_data = (const guint8 *) tenc->data + 16 + 12;
10373     gst_byte_reader_init (&br, tenc_data, 20);
10374     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10375       GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10376       return FALSE;
10377     }
10378     stream->protection_scheme_type = FOURCC_cenc;
10379   }
10380 
10381   return TRUE;
10382 }
10383 
10384 static gint
qtdemux_track_id_compare_func(QtDemuxStream ** stream1,QtDemuxStream ** stream2)10385 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10386     QtDemuxStream ** stream2)
10387 {
10388   return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10389 }
10390 
10391 /* parse the traks.
10392  * With each track we associate a new QtDemuxStream that contains all the info
10393  * about the trak.
10394  * traks that do not decode to something (like strm traks) will not have a pad.
10395  */
10396 static gboolean
qtdemux_parse_trak(GstQTDemux * qtdemux,GNode * trak)10397 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10398 {
10399   GstByteReader tkhd;
10400   int offset;
10401   GNode *mdia;
10402   GNode *mdhd;
10403   GNode *hdlr;
10404   GNode *minf;
10405   GNode *stbl;
10406   GNode *stsd;
10407   GNode *mp4a;
10408   GNode *mp4v;
10409   GNode *esds;
10410   GNode *tref;
10411   GNode *udta;
10412   GNode *svmi;
10413 
10414   QtDemuxStream *stream = NULL;
10415   const guint8 *stsd_data;
10416   const guint8 *stsd_entry_data;
10417   guint remaining_stsd_len;
10418   guint stsd_entry_count;
10419   guint stsd_index;
10420   guint16 lang_code;            /* quicktime lang code or packed iso code */
10421   guint32 version;
10422   guint32 tkhd_flags = 0;
10423   guint8 tkhd_version = 0;
10424   guint32 w = 0, h = 0;
10425   guint value_size, stsd_len, len;
10426   guint32 track_id;
10427   guint32 dummy;
10428 
10429   GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10430 
10431   if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10432       || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10433       || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10434     goto corrupt_file;
10435 
10436   /* pick between 64 or 32 bits */
10437   value_size = tkhd_version == 1 ? 8 : 4;
10438   if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10439       !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10440     goto corrupt_file;
10441 
10442   /* Check if current moov has duplicated track_id */
10443   if (qtdemux_find_stream (qtdemux, track_id))
10444     goto existing_stream;
10445 
10446   stream = _create_stream (qtdemux, track_id);
10447   stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10448 
10449   /* need defaults for fragments */
10450   qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10451 
10452   if ((tkhd_flags & 1) == 0)
10453     stream->disabled = TRUE;
10454 
10455   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10456       tkhd_version, tkhd_flags, stream->track_id);
10457 
10458   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10459     goto corrupt_file;
10460 
10461   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10462     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10463     if (qtdemux->major_brand != FOURCC_mjp2 ||
10464         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10465       goto corrupt_file;
10466   }
10467 
10468   len = QT_UINT32 ((guint8 *) mdhd->data);
10469   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10470   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10471   if (version == 0x01000000) {
10472     if (len < 42)
10473       goto corrupt_file;
10474     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10475     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10476     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10477   } else {
10478     if (len < 30)
10479       goto corrupt_file;
10480     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10481     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10482     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10483   }
10484 
10485   if (lang_code < 0x400) {
10486     qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10487   } else if (lang_code == 0x7fff) {
10488     stream->lang_id[0] = 0;     /* unspecified */
10489   } else {
10490     stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10491     stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10492     stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10493     stream->lang_id[3] = 0;
10494   }
10495 
10496   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10497       stream->timescale);
10498   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10499       stream->duration);
10500   GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10501       lang_code, stream->lang_id);
10502 
10503   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10504     goto corrupt_file;
10505 
10506   if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10507     /* chapters track reference */
10508     GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10509     if (chap) {
10510       gsize length = GST_READ_UINT32_BE (chap->data);
10511       if (qtdemux->chapters_track_id)
10512         GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10513 
10514       if (length >= 12) {
10515         qtdemux->chapters_track_id =
10516             GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10517       }
10518     }
10519   }
10520 
10521   /* fragmented files may have bogus duration in moov */
10522   if (!qtdemux->fragmented &&
10523       qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10524     guint64 tdur1, tdur2;
10525 
10526     /* don't overflow */
10527     tdur1 = stream->timescale * (guint64) qtdemux->duration;
10528     tdur2 = qtdemux->timescale * (guint64) stream->duration;
10529 
10530     /* HACK:
10531      * some of those trailers, nowadays, have prologue images that are
10532      * themselves video tracks as well. I haven't really found a way to
10533      * identify those yet, except for just looking at their duration. */
10534     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10535       GST_WARNING_OBJECT (qtdemux,
10536           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10537           " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10538           "found, assuming preview image or something; skipping track",
10539           stream->duration, stream->timescale, qtdemux->duration,
10540           qtdemux->timescale);
10541       gst_qtdemux_stream_unref (stream);
10542       return TRUE;
10543     }
10544   }
10545 
10546   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10547     goto corrupt_file;
10548 
10549   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10550       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10551 
10552   len = QT_UINT32 ((guint8 *) hdlr->data);
10553   if (len >= 20)
10554     stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10555   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10556       GST_FOURCC_ARGS (stream->subtype));
10557 
10558   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10559     goto corrupt_file;
10560 
10561   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10562     goto corrupt_file;
10563 
10564   /*parse svmi header if existing */
10565   svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10566   if (svmi) {
10567     len = QT_UINT32 ((guint8 *) svmi->data);
10568     version = QT_UINT32 ((guint8 *) svmi->data + 8);
10569     if (!version) {
10570       GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10571       GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10572       guint8 frame_type, frame_layout;
10573 
10574       /* MPEG-A stereo video */
10575       if (qtdemux->major_brand == FOURCC_ss02)
10576         flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10577 
10578       frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10579       frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10580       switch (frame_type) {
10581         case 0:
10582           mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10583           break;
10584         case 1:
10585           mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10586           break;
10587         case 2:
10588           mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10589           break;
10590         case 3:
10591           /* mode 3 is primary/secondary view sequence, ie
10592            * left/right views in separate tracks. See section 7.2
10593            * of ISO/IEC 23000-11:2009 */
10594           GST_FIXME_OBJECT (qtdemux,
10595               "Implement stereo video in separate streams");
10596       }
10597 
10598       if ((frame_layout & 0x1) == 0)
10599         flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10600 
10601       GST_LOG_OBJECT (qtdemux,
10602           "StereoVideo: composition type: %u, is_left_first: %u",
10603           frame_type, frame_layout);
10604       stream->multiview_mode = mode;
10605       stream->multiview_flags = flags;
10606     }
10607   }
10608 
10609   /* parse rest of tkhd */
10610   if (stream->subtype == FOURCC_vide) {
10611     guint32 matrix[9];
10612 
10613     /* version 1 uses some 64-bit ints */
10614     if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10615       goto corrupt_file;
10616 
10617     if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10618       goto corrupt_file;
10619 
10620     if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10621         || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10622       goto corrupt_file;
10623 
10624     qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10625         &stream->stream_tags);
10626   }
10627 
10628   /* parse stsd */
10629   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10630     goto corrupt_file;
10631   stsd_data = (const guint8 *) stsd->data;
10632 
10633   /* stsd should at least have one entry */
10634   stsd_len = QT_UINT32 (stsd_data);
10635   if (stsd_len < 24) {
10636     /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10637     if (stream->subtype == FOURCC_vivo) {
10638       gst_qtdemux_stream_unref (stream);
10639       return TRUE;
10640     } else {
10641       goto corrupt_file;
10642     }
10643   }
10644 
10645   stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10646   stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10647   GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
10648   GST_LOG_OBJECT (qtdemux, "stsd entry count:   %u", stsd_entry_count);
10649 
10650   stsd_entry_data = stsd_data + 16;
10651   remaining_stsd_len = stsd_len - 16;
10652   for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10653     guint32 fourcc;
10654     gchar *codec = NULL;
10655     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10656 
10657     /* and that entry should fit within stsd */
10658     len = QT_UINT32 (stsd_entry_data);
10659     if (len > remaining_stsd_len)
10660       goto corrupt_file;
10661 
10662     entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10663     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
10664         GST_FOURCC_ARGS (entry->fourcc));
10665     GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
10666 
10667     if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10668       goto error_encrypted;
10669 
10670     if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10671       /* FIXME this looks wrong, there might be multiple children
10672        * with the same type */
10673       GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10674       stream->protected = TRUE;
10675       if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10676         GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10677     }
10678 
10679     if (stream->subtype == FOURCC_vide) {
10680       GNode *colr;
10681       GNode *fiel;
10682       GNode *pasp;
10683       gboolean gray;
10684       gint depth, palette_size, palette_count;
10685       guint32 *palette_data = NULL;
10686 
10687       entry->sampled = TRUE;
10688 
10689       stream->display_width = w >> 16;
10690       stream->display_height = h >> 16;
10691 
10692       offset = 16;
10693       if (len < 86)             /* TODO verify */
10694         goto corrupt_file;
10695 
10696       entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10697       entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10698       entry->fps_n = 0;         /* this is filled in later */
10699       entry->fps_d = 0;         /* this is filled in later */
10700       entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10701       entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10702 
10703       /* if color_table_id is 0, ctab atom must follow; however some files
10704        * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10705        * if color table is not present we'll correct the value */
10706       if (entry->color_table_id == 0 &&
10707           (len < 90
10708               || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10709         entry->color_table_id = -1;
10710       }
10711 
10712       GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10713           entry->width, entry->height, entry->bits_per_sample,
10714           entry->color_table_id);
10715 
10716       depth = entry->bits_per_sample;
10717 
10718       /* more than 32 bits means grayscale */
10719       gray = (depth > 32);
10720       /* low 32 bits specify the depth  */
10721       depth &= 0x1F;
10722 
10723       /* different number of palette entries is determined by depth. */
10724       palette_count = 0;
10725       if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10726         palette_count = (1 << depth);
10727       palette_size = palette_count * 4;
10728 
10729       if (entry->color_table_id) {
10730         switch (palette_count) {
10731           case 0:
10732             break;
10733           case 2:
10734             palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10735             break;
10736           case 4:
10737             palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10738             break;
10739           case 16:
10740             if (gray)
10741               palette_data =
10742                   g_memdup (ff_qt_grayscale_palette_16, palette_size);
10743             else
10744               palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10745             break;
10746           case 256:
10747             if (gray)
10748               palette_data =
10749                   g_memdup (ff_qt_grayscale_palette_256, palette_size);
10750             else
10751               palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10752             break;
10753           default:
10754             GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10755                 (_("The video in this file might not play correctly.")),
10756                 ("unsupported palette depth %d", depth));
10757             break;
10758         }
10759       } else {
10760         gint i, j, start, end;
10761 
10762         if (len < 94)
10763           goto corrupt_file;
10764 
10765         /* read table */
10766         start = QT_UINT32 (stsd_entry_data + offset + 70);
10767         palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10768         end = QT_UINT16 (stsd_entry_data + offset + 76);
10769 
10770         GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10771             start, end, palette_count);
10772 
10773         if (end > 255)
10774           end = 255;
10775         if (start > end)
10776           start = end;
10777 
10778         if (len < 94 + (end - start) * 8)
10779           goto corrupt_file;
10780 
10781         /* palette is always the same size */
10782         palette_data = g_malloc0 (256 * 4);
10783         palette_size = 256 * 4;
10784 
10785         for (j = 0, i = start; i <= end; j++, i++) {
10786           guint32 a, r, g, b;
10787 
10788           a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10789           r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10790           g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10791           b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10792 
10793           palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10794               (g & 0xff00) | (b >> 8);
10795         }
10796       }
10797 
10798       if (entry->caps)
10799         gst_caps_unref (entry->caps);
10800 
10801       entry->caps =
10802           qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10803           &codec);
10804       if (G_UNLIKELY (!entry->caps)) {
10805         g_free (palette_data);
10806         goto unknown_stream;
10807       }
10808 
10809       if (codec) {
10810         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10811             GST_TAG_VIDEO_CODEC, codec, NULL);
10812         g_free (codec);
10813         codec = NULL;
10814       }
10815 
10816       if (palette_data) {
10817         GstStructure *s;
10818 
10819         if (entry->rgb8_palette)
10820           gst_memory_unref (entry->rgb8_palette);
10821         entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10822             palette_data, palette_size, 0, palette_size, palette_data, g_free);
10823 
10824         s = gst_caps_get_structure (entry->caps, 0);
10825 
10826         /* non-raw video has a palette_data property. raw video has the palette as
10827          * an extra plane that we append to the output buffers before we push
10828          * them*/
10829         if (!gst_structure_has_name (s, "video/x-raw")) {
10830           GstBuffer *palette;
10831 
10832           palette = gst_buffer_new ();
10833           gst_buffer_append_memory (palette, entry->rgb8_palette);
10834           entry->rgb8_palette = NULL;
10835 
10836           gst_caps_set_simple (entry->caps, "palette_data",
10837               GST_TYPE_BUFFER, palette, NULL);
10838           gst_buffer_unref (palette);
10839         }
10840       } else if (palette_count != 0) {
10841         GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10842             (NULL), ("Unsupported palette depth %d", depth));
10843       }
10844 
10845       GST_LOG_OBJECT (qtdemux, "frame count:   %u",
10846           QT_UINT16 (stsd_entry_data + offset + 32));
10847 
10848       esds = NULL;
10849       pasp = NULL;
10850       colr = NULL;
10851       fiel = NULL;
10852       /* pick 'the' stsd child */
10853       mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10854       // We should skip parsing the stsd for non-protected streams if
10855       // the entry doesn't match the fourcc, since they don't change
10856       // format. However, for protected streams we can have partial
10857       // encryption, where parts of the stream are encrypted and parts
10858       // not. For both parts of such streams, we should ensure the
10859       // esds overrides are parsed for both from the stsd.
10860       if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10861         if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
10862           mp4v = NULL;
10863         else if (!stream->protected)
10864           mp4v = NULL;
10865       }
10866 
10867       if (mp4v) {
10868         esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10869         pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10870         colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10871         fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10872       }
10873 
10874       if (pasp) {
10875         const guint8 *pasp_data = (const guint8 *) pasp->data;
10876         gint len = QT_UINT32 (pasp_data);
10877 
10878         if (len == 16) {
10879           CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10880           CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10881         } else {
10882           CUR_STREAM (stream)->par_w = 0;
10883           CUR_STREAM (stream)->par_h = 0;
10884         }
10885       } else {
10886         CUR_STREAM (stream)->par_w = 0;
10887         CUR_STREAM (stream)->par_h = 0;
10888       }
10889 
10890       if (fiel) {
10891         const guint8 *fiel_data = (const guint8 *) fiel->data;
10892         gint len = QT_UINT32 (fiel_data);
10893 
10894         if (len == 10) {
10895           CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10896           CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10897         }
10898       }
10899 
10900       if (colr) {
10901         const guint8 *colr_data = (const guint8 *) colr->data;
10902         gint len = QT_UINT32 (colr_data);
10903 
10904         if (len == 19 || len == 18) {
10905           guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10906 
10907           if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10908             guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10909             guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10910             guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10911             gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10912 
10913             switch (primaries) {
10914               case 1:
10915                 CUR_STREAM (stream)->colorimetry.primaries =
10916                     GST_VIDEO_COLOR_PRIMARIES_BT709;
10917                 break;
10918               case 5:
10919                 CUR_STREAM (stream)->colorimetry.primaries =
10920                     GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10921                 break;
10922               case 6:
10923                 CUR_STREAM (stream)->colorimetry.primaries =
10924                     GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10925                 break;
10926               case 9:
10927                 CUR_STREAM (stream)->colorimetry.primaries =
10928                     GST_VIDEO_COLOR_PRIMARIES_BT2020;
10929                 break;
10930               default:
10931                 break;
10932             }
10933 
10934             switch (transfer_function) {
10935               case 1:
10936                 CUR_STREAM (stream)->colorimetry.transfer =
10937                     GST_VIDEO_TRANSFER_BT709;
10938                 break;
10939               case 7:
10940                 CUR_STREAM (stream)->colorimetry.transfer =
10941                     GST_VIDEO_TRANSFER_SMPTE240M;
10942                 break;
10943               default:
10944                 break;
10945             }
10946 
10947             switch (matrix) {
10948               case 1:
10949                 CUR_STREAM (stream)->colorimetry.matrix =
10950                     GST_VIDEO_COLOR_MATRIX_BT709;
10951                 break;
10952               case 6:
10953                 CUR_STREAM (stream)->colorimetry.matrix =
10954                     GST_VIDEO_COLOR_MATRIX_BT601;
10955                 break;
10956               case 7:
10957                 CUR_STREAM (stream)->colorimetry.matrix =
10958                     GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10959                 break;
10960               case 9:
10961                 CUR_STREAM (stream)->colorimetry.matrix =
10962                     GST_VIDEO_COLOR_MATRIX_BT2020;
10963                 break;
10964               default:
10965                 break;
10966             }
10967 
10968             CUR_STREAM (stream)->colorimetry.range =
10969                 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10970                 GST_VIDEO_COLOR_RANGE_16_235;
10971           } else {
10972             GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10973           }
10974         } else {
10975           GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10976         }
10977       }
10978 
10979       if (esds) {
10980         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10981             stream->stream_tags);
10982       } else {
10983         switch (fourcc) {
10984           case FOURCC_H264:
10985           case FOURCC_avc1:
10986           case FOURCC_avc3:
10987           {
10988             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10989             const guint8 *avc_data = stsd_entry_data + 0x56;
10990 
10991             /* find avcC */
10992             while (len >= 0x8) {
10993               gint size;
10994 
10995               if (QT_UINT32 (avc_data) <= len)
10996                 size = QT_UINT32 (avc_data) - 0x8;
10997               else
10998                 size = len - 0x8;
10999 
11000               if (size < 1)
11001                 /* No real data, so break out */
11002                 break;
11003 
11004               switch (QT_FOURCC (avc_data + 0x4)) {
11005                 case FOURCC_avcC:
11006                 {
11007                   /* parse, if found */
11008                   GstBuffer *buf;
11009 
11010                   GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11011 
11012                   /* First 4 bytes are the length of the atom, the next 4 bytes
11013                    * are the fourcc, the next 1 byte is the version, and the
11014                    * subsequent bytes are profile_tier_level structure like data. */
11015                   gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11016                       avc_data + 8 + 1, size - 1);
11017                   buf = gst_buffer_new_and_alloc (size);
11018                   gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11019                   gst_caps_set_simple (entry->caps,
11020                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11021                   gst_buffer_unref (buf);
11022 
11023                   break;
11024                 }
11025                 case FOURCC_strf:
11026                 {
11027                   GstBuffer *buf;
11028 
11029                   GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11030 
11031                   /* First 4 bytes are the length of the atom, the next 4 bytes
11032                    * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11033                    * next 1 byte is the version, and the
11034                    * subsequent bytes are sequence parameter set like data. */
11035 
11036                   size -= 40;   /* we'll be skipping BITMAPINFOHEADER */
11037                   if (size > 1) {
11038                     gst_codec_utils_h264_caps_set_level_and_profile
11039                         (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11040 
11041                     buf = gst_buffer_new_and_alloc (size);
11042                     gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11043                     gst_caps_set_simple (entry->caps,
11044                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
11045                     gst_buffer_unref (buf);
11046                   }
11047                   break;
11048                 }
11049                 case FOURCC_btrt:
11050                 {
11051                   guint avg_bitrate, max_bitrate;
11052 
11053                   /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11054                   if (size < 12)
11055                     break;
11056 
11057                   max_bitrate = QT_UINT32 (avc_data + 0xc);
11058                   avg_bitrate = QT_UINT32 (avc_data + 0x10);
11059 
11060                   if (!max_bitrate && !avg_bitrate)
11061                     break;
11062 
11063                   /* Some muxers seem to swap the average and maximum bitrates
11064                    * (I'm looking at you, YouTube), so we swap for sanity. */
11065                   if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11066                     guint temp = avg_bitrate;
11067 
11068                     avg_bitrate = max_bitrate;
11069                     max_bitrate = temp;
11070                   }
11071 
11072                   if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11073                     gst_tag_list_add (stream->stream_tags,
11074                         GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11075                         max_bitrate, NULL);
11076                   }
11077                   if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11078                     gst_tag_list_add (stream->stream_tags,
11079                         GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11080                         NULL);
11081                   }
11082 
11083                   break;
11084                 }
11085 
11086                 default:
11087                   break;
11088               }
11089 
11090               len -= size + 8;
11091               avc_data += size + 8;
11092             }
11093 
11094             break;
11095           }
11096           case FOURCC_H265:
11097           case FOURCC_hvc1:
11098           case FOURCC_hev1:
11099           {
11100             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11101             const guint8 *hevc_data = stsd_entry_data + 0x56;
11102 
11103             /* find hevc */
11104             while (len >= 0x8) {
11105               gint size;
11106 
11107               if (QT_UINT32 (hevc_data) <= len)
11108                 size = QT_UINT32 (hevc_data) - 0x8;
11109               else
11110                 size = len - 0x8;
11111 
11112               if (size < 1)
11113                 /* No real data, so break out */
11114                 break;
11115 
11116               switch (QT_FOURCC (hevc_data + 0x4)) {
11117                 case FOURCC_hvcC:
11118                 {
11119                   /* parse, if found */
11120                   GstBuffer *buf;
11121 
11122                   GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11123 
11124                   /* First 4 bytes are the length of the atom, the next 4 bytes
11125                    * are the fourcc, the next 1 byte is the version, and the
11126                    * subsequent bytes are sequence parameter set like data. */
11127                   gst_codec_utils_h265_caps_set_level_tier_and_profile
11128                       (entry->caps, hevc_data + 8 + 1, size - 1);
11129 
11130                   buf = gst_buffer_new_and_alloc (size);
11131                   gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11132                   gst_caps_set_simple (entry->caps,
11133                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11134                   gst_buffer_unref (buf);
11135                   break;
11136                 }
11137                 default:
11138                   break;
11139               }
11140               len -= size + 8;
11141               hevc_data += size + 8;
11142             }
11143             break;
11144           }
11145           case FOURCC_mp4v:
11146           case FOURCC_MP4V:
11147           case FOURCC_fmp4:
11148           case FOURCC_FMP4:
11149           case FOURCC_xvid:
11150           case FOURCC_XVID:
11151           {
11152             GNode *glbl;
11153 
11154             GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11155                 GST_FOURCC_ARGS (fourcc));
11156 
11157             /* codec data might be in glbl extension atom */
11158             glbl = mp4v ?
11159                 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11160             if (glbl) {
11161               guint8 *data;
11162               GstBuffer *buf;
11163               gint len;
11164 
11165               GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11166               data = glbl->data;
11167               len = QT_UINT32 (data);
11168               if (len > 0x8) {
11169                 len -= 0x8;
11170                 buf = gst_buffer_new_and_alloc (len);
11171                 gst_buffer_fill (buf, 0, data + 8, len);
11172                 gst_caps_set_simple (entry->caps,
11173                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11174                 gst_buffer_unref (buf);
11175               }
11176             }
11177             break;
11178           }
11179           case FOURCC_mjp2:
11180           {
11181             /* see annex I of the jpeg2000 spec */
11182             GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11183             const guint8 *data;
11184             const gchar *colorspace = NULL;
11185             gint ncomp = 0;
11186             guint32 ncomp_map = 0;
11187             gint32 *comp_map = NULL;
11188             guint32 nchan_def = 0;
11189             gint32 *chan_def = NULL;
11190 
11191             GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11192             /* some required atoms */
11193             mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11194             if (!mjp2)
11195               break;
11196             jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11197             if (!jp2h)
11198               break;
11199 
11200             /* number of components; redundant with info in codestream, but useful
11201                to a muxer */
11202             ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11203             if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11204               break;
11205             ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11206 
11207             colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11208             if (!colr)
11209               break;
11210             GST_DEBUG_OBJECT (qtdemux, "found colr");
11211             /* extract colour space info */
11212             if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11213               switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11214                 case 16:
11215                   colorspace = "sRGB";
11216                   break;
11217                 case 17:
11218                   colorspace = "GRAY";
11219                   break;
11220                 case 18:
11221                   colorspace = "sYUV";
11222                   break;
11223                 default:
11224                   colorspace = NULL;
11225                   break;
11226               }
11227             }
11228             if (!colorspace)
11229               /* colr is required, and only values 16, 17, and 18 are specified,
11230                  so error if we have no colorspace */
11231               break;
11232 
11233             /* extract component mapping */
11234             cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11235             if (cmap) {
11236               guint32 cmap_len = 0;
11237               int i;
11238               cmap_len = QT_UINT32 (cmap->data);
11239               if (cmap_len >= 8) {
11240                 /* normal box, subtract off header */
11241                 cmap_len -= 8;
11242                 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11243                 if (cmap_len % 4 == 0) {
11244                   ncomp_map = (cmap_len / 4);
11245                   comp_map = g_new0 (gint32, ncomp_map);
11246                   for (i = 0; i < ncomp_map; i++) {
11247                     guint16 cmp;
11248                     guint8 mtyp, pcol;
11249                     cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11250                     mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11251                     pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11252                     comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11253                   }
11254                 }
11255               }
11256             }
11257             /* extract channel definitions */
11258             cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11259             if (cdef) {
11260               guint32 cdef_len = 0;
11261               int i;
11262               cdef_len = QT_UINT32 (cdef->data);
11263               if (cdef_len >= 10) {
11264                 /* normal box, subtract off header and len */
11265                 cdef_len -= 10;
11266                 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11267                 if (cdef_len % 6 == 0) {
11268                   nchan_def = (cdef_len / 6);
11269                   chan_def = g_new0 (gint32, nchan_def);
11270                   for (i = 0; i < nchan_def; i++)
11271                     chan_def[i] = -1;
11272                   for (i = 0; i < nchan_def; i++) {
11273                     guint16 cn, typ, asoc;
11274                     cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11275                     typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11276                     asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11277                     if (cn < nchan_def) {
11278                       switch (typ) {
11279                         case 0:
11280                           chan_def[cn] = asoc;
11281                           break;
11282                         case 1:
11283                           chan_def[cn] = 0;     /* alpha */
11284                           break;
11285                         default:
11286                           chan_def[cn] = -typ;
11287                       }
11288                     }
11289                   }
11290                 }
11291               }
11292             }
11293 
11294             gst_caps_set_simple (entry->caps,
11295                 "num-components", G_TYPE_INT, ncomp, NULL);
11296             gst_caps_set_simple (entry->caps,
11297                 "colorspace", G_TYPE_STRING, colorspace, NULL);
11298 
11299             if (comp_map) {
11300               GValue arr = { 0, };
11301               GValue elt = { 0, };
11302               int i;
11303               g_value_init (&arr, GST_TYPE_ARRAY);
11304               g_value_init (&elt, G_TYPE_INT);
11305               for (i = 0; i < ncomp_map; i++) {
11306                 g_value_set_int (&elt, comp_map[i]);
11307                 gst_value_array_append_value (&arr, &elt);
11308               }
11309               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11310                   "component-map", &arr);
11311               g_value_unset (&elt);
11312               g_value_unset (&arr);
11313               g_free (comp_map);
11314             }
11315 
11316             if (chan_def) {
11317               GValue arr = { 0, };
11318               GValue elt = { 0, };
11319               int i;
11320               g_value_init (&arr, GST_TYPE_ARRAY);
11321               g_value_init (&elt, G_TYPE_INT);
11322               for (i = 0; i < nchan_def; i++) {
11323                 g_value_set_int (&elt, chan_def[i]);
11324                 gst_value_array_append_value (&arr, &elt);
11325               }
11326               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11327                   "channel-definitions", &arr);
11328               g_value_unset (&elt);
11329               g_value_unset (&arr);
11330               g_free (chan_def);
11331             }
11332 
11333             /* some optional atoms */
11334             field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11335             prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11336 
11337             /* indicate possible fields in caps */
11338             if (field) {
11339               data = (guint8 *) field->data + 8;
11340               if (*data != 1)
11341                 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11342                     (gint) * data, NULL);
11343             }
11344             /* add codec_data if provided */
11345             if (prefix) {
11346               GstBuffer *buf;
11347               gint len;
11348 
11349               GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11350               data = prefix->data;
11351               len = QT_UINT32 (data);
11352               if (len > 0x8) {
11353                 len -= 0x8;
11354                 buf = gst_buffer_new_and_alloc (len);
11355                 gst_buffer_fill (buf, 0, data + 8, len);
11356                 gst_caps_set_simple (entry->caps,
11357                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11358                 gst_buffer_unref (buf);
11359               }
11360             }
11361             break;
11362           }
11363           case FOURCC_SVQ3:
11364           case FOURCC_VP31:
11365           {
11366             GstBuffer *buf;
11367             GstBuffer *seqh = NULL;
11368             const guint8 *gamma_data = NULL;
11369             gint len = QT_UINT32 (stsd_data);   /* FIXME review - why put the whole stsd in codec data? */
11370 
11371             qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11372                 &seqh);
11373             if (gamma_data) {
11374               gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11375                   QT_FP32 (gamma_data), NULL);
11376             }
11377             if (seqh) {
11378               /* sorry for the bad name, but we don't know what this is, other
11379                * than its own fourcc */
11380               gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11381                   NULL);
11382               gst_buffer_unref (seqh);
11383             }
11384 
11385             GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11386             buf = gst_buffer_new_and_alloc (len);
11387             gst_buffer_fill (buf, 0, stsd_data, len);
11388             gst_caps_set_simple (entry->caps,
11389                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11390             gst_buffer_unref (buf);
11391             break;
11392           }
11393           case FOURCC_jpeg:
11394           {
11395             /* https://developer.apple.com/standards/qtff-2001.pdf,
11396              * page 92, "Video Sample Description", under table 3.1 */
11397             GstByteReader br;
11398 
11399             const gint compressor_offset =
11400                 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11401             const gint min_size = compressor_offset + 32 + 2 + 2;
11402             GNode *jpeg;
11403             guint32 len;
11404             guint16 color_table_id = 0;
11405             gboolean ok;
11406 
11407             GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11408 
11409             /* recover information on interlaced/progressive */
11410             jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11411             if (!jpeg)
11412               break;
11413 
11414             len = QT_UINT32 (jpeg->data);
11415             GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11416                 min_size);
11417             if (len >= min_size) {
11418               gst_byte_reader_init (&br, jpeg->data, len);
11419 
11420               gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11421               gst_byte_reader_get_uint16_le (&br, &color_table_id);
11422               if (color_table_id != 0) {
11423                 /* the spec says there can be concatenated chunks in the data, and we want
11424                  * to find one called field. Walk through them. */
11425                 gint offset = min_size;
11426                 while (offset + 8 < len) {
11427                   guint32 size = 0, tag;
11428                   ok = gst_byte_reader_get_uint32_le (&br, &size);
11429                   ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11430                   if (!ok || size < 8) {
11431                     GST_WARNING_OBJECT (qtdemux,
11432                         "Failed to walk optional chunk list");
11433                     break;
11434                   }
11435                   GST_DEBUG_OBJECT (qtdemux,
11436                       "Found optional %4.4s chunk, size %u",
11437                       (const char *) &tag, size);
11438                   if (tag == FOURCC_fiel) {
11439                     guint8 n_fields = 0, ordering = 0;
11440                     gst_byte_reader_get_uint8 (&br, &n_fields);
11441                     gst_byte_reader_get_uint8 (&br, &ordering);
11442                     if (n_fields == 1 || n_fields == 2) {
11443                       GST_DEBUG_OBJECT (qtdemux,
11444                           "Found fiel tag with %u fields, ordering %u",
11445                           n_fields, ordering);
11446                       if (n_fields == 2)
11447                         gst_caps_set_simple (CUR_STREAM (stream)->caps,
11448                             "interlace-mode", G_TYPE_STRING, "interleaved",
11449                             NULL);
11450                     } else {
11451                       GST_WARNING_OBJECT (qtdemux,
11452                           "Found fiel tag with invalid fields (%u)", n_fields);
11453                     }
11454                   }
11455                   offset += size;
11456                 }
11457               } else {
11458                 GST_DEBUG_OBJECT (qtdemux,
11459                     "Color table ID is 0, not trying to get interlacedness");
11460               }
11461             } else {
11462               GST_WARNING_OBJECT (qtdemux,
11463                   "Length of jpeg chunk is too small, not trying to get interlacedness");
11464             }
11465 
11466             break;
11467           }
11468           case FOURCC_rle_:
11469           case FOURCC_WRLE:
11470           {
11471             gst_caps_set_simple (entry->caps,
11472                 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11473                 NULL);
11474             break;
11475           }
11476           case FOURCC_XiTh:
11477           {
11478             GNode *xith, *xdxt;
11479 
11480             GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11481             xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11482             if (!xith)
11483               break;
11484 
11485             xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11486             if (!xdxt)
11487               break;
11488 
11489             GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11490             /* collect the headers and store them in a stream list so that we can
11491              * send them out first */
11492             qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11493             break;
11494           }
11495           case FOURCC_ovc1:
11496           {
11497             GNode *ovc1;
11498             guint8 *ovc1_data;
11499             guint ovc1_len;
11500             GstBuffer *buf;
11501 
11502             GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11503             ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11504             if (!ovc1)
11505               break;
11506             ovc1_data = ovc1->data;
11507             ovc1_len = QT_UINT32 (ovc1_data);
11508             if (ovc1_len <= 198) {
11509               GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11510               break;
11511             }
11512             buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11513             gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11514             gst_caps_set_simple (entry->caps,
11515                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11516             gst_buffer_unref (buf);
11517             break;
11518           }
11519           case FOURCC_vc_1:
11520           {
11521             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11522             const guint8 *vc1_data = stsd_entry_data + 0x56;
11523 
11524             /* find dvc1 */
11525             while (len >= 8) {
11526               gint size;
11527 
11528               if (QT_UINT32 (vc1_data) <= len)
11529                 size = QT_UINT32 (vc1_data) - 8;
11530               else
11531                 size = len - 8;
11532 
11533               if (size < 1)
11534                 /* No real data, so break out */
11535                 break;
11536 
11537               switch (QT_FOURCC (vc1_data + 0x4)) {
11538                 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11539                 {
11540                   GstBuffer *buf;
11541 
11542                   GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11543                   buf = gst_buffer_new_and_alloc (size);
11544                   gst_buffer_fill (buf, 0, vc1_data + 8, size);
11545                   gst_caps_set_simple (entry->caps,
11546                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11547                   gst_buffer_unref (buf);
11548                   break;
11549                 }
11550                 default:
11551                   break;
11552               }
11553               len -= size + 8;
11554               vc1_data += size + 8;
11555             }
11556             break;
11557           }
11558           case FOURCC_av01:
11559           {
11560             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11561             const guint8 *av1_data = stsd_entry_data + 0x56;
11562 
11563             /* find av1C */
11564             while (len >= 0x8) {
11565               gint size;
11566 
11567               if (QT_UINT32 (av1_data) <= len)
11568                 size = QT_UINT32 (av1_data) - 0x8;
11569               else
11570                 size = len - 0x8;
11571 
11572               if (size < 1)
11573                 /* No real data, so break out */
11574                 break;
11575 
11576               switch (QT_FOURCC (av1_data + 0x4)) {
11577                 case FOURCC_av1C:
11578                 {
11579                   /* parse, if found */
11580                   GstBuffer *buf;
11581                   guint8 pres_delay_field;
11582 
11583                   GST_DEBUG_OBJECT (qtdemux,
11584                       "found av1C codec_data in stsd of size %d", size);
11585 
11586                   /* not enough data, just ignore and hope for the best */
11587                   if (size < 5)
11588                     break;
11589 
11590                   /* Content is:
11591                    * 4 bytes: atom length
11592                    * 4 bytes: fourcc
11593                    * 1 byte: version
11594                    * 3 bytes: flags
11595                    * 3 bits: reserved
11596                    * 1 bits:  initial_presentation_delay_present
11597                    * 4 bits: initial_presentation_delay (if present else reserved
11598                    * rest: OBUs.
11599                    */
11600 
11601                   if (av1_data[9] != 0) {
11602                     GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11603                     break;
11604                   }
11605 
11606                   /* We skip initial_presentation_delay* for now */
11607                   pres_delay_field = *(av1_data + 12);
11608                   if (pres_delay_field & (1 << 5)) {
11609                     gst_caps_set_simple (entry->caps,
11610                         "presentation-delay", G_TYPE_INT,
11611                         (gint) (pres_delay_field & 0x0F) + 1, NULL);
11612                   }
11613                   if (size > 5) {
11614                     buf = gst_buffer_new_and_alloc (size - 5);
11615                     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11616                     gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11617                     gst_caps_set_simple (entry->caps,
11618                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
11619                     gst_buffer_unref (buf);
11620                   }
11621                   break;
11622                 }
11623                 default:
11624                   break;
11625               }
11626 
11627               len -= size + 8;
11628               av1_data += size + 8;
11629             }
11630 
11631             break;
11632           }
11633           default:
11634             break;
11635         }
11636       }
11637 
11638       GST_INFO_OBJECT (qtdemux,
11639           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11640           GST_FOURCC_ARGS (fourcc), entry->caps);
11641 
11642     } else if (stream->subtype == FOURCC_soun) {
11643       GNode *wave;
11644       int version, samplesize;
11645       guint16 compression_id;
11646       gboolean amrwb = FALSE;
11647 
11648       offset = 16;
11649       /* sample description entry (16) + sound sample description v0 (20) */
11650       if (len < 36)
11651         goto corrupt_file;
11652 
11653       version = QT_UINT32 (stsd_entry_data + offset);
11654       entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11655       samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11656       compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11657       entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11658 
11659       GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
11660       GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
11661           QT_UINT32 (stsd_entry_data + offset + 4));
11662       GST_LOG_OBJECT (qtdemux, "n_channels:       %d", entry->n_channels);
11663       GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
11664       GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
11665       GST_LOG_OBJECT (qtdemux, "packet size:      %d",
11666           QT_UINT16 (stsd_entry_data + offset + 14));
11667       GST_LOG_OBJECT (qtdemux, "sample rate:      %g", entry->rate);
11668 
11669       if (compression_id == 0xfffe)
11670         entry->sampled = TRUE;
11671 
11672       /* first assume uncompressed audio */
11673       entry->bytes_per_sample = samplesize / 8;
11674       entry->samples_per_frame = entry->n_channels;
11675       entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11676       entry->samples_per_packet = entry->samples_per_frame;
11677       entry->bytes_per_packet = entry->bytes_per_sample;
11678 
11679       offset = 36;
11680       switch (fourcc) {
11681           /* Yes, these have to be hard-coded */
11682         case FOURCC_MAC6:
11683         {
11684           entry->samples_per_packet = 6;
11685           entry->bytes_per_packet = 1;
11686           entry->bytes_per_frame = 1 * entry->n_channels;
11687           entry->bytes_per_sample = 1;
11688           entry->samples_per_frame = 6 * entry->n_channels;
11689           break;
11690         }
11691         case FOURCC_MAC3:
11692         {
11693           entry->samples_per_packet = 3;
11694           entry->bytes_per_packet = 1;
11695           entry->bytes_per_frame = 1 * entry->n_channels;
11696           entry->bytes_per_sample = 1;
11697           entry->samples_per_frame = 3 * entry->n_channels;
11698           break;
11699         }
11700         case FOURCC_ima4:
11701         {
11702           entry->samples_per_packet = 64;
11703           entry->bytes_per_packet = 34;
11704           entry->bytes_per_frame = 34 * entry->n_channels;
11705           entry->bytes_per_sample = 2;
11706           entry->samples_per_frame = 64 * entry->n_channels;
11707           break;
11708         }
11709         case FOURCC_ulaw:
11710         case FOURCC_alaw:
11711         {
11712           entry->samples_per_packet = 1;
11713           entry->bytes_per_packet = 1;
11714           entry->bytes_per_frame = 1 * entry->n_channels;
11715           entry->bytes_per_sample = 1;
11716           entry->samples_per_frame = 1 * entry->n_channels;
11717           break;
11718         }
11719         case FOURCC_agsm:
11720         {
11721           entry->samples_per_packet = 160;
11722           entry->bytes_per_packet = 33;
11723           entry->bytes_per_frame = 33 * entry->n_channels;
11724           entry->bytes_per_sample = 2;
11725           entry->samples_per_frame = 160 * entry->n_channels;
11726           break;
11727         }
11728         default:
11729           break;
11730       }
11731 
11732       if (version == 0x00010000) {
11733         /* sample description entry (16) + sound sample description v1 (20+16) */
11734         if (len < 52)
11735           goto corrupt_file;
11736 
11737         switch (fourcc) {
11738           case FOURCC_twos:
11739           case FOURCC_sowt:
11740           case FOURCC_raw_:
11741           case FOURCC_lpcm:
11742             break;
11743           default:
11744           {
11745             /* only parse extra decoding config for non-pcm audio */
11746             entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11747             entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11748             entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11749             entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11750 
11751             GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
11752                 entry->samples_per_packet);
11753             GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
11754                 entry->bytes_per_packet);
11755             GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
11756                 entry->bytes_per_frame);
11757             GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
11758                 entry->bytes_per_sample);
11759 
11760             if (!entry->sampled && entry->bytes_per_packet) {
11761               entry->samples_per_frame = (entry->bytes_per_frame /
11762                   entry->bytes_per_packet) * entry->samples_per_packet;
11763               GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
11764                   entry->samples_per_frame);
11765             }
11766             break;
11767           }
11768         }
11769       } else if (version == 0x00020000) {
11770         union
11771         {
11772           gdouble fp;
11773           guint64 val;
11774         } qtfp;
11775 
11776         /* sample description entry (16) + sound sample description v2 (56) */
11777         if (len < 72)
11778           goto corrupt_file;
11779 
11780         qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
11781         entry->rate = qtfp.fp;
11782         entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11783 
11784         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11785         GST_LOG_OBJECT (qtdemux, "sample rate:        %g", entry->rate);
11786         GST_LOG_OBJECT (qtdemux, "n_channels:         %d", entry->n_channels);
11787         GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
11788             QT_UINT32 (stsd_entry_data + offset + 20));
11789         GST_LOG_OBJECT (qtdemux, "format flags:       %X",
11790             QT_UINT32 (stsd_entry_data + offset + 24));
11791         GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
11792             QT_UINT32 (stsd_entry_data + offset + 28));
11793         GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11794             QT_UINT32 (stsd_entry_data + offset + 32));
11795       } else if (version != 0x00000) {
11796         GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11797             version);
11798       }
11799 
11800       if (entry->caps)
11801         gst_caps_unref (entry->caps);
11802 
11803       entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
11804           stsd_entry_data + 32, len - 16, &codec);
11805 
11806       switch (fourcc) {
11807         case FOURCC_in24:
11808         {
11809           GNode *enda;
11810           GNode *in24;
11811 
11812           in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
11813 
11814           enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
11815           if (!enda) {
11816             wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
11817             if (wave)
11818               enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
11819           }
11820           if (enda) {
11821             int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
11822             gst_caps_set_simple (entry->caps,
11823                 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
11824                 NULL);
11825           }
11826           break;
11827         }
11828         case FOURCC_owma:
11829         {
11830           const guint8 *owma_data;
11831           const gchar *codec_name = NULL;
11832           guint owma_len;
11833           GstBuffer *buf;
11834           gint version = 1;
11835           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11836           /* FIXME this should also be gst_riff_strf_auds,
11837            * but the latter one is actually missing bits-per-sample :( */
11838           typedef struct
11839           {
11840             gint16 wFormatTag;
11841             gint16 nChannels;
11842             gint32 nSamplesPerSec;
11843             gint32 nAvgBytesPerSec;
11844             gint16 nBlockAlign;
11845             gint16 wBitsPerSample;
11846             gint16 cbSize;
11847           } WAVEFORMATEX;
11848           WAVEFORMATEX *wfex;
11849 
11850           GST_DEBUG_OBJECT (qtdemux, "parse owma");
11851           owma_data = stsd_entry_data;
11852           owma_len = QT_UINT32 (owma_data);
11853           if (owma_len <= 54) {
11854             GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11855             break;
11856           }
11857           wfex = (WAVEFORMATEX *) (owma_data + 36);
11858           buf = gst_buffer_new_and_alloc (owma_len - 54);
11859           gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11860           if (wfex->wFormatTag == 0x0161) {
11861             codec_name = "Windows Media Audio";
11862             version = 2;
11863           } else if (wfex->wFormatTag == 0x0162) {
11864             codec_name = "Windows Media Audio 9 Pro";
11865             version = 3;
11866           } else if (wfex->wFormatTag == 0x0163) {
11867             codec_name = "Windows Media Audio 9 Lossless";
11868             /* is that correct? gstffmpegcodecmap.c is missing it, but
11869              * fluendo codec seems to support it */
11870             version = 4;
11871           }
11872 
11873           gst_caps_set_simple (entry->caps,
11874               "codec_data", GST_TYPE_BUFFER, buf,
11875               "wmaversion", G_TYPE_INT, version,
11876               "block_align", G_TYPE_INT,
11877               GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11878               GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11879               GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11880               GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11881           gst_buffer_unref (buf);
11882 
11883           if (codec_name) {
11884             g_free (codec);
11885             codec = g_strdup (codec_name);
11886           }
11887           break;
11888         }
11889         case FOURCC_wma_:
11890         {
11891           gint len = QT_UINT32 (stsd_entry_data) - offset;
11892           const guint8 *wfex_data = stsd_entry_data + offset;
11893           const gchar *codec_name = NULL;
11894           gint version = 1;
11895           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11896           /* FIXME this should also be gst_riff_strf_auds,
11897            * but the latter one is actually missing bits-per-sample :( */
11898           typedef struct
11899           {
11900             gint16 wFormatTag;
11901             gint16 nChannels;
11902             gint32 nSamplesPerSec;
11903             gint32 nAvgBytesPerSec;
11904             gint16 nBlockAlign;
11905             gint16 wBitsPerSample;
11906             gint16 cbSize;
11907           } WAVEFORMATEX;
11908           WAVEFORMATEX wfex;
11909 
11910           /* FIXME: unify with similar wavformatex parsing code above */
11911           GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11912 
11913           /* find wfex */
11914           while (len >= 8) {
11915             gint size;
11916 
11917             if (QT_UINT32 (wfex_data) <= len)
11918               size = QT_UINT32 (wfex_data) - 8;
11919             else
11920               size = len - 8;
11921 
11922             if (size < 1)
11923               /* No real data, so break out */
11924               break;
11925 
11926             switch (QT_FOURCC (wfex_data + 4)) {
11927               case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11928               {
11929                 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11930 
11931                 if (size < 8 + 18)
11932                   break;
11933 
11934                 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11935                 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11936                 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11937                 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11938                 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11939                 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11940                 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11941 
11942                 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11943                 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11944                     "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11945                     "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11946                     wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11947                     wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11948 
11949                 if (wfex.wFormatTag == 0x0161) {
11950                   codec_name = "Windows Media Audio";
11951                   version = 2;
11952                 } else if (wfex.wFormatTag == 0x0162) {
11953                   codec_name = "Windows Media Audio 9 Pro";
11954                   version = 3;
11955                 } else if (wfex.wFormatTag == 0x0163) {
11956                   codec_name = "Windows Media Audio 9 Lossless";
11957                   /* is that correct? gstffmpegcodecmap.c is missing it, but
11958                    * fluendo codec seems to support it */
11959                   version = 4;
11960                 }
11961 
11962                 gst_caps_set_simple (entry->caps,
11963                     "wmaversion", G_TYPE_INT, version,
11964                     "block_align", G_TYPE_INT, wfex.nBlockAlign,
11965                     "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11966                     "width", G_TYPE_INT, wfex.wBitsPerSample,
11967                     "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11968 
11969                 if (size > wfex.cbSize) {
11970                   GstBuffer *buf;
11971 
11972                   buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11973                   gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11974                       size - wfex.cbSize);
11975                   gst_caps_set_simple (entry->caps,
11976                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11977                   gst_buffer_unref (buf);
11978                 } else {
11979                   GST_WARNING_OBJECT (qtdemux, "no codec data");
11980                 }
11981 
11982                 if (codec_name) {
11983                   g_free (codec);
11984                   codec = g_strdup (codec_name);
11985                 }
11986                 break;
11987               }
11988               default:
11989                 break;
11990             }
11991             len -= size + 8;
11992             wfex_data += size + 8;
11993           }
11994           break;
11995         }
11996         case FOURCC_opus:
11997         {
11998           const guint8 *opus_data;
11999           guint8 *channel_mapping = NULL;
12000           guint32 rate;
12001           guint8 channels;
12002           guint8 channel_mapping_family;
12003           guint8 stream_count;
12004           guint8 coupled_count;
12005           guint8 i;
12006 
12007           opus_data = stsd_entry_data;
12008 
12009           channels = GST_READ_UINT8 (opus_data + 45);
12010           rate = GST_READ_UINT32_LE (opus_data + 48);
12011           channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
12012           stream_count = GST_READ_UINT8 (opus_data + 55);
12013           coupled_count = GST_READ_UINT8 (opus_data + 56);
12014 
12015           if (channels > 0) {
12016             channel_mapping = g_malloc (channels * sizeof (guint8));
12017             for (i = 0; i < channels; i++)
12018               channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
12019           }
12020 
12021           entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12022               channel_mapping_family, stream_count, coupled_count,
12023               channel_mapping);
12024           break;
12025         }
12026         default:
12027           break;
12028       }
12029 
12030       if (codec) {
12031         GstStructure *s;
12032         gint bitrate = 0;
12033 
12034         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12035             GST_TAG_AUDIO_CODEC, codec, NULL);
12036         g_free (codec);
12037         codec = NULL;
12038 
12039         /* some bitrate info may have ended up in caps */
12040         s = gst_caps_get_structure (entry->caps, 0);
12041         gst_structure_get_int (s, "bitrate", &bitrate);
12042         if (bitrate > 0)
12043           gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12044               GST_TAG_BITRATE, bitrate, NULL);
12045       }
12046 
12047       mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12048       if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12049         if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca)
12050           mp4a = NULL;
12051         else if (!stream->protected)
12052           mp4a = NULL;
12053       }
12054 
12055       wave = NULL;
12056       esds = NULL;
12057       if (mp4a) {
12058         wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12059         if (wave)
12060           esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12061         if (!esds)
12062           esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12063       }
12064 
12065 
12066       /* If the fourcc's bottom 16 bits gives 'sm', then the top
12067          16 bits is a byte-swapped wave-style codec identifier,
12068          and we can find a WAVE header internally to a 'wave' atom here.
12069          This can more clearly be thought of as 'ms' as the top 16 bits, and a
12070          codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12071          is big-endian).
12072        */
12073       if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12074         if (len < offset + 20) {
12075           GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12076         } else {
12077           guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12078           const guint8 *data = stsd_entry_data + offset + 16;
12079           GNode *wavenode;
12080           GNode *waveheadernode;
12081 
12082           wavenode = g_node_new ((guint8 *) data);
12083           if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12084             const guint8 *waveheader;
12085             guint32 headerlen;
12086 
12087             waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12088             if (waveheadernode) {
12089               waveheader = (const guint8 *) waveheadernode->data;
12090               headerlen = QT_UINT32 (waveheader);
12091 
12092               if (headerlen > 8) {
12093                 gst_riff_strf_auds *header = NULL;
12094                 GstBuffer *headerbuf;
12095                 GstBuffer *extra;
12096 
12097                 waveheader += 8;
12098                 headerlen -= 8;
12099 
12100                 headerbuf = gst_buffer_new_and_alloc (headerlen);
12101                 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12102 
12103                 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12104                         headerbuf, &header, &extra)) {
12105                   gst_caps_unref (entry->caps);
12106                   /* FIXME: Need to do something with the channel reorder map */
12107                   entry->caps =
12108                       gst_riff_create_audio_caps (header->format, NULL, header,
12109                       extra, NULL, NULL, NULL);
12110 
12111                   if (extra)
12112                     gst_buffer_unref (extra);
12113                   g_free (header);
12114                 }
12115               }
12116             } else
12117               GST_DEBUG ("Didn't find waveheadernode for this codec");
12118           }
12119           g_node_destroy (wavenode);
12120         }
12121       } else if (esds) {
12122         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12123             stream->stream_tags);
12124       } else {
12125         switch (fourcc) {
12126 #if 0
12127             /* FIXME: what is in the chunk? */
12128           case FOURCC_QDMC:
12129           {
12130             gint len = QT_UINT32 (stsd_data);
12131 
12132             /* seems to be always = 116 = 0x74 */
12133             break;
12134           }
12135 #endif
12136           case FOURCC_QDM2:
12137           {
12138             gint len = QT_UINT32 (stsd_entry_data);
12139 
12140             if (len > 0x3C) {
12141               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12142 
12143               gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12144               gst_caps_set_simple (entry->caps,
12145                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12146               gst_buffer_unref (buf);
12147             }
12148             gst_caps_set_simple (entry->caps,
12149                 "samplesize", G_TYPE_INT, samplesize, NULL);
12150             break;
12151           }
12152           case FOURCC_alac:
12153           {
12154             GNode *alac, *wave = NULL;
12155 
12156             /* apparently, m4a has this atom appended directly in the stsd entry,
12157              * while mov has it in a wave atom */
12158             alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12159             if (alac) {
12160               /* alac now refers to stsd entry atom */
12161               wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12162               if (wave)
12163                 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12164               else
12165                 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12166             }
12167             if (alac) {
12168               const guint8 *alac_data = alac->data;
12169               gint len = QT_UINT32 (alac->data);
12170               GstBuffer *buf;
12171 
12172               if (len < 36) {
12173                 GST_DEBUG_OBJECT (qtdemux,
12174                     "discarding alac atom with unexpected len %d", len);
12175               } else {
12176                 /* codec-data contains alac atom size and prefix,
12177                  * ffmpeg likes it that way, not quite gst-ish though ...*/
12178                 buf = gst_buffer_new_and_alloc (len);
12179                 gst_buffer_fill (buf, 0, alac->data, len);
12180                 gst_caps_set_simple (entry->caps,
12181                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12182                 gst_buffer_unref (buf);
12183 
12184                 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12185                 entry->n_channels = QT_UINT8 (alac_data + 21);
12186                 entry->rate = QT_UINT32 (alac_data + 32);
12187               }
12188             }
12189             gst_caps_set_simple (entry->caps,
12190                 "samplesize", G_TYPE_INT, samplesize, NULL);
12191             break;
12192           }
12193           case FOURCC_fLaC:
12194           {
12195             /* The codingname of the sample entry is 'fLaC' */
12196             GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12197 
12198             if (flac) {
12199               /* The 'dfLa' box is added to the sample entry to convey
12200                  initializing information for the decoder. */
12201               const GNode *dfla =
12202                   qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12203 
12204               if (dfla) {
12205                 const guint32 len = QT_UINT32 (dfla->data);
12206 
12207                 /* Must contain at least dfLa box header (12),
12208                  * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12209                 if (len < 50) {
12210                   GST_DEBUG_OBJECT (qtdemux,
12211                       "discarding dfla atom with unexpected len %d", len);
12212                 } else {
12213                   /* skip dfLa header to get the METADATA_BLOCKs */
12214                   const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12215                   const guint32 metadata_blocks_len = len - 12;
12216 
12217                   gchar *stream_marker = g_strdup ("fLaC");
12218                   GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12219                       strlen (stream_marker));
12220 
12221                   guint32 index = 0;
12222                   guint32 remainder = 0;
12223                   guint32 block_size = 0;
12224                   gboolean is_last = FALSE;
12225 
12226                   GValue array = G_VALUE_INIT;
12227                   GValue value = G_VALUE_INIT;
12228 
12229                   g_value_init (&array, GST_TYPE_ARRAY);
12230                   g_value_init (&value, GST_TYPE_BUFFER);
12231 
12232                   gst_value_set_buffer (&value, block);
12233                   gst_value_array_append_value (&array, &value);
12234                   g_value_reset (&value);
12235 
12236                   gst_buffer_unref (block);
12237 
12238                   /* check there's at least one METADATA_BLOCK_HEADER's worth
12239                    * of data, and we haven't already finished parsing */
12240                   while (!is_last && ((index + 3) < metadata_blocks_len)) {
12241                     remainder = metadata_blocks_len - index;
12242 
12243                     /* add the METADATA_BLOCK_HEADER size to the signalled size */
12244                     block_size = 4 +
12245                         (metadata_blocks[index + 1] << 16) +
12246                         (metadata_blocks[index + 2] << 8) +
12247                         metadata_blocks[index + 3];
12248 
12249                     /* be careful not to read off end of box */
12250                     if (block_size > remainder) {
12251                       break;
12252                     }
12253 
12254                     is_last = metadata_blocks[index] >> 7;
12255 
12256                     block = gst_buffer_new_and_alloc (block_size);
12257 
12258                     gst_buffer_fill (block, 0, &metadata_blocks[index],
12259                         block_size);
12260 
12261                     gst_value_set_buffer (&value, block);
12262                     gst_value_array_append_value (&array, &value);
12263                     g_value_reset (&value);
12264 
12265                     gst_buffer_unref (block);
12266 
12267                     index += block_size;
12268                   }
12269 
12270                   /* only append the metadata if we successfully read all of it */
12271                   if (is_last) {
12272                     gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12273                             (stream)->caps, 0), "streamheader", &array);
12274                   } else {
12275                     GST_WARNING_OBJECT (qtdemux,
12276                         "discarding all METADATA_BLOCKs due to invalid "
12277                         "block_size %d at idx %d, rem %d", block_size, index,
12278                         remainder);
12279                   }
12280 
12281                   g_value_unset (&value);
12282                   g_value_unset (&array);
12283 
12284                   /* The sample rate obtained from the stsd may not be accurate
12285                    * since it cannot represent rates greater than 65535Hz, so
12286                    * override that value with the sample rate from the
12287                    * METADATA_BLOCK_STREAMINFO block */
12288                   CUR_STREAM (stream)->rate =
12289                       (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12290                 }
12291               }
12292             }
12293             break;
12294           }
12295           case FOURCC_sawb:
12296             /* Fallthrough! */
12297             amrwb = TRUE;
12298           case FOURCC_samr:
12299           {
12300             gint len = QT_UINT32 (stsd_entry_data);
12301 
12302             if (len > 0x24) {
12303               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12304               guint bitrate;
12305 
12306               gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12307 
12308               /* If we have enough data, let's try to get the 'damr' atom. See
12309                * the 3GPP container spec (26.244) for more details. */
12310               if ((len - 0x34) > 8 &&
12311                   (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12312                 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12313                     GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12314               }
12315 
12316               gst_caps_set_simple (entry->caps,
12317                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12318               gst_buffer_unref (buf);
12319             }
12320             break;
12321           }
12322           case FOURCC_mp4a:
12323           {
12324             /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12325             gint len = QT_UINT32 (stsd_entry_data);
12326 
12327             if (len >= 34) {
12328               guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12329 
12330               if (sound_version == 1) {
12331                 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12332                 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12333                 guint8 codec_data[2];
12334                 GstBuffer *buf;
12335                 gint profile = 2;       /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12336 
12337                 gint sample_rate_index =
12338                     gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12339 
12340                 /* build AAC codec data */
12341                 codec_data[0] = profile << 3;
12342                 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12343                 codec_data[1] = (sample_rate_index & 0x01) << 7;
12344                 codec_data[1] |= (channels & 0xF) << 3;
12345 
12346                 buf = gst_buffer_new_and_alloc (2);
12347                 gst_buffer_fill (buf, 0, codec_data, 2);
12348                 gst_caps_set_simple (entry->caps,
12349                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12350                 gst_buffer_unref (buf);
12351               }
12352             }
12353             break;
12354           }
12355           case FOURCC_lpcm:
12356             /* Fully handled elsewhere */
12357             break;
12358           default:
12359             GST_INFO_OBJECT (qtdemux,
12360                 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12361             break;
12362         }
12363       }
12364       GST_INFO_OBJECT (qtdemux,
12365           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12366           GST_FOURCC_ARGS (fourcc), entry->caps);
12367 
12368     } else if (stream->subtype == FOURCC_strm) {
12369       if (fourcc == FOURCC_rtsp) {
12370         stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12371       } else {
12372         GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12373             GST_FOURCC_ARGS (fourcc));
12374         goto unknown_stream;
12375       }
12376       entry->sampled = TRUE;
12377     } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12378         || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12379         || stream->subtype == FOURCC_clcp) {
12380 
12381       entry->sampled = TRUE;
12382       entry->sparse = TRUE;
12383 
12384       entry->caps =
12385           qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12386           &codec);
12387       if (codec) {
12388         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12389             GST_TAG_SUBTITLE_CODEC, codec, NULL);
12390         g_free (codec);
12391         codec = NULL;
12392       }
12393 
12394       /* hunt for sort-of codec data */
12395       switch (fourcc) {
12396         case FOURCC_mp4s:
12397         {
12398           GNode *mp4s = NULL;
12399           GNode *esds = NULL;
12400 
12401           /* look for palette in a stsd->mp4s->esds sub-atom */
12402           mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12403           if (mp4s)
12404             esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12405           if (esds == NULL) {
12406             /* Invalid STSD */
12407             GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12408             break;
12409           }
12410 
12411           gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12412               stream->stream_tags);
12413           break;
12414         }
12415         default:
12416           GST_INFO_OBJECT (qtdemux,
12417               "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12418           break;
12419       }
12420       GST_INFO_OBJECT (qtdemux,
12421           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12422           GST_FOURCC_ARGS (fourcc), entry->caps);
12423     } else {
12424       /* everything in 1 sample */
12425       entry->sampled = TRUE;
12426 
12427       entry->caps =
12428           qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12429           &codec);
12430 
12431       if (entry->caps == NULL)
12432         goto unknown_stream;
12433 
12434       if (codec) {
12435         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12436             GST_TAG_SUBTITLE_CODEC, codec, NULL);
12437         g_free (codec);
12438         codec = NULL;
12439       }
12440     }
12441 
12442     /* promote to sampled format */
12443     if (entry->fourcc == FOURCC_samr) {
12444       /* force mono 8000 Hz for AMR */
12445       entry->sampled = TRUE;
12446       entry->n_channels = 1;
12447       entry->rate = 8000;
12448     } else if (entry->fourcc == FOURCC_sawb) {
12449       /* force mono 16000 Hz for AMR-WB */
12450       entry->sampled = TRUE;
12451       entry->n_channels = 1;
12452       entry->rate = 16000;
12453     } else if (entry->fourcc == FOURCC_mp4a) {
12454       entry->sampled = TRUE;
12455     }
12456 
12457 
12458     stsd_entry_data += len;
12459     remaining_stsd_len -= len;
12460 
12461   }
12462 
12463   /* collect sample information */
12464   if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12465     goto samples_failed;
12466 
12467   if (qtdemux->fragmented) {
12468     guint64 offset;
12469 
12470     /* need all moov samples as basis; probably not many if any at all */
12471     /* prevent moof parsing taking of at this time */
12472     offset = qtdemux->moof_offset;
12473     qtdemux->moof_offset = 0;
12474     if (stream->n_samples &&
12475         !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12476       qtdemux->moof_offset = offset;
12477       goto samples_failed;
12478     }
12479     qtdemux->moof_offset = 0;
12480     /* movie duration more reliable in this case (e.g. mehd) */
12481     if (qtdemux->segment.duration &&
12482         GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12483       stream->duration =
12484           GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12485   }
12486 
12487   /* configure segments */
12488   if (!qtdemux_parse_segments (qtdemux, stream, trak))
12489     goto segments_failed;
12490 
12491   /* add some language tag, if useful */
12492   if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12493       strcmp (stream->lang_id, "und")) {
12494     const gchar *lang_code;
12495 
12496     /* convert ISO 639-2 code to ISO 639-1 */
12497     lang_code = gst_tag_get_language_code (stream->lang_id);
12498     gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12499         GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12500   }
12501 
12502   /* Check for UDTA tags */
12503   if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12504     qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12505   }
12506 
12507   /* Insert and sort new stream in track-id order.
12508    * This will help in comparing old/new streams during stream update check */
12509   g_ptr_array_add (qtdemux->active_streams, stream);
12510   g_ptr_array_sort (qtdemux->active_streams,
12511       (GCompareFunc) qtdemux_track_id_compare_func);
12512   GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
12513       QTDEMUX_N_STREAMS (qtdemux));
12514 
12515   return TRUE;
12516 
12517 /* ERRORS */
12518 corrupt_file:
12519   {
12520     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12521         (_("This file is corrupt and cannot be played.")), (NULL));
12522     if (stream)
12523       gst_qtdemux_stream_unref (stream);
12524     return FALSE;
12525   }
12526 error_encrypted:
12527   {
12528     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12529     gst_qtdemux_stream_unref (stream);
12530     return FALSE;
12531   }
12532 samples_failed:
12533 segments_failed:
12534   {
12535     /* we posted an error already */
12536     /* free stbl sub-atoms */
12537     gst_qtdemux_stbl_free (stream);
12538     gst_qtdemux_stream_unref (stream);
12539     return FALSE;
12540   }
12541 existing_stream:
12542   {
12543     GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12544         track_id);
12545     return TRUE;
12546   }
12547 unknown_stream:
12548   {
12549     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12550         GST_FOURCC_ARGS (stream->subtype));
12551     gst_qtdemux_stream_unref (stream);
12552     return TRUE;
12553   }
12554 }
12555 
12556 /* If we can estimate the overall bitrate, and don't have information about the
12557  * stream bitrate for exactly one stream, this guesses the stream bitrate as
12558  * the overall bitrate minus the sum of the bitrates of all other streams. This
12559  * should be useful for the common case where we have one audio and one video
12560  * stream and can estimate the bitrate of one, but not the other. */
12561 static void
gst_qtdemux_guess_bitrate(GstQTDemux * qtdemux)12562 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12563 {
12564   QtDemuxStream *stream = NULL;
12565   gint64 size, sys_bitrate, sum_bitrate = 0;
12566   GstClockTime duration;
12567   guint bitrate;
12568   gint i;
12569 
12570   if (qtdemux->fragmented)
12571     return;
12572 
12573   GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12574 
12575   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12576       || size <= 0) {
12577     GST_DEBUG_OBJECT (qtdemux,
12578         "Size in bytes of the stream not known - bailing");
12579     return;
12580   }
12581 
12582   /* Subtract the header size */
12583   GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12584       size, qtdemux->header_size);
12585 
12586   if (size < qtdemux->header_size)
12587     return;
12588 
12589   size = size - qtdemux->header_size;
12590 
12591   if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12592     GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12593     return;
12594   }
12595 
12596   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12597     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
12598     switch (str->subtype) {
12599       case FOURCC_soun:
12600       case FOURCC_vide:
12601         GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12602             CUR_STREAM (str)->caps);
12603         /* retrieve bitrate, prefer avg then max */
12604         bitrate = 0;
12605         if (str->stream_tags) {
12606           if (gst_tag_list_get_uint (str->stream_tags,
12607                   GST_TAG_MAXIMUM_BITRATE, &bitrate))
12608             GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
12609           if (gst_tag_list_get_uint (str->stream_tags,
12610                   GST_TAG_NOMINAL_BITRATE, &bitrate))
12611             GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
12612           if (gst_tag_list_get_uint (str->stream_tags,
12613                   GST_TAG_BITRATE, &bitrate))
12614             GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12615         }
12616         if (bitrate)
12617           sum_bitrate += bitrate;
12618         else {
12619           if (stream) {
12620             GST_DEBUG_OBJECT (qtdemux,
12621                 ">1 stream with unknown bitrate - bailing");
12622             return;
12623           } else
12624             stream = str;
12625         }
12626 
12627       default:
12628         /* For other subtypes, we assume no significant impact on bitrate */
12629         break;
12630     }
12631   }
12632 
12633   if (!stream) {
12634     GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12635     return;
12636   }
12637 
12638   sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12639 
12640   if (sys_bitrate < sum_bitrate) {
12641     /* This can happen, since sum_bitrate might be derived from maximum
12642      * bitrates and not average bitrates */
12643     GST_DEBUG_OBJECT (qtdemux,
12644         "System bitrate less than sum bitrate - bailing");
12645     return;
12646   }
12647 
12648   bitrate = sys_bitrate - sum_bitrate;
12649   GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12650       ", Stream bitrate = %u", sys_bitrate, bitrate);
12651 
12652   if (!stream->stream_tags)
12653     stream->stream_tags = gst_tag_list_new_empty ();
12654   else
12655     stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12656 
12657   gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12658       GST_TAG_BITRATE, bitrate, NULL);
12659 }
12660 
12661 static GstFlowReturn
qtdemux_prepare_streams(GstQTDemux * qtdemux)12662 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12663 {
12664   GstFlowReturn ret = GST_FLOW_OK;
12665   gint i;
12666 
12667   GST_DEBUG_OBJECT (qtdemux, "prepare streams");
12668 
12669   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12670     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12671     guint32 sample_num = 0;
12672 
12673     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12674         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12675 
12676     if (qtdemux->fragmented) {
12677       /* need all moov samples first */
12678       GST_OBJECT_LOCK (qtdemux);
12679       while (stream->n_samples == 0)
12680         if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12681           break;
12682       GST_OBJECT_UNLOCK (qtdemux);
12683     } else {
12684       /* discard any stray moof */
12685       qtdemux->moof_offset = 0;
12686     }
12687 
12688     /* prepare braking */
12689     if (ret != GST_FLOW_ERROR)
12690       ret = GST_FLOW_OK;
12691 
12692     /* in pull mode, we should have parsed some sample info by now;
12693      * and quite some code will not handle no samples.
12694      * in push mode, we'll just have to deal with it */
12695     if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
12696       GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
12697       g_ptr_array_remove_index (qtdemux->active_streams, i);
12698       i--;
12699       continue;
12700     } else if (stream->track_id == qtdemux->chapters_track_id &&
12701         (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
12702       /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
12703          so that it doesn't look like a subtitle track */
12704       g_ptr_array_remove_index (qtdemux->active_streams, i);
12705       i--;
12706       continue;
12707     }
12708 
12709     /* parse the initial sample for use in setting the frame rate cap */
12710     while (sample_num == 0 && sample_num < stream->n_samples) {
12711       if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
12712         break;
12713       ++sample_num;
12714     }
12715   }
12716 
12717   return ret;
12718 }
12719 
12720 static gboolean
_stream_equal_func(const QtDemuxStream * stream,const gchar * stream_id)12721 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
12722 {
12723   return g_strcmp0 (stream->stream_id, stream_id) == 0;
12724 }
12725 
12726 static gboolean
qtdemux_is_streams_update(GstQTDemux * qtdemux)12727 qtdemux_is_streams_update (GstQTDemux * qtdemux)
12728 {
12729   gint i;
12730 
12731   /* Different length, updated */
12732   if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
12733     return TRUE;
12734 
12735   /* streams in list are sorted in track-id order */
12736   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12737     /* Different stream-id, updated */
12738     if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
12739             QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
12740       return TRUE;
12741   }
12742 
12743   return FALSE;
12744 }
12745 
12746 static gboolean
qtdemux_reuse_and_configure_stream(GstQTDemux * qtdemux,QtDemuxStream * oldstream,QtDemuxStream * newstream)12747 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
12748     QtDemuxStream * oldstream, QtDemuxStream * newstream)
12749 {
12750   /* Connect old stream's srcpad to new stream */
12751   newstream->pad = oldstream->pad;
12752   oldstream->pad = NULL;
12753 
12754   /* unset new_stream to prevent stream-start event */
12755   newstream->new_stream = FALSE;
12756 
12757   return gst_qtdemux_configure_stream (qtdemux, newstream);
12758 }
12759 
12760 /* g_ptr_array_find_with_equal_func is available since 2.54,
12761  * replacement until we can depend unconditionally on the real one in GLib */
12762 #if !GLIB_CHECK_VERSION(2,54,0)
12763 #define g_ptr_array_find_with_equal_func qtdemux_ptr_array_find_with_equal_func
12764 static gboolean
qtdemux_ptr_array_find_with_equal_func(GPtrArray * haystack,gconstpointer needle,GEqualFunc equal_func,guint * index_)12765 qtdemux_ptr_array_find_with_equal_func (GPtrArray * haystack,
12766     gconstpointer needle, GEqualFunc equal_func, guint * index_)
12767 {
12768   guint i;
12769 
12770   g_return_val_if_fail (haystack != NULL, FALSE);
12771 
12772   if (equal_func == NULL)
12773     equal_func = g_direct_equal;
12774 
12775   for (i = 0; i < haystack->len; i++) {
12776     if (equal_func (g_ptr_array_index (haystack, i), needle)) {
12777       if (index_ != NULL)
12778         *index_ = i;
12779       return TRUE;
12780     }
12781   }
12782 
12783   return FALSE;
12784 }
12785 #endif
12786 
12787 static gboolean
qtdemux_update_streams(GstQTDemux * qtdemux)12788 qtdemux_update_streams (GstQTDemux * qtdemux)
12789 {
12790   gint i;
12791   g_assert (qtdemux->streams_aware);
12792 
12793   /* At below, figure out which stream in active_streams has identical stream-id
12794    * with that of in old_streams. If there is matching stream-id,
12795    * corresponding newstream will not be exposed again,
12796    * but demux will reuse srcpad of matched old stream
12797    *
12798    * active_streams : newly created streams from the latest moov
12799    * old_streams : existing streams (belong to previous moov)
12800    */
12801 
12802   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12803     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12804     QtDemuxStream *oldstream = NULL;
12805     guint target;
12806 
12807     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12808         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12809 
12810     if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
12811             stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
12812       oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
12813 
12814       /* null pad stream cannot be reused */
12815       if (oldstream->pad == NULL)
12816         oldstream = NULL;
12817     }
12818 
12819     if (oldstream) {
12820       GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
12821 
12822       if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
12823         return FALSE;
12824 
12825       /* we don't need to preserve order of old streams */
12826       g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
12827     } else {
12828       GstTagList *list;
12829 
12830       /* now we have all info and can expose */
12831       list = stream->stream_tags;
12832       stream->stream_tags = NULL;
12833       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12834         return FALSE;
12835     }
12836   }
12837 
12838   return TRUE;
12839 }
12840 
12841 /* Must be called with expose lock */
12842 static GstFlowReturn
qtdemux_expose_streams(GstQTDemux * qtdemux)12843 qtdemux_expose_streams (GstQTDemux * qtdemux)
12844 {
12845   gint i;
12846 
12847   GST_DEBUG_OBJECT (qtdemux, "exposing streams");
12848 
12849   if (!qtdemux_is_streams_update (qtdemux)) {
12850     GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
12851     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12852       QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12853       QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
12854       if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
12855         return GST_FLOW_ERROR;
12856     }
12857 
12858     g_ptr_array_set_size (qtdemux->old_streams, 0);
12859     qtdemux->need_segment = TRUE;
12860 
12861     return GST_FLOW_OK;
12862   }
12863 
12864   if (qtdemux->streams_aware) {
12865     if (!qtdemux_update_streams (qtdemux))
12866       return GST_FLOW_ERROR;
12867   } else {
12868     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12869       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12870       GstTagList *list;
12871 
12872       /* now we have all info and can expose */
12873       list = stream->stream_tags;
12874       stream->stream_tags = NULL;
12875       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12876         return GST_FLOW_ERROR;
12877 
12878     }
12879   }
12880 
12881   gst_qtdemux_guess_bitrate (qtdemux);
12882 
12883   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
12884 
12885   /* If we have still old_streams, it's no more used stream */
12886   for (i = 0; i < qtdemux->old_streams->len; i++) {
12887     QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
12888 
12889     if (stream->pad) {
12890       GstEvent *event;
12891 
12892       event = gst_event_new_eos ();
12893       if (qtdemux->segment_seqnum)
12894         gst_event_set_seqnum (event, qtdemux->segment_seqnum);
12895 
12896       gst_pad_push_event (stream->pad, event);
12897     }
12898   }
12899 
12900   g_ptr_array_set_size (qtdemux->old_streams, 0);
12901 
12902   /* check if we should post a redirect in case there is a single trak
12903    * and it is a redirecting trak */
12904   if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
12905       QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
12906     GstMessage *m;
12907 
12908     GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
12909         "an external content");
12910     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
12911         gst_structure_new ("redirect",
12912             "new-location", G_TYPE_STRING,
12913             QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
12914     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
12915     qtdemux->posted_redirect = TRUE;
12916   }
12917 
12918   g_ptr_array_foreach (qtdemux->active_streams,
12919       (GFunc) qtdemux_do_allocation, qtdemux);
12920 
12921   qtdemux->need_segment = TRUE;
12922 
12923   qtdemux->exposed = TRUE;
12924   return GST_FLOW_OK;
12925 }
12926 
12927 /* check if major or compatible brand is 3GP */
12928 static inline gboolean
qtdemux_is_brand_3gp(GstQTDemux * qtdemux,gboolean major)12929 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
12930 {
12931   if (major) {
12932     return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12933         FOURCC_3g__);
12934   } else if (qtdemux->comp_brands != NULL) {
12935     GstMapInfo map;
12936     guint8 *data;
12937     gsize size;
12938     gboolean res = FALSE;
12939 
12940     gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
12941     data = map.data;
12942     size = map.size;
12943     while (size >= 4) {
12944       res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12945           FOURCC_3g__);
12946       data += 4;
12947       size -= 4;
12948     }
12949     gst_buffer_unmap (qtdemux->comp_brands, &map);
12950     return res;
12951   } else {
12952     return FALSE;
12953   }
12954 }
12955 
12956 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12957 static inline gboolean
qtdemux_is_string_tag_3gp(GstQTDemux * qtdemux,guint32 fourcc)12958 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12959 {
12960   return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12961       || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12962       || fourcc == FOURCC_albm;
12963 }
12964 
12965 static void
qtdemux_tag_add_location(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag,const char * dummy,GNode * node)12966 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12967     const char *tag, const char *dummy, GNode * node)
12968 {
12969   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12970   int offset;
12971   char *name;
12972   gchar *data;
12973   gdouble longitude, latitude, altitude;
12974   gint len;
12975 
12976   len = QT_UINT32 (node->data);
12977   if (len <= 14)
12978     goto short_read;
12979 
12980   data = node->data;
12981   offset = 14;
12982 
12983   /* TODO: language code skipped */
12984 
12985   name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12986 
12987   if (!name) {
12988     /* do not alarm in trivial case, but bail out otherwise */
12989     if (*(data + offset) != 0) {
12990       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12991           "giving up", tag);
12992     }
12993   } else {
12994     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12995         GST_TAG_GEO_LOCATION_NAME, name, NULL);
12996     offset += strlen (name);
12997     g_free (name);
12998   }
12999 
13000   if (len < offset + 2 + 4 + 4 + 4)
13001     goto short_read;
13002 
13003   /* +1 +1 = skip null-terminator and location role byte */
13004   offset += 1 + 1;
13005   /* table in spec says unsigned, semantics say negative has meaning ... */
13006   longitude = QT_SFP32 (data + offset);
13007 
13008   offset += 4;
13009   latitude = QT_SFP32 (data + offset);
13010 
13011   offset += 4;
13012   altitude = QT_SFP32 (data + offset);
13013 
13014   /* one invalid means all are invalid */
13015   if (longitude >= -180.0 && longitude <= 180.0 &&
13016       latitude >= -90.0 && latitude <= 90.0) {
13017     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
13018         GST_TAG_GEO_LOCATION_LATITUDE, latitude,
13019         GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
13020         GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
13021   }
13022 
13023   /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
13024 
13025   return;
13026 
13027   /* ERRORS */
13028 short_read:
13029   {
13030     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
13031     return;
13032   }
13033 }
13034 
13035 
13036 static void
qtdemux_tag_add_year(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag,const char * dummy,GNode * node)13037 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
13038     const char *tag, const char *dummy, GNode * node)
13039 {
13040   guint16 y;
13041   GDate *date;
13042   gint len;
13043 
13044   len = QT_UINT32 (node->data);
13045   if (len < 14)
13046     return;
13047 
13048   y = QT_UINT16 ((guint8 *) node->data + 12);
13049   if (y == 0) {
13050     GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
13051     return;
13052   }
13053   GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
13054 
13055   date = g_date_new_dmy (1, 1, y);
13056   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13057   g_date_free (date);
13058 }
13059 
13060 static void
qtdemux_tag_add_classification(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag,const char * dummy,GNode * node)13061 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
13062     const char *tag, const char *dummy, GNode * node)
13063 {
13064   int offset;
13065   char *tag_str = NULL;
13066   guint8 *entity;
13067   guint16 table;
13068   gint len;
13069 
13070   len = QT_UINT32 (node->data);
13071   if (len <= 20)
13072     goto short_read;
13073 
13074   offset = 12;
13075   entity = (guint8 *) node->data + offset;
13076   if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
13077     GST_DEBUG_OBJECT (qtdemux,
13078         "classification info: %c%c%c%c invalid classification entity",
13079         entity[0], entity[1], entity[2], entity[3]);
13080     return;
13081   }
13082 
13083   offset += 4;
13084   table = QT_UINT16 ((guint8 *) node->data + offset);
13085 
13086   /* Language code skipped */
13087 
13088   offset += 4;
13089 
13090   /* Tag format: "XXXX://Y[YYYY]/classification info string"
13091    * XXXX: classification entity, fixed length 4 chars.
13092    * Y[YYYY]: classification table, max 5 chars.
13093    */
13094   tag_str = g_strdup_printf ("----://%u/%s",
13095       table, (char *) node->data + offset);
13096 
13097   /* memcpy To be sure we're preserving byte order */
13098   memcpy (tag_str, entity, 4);
13099   GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
13100 
13101   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
13102 
13103   g_free (tag_str);
13104 
13105   return;
13106 
13107   /* ERRORS */
13108 short_read:
13109   {
13110     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
13111     return;
13112   }
13113 }
13114 
13115 static gboolean
qtdemux_tag_add_str_full(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag,const char * dummy,GNode * node)13116 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
13117     const char *tag, const char *dummy, GNode * node)
13118 {
13119   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13120   GNode *data;
13121   char *s;
13122   int len;
13123   guint32 type;
13124   int offset;
13125   gboolean ret = TRUE;
13126   const gchar *charset = NULL;
13127 
13128   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13129   if (data) {
13130     len = QT_UINT32 (data->data);
13131     type = QT_UINT32 ((guint8 *) data->data + 8);
13132     if (type == 0x00000001 && len > 16) {
13133       s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
13134           env_vars);
13135       if (s) {
13136         GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
13137         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
13138         g_free (s);
13139       } else {
13140         GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
13141       }
13142     }
13143   } else {
13144     len = QT_UINT32 (node->data);
13145     type = QT_UINT32 ((guint8 *) node->data + 4);
13146     if ((type >> 24) == 0xa9 && len > 8 + 4) {
13147       gint str_len;
13148       gint lang_code;
13149 
13150       /* Type starts with the (C) symbol, so the next data is a list
13151        * of (string size(16), language code(16), string) */
13152 
13153       str_len = QT_UINT16 ((guint8 *) node->data + 8);
13154       lang_code = QT_UINT16 ((guint8 *) node->data + 10);
13155 
13156       /* the string + fourcc + size + 2 16bit fields,
13157        * means that there are more tags in this atom */
13158       if (len > str_len + 8 + 4) {
13159         /* TODO how to represent the same tag in different languages? */
13160         GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
13161             "text alternatives, reading only first one");
13162       }
13163 
13164       offset = 12;
13165       len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
13166       GST_DEBUG_OBJECT (qtdemux, "found international text tag");
13167 
13168       if (lang_code < 0x800) {  /* MAC encoded string */
13169         charset = "mac";
13170       }
13171     } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
13172             QT_FOURCC ((guint8 *) node->data + 4))) {
13173       guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
13174 
13175       /* we go for 3GP style encoding if major brands claims so,
13176        * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
13177       if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13178           (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
13179               ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
13180         offset = 14;
13181         /* 16-bit Language code is ignored here as well */
13182         GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
13183       } else {
13184         goto normal;
13185       }
13186     } else {
13187     normal:
13188       offset = 8;
13189       GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
13190       ret = FALSE;              /* may have to fallback */
13191     }
13192     if (charset) {
13193       GError *err = NULL;
13194 
13195       s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
13196           charset, NULL, NULL, &err);
13197       if (err) {
13198         GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
13199             " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
13200             err->message);
13201         g_error_free (err);
13202       }
13203     } else {
13204       s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
13205           len - offset, env_vars);
13206     }
13207     if (s) {
13208       GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
13209       gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
13210       g_free (s);
13211       ret = TRUE;
13212     } else {
13213       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
13214     }
13215   }
13216   return ret;
13217 }
13218 
13219 static void
qtdemux_tag_add_str(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag,const char * dummy,GNode * node)13220 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
13221     const char *tag, const char *dummy, GNode * node)
13222 {
13223   qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
13224 }
13225 
13226 static void
qtdemux_tag_add_keywords(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag,const char * dummy,GNode * node)13227 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
13228     const char *tag, const char *dummy, GNode * node)
13229 {
13230   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13231   guint8 *data;
13232   char *s, *t, *k = NULL;
13233   int len;
13234   int offset;
13235   int count;
13236 
13237   /* first try normal string tag if major brand not 3GP */
13238   if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
13239     if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
13240       /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
13241        * let's try it 3gpp way after minor safety check */
13242       data = node->data;
13243       if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
13244         return;
13245     } else
13246       return;
13247   }
13248 
13249   GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
13250 
13251   data = node->data;
13252 
13253   len = QT_UINT32 (data);
13254   if (len < 15)
13255     goto short_read;
13256 
13257   count = QT_UINT8 (data + 14);
13258   offset = 15;
13259   for (; count; count--) {
13260     gint slen;
13261 
13262     if (offset + 1 > len)
13263       goto short_read;
13264     slen = QT_UINT8 (data + offset);
13265     offset += 1;
13266     if (offset + slen > len)
13267       goto short_read;
13268     s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
13269         slen, env_vars);
13270     if (s) {
13271       GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
13272       if (k) {
13273         t = g_strjoin (",", k, s, NULL);
13274         g_free (s);
13275         g_free (k);
13276         k = t;
13277       } else {
13278         k = s;
13279       }
13280     } else {
13281       GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
13282     }
13283     offset += slen;
13284   }
13285 
13286 done:
13287   if (k) {
13288     GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
13289     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
13290   }
13291   g_free (k);
13292 
13293   return;
13294 
13295   /* ERRORS */
13296 short_read:
13297   {
13298     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
13299     goto done;
13300   }
13301 }
13302 
13303 static void
qtdemux_tag_add_num(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag1,const char * tag2,GNode * node)13304 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
13305     const char *tag1, const char *tag2, GNode * node)
13306 {
13307   GNode *data;
13308   int len;
13309   int type;
13310   int n1, n2;
13311 
13312   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13313   if (data) {
13314     len = QT_UINT32 (data->data);
13315     type = QT_UINT32 ((guint8 *) data->data + 8);
13316     if (type == 0x00000000 && len >= 22) {
13317       n1 = QT_UINT16 ((guint8 *) data->data + 18);
13318       n2 = QT_UINT16 ((guint8 *) data->data + 20);
13319       if (n1 > 0) {
13320         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
13321         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
13322       }
13323       if (n2 > 0) {
13324         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
13325         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
13326       }
13327     }
13328   }
13329 }
13330 
13331 static void
qtdemux_tag_add_tmpo(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag1,const char * dummy,GNode * node)13332 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
13333     const char *tag1, const char *dummy, GNode * node)
13334 {
13335   GNode *data;
13336   int len;
13337   int type;
13338   int n1;
13339 
13340   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13341   if (data) {
13342     len = QT_UINT32 (data->data);
13343     type = QT_UINT32 ((guint8 *) data->data + 8);
13344     GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
13345     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13346     if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
13347       n1 = QT_UINT16 ((guint8 *) data->data + 16);
13348       if (n1) {
13349         /* do not add bpm=0 */
13350         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
13351         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
13352             NULL);
13353       }
13354     }
13355   }
13356 }
13357 
13358 static void
qtdemux_tag_add_uint32(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag1,const char * dummy,GNode * node)13359 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
13360     const char *tag1, const char *dummy, GNode * node)
13361 {
13362   GNode *data;
13363   int len;
13364   int type;
13365   guint32 num;
13366 
13367   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13368   if (data) {
13369     len = QT_UINT32 (data->data);
13370     type = QT_UINT32 ((guint8 *) data->data + 8);
13371     GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
13372     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13373     if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
13374       num = QT_UINT32 ((guint8 *) data->data + 16);
13375       if (num) {
13376         /* do not add num=0 */
13377         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
13378         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
13379       }
13380     }
13381   }
13382 }
13383 
13384 static void
qtdemux_tag_add_covr(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag1,const char * dummy,GNode * node)13385 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
13386     const char *tag1, const char *dummy, GNode * node)
13387 {
13388   GNode *data;
13389   int len;
13390   int type;
13391   GstSample *sample;
13392 
13393   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13394   if (data) {
13395     len = QT_UINT32 (data->data);
13396     type = QT_UINT32 ((guint8 *) data->data + 8);
13397     GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
13398     if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
13399       GstTagImageType image_type;
13400 
13401       if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
13402         image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
13403       else
13404         image_type = GST_TAG_IMAGE_TYPE_NONE;
13405 
13406       if ((sample =
13407               gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
13408                   len - 16, image_type))) {
13409         GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
13410         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
13411         gst_sample_unref (sample);
13412       }
13413     }
13414   }
13415 }
13416 
13417 static void
qtdemux_tag_add_date(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag,const char * dummy,GNode * node)13418 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
13419     const char *tag, const char *dummy, GNode * node)
13420 {
13421   GNode *data;
13422   GstDateTime *datetime = NULL;
13423   char *s;
13424   int len;
13425   int type;
13426 
13427   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13428   if (data) {
13429     len = QT_UINT32 (data->data);
13430     type = QT_UINT32 ((guint8 *) data->data + 8);
13431     if (type == 0x00000001 && len > 16) {
13432       guint y, m = 1, d = 1;
13433       gint ret;
13434 
13435       s = g_strndup ((char *) data->data + 16, len - 16);
13436       GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
13437       datetime = gst_date_time_new_from_iso8601_string (s);
13438       if (datetime != NULL) {
13439         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
13440             datetime, NULL);
13441         gst_date_time_unref (datetime);
13442       }
13443 
13444       ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
13445       if (ret >= 1 && y > 1500 && y < 3000) {
13446         GDate *date;
13447 
13448         date = g_date_new_dmy (d, m, y);
13449         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13450         g_date_free (date);
13451       } else {
13452         GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
13453       }
13454       g_free (s);
13455     }
13456   }
13457 }
13458 
13459 static void
qtdemux_tag_add_gnre(GstQTDemux * qtdemux,GstTagList * taglist,const char * tag,const char * dummy,GNode * node)13460 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
13461     const char *tag, const char *dummy, GNode * node)
13462 {
13463   GNode *data;
13464 
13465   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13466 
13467   /* re-route to normal string tag if major brand says so
13468    * or no data atom and compatible brand suggests so */
13469   if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13470       (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
13471     qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
13472     return;
13473   }
13474 
13475   if (data) {
13476     guint len, type, n;
13477 
13478     len = QT_UINT32 (data->data);
13479     type = QT_UINT32 ((guint8 *) data->data + 8);
13480     if (type == 0x00000000 && len >= 18) {
13481       n = QT_UINT16 ((guint8 *) data->data + 16);
13482       if (n > 0) {
13483         const gchar *genre;
13484 
13485         genre = gst_tag_id3_genre_get (n - 1);
13486         if (genre != NULL) {
13487           GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
13488           gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
13489         }
13490       }
13491     }
13492   }
13493 }
13494 
13495 static void
qtdemux_add_double_tag_from_str(GstQTDemux * demux,GstTagList * taglist,const gchar * tag,guint8 * data,guint32 datasize)13496 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
13497     const gchar * tag, guint8 * data, guint32 datasize)
13498 {
13499   gdouble value;
13500   gchar *datacopy;
13501 
13502   /* make a copy to have \0 at the end */
13503   datacopy = g_strndup ((gchar *) data, datasize);
13504 
13505   /* convert the str to double */
13506   if (sscanf (datacopy, "%lf", &value) == 1) {
13507     GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
13508     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
13509   } else {
13510     GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
13511         datacopy);
13512   }
13513   g_free (datacopy);
13514 }
13515 
13516 
13517 static void
qtdemux_tag_add_revdns(GstQTDemux * demux,GstTagList * taglist,const char * tag,const char * tag_bis,GNode * node)13518 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
13519     const char *tag, const char *tag_bis, GNode * node)
13520 {
13521   GNode *mean;
13522   GNode *name;
13523   GNode *data;
13524   guint32 meansize;
13525   guint32 namesize;
13526   guint32 datatype;
13527   guint32 datasize;
13528   const gchar *meanstr;
13529   const gchar *namestr;
13530 
13531   /* checking the whole ---- atom size for consistency */
13532   if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
13533     GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
13534     return;
13535   }
13536 
13537   mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
13538   if (!mean) {
13539     GST_WARNING_OBJECT (demux, "No 'mean' atom found");
13540     return;
13541   }
13542 
13543   meansize = QT_UINT32 (mean->data);
13544   if (meansize <= 12) {
13545     GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
13546     return;
13547   }
13548   meanstr = ((gchar *) mean->data) + 12;
13549   meansize -= 12;
13550 
13551   name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
13552   if (!name) {
13553     GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
13554     return;
13555   }
13556 
13557   namesize = QT_UINT32 (name->data);
13558   if (namesize <= 12) {
13559     GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
13560     return;
13561   }
13562   namestr = ((gchar *) name->data) + 12;
13563   namesize -= 12;
13564 
13565   /*
13566    * Data atom is:
13567    * uint32 - size
13568    * uint32 - name
13569    * uint8  - version
13570    * uint24 - data type
13571    * uint32 - all 0
13572    * rest   - the data
13573    */
13574   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13575   if (!data) {
13576     GST_WARNING_OBJECT (demux, "No data atom in this tag");
13577     return;
13578   }
13579   datasize = QT_UINT32 (data->data);
13580   if (datasize <= 16) {
13581     GST_WARNING_OBJECT (demux, "Data atom too small");
13582     return;
13583   }
13584   datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
13585 
13586   if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
13587       (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
13588     static const struct
13589     {
13590       const gchar name[28];
13591       const gchar tag[28];
13592     } tags[] = {
13593       {
13594       "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
13595       "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
13596       "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
13597       "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
13598       "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
13599       "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
13600       "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
13601       "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
13602     };
13603     int i;
13604 
13605     for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
13606       if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
13607         switch (gst_tag_get_type (tags[i].tag)) {
13608           case G_TYPE_DOUBLE:
13609             qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
13610                 ((guint8 *) data->data) + 16, datasize - 16);
13611             break;
13612           case G_TYPE_STRING:
13613             qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
13614             break;
13615           default:
13616             /* not reached */
13617             break;
13618         }
13619         break;
13620       }
13621     }
13622     if (i == G_N_ELEMENTS (tags))
13623       goto unknown_tag;
13624   } else {
13625     goto unknown_tag;
13626   }
13627 
13628   return;
13629 
13630 /* errors */
13631 unknown_tag:
13632 #ifndef GST_DISABLE_GST_DEBUG
13633   {
13634     gchar *namestr_dbg;
13635     gchar *meanstr_dbg;
13636 
13637     meanstr_dbg = g_strndup (meanstr, meansize);
13638     namestr_dbg = g_strndup (namestr, namesize);
13639 
13640     GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
13641         "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
13642 
13643     g_free (namestr_dbg);
13644     g_free (meanstr_dbg);
13645   }
13646 #endif
13647   return;
13648 }
13649 
13650 static void
qtdemux_tag_add_id32(GstQTDemux * demux,GstTagList * taglist,const char * tag,const char * tag_bis,GNode * node)13651 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
13652     const char *tag_bis, GNode * node)
13653 {
13654   guint8 *data;
13655   GstBuffer *buf;
13656   guint len;
13657   GstTagList *id32_taglist = NULL;
13658 
13659   GST_LOG_OBJECT (demux, "parsing ID32");
13660 
13661   data = node->data;
13662   len = GST_READ_UINT32_BE (data);
13663 
13664   /* need at least full box and language tag */
13665   if (len < 12 + 2)
13666     return;
13667 
13668   buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
13669   gst_buffer_fill (buf, 0, data + 14, len - 14);
13670 
13671   id32_taglist = gst_tag_list_from_id3v2_tag (buf);
13672   if (id32_taglist) {
13673     GST_LOG_OBJECT (demux, "parsing ok");
13674     gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
13675     gst_tag_list_unref (id32_taglist);
13676   } else {
13677     GST_LOG_OBJECT (demux, "parsing failed");
13678   }
13679 
13680   gst_buffer_unref (buf);
13681 }
13682 
13683 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
13684     const char *tag, const char *tag_bis, GNode * node);
13685 
13686 /* unmapped tags
13687 FOURCC_pcst -> if media is a podcast -> bool
13688 FOURCC_cpil -> if media is part of a compilation -> bool
13689 FOURCC_pgap -> if media is part of a gapless context -> bool
13690 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
13691 */
13692 
13693 static const struct
13694 {
13695   guint32 fourcc;
13696   const gchar *gst_tag;
13697   const gchar *gst_tag_bis;
13698   const GstQTDemuxAddTagFunc func;
13699 } add_funcs[] = {
13700   {
13701   FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13702   FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13703   FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
13704   FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13705   FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13706   FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
13707   FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13708   FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13709   FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13710   FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13711   FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13712   FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13713   FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13714   FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13715   FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13716   FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13717   FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
13718   FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
13719   FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
13720   FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13721   FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13722   FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
13723   FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13724         qtdemux_tag_add_num}, {
13725   FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13726         qtdemux_tag_add_num}, {
13727   FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
13728   FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
13729   FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
13730   FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
13731   FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
13732   FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
13733   FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13734   FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13735   FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
13736   FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
13737   FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
13738   FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13739   FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13740   FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
13741   FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
13742   FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13743   FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
13744   FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
13745         qtdemux_tag_add_classification}, {
13746   FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
13747   FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
13748   FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
13749 
13750     /* This is a special case, some tags are stored in this
13751      * 'reverse dns naming', according to:
13752      * http://atomicparsley.sourceforge.net/mpeg-4files.html and
13753      * bug #614471
13754      */
13755   FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
13756     /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
13757   FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
13758 };
13759 
13760 struct _GstQtDemuxTagList
13761 {
13762   GstQTDemux *demux;
13763   GstTagList *taglist;
13764 };
13765 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
13766 
13767 static void
qtdemux_tag_add_blob(GNode * node,GstQtDemuxTagList * qtdemuxtaglist)13768 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
13769 {
13770   gint len;
13771   guint8 *data;
13772   GstBuffer *buf;
13773   gchar *media_type;
13774   const gchar *style;
13775   GstSample *sample;
13776   GstStructure *s;
13777   guint i;
13778   guint8 ndata[4];
13779   GstQTDemux *demux = qtdemuxtaglist->demux;
13780   GstTagList *taglist = qtdemuxtaglist->taglist;
13781 
13782   data = node->data;
13783   len = QT_UINT32 (data);
13784   buf = gst_buffer_new_and_alloc (len);
13785   gst_buffer_fill (buf, 0, data, len);
13786 
13787   /* heuristic to determine style of tag */
13788   if (QT_FOURCC (data + 4) == FOURCC_____ ||
13789       (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
13790     style = "itunes";
13791   else if (demux->major_brand == FOURCC_qt__)
13792     style = "quicktime";
13793   /* fall back to assuming iso/3gp tag style */
13794   else
13795     style = "iso";
13796 
13797   /* santize the name for the caps. */
13798   for (i = 0; i < 4; i++) {
13799     guint8 d = data[4 + i];
13800     if (g_ascii_isalnum (d))
13801       ndata[i] = g_ascii_tolower (d);
13802     else
13803       ndata[i] = '_';
13804   }
13805 
13806   media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
13807       ndata[0], ndata[1], ndata[2], ndata[3]);
13808   GST_DEBUG_OBJECT (demux, "media type %s", media_type);
13809 
13810   s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
13811   sample = gst_sample_new (buf, NULL, NULL, s);
13812   gst_buffer_unref (buf);
13813   g_free (media_type);
13814 
13815   GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
13816       len, s);
13817 
13818   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
13819       GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
13820 
13821   gst_sample_unref (sample);
13822 }
13823 
13824 static void
qtdemux_parse_udta(GstQTDemux * qtdemux,GstTagList * taglist,GNode * udta)13825 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
13826 {
13827   GNode *meta;
13828   GNode *ilst;
13829   GNode *xmp_;
13830   GNode *node;
13831   gint i;
13832   GstQtDemuxTagList demuxtaglist;
13833 
13834   demuxtaglist.demux = qtdemux;
13835   demuxtaglist.taglist = taglist;
13836 
13837   meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
13838   if (meta != NULL) {
13839     ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
13840     if (ilst == NULL) {
13841       GST_LOG_OBJECT (qtdemux, "no ilst");
13842       return;
13843     }
13844   } else {
13845     ilst = udta;
13846     GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
13847   }
13848 
13849   i = 0;
13850   while (i < G_N_ELEMENTS (add_funcs)) {
13851     node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
13852     if (node) {
13853       gint len;
13854 
13855       len = QT_UINT32 (node->data);
13856       if (len < 12) {
13857         GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
13858             GST_FOURCC_ARGS (add_funcs[i].fourcc));
13859       } else {
13860         add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
13861             add_funcs[i].gst_tag_bis, node);
13862       }
13863       g_node_destroy (node);
13864     } else {
13865       i++;
13866     }
13867   }
13868 
13869   /* parsed nodes have been removed, pass along remainder as blob */
13870   g_node_children_foreach (ilst, G_TRAVERSE_ALL,
13871       (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
13872 
13873   /* parse up XMP_ node if existing */
13874   xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
13875   if (xmp_ != NULL) {
13876     GstBuffer *buf;
13877     GstTagList *xmptaglist;
13878 
13879     buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
13880         QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
13881     xmptaglist = gst_tag_list_from_xmp_buffer (buf);
13882     gst_buffer_unref (buf);
13883 
13884     qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
13885   } else {
13886     GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
13887   }
13888 }
13889 
13890 typedef struct
13891 {
13892   GstStructure *structure;      /* helper for sort function */
13893   gchar *location;
13894   guint min_req_bitrate;
13895   guint min_req_qt_version;
13896 } GstQtReference;
13897 
13898 static gint
qtdemux_redirects_sort_func(gconstpointer a,gconstpointer b)13899 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13900 {
13901   GstQtReference *ref_a = (GstQtReference *) a;
13902   GstQtReference *ref_b = (GstQtReference *) b;
13903 
13904   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13905     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13906 
13907   /* known bitrates go before unknown; higher bitrates go first */
13908   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13909 }
13910 
13911 /* sort the redirects and post a message for the application.
13912  */
13913 static void
qtdemux_process_redirects(GstQTDemux * qtdemux,GList * references)13914 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13915 {
13916   GstQtReference *best;
13917   GstStructure *s;
13918   GstMessage *msg;
13919   GValue list_val = { 0, };
13920   GList *l;
13921 
13922   g_assert (references != NULL);
13923 
13924   references = g_list_sort (references, qtdemux_redirects_sort_func);
13925 
13926   best = (GstQtReference *) references->data;
13927 
13928   g_value_init (&list_val, GST_TYPE_LIST);
13929 
13930   for (l = references; l != NULL; l = l->next) {
13931     GstQtReference *ref = (GstQtReference *) l->data;
13932     GValue struct_val = { 0, };
13933 
13934     ref->structure = gst_structure_new ("redirect",
13935         "new-location", G_TYPE_STRING, ref->location, NULL);
13936 
13937     if (ref->min_req_bitrate > 0) {
13938       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13939           ref->min_req_bitrate, NULL);
13940     }
13941 
13942     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13943     g_value_set_boxed (&struct_val, ref->structure);
13944     gst_value_list_append_value (&list_val, &struct_val);
13945     g_value_unset (&struct_val);
13946     /* don't free anything here yet, since we need best->structure below */
13947   }
13948 
13949   g_assert (best != NULL);
13950   s = gst_structure_copy (best->structure);
13951 
13952   if (g_list_length (references) > 1) {
13953     gst_structure_set_value (s, "locations", &list_val);
13954   }
13955 
13956   g_value_unset (&list_val);
13957 
13958   for (l = references; l != NULL; l = l->next) {
13959     GstQtReference *ref = (GstQtReference *) l->data;
13960 
13961     gst_structure_free (ref->structure);
13962     g_free (ref->location);
13963     g_free (ref);
13964   }
13965   g_list_free (references);
13966 
13967   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13968   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13969   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13970   qtdemux->posted_redirect = TRUE;
13971 }
13972 
13973 /* look for redirect nodes, collect all redirect information and
13974  * process it.
13975  */
13976 static gboolean
qtdemux_parse_redirects(GstQTDemux * qtdemux)13977 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13978 {
13979   GNode *rmra, *rmda, *rdrf;
13980 
13981   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13982   if (rmra) {
13983     GList *redirects = NULL;
13984 
13985     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13986     while (rmda) {
13987       GstQtReference ref = { NULL, NULL, 0, 0 };
13988       GNode *rmdr, *rmvc;
13989 
13990       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13991         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13992         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13993             ref.min_req_bitrate);
13994       }
13995 
13996       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13997         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13998         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13999 
14000 #ifndef GST_DISABLE_GST_DEBUG
14001         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
14002 #endif
14003         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
14004 
14005         GST_LOG_OBJECT (qtdemux,
14006             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
14007             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
14008             bitmask, check_type);
14009         if (package == FOURCC_qtim && check_type == 0) {
14010           ref.min_req_qt_version = version;
14011         }
14012       }
14013 
14014       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
14015       if (rdrf) {
14016         guint32 ref_type;
14017         guint8 *ref_data;
14018         guint ref_len;
14019 
14020         ref_len = QT_UINT32 ((guint8 *) rdrf->data);
14021         if (ref_len > 20) {
14022           ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
14023           ref_data = (guint8 *) rdrf->data + 20;
14024           if (ref_type == FOURCC_alis) {
14025             guint record_len, record_version, fn_len;
14026 
14027             if (ref_len > 70) {
14028               /* MacOSX alias record, google for alias-layout.txt */
14029               record_len = QT_UINT16 (ref_data + 4);
14030               record_version = QT_UINT16 (ref_data + 4 + 2);
14031               fn_len = QT_UINT8 (ref_data + 50);
14032               if (record_len > 50 && record_version == 2 && fn_len > 0) {
14033                 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
14034               }
14035             } else {
14036               GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
14037                   ref_len);
14038             }
14039           } else if (ref_type == FOURCC_url_) {
14040             ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
14041           } else {
14042             GST_DEBUG_OBJECT (qtdemux,
14043                 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
14044                 GST_FOURCC_ARGS (ref_type));
14045           }
14046           if (ref.location != NULL) {
14047             GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
14048             redirects =
14049                 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
14050           } else {
14051             GST_WARNING_OBJECT (qtdemux,
14052                 "Failed to extract redirect location from rdrf atom");
14053           }
14054         } else {
14055           GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
14056         }
14057       }
14058 
14059       /* look for others */
14060       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
14061     }
14062 
14063     if (redirects != NULL) {
14064       qtdemux_process_redirects (qtdemux, redirects);
14065     }
14066   }
14067   return TRUE;
14068 }
14069 
14070 static GstTagList *
qtdemux_add_container_format(GstQTDemux * qtdemux,GstTagList * tags)14071 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
14072 {
14073   const gchar *fmt;
14074 
14075   if (tags == NULL) {
14076     tags = gst_tag_list_new_empty ();
14077     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
14078   }
14079 
14080   if (qtdemux->major_brand == FOURCC_mjp2)
14081     fmt = "Motion JPEG 2000";
14082   else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
14083     fmt = "3GP";
14084   else if (qtdemux->major_brand == FOURCC_qt__)
14085     fmt = "Quicktime";
14086   else if (qtdemux->fragmented)
14087     fmt = "ISO fMP4";
14088   else
14089     fmt = "ISO MP4/M4A";
14090 
14091   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
14092       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
14093 
14094   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
14095       fmt, NULL);
14096 
14097   return tags;
14098 }
14099 
14100 /* we have read the complete moov node now.
14101  * This function parses all of the relevant info, creates the traks and
14102  * prepares all data structures for playback
14103  */
14104 static gboolean
qtdemux_parse_tree(GstQTDemux * qtdemux)14105 qtdemux_parse_tree (GstQTDemux * qtdemux)
14106 {
14107   GNode *mvhd;
14108   GNode *trak;
14109   GNode *udta;
14110   GNode *mvex;
14111   GNode *pssh;
14112   guint64 creation_time;
14113   GstDateTime *datetime = NULL;
14114   gint version;
14115 
14116   /* make sure we have a usable taglist */
14117   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14118 
14119   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
14120   if (mvhd == NULL) {
14121     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
14122     return qtdemux_parse_redirects (qtdemux);
14123   }
14124 
14125   version = QT_UINT8 ((guint8 *) mvhd->data + 8);
14126   if (version == 1) {
14127     creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
14128     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
14129     qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
14130   } else if (version == 0) {
14131     creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
14132     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
14133     qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
14134   } else {
14135     GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
14136     return FALSE;
14137   }
14138 
14139   /* Moving qt creation time (secs since 1904) to unix time */
14140   if (creation_time != 0) {
14141     /* Try to use epoch first as it should be faster and more commonly found */
14142     if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
14143       GTimeVal now;
14144 
14145       creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
14146       /* some data cleansing sanity */
14147       g_get_current_time (&now);
14148       if (now.tv_sec + 24 * 3600 < creation_time) {
14149         GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
14150       } else {
14151         datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
14152       }
14153     } else {
14154       GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
14155       GDateTime *dt, *dt_local;
14156 
14157       dt = g_date_time_add_seconds (base_dt, creation_time);
14158       dt_local = g_date_time_to_local (dt);
14159       datetime = gst_date_time_new_from_g_date_time (dt_local);
14160 
14161       g_date_time_unref (base_dt);
14162       g_date_time_unref (dt);
14163     }
14164   }
14165   if (datetime) {
14166     /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
14167     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
14168         datetime, NULL);
14169     gst_date_time_unref (datetime);
14170   }
14171 
14172   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
14173   GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
14174 
14175   /* check for fragmented file and get some (default) data */
14176   mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
14177   if (mvex) {
14178     GNode *mehd;
14179     GstByteReader mehd_data;
14180 
14181     /* let track parsing or anyone know weird stuff might happen ... */
14182     qtdemux->fragmented = TRUE;
14183 
14184     /* compensate for total duration */
14185     mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
14186     if (mehd)
14187       qtdemux_parse_mehd (qtdemux, &mehd_data);
14188   }
14189 
14190   /* Update the movie segment duration, unless it was directly given to us
14191    * by upstream. Otherwise let it as is, as we don't want to mangle the
14192    * duration provided by upstream that may come e.g. from a MPD file. */
14193   if (!qtdemux->upstream_format_is_time) {
14194     GstClockTime duration;
14195     /* set duration in the segment info */
14196     gst_qtdemux_get_duration (qtdemux, &duration);
14197     qtdemux->segment.duration = duration;
14198     /* also do not exceed duration; stop is set that way post seek anyway,
14199      * and segment activation falls back to duration,
14200      * whereas loop only checks stop, so let's align this here as well */
14201     qtdemux->segment.stop = duration;
14202   }
14203 
14204   /* parse all traks */
14205   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
14206   while (trak) {
14207     qtdemux_parse_trak (qtdemux, trak);
14208     /* iterate all siblings */
14209     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
14210   }
14211 
14212   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14213 
14214   /* find tags */
14215   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
14216   if (udta) {
14217     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14218   } else {
14219     GST_LOG_OBJECT (qtdemux, "No udta node found.");
14220   }
14221 
14222   /* maybe also some tags in meta box */
14223   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
14224   if (udta) {
14225     GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
14226     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14227   } else {
14228     GST_LOG_OBJECT (qtdemux, "No meta node found.");
14229   }
14230 
14231   /* parse any protection system info */
14232   pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
14233   while (pssh) {
14234     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
14235     qtdemux_parse_pssh (qtdemux, pssh);
14236     pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14237   }
14238 
14239   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14240 
14241   return TRUE;
14242 }
14243 
14244 /* taken from ffmpeg */
14245 static int
read_descr_size(guint8 * ptr,guint8 * end,guint8 ** end_out)14246 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14247 {
14248   int count = 4;
14249   int len = 0;
14250 
14251   while (count--) {
14252     int c;
14253 
14254     if (ptr >= end)
14255       return -1;
14256 
14257     c = *ptr++;
14258     len = (len << 7) | (c & 0x7f);
14259     if (!(c & 0x80))
14260       break;
14261   }
14262   *end_out = ptr;
14263   return len;
14264 }
14265 
14266 static GList *
parse_xiph_stream_headers(GstQTDemux * qtdemux,gpointer codec_data,gsize codec_data_size)14267 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14268     gsize codec_data_size)
14269 {
14270   GList *list = NULL;
14271   guint8 *p = codec_data;
14272   gint i, offset, num_packets;
14273   guint *length, last;
14274 
14275   GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14276 
14277   if (codec_data == NULL || codec_data_size == 0)
14278     goto error;
14279 
14280   /* start of the stream and vorbis audio or theora video, need to
14281    * send the codec_priv data as first three packets */
14282   num_packets = p[0] + 1;
14283   GST_DEBUG_OBJECT (qtdemux,
14284       "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14285       (guint) num_packets, codec_data_size);
14286 
14287   /* Let's put some limits, Don't think there even is a xiph codec
14288    * with more than 3-4 headers */
14289   if (G_UNLIKELY (num_packets > 16)) {
14290     GST_WARNING_OBJECT (qtdemux,
14291         "Unlikely number of xiph headers, most likely not valid");
14292     goto error;
14293   }
14294 
14295   length = g_alloca (num_packets * sizeof (guint));
14296   last = 0;
14297   offset = 1;
14298 
14299   /* first packets, read length values */
14300   for (i = 0; i < num_packets - 1; i++) {
14301     length[i] = 0;
14302     while (offset < codec_data_size) {
14303       length[i] += p[offset];
14304       if (p[offset++] != 0xff)
14305         break;
14306     }
14307     last += length[i];
14308   }
14309   if (offset + last > codec_data_size)
14310     goto error;
14311 
14312   /* last packet is the remaining size */
14313   length[i] = codec_data_size - offset - last;
14314 
14315   for (i = 0; i < num_packets; i++) {
14316     GstBuffer *hdr;
14317 
14318     GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14319 
14320     if (offset + length[i] > codec_data_size)
14321       goto error;
14322 
14323     hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
14324     list = g_list_append (list, hdr);
14325 
14326     offset += length[i];
14327   }
14328 
14329   return list;
14330 
14331   /* ERRORS */
14332 error:
14333   {
14334     if (list != NULL)
14335       g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14336     return NULL;
14337   }
14338 
14339 }
14340 
14341 /* this can change the codec originally present in @list */
14342 static void
gst_qtdemux_handle_esds(GstQTDemux * qtdemux,QtDemuxStream * stream,QtDemuxStreamStsdEntry * entry,GNode * esds,GstTagList * list)14343 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14344     QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14345 {
14346   int len = QT_UINT32 (esds->data);
14347   guint8 *ptr = esds->data;
14348   guint8 *end = ptr + len;
14349   int tag;
14350   guint8 *data_ptr = NULL;
14351   int data_len = 0;
14352   guint8 object_type_id = 0;
14353   guint8 stream_type = 0;
14354   const char *codec_name = NULL;
14355   GstCaps *caps = NULL;
14356 
14357   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14358   ptr += 8;
14359   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14360   ptr += 4;
14361   while (ptr + 1 < end) {
14362     tag = QT_UINT8 (ptr);
14363     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14364     ptr++;
14365     len = read_descr_size (ptr, end, &ptr);
14366     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14367 
14368     /* Check the stated amount of data is available for reading */
14369     if (len < 0 || ptr + len > end)
14370       break;
14371 
14372     switch (tag) {
14373       case ES_DESCRIPTOR_TAG:
14374         GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14375         GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14376         ptr += 3;
14377         break;
14378       case DECODER_CONFIG_DESC_TAG:{
14379         guint max_bitrate, avg_bitrate;
14380 
14381         object_type_id = QT_UINT8 (ptr);
14382         stream_type = QT_UINT8 (ptr + 1) >> 2;
14383         max_bitrate = QT_UINT32 (ptr + 5);
14384         avg_bitrate = QT_UINT32 (ptr + 9);
14385         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14386         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14387         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14388         GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14389         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14390         if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14391           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14392               GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14393         }
14394         if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14395           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14396               avg_bitrate, NULL);
14397         }
14398         ptr += 13;
14399         break;
14400       }
14401       case DECODER_SPECIFIC_INFO_TAG:
14402         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14403         if (object_type_id == 0xe0 && len == 0x40) {
14404           guint8 *data;
14405           GstStructure *s;
14406           guint32 clut[16];
14407           gint i;
14408 
14409           GST_DEBUG_OBJECT (qtdemux,
14410               "Have VOBSUB palette. Creating palette event");
14411           /* move to decConfigDescr data and read palette */
14412           data = ptr;
14413           for (i = 0; i < 16; i++) {
14414             clut[i] = QT_UINT32 (data);
14415             data += 4;
14416           }
14417 
14418           s = gst_structure_new ("application/x-gst-dvd", "event",
14419               G_TYPE_STRING, "dvd-spu-clut-change",
14420               "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14421               "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14422               "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14423               "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14424               "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14425               "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14426               "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14427               "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14428               NULL);
14429 
14430           /* store event and trigger custom processing */
14431           stream->pending_event =
14432               gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14433         } else {
14434           /* Generic codec_data handler puts it on the caps */
14435           data_ptr = ptr;
14436           data_len = len;
14437         }
14438 
14439         ptr += len;
14440         break;
14441       case SL_CONFIG_DESC_TAG:
14442         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14443         ptr += 1;
14444         break;
14445       default:
14446         GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14447             tag);
14448         GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14449         ptr += len;
14450         break;
14451     }
14452   }
14453 
14454   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14455    * in use, and should also be used to override some other parameters for some
14456    * codecs. */
14457   switch (object_type_id) {
14458     case 0x20:                 /* MPEG-4 */
14459       /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14460        * profile_and_level_indication */
14461       if (data_ptr != NULL && data_len >= 5 &&
14462           GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14463         gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14464             data_ptr + 4, data_len - 4);
14465       }
14466       break;                    /* Nothing special needed here */
14467     case 0x21:                 /* H.264 */
14468       codec_name = "H.264 / AVC";
14469       caps = gst_caps_new_simple ("video/x-h264",
14470           "stream-format", G_TYPE_STRING, "avc",
14471           "alignment", G_TYPE_STRING, "au", NULL);
14472       break;
14473     case 0x40:                 /* AAC (any) */
14474     case 0x66:                 /* AAC Main */
14475     case 0x67:                 /* AAC LC */
14476     case 0x68:                 /* AAC SSR */
14477       /* Override channels and rate based on the codec_data, as it's often
14478        * wrong. */
14479       /* Only do so for basic setup without HE-AAC extension */
14480       if (data_ptr && data_len == 2) {
14481         guint channels, rate;
14482 
14483         channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14484         if (channels > 0)
14485           entry->n_channels = channels;
14486 
14487         rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14488         if (rate > 0)
14489           entry->rate = rate;
14490       }
14491 
14492       /* Set level and profile if possible */
14493       if (data_ptr != NULL && data_len >= 2) {
14494         gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14495             data_ptr, data_len);
14496       } else {
14497         const gchar *profile_str = NULL;
14498         GstBuffer *buffer;
14499         GstMapInfo map;
14500         guint8 *codec_data;
14501         gint rate_idx, profile;
14502 
14503         /* No codec_data, let's invent something.
14504          * FIXME: This is wrong for SBR! */
14505 
14506         GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14507 
14508         buffer = gst_buffer_new_and_alloc (2);
14509         gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14510         codec_data = map.data;
14511 
14512         rate_idx =
14513             gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14514             (stream)->rate);
14515 
14516         switch (object_type_id) {
14517           case 0x66:
14518             profile_str = "main";
14519             profile = 0;
14520             break;
14521           case 0x67:
14522             profile_str = "lc";
14523             profile = 1;
14524             break;
14525           case 0x68:
14526             profile_str = "ssr";
14527             profile = 2;
14528             break;
14529           default:
14530             profile = 3;
14531             break;
14532         }
14533 
14534         codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14535         codec_data[1] =
14536             ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14537 
14538         gst_buffer_unmap (buffer, &map);
14539         gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14540             GST_TYPE_BUFFER, buffer, NULL);
14541         gst_buffer_unref (buffer);
14542 
14543         if (profile_str) {
14544           gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14545               G_TYPE_STRING, profile_str, NULL);
14546         }
14547       }
14548       break;
14549     case 0x60:                 /* MPEG-2, various profiles */
14550     case 0x61:
14551     case 0x62:
14552     case 0x63:
14553     case 0x64:
14554     case 0x65:
14555       codec_name = "MPEG-2 video";
14556       caps = gst_caps_new_simple ("video/mpeg",
14557           "mpegversion", G_TYPE_INT, 2,
14558           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14559       break;
14560     case 0x69:                 /* MPEG-2 BC audio */
14561     case 0x6B:                 /* MPEG-1 audio */
14562       caps = gst_caps_new_simple ("audio/mpeg",
14563           "mpegversion", G_TYPE_INT, 1, NULL);
14564       codec_name = "MPEG-1 audio";
14565       break;
14566     case 0x6A:                 /* MPEG-1 */
14567       codec_name = "MPEG-1 video";
14568       caps = gst_caps_new_simple ("video/mpeg",
14569           "mpegversion", G_TYPE_INT, 1,
14570           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14571       break;
14572     case 0x6C:                 /* MJPEG */
14573       caps =
14574           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14575           NULL);
14576       codec_name = "Motion-JPEG";
14577       break;
14578     case 0x6D:                 /* PNG */
14579       caps =
14580           gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14581           NULL);
14582       codec_name = "PNG still images";
14583       break;
14584     case 0x6E:                 /* JPEG2000 */
14585       codec_name = "JPEG-2000";
14586       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14587       break;
14588     case 0xA4:                 /* Dirac */
14589       codec_name = "Dirac";
14590       caps = gst_caps_new_empty_simple ("video/x-dirac");
14591       break;
14592     case 0xA5:                 /* AC3 */
14593       codec_name = "AC-3 audio";
14594       caps = gst_caps_new_simple ("audio/x-ac3",
14595           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14596       break;
14597     case 0xA9:                 /* AC3 */
14598       codec_name = "DTS audio";
14599       caps = gst_caps_new_simple ("audio/x-dts",
14600           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14601       break;
14602     case 0xDD:
14603       if (stream_type == 0x05 && data_ptr) {
14604         GList *headers =
14605             parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14606         if (headers) {
14607           GList *tmp;
14608           GValue arr_val = G_VALUE_INIT;
14609           GValue buf_val = G_VALUE_INIT;
14610           GstStructure *s;
14611 
14612           /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14613           codec_name = "Vorbis";
14614           caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14615           g_value_init (&arr_val, GST_TYPE_ARRAY);
14616           g_value_init (&buf_val, GST_TYPE_BUFFER);
14617           for (tmp = headers; tmp; tmp = tmp->next) {
14618             g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14619             gst_value_array_append_value (&arr_val, &buf_val);
14620           }
14621           s = gst_caps_get_structure (caps, 0);
14622           gst_structure_take_value (s, "streamheader", &arr_val);
14623           g_value_unset (&buf_val);
14624           g_list_free (headers);
14625 
14626           data_ptr = NULL;
14627           data_len = 0;
14628         }
14629       }
14630       break;
14631     case 0xE1:                 /* QCELP */
14632       /* QCELP, the codec_data is a riff tag (little endian) with
14633        * 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). */
14634       caps = gst_caps_new_empty_simple ("audio/qcelp");
14635       codec_name = "QCELP";
14636       break;
14637     default:
14638       break;
14639   }
14640 
14641   /* If we have a replacement caps, then change our caps for this stream */
14642   if (caps) {
14643     gst_caps_unref (entry->caps);
14644     entry->caps = caps;
14645   }
14646 
14647   if (codec_name && list)
14648     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14649         GST_TAG_AUDIO_CODEC, codec_name, NULL);
14650 
14651   /* Add the codec_data attribute to caps, if we have it */
14652   if (data_ptr) {
14653     GstBuffer *buffer;
14654 
14655     buffer = gst_buffer_new_and_alloc (data_len);
14656     gst_buffer_fill (buffer, 0, data_ptr, data_len);
14657 
14658     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14659     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14660 
14661     gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14662         buffer, NULL);
14663     gst_buffer_unref (buffer);
14664   }
14665 
14666 }
14667 
14668 static inline GstCaps *
_get_unknown_codec_name(const gchar * type,guint32 fourcc)14669 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14670 {
14671   GstCaps *caps;
14672   guint i;
14673   char *s, fourstr[5];
14674 
14675   g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14676   for (i = 0; i < 4; i++) {
14677     if (!g_ascii_isalnum (fourstr[i]))
14678       fourstr[i] = '_';
14679   }
14680   s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14681   caps = gst_caps_new_empty_simple (s);
14682   g_free (s);
14683   return caps;
14684 }
14685 
14686 #define _codec(name) \
14687   do { \
14688     if (codec_name) { \
14689       *codec_name = g_strdup (name); \
14690     } \
14691   } while (0)
14692 
14693 static GstCaps *
qtdemux_video_caps(GstQTDemux * qtdemux,QtDemuxStream * stream,QtDemuxStreamStsdEntry * entry,guint32 fourcc,const guint8 * stsd_entry_data,gchar ** codec_name)14694 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14695     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14696     const guint8 * stsd_entry_data, gchar ** codec_name)
14697 {
14698   GstCaps *caps = NULL;
14699   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14700 
14701   switch (fourcc) {
14702     case FOURCC_png:
14703       _codec ("PNG still images");
14704       caps = gst_caps_new_empty_simple ("image/png");
14705       break;
14706     case FOURCC_jpeg:
14707       _codec ("JPEG still images");
14708       caps =
14709           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14710           NULL);
14711       break;
14712     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14713     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14714     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14715     case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14716       _codec ("Motion-JPEG");
14717       caps =
14718           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14719           NULL);
14720       break;
14721     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14722       _codec ("Motion-JPEG format B");
14723       caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14724       break;
14725     case FOURCC_mjp2:
14726       _codec ("JPEG-2000");
14727       /* override to what it should be according to spec, avoid palette_data */
14728       entry->bits_per_sample = 24;
14729       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14730       break;
14731     case FOURCC_SVQ3:
14732       _codec ("Sorensen video v.3");
14733       caps = gst_caps_new_simple ("video/x-svq",
14734           "svqversion", G_TYPE_INT, 3, NULL);
14735       break;
14736     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14737     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14738       _codec ("Sorensen video v.1");
14739       caps = gst_caps_new_simple ("video/x-svq",
14740           "svqversion", G_TYPE_INT, 1, NULL);
14741       break;
14742     case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14743       caps = gst_caps_new_empty_simple ("video/x-raw");
14744       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14745       _codec ("Windows Raw RGB");
14746       stream->alignment = 32;
14747       break;
14748     case FOURCC_raw_:
14749     {
14750       guint16 bps;
14751 
14752       bps = QT_UINT16 (stsd_entry_data + 82);
14753       switch (bps) {
14754         case 15:
14755           format = GST_VIDEO_FORMAT_RGB15;
14756           break;
14757         case 16:
14758           format = GST_VIDEO_FORMAT_RGB16;
14759           break;
14760         case 24:
14761           format = GST_VIDEO_FORMAT_RGB;
14762           break;
14763         case 32:
14764           format = GST_VIDEO_FORMAT_ARGB;
14765           break;
14766         default:
14767           /* unknown */
14768           break;
14769       }
14770       break;
14771     }
14772     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14773       format = GST_VIDEO_FORMAT_I420;
14774       break;
14775     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14776     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14777       format = GST_VIDEO_FORMAT_I420;
14778       break;
14779     case FOURCC_2vuy:
14780     case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14781       format = GST_VIDEO_FORMAT_UYVY;
14782       break;
14783     case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14784       format = GST_VIDEO_FORMAT_v308;
14785       break;
14786     case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14787       format = GST_VIDEO_FORMAT_v216;
14788       break;
14789     case FOURCC_v210:
14790       format = GST_VIDEO_FORMAT_v210;
14791       break;
14792     case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14793       format = GST_VIDEO_FORMAT_r210;
14794       break;
14795       /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14796          case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14797          format = GST_VIDEO_FORMAT_v410;
14798          break;
14799        */
14800       /* Packed YUV 4:4:4:4 8 bit in 32 bits
14801        * but different order than AYUV
14802        case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14803        format = GST_VIDEO_FORMAT_v408;
14804        break;
14805        */
14806     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14807     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14808       _codec ("MPEG-1 video");
14809       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14810           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14811       break;
14812     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14813     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14814     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14815     case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14816     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14817     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14818     case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14819     case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14820     case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14821     case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14822     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14823     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14824     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14825     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14826     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14827     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14828     case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14829     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14830     case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14831     case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14832     case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14833     case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14834     case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14835     case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14836     case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14837     case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14838     case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14839     case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14840     case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14841     case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14842     case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14843     case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14844     case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14845     case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14846     case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14847     case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14848     case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14849     case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14850     case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14851     case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14852     case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14853     case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14854     case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14855     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14856     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14857     case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14858     case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14859       _codec ("MPEG-2 video");
14860       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14861           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14862       break;
14863     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14864       _codec ("GIF still images");
14865       caps = gst_caps_new_empty_simple ("image/gif");
14866       break;
14867     case FOURCC_h263:
14868     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14869     case FOURCC_s263:
14870     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14871       _codec ("H.263");
14872       /* ffmpeg uses the height/width props, don't know why */
14873       caps = gst_caps_new_simple ("video/x-h263",
14874           "variant", G_TYPE_STRING, "itu", NULL);
14875       break;
14876     case FOURCC_mp4v:
14877     case FOURCC_MP4V:
14878       _codec ("MPEG-4 video");
14879       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14880           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14881       break;
14882     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14883     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14884       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
14885       caps = gst_caps_new_simple ("video/x-msmpeg",
14886           "msmpegversion", G_TYPE_INT, 43, NULL);
14887       break;
14888     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14889       _codec ("DivX 3");
14890       caps = gst_caps_new_simple ("video/x-divx",
14891           "divxversion", G_TYPE_INT, 3, NULL);
14892       break;
14893     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14894     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14895       _codec ("DivX 4");
14896       caps = gst_caps_new_simple ("video/x-divx",
14897           "divxversion", G_TYPE_INT, 4, NULL);
14898       break;
14899     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14900       _codec ("DivX 5");
14901       caps = gst_caps_new_simple ("video/x-divx",
14902           "divxversion", G_TYPE_INT, 5, NULL);
14903       break;
14904 
14905     case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14906       _codec ("FFV1");
14907       caps = gst_caps_new_simple ("video/x-ffv",
14908           "ffvversion", G_TYPE_INT, 1, NULL);
14909       break;
14910 
14911     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14912     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14913     case FOURCC_XVID:
14914     case FOURCC_xvid:
14915     case FOURCC_FMP4:
14916     case FOURCC_fmp4:
14917     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14918       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14919           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14920       _codec ("MPEG-4");
14921       break;
14922 
14923     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14924       _codec ("Cinepak");
14925       caps = gst_caps_new_empty_simple ("video/x-cinepak");
14926       break;
14927     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14928       _codec ("Apple QuickDraw");
14929       caps = gst_caps_new_empty_simple ("video/x-qdrw");
14930       break;
14931     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14932       _codec ("Apple video");
14933       caps = gst_caps_new_empty_simple ("video/x-apple-video");
14934       break;
14935     case FOURCC_H264:
14936     case FOURCC_avc1:
14937       _codec ("H.264 / AVC");
14938       caps = gst_caps_new_simple ("video/x-h264",
14939           "stream-format", G_TYPE_STRING, "avc",
14940           "alignment", G_TYPE_STRING, "au", NULL);
14941       break;
14942     case FOURCC_avc3:
14943       _codec ("H.264 / AVC");
14944       caps = gst_caps_new_simple ("video/x-h264",
14945           "stream-format", G_TYPE_STRING, "avc3",
14946           "alignment", G_TYPE_STRING, "au", NULL);
14947       break;
14948     case FOURCC_H265:
14949     case FOURCC_hvc1:
14950       _codec ("H.265 / HEVC");
14951       caps = gst_caps_new_simple ("video/x-h265",
14952           "stream-format", G_TYPE_STRING, "hvc1",
14953           "alignment", G_TYPE_STRING, "au", NULL);
14954       break;
14955     case FOURCC_hev1:
14956       _codec ("H.265 / HEVC");
14957       caps = gst_caps_new_simple ("video/x-h265",
14958           "stream-format", G_TYPE_STRING, "hev1",
14959           "alignment", G_TYPE_STRING, "au", NULL);
14960       break;
14961     case FOURCC_rle_:
14962       _codec ("Run-length encoding");
14963       caps = gst_caps_new_simple ("video/x-rle",
14964           "layout", G_TYPE_STRING, "quicktime", NULL);
14965       break;
14966     case FOURCC_WRLE:
14967       _codec ("Run-length encoding");
14968       caps = gst_caps_new_simple ("video/x-rle",
14969           "layout", G_TYPE_STRING, "microsoft", NULL);
14970       break;
14971     case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14972     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14973       _codec ("Indeo Video 3");
14974       caps = gst_caps_new_simple ("video/x-indeo",
14975           "indeoversion", G_TYPE_INT, 3, NULL);
14976       break;
14977     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14978     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14979       _codec ("Intel Video 4");
14980       caps = gst_caps_new_simple ("video/x-indeo",
14981           "indeoversion", G_TYPE_INT, 4, NULL);
14982       break;
14983     case FOURCC_dvcp:
14984     case FOURCC_dvc_:
14985     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14986     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14987     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14988     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14989     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14990     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14991       _codec ("DV Video");
14992       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14993           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14994       break;
14995     case FOURCC_dv5n:          /* DVCPRO50 NTSC */
14996     case FOURCC_dv5p:          /* DVCPRO50 PAL */
14997       _codec ("DVCPro50 Video");
14998       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14999           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15000       break;
15001     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
15002     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
15003       _codec ("DVCProHD Video");
15004       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
15005           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15006       break;
15007     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
15008       _codec ("Apple Graphics (SMC)");
15009       caps = gst_caps_new_empty_simple ("video/x-smc");
15010       break;
15011     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
15012       _codec ("VP3");
15013       caps = gst_caps_new_empty_simple ("video/x-vp3");
15014       break;
15015     case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
15016       _codec ("VP6 Flash");
15017       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
15018       break;
15019     case FOURCC_XiTh:
15020       _codec ("Theora");
15021       caps = gst_caps_new_empty_simple ("video/x-theora");
15022       /* theora uses one byte of padding in the data stream because it does not
15023        * allow 0 sized packets while theora does */
15024       entry->padding = 1;
15025       break;
15026     case FOURCC_drac:
15027       _codec ("Dirac");
15028       caps = gst_caps_new_empty_simple ("video/x-dirac");
15029       break;
15030     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
15031       _codec ("TIFF still images");
15032       caps = gst_caps_new_empty_simple ("image/tiff");
15033       break;
15034     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
15035       _codec ("Apple Intermediate Codec");
15036       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
15037       break;
15038     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
15039       _codec ("AVID DNxHD");
15040       caps = gst_caps_from_string ("video/x-dnxhd");
15041       break;
15042     case FOURCC_VP80:
15043     case FOURCC_vp08:
15044       _codec ("On2 VP8");
15045       caps = gst_caps_from_string ("video/x-vp8");
15046       break;
15047     case FOURCC_vp09:
15048       _codec ("Google VP9");
15049       caps = gst_caps_from_string ("video/x-vp9");
15050       break;
15051     case FOURCC_apcs:
15052       _codec ("Apple ProRes LT");
15053       caps =
15054           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
15055           NULL);
15056       break;
15057     case FOURCC_apch:
15058       _codec ("Apple ProRes HQ");
15059       caps =
15060           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
15061           NULL);
15062       break;
15063     case FOURCC_apcn:
15064       _codec ("Apple ProRes");
15065       caps =
15066           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15067           "standard", NULL);
15068       break;
15069     case FOURCC_apco:
15070       _codec ("Apple ProRes Proxy");
15071       caps =
15072           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15073           "proxy", NULL);
15074       break;
15075     case FOURCC_ap4h:
15076       _codec ("Apple ProRes 4444");
15077       caps =
15078           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15079           "4444", NULL);
15080       break;
15081     case FOURCC_ap4x:
15082       _codec ("Apple ProRes 4444 XQ");
15083       caps =
15084           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15085           "4444xq", NULL);
15086       break;
15087     case FOURCC_cfhd:
15088       _codec ("GoPro CineForm");
15089       caps = gst_caps_from_string ("video/x-cineform");
15090       break;
15091     case FOURCC_vc_1:
15092     case FOURCC_ovc1:
15093       _codec ("VC-1");
15094       caps = gst_caps_new_simple ("video/x-wmv",
15095           "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
15096       break;
15097     case FOURCC_av01:
15098       _codec ("AV1");
15099       caps = gst_caps_new_empty_simple ("video/x-av1");
15100       break;
15101     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
15102     default:
15103     {
15104       caps = _get_unknown_codec_name ("video", fourcc);
15105       break;
15106     }
15107   }
15108 
15109   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
15110     GstVideoInfo info;
15111 
15112     gst_video_info_init (&info);
15113     gst_video_info_set_format (&info, format, entry->width, entry->height);
15114 
15115     caps = gst_video_info_to_caps (&info);
15116     *codec_name = gst_pb_utils_get_codec_description (caps);
15117 
15118     /* enable clipping for raw video streams */
15119     stream->need_clip = TRUE;
15120     stream->alignment = 32;
15121   }
15122 
15123   return caps;
15124 }
15125 
15126 static guint
round_up_pow2(guint n)15127 round_up_pow2 (guint n)
15128 {
15129   n = n - 1;
15130   n = n | (n >> 1);
15131   n = n | (n >> 2);
15132   n = n | (n >> 4);
15133   n = n | (n >> 8);
15134   n = n | (n >> 16);
15135   return n + 1;
15136 }
15137 
15138 static GstCaps *
qtdemux_audio_caps(GstQTDemux * qtdemux,QtDemuxStream * stream,QtDemuxStreamStsdEntry * entry,guint32 fourcc,const guint8 * data,int len,gchar ** codec_name)15139 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15140     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
15141     int len, gchar ** codec_name)
15142 {
15143   GstCaps *caps;
15144   const GstStructure *s;
15145   const gchar *name;
15146   gint endian = 0;
15147   GstAudioFormat format = 0;
15148   gint depth;
15149 
15150   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15151 
15152   depth = entry->bytes_per_packet * 8;
15153 
15154   switch (fourcc) {
15155     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
15156     case FOURCC_raw_:
15157       /* 8-bit audio is unsigned */
15158       if (depth == 8)
15159         format = GST_AUDIO_FORMAT_U8;
15160       /* otherwise it's signed and big-endian just like 'twos' */
15161     case FOURCC_twos:
15162       endian = G_BIG_ENDIAN;
15163       /* fall-through */
15164     case FOURCC_sowt:
15165     {
15166       gchar *str;
15167 
15168       if (!endian)
15169         endian = G_LITTLE_ENDIAN;
15170 
15171       if (!format)
15172         format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
15173 
15174       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
15175       _codec (str);
15176       g_free (str);
15177 
15178       caps = gst_caps_new_simple ("audio/x-raw",
15179           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15180           "layout", G_TYPE_STRING, "interleaved", NULL);
15181       stream->alignment = GST_ROUND_UP_8 (depth);
15182       stream->alignment = round_up_pow2 (stream->alignment);
15183       break;
15184     }
15185     case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
15186       _codec ("Raw 64-bit floating-point audio");
15187       caps = gst_caps_new_simple ("audio/x-raw",
15188           "format", G_TYPE_STRING, "F64BE",
15189           "layout", G_TYPE_STRING, "interleaved", NULL);
15190       stream->alignment = 8;
15191       break;
15192     case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
15193       _codec ("Raw 32-bit floating-point audio");
15194       caps = gst_caps_new_simple ("audio/x-raw",
15195           "format", G_TYPE_STRING, "F32BE",
15196           "layout", G_TYPE_STRING, "interleaved", NULL);
15197       stream->alignment = 4;
15198       break;
15199     case FOURCC_in24:
15200       _codec ("Raw 24-bit PCM audio");
15201       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15202        * endian later */
15203       caps = gst_caps_new_simple ("audio/x-raw",
15204           "format", G_TYPE_STRING, "S24BE",
15205           "layout", G_TYPE_STRING, "interleaved", NULL);
15206       stream->alignment = 4;
15207       break;
15208     case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
15209       _codec ("Raw 32-bit PCM audio");
15210       caps = gst_caps_new_simple ("audio/x-raw",
15211           "format", G_TYPE_STRING, "S32BE",
15212           "layout", G_TYPE_STRING, "interleaved", NULL);
15213       stream->alignment = 4;
15214       break;
15215     case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
15216       _codec ("Raw 16-bit PCM audio");
15217       caps = gst_caps_new_simple ("audio/x-raw",
15218           "format", G_TYPE_STRING, "S16LE",
15219           "layout", G_TYPE_STRING, "interleaved", NULL);
15220       stream->alignment = 2;
15221       break;
15222     case FOURCC_ulaw:
15223       _codec ("Mu-law audio");
15224       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15225       break;
15226     case FOURCC_alaw:
15227       _codec ("A-law audio");
15228       caps = gst_caps_new_empty_simple ("audio/x-alaw");
15229       break;
15230     case 0x0200736d:
15231     case 0x6d730002:
15232       _codec ("Microsoft ADPCM");
15233       /* Microsoft ADPCM-ACM code 2 */
15234       caps = gst_caps_new_simple ("audio/x-adpcm",
15235           "layout", G_TYPE_STRING, "microsoft", NULL);
15236       break;
15237     case 0x1100736d:
15238     case 0x6d730011:
15239       _codec ("DVI/IMA ADPCM");
15240       caps = gst_caps_new_simple ("audio/x-adpcm",
15241           "layout", G_TYPE_STRING, "dvi", NULL);
15242       break;
15243     case 0x1700736d:
15244     case 0x6d730017:
15245       _codec ("DVI/Intel IMA ADPCM");
15246       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15247       caps = gst_caps_new_simple ("audio/x-adpcm",
15248           "layout", G_TYPE_STRING, "quicktime", NULL);
15249       break;
15250     case 0x5500736d:
15251     case 0x6d730055:
15252       /* MPEG layer 3, CBR only (pre QT4.1) */
15253     case FOURCC__mp3:
15254       _codec ("MPEG-1 layer 3");
15255       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15256       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15257           "mpegversion", G_TYPE_INT, 1, NULL);
15258       break;
15259     case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15260       _codec ("MPEG-1 layer 2");
15261       /* MPEG layer 2 */
15262       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15263           "mpegversion", G_TYPE_INT, 1, NULL);
15264       break;
15265     case 0x20736d:
15266     case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15267       _codec ("EAC-3 audio");
15268       caps = gst_caps_new_simple ("audio/x-eac3",
15269           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15270       entry->sampled = TRUE;
15271       break;
15272     case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15273     case FOURCC_ac_3:
15274       _codec ("AC-3 audio");
15275       caps = gst_caps_new_simple ("audio/x-ac3",
15276           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15277       entry->sampled = TRUE;
15278       break;
15279     case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15280     case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15281       _codec ("DTS audio");
15282       caps = gst_caps_new_simple ("audio/x-dts",
15283           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15284       entry->sampled = TRUE;
15285       break;
15286     case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15287     case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15288       _codec ("DTS-HD audio");
15289       caps = gst_caps_new_simple ("audio/x-dts",
15290           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15291       entry->sampled = TRUE;
15292       break;
15293     case FOURCC_MAC3:
15294       _codec ("MACE-3");
15295       caps = gst_caps_new_simple ("audio/x-mace",
15296           "maceversion", G_TYPE_INT, 3, NULL);
15297       break;
15298     case FOURCC_MAC6:
15299       _codec ("MACE-6");
15300       caps = gst_caps_new_simple ("audio/x-mace",
15301           "maceversion", G_TYPE_INT, 6, NULL);
15302       break;
15303     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15304       /* ogg/vorbis */
15305       caps = gst_caps_new_empty_simple ("application/ogg");
15306       break;
15307     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15308       _codec ("DV audio");
15309       caps = gst_caps_new_empty_simple ("audio/x-dv");
15310       break;
15311     case FOURCC_mp4a:
15312       _codec ("MPEG-4 AAC audio");
15313       caps = gst_caps_new_simple ("audio/mpeg",
15314           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15315           "stream-format", G_TYPE_STRING, "raw", NULL);
15316       break;
15317     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15318       _codec ("QDesign Music");
15319       caps = gst_caps_new_empty_simple ("audio/x-qdm");
15320       break;
15321     case FOURCC_QDM2:
15322       _codec ("QDesign Music v.2");
15323       /* FIXME: QDesign music version 2 (no constant) */
15324       if (FALSE && data) {
15325         caps = gst_caps_new_simple ("audio/x-qdm2",
15326             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15327             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15328             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15329       } else {
15330         caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15331       }
15332       break;
15333     case FOURCC_agsm:
15334       _codec ("GSM audio");
15335       caps = gst_caps_new_empty_simple ("audio/x-gsm");
15336       break;
15337     case FOURCC_samr:
15338       _codec ("AMR audio");
15339       caps = gst_caps_new_empty_simple ("audio/AMR");
15340       break;
15341     case FOURCC_sawb:
15342       _codec ("AMR-WB audio");
15343       caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15344       break;
15345     case FOURCC_ima4:
15346       _codec ("Quicktime IMA ADPCM");
15347       caps = gst_caps_new_simple ("audio/x-adpcm",
15348           "layout", G_TYPE_STRING, "quicktime", NULL);
15349       break;
15350     case FOURCC_alac:
15351       _codec ("Apple lossless audio");
15352       caps = gst_caps_new_empty_simple ("audio/x-alac");
15353       break;
15354     case FOURCC_fLaC:
15355       _codec ("Free Lossless Audio Codec");
15356       caps = gst_caps_new_simple ("audio/x-flac",
15357           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15358       break;
15359     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15360       _codec ("QualComm PureVoice");
15361       caps = gst_caps_from_string ("audio/qcelp");
15362       break;
15363     case FOURCC_wma_:
15364     case FOURCC_owma:
15365       _codec ("WMA");
15366       caps = gst_caps_new_empty_simple ("audio/x-wma");
15367       break;
15368     case FOURCC_opus:
15369       _codec ("Opus");
15370       caps = gst_caps_new_empty_simple ("audio/x-opus");
15371       break;
15372     case FOURCC_lpcm:
15373     {
15374       guint32 flags = 0;
15375       guint32 depth = 0;
15376       guint32 width = 0;
15377       GstAudioFormat format;
15378       enum
15379       {
15380         FLAG_IS_FLOAT = 0x1,
15381         FLAG_IS_BIG_ENDIAN = 0x2,
15382         FLAG_IS_SIGNED = 0x4,
15383         FLAG_IS_PACKED = 0x8,
15384         FLAG_IS_ALIGNED_HIGH = 0x10,
15385         FLAG_IS_NON_INTERLEAVED = 0x20
15386       };
15387       _codec ("Raw LPCM audio");
15388 
15389       if (data && len >= 36) {
15390         depth = QT_UINT32 (data + 24);
15391         flags = QT_UINT32 (data + 28);
15392         width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15393       }
15394       if ((flags & FLAG_IS_FLOAT) == 0) {
15395         if (depth == 0)
15396           depth = 16;
15397         if (width == 0)
15398           width = 16;
15399         if ((flags & FLAG_IS_ALIGNED_HIGH))
15400           depth = width;
15401 
15402         format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15403             TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15404             G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15405         caps = gst_caps_new_simple ("audio/x-raw",
15406             "format", G_TYPE_STRING,
15407             format !=
15408             GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15409             "UNKNOWN", "layout", G_TYPE_STRING,
15410             (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15411             "interleaved", NULL);
15412         stream->alignment = GST_ROUND_UP_8 (depth);
15413         stream->alignment = round_up_pow2 (stream->alignment);
15414       } else {
15415         if (width == 0)
15416           width = 32;
15417         if (width == 64) {
15418           if (flags & FLAG_IS_BIG_ENDIAN)
15419             format = GST_AUDIO_FORMAT_F64BE;
15420           else
15421             format = GST_AUDIO_FORMAT_F64LE;
15422         } else {
15423           if (flags & FLAG_IS_BIG_ENDIAN)
15424             format = GST_AUDIO_FORMAT_F32BE;
15425           else
15426             format = GST_AUDIO_FORMAT_F32LE;
15427         }
15428         caps = gst_caps_new_simple ("audio/x-raw",
15429             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15430             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15431             "non-interleaved" : "interleaved", NULL);
15432         stream->alignment = width / 8;
15433       }
15434       break;
15435     }
15436     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15437       /* ? */
15438     default:
15439     {
15440       caps = _get_unknown_codec_name ("audio", fourcc);
15441       break;
15442     }
15443   }
15444 
15445   if (caps) {
15446     GstCaps *templ_caps =
15447         gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15448     GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15449     gst_caps_unref (caps);
15450     gst_caps_unref (templ_caps);
15451     caps = intersection;
15452   }
15453 
15454   /* enable clipping for raw audio streams */
15455   s = gst_caps_get_structure (caps, 0);
15456   name = gst_structure_get_name (s);
15457   if (g_str_has_prefix (name, "audio/x-raw")) {
15458     stream->need_clip = TRUE;
15459     stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15460     GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
15461   }
15462   return caps;
15463 }
15464 
15465 static GstCaps *
qtdemux_sub_caps(GstQTDemux * qtdemux,QtDemuxStream * stream,QtDemuxStreamStsdEntry * entry,guint32 fourcc,const guint8 * stsd_entry_data,gchar ** codec_name)15466 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15467     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15468     const guint8 * stsd_entry_data, gchar ** codec_name)
15469 {
15470   GstCaps *caps;
15471 
15472   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15473 
15474   switch (fourcc) {
15475     case FOURCC_mp4s:
15476       _codec ("DVD subtitle");
15477       caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15478       stream->need_process = TRUE;
15479       break;
15480     case FOURCC_text:
15481       _codec ("Quicktime timed text");
15482       goto text;
15483     case FOURCC_tx3g:
15484       _codec ("3GPP timed text");
15485     text:
15486       caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15487           "utf8", NULL);
15488       /* actual text piece needs to be extracted */
15489       stream->need_process = TRUE;
15490       break;
15491     case FOURCC_stpp:
15492       _codec ("XML subtitles");
15493       caps = gst_caps_new_empty_simple ("application/ttml+xml");
15494       break;
15495     case FOURCC_c608:
15496       _codec ("CEA 608 Closed Caption");
15497       caps =
15498           gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15499           G_TYPE_STRING, "s334-1a", NULL);
15500       stream->need_process = TRUE;
15501       stream->need_split = TRUE;
15502       break;
15503     case FOURCC_c708:
15504       _codec ("CEA 708 Closed Caption");
15505       caps =
15506           gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15507           G_TYPE_STRING, "cdp", NULL);
15508       stream->need_process = TRUE;
15509       break;
15510 
15511     default:
15512     {
15513       caps = _get_unknown_codec_name ("text", fourcc);
15514       break;
15515     }
15516   }
15517   return caps;
15518 }
15519 
15520 static GstCaps *
qtdemux_generic_caps(GstQTDemux * qtdemux,QtDemuxStream * stream,QtDemuxStreamStsdEntry * entry,guint32 fourcc,const guint8 * stsd_entry_data,gchar ** codec_name)15521 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15522     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15523     const guint8 * stsd_entry_data, gchar ** codec_name)
15524 {
15525   GstCaps *caps;
15526 
15527   switch (fourcc) {
15528     case FOURCC_m1v:
15529       _codec ("MPEG 1 video");
15530       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15531           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15532       break;
15533     default:
15534       caps = NULL;
15535       break;
15536   }
15537   return caps;
15538 }
15539 
15540 static void
gst_qtdemux_append_protection_system_id(GstQTDemux * qtdemux,const gchar * system_id)15541 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15542     const gchar * system_id)
15543 {
15544   gint i;
15545 
15546   if (!qtdemux->protection_system_ids)
15547     qtdemux->protection_system_ids =
15548         g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15549   /* Check whether we already have an entry for this system ID. */
15550   for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15551     const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15552     if (g_ascii_strcasecmp (system_id, id) == 0) {
15553       return;
15554     }
15555   }
15556   GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15557   g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
15558           -1));
15559 }
15560