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), ¶ms);
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