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
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.
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.
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.
31 * SECTION:element-qtdemux
33 * Demuxes a .mov file into raw or compressed audio and/or video streams.
35 * This element supports both push and pull-based scheduling, depending on the
36 * capabilities of the upstream elements.
39 * <title>Example launch line</title>
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.
53 #include "gst/gst-i18n-plugin.h"
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>
62 #include "qtatomparser.h"
63 #include "qtdemux_types.h"
64 #include "qtdemux_dump.h"
66 #include "descriptors.h"
67 #include "qtdemux_lang.h"
69 #include "qtpalette.h"
76 #include <gst/math-compat.h>
82 /* max. size considered 'sane' for non-mdat atoms */
83 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
85 /* if the sample index is larger than this, something is likely wrong */
86 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
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)
94 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
96 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
98 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
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))
107 GST_DEBUG_CATEGORY (qtdemux_debug);
108 #define GST_CAT_DEFAULT qtdemux_debug
110 typedef struct _QtDemuxSegment QtDemuxSegment;
111 typedef struct _QtDemuxSample QtDemuxSample;
113 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
115 struct _QtDemuxSample
118 gint32 pts_offset; /* Add this value to timestamp to get the pts */
120 guint64 timestamp; /* DTS In mov time */
121 guint32 duration; /* In mov time */
122 gboolean keyframe; /* TRUE when this packet is a keyframe */
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))
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))
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))
141 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
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()); \
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)); \
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.
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.
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:
169 * segment 1: media_time: 1 second, duration: 1 second, rate 1
170 * segment 2: media_time: 3 second, duration: 2 second, rate 2
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
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
181 * Visually, assuming the track has 4 second of media_time:
184 * .-----------------------------------------------------------.
185 * track: | K.....K.........K........K.......K.......K...........K... |
186 * '-----------------------------------------------------------'
188 * .------------^ ^ .----------^ ^
189 * / .-------------' / .------------------'
191 * .--------------. .--------------.
192 * | segment 1 | | segment 2 |
193 * '--------------' '--------------'
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.
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.
204 * We then proceed to push data from keyframe (a) to frame (b). The decoder
205 * decodes but clips all before media_time 1.
207 * After finishing a segment, we push out a new SEGMENT event with the clipping
208 * boundaries of the new data.
210 * This is a good usecase for the GStreamer accumulated SEGMENT events.
213 struct _QtDemuxSegment
215 /* global time and duration, all gst time */
217 GstClockTime stop_time;
218 GstClockTime duration;
219 /* media time of trak, all gst time */
220 GstClockTime media_start;
221 GstClockTime media_stop;
223 /* Media start time in trak timescale units */
224 guint32 trak_media_start;
227 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
229 /* Used with fragmented MP4 files (mfra atom) */
234 } QtDemuxRandomAccessEntry;
236 typedef struct _QtDemuxStreamStsdEntry
247 /* Numerator/denominator framerate */
250 GstVideoColorimetry colorimetry;
251 guint16 bits_per_sample;
252 guint16 color_table_id;
253 GstMemory *rgb8_palette;
254 guint interlace_mode;
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;
267 /* if we use chunks or samples */
271 } QtDemuxStreamStsdEntry;
273 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
275 struct _QtDemuxStream
282 QtDemuxStreamStsdEntry *stsd_entries;
283 guint stsd_entries_length;
284 guint cur_stsd_entry_index;
289 gboolean new_caps; /* If TRUE, caps need to be generated (by
290 * calling _configure_stream()) This happens
291 * for MSS and fragmented streams */
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 */
299 /* if the stream has a redirect URI in its headers, we store it here */
306 guint64 duration; /* in timescale units */
310 gchar lang_id[4]; /* ISO 639-2T language code */
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;
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*/
334 gboolean use_allocator;
335 GstAllocator *allocator;
336 GstAllocationParams params;
340 /* when a discontinuity is pending */
343 /* list of buffers to push first */
346 /* if we need to clip this buffer. This is only needed for uncompressed
350 /* buffer needs some custom processing, e.g. subtitles */
351 gboolean need_process;
353 /* current position */
354 guint32 segment_index;
355 guint32 sample_index;
356 GstClockTime time_position; /* in gst time */
357 guint64 accumulated_base;
359 /* the Gst segment we are processing out, used for clipping */
362 /* quicktime segments */
364 QtDemuxSegment *segments;
365 gboolean dummy_segment;
370 GstTagList *stream_tags;
371 gboolean send_global_tags;
373 GstEvent *pending_event;
383 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
387 GstByteReader co_chunk;
389 guint32 current_chunk;
391 guint32 samples_per_chunk;
392 guint32 stsd_sample_description_id;
393 guint32 stco_sample_index;
395 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
398 guint32 n_samples_per_chunk;
399 guint32 stsc_chunk_index;
400 guint32 stsc_sample_index;
401 guint64 chunk_offset;
404 guint32 stts_samples;
405 guint32 n_sample_times;
406 guint32 stts_sample_index;
408 guint32 stts_duration;
410 gboolean stss_present;
411 guint32 n_sample_syncs;
414 gboolean stps_present;
415 guint32 n_sample_partial_syncs;
417 QtDemuxRandomAccessEntry *ra_entries;
420 const QtDemuxRandomAccessEntry *pending_seek;
423 gboolean ctts_present;
424 guint32 n_composition_times;
426 guint32 ctts_sample_index;
434 gboolean parsed_trex;
435 guint32 def_sample_description_index; /* index is 1-based */
436 guint32 def_sample_duration;
437 guint32 def_sample_size;
438 guint32 def_sample_flags;
442 /* stereoscopic video streams */
443 GstVideoMultiviewMode multiview_mode;
444 GstVideoMultiviewFlags multiview_flags;
446 /* protected streams */
448 guint32 protection_scheme_type;
449 guint32 protection_scheme_version;
450 gpointer protection_scheme_info; /* specific to the protection scheme */
451 GQueue protection_scheme_event_queue;
453 gint ref_count; /* atomic */
456 /* Contains properties and cryptographic info for a set of samples from a
457 * track protected using Common Encryption (cenc) */
458 struct _QtDemuxCencSampleSetInfo
460 GstStructure *default_properties;
462 /* @crypto_info holds one GstStructure per sample */
463 GPtrArray *crypto_info;
467 qt_demux_state_string (enum QtDemuxState state)
470 case QTDEMUX_STATE_INITIAL:
472 case QTDEMUX_STATE_HEADER:
474 case QTDEMUX_STATE_MOVIE:
476 case QTDEMUX_STATE_BUFFER_MDAT:
477 return "<BUFFER_MDAT>";
483 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
484 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
485 guint32 fourcc, GstByteReader * parser);
486 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
487 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
488 guint32 fourcc, GstByteReader * parser);
490 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
492 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
494 static GstStaticPadTemplate gst_qtdemux_sink_template =
495 GST_STATIC_PAD_TEMPLATE ("sink",
498 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
502 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
503 GST_STATIC_PAD_TEMPLATE ("video_%u",
506 GST_STATIC_CAPS_ANY);
508 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
509 GST_STATIC_PAD_TEMPLATE ("audio_%u",
512 GST_STATIC_CAPS_ANY);
514 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
515 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
518 GST_STATIC_CAPS_ANY);
520 #define gst_qtdemux_parent_class parent_class
521 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
523 static void gst_qtdemux_dispose (GObject * object);
526 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
527 GstClockTime media_time);
529 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
530 QtDemuxStream * str, gint64 media_offset);
533 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
534 static GstIndex *gst_qtdemux_get_index (GstElement * element);
536 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
537 GstStateChange transition);
538 static void gst_qtdemux_set_context (GstElement * element,
539 GstContext * context);
540 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
541 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
542 GstObject * parent, GstPadMode mode, gboolean active);
544 static void gst_qtdemux_loop (GstPad * pad);
545 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
547 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
549 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
550 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
551 QtDemuxStream * stream);
552 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
553 QtDemuxStream * stream);
554 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
557 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
558 const guint8 * buffer, guint length);
559 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
560 const guint8 * buffer, guint length);
561 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
562 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
565 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
566 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
568 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
569 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
570 const guint8 * stsd_entry_data, gchar ** codec_name);
571 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
572 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
573 const guint8 * data, int len, gchar ** codec_name);
574 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
575 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
576 gchar ** codec_name);
577 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
578 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
579 const guint8 * stsd_entry_data, gchar ** codec_name);
581 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
582 QtDemuxStream * stream, guint32 n);
583 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
584 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
585 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
586 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
587 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
588 static void qtdemux_do_allocation (QtDemuxStream * stream,
589 GstQTDemux * qtdemux);
590 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
591 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
592 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
593 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
594 GstClockTime * _start, GstClockTime * _stop);
595 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
596 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
598 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
599 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
601 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
603 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
604 QtDemuxStream * stream, guint sample_index);
605 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
607 static void qtdemux_gst_structure_free (GstStructure * gststructure);
608 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
611 gst_qtdemux_class_init (GstQTDemuxClass * klass)
613 GObjectClass *gobject_class;
614 GstElementClass *gstelement_class;
616 gobject_class = (GObjectClass *) klass;
617 gstelement_class = (GstElementClass *) klass;
619 parent_class = g_type_class_peek_parent (klass);
621 gobject_class->dispose = gst_qtdemux_dispose;
623 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
625 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
626 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
628 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
630 gst_tag_register_musicbrainz_tags ();
632 gst_element_class_add_static_pad_template (gstelement_class,
633 &gst_qtdemux_sink_template);
634 gst_element_class_add_static_pad_template (gstelement_class,
635 &gst_qtdemux_videosrc_template);
636 gst_element_class_add_static_pad_template (gstelement_class,
637 &gst_qtdemux_audiosrc_template);
638 gst_element_class_add_static_pad_template (gstelement_class,
639 &gst_qtdemux_subsrc_template);
640 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
642 "Demultiplex a QuickTime file into audio and video streams",
643 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
645 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
650 gst_qtdemux_init (GstQTDemux * qtdemux)
653 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
654 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
655 gst_pad_set_activatemode_function (qtdemux->sinkpad,
656 qtdemux_sink_activate_mode);
657 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
658 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
659 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
661 qtdemux->adapter = gst_adapter_new ();
662 g_queue_init (&qtdemux->protection_event_queue);
663 qtdemux->flowcombiner = gst_flow_combiner_new ();
664 g_mutex_init (&qtdemux->expose_lock);
666 qtdemux->active_streams = g_ptr_array_new_with_free_func
667 ((GDestroyNotify) gst_qtdemux_stream_unref);
668 qtdemux->old_streams = g_ptr_array_new_with_free_func
669 ((GDestroyNotify) gst_qtdemux_stream_unref);
671 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
673 gst_qtdemux_reset (qtdemux, TRUE);
677 gst_qtdemux_dispose (GObject * object)
679 GstQTDemux *qtdemux = GST_QTDEMUX (object);
681 if (qtdemux->adapter) {
682 g_object_unref (G_OBJECT (qtdemux->adapter));
683 qtdemux->adapter = NULL;
685 gst_tag_list_unref (qtdemux->tag_list);
686 gst_flow_combiner_free (qtdemux->flowcombiner);
687 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
689 g_queue_clear (&qtdemux->protection_event_queue);
691 g_free (qtdemux->cenc_aux_info_sizes);
692 qtdemux->cenc_aux_info_sizes = NULL;
693 g_mutex_clear (&qtdemux->expose_lock);
695 g_ptr_array_free (qtdemux->active_streams, TRUE);
696 g_ptr_array_free (qtdemux->old_streams, TRUE);
698 G_OBJECT_CLASS (parent_class)->dispose (object);
702 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
704 if (qtdemux->posted_redirect) {
705 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
706 (_("This file contains no playable streams.")),
707 ("no known streams found, a redirect message has been posted"));
709 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
710 (_("This file contains no playable streams.")),
711 ("no known streams found"));
716 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
718 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
719 mem, size, 0, size, mem, free_func);
723 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
730 if (G_UNLIKELY (size == 0)) {
732 GstBuffer *tmp = NULL;
734 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
735 if (ret != GST_FLOW_OK)
738 gst_buffer_map (tmp, &map, GST_MAP_READ);
739 size = QT_UINT32 (map.data);
740 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
742 gst_buffer_unmap (tmp, &map);
743 gst_buffer_unref (tmp);
746 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
747 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
748 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
749 /* we're pulling header but already got most interesting bits,
750 * so never mind the rest (e.g. tags) (that much) */
751 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
755 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
756 (_("This file is invalid and cannot be played.")),
757 ("atom has bogus size %" G_GUINT64_FORMAT, size));
758 return GST_FLOW_ERROR;
762 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
764 if (G_UNLIKELY (flow != GST_FLOW_OK))
767 bsize = gst_buffer_get_size (*buf);
768 /* Catch short reads - we don't want any partial atoms */
769 if (G_UNLIKELY (bsize < size)) {
770 GST_WARNING_OBJECT (qtdemux,
771 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
772 gst_buffer_unref (*buf);
782 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
783 GstFormat src_format, gint64 src_value, GstFormat dest_format,
787 QtDemuxStream *stream = gst_pad_get_element_private (pad);
790 if (stream->subtype != FOURCC_vide) {
795 switch (src_format) {
796 case GST_FORMAT_TIME:
797 switch (dest_format) {
798 case GST_FORMAT_BYTES:{
799 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
805 *dest_value = stream->samples[index].offset;
807 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
808 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
809 GST_TIME_ARGS (src_value), *dest_value);
817 case GST_FORMAT_BYTES:
818 switch (dest_format) {
819 case GST_FORMAT_TIME:{
821 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
830 QTSTREAMTIME_TO_GSTTIME (stream,
831 stream->samples[index].timestamp);
832 GST_DEBUG_OBJECT (qtdemux,
833 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
834 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
853 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
855 gboolean res = FALSE;
857 *duration = GST_CLOCK_TIME_NONE;
859 if (qtdemux->duration != 0 &&
860 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
861 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
864 *duration = GST_CLOCK_TIME_NONE;
871 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
874 gboolean res = FALSE;
875 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
877 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
879 switch (GST_QUERY_TYPE (query)) {
880 case GST_QUERY_POSITION:{
883 gst_query_parse_position (query, &fmt, NULL);
884 if (fmt == GST_FORMAT_TIME
885 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
886 gst_query_set_position (query, GST_FORMAT_TIME,
887 qtdemux->segment.position);
892 case GST_QUERY_DURATION:{
895 gst_query_parse_duration (query, &fmt, NULL);
896 if (fmt == GST_FORMAT_TIME) {
897 /* First try to query upstream */
898 res = gst_pad_query_default (pad, parent, query);
900 GstClockTime duration;
901 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
902 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
909 case GST_QUERY_CONVERT:{
910 GstFormat src_fmt, dest_fmt;
911 gint64 src_value, dest_value = 0;
913 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
915 res = gst_qtdemux_src_convert (qtdemux, pad,
916 src_fmt, src_value, dest_fmt, &dest_value);
918 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
922 case GST_QUERY_FORMATS:
923 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
926 case GST_QUERY_SEEKING:{
930 /* try upstream first */
931 res = gst_pad_query_default (pad, parent, query);
934 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
935 if (fmt == GST_FORMAT_TIME) {
936 GstClockTime duration;
938 gst_qtdemux_get_duration (qtdemux, &duration);
940 if (!qtdemux->pullbased) {
943 /* we might be able with help from upstream */
945 q = gst_query_new_seeking (GST_FORMAT_BYTES);
946 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
947 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
948 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
952 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
958 case GST_QUERY_SEGMENT:
963 format = qtdemux->segment.format;
966 gst_segment_to_stream_time (&qtdemux->segment, format,
967 qtdemux->segment.start);
968 if ((stop = qtdemux->segment.stop) == -1)
969 stop = qtdemux->segment.duration;
971 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
973 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
978 res = gst_pad_query_default (pad, parent, query);
986 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
988 if (G_LIKELY (stream->pad)) {
989 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
990 GST_DEBUG_PAD_NAME (stream->pad));
992 if (!gst_tag_list_is_empty (stream->stream_tags)) {
993 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
994 stream->stream_tags);
995 gst_pad_push_event (stream->pad,
996 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
999 if (G_UNLIKELY (stream->send_global_tags)) {
1000 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
1002 gst_pad_push_event (stream->pad,
1003 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
1004 stream->send_global_tags = FALSE;
1009 /* push event on all source pads; takes ownership of the event */
1011 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1013 gboolean has_valid_stream = FALSE;
1014 GstEventType etype = GST_EVENT_TYPE (event);
1017 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1018 GST_EVENT_TYPE_NAME (event));
1020 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1022 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1023 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
1025 if ((pad = stream->pad)) {
1026 has_valid_stream = TRUE;
1028 if (etype == GST_EVENT_EOS) {
1029 /* let's not send twice */
1030 if (stream->sent_eos)
1032 stream->sent_eos = TRUE;
1035 gst_pad_push_event (pad, gst_event_ref (event));
1039 gst_event_unref (event);
1041 /* if it is EOS and there are no pads, post an error */
1042 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1043 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1053 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1055 if ((gint64) s1->timestamp > *media_time)
1057 if ((gint64) s1->timestamp == *media_time)
1063 /* find the index of the sample that includes the data for @media_time using a
1064 * binary search. Only to be called in optimized cases of linear search below.
1066 * Returns the index of the sample with the corresponding *DTS*.
1069 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1072 QtDemuxSample *result;
1075 /* convert media_time to mov format */
1077 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1079 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1080 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1081 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1083 if (G_LIKELY (result))
1084 index = result - str->samples;
1093 /* find the index of the sample that includes the data for @media_offset using a
1096 * Returns the index of the sample.
1099 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1100 QtDemuxStream * str, gint64 media_offset)
1102 QtDemuxSample *result = str->samples;
1105 if (result == NULL || str->n_samples == 0)
1108 if (media_offset == result->offset)
1112 while (index < str->n_samples - 1) {
1113 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1116 if (media_offset < result->offset)
1127 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1132 /* find the index of the sample that includes the data for @media_time using a
1133 * linear search, and keeping in mind that not all samples may have been parsed
1134 * yet. If possible, it will delegate to binary search.
1136 * Returns the index of the sample.
1139 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1140 GstClockTime media_time)
1144 QtDemuxSample *sample;
1146 /* convert media_time to mov format */
1148 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1150 sample = str->samples;
1151 if (mov_time == sample->timestamp + sample->pts_offset)
1154 /* use faster search if requested time in already parsed range */
1155 sample = str->samples + str->stbl_index;
1156 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
1157 index = gst_qtdemux_find_index (qtdemux, str, media_time);
1158 sample = str->samples + index;
1160 while (index < str->n_samples - 1) {
1161 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1164 sample = str->samples + index + 1;
1165 if (mov_time < sample->timestamp) {
1166 sample = str->samples + index;
1174 /* sample->timestamp is now <= media_time, need to find the corresponding
1175 * PTS now by looking backwards */
1176 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
1178 sample = str->samples + index;
1186 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1191 /* find the index of the keyframe needed to decode the sample at @index
1192 * of stream @str, or of a subsequent keyframe (depending on @next)
1194 * Returns the index of the keyframe.
1197 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1198 guint32 index, gboolean next)
1200 guint32 new_index = index;
1202 if (index >= str->n_samples) {
1203 new_index = str->n_samples;
1207 /* all keyframes, return index */
1208 if (str->all_keyframe) {
1213 /* else search until we have a keyframe */
1214 while (new_index < str->n_samples) {
1215 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1218 if (str->samples[new_index].keyframe)
1230 if (new_index == str->n_samples) {
1231 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1236 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1237 "gave %u", next ? "after" : "before", index, new_index);
1244 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1249 /* find the segment for @time_position for @stream
1251 * Returns the index of the segment containing @time_position.
1252 * Returns the last segment and sets the @eos variable to TRUE
1253 * if the time is beyond the end. @eos may be NULL
1256 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1257 GstClockTime time_position)
1262 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1263 GST_TIME_ARGS (time_position));
1266 for (i = 0; i < stream->n_segments; i++) {
1267 QtDemuxSegment *segment = &stream->segments[i];
1269 GST_LOG_OBJECT (stream->pad,
1270 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1271 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1273 /* For the last segment we include stop_time in the last segment */
1274 if (i < stream->n_segments - 1) {
1275 if (segment->time <= time_position && time_position < segment->stop_time) {
1276 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1281 /* Last segment always matches */
1289 /* move the stream @str to the sample position @index.
1291 * Updates @str->sample_index and marks discontinuity if needed.
1294 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1297 /* no change needed */
1298 if (index == str->sample_index)
1301 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1304 /* position changed, we have a discont */
1305 str->sample_index = index;
1306 str->offset_in_sample = 0;
1307 /* Each time we move in the stream we store the position where we are
1309 str->from_sample = index;
1310 str->discont = TRUE;
1314 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1315 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1318 gint64 min_byte_offset = -1;
1321 min_offset = desired_time;
1323 /* for each stream, find the index of the sample in the segment
1324 * and move back to the previous keyframe. */
1325 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1327 guint32 index, kindex;
1329 GstClockTime media_start;
1330 GstClockTime media_time;
1331 GstClockTime seg_time;
1332 QtDemuxSegment *seg;
1333 gboolean empty_segment = FALSE;
1335 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1337 if (CUR_STREAM (str)->sparse && !use_sparse)
1340 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1341 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1343 /* get segment and time in the segment */
1344 seg = &str->segments[seg_idx];
1345 seg_time = (desired_time - seg->time) * seg->rate;
1347 while (QTSEGMENT_IS_EMPTY (seg)) {
1349 empty_segment = TRUE;
1350 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1353 if (seg_idx == str->n_segments)
1355 seg = &str->segments[seg_idx];
1358 if (seg_idx == str->n_segments) {
1359 /* FIXME track shouldn't have the last segment as empty, but if it
1360 * happens we better handle it */
1364 /* get the media time in the segment */
1365 media_start = seg->media_start + seg_time;
1367 /* get the index of the sample with media time */
1368 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1369 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1370 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1371 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1374 /* shift to next frame if we are looking for next keyframe */
1375 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1376 && index < str->stbl_index)
1379 if (!empty_segment) {
1380 /* find previous keyframe */
1381 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1383 /* we will settle for one before if none found after */
1384 if (next && kindex == -1)
1385 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1387 /* if the keyframe is at a different position, we need to update the
1388 * requested seek time */
1389 if (index != kindex) {
1392 /* get timestamp of keyframe */
1393 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1394 GST_DEBUG_OBJECT (qtdemux,
1395 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1396 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1397 str->samples[kindex].offset);
1399 /* keyframes in the segment get a chance to change the
1400 * desired_offset. keyframes out of the segment are
1402 if (media_time >= seg->media_start) {
1403 GstClockTime seg_time;
1405 /* this keyframe is inside the segment, convert back to
1407 seg_time = (media_time - seg->media_start) + seg->time;
1408 if ((!next && (seg_time < min_offset)) ||
1409 (next && (seg_time > min_offset)))
1410 min_offset = seg_time;
1415 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1416 min_byte_offset = str->samples[index].offset;
1420 *key_time = min_offset;
1422 *key_offset = min_byte_offset;
1426 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1427 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1431 g_return_val_if_fail (format != NULL, FALSE);
1432 g_return_val_if_fail (cur != NULL, FALSE);
1433 g_return_val_if_fail (stop != NULL, FALSE);
1435 if (*format == GST_FORMAT_TIME)
1439 if (cur_type != GST_SEEK_TYPE_NONE)
1440 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1441 if (res && stop_type != GST_SEEK_TYPE_NONE)
1442 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1445 *format = GST_FORMAT_TIME;
1450 /* perform seek in push based mode:
1451 find BYTE position to move to based on time and delegate to upstream
1454 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1459 GstSeekType cur_type, stop_type;
1460 gint64 cur, stop, key_cur;
1463 gint64 original_stop;
1466 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1468 gst_event_parse_seek (event, &rate, &format, &flags,
1469 &cur_type, &cur, &stop_type, &stop);
1470 seqnum = gst_event_get_seqnum (event);
1472 /* only forward streaming and seeking is possible */
1474 goto unsupported_seek;
1476 /* convert to TIME if needed and possible */
1477 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1481 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1482 * the original stop position to use when upstream pushes the new segment
1484 original_stop = stop;
1487 /* find reasonable corresponding BYTE position,
1488 * also try to mind about keyframes, since we can not go back a bit for them
1490 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1491 * mostly just work, but let's not yet boldly go there ... */
1492 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1497 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1498 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1501 GST_OBJECT_LOCK (qtdemux);
1502 qtdemux->seek_offset = byte_cur;
1503 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1504 qtdemux->push_seek_start = cur;
1506 qtdemux->push_seek_start = key_cur;
1509 if (stop_type == GST_SEEK_TYPE_NONE) {
1510 qtdemux->push_seek_stop = qtdemux->segment.stop;
1512 qtdemux->push_seek_stop = original_stop;
1514 GST_OBJECT_UNLOCK (qtdemux);
1516 qtdemux->segment_seqnum = seqnum;
1517 /* BYTE seek event */
1518 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1520 gst_event_set_seqnum (event, seqnum);
1521 res = gst_pad_push_event (qtdemux->sinkpad, event);
1528 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1534 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1539 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1544 /* perform the seek.
1546 * We set all segment_indexes in the streams to unknown and
1547 * adjust the time_position to the desired position. this is enough
1548 * to trigger a segment switch in the streaming thread to start
1549 * streaming from the desired position.
1551 * Keyframe seeking is a little more complicated when dealing with
1552 * segments. Ideally we want to move to the previous keyframe in
1553 * the segment but there might not be a keyframe in the segment. In
1554 * fact, none of the segments could contain a keyframe. We take a
1555 * practical approach: seek to the previous keyframe in the segment,
1556 * if there is none, seek to the beginning of the segment.
1558 * Called with STREAM_LOCK
1561 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1562 guint32 seqnum, GstSeekFlags flags)
1564 gint64 desired_offset;
1567 desired_offset = segment->position;
1569 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1570 GST_TIME_ARGS (desired_offset));
1572 /* may not have enough fragmented info to do this adjustment,
1573 * and we can't scan (and probably should not) at this time with
1574 * possibly flushing upstream */
1575 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1577 gboolean next, before, after;
1579 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1580 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1581 next = after && !before;
1582 if (segment->rate < 0)
1585 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1587 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1588 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1589 desired_offset = min_offset;
1592 /* and set all streams to the final position */
1593 gst_flow_combiner_reset (qtdemux->flowcombiner);
1594 qtdemux->segment_seqnum = seqnum;
1595 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1596 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1598 stream->time_position = desired_offset;
1599 stream->accumulated_base = 0;
1600 stream->sample_index = -1;
1601 stream->offset_in_sample = 0;
1602 stream->segment_index = -1;
1603 stream->sent_eos = FALSE;
1605 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1606 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1608 segment->position = desired_offset;
1609 segment->time = desired_offset;
1610 if (segment->rate >= 0) {
1611 segment->start = desired_offset;
1613 /* we stop at the end */
1614 if (segment->stop == -1)
1615 segment->stop = segment->duration;
1617 segment->stop = desired_offset;
1620 if (qtdemux->fragmented)
1621 qtdemux->fragmented_seek_pending = TRUE;
1626 /* do a seek in pull based mode */
1628 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1633 GstSeekType cur_type, stop_type;
1637 GstSegment seeksegment;
1638 guint32 seqnum = GST_SEQNUM_INVALID;
1639 GstEvent *flush_event;
1643 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1645 gst_event_parse_seek (event, &rate, &format, &flags,
1646 &cur_type, &cur, &stop_type, &stop);
1647 seqnum = gst_event_get_seqnum (event);
1649 /* we have to have a format as the segment format. Try to convert
1651 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1655 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1657 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1661 flush = flags & GST_SEEK_FLAG_FLUSH;
1663 /* stop streaming, either by flushing or by pausing the task */
1665 flush_event = gst_event_new_flush_start ();
1666 if (seqnum != GST_SEQNUM_INVALID)
1667 gst_event_set_seqnum (flush_event, seqnum);
1668 /* unlock upstream pull_range */
1669 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1670 /* make sure out loop function exits */
1671 gst_qtdemux_push_event (qtdemux, flush_event);
1673 /* non flushing seek, pause the task */
1674 gst_pad_pause_task (qtdemux->sinkpad);
1677 /* wait for streaming to finish */
1678 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1680 /* copy segment, we need this because we still need the old
1681 * segment when we close the current segment. */
1682 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1685 /* configure the segment with the seek variables */
1686 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1687 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1688 cur_type, cur, stop_type, stop, &update)) {
1690 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1692 /* now do the seek */
1693 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1696 /* now do the seek */
1697 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1700 /* prepare for streaming again */
1702 flush_event = gst_event_new_flush_stop (TRUE);
1703 if (seqnum != GST_SEQNUM_INVALID)
1704 gst_event_set_seqnum (flush_event, seqnum);
1706 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1707 gst_qtdemux_push_event (qtdemux, flush_event);
1710 /* commit the new segment */
1711 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1713 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1714 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1715 qtdemux->segment.format, qtdemux->segment.position);
1716 if (seqnum != GST_SEQNUM_INVALID)
1717 gst_message_set_seqnum (msg, seqnum);
1718 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1721 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1722 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1723 qtdemux->sinkpad, NULL);
1725 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1732 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1738 qtdemux_ensure_index (GstQTDemux * qtdemux)
1742 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1744 /* Build complete index */
1745 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1746 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1748 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1749 GST_LOG_OBJECT (qtdemux,
1750 "Building complete index of track-id %u for seeking failed!",
1760 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1763 gboolean res = TRUE;
1764 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1766 switch (GST_EVENT_TYPE (event)) {
1767 case GST_EVENT_SEEK:
1769 #ifndef GST_DISABLE_GST_DEBUG
1770 GstClockTime ts = gst_util_get_timestamp ();
1772 guint32 seqnum = gst_event_get_seqnum (event);
1774 qtdemux->received_seek = TRUE;
1776 if (seqnum == qtdemux->segment_seqnum) {
1777 GST_LOG_OBJECT (pad,
1778 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1779 gst_event_unref (event);
1783 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1784 /* seek should be handled by upstream, we might need to re-download fragments */
1785 GST_DEBUG_OBJECT (qtdemux,
1786 "let upstream handle seek for fragmented playback");
1790 /* Build complete index for seeking;
1791 * if not a fragmented file at least */
1792 if (!qtdemux->fragmented)
1793 if (!qtdemux_ensure_index (qtdemux))
1795 #ifndef GST_DISABLE_GST_DEBUG
1796 ts = gst_util_get_timestamp () - ts;
1797 GST_INFO_OBJECT (qtdemux,
1798 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1801 if (qtdemux->pullbased) {
1802 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1803 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1804 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1806 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1807 && QTDEMUX_N_STREAMS (qtdemux)
1808 && !qtdemux->fragmented) {
1809 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1811 GST_DEBUG_OBJECT (qtdemux,
1812 "ignoring seek in push mode in current state");
1815 gst_event_unref (event);
1819 res = gst_pad_event_default (pad, parent, event);
1829 GST_ERROR_OBJECT (qtdemux, "Index failed");
1830 gst_event_unref (event);
1836 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1838 * If @fw is false, the coding order is explored backwards.
1840 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1841 * sample is found for that track.
1843 * The stream and sample index of the sample with the minimum offset in the direction explored
1844 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1846 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1847 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1848 * @_stream and @_index. */
1850 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1851 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1854 gint64 time, min_time;
1855 QtDemuxStream *stream;
1862 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1865 gboolean set_sample;
1867 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1874 i = str->n_samples - 1;
1878 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1879 if (str->samples[i].size == 0)
1882 if (fw && (str->samples[i].offset < byte_pos))
1885 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1888 /* move stream to first available sample */
1890 gst_qtdemux_move_stream (qtdemux, str, i);
1894 /* avoid index from sparse streams since they might be far away */
1895 if (!CUR_STREAM (str)->sparse) {
1896 /* determine min/max time */
1897 time = QTSAMPLE_PTS (str, &str->samples[i]);
1898 if (min_time == -1 || (!fw && time > min_time) ||
1899 (fw && time < min_time)) {
1903 /* determine stream with leading sample, to get its position */
1905 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1906 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1914 /* no sample for this stream, mark eos */
1916 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1927 /* Copied from mpegtsbase code */
1928 /* FIXME: replace this function when we add new util function for stream-id creation */
1930 _get_upstream_id (GstQTDemux * demux)
1932 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1935 /* Try to create one from the upstream URI, else use a randome number */
1939 /* Try to generate one from the URI query and
1940 * if it fails take a random number instead */
1941 query = gst_query_new_uri ();
1942 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1943 gst_query_parse_uri (query, &uri);
1949 /* And then generate an SHA256 sum of the URI */
1950 cs = g_checksum_new (G_CHECKSUM_SHA256);
1951 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1953 upstream_id = g_strdup (g_checksum_get_string (cs));
1954 g_checksum_free (cs);
1956 /* Just get some random number if the URI query fails */
1957 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1958 "implementing a deterministic way of creating a stream-id");
1960 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1961 g_random_int (), g_random_int ());
1964 gst_query_unref (query);
1969 static QtDemuxStream *
1970 _create_stream (GstQTDemux * demux, guint32 track_id)
1972 QtDemuxStream *stream;
1975 stream = g_new0 (QtDemuxStream, 1);
1976 stream->demux = demux;
1977 stream->track_id = track_id;
1978 upstream_id = _get_upstream_id (demux);
1979 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1980 g_free (upstream_id);
1981 /* new streams always need a discont */
1982 stream->discont = TRUE;
1983 /* we enable clipping for raw audio/video streams */
1984 stream->need_clip = FALSE;
1985 stream->need_process = FALSE;
1986 stream->segment_index = -1;
1987 stream->time_position = 0;
1988 stream->sample_index = -1;
1989 stream->offset_in_sample = 0;
1990 stream->new_stream = TRUE;
1991 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1992 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1993 stream->protected = FALSE;
1994 stream->protection_scheme_type = 0;
1995 stream->protection_scheme_version = 0;
1996 stream->protection_scheme_info = NULL;
1997 stream->n_samples_moof = 0;
1998 stream->duration_moof = 0;
1999 stream->duration_last_moof = 0;
2000 stream->alignment = 1;
2001 stream->stream_tags = gst_tag_list_new_empty ();
2002 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2003 g_queue_init (&stream->protection_scheme_event_queue);
2004 stream->ref_count = 1;
2009 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
2011 GstStructure *structure;
2012 const gchar *variant;
2013 const GstCaps *mediacaps = NULL;
2015 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
2017 structure = gst_caps_get_structure (caps, 0);
2018 variant = gst_structure_get_string (structure, "variant");
2020 if (variant && strcmp (variant, "mss-fragmented") == 0) {
2021 QtDemuxStream *stream;
2022 const GValue *value;
2024 demux->fragmented = TRUE;
2025 demux->mss_mode = TRUE;
2027 if (QTDEMUX_N_STREAMS (demux) > 1) {
2028 /* can't do this, we can only renegotiate for another mss format */
2032 value = gst_structure_get_value (structure, "media-caps");
2035 const GValue *timescale_v;
2037 /* TODO update when stream changes during playback */
2039 if (QTDEMUX_N_STREAMS (demux) == 0) {
2040 stream = _create_stream (demux, 1);
2041 g_ptr_array_add (demux->active_streams, stream);
2042 /* mss has no stsd/stsd entry, use id 0 as default */
2043 stream->stsd_entries_length = 1;
2044 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
2045 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
2047 stream = QTDEMUX_NTH_STREAM (demux, 0);
2050 timescale_v = gst_structure_get_value (structure, "timescale");
2052 stream->timescale = g_value_get_uint64 (timescale_v);
2054 /* default mss timescale */
2055 stream->timescale = 10000000;
2057 demux->timescale = stream->timescale;
2059 mediacaps = gst_value_get_caps (value);
2060 if (!CUR_STREAM (stream)->caps
2061 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2062 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2064 stream->new_caps = TRUE;
2066 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2067 structure = gst_caps_get_structure (mediacaps, 0);
2068 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2069 stream->subtype = FOURCC_vide;
2071 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2072 gst_structure_get_int (structure, "height",
2073 &CUR_STREAM (stream)->height);
2074 gst_structure_get_fraction (structure, "framerate",
2075 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2076 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2078 stream->subtype = FOURCC_soun;
2079 gst_structure_get_int (structure, "channels",
2080 &CUR_STREAM (stream)->n_channels);
2081 gst_structure_get_int (structure, "rate", &rate);
2082 CUR_STREAM (stream)->rate = rate;
2085 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2087 demux->mss_mode = FALSE;
2094 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2098 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2099 gst_pad_stop_task (qtdemux->sinkpad);
2101 if (hard || qtdemux->upstream_format_is_time) {
2102 qtdemux->state = QTDEMUX_STATE_INITIAL;
2103 qtdemux->neededbytes = 16;
2104 qtdemux->todrop = 0;
2105 qtdemux->pullbased = FALSE;
2106 qtdemux->posted_redirect = FALSE;
2107 qtdemux->first_mdat = -1;
2108 qtdemux->header_size = 0;
2109 qtdemux->mdatoffset = -1;
2110 qtdemux->restoredata_offset = -1;
2111 if (qtdemux->mdatbuffer)
2112 gst_buffer_unref (qtdemux->mdatbuffer);
2113 if (qtdemux->restoredata_buffer)
2114 gst_buffer_unref (qtdemux->restoredata_buffer);
2115 qtdemux->mdatbuffer = NULL;
2116 qtdemux->restoredata_buffer = NULL;
2117 qtdemux->mdatleft = 0;
2118 qtdemux->mdatsize = 0;
2119 if (qtdemux->comp_brands)
2120 gst_buffer_unref (qtdemux->comp_brands);
2121 qtdemux->comp_brands = NULL;
2122 qtdemux->last_moov_offset = -1;
2123 if (qtdemux->moov_node_compressed) {
2124 g_node_destroy (qtdemux->moov_node_compressed);
2125 if (qtdemux->moov_node)
2126 g_free (qtdemux->moov_node->data);
2128 qtdemux->moov_node_compressed = NULL;
2129 if (qtdemux->moov_node)
2130 g_node_destroy (qtdemux->moov_node);
2131 qtdemux->moov_node = NULL;
2132 if (qtdemux->tag_list)
2133 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2134 qtdemux->tag_list = gst_tag_list_new_empty ();
2135 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2137 if (qtdemux->element_index)
2138 gst_object_unref (qtdemux->element_index);
2139 qtdemux->element_index = NULL;
2141 qtdemux->major_brand = 0;
2142 qtdemux->upstream_format_is_time = FALSE;
2143 qtdemux->upstream_seekable = FALSE;
2144 qtdemux->upstream_size = 0;
2146 qtdemux->fragment_start = -1;
2147 qtdemux->fragment_start_offset = -1;
2148 qtdemux->duration = 0;
2149 qtdemux->moof_offset = 0;
2150 qtdemux->chapters_track_id = 0;
2151 qtdemux->have_group_id = FALSE;
2152 qtdemux->group_id = G_MAXUINT;
2154 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2156 g_queue_clear (&qtdemux->protection_event_queue);
2158 qtdemux->received_seek = FALSE;
2159 qtdemux->first_moof_already_parsed = FALSE;
2161 qtdemux->offset = 0;
2162 gst_adapter_clear (qtdemux->adapter);
2163 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2164 qtdemux->need_segment = TRUE;
2167 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2168 g_ptr_array_remove_range (qtdemux->active_streams,
2169 0, qtdemux->active_streams->len);
2170 g_ptr_array_remove_range (qtdemux->old_streams,
2171 0, qtdemux->old_streams->len);
2172 qtdemux->n_video_streams = 0;
2173 qtdemux->n_audio_streams = 0;
2174 qtdemux->n_sub_streams = 0;
2175 qtdemux->exposed = FALSE;
2176 qtdemux->fragmented = FALSE;
2177 qtdemux->mss_mode = FALSE;
2178 gst_caps_replace (&qtdemux->media_caps, NULL);
2179 qtdemux->timescale = 0;
2180 qtdemux->got_moov = FALSE;
2181 qtdemux->cenc_aux_info_offset = 0;
2182 qtdemux->cenc_aux_info_sizes = NULL;
2183 qtdemux->cenc_aux_sample_count = 0;
2184 if (qtdemux->protection_system_ids) {
2185 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2186 qtdemux->protection_system_ids = NULL;
2188 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2189 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2190 GST_BIN_FLAG_STREAMS_AWARE);
2192 if (qtdemux->preferred_protection_system_id) {
2193 g_free (qtdemux->preferred_protection_system_id);
2194 qtdemux->preferred_protection_system_id = NULL;
2196 } else if (qtdemux->mss_mode) {
2197 gst_flow_combiner_reset (qtdemux->flowcombiner);
2198 g_ptr_array_foreach (qtdemux->active_streams,
2199 (GFunc) gst_qtdemux_stream_clear, NULL);
2201 gst_flow_combiner_reset (qtdemux->flowcombiner);
2202 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2203 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2204 stream->sent_eos = FALSE;
2205 stream->time_position = 0;
2206 stream->accumulated_base = 0;
2212 /* Maps the @segment to the qt edts internal segments and pushes
2213 * the correspnding segment event.
2215 * If it ends up being at a empty segment, a gap will be pushed and the next
2216 * edts segment will be activated in sequence.
2218 * To be used in push-mode only */
2220 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2224 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2225 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2227 stream->time_position = segment->start;
2229 /* in push mode we should be guaranteed that we will have empty segments
2230 * at the beginning and then one segment after, other scenarios are not
2231 * supported and are discarded when parsing the edts */
2232 for (i = 0; i < stream->n_segments; i++) {
2233 if (stream->segments[i].stop_time > segment->start) {
2234 /* push the empty segment and move to the next one */
2235 gst_qtdemux_activate_segment (qtdemux, stream, i,
2236 stream->time_position);
2237 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2238 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2239 stream->time_position);
2241 /* accumulate previous segments */
2242 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2243 stream->accumulated_base +=
2244 (stream->segment.stop -
2245 stream->segment.start) / ABS (stream->segment.rate);
2249 g_assert (i == stream->n_segments - 1);
2256 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2267 for (i = 0; i < len; i++) {
2268 QtDemuxStream *stream = g_ptr_array_index (src, i);
2270 #ifndef GST_DISABLE_GST_DEBUG
2271 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2272 stream, GST_STR_NULL (stream->stream_id), dest);
2274 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2277 g_ptr_array_remove_range (src, 0, len);
2281 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2284 GstQTDemux *demux = GST_QTDEMUX (parent);
2285 gboolean res = TRUE;
2287 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2289 switch (GST_EVENT_TYPE (event)) {
2290 case GST_EVENT_SEGMENT:
2293 QtDemuxStream *stream;
2297 /* some debug output */
2298 gst_event_copy_segment (event, &segment);
2299 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2302 if (segment.format == GST_FORMAT_TIME) {
2303 demux->upstream_format_is_time = TRUE;
2304 demux->segment_seqnum = gst_event_get_seqnum (event);
2306 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2307 "not in time format");
2309 /* chain will send initial newsegment after pads have been added */
2310 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2311 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2316 /* check if this matches a time seek we received previously
2317 * FIXME for backwards compatibility reasons we use the
2318 * seek_offset here to compare. In the future we might want to
2319 * change this to use the seqnum as it uniquely should identify
2320 * the segment that corresponds to the seek. */
2321 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2322 ", received segment offset %" G_GINT64_FORMAT,
2323 demux->seek_offset, segment.start);
2324 if (segment.format == GST_FORMAT_BYTES
2325 && demux->seek_offset == segment.start) {
2326 GST_OBJECT_LOCK (demux);
2327 offset = segment.start;
2329 segment.format = GST_FORMAT_TIME;
2330 segment.start = demux->push_seek_start;
2331 segment.stop = demux->push_seek_stop;
2332 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2333 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2334 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2335 GST_OBJECT_UNLOCK (demux);
2338 /* we only expect a BYTE segment, e.g. following a seek */
2339 if (segment.format == GST_FORMAT_BYTES) {
2340 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2341 offset = segment.start;
2343 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2344 NULL, (gint64 *) & segment.start);
2345 if ((gint64) segment.start < 0)
2348 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2349 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2350 NULL, (gint64 *) & segment.stop);
2351 /* keyframe seeking should already arrange for start >= stop,
2352 * but make sure in other rare cases */
2353 segment.stop = MAX (segment.stop, segment.start);
2355 } else if (segment.format == GST_FORMAT_TIME) {
2356 /* push all data on the adapter before starting this
2358 gst_qtdemux_process_adapter (demux, TRUE);
2360 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2364 /* We shouldn't modify upstream driven TIME FORMAT segment */
2365 if (!demux->upstream_format_is_time) {
2366 /* accept upstream's notion of segment and distribute along */
2367 segment.format = GST_FORMAT_TIME;
2368 segment.position = segment.time = segment.start;
2369 segment.duration = demux->segment.duration;
2370 segment.base = gst_segment_to_running_time (&demux->segment,
2371 GST_FORMAT_TIME, demux->segment.position);
2374 gst_segment_copy_into (&segment, &demux->segment);
2375 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2377 /* map segment to internal qt segments and push on each stream */
2378 if (QTDEMUX_N_STREAMS (demux)) {
2379 demux->need_segment = TRUE;
2380 gst_qtdemux_check_send_pending_segment (demux);
2383 /* clear leftover in current segment, if any */
2384 gst_adapter_clear (demux->adapter);
2386 /* set up streaming thread */
2387 demux->offset = offset;
2388 if (demux->upstream_format_is_time) {
2389 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2390 "set values to restart reading from a new atom");
2391 demux->neededbytes = 16;
2394 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2397 demux->todrop = stream->samples[idx].offset - offset;
2398 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2400 /* set up for EOS */
2401 demux->neededbytes = -1;
2406 gst_event_unref (event);
2410 case GST_EVENT_FLUSH_START:
2412 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2413 gst_event_unref (event);
2416 QTDEMUX_EXPOSE_LOCK (demux);
2417 res = gst_pad_event_default (demux->sinkpad, parent, event);
2418 QTDEMUX_EXPOSE_UNLOCK (demux);
2421 case GST_EVENT_FLUSH_STOP:
2425 dur = demux->segment.duration;
2426 gst_qtdemux_reset (demux, FALSE);
2427 demux->segment.duration = dur;
2429 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2430 gst_event_unref (event);
2436 /* If we are in push mode, and get an EOS before we've seen any streams,
2437 * then error out - we have nowhere to send the EOS */
2438 if (!demux->pullbased) {
2440 gboolean has_valid_stream = FALSE;
2441 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2442 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2443 has_valid_stream = TRUE;
2447 if (!has_valid_stream)
2448 gst_qtdemux_post_no_playable_stream_error (demux);
2450 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2451 (guint) gst_adapter_available (demux->adapter));
2452 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2458 case GST_EVENT_CAPS:{
2459 GstCaps *caps = NULL;
2461 gst_event_parse_caps (event, &caps);
2462 gst_qtdemux_setcaps (demux, caps);
2464 gst_event_unref (event);
2467 case GST_EVENT_PROTECTION:
2469 const gchar *system_id = NULL;
2471 gst_event_parse_protection (event, &system_id, NULL, NULL);
2472 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2474 gst_qtdemux_append_protection_system_id (demux, system_id);
2475 /* save the event for later, for source pads that have not been created */
2476 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2477 /* send it to all pads that already exist */
2478 gst_qtdemux_push_event (demux, event);
2482 case GST_EVENT_STREAM_START:
2485 gst_event_unref (event);
2487 /* Drain all the buffers */
2488 gst_qtdemux_process_adapter (demux, TRUE);
2489 gst_qtdemux_reset (demux, FALSE);
2490 /* We expect new moov box after new stream-start event */
2491 if (demux->exposed) {
2492 gst_qtdemux_stream_concat (demux,
2493 demux->old_streams, demux->active_streams);
2502 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2510 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2512 GstQTDemux *demux = GST_QTDEMUX (element);
2514 GST_OBJECT_LOCK (demux);
2515 if (demux->element_index)
2516 gst_object_unref (demux->element_index);
2518 demux->element_index = gst_object_ref (index);
2520 demux->element_index = NULL;
2522 GST_OBJECT_UNLOCK (demux);
2523 /* object lock might be taken again */
2525 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2526 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2527 demux->element_index, demux->index_id);
2531 gst_qtdemux_get_index (GstElement * element)
2533 GstIndex *result = NULL;
2534 GstQTDemux *demux = GST_QTDEMUX (element);
2536 GST_OBJECT_LOCK (demux);
2537 if (demux->element_index)
2538 result = gst_object_ref (demux->element_index);
2539 GST_OBJECT_UNLOCK (demux);
2541 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2548 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2550 g_free ((gpointer) stream->stco.data);
2551 stream->stco.data = NULL;
2552 g_free ((gpointer) stream->stsz.data);
2553 stream->stsz.data = NULL;
2554 g_free ((gpointer) stream->stsc.data);
2555 stream->stsc.data = NULL;
2556 g_free ((gpointer) stream->stts.data);
2557 stream->stts.data = NULL;
2558 g_free ((gpointer) stream->stss.data);
2559 stream->stss.data = NULL;
2560 g_free ((gpointer) stream->stps.data);
2561 stream->stps.data = NULL;
2562 g_free ((gpointer) stream->ctts.data);
2563 stream->ctts.data = NULL;
2567 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2569 g_free (stream->segments);
2570 stream->segments = NULL;
2571 stream->segment_index = -1;
2572 stream->accumulated_base = 0;
2576 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2578 g_free (stream->samples);
2579 stream->samples = NULL;
2580 gst_qtdemux_stbl_free (stream);
2583 g_free (stream->ra_entries);
2584 stream->ra_entries = NULL;
2585 stream->n_ra_entries = 0;
2587 stream->sample_index = -1;
2588 stream->stbl_index = -1;
2589 stream->n_samples = 0;
2590 stream->time_position = 0;
2592 stream->n_samples_moof = 0;
2593 stream->duration_moof = 0;
2594 stream->duration_last_moof = 0;
2598 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2601 if (stream->allocator)
2602 gst_object_unref (stream->allocator);
2603 while (stream->buffers) {
2604 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2605 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2607 for (i = 0; i < stream->stsd_entries_length; i++) {
2608 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2609 if (entry->rgb8_palette) {
2610 gst_memory_unref (entry->rgb8_palette);
2611 entry->rgb8_palette = NULL;
2613 entry->sparse = FALSE;
2616 if (stream->stream_tags)
2617 gst_tag_list_unref (stream->stream_tags);
2619 stream->stream_tags = gst_tag_list_new_empty ();
2620 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2621 g_free (stream->redirect_uri);
2622 stream->redirect_uri = NULL;
2623 stream->sent_eos = FALSE;
2624 stream->protected = FALSE;
2625 if (stream->protection_scheme_info) {
2626 if (stream->protection_scheme_type == FOURCC_cenc) {
2627 QtDemuxCencSampleSetInfo *info =
2628 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2629 if (info->default_properties)
2630 gst_structure_free (info->default_properties);
2631 if (info->crypto_info)
2632 g_ptr_array_free (info->crypto_info, TRUE);
2634 g_free (stream->protection_scheme_info);
2635 stream->protection_scheme_info = NULL;
2637 stream->protection_scheme_type = 0;
2638 stream->protection_scheme_version = 0;
2639 g_queue_foreach (&stream->protection_scheme_event_queue,
2640 (GFunc) gst_event_unref, NULL);
2641 g_queue_clear (&stream->protection_scheme_event_queue);
2642 gst_qtdemux_stream_flush_segments_data (stream);
2643 gst_qtdemux_stream_flush_samples_data (stream);
2647 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2650 gst_qtdemux_stream_clear (stream);
2651 for (i = 0; i < stream->stsd_entries_length; i++) {
2652 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2654 gst_caps_unref (entry->caps);
2658 g_free (stream->stsd_entries);
2659 stream->stsd_entries = NULL;
2660 stream->stsd_entries_length = 0;
2663 static QtDemuxStream *
2664 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2666 g_atomic_int_add (&stream->ref_count, 1);
2672 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2674 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2675 gst_qtdemux_stream_reset (stream);
2676 gst_tag_list_unref (stream->stream_tags);
2678 GstQTDemux *demux = stream->demux;
2679 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2680 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2682 g_free (stream->stream_id);
2687 static GstStateChangeReturn
2688 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2690 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2691 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2693 switch (transition) {
2694 case GST_STATE_CHANGE_READY_TO_PAUSED:
2695 gst_qtdemux_reset (qtdemux, TRUE);
2701 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2703 switch (transition) {
2704 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2705 gst_qtdemux_reset (qtdemux, TRUE);
2716 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2718 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2720 g_return_if_fail (GST_IS_CONTEXT (context));
2722 if (gst_context_has_context_type (context,
2723 "drm-preferred-decryption-system-id")) {
2724 const GstStructure *s;
2726 s = gst_context_get_structure (context);
2727 g_free (qtdemux->preferred_protection_system_id);
2728 qtdemux->preferred_protection_system_id =
2729 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2730 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2731 qtdemux->preferred_protection_system_id);
2734 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2738 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2740 /* counts as header data */
2741 qtdemux->header_size += length;
2743 /* only consider at least a sufficiently complete ftyp atom */
2747 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2748 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2749 GST_FOURCC_ARGS (qtdemux->major_brand));
2750 if (qtdemux->comp_brands)
2751 gst_buffer_unref (qtdemux->comp_brands);
2752 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2753 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2758 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2759 GstTagList * xmptaglist)
2761 /* Strip out bogus fields */
2763 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2764 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2765 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2767 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2770 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2772 /* prioritize native tags using _KEEP mode */
2773 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2774 gst_tag_list_unref (xmptaglist);
2779 qtdemux_update_default_sample_encryption_settings (GstQTDemux * qtdemux,
2780 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted, guint8 iv_size,
2783 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2784 gst_buffer_fill (kid_buf, 0, kid, 16);
2785 if (info->default_properties)
2786 gst_structure_free (info->default_properties);
2787 info->default_properties =
2788 gst_structure_new ("application/x-cenc",
2789 "iv_size", G_TYPE_UINT, iv_size,
2790 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2791 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2792 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2793 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2794 gst_buffer_unref (kid_buf);
2798 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2799 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2801 guint32 algorithm_id = 0;
2803 gboolean is_encrypted = TRUE;
2806 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2807 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2812 if (algorithm_id == 0) {
2813 is_encrypted = FALSE;
2814 } else if (algorithm_id == 1) {
2815 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2816 } else if (algorithm_id == 2) {
2817 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2820 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2823 if (!gst_byte_reader_get_data (br, 16, &kid))
2826 qtdemux_update_default_sample_encryption_settings (qtdemux, info,
2827 is_encrypted, iv_size, kid);
2828 gst_structure_set (info->default_properties, "piff_algorithm_id",
2829 G_TYPE_UINT, algorithm_id, NULL);
2835 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2843 QtDemuxStream *stream;
2844 GstStructure *structure;
2845 QtDemuxCencSampleSetInfo *ss_info = NULL;
2846 const gchar *system_id;
2847 gboolean uses_sub_sample_encryption = FALSE;
2848 guint32 sample_count;
2850 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2853 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2855 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2856 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2857 GST_WARNING_OBJECT (qtdemux,
2858 "Attempting PIFF box parsing on an unencrypted stream.");
2862 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2863 G_TYPE_STRING, &system_id, NULL);
2864 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2866 stream->protected = TRUE;
2867 stream->protection_scheme_type = FOURCC_cenc;
2869 if (!stream->protection_scheme_info)
2870 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2872 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2873 if (!ss_info->default_properties) {
2874 ss_info->default_properties =
2875 gst_structure_new ("application/x-cenc",
2876 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2881 if (ss_info->crypto_info) {
2882 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2883 g_ptr_array_free (ss_info->crypto_info, TRUE);
2884 ss_info->crypto_info = NULL;
2888 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2890 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2891 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2895 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2896 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2900 if ((flags & 0x000001)) {
2901 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2904 } else if ((flags & 0x000002)) {
2905 uses_sub_sample_encryption = TRUE;
2908 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2910 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2914 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2915 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2919 ss_info->crypto_info =
2920 g_ptr_array_new_full (sample_count,
2921 (GDestroyNotify) qtdemux_gst_structure_free);
2923 for (i = 0; i < sample_count; ++i) {
2924 GstStructure *properties;
2928 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2929 if (properties == NULL) {
2930 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2931 qtdemux->cenc_aux_sample_count = i;
2935 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2936 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2937 gst_structure_free (properties);
2938 qtdemux->cenc_aux_sample_count = i;
2941 buf = gst_buffer_new_wrapped (data, iv_size);
2942 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2943 gst_buffer_unref (buf);
2945 if (uses_sub_sample_encryption) {
2946 guint16 n_subsamples;
2947 const GValue *kid_buf_value;
2949 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2950 || n_subsamples == 0) {
2951 GST_ERROR_OBJECT (qtdemux,
2952 "failed to get subsample count for sample %u", i);
2953 gst_structure_free (properties);
2954 qtdemux->cenc_aux_sample_count = i;
2957 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2958 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2959 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2961 gst_structure_free (properties);
2962 qtdemux->cenc_aux_sample_count = i;
2965 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2968 gst_structure_get_value (ss_info->default_properties, "kid");
2970 gst_structure_set (properties,
2971 "subsample_count", G_TYPE_UINT, n_subsamples,
2972 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2973 gst_structure_set_value (properties, "kid", kid_buf_value);
2974 gst_buffer_unref (buf);
2976 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2979 g_ptr_array_add (ss_info->crypto_info, properties);
2982 qtdemux->cenc_aux_sample_count = sample_count;
2986 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2988 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2989 0x97, 0xA9, 0x42, 0xE8,
2990 0x9C, 0x71, 0x99, 0x94,
2991 0x91, 0xE3, 0xAF, 0xAC
2993 static const guint8 playready_uuid[] = {
2994 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2995 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2998 static const guint8 piff_sample_encryption_uuid[] = {
2999 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
3000 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
3005 /* counts as header data */
3006 qtdemux->header_size += length;
3008 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3010 if (length <= offset + 16) {
3011 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
3015 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3017 GstTagList *taglist;
3019 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3020 length - offset - 16, NULL);
3021 taglist = gst_tag_list_from_xmp_buffer (buf);
3022 gst_buffer_unref (buf);
3024 /* make sure we have a usable taglist */
3025 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3027 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3029 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3031 const gunichar2 *s_utf16;
3034 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3035 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3036 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3037 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3041 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3042 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3044 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3045 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3047 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3048 GST_READ_UINT32_LE (buffer + offset),
3049 GST_READ_UINT32_LE (buffer + offset + 4),
3050 GST_READ_UINT32_LE (buffer + offset + 8),
3051 GST_READ_UINT32_LE (buffer + offset + 12));
3056 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3058 GstSidxParser sidx_parser;
3059 GstIsoffParserResult res;
3062 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3065 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3067 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3068 if (res == GST_ISOFF_QT_PARSER_DONE) {
3069 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3071 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3074 /* caller verifies at least 8 bytes in buf */
3076 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3077 guint64 * plength, guint32 * pfourcc)
3082 length = QT_UINT32 (data);
3083 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3084 fourcc = QT_FOURCC (data + 4);
3085 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3088 length = G_MAXUINT64;
3089 } else if (length == 1 && size >= 16) {
3090 /* this means we have an extended size, which is the 64 bit value of
3091 * the next 8 bytes */
3092 length = QT_UINT64 (data + 8);
3093 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3103 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3105 guint32 version = 0;
3106 GstClockTime duration = 0;
3108 if (!gst_byte_reader_get_uint32_be (br, &version))
3113 if (!gst_byte_reader_get_uint64_be (br, &duration))
3118 if (!gst_byte_reader_get_uint32_be (br, &dur))
3123 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3124 qtdemux->duration = duration;
3130 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3136 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3137 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3139 if (!stream->parsed_trex && qtdemux->moov_node) {
3141 GstByteReader trex_data;
3143 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3145 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3148 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3150 /* skip version/flags */
3151 if (!gst_byte_reader_skip (&trex_data, 4))
3153 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3155 if (id != stream->track_id)
3157 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3159 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3161 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3163 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3166 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3167 "duration %d, size %d, flags 0x%x", stream->track_id,
3170 stream->parsed_trex = TRUE;
3171 stream->def_sample_description_index = sdi;
3172 stream->def_sample_duration = dur;
3173 stream->def_sample_size = size;
3174 stream->def_sample_flags = flags;
3177 /* iterate all siblings */
3178 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3184 *ds_duration = stream->def_sample_duration;
3185 *ds_size = stream->def_sample_size;
3186 *ds_flags = stream->def_sample_flags;
3188 /* even then, above values are better than random ... */
3189 if (G_UNLIKELY (!stream->parsed_trex)) {
3190 GST_WARNING_OBJECT (qtdemux,
3191 "failed to find fragment defaults for stream %d", stream->track_id);
3198 /* This method should be called whenever a more accurate duration might
3199 * have been found. It will update all relevant variables if/where needed
3202 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3206 GstClockTime prevdur;
3208 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3210 if (movdur > qtdemux->duration) {
3211 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3212 GST_DEBUG_OBJECT (qtdemux,
3213 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3214 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3215 qtdemux->duration = movdur;
3216 GST_DEBUG_OBJECT (qtdemux,
3217 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3218 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3219 GST_TIME_ARGS (qtdemux->segment.stop));
3220 if (qtdemux->segment.duration == prevdur) {
3221 /* If the current segment has duration/stop identical to previous duration
3222 * update them also (because they were set at that point in time with
3223 * the wrong duration */
3224 /* We convert the value *from* the timescale version to avoid rounding errors */
3225 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3226 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3227 qtdemux->segment.duration = fixeddur;
3228 qtdemux->segment.stop = fixeddur;
3232 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3233 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3235 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3236 if (movdur > stream->duration) {
3237 GST_DEBUG_OBJECT (qtdemux,
3238 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3239 GST_TIME_ARGS (duration));
3240 stream->duration = movdur;
3241 /* internal duration tracking state has been updated above, so */
3242 /* preserve an open-ended dummy segment rather than repeatedly updating
3243 * it and spamming downstream accordingly with segment events */
3244 if (stream->dummy_segment &&
3245 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3246 /* Update all dummy values to new duration */
3247 stream->segments[0].stop_time = duration;
3248 stream->segments[0].duration = duration;
3249 stream->segments[0].media_stop = duration;
3251 /* let downstream know we possibly have a new stop time */
3252 if (stream->segment_index != -1) {
3255 if (qtdemux->segment.rate >= 0) {
3256 pos = stream->segment.start;
3258 pos = stream->segment.stop;
3261 gst_qtdemux_stream_update_segment (qtdemux, stream,
3262 stream->segment_index, pos, NULL, NULL);
3270 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3271 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3272 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3273 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3276 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3278 gint32 data_offset = 0;
3279 guint32 flags = 0, first_flags = 0, samples_count = 0;
3282 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3283 QtDemuxSample *sample;
3284 gboolean ismv = FALSE;
3285 gint64 initial_offset;
3287 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3288 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3289 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3290 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3292 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3293 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3297 /* presence of stss or not can't really tell us much,
3298 * and flags and so on tend to be marginally reliable in these files */
3299 if (stream->subtype == FOURCC_soun) {
3300 GST_DEBUG_OBJECT (qtdemux,
3301 "sound track in fragmented file; marking all keyframes");
3302 stream->all_keyframe = TRUE;
3305 if (!gst_byte_reader_skip (trun, 1) ||
3306 !gst_byte_reader_get_uint24_be (trun, &flags))
3309 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3312 if (flags & TR_DATA_OFFSET) {
3313 /* note this is really signed */
3314 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3316 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3317 /* default base offset = first byte of moof */
3318 if (*base_offset == -1) {
3319 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3320 *base_offset = moof_offset;
3322 *running_offset = *base_offset + data_offset;
3324 /* if no offset at all, that would mean data starts at moof start,
3325 * which is a bit wrong and is ismv crappy way, so compensate
3326 * assuming data is in mdat following moof */
3327 if (*base_offset == -1) {
3328 *base_offset = moof_offset + moof_length + 8;
3329 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3332 if (*running_offset == -1)
3333 *running_offset = *base_offset;
3336 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3338 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3339 data_offset, flags, samples_count);
3341 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3342 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3343 GST_DEBUG_OBJECT (qtdemux,
3344 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3345 flags ^= TR_FIRST_SAMPLE_FLAGS;
3347 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3349 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3353 /* FIXME ? spec says other bits should also be checked to determine
3354 * entry size (and prefix size for that matter) */
3356 dur_offset = size_offset = 0;
3357 if (flags & TR_SAMPLE_DURATION) {
3358 GST_LOG_OBJECT (qtdemux, "entry duration present");
3359 dur_offset = entry_size;
3362 if (flags & TR_SAMPLE_SIZE) {
3363 GST_LOG_OBJECT (qtdemux, "entry size present");
3364 size_offset = entry_size;
3367 if (flags & TR_SAMPLE_FLAGS) {
3368 GST_LOG_OBJECT (qtdemux, "entry flags present");
3369 flags_offset = entry_size;
3372 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3373 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3374 ct_offset = entry_size;
3378 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3380 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3382 if (stream->n_samples + samples_count >=
3383 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3386 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3387 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3388 (stream->n_samples + samples_count) *
3389 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3391 /* create a new array of samples if it's the first sample parsed */
3392 if (stream->n_samples == 0) {
3393 g_assert (stream->samples == NULL);
3394 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3395 /* or try to reallocate it with space enough to insert the new samples */
3397 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3398 stream->n_samples + samples_count);
3399 if (stream->samples == NULL)
3402 if (qtdemux->fragment_start != -1) {
3403 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3404 qtdemux->fragment_start = -1;
3406 if (stream->n_samples == 0) {
3407 if (decode_ts > 0) {
3408 timestamp = decode_ts;
3409 } else if (stream->pending_seek != NULL) {
3410 /* if we don't have a timestamp from a tfdt box, we'll use the one
3411 * from the mfra seek table */
3412 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3413 GST_TIME_ARGS (stream->pending_seek->ts));
3415 /* FIXME: this is not fully correct, the timestamp refers to the random
3416 * access sample refered to in the tfra entry, which may not necessarily
3417 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3418 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3423 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3424 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3425 GST_TIME_ARGS (gst_ts));
3427 /* subsequent fragments extend stream */
3429 stream->samples[stream->n_samples - 1].timestamp +
3430 stream->samples[stream->n_samples - 1].duration;
3432 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3433 * difference (1 sec.) between decode_ts and timestamp, prefer the
3435 if (has_tfdt && !qtdemux->upstream_format_is_time
3436 && ABSDIFF (decode_ts, timestamp) >
3437 MAX (stream->duration_last_moof / 2,
3438 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3439 GST_INFO_OBJECT (qtdemux,
3440 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3441 ") are significantly different (more than %" GST_TIME_FORMAT
3442 "), using decode_ts",
3443 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3444 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3445 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3446 MAX (stream->duration_last_moof / 2,
3447 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3448 timestamp = decode_ts;
3451 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3452 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3453 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3457 initial_offset = *running_offset;
3459 sample = stream->samples + stream->n_samples;
3460 for (i = 0; i < samples_count; i++) {
3461 guint32 dur, size, sflags, ct;
3463 /* first read sample data */
3464 if (flags & TR_SAMPLE_DURATION) {
3465 dur = QT_UINT32 (data + dur_offset);
3467 dur = d_sample_duration;
3469 if (flags & TR_SAMPLE_SIZE) {
3470 size = QT_UINT32 (data + size_offset);
3472 size = d_sample_size;
3474 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3476 sflags = first_flags;
3478 sflags = d_sample_flags;
3480 } else if (flags & TR_SAMPLE_FLAGS) {
3481 sflags = QT_UINT32 (data + flags_offset);
3483 sflags = d_sample_flags;
3485 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3486 ct = QT_UINT32 (data + ct_offset);
3492 /* fill the sample information */
3493 sample->offset = *running_offset;
3494 sample->pts_offset = ct;
3495 sample->size = size;
3496 sample->timestamp = timestamp;
3497 sample->duration = dur;
3498 /* sample-is-difference-sample */
3499 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3500 * now idea how it relates to bitfield other than massive LE/BE confusion */
3501 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3502 *running_offset += size;
3504 stream->duration_moof += dur;
3508 /* Update total duration if needed */
3509 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3511 /* Pre-emptively figure out size of mdat based on trun information.
3512 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3513 * size, else we will still be able to use this when dealing with gap'ed
3515 qtdemux->mdatleft = *running_offset - initial_offset;
3516 qtdemux->mdatoffset = initial_offset;
3517 qtdemux->mdatsize = qtdemux->mdatleft;
3519 stream->n_samples += samples_count;
3520 stream->n_samples_moof += samples_count;
3522 if (stream->pending_seek != NULL)
3523 stream->pending_seek = NULL;
3529 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3534 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3540 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3541 "be larger than %uMB (broken file?)", stream->n_samples,
3542 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3547 /* find stream with @id */
3548 static inline QtDemuxStream *
3549 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3551 QtDemuxStream *stream;
3555 if (G_UNLIKELY (!id)) {
3556 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3560 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3561 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3562 if (stream->track_id == id)
3565 if (qtdemux->mss_mode) {
3566 /* mss should have only 1 stream anyway */
3567 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3574 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3575 guint32 * fragment_number)
3577 if (!gst_byte_reader_skip (mfhd, 4))
3579 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3584 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3590 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3591 QtDemuxStream ** stream, guint32 * default_sample_duration,
3592 guint32 * default_sample_size, guint32 * default_sample_flags,
3593 gint64 * base_offset)
3596 guint32 track_id = 0;
3598 if (!gst_byte_reader_skip (tfhd, 1) ||
3599 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3602 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3605 *stream = qtdemux_find_stream (qtdemux, track_id);
3606 if (G_UNLIKELY (!*stream))
3607 goto unknown_stream;
3609 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3610 *base_offset = qtdemux->moof_offset;
3612 if (flags & TF_BASE_DATA_OFFSET)
3613 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3616 /* obtain stream defaults */
3617 qtdemux_parse_trex (qtdemux, *stream,
3618 default_sample_duration, default_sample_size, default_sample_flags);
3620 (*stream)->stsd_sample_description_id =
3621 (*stream)->def_sample_description_index - 1;
3623 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3624 guint32 sample_description_index;
3625 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3627 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3630 if (qtdemux->mss_mode) {
3631 /* mss has no stsd entry */
3632 (*stream)->stsd_sample_description_id = 0;
3635 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3636 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3639 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3640 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3643 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3644 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3651 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3656 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3662 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3663 guint64 * decode_time)
3665 guint32 version = 0;
3667 if (!gst_byte_reader_get_uint32_be (br, &version))
3672 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3675 guint32 dec_time = 0;
3676 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3678 *decode_time = dec_time;
3681 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3688 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3693 /* Returns a pointer to a GstStructure containing the properties of
3694 * the stream sample identified by @sample_index. The caller must unref
3695 * the returned object after use. Returns NULL if unsuccessful. */
3696 static GstStructure *
3697 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3698 QtDemuxStream * stream, guint sample_index)
3700 QtDemuxCencSampleSetInfo *info = NULL;
3702 g_return_val_if_fail (stream != NULL, NULL);
3703 g_return_val_if_fail (stream->protected, NULL);
3704 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3706 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3708 /* Currently, cenc properties for groups of samples are not supported, so
3709 * simply return a copy of the default sample properties */
3710 return gst_structure_copy (info->default_properties);
3713 /* Parses the sizes of sample auxiliary information contained within a stream,
3714 * as given in a saiz box. Returns array of sample_count guint8 size values,
3715 * or NULL on failure */
3717 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3718 GstByteReader * br, guint32 * sample_count)
3722 guint8 default_info_size;
3724 g_return_val_if_fail (qtdemux != NULL, NULL);
3725 g_return_val_if_fail (stream != NULL, NULL);
3726 g_return_val_if_fail (br != NULL, NULL);
3727 g_return_val_if_fail (sample_count != NULL, NULL);
3729 if (!gst_byte_reader_get_uint32_be (br, &flags))
3733 /* aux_info_type and aux_info_type_parameter are ignored */
3734 if (!gst_byte_reader_skip (br, 8))
3738 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3740 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3742 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3744 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3747 if (default_info_size == 0) {
3748 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3752 info_sizes = g_new (guint8, *sample_count);
3753 memset (info_sizes, default_info_size, *sample_count);
3759 /* Parses the offset of sample auxiliary information contained within a stream,
3760 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3762 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3763 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3768 guint32 aux_info_type = 0;
3769 guint32 aux_info_type_parameter = 0;
3770 guint32 entry_count;
3773 const guint8 *aux_info_type_data = NULL;
3775 g_return_val_if_fail (qtdemux != NULL, FALSE);
3776 g_return_val_if_fail (stream != NULL, FALSE);
3777 g_return_val_if_fail (br != NULL, FALSE);
3778 g_return_val_if_fail (offset != NULL, FALSE);
3780 if (!gst_byte_reader_get_uint8 (br, &version))
3783 if (!gst_byte_reader_get_uint24_be (br, &flags))
3788 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3790 aux_info_type = QT_FOURCC (aux_info_type_data);
3792 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3794 } else if (stream->protected) {
3795 aux_info_type = stream->protection_scheme_type;
3797 aux_info_type = CUR_STREAM (stream)->fourcc;
3801 *info_type = aux_info_type;
3802 if (info_type_parameter)
3803 *info_type_parameter = aux_info_type_parameter;
3805 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3806 "aux_info_type_parameter: %#06x",
3807 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3809 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3812 if (entry_count != 1) {
3813 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3818 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3820 *offset = (guint64) off_32;
3822 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3827 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3832 qtdemux_gst_structure_free (GstStructure * gststructure)
3835 gst_structure_free (gststructure);
3839 /* Parses auxiliary information relating to samples protected using Common
3840 * Encryption (cenc); the format of this information is defined in
3841 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3843 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3844 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3846 QtDemuxCencSampleSetInfo *ss_info = NULL;
3849 GPtrArray *old_crypto_info = NULL;
3850 guint old_entries = 0;
3852 g_return_val_if_fail (qtdemux != NULL, FALSE);
3853 g_return_val_if_fail (stream != NULL, FALSE);
3854 g_return_val_if_fail (br != NULL, FALSE);
3855 g_return_val_if_fail (stream->protected, FALSE);
3856 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3858 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3860 if (ss_info->crypto_info) {
3861 old_crypto_info = ss_info->crypto_info;
3862 /* Count number of non-null entries remaining at the tail end */
3863 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3864 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3870 ss_info->crypto_info =
3871 g_ptr_array_new_full (sample_count + old_entries,
3872 (GDestroyNotify) qtdemux_gst_structure_free);
3874 /* We preserve old entries because we parse the next moof in advance
3875 * of consuming all samples from the previous moof, and otherwise
3876 * we'd discard the corresponding crypto info for the samples
3877 * from the previous fragment. */
3879 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3881 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3882 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3884 g_ptr_array_index (old_crypto_info, i) = NULL;
3888 if (old_crypto_info) {
3889 /* Everything now belongs to the new array */
3890 g_ptr_array_free (old_crypto_info, TRUE);
3893 for (i = 0; i < sample_count; ++i) {
3894 GstStructure *properties;
3895 guint16 n_subsamples = 0;
3900 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3901 if (properties == NULL) {
3902 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3905 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3906 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3907 gst_structure_free (properties);
3910 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3911 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3912 gst_structure_free (properties);
3915 buf = gst_buffer_new_wrapped (data, iv_size);
3916 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3917 gst_buffer_unref (buf);
3918 size = info_sizes[i];
3919 if (size > iv_size) {
3920 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3921 || !(n_subsamples > 0)) {
3922 gst_structure_free (properties);
3923 GST_ERROR_OBJECT (qtdemux,
3924 "failed to get subsample count for sample %u", i);
3927 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3928 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3929 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3931 gst_structure_free (properties);
3934 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3936 gst_structure_free (properties);
3939 gst_structure_set (properties,
3940 "subsample_count", G_TYPE_UINT, n_subsamples,
3941 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3942 gst_buffer_unref (buf);
3944 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3946 g_ptr_array_add (ss_info->crypto_info, properties);
3951 /* Converts a UUID in raw byte form to a string representation, as defined in
3952 * RFC 4122. The caller takes ownership of the returned string and is
3953 * responsible for freeing it after use. */
3955 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3957 const guint8 *uuid = (const guint8 *) uuid_bytes;
3959 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3960 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3961 uuid[0], uuid[1], uuid[2], uuid[3],
3962 uuid[4], uuid[5], uuid[6], uuid[7],
3963 uuid[8], uuid[9], uuid[10], uuid[11],
3964 uuid[12], uuid[13], uuid[14], uuid[15]);
3967 /* Parses a Protection System Specific Header box (pssh), as defined in the
3968 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3969 * information needed by a specific content protection system in order to
3970 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3973 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3975 gchar *sysid_string;
3976 guint32 pssh_size = QT_UINT32 (node->data);
3977 GstBuffer *pssh = NULL;
3978 GstEvent *event = NULL;
3979 guint32 parent_box_type;
3982 if (G_UNLIKELY (pssh_size < 32U)) {
3983 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3988 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3990 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3992 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3993 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3994 gst_buffer_get_size (pssh));
3996 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3998 /* Push an event containing the pssh box onto the queues of all streams. */
3999 event = gst_event_new_protection (sysid_string, pssh,
4000 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4001 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4002 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4003 GST_TRACE_OBJECT (qtdemux,
4004 "adding protection event for stream %s and system %s",
4005 stream->stream_id, sysid_string);
4006 g_queue_push_tail (&stream->protection_scheme_event_queue,
4007 gst_event_ref (event));
4009 g_free (sysid_string);
4010 gst_event_unref (event);
4011 gst_buffer_unref (pssh);
4016 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4017 guint64 moof_offset, QtDemuxStream * stream)
4019 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4021 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4022 GNode *saiz_node, *saio_node, *pssh_node;
4023 GstByteReader saiz_data, saio_data;
4024 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4025 gint64 base_offset, running_offset;
4027 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4029 /* NOTE @stream ignored */
4031 moof_node = g_node_new ((guint8 *) buffer);
4032 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4033 qtdemux_node_dump (qtdemux, moof_node);
4035 /* Get fragment number from mfhd and check it's valid */
4037 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4038 if (mfhd_node == NULL)
4040 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4042 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4044 /* unknown base_offset to start with */
4045 base_offset = running_offset = -1;
4046 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4048 guint64 decode_time = 0;
4050 /* Fragment Header node */
4052 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4056 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4057 &ds_size, &ds_flags, &base_offset))
4060 /* The following code assumes at most a single set of sample auxiliary
4061 * data in the fragment (consisting of a saiz box and a corresponding saio
4062 * box); in theory, however, there could be multiple sets of sample
4063 * auxiliary data in a fragment. */
4065 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4068 guint32 info_type = 0;
4070 guint32 info_type_parameter = 0;
4072 g_free (qtdemux->cenc_aux_info_sizes);
4074 qtdemux->cenc_aux_info_sizes =
4075 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4076 &qtdemux->cenc_aux_sample_count);
4077 if (qtdemux->cenc_aux_info_sizes == NULL) {
4078 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4082 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4085 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4086 g_free (qtdemux->cenc_aux_info_sizes);
4087 qtdemux->cenc_aux_info_sizes = NULL;
4091 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4092 &info_type, &info_type_parameter, &offset))) {
4093 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4094 g_free (qtdemux->cenc_aux_info_sizes);
4095 qtdemux->cenc_aux_info_sizes = NULL;
4098 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4099 offset += (guint64) (base_offset - qtdemux->moof_offset);
4100 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4102 if (offset > length) {
4103 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4104 qtdemux->cenc_aux_info_offset = offset;
4106 gst_byte_reader_init (&br, buffer + offset, length - offset);
4107 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4108 qtdemux->cenc_aux_info_sizes,
4109 qtdemux->cenc_aux_sample_count)) {
4110 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4111 g_free (qtdemux->cenc_aux_info_sizes);
4112 qtdemux->cenc_aux_info_sizes = NULL;
4120 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4123 /* We'll use decode_time to interpolate timestamps
4124 * in case the input timestamps are missing */
4125 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4127 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4128 " (%" GST_TIME_FORMAT ")", decode_time,
4129 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4130 decode_time) : GST_CLOCK_TIME_NONE));
4132 /* Discard the fragment buffer timestamp info to avoid using it.
4133 * Rely on tfdt instead as it is more accurate than the timestamp
4134 * that is fetched from a manifest/playlist and is usually
4136 qtdemux->fragment_start = -1;
4139 if (G_UNLIKELY (!stream)) {
4140 /* we lost track of offset, we'll need to regain it,
4141 * but can delay complaining until later or avoid doing so altogether */
4145 if (G_UNLIKELY (base_offset < -1))
4148 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4150 if (!qtdemux->pullbased) {
4151 /* Sample tables can grow enough to be problematic if the system memory
4152 * is very low (e.g. embedded devices) and the videos very long
4153 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4154 * Fortunately, we can easily discard them for each new fragment when
4155 * we know qtdemux will not receive seeks outside of the current fragment.
4156 * adaptivedemux honors this assumption.
4157 * This optimization is also useful for applications that use qtdemux as
4158 * a push-based simple demuxer, like Media Source Extensions. */
4159 gst_qtdemux_stream_flush_samples_data (stream);
4162 /* initialise moof sample data */
4163 stream->n_samples_moof = 0;
4164 stream->duration_last_moof = stream->duration_moof;
4165 stream->duration_moof = 0;
4167 /* Track Run node */
4169 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4172 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4173 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4174 &running_offset, decode_time, (tfdt_node != NULL));
4175 /* iterate all siblings */
4176 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4180 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4182 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4183 guint32 box_length = QT_UINT32 (uuid_buffer);
4185 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4188 /* if no new base_offset provided for next traf,
4189 * base is end of current traf */
4190 base_offset = running_offset;
4191 running_offset = -1;
4193 if (stream->n_samples_moof && stream->duration_moof)
4194 stream->new_caps = TRUE;
4197 /* iterate all siblings */
4198 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4201 /* parse any protection system info */
4202 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4204 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4205 qtdemux_parse_pssh (qtdemux, pssh_node);
4206 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4209 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4210 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4212 /* Unless the user has explictly requested another seek, perform an
4213 * internal seek to the time specified in the tfdt.
4215 * This way if the user opens a file where the first tfdt is 1 hour
4216 * into the presentation, they will not have to wait 1 hour for run
4217 * time to catch up and actual playback to start. */
4220 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4221 "performing an internal seek to %" GST_TIME_FORMAT,
4222 GST_TIME_ARGS (min_dts));
4224 qtdemux->segment.start = min_dts;
4225 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4227 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4228 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4229 stream->time_position = min_dts;
4232 /* Before this code was run a segment was already sent when the moov was
4233 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4234 * be emitted after a moov, and we can emit a second segment anyway for
4235 * special cases like this. */
4236 qtdemux->need_segment = TRUE;
4239 qtdemux->first_moof_already_parsed = TRUE;
4241 g_node_destroy (moof_node);
4246 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4251 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4256 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4261 g_node_destroy (moof_node);
4262 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4263 (_("This file is corrupt and cannot be played.")), (NULL));
4269 /* might be used if some day we actually use mfra & co
4270 * for random access to fragments,
4271 * but that will require quite some modifications and much less relying
4272 * on a sample array */
4276 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4278 QtDemuxStream *stream;
4279 guint32 ver_flags, track_id, len, num_entries, i;
4280 guint value_size, traf_size, trun_size, sample_size;
4281 guint64 time = 0, moof_offset = 0;
4283 GstBuffer *buf = NULL;
4288 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4290 if (!gst_byte_reader_skip (&tfra, 8))
4293 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4296 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4297 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4298 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4301 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4303 stream = qtdemux_find_stream (qtdemux, track_id);
4305 goto unknown_trackid;
4307 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4308 sample_size = (len & 3) + 1;
4309 trun_size = ((len & 12) >> 2) + 1;
4310 traf_size = ((len & 48) >> 4) + 1;
4312 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4313 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4315 if (num_entries == 0)
4318 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4319 value_size + value_size + traf_size + trun_size + sample_size))
4322 g_free (stream->ra_entries);
4323 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4324 stream->n_ra_entries = num_entries;
4326 for (i = 0; i < num_entries; i++) {
4327 qt_atom_parser_get_offset (&tfra, value_size, &time);
4328 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4329 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4330 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4331 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4333 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4335 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4336 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4338 stream->ra_entries[i].ts = time;
4339 stream->ra_entries[i].moof_offset = moof_offset;
4341 /* don't want to go through the entire file and read all moofs at startup */
4343 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4344 if (ret != GST_FLOW_OK)
4346 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4347 moof_offset, stream);
4348 gst_buffer_unref (buf);
4352 check_update_duration (qtdemux, time);
4359 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4364 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4369 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4375 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4377 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4378 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4379 GstBuffer *mfro = NULL, *mfra = NULL;
4381 gboolean ret = FALSE;
4382 GNode *mfra_node, *tfra_node;
4383 guint64 mfra_offset = 0;
4384 guint32 fourcc, mfra_size;
4387 /* query upstream size in bytes */
4388 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4389 goto size_query_failed;
4391 /* mfro box should be at the very end of the file */
4392 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4393 if (flow != GST_FLOW_OK)
4396 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4398 fourcc = QT_FOURCC (mfro_map.data + 4);
4399 if (fourcc != FOURCC_mfro)
4402 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4403 if (mfro_map.size < 16)
4404 goto invalid_mfro_size;
4406 mfra_size = QT_UINT32 (mfro_map.data + 12);
4407 if (mfra_size >= len)
4408 goto invalid_mfra_size;
4410 mfra_offset = len - mfra_size;
4412 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4413 mfra_offset, mfra_size);
4415 /* now get and parse mfra box */
4416 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4417 if (flow != GST_FLOW_OK)
4420 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4422 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4423 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4425 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4428 qtdemux_parse_tfra (qtdemux, tfra_node);
4429 /* iterate all siblings */
4430 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4432 g_node_destroy (mfra_node);
4434 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4440 if (mfro_map.memory != NULL)
4441 gst_buffer_unmap (mfro, &mfro_map);
4442 gst_buffer_unref (mfro);
4445 if (mfra_map.memory != NULL)
4446 gst_buffer_unmap (mfra, &mfra_map);
4447 gst_buffer_unref (mfra);
4454 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4459 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4464 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4469 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4475 add_offset (guint64 offset, guint64 advance)
4477 /* Avoid 64-bit overflow by clamping */
4478 if (offset > G_MAXUINT64 - advance)
4480 return offset + advance;
4483 static GstFlowReturn
4484 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4488 GstBuffer *buf = NULL;
4489 GstFlowReturn ret = GST_FLOW_OK;
4490 guint64 cur_offset = qtdemux->offset;
4493 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4494 if (G_UNLIKELY (ret != GST_FLOW_OK))
4496 gst_buffer_map (buf, &map, GST_MAP_READ);
4497 if (G_LIKELY (map.size >= 8))
4498 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4499 gst_buffer_unmap (buf, &map);
4500 gst_buffer_unref (buf);
4502 /* maybe we already got most we needed, so only consider this eof */
4503 if (G_UNLIKELY (length == 0)) {
4504 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4505 (_("Invalid atom size.")),
4506 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4507 GST_FOURCC_ARGS (fourcc)));
4514 /* record for later parsing when needed */
4515 if (!qtdemux->moof_offset) {
4516 qtdemux->moof_offset = qtdemux->offset;
4518 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4521 qtdemux->offset += length; /* skip moof and keep going */
4523 if (qtdemux->got_moov) {
4524 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4536 GST_LOG_OBJECT (qtdemux,
4537 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4538 GST_FOURCC_ARGS (fourcc), cur_offset);
4539 qtdemux->offset = add_offset (qtdemux->offset, length);
4544 GstBuffer *moov = NULL;
4546 if (qtdemux->got_moov) {
4547 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4548 qtdemux->offset = add_offset (qtdemux->offset, length);
4552 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4553 if (ret != GST_FLOW_OK)
4555 gst_buffer_map (moov, &map, GST_MAP_READ);
4557 if (length != map.size) {
4558 /* Some files have a 'moov' atom at the end of the file which contains
4559 * a terminal 'free' atom where the body of the atom is missing.
4560 * Check for, and permit, this special case.
4562 if (map.size >= 8) {
4563 guint8 *final_data = map.data + (map.size - 8);
4564 guint32 final_length = QT_UINT32 (final_data);
4565 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4567 if (final_fourcc == FOURCC_free
4568 && map.size + final_length - 8 == length) {
4569 /* Ok, we've found that special case. Allocate a new buffer with
4570 * that free atom actually present. */
4571 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4572 gst_buffer_fill (newmoov, 0, map.data, map.size);
4573 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4574 gst_buffer_unmap (moov, &map);
4575 gst_buffer_unref (moov);
4577 gst_buffer_map (moov, &map, GST_MAP_READ);
4582 if (length != map.size) {
4583 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4584 (_("This file is incomplete and cannot be played.")),
4585 ("We got less than expected (received %" G_GSIZE_FORMAT
4586 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4587 (guint) length, cur_offset));
4588 gst_buffer_unmap (moov, &map);
4589 gst_buffer_unref (moov);
4590 ret = GST_FLOW_ERROR;
4593 qtdemux->offset += length;
4595 qtdemux_parse_moov (qtdemux, map.data, length);
4596 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4598 qtdemux_parse_tree (qtdemux);
4599 if (qtdemux->moov_node_compressed) {
4600 g_node_destroy (qtdemux->moov_node_compressed);
4601 g_free (qtdemux->moov_node->data);
4603 qtdemux->moov_node_compressed = NULL;
4604 g_node_destroy (qtdemux->moov_node);
4605 qtdemux->moov_node = NULL;
4606 gst_buffer_unmap (moov, &map);
4607 gst_buffer_unref (moov);
4608 qtdemux->got_moov = TRUE;
4614 GstBuffer *ftyp = NULL;
4616 /* extract major brand; might come in handy for ISO vs QT issues */
4617 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4618 if (ret != GST_FLOW_OK)
4620 qtdemux->offset += length;
4621 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4622 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4623 gst_buffer_unmap (ftyp, &map);
4624 gst_buffer_unref (ftyp);
4629 GstBuffer *uuid = NULL;
4631 /* uuid are extension atoms */
4632 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4633 if (ret != GST_FLOW_OK)
4635 qtdemux->offset += length;
4636 gst_buffer_map (uuid, &map, GST_MAP_READ);
4637 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4638 gst_buffer_unmap (uuid, &map);
4639 gst_buffer_unref (uuid);
4644 GstBuffer *sidx = NULL;
4645 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4646 if (ret != GST_FLOW_OK)
4648 qtdemux->offset += length;
4649 gst_buffer_map (sidx, &map, GST_MAP_READ);
4650 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4651 gst_buffer_unmap (sidx, &map);
4652 gst_buffer_unref (sidx);
4657 GstBuffer *unknown = NULL;
4659 GST_LOG_OBJECT (qtdemux,
4660 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4661 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4663 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4664 if (ret != GST_FLOW_OK)
4666 gst_buffer_map (unknown, &map, GST_MAP_READ);
4667 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4668 gst_buffer_unmap (unknown, &map);
4669 gst_buffer_unref (unknown);
4670 qtdemux->offset += length;
4676 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4677 /* digested all data, show what we have */
4678 qtdemux_prepare_streams (qtdemux);
4679 QTDEMUX_EXPOSE_LOCK (qtdemux);
4680 ret = qtdemux_expose_streams (qtdemux);
4681 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4683 qtdemux->state = QTDEMUX_STATE_MOVIE;
4684 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4691 /* Seeks to the previous keyframe of the indexed stream and
4692 * aligns other streams with respect to the keyframe timestamp
4693 * of indexed stream. Only called in case of Reverse Playback
4695 static GstFlowReturn
4696 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4698 guint32 seg_idx = 0, k_index = 0;
4699 guint32 ref_seg_idx, ref_k_index;
4700 GstClockTime k_pos = 0, last_stop = 0;
4701 QtDemuxSegment *seg = NULL;
4702 QtDemuxStream *ref_str = NULL;
4703 guint64 seg_media_start_mov; /* segment media start time in mov format */
4707 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4708 * and finally align all the other streams on that timestamp with their
4709 * respective keyframes */
4710 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4711 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4713 /* No candidate yet, take the first stream */
4719 /* So that stream has a segment, we prefer video streams */
4720 if (str->subtype == FOURCC_vide) {
4726 if (G_UNLIKELY (!ref_str)) {
4727 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4731 if (G_UNLIKELY (!ref_str->from_sample)) {
4732 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4736 /* So that stream has been playing from from_sample to to_sample. We will
4737 * get the timestamp of the previous sample and search for a keyframe before
4738 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4739 if (ref_str->subtype == FOURCC_vide) {
4740 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4741 ref_str->from_sample - 1, FALSE);
4743 if (ref_str->from_sample >= 10)
4744 k_index = ref_str->from_sample - 10;
4750 ref_str->samples[k_index].timestamp +
4751 ref_str->samples[k_index].pts_offset;
4753 /* get current segment for that stream */
4754 seg = &ref_str->segments[ref_str->segment_index];
4755 /* Use segment start in original timescale for comparisons */
4756 seg_media_start_mov = seg->trak_media_start;
4758 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4759 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4760 k_index, target_ts, seg_media_start_mov,
4761 GST_TIME_ARGS (seg->media_start));
4763 /* Crawl back through segments to find the one containing this I frame */
4764 while (target_ts < seg_media_start_mov) {
4765 GST_DEBUG_OBJECT (qtdemux,
4766 "keyframe position (sample %u) is out of segment %u " " target %"
4767 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4768 ref_str->segment_index, target_ts, seg_media_start_mov);
4770 if (G_UNLIKELY (!ref_str->segment_index)) {
4771 /* Reached first segment, let's consider it's EOS */
4774 ref_str->segment_index--;
4775 seg = &ref_str->segments[ref_str->segment_index];
4776 /* Use segment start in original timescale for comparisons */
4777 seg_media_start_mov = seg->trak_media_start;
4779 /* Calculate time position of the keyframe and where we should stop */
4781 QTSTREAMTIME_TO_GSTTIME (ref_str,
4782 target_ts - seg->trak_media_start) + seg->time;
4784 QTSTREAMTIME_TO_GSTTIME (ref_str,
4785 ref_str->samples[ref_str->from_sample].timestamp -
4786 seg->trak_media_start) + seg->time;
4788 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4789 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4790 k_index, GST_TIME_ARGS (k_pos));
4792 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4793 qtdemux->segment.position = last_stop;
4794 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4795 GST_TIME_ARGS (last_stop));
4797 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4798 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4802 ref_seg_idx = ref_str->segment_index;
4803 ref_k_index = k_index;
4805 /* Align them all on this */
4806 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4808 GstClockTime seg_time = 0;
4809 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4811 /* aligning reference stream again might lead to backing up to yet another
4812 * keyframe (due to timestamp rounding issues),
4813 * potentially putting more load on downstream; so let's try to avoid */
4814 if (str == ref_str) {
4815 seg_idx = ref_seg_idx;
4816 seg = &str->segments[seg_idx];
4817 k_index = ref_k_index;
4818 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4819 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4821 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4822 GST_DEBUG_OBJECT (qtdemux,
4823 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4824 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4826 /* get segment and time in the segment */
4827 seg = &str->segments[seg_idx];
4828 seg_time = k_pos - seg->time;
4830 /* get the media time in the segment.
4831 * No adjustment for empty "filler" segments */
4832 if (seg->media_start != GST_CLOCK_TIME_NONE)
4833 seg_time += seg->media_start;
4835 /* get the index of the sample with media time */
4836 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4837 GST_DEBUG_OBJECT (qtdemux,
4838 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4839 GST_TIME_ARGS (seg_time), index);
4841 /* find previous keyframe */
4842 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4845 /* Remember until where we want to go */
4846 str->to_sample = str->from_sample - 1;
4847 /* Define our time position */
4849 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4850 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4851 if (seg->media_start != GST_CLOCK_TIME_NONE)
4852 str->time_position -= seg->media_start;
4854 /* Now seek back in time */
4855 gst_qtdemux_move_stream (qtdemux, str, k_index);
4856 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4857 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4858 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4864 return GST_FLOW_EOS;
4868 * Gets the current qt segment start, stop and position for the
4869 * given time offset. This is used in update_segment()
4872 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4873 QtDemuxStream * stream, GstClockTime offset,
4874 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4876 GstClockTime seg_time;
4877 GstClockTime start, stop, time;
4878 QtDemuxSegment *segment;
4880 segment = &stream->segments[stream->segment_index];
4882 /* get time in this segment */
4883 seg_time = (offset - segment->time) * segment->rate;
4885 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4886 GST_TIME_ARGS (seg_time));
4888 if (G_UNLIKELY (seg_time > segment->duration)) {
4889 GST_LOG_OBJECT (stream->pad,
4890 "seg_time > segment->duration %" GST_TIME_FORMAT,
4891 GST_TIME_ARGS (segment->duration));
4892 seg_time = segment->duration;
4895 /* qtdemux->segment.stop is in outside-time-realm, whereas
4896 * segment->media_stop is in track-time-realm.
4898 * In order to compare the two, we need to bring segment.stop
4899 * into the track-time-realm
4901 * FIXME - does this comment still hold? Don't see any conversion here */
4903 stop = qtdemux->segment.stop;
4904 if (stop == GST_CLOCK_TIME_NONE)
4905 stop = qtdemux->segment.duration;
4906 if (stop == GST_CLOCK_TIME_NONE)
4907 stop = segment->media_stop;
4910 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4912 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4913 start = segment->time + seg_time;
4915 stop = start - seg_time + segment->duration;
4916 } else if (qtdemux->segment.rate >= 0) {
4917 start = MIN (segment->media_start + seg_time, stop);
4920 if (segment->media_start >= qtdemux->segment.start) {
4921 time = segment->time;
4923 time = segment->time + (qtdemux->segment.start - segment->media_start);
4926 start = MAX (segment->media_start, qtdemux->segment.start);
4927 stop = MIN (segment->media_start + seg_time, stop);
4936 * Updates the qt segment used for the stream and pushes a new segment event
4937 * downstream on this stream's pad.
4940 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4941 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4942 GstClockTime * _stop)
4944 QtDemuxSegment *segment;
4945 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4949 /* update the current segment */
4950 stream->segment_index = seg_idx;
4952 /* get the segment */
4953 segment = &stream->segments[seg_idx];
4955 if (G_UNLIKELY (offset < segment->time)) {
4956 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4957 GST_TIME_ARGS (segment->time));
4961 /* segment lies beyond total indicated duration */
4962 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4963 segment->time > qtdemux->segment.duration)) {
4964 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4965 " < segment->time %" GST_TIME_FORMAT,
4966 GST_TIME_ARGS (qtdemux->segment.duration),
4967 GST_TIME_ARGS (segment->time));
4971 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4972 &start, &stop, &time);
4974 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4975 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4976 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4978 /* combine global rate with that of the segment */
4979 rate = segment->rate * qtdemux->segment.rate;
4981 /* Copy flags from main segment */
4982 stream->segment.flags = qtdemux->segment.flags;
4984 /* update the segment values used for clipping */
4985 stream->segment.offset = qtdemux->segment.offset;
4986 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4987 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4988 stream->segment.rate = rate;
4989 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4990 stream->cslg_shift);
4991 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4992 stream->cslg_shift);
4993 stream->segment.time = time;
4994 stream->segment.position = stream->segment.start;
4996 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4999 /* now prepare and send the segment */
5001 event = gst_event_new_segment (&stream->segment);
5002 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5003 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5005 gst_pad_push_event (stream->pad, event);
5006 /* assume we can send more data now */
5007 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5008 /* clear to send tags on this pad now */
5009 gst_qtdemux_push_tags (qtdemux, stream);
5020 /* activate the given segment number @seg_idx of @stream at time @offset.
5021 * @offset is an absolute global position over all the segments.
5023 * This will push out a NEWSEGMENT event with the right values and
5024 * position the stream index to the first decodable sample before
5028 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5029 guint32 seg_idx, GstClockTime offset)
5031 QtDemuxSegment *segment;
5032 guint32 index, kf_index;
5033 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5035 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5036 seg_idx, GST_TIME_ARGS (offset));
5038 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5042 segment = &stream->segments[stream->segment_index];
5044 /* in the fragmented case, we pick a fragment that starts before our
5045 * desired position and rely on downstream to wait for a keyframe
5046 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5047 * tfra entries tells us which trun/sample the key unit is in, but we don't
5048 * make use of this additional information at the moment) */
5049 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5050 stream->to_sample = G_MAXUINT32;
5053 /* well, it will be taken care of below */
5054 qtdemux->fragmented_seek_pending = FALSE;
5055 /* FIXME ideally the do_fragmented_seek can be done right here,
5056 * rather than at loop level
5057 * (which might even allow handling edit lists in a fragmented file) */
5060 /* We don't need to look for a sample in push-based */
5061 if (!qtdemux->pullbased)
5064 /* and move to the keyframe before the indicated media time of the
5066 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5067 if (qtdemux->segment.rate >= 0) {
5068 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5069 stream->to_sample = G_MAXUINT32;
5070 GST_DEBUG_OBJECT (stream->pad,
5071 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5072 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5073 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5075 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5076 stream->to_sample = index;
5077 GST_DEBUG_OBJECT (stream->pad,
5078 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5079 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5080 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5083 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5084 "this is an empty segment");
5088 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5089 * encountered an error and printed a message so we return appropriately */
5093 /* we're at the right spot */
5094 if (index == stream->sample_index) {
5095 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5099 /* find keyframe of the target index */
5100 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5103 /* indent does stupid stuff with stream->samples[].timestamp */
5105 /* if we move forwards, we don't have to go back to the previous
5106 * keyframe since we already sent that. We can also just jump to
5107 * the keyframe right before the target index if there is one. */
5108 if (index > stream->sample_index) {
5109 /* moving forwards check if we move past a keyframe */
5110 if (kf_index > stream->sample_index) {
5111 GST_DEBUG_OBJECT (stream->pad,
5112 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5113 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5114 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5115 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5117 GST_DEBUG_OBJECT (stream->pad,
5118 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5119 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5120 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5123 GST_DEBUG_OBJECT (stream->pad,
5124 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5125 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5126 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5127 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5135 /* prepare to get the current sample of @stream, getting essential values.
5137 * This function will also prepare and send the segment when needed.
5139 * Return FALSE if the stream is EOS.
5144 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5145 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5146 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5147 gboolean * keyframe)
5149 QtDemuxSample *sample;
5150 GstClockTime time_position;
5153 g_return_val_if_fail (stream != NULL, FALSE);
5155 time_position = stream->time_position;
5156 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5159 seg_idx = stream->segment_index;
5160 if (G_UNLIKELY (seg_idx == -1)) {
5161 /* find segment corresponding to time_position if we are looking
5163 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5166 /* different segment, activate it, sample_index will be set. */
5167 if (G_UNLIKELY (stream->segment_index != seg_idx))
5168 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5170 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
5172 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5174 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5175 " prepare empty sample");
5178 *pts = *dts = time_position;
5179 *duration = seg->duration - (time_position - seg->time);
5186 if (stream->sample_index == -1)
5187 stream->sample_index = 0;
5189 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5190 stream->sample_index, stream->n_samples);
5192 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5193 if (!qtdemux->fragmented)
5196 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5200 GST_OBJECT_LOCK (qtdemux);
5201 flow = qtdemux_add_fragmented_samples (qtdemux);
5202 GST_OBJECT_UNLOCK (qtdemux);
5204 if (flow != GST_FLOW_OK)
5207 while (stream->sample_index >= stream->n_samples);
5210 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5211 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5212 stream->sample_index);
5216 /* now get the info for the sample we're at */
5217 sample = &stream->samples[stream->sample_index];
5219 *dts = QTSAMPLE_DTS (stream, sample);
5220 *pts = QTSAMPLE_PTS (stream, sample);
5221 *offset = sample->offset;
5222 *size = sample->size;
5223 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5224 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5231 stream->time_position = GST_CLOCK_TIME_NONE;
5236 /* move to the next sample in @stream.
5238 * Moves to the next segment when needed.
5241 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5243 QtDemuxSample *sample;
5244 QtDemuxSegment *segment;
5246 /* get current segment */
5247 segment = &stream->segments[stream->segment_index];
5249 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5250 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5254 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5255 /* Mark the stream as EOS */
5256 GST_DEBUG_OBJECT (qtdemux,
5257 "reached max allowed sample %u, mark EOS", stream->to_sample);
5258 stream->time_position = GST_CLOCK_TIME_NONE;
5262 /* move to next sample */
5263 stream->sample_index++;
5264 stream->offset_in_sample = 0;
5266 /* reached the last sample, we need the next segment */
5267 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5270 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5271 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5272 stream->sample_index);
5276 /* get next sample */
5277 sample = &stream->samples[stream->sample_index];
5279 /* see if we are past the segment */
5280 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5283 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5284 /* inside the segment, update time_position, looks very familiar to
5285 * GStreamer segments, doesn't it? */
5286 stream->time_position =
5287 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5289 /* not yet in segment, time does not yet increment. This means
5290 * that we are still prerolling keyframes to the decoder so it can
5291 * decode the first sample of the segment. */
5292 stream->time_position = segment->time;
5296 /* move to the next segment */
5299 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5301 if (stream->segment_index == stream->n_segments - 1) {
5302 /* are we at the end of the last segment, we're EOS */
5303 stream->time_position = GST_CLOCK_TIME_NONE;
5305 /* else we're only at the end of the current segment */
5306 stream->time_position = segment->stop_time;
5308 /* make sure we select a new segment */
5310 /* accumulate previous segments */
5311 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5312 stream->accumulated_base +=
5313 (stream->segment.stop -
5314 stream->segment.start) / ABS (stream->segment.rate);
5316 stream->segment_index = -1;
5321 gst_qtdemux_sync_streams (GstQTDemux * demux)
5325 if (QTDEMUX_N_STREAMS (demux) <= 1)
5328 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5329 QtDemuxStream *stream;
5330 GstClockTime end_time;
5332 stream = QTDEMUX_NTH_STREAM (demux, i);
5337 /* TODO advance time on subtitle streams here, if any some day */
5339 /* some clips/trailers may have unbalanced streams at the end,
5340 * so send EOS on shorter stream to prevent stalling others */
5342 /* do not mess with EOS if SEGMENT seeking */
5343 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5346 if (demux->pullbased) {
5347 /* loop mode is sample time based */
5348 if (!STREAM_IS_EOS (stream))
5351 /* push mode is byte position based */
5352 if (stream->n_samples &&
5353 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5357 if (stream->sent_eos)
5360 /* only act if some gap */
5361 end_time = stream->segments[stream->n_segments - 1].stop_time;
5362 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5363 ", stream end: %" GST_TIME_FORMAT,
5364 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5365 if (GST_CLOCK_TIME_IS_VALID (end_time)
5366 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5369 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5370 GST_PAD_NAME (stream->pad));
5371 stream->sent_eos = TRUE;
5372 event = gst_event_new_eos ();
5373 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5374 gst_event_set_seqnum (event, demux->segment_seqnum);
5375 gst_pad_push_event (stream->pad, event);
5380 /* EOS and NOT_LINKED need to be combined. This means that we return:
5382 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5383 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5385 static GstFlowReturn
5386 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5389 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5392 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5395 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5397 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5401 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5402 * completely clipped
5404 * Should be used only with raw buffers */
5406 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5409 guint64 start, stop, cstart, cstop, diff;
5410 GstClockTime pts, duration;
5412 gint num_rate, denom_rate;
5417 osize = size = gst_buffer_get_size (buf);
5420 /* depending on the type, setup the clip parameters */
5421 if (stream->subtype == FOURCC_soun) {
5422 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5423 num_rate = GST_SECOND;
5424 denom_rate = (gint) CUR_STREAM (stream)->rate;
5426 } else if (stream->subtype == FOURCC_vide) {
5428 num_rate = CUR_STREAM (stream)->fps_n;
5429 denom_rate = CUR_STREAM (stream)->fps_d;
5434 if (frame_size <= 0)
5435 goto bad_frame_size;
5437 /* we can only clip if we have a valid pts */
5438 pts = GST_BUFFER_PTS (buf);
5439 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5442 duration = GST_BUFFER_DURATION (buf);
5444 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5446 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5450 stop = start + duration;
5452 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5453 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5456 /* see if some clipping happened */
5457 diff = cstart - start;
5463 /* bring clipped time to samples and to bytes */
5464 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5467 GST_DEBUG_OBJECT (qtdemux,
5468 "clipping start to %" GST_TIME_FORMAT " %"
5469 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5475 diff = stop - cstop;
5480 /* bring clipped time to samples and then to bytes */
5481 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5483 GST_DEBUG_OBJECT (qtdemux,
5484 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5485 " bytes", GST_TIME_ARGS (cstop), diff);
5490 if (offset != 0 || size != osize)
5491 gst_buffer_resize (buf, offset, size);
5493 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5494 GST_BUFFER_PTS (buf) = pts;
5495 GST_BUFFER_DURATION (buf) = duration;
5499 /* dropped buffer */
5502 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5507 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5512 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5517 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5518 gst_buffer_unref (buf);
5524 gst_qtdemux_align_buffer (GstQTDemux * demux,
5525 GstBuffer * buffer, gsize alignment)
5529 gst_buffer_map (buffer, &map, GST_MAP_READ);
5531 if (map.size < sizeof (guintptr)) {
5532 gst_buffer_unmap (buffer, &map);
5536 if (((guintptr) map.data) & (alignment - 1)) {
5537 GstBuffer *new_buffer;
5538 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5540 new_buffer = gst_buffer_new_allocate (NULL,
5541 gst_buffer_get_size (buffer), ¶ms);
5543 /* Copy data "by hand", so ensure alignment is kept: */
5544 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5546 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5547 GST_DEBUG_OBJECT (demux,
5548 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5551 gst_buffer_unmap (buffer, &map);
5552 gst_buffer_unref (buffer);
5557 gst_buffer_unmap (buffer, &map);
5562 convert_to_ccdata (const guint8 * ccpair, guint8 ccpair_size, guint field,
5568 /* We are converting from pairs to triplets */
5569 *res = ccpair_size / 2 * 3;
5570 storage = g_malloc (*res);
5571 for (i = 0; i * 2 < ccpair_size; i += 1) {
5573 storage[i * 3] = 0xfc;
5575 storage[i * 3] = 0xfd;
5576 storage[i * 3 + 1] = ccpair[i * 2];
5577 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5584 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5588 guint32 atom_length, fourcc;
5589 QtDemuxStreamStsdEntry *stsd_entry;
5591 GST_MEMDUMP ("caption atom", data, size);
5593 /* There might be multiple atoms */
5598 atom_length = QT_UINT32 (data);
5599 fourcc = QT_FOURCC (data + 4);
5600 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5603 GST_DEBUG_OBJECT (stream->pad, "here");
5605 /* Check if we have somethig compatible */
5606 stsd_entry = CUR_STREAM (stream);
5607 switch (stsd_entry->fourcc) {
5609 guint8 *cdat = NULL, *cdt2 = NULL;
5610 gsize cdat_size = 0, cdt2_size = 0;
5611 /* Should be cdat or cdt2 */
5612 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5613 GST_WARNING_OBJECT (stream->pad,
5614 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5615 GST_FOURCC_ARGS (fourcc));
5619 /* Convert to cc_data triplet */
5620 if (fourcc == FOURCC_cdat)
5621 cdat = convert_to_ccdata (data + 8, atom_length - 8, 1, &cdat_size);
5623 cdt2 = convert_to_ccdata (data + 8, atom_length - 8, 2, &cdt2_size);
5624 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5627 /* Check for another atom ? */
5628 if (size > atom_length + 8) {
5629 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5630 if (size >= atom_length + new_atom_length) {
5631 fourcc = QT_FOURCC (data + atom_length + 4);
5632 if (fourcc == FOURCC_cdat) {
5635 convert_to_ccdata (data + atom_length + 8,
5636 new_atom_length - 8, 1, &cdat_size);
5638 GST_WARNING_OBJECT (stream->pad,
5639 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5643 convert_to_ccdata (data + atom_length + 8,
5644 new_atom_length - 8, 2, &cdt2_size);
5646 GST_WARNING_OBJECT (stream->pad,
5647 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5652 *cclen = cdat_size + cdt2_size;
5653 res = g_malloc (*cclen);
5655 memcpy (res, cdat, cdat_size);
5657 memcpy (res + cdat_size, cdt2, cdt2_size);
5663 if (fourcc != FOURCC_ccdp) {
5664 GST_WARNING_OBJECT (stream->pad,
5665 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5666 GST_FOURCC_ARGS (fourcc));
5669 *cclen = atom_length - 8;
5670 res = g_memdup (data + 8, *cclen);
5673 /* Keep this here in case other closed caption formats are added */
5674 g_assert_not_reached ();
5678 GST_MEMDUMP ("Output", res, *cclen);
5683 GST_WARNING ("[cdat] atom is too small or invalid");
5687 /* the input buffer metadata must be writable,
5688 * but time/duration etc not yet set and need not be preserved */
5690 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5697 /* not many cases for now */
5698 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5699 /* send a one time dvd clut event */
5700 if (stream->pending_event && stream->pad)
5701 gst_pad_push_event (stream->pad, stream->pending_event);
5702 stream->pending_event = NULL;
5705 if (G_UNLIKELY (stream->subtype != FOURCC_text
5706 && stream->subtype != FOURCC_sbtl &&
5707 stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5711 gst_buffer_map (buf, &map, GST_MAP_READ);
5713 /* empty buffer is sent to terminate previous subtitle */
5714 if (map.size <= 2) {
5715 gst_buffer_unmap (buf, &map);
5716 gst_buffer_unref (buf);
5719 if (stream->subtype == FOURCC_subp) {
5720 /* That's all the processing needed for subpictures */
5721 gst_buffer_unmap (buf, &map);
5725 if (stream->subtype == FOURCC_clcp) {
5728 /* For closed caption, we need to extract the information from the
5729 * [cdat],[cdt2] or [ccdp] atom */
5730 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5731 gst_buffer_unmap (buf, &map);
5732 gst_buffer_unref (buf);
5734 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5736 /* Conversion failed or there's nothing */
5742 nsize = GST_READ_UINT16_BE (map.data);
5743 nsize = MIN (nsize, map.size - 2);
5745 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5748 /* takes care of UTF-8 validation or UTF-16 recognition,
5749 * no other encoding expected */
5750 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5751 gst_buffer_unmap (buf, &map);
5753 gst_buffer_unref (buf);
5754 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5756 /* this should not really happen unless the subtitle is corrupted */
5757 gst_buffer_unref (buf);
5761 /* FIXME ? convert optional subsequent style info to markup */
5766 /* Sets a buffer's attributes properly and pushes it downstream.
5767 * Also checks for additional actions and custom processing that may
5768 * need to be done first.
5770 static GstFlowReturn
5771 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5772 QtDemuxStream * stream, GstBuffer * buf,
5773 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5774 gboolean keyframe, GstClockTime position, guint64 byte_position)
5776 GstFlowReturn ret = GST_FLOW_OK;
5778 /* offset the timestamps according to the edit list */
5780 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5784 gst_buffer_map (buf, &map, GST_MAP_READ);
5785 url = g_strndup ((gchar *) map.data, map.size);
5786 gst_buffer_unmap (buf, &map);
5787 if (url != NULL && strlen (url) != 0) {
5788 /* we have RTSP redirect now */
5789 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5790 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5791 gst_structure_new ("redirect",
5792 "new-location", G_TYPE_STRING, url, NULL)));
5793 qtdemux->posted_redirect = TRUE;
5795 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5801 /* position reporting */
5802 if (qtdemux->segment.rate >= 0) {
5803 qtdemux->segment.position = position;
5804 gst_qtdemux_sync_streams (qtdemux);
5807 if (G_UNLIKELY (!stream->pad)) {
5808 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5809 gst_buffer_unref (buf);
5813 /* send out pending buffers */
5814 while (stream->buffers) {
5815 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5817 if (G_UNLIKELY (stream->discont)) {
5818 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5819 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5820 stream->discont = FALSE;
5822 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5825 if (stream->alignment > 1)
5826 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5827 gst_pad_push (stream->pad, buffer);
5829 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5832 /* we're going to modify the metadata */
5833 buf = gst_buffer_make_writable (buf);
5835 if (G_UNLIKELY (stream->need_process))
5836 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5842 GST_BUFFER_DTS (buf) = dts;
5843 GST_BUFFER_PTS (buf) = pts;
5844 GST_BUFFER_DURATION (buf) = duration;
5845 GST_BUFFER_OFFSET (buf) = -1;
5846 GST_BUFFER_OFFSET_END (buf) = -1;
5848 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5849 gst_buffer_append_memory (buf,
5850 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5852 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5853 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5856 if (G_UNLIKELY (qtdemux->element_index)) {
5857 GstClockTime stream_time;
5860 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5862 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5863 GST_LOG_OBJECT (qtdemux,
5864 "adding association %" GST_TIME_FORMAT "-> %"
5865 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5866 gst_index_add_association (qtdemux->element_index,
5868 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5869 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5870 GST_FORMAT_BYTES, byte_position, NULL);
5875 if (stream->need_clip)
5876 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5878 if (G_UNLIKELY (buf == NULL))
5881 if (G_UNLIKELY (stream->discont)) {
5882 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5883 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5884 stream->discont = FALSE;
5886 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5890 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5891 stream->on_keyframe = FALSE;
5893 stream->on_keyframe = TRUE;
5897 GST_LOG_OBJECT (qtdemux,
5898 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5899 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5900 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5901 GST_PAD_NAME (stream->pad));
5903 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5904 GstStructure *crypto_info;
5905 QtDemuxCencSampleSetInfo *info =
5906 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5910 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5911 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5912 GST_PTR_FORMAT, event);
5913 gst_pad_push_event (stream->pad, event);
5916 if (info->crypto_info == NULL) {
5917 GST_DEBUG_OBJECT (qtdemux,
5918 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5920 /* The end of the crypto_info array matches our n_samples position,
5921 * so count backward from there */
5922 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5923 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5924 /* steal structure from array */
5925 crypto_info = g_ptr_array_index (info->crypto_info, index);
5926 g_ptr_array_index (info->crypto_info, index) = NULL;
5927 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5928 info->crypto_info->len);
5929 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5930 GST_ERROR_OBJECT (qtdemux,
5931 "failed to attach cenc metadata to buffer");
5933 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5934 index, stream->sample_index);
5939 if (stream->alignment > 1)
5940 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5942 ret = gst_pad_push (stream->pad, buf);
5944 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5945 /* mark position in stream, we'll need this to know when to send GAP event */
5946 stream->segment.position = pts + duration;
5953 static const QtDemuxRandomAccessEntry *
5954 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5955 GstClockTime pos, gboolean after)
5957 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5958 guint n_entries = stream->n_ra_entries;
5961 /* we assume the table is sorted */
5962 for (i = 0; i < n_entries; ++i) {
5963 if (entries[i].ts > pos)
5967 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5968 * probably okay to assume that the index lists the very first fragment */
5975 return &entries[i - 1];
5979 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5981 const QtDemuxRandomAccessEntry *best_entry = NULL;
5984 GST_OBJECT_LOCK (qtdemux);
5986 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
5988 /* first see if we can determine where to go to using mfra,
5989 * before we start clearing things */
5990 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
5991 const QtDemuxRandomAccessEntry *entry;
5992 QtDemuxStream *stream;
5993 gboolean is_audio_or_video;
5995 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
5997 if (stream->ra_entries == NULL)
6000 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6001 is_audio_or_video = TRUE;
6003 is_audio_or_video = FALSE;
6006 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6007 stream->time_position, !is_audio_or_video);
6009 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6010 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6012 stream->pending_seek = entry;
6014 /* decide position to jump to just based on audio/video tracks, not subs */
6015 if (!is_audio_or_video)
6018 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6022 /* no luck, will handle seek otherwise */
6023 if (best_entry == NULL) {
6024 GST_OBJECT_UNLOCK (qtdemux);
6028 /* ok, now we can prepare for processing as of located moof */
6029 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6030 QtDemuxStream *stream;
6032 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6034 g_free (stream->samples);
6035 stream->samples = NULL;
6036 stream->n_samples = 0;
6037 stream->stbl_index = -1; /* no samples have yet been parsed */
6038 stream->sample_index = -1;
6040 if (stream->protection_scheme_info) {
6041 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6042 if (stream->protection_scheme_type == FOURCC_cenc) {
6043 QtDemuxCencSampleSetInfo *info =
6044 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6045 if (info->crypto_info) {
6046 g_ptr_array_free (info->crypto_info, TRUE);
6047 info->crypto_info = NULL;
6053 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6054 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6055 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6056 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6058 qtdemux->moof_offset = best_entry->moof_offset;
6060 qtdemux_add_fragmented_samples (qtdemux);
6062 GST_OBJECT_UNLOCK (qtdemux);
6066 static GstFlowReturn
6067 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6069 GstFlowReturn ret = GST_FLOW_OK;
6070 GstBuffer *buf = NULL;
6071 QtDemuxStream *stream, *target_stream = NULL;
6072 GstClockTime min_time;
6074 GstClockTime dts = GST_CLOCK_TIME_NONE;
6075 GstClockTime pts = GST_CLOCK_TIME_NONE;
6076 GstClockTime duration = 0;
6077 gboolean keyframe = FALSE;
6078 guint sample_size = 0;
6083 if (qtdemux->fragmented_seek_pending) {
6084 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6085 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6086 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6087 qtdemux->fragmented_seek_pending = FALSE;
6089 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6093 /* Figure out the next stream sample to output, min_time is expressed in
6094 * global time and runs over the edit list segments. */
6095 min_time = G_MAXUINT64;
6096 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6097 GstClockTime position;
6099 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6100 position = stream->time_position;
6102 /* position of -1 is EOS */
6103 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6104 min_time = position;
6105 target_stream = stream;
6109 if (G_UNLIKELY (target_stream == NULL)) {
6110 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6114 /* check for segment end */
6115 if (G_UNLIKELY (qtdemux->segment.stop != -1
6116 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6117 || (qtdemux->segment.rate < 0
6118 && qtdemux->segment.start > min_time))
6119 && target_stream->on_keyframe)) {
6120 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6121 target_stream->time_position = GST_CLOCK_TIME_NONE;
6125 /* gap events for subtitle streams */
6126 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6127 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6128 if (stream->pad && (stream->subtype == FOURCC_subp
6129 || stream->subtype == FOURCC_text
6130 || stream->subtype == FOURCC_sbtl)) {
6131 /* send one second gap events until the stream catches up */
6132 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6133 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6134 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6135 stream->segment.position + GST_SECOND < min_time) {
6137 gst_event_new_gap (stream->segment.position, GST_SECOND);
6138 gst_pad_push_event (stream->pad, gap);
6139 stream->segment.position += GST_SECOND;
6144 stream = target_stream;
6145 /* fetch info for the current sample of this stream */
6146 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6147 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6150 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6151 if (stream->new_caps) {
6152 gst_qtdemux_configure_stream (qtdemux, stream);
6153 qtdemux_do_allocation (stream, qtdemux);
6156 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6157 if (G_UNLIKELY (qtdemux->
6158 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6159 if (stream->subtype == FOURCC_vide && !keyframe) {
6160 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6166 GST_DEBUG_OBJECT (qtdemux,
6167 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6168 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6169 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6170 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6171 GST_TIME_ARGS (duration));
6173 if (G_UNLIKELY (empty)) {
6174 /* empty segment, push a gap if there's a second or more
6175 * difference and move to the next one */
6176 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6177 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6178 stream->segment.position = pts + duration;
6182 /* hmm, empty sample, skip and move to next sample */
6183 if (G_UNLIKELY (sample_size <= 0))
6186 /* last pushed sample was out of boundary, goto next sample */
6187 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6190 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6193 GST_DEBUG_OBJECT (qtdemux,
6194 "size %d larger than stream max_buffer_size %d, trimming",
6195 sample_size, stream->max_buffer_size);
6197 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6200 if (qtdemux->cenc_aux_info_offset > 0) {
6203 GstBuffer *aux_info = NULL;
6205 /* pull the data stored before the sample */
6207 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6208 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6209 if (G_UNLIKELY (ret != GST_FLOW_OK))
6211 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6212 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6213 gst_byte_reader_init (&br, map.data + 8, map.size);
6214 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6215 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6216 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6217 gst_buffer_unmap (aux_info, &map);
6218 gst_buffer_unref (aux_info);
6219 ret = GST_FLOW_ERROR;
6222 gst_buffer_unmap (aux_info, &map);
6223 gst_buffer_unref (aux_info);
6226 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6229 if (stream->use_allocator) {
6230 /* if we have a per-stream allocator, use it */
6231 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6234 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6236 if (G_UNLIKELY (ret != GST_FLOW_OK))
6239 if (size != sample_size) {
6240 pts += gst_util_uint64_scale_int (GST_SECOND,
6241 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6244 gst_util_uint64_scale_int (GST_SECOND,
6245 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6248 gst_util_uint64_scale_int (GST_SECOND,
6249 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6252 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6253 dts, pts, duration, keyframe, min_time, offset);
6255 if (size != sample_size) {
6256 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6257 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6259 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6261 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6262 if (time_position >= segment->media_start) {
6263 /* inside the segment, update time_position, looks very familiar to
6264 * GStreamer segments, doesn't it? */
6265 stream->time_position = (time_position - segment->media_start) +
6268 /* not yet in segment, time does not yet increment. This means
6269 * that we are still prerolling keyframes to the decoder so it can
6270 * decode the first sample of the segment. */
6271 stream->time_position = segment->time;
6276 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6277 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6278 * we have no more data for the pad to push */
6279 if (ret == GST_FLOW_EOS)
6282 stream->offset_in_sample += size;
6283 if (stream->offset_in_sample >= sample_size) {
6284 gst_qtdemux_advance_sample (qtdemux, stream);
6289 gst_qtdemux_advance_sample (qtdemux, stream);
6297 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6303 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6304 /* EOS will be raised if all are EOS */
6311 gst_qtdemux_loop (GstPad * pad)
6313 GstQTDemux *qtdemux;
6317 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6319 cur_offset = qtdemux->offset;
6320 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6321 cur_offset, qt_demux_state_string (qtdemux->state));
6323 switch (qtdemux->state) {
6324 case QTDEMUX_STATE_INITIAL:
6325 case QTDEMUX_STATE_HEADER:
6326 ret = gst_qtdemux_loop_state_header (qtdemux);
6328 case QTDEMUX_STATE_MOVIE:
6329 ret = gst_qtdemux_loop_state_movie (qtdemux);
6330 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6331 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6339 /* if something went wrong, pause */
6340 if (ret != GST_FLOW_OK)
6344 gst_object_unref (qtdemux);
6350 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6351 (NULL), ("streaming stopped, invalid state"));
6352 gst_pad_pause_task (pad);
6353 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6358 const gchar *reason = gst_flow_get_name (ret);
6360 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6362 gst_pad_pause_task (pad);
6364 /* fatal errors need special actions */
6366 if (ret == GST_FLOW_EOS) {
6367 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6368 /* we have no streams, post an error */
6369 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6371 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6374 if ((stop = qtdemux->segment.stop) == -1)
6375 stop = qtdemux->segment.duration;
6377 if (qtdemux->segment.rate >= 0) {
6378 GstMessage *message;
6381 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6382 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6383 GST_FORMAT_TIME, stop);
6384 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6385 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6386 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6387 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6389 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6390 gst_qtdemux_push_event (qtdemux, event);
6392 GstMessage *message;
6395 /* For Reverse Playback */
6396 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6397 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6398 GST_FORMAT_TIME, qtdemux->segment.start);
6399 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6400 qtdemux->segment.start);
6401 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6402 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6403 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6405 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6406 gst_qtdemux_push_event (qtdemux, event);
6411 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6412 event = gst_event_new_eos ();
6413 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6414 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6415 gst_qtdemux_push_event (qtdemux, event);
6417 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6418 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6419 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6428 * Returns if there are samples to be played.
6431 has_next_entry (GstQTDemux * demux)
6433 QtDemuxStream *stream;
6436 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6438 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6439 stream = QTDEMUX_NTH_STREAM (demux, i);
6441 if (stream->sample_index == -1) {
6442 stream->sample_index = 0;
6443 stream->offset_in_sample = 0;
6446 if (stream->sample_index >= stream->n_samples) {
6447 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6450 GST_DEBUG_OBJECT (demux, "Found a sample");
6454 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6461 * Returns the size of the first entry at the current offset.
6462 * If -1, there are none (which means EOS or empty file).
6465 next_entry_size (GstQTDemux * demux)
6467 QtDemuxStream *stream, *target_stream = NULL;
6468 guint64 smalloffs = (guint64) - 1;
6469 QtDemuxSample *sample;
6472 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6475 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6476 stream = QTDEMUX_NTH_STREAM (demux, i);
6478 if (stream->sample_index == -1) {
6479 stream->sample_index = 0;
6480 stream->offset_in_sample = 0;
6483 if (stream->sample_index >= stream->n_samples) {
6484 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6488 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6489 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6490 stream->sample_index);
6494 sample = &stream->samples[stream->sample_index];
6496 GST_LOG_OBJECT (demux,
6497 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6498 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6499 stream->sample_index, sample->offset, sample->size);
6501 if (((smalloffs == -1)
6502 || (sample->offset < smalloffs)) && (sample->size)) {
6503 smalloffs = sample->offset;
6504 target_stream = stream;
6511 GST_LOG_OBJECT (demux,
6512 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6513 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6515 stream = target_stream;
6516 sample = &stream->samples[stream->sample_index];
6518 if (sample->offset >= demux->offset) {
6519 demux->todrop = sample->offset - demux->offset;
6520 return sample->size + demux->todrop;
6523 GST_DEBUG_OBJECT (demux,
6524 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6529 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6531 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6533 gst_element_post_message (GST_ELEMENT_CAST (demux),
6534 gst_message_new_element (GST_OBJECT_CAST (demux),
6535 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6539 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6544 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6547 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6548 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6549 GST_SEEK_TYPE_NONE, -1);
6551 /* store seqnum to drop flush events, they don't need to reach downstream */
6552 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6553 res = gst_pad_push_event (demux->sinkpad, event);
6554 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6559 /* check for seekable upstream, above and beyond a mere query */
6561 gst_qtdemux_check_seekability (GstQTDemux * demux)
6564 gboolean seekable = FALSE;
6565 gint64 start = -1, stop = -1;
6567 if (demux->upstream_size)
6570 if (demux->upstream_format_is_time)
6573 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6574 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6575 GST_DEBUG_OBJECT (demux, "seeking query failed");
6579 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6581 /* try harder to query upstream size if we didn't get it the first time */
6582 if (seekable && stop == -1) {
6583 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6584 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6587 /* if upstream doesn't know the size, it's likely that it's not seekable in
6588 * practice even if it technically may be seekable */
6589 if (seekable && (start != 0 || stop <= start)) {
6590 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6595 gst_query_unref (query);
6597 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6598 G_GUINT64_FORMAT ")", seekable, start, stop);
6599 demux->upstream_seekable = seekable;
6600 demux->upstream_size = seekable ? stop : -1;
6604 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6606 g_return_if_fail (bytes <= demux->todrop);
6608 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6609 gst_adapter_flush (demux->adapter, bytes);
6610 demux->neededbytes -= bytes;
6611 demux->offset += bytes;
6612 demux->todrop -= bytes;
6615 /* PUSH-MODE only: Send a segment, if not done already. */
6617 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6619 if (G_UNLIKELY (demux->need_segment)) {
6622 if (!demux->upstream_format_is_time) {
6623 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6625 GstEvent *segment_event;
6626 segment_event = gst_event_new_segment (&demux->segment);
6627 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6628 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6629 gst_qtdemux_push_event (demux, segment_event);
6632 demux->need_segment = FALSE;
6634 /* clear to send tags on all streams */
6635 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6636 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6637 gst_qtdemux_push_tags (demux, stream);
6638 if (CUR_STREAM (stream)->sparse) {
6639 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6640 gst_pad_push_event (stream->pad,
6641 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6647 /* Used for push mode only. */
6649 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6650 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6652 GstClockTime ts, dur;
6656 stream->segments[segment_index].duration - (pos -
6657 stream->segments[segment_index].time);
6658 stream->time_position += dur;
6660 /* Only gaps with a duration of at least one second are propagated.
6661 * Same workaround as in pull mode.
6662 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6663 if (dur >= GST_SECOND) {
6665 gap = gst_event_new_gap (ts, dur);
6667 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6668 "segment: %" GST_PTR_FORMAT, gap);
6669 gst_pad_push_event (stream->pad, gap);
6673 static GstFlowReturn
6674 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6678 demux = GST_QTDEMUX (parent);
6680 GST_DEBUG_OBJECT (demux,
6681 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6682 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6683 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6684 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6685 gst_buffer_get_size (inbuf), demux->offset);
6687 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6688 gboolean is_gap_input = FALSE;
6691 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6693 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6694 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
6697 /* Check if we can land back on our feet in the case where upstream is
6698 * handling the seeking/pushing of samples with gaps in between (like
6699 * in the case of trick-mode DASH for example) */
6700 if (demux->upstream_format_is_time
6701 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6702 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6704 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6705 GST_LOG_OBJECT (demux,
6706 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6707 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6709 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6710 stream, GST_BUFFER_OFFSET (inbuf));
6712 QtDemuxSample *sample = &stream->samples[res];
6713 GST_LOG_OBJECT (demux,
6714 "Checking if sample %d from track-id %u is valid (offset:%"
6715 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6716 stream->track_id, sample->offset, sample->size);
6717 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6718 GST_LOG_OBJECT (demux,
6719 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6721 is_gap_input = TRUE;
6722 /* We can go back to standard playback mode */
6723 demux->state = QTDEMUX_STATE_MOVIE;
6724 /* Remember which sample this stream is at */
6725 stream->sample_index = res;
6726 /* Finally update all push-based values to the expected values */
6727 demux->neededbytes = stream->samples[res].size;
6728 demux->offset = GST_BUFFER_OFFSET (inbuf);
6730 demux->mdatsize - demux->offset + demux->mdatoffset;
6735 if (!is_gap_input) {
6736 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6737 /* Reset state if it's a real discont */
6738 demux->neededbytes = 16;
6739 demux->state = QTDEMUX_STATE_INITIAL;
6740 demux->offset = GST_BUFFER_OFFSET (inbuf);
6741 gst_adapter_clear (demux->adapter);
6744 /* Reverse fragmented playback, need to flush all we have before
6745 * consuming a new fragment.
6746 * The samples array have the timestamps calculated by accumulating the
6747 * durations but this won't work for reverse playback of fragments as
6748 * the timestamps of a subsequent fragment should be smaller than the
6749 * previously received one. */
6750 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6751 gst_qtdemux_process_adapter (demux, TRUE);
6752 g_ptr_array_foreach (demux->active_streams,
6753 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6757 gst_adapter_push (demux->adapter, inbuf);
6759 GST_DEBUG_OBJECT (demux,
6760 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6761 demux->neededbytes, gst_adapter_available (demux->adapter));
6763 return gst_qtdemux_process_adapter (demux, FALSE);
6766 static GstFlowReturn
6767 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6769 GstFlowReturn ret = GST_FLOW_OK;
6771 /* we never really mean to buffer that much */
6772 if (demux->neededbytes == -1) {
6776 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6777 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6779 #ifndef GST_DISABLE_GST_DEBUG
6781 guint64 discont_offset, distance_from_discont;
6783 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6784 distance_from_discont =
6785 gst_adapter_distance_from_discont (demux->adapter);
6787 GST_DEBUG_OBJECT (demux,
6788 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6789 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6790 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6791 demux->offset, discont_offset, distance_from_discont);
6795 switch (demux->state) {
6796 case QTDEMUX_STATE_INITIAL:{
6801 gst_qtdemux_check_seekability (demux);
6803 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6805 /* get fourcc/length, set neededbytes */
6806 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6808 gst_adapter_unmap (demux->adapter);
6810 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6811 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6813 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6814 (_("This file is invalid and cannot be played.")),
6815 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6816 GST_FOURCC_ARGS (fourcc)));
6817 ret = GST_FLOW_ERROR;
6820 if (fourcc == FOURCC_mdat) {
6821 gint next_entry = next_entry_size (demux);
6822 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
6823 || !demux->fragmented)) {
6824 /* we have the headers, start playback */
6825 demux->state = QTDEMUX_STATE_MOVIE;
6826 demux->neededbytes = next_entry;
6827 demux->mdatleft = size;
6828 demux->mdatsize = demux->mdatleft;
6830 /* no headers yet, try to get them */
6833 guint64 old, target;
6836 old = demux->offset;
6837 target = old + size;
6839 /* try to jump over the atom with a seek */
6840 /* only bother if it seems worth doing so,
6841 * and avoids possible upstream/server problems */
6842 if (demux->upstream_seekable &&
6843 demux->upstream_size > 4 * (1 << 20)) {
6844 res = qtdemux_seek_offset (demux, target);
6846 GST_DEBUG_OBJECT (demux, "skipping seek");
6851 GST_DEBUG_OBJECT (demux, "seek success");
6852 /* remember the offset fo the first mdat so we can seek back to it
6853 * after we have the headers */
6854 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6855 demux->first_mdat = old;
6856 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6859 /* seek worked, continue reading */
6860 demux->offset = target;
6861 demux->neededbytes = 16;
6862 demux->state = QTDEMUX_STATE_INITIAL;
6864 /* seek failed, need to buffer */
6865 demux->offset = old;
6866 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6867 /* there may be multiple mdat (or alike) buffers */
6869 if (demux->mdatbuffer)
6870 bs = gst_buffer_get_size (demux->mdatbuffer);
6873 if (size + bs > 10 * (1 << 20))
6875 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6876 demux->neededbytes = size;
6877 if (!demux->mdatbuffer)
6878 demux->mdatoffset = demux->offset;
6881 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6882 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6883 (_("This file is invalid and cannot be played.")),
6884 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6885 GST_FOURCC_ARGS (fourcc), size));
6886 ret = GST_FLOW_ERROR;
6889 /* this means we already started buffering and still no moov header,
6890 * let's continue buffering everything till we get moov */
6891 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6892 || fourcc == FOURCC_moof))
6894 demux->neededbytes = size;
6895 demux->state = QTDEMUX_STATE_HEADER;
6899 case QTDEMUX_STATE_HEADER:{
6903 GST_DEBUG_OBJECT (demux, "In header");
6905 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6907 /* parse the header */
6908 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6910 if (fourcc == FOURCC_moov) {
6911 /* in usual fragmented setup we could try to scan for more
6912 * and end up at the the moov (after mdat) again */
6913 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
6915 || demux->last_moov_offset == demux->offset)) {
6916 GST_DEBUG_OBJECT (demux,
6917 "Skipping moov atom as we have (this) one already");
6919 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6921 if (demux->got_moov && demux->fragmented) {
6922 GST_DEBUG_OBJECT (demux,
6923 "Got a second moov, clean up data from old one");
6924 if (demux->moov_node_compressed) {
6925 g_node_destroy (demux->moov_node_compressed);
6926 if (demux->moov_node)
6927 g_free (demux->moov_node->data);
6929 demux->moov_node_compressed = NULL;
6930 if (demux->moov_node)
6931 g_node_destroy (demux->moov_node);
6932 demux->moov_node = NULL;
6935 demux->last_moov_offset = demux->offset;
6937 /* Update streams with new moov */
6938 gst_qtdemux_stream_concat (demux,
6939 demux->old_streams, demux->active_streams);
6941 qtdemux_parse_moov (demux, data, demux->neededbytes);
6942 qtdemux_node_dump (demux, demux->moov_node);
6943 qtdemux_parse_tree (demux);
6944 qtdemux_prepare_streams (demux);
6945 QTDEMUX_EXPOSE_LOCK (demux);
6946 qtdemux_expose_streams (demux);
6947 QTDEMUX_EXPOSE_UNLOCK (demux);
6949 demux->got_moov = TRUE;
6951 gst_qtdemux_check_send_pending_segment (demux);
6953 if (demux->moov_node_compressed) {
6954 g_node_destroy (demux->moov_node_compressed);
6955 g_free (demux->moov_node->data);
6957 demux->moov_node_compressed = NULL;
6958 g_node_destroy (demux->moov_node);
6959 demux->moov_node = NULL;
6960 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6962 } else if (fourcc == FOURCC_moof) {
6963 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6965 GstClockTime prev_pts;
6966 guint64 prev_offset;
6967 guint64 adapter_discont_offset, adapter_discont_dist;
6969 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6972 * The timestamp of the moof buffer is relevant as some scenarios
6973 * won't have the initial timestamp in the atoms. Whenever a new
6974 * buffer has started, we get that buffer's PTS and use it as a base
6975 * timestamp for the trun entries.
6977 * To keep track of the current buffer timestamp and starting point
6978 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6979 * from the beggining of the buffer, with the distance and demux->offset
6980 * we know if it is still the same buffer or not.
6982 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6983 prev_offset = demux->offset - dist;
6984 if (demux->fragment_start_offset == -1
6985 || prev_offset > demux->fragment_start_offset) {
6986 demux->fragment_start_offset = prev_offset;
6987 demux->fragment_start = prev_pts;
6988 GST_DEBUG_OBJECT (demux,
6989 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6990 GST_TIME_FORMAT, demux->fragment_start_offset,
6991 GST_TIME_ARGS (demux->fragment_start));
6994 /* We can't use prev_offset() here because this would require
6995 * upstream to set consistent and correct offsets on all buffers
6996 * since the discont. Nothing ever did that in the past and we
6997 * would break backwards compatibility here then.
6998 * Instead take the offset we had at the last discont and count
6999 * the bytes from there. This works with old code as there would
7000 * be no discont between moov and moof, and also works with
7001 * adaptivedemux which correctly sets offset and will set the
7002 * DISCONT flag accordingly when needed.
7004 * We also only do this for upstream TIME segments as otherwise
7005 * there are potential backwards compatibility problems with
7006 * seeking in PUSH mode and upstream providing inconsistent
7008 adapter_discont_offset =
7009 gst_adapter_offset_at_discont (demux->adapter);
7010 adapter_discont_dist =
7011 gst_adapter_distance_from_discont (demux->adapter);
7013 GST_DEBUG_OBJECT (demux,
7014 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7015 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7016 demux->offset, adapter_discont_offset, adapter_discont_dist);
7018 if (demux->upstream_format_is_time) {
7019 demux->moof_offset = adapter_discont_offset;
7020 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7021 demux->moof_offset += adapter_discont_dist;
7022 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7023 demux->moof_offset = demux->offset;
7025 demux->moof_offset = demux->offset;
7028 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7029 demux->moof_offset, NULL)) {
7030 gst_adapter_unmap (demux->adapter);
7031 ret = GST_FLOW_ERROR;
7035 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7036 if (demux->mss_mode && !demux->exposed) {
7037 QTDEMUX_EXPOSE_LOCK (demux);
7038 qtdemux_expose_streams (demux);
7039 QTDEMUX_EXPOSE_UNLOCK (demux);
7042 gst_qtdemux_check_send_pending_segment (demux);
7044 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7046 } else if (fourcc == FOURCC_ftyp) {
7047 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7048 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7049 } else if (fourcc == FOURCC_uuid) {
7050 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7051 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7052 } else if (fourcc == FOURCC_sidx) {
7053 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7054 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7058 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7062 /* [free] and [skip] are padding atoms */
7063 GST_DEBUG_OBJECT (demux,
7064 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7065 GST_FOURCC_ARGS (fourcc));
7068 GST_WARNING_OBJECT (demux,
7069 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7070 GST_FOURCC_ARGS (fourcc));
7071 /* Let's jump that one and go back to initial state */
7075 gst_adapter_unmap (demux->adapter);
7078 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7079 gsize remaining_data_size = 0;
7081 /* the mdat was before the header */
7082 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7083 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7084 /* restore our adapter/offset view of things with upstream;
7085 * put preceding buffered data ahead of current moov data.
7086 * This should also handle evil mdat, moov, mdat cases and alike */
7087 gst_adapter_flush (demux->adapter, demux->neededbytes);
7089 /* Store any remaining data after the mdat for later usage */
7090 remaining_data_size = gst_adapter_available (demux->adapter);
7091 if (remaining_data_size > 0) {
7092 g_assert (demux->restoredata_buffer == NULL);
7093 demux->restoredata_buffer =
7094 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7095 demux->restoredata_offset = demux->offset + demux->neededbytes;
7096 GST_DEBUG_OBJECT (demux,
7097 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7098 G_GUINT64_FORMAT, remaining_data_size,
7099 demux->restoredata_offset);
7102 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7103 demux->mdatbuffer = NULL;
7104 demux->offset = demux->mdatoffset;
7105 demux->neededbytes = next_entry_size (demux);
7106 demux->state = QTDEMUX_STATE_MOVIE;
7107 demux->mdatleft = gst_adapter_available (demux->adapter);
7108 demux->mdatsize = demux->mdatleft;
7110 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7111 gst_adapter_flush (demux->adapter, demux->neededbytes);
7113 /* only go back to the mdat if there are samples to play */
7114 if (demux->got_moov && demux->first_mdat != -1
7115 && has_next_entry (demux)) {
7118 /* we need to seek back */
7119 res = qtdemux_seek_offset (demux, demux->first_mdat);
7121 demux->offset = demux->first_mdat;
7123 GST_DEBUG_OBJECT (demux, "Seek back failed");
7126 demux->offset += demux->neededbytes;
7128 demux->neededbytes = 16;
7129 demux->state = QTDEMUX_STATE_INITIAL;
7134 case QTDEMUX_STATE_BUFFER_MDAT:{
7138 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7140 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7141 gst_buffer_extract (buf, 0, fourcc, 4);
7142 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7143 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7144 if (demux->mdatbuffer)
7145 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7147 demux->mdatbuffer = buf;
7148 demux->offset += demux->neededbytes;
7149 demux->neededbytes = 16;
7150 demux->state = QTDEMUX_STATE_INITIAL;
7151 gst_qtdemux_post_progress (demux, 1, 1);
7155 case QTDEMUX_STATE_MOVIE:{
7156 QtDemuxStream *stream = NULL;
7157 QtDemuxSample *sample;
7158 GstClockTime dts, pts, duration;
7162 GST_DEBUG_OBJECT (demux,
7163 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7165 if (demux->fragmented) {
7166 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7168 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7169 /* if needed data starts within this atom,
7170 * then it should not exceed this atom */
7171 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7172 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7173 (_("This file is invalid and cannot be played.")),
7174 ("sample data crosses atom boundary"));
7175 ret = GST_FLOW_ERROR;
7178 demux->mdatleft -= demux->neededbytes;
7180 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7181 /* so we are dropping more than left in this atom */
7182 gst_qtdemux_drop_data (demux, demux->mdatleft);
7183 demux->mdatleft = 0;
7185 /* need to resume atom parsing so we do not miss any other pieces */
7186 demux->state = QTDEMUX_STATE_INITIAL;
7187 demux->neededbytes = 16;
7189 /* check if there was any stored post mdat data from previous buffers */
7190 if (demux->restoredata_buffer) {
7191 g_assert (gst_adapter_available (demux->adapter) == 0);
7193 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7194 demux->restoredata_buffer = NULL;
7195 demux->offset = demux->restoredata_offset;
7202 if (demux->todrop) {
7203 if (demux->cenc_aux_info_offset > 0) {
7207 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7208 data = gst_adapter_map (demux->adapter, demux->todrop);
7209 gst_byte_reader_init (&br, data + 8, demux->todrop);
7210 if (!qtdemux_parse_cenc_aux_info (demux,
7211 QTDEMUX_NTH_STREAM (demux, 0), &br,
7212 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7213 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7214 ret = GST_FLOW_ERROR;
7215 gst_adapter_unmap (demux->adapter);
7216 g_free (demux->cenc_aux_info_sizes);
7217 demux->cenc_aux_info_sizes = NULL;
7220 demux->cenc_aux_info_offset = 0;
7221 g_free (demux->cenc_aux_info_sizes);
7222 demux->cenc_aux_info_sizes = NULL;
7223 gst_adapter_unmap (demux->adapter);
7225 gst_qtdemux_drop_data (demux, demux->todrop);
7229 /* initial newsegment sent here after having added pads,
7230 * possible others in sink_event */
7231 gst_qtdemux_check_send_pending_segment (demux);
7233 /* Figure out which stream this packet belongs to */
7234 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7235 stream = QTDEMUX_NTH_STREAM (demux, i);
7236 if (stream->sample_index >= stream->n_samples) {
7237 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7241 GST_LOG_OBJECT (demux,
7242 "Checking track-id %u (sample_index:%d / offset:%"
7243 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7244 stream->sample_index,
7245 stream->samples[stream->sample_index].offset,
7246 stream->samples[stream->sample_index].size);
7248 if (stream->samples[stream->sample_index].offset == demux->offset)
7252 if (G_UNLIKELY (stream == NULL))
7253 goto unknown_stream;
7255 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7257 if (stream->new_caps) {
7258 gst_qtdemux_configure_stream (demux, stream);
7261 /* Put data in a buffer, set timestamps, caps, ... */
7262 sample = &stream->samples[stream->sample_index];
7264 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7265 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7266 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7268 dts = QTSAMPLE_DTS (stream, sample);
7269 pts = QTSAMPLE_PTS (stream, sample);
7270 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7271 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7273 /* check for segment end */
7274 if (G_UNLIKELY (demux->segment.stop != -1
7275 && demux->segment.stop <= pts && stream->on_keyframe)
7276 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7277 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7278 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7280 /* skip this data, stream is EOS */
7281 gst_adapter_flush (demux->adapter, demux->neededbytes);
7282 demux->offset += demux->neededbytes;
7284 /* check if all streams are eos */
7286 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7287 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7296 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7298 /* FIXME: should either be an assert or a plain check */
7299 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7301 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7302 dts, pts, duration, keyframe, dts, demux->offset);
7306 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7308 /* skip this data, stream is EOS */
7309 gst_adapter_flush (demux->adapter, demux->neededbytes);
7312 stream->sample_index++;
7313 stream->offset_in_sample = 0;
7315 /* update current offset and figure out size of next buffer */
7316 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7317 demux->offset, demux->neededbytes);
7318 demux->offset += demux->neededbytes;
7319 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7323 if (ret == GST_FLOW_EOS) {
7324 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7325 demux->neededbytes = -1;
7329 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7330 if (demux->fragmented) {
7331 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7332 /* there may be more to follow, only finish this atom */
7333 demux->todrop = demux->mdatleft;
7334 demux->neededbytes = demux->todrop;
7339 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7340 goto non_ok_unlinked_flow;
7349 /* when buffering movie data, at least show user something is happening */
7350 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7351 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7352 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7353 demux->neededbytes);
7360 non_ok_unlinked_flow:
7362 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7363 gst_flow_get_name (ret));
7368 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7369 ret = GST_FLOW_ERROR;
7374 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7380 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7381 (NULL), ("qtdemuxer invalid state %d", demux->state));
7382 ret = GST_FLOW_ERROR;
7387 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7388 (NULL), ("no 'moov' atom within the first 10 MB"));
7389 ret = GST_FLOW_ERROR;
7395 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7400 query = gst_query_new_scheduling ();
7402 if (!gst_pad_peer_query (sinkpad, query)) {
7403 gst_query_unref (query);
7407 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7408 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7409 gst_query_unref (query);
7414 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7415 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7419 GST_DEBUG_OBJECT (sinkpad, "activating push");
7420 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7425 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7426 GstPadMode mode, gboolean active)
7429 GstQTDemux *demux = GST_QTDEMUX (parent);
7432 case GST_PAD_MODE_PUSH:
7433 demux->pullbased = FALSE;
7436 case GST_PAD_MODE_PULL:
7438 demux->pullbased = TRUE;
7439 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7442 res = gst_pad_stop_task (sinkpad);
7454 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7460 memset (&z, 0, sizeof (z));
7465 if ((ret = inflateInit (&z)) != Z_OK) {
7466 GST_ERROR ("inflateInit() returned %d", ret);
7470 z.next_in = z_buffer;
7471 z.avail_in = z_length;
7473 buffer = (guint8 *) g_malloc (*length);
7474 z.avail_out = *length;
7475 z.next_out = (Bytef *) buffer;
7477 ret = inflate (&z, Z_NO_FLUSH);
7478 if (ret == Z_STREAM_END) {
7480 } else if (ret != Z_OK) {
7481 GST_WARNING ("inflate() returned %d", ret);
7486 buffer = (guint8 *) g_realloc (buffer, *length);
7487 z.next_out = (Bytef *) (buffer + z.total_out);
7488 z.avail_out += 4096;
7489 } while (z.avail_in > 0);
7491 if (ret != Z_STREAM_END) {
7496 *length = z.total_out;
7503 #endif /* HAVE_ZLIB */
7506 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7510 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7512 /* counts as header data */
7513 qtdemux->header_size += length;
7515 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7516 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7518 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7525 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7526 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7527 if (dcom == NULL || cmvd == NULL)
7528 goto invalid_compression;
7530 dcom_len = QT_UINT32 (dcom->data);
7532 goto invalid_compression;
7534 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7538 guint uncompressed_length;
7539 guint compressed_length;
7543 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7545 goto invalid_compression;
7547 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7548 compressed_length = cmvd_len - 12;
7549 GST_LOG ("length = %u", uncompressed_length);
7552 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7553 compressed_length, &uncompressed_length);
7556 qtdemux->moov_node_compressed = qtdemux->moov_node;
7557 qtdemux->moov_node = g_node_new (buf);
7559 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7560 uncompressed_length);
7564 #endif /* HAVE_ZLIB */
7566 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7567 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7574 invalid_compression:
7576 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7582 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7585 while (G_UNLIKELY (buf < end)) {
7589 if (G_UNLIKELY (buf + 4 > end)) {
7590 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7593 len = QT_UINT32 (buf);
7594 if (G_UNLIKELY (len == 0)) {
7595 GST_LOG_OBJECT (qtdemux, "empty container");
7598 if (G_UNLIKELY (len < 8)) {
7599 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7602 if (G_UNLIKELY (len > (end - buf))) {
7603 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7604 (gint) (end - buf));
7608 child = g_node_new ((guint8 *) buf);
7609 g_node_append (node, child);
7610 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7611 qtdemux_parse_node (qtdemux, child, buf, len);
7619 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7622 int len = QT_UINT32 (xdxt->data);
7623 guint8 *buf = xdxt->data;
7624 guint8 *end = buf + len;
7627 /* skip size and type */
7635 size = QT_UINT32 (buf);
7636 type = QT_FOURCC (buf + 4);
7638 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7640 if (buf + size > end || size <= 0)
7646 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7647 GST_FOURCC_ARGS (type));
7651 buffer = gst_buffer_new_and_alloc (size);
7652 gst_buffer_fill (buffer, 0, buf, size);
7653 stream->buffers = g_slist_append (stream->buffers, buffer);
7654 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7657 buffer = gst_buffer_new_and_alloc (size);
7658 gst_buffer_fill (buffer, 0, buf, size);
7659 stream->buffers = g_slist_append (stream->buffers, buffer);
7660 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7663 buffer = gst_buffer_new_and_alloc (size);
7664 gst_buffer_fill (buffer, 0, buf, size);
7665 stream->buffers = g_slist_append (stream->buffers, buffer);
7666 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7669 GST_WARNING_OBJECT (qtdemux,
7670 "unknown theora cookie %" GST_FOURCC_FORMAT,
7671 GST_FOURCC_ARGS (type));
7680 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7684 guint32 node_length = 0;
7685 const QtNodeType *type;
7688 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7690 if (G_UNLIKELY (length < 8))
7691 goto not_enough_data;
7693 node_length = QT_UINT32 (buffer);
7694 fourcc = QT_FOURCC (buffer + 4);
7696 /* ignore empty nodes */
7697 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7700 type = qtdemux_type_get (fourcc);
7702 end = buffer + length;
7704 GST_LOG_OBJECT (qtdemux,
7705 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7706 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7708 if (node_length > length)
7709 goto broken_atom_size;
7711 if (type->flags & QT_FLAG_CONTAINER) {
7712 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7717 if (node_length < 20) {
7718 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7721 GST_DEBUG_OBJECT (qtdemux,
7722 "parsing stsd (sample table, sample description) atom");
7723 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7724 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7735 /* also read alac (or whatever) in stead of mp4a in the following,
7736 * since a similar layout is used in other cases as well */
7737 if (fourcc == FOURCC_mp4a)
7739 else if (fourcc == FOURCC_fLaC)
7744 /* There are two things we might encounter here: a true mp4a atom, and
7745 an mp4a entry in an stsd atom. The latter is what we're interested
7746 in, and it looks like an atom, but isn't really one. The true mp4a
7747 atom is short, so we detect it based on length here. */
7748 if (length < min_size) {
7749 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7750 GST_FOURCC_ARGS (fourcc));
7754 /* 'version' here is the sound sample description version. Types 0 and
7755 1 are documented in the QTFF reference, but type 2 is not: it's
7756 described in Apple header files instead (struct SoundDescriptionV2
7758 version = QT_UINT16 (buffer + 16);
7760 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7761 GST_FOURCC_ARGS (fourcc), version);
7763 /* parse any esds descriptors */
7775 GST_WARNING_OBJECT (qtdemux,
7776 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7777 GST_FOURCC_ARGS (fourcc), version);
7782 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7808 /* codec_data is contained inside these atoms, which all have
7809 * the same format. */
7810 /* video sample description size is 86 bytes without extension.
7811 * node_length have to be bigger than 86 bytes because video sample
7812 * description can include extenstions such as esds, fiel, glbl, etc. */
7813 if (node_length < 86) {
7814 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7815 " sample description length too short (%u < 86)",
7816 GST_FOURCC_ARGS (fourcc), node_length);
7820 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7821 GST_FOURCC_ARGS (fourcc));
7823 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7825 * revision level (2 bytes) : must be set to 0. */
7826 version = QT_UINT32 (buffer + 16);
7827 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7829 /* compressor name : PASCAL string and informative purposes
7830 * first byte : the number of bytes to be displayed.
7831 * it has to be less than 32 because it is reserved
7832 * space of 32 bytes total including itself. */
7833 str_len = QT_UINT8 (buffer + 50);
7835 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7836 (char *) buffer + 51);
7838 GST_WARNING_OBJECT (qtdemux,
7839 "compressorname length too big (%u > 31)", str_len);
7841 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7843 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7848 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7850 /* You are reading this correctly. QTFF specifies that the
7851 * metadata atom is a short atom, whereas ISO BMFF specifies
7852 * it's a full atom. But since so many people are doing things
7853 * differently, we actually peek into the atom to see which
7856 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7857 GST_FOURCC_ARGS (fourcc));
7860 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
7861 /* Variant 1: What QTFF specifies. 'meta' is a short header which
7862 * starts with a 'hdlr' atom */
7863 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7864 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
7865 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
7866 * with version/flags both set to zero */
7867 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7869 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
7874 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7875 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7876 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7885 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7886 GST_FOURCC_ARGS (fourcc));
7890 version = QT_UINT32 (buffer + 12);
7891 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7898 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7903 if (length < offset) {
7904 GST_WARNING_OBJECT (qtdemux,
7905 "skipping too small %" GST_FOURCC_FORMAT " box",
7906 GST_FOURCC_ARGS (fourcc));
7909 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7915 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7920 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7925 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7929 if (!strcmp (type->name, "unknown"))
7930 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7934 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7935 GST_FOURCC_ARGS (fourcc));
7941 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7942 (_("This file is corrupt and cannot be played.")),
7943 ("Not enough data for an atom header, got only %u bytes", length));
7948 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7949 (_("This file is corrupt and cannot be played.")),
7950 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7951 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7958 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7962 guint32 child_fourcc;
7964 for (child = g_node_first_child (node); child;
7965 child = g_node_next_sibling (child)) {
7966 buffer = (guint8 *) child->data;
7968 child_fourcc = QT_FOURCC (buffer + 4);
7970 if (G_UNLIKELY (child_fourcc == fourcc)) {
7978 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7979 GstByteReader * parser)
7983 guint32 child_fourcc, child_len;
7985 for (child = g_node_first_child (node); child;
7986 child = g_node_next_sibling (child)) {
7987 buffer = (guint8 *) child->data;
7989 child_len = QT_UINT32 (buffer);
7990 child_fourcc = QT_FOURCC (buffer + 4);
7992 if (G_UNLIKELY (child_fourcc == fourcc)) {
7993 if (G_UNLIKELY (child_len < (4 + 4)))
7995 /* FIXME: must verify if atom length < parent atom length */
7996 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8004 qtdemux_tree_get_child_by_index (GNode * node, guint index)
8006 return g_node_nth_child (node, index);
8010 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
8011 GstByteReader * parser)
8015 guint32 child_fourcc, child_len;
8017 for (child = g_node_next_sibling (node); child;
8018 child = g_node_next_sibling (child)) {
8019 buffer = (guint8 *) child->data;
8021 child_fourcc = QT_FOURCC (buffer + 4);
8023 if (child_fourcc == fourcc) {
8025 child_len = QT_UINT32 (buffer);
8026 if (G_UNLIKELY (child_len < (4 + 4)))
8028 /* FIXME: must verify if atom length < parent atom length */
8029 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8038 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
8040 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
8044 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8046 /* FIXME: This can only reliably work if demuxers have a
8047 * separate streaming thread per srcpad. This should be
8048 * done in a demuxer base class, which integrates parts
8051 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8056 query = gst_query_new_allocation (stream->caps, FALSE);
8058 if (!gst_pad_peer_query (stream->pad, query)) {
8059 /* not a problem, just debug a little */
8060 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8063 if (stream->allocator)
8064 gst_object_unref (stream->allocator);
8066 if (gst_query_get_n_allocation_params (query) > 0) {
8067 /* try the allocator */
8068 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8070 stream->use_allocator = TRUE;
8072 stream->allocator = NULL;
8073 gst_allocation_params_init (&stream->params);
8074 stream->use_allocator = FALSE;
8076 gst_query_unref (query);
8081 pad_query (const GValue * item, GValue * value, gpointer user_data)
8083 GstPad *pad = g_value_get_object (item);
8084 GstQuery *query = user_data;
8087 res = gst_pad_peer_query (pad, query);
8090 g_value_set_boolean (value, TRUE);
8094 GST_INFO_OBJECT (pad, "pad peer query failed");
8099 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8100 GstPadDirection direction)
8103 GstIteratorFoldFunction func = pad_query;
8104 GValue res = { 0, };
8106 g_value_init (&res, G_TYPE_BOOLEAN);
8107 g_value_set_boolean (&res, FALSE);
8110 if (direction == GST_PAD_SRC)
8111 it = gst_element_iterate_src_pads (element);
8113 it = gst_element_iterate_sink_pads (element);
8115 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8116 gst_iterator_resync (it);
8118 gst_iterator_free (it);
8120 return g_value_get_boolean (&res);
8124 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8125 QtDemuxStream * stream)
8129 GstElement *element = GST_ELEMENT (qtdemux);
8131 gchar **filtered_sys_ids;
8132 GValue event_list = G_VALUE_INIT;
8135 /* 1. Check if we already have the context. */
8136 if (qtdemux->preferred_protection_system_id != NULL) {
8137 GST_LOG_OBJECT (element,
8138 "already have the protection context, no need to request it again");
8142 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8143 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8144 (const gchar **) qtdemux->protection_system_ids->pdata);
8146 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8147 qtdemux->protection_system_ids->len - 1);
8148 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8149 "decryptors for %u of them, running context request",
8150 qtdemux->protection_system_ids->len,
8151 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8154 if (stream->protection_scheme_event_queue.length) {
8155 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8156 stream->protection_scheme_event_queue.length);
8157 walk = stream->protection_scheme_event_queue.tail;
8159 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8160 qtdemux->protection_event_queue.length);
8161 walk = qtdemux->protection_event_queue.tail;
8164 g_value_init (&event_list, GST_TYPE_LIST);
8165 for (; walk; walk = g_list_previous (walk)) {
8166 GValue *event_value = g_new0 (GValue, 1);
8167 g_value_init (event_value, GST_TYPE_EVENT);
8168 g_value_set_boxed (event_value, walk->data);
8169 gst_value_list_append_and_take_value (&event_list, event_value);
8172 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8173 * check if downstream already has a context of the specific type
8174 * 2b) Query upstream as above.
8176 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8177 st = gst_query_writable_structure (query);
8178 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8179 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8181 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8182 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8183 gst_query_parse_context (query, &ctxt);
8184 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8185 gst_element_set_context (element, ctxt);
8186 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8187 gst_query_parse_context (query, &ctxt);
8188 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8189 gst_element_set_context (element, ctxt);
8191 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8192 * the required context type and afterwards check if a
8193 * usable context was set now as in 1). The message could
8194 * be handled by the parent bins of the element and the
8199 GST_INFO_OBJECT (element, "posting need context message");
8200 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8201 "drm-preferred-decryption-system-id");
8202 st = (GstStructure *) gst_message_get_structure (msg);
8203 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8204 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8207 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8208 gst_element_post_message (element, msg);
8211 g_strfreev (filtered_sys_ids);
8212 g_value_unset (&event_list);
8213 gst_query_unref (query);
8217 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8218 QtDemuxStream * stream)
8221 const gchar *selected_system = NULL;
8223 g_return_val_if_fail (qtdemux != NULL, FALSE);
8224 g_return_val_if_fail (stream != NULL, FALSE);
8225 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8228 if (stream->protection_scheme_type != FOURCC_cenc) {
8229 GST_ERROR_OBJECT (qtdemux,
8230 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8231 GST_FOURCC_ARGS (stream->protection_scheme_type));
8234 if (qtdemux->protection_system_ids == NULL) {
8235 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
8236 "cenc protection system information has been found");
8240 gst_qtdemux_request_protection_context (qtdemux, stream);
8241 if (qtdemux->preferred_protection_system_id != NULL) {
8242 const gchar *preferred_system_array[] =
8243 { qtdemux->preferred_protection_system_id, NULL };
8245 selected_system = gst_protection_select_system (preferred_system_array);
8247 if (selected_system) {
8248 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8249 qtdemux->preferred_protection_system_id);
8251 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8252 "because there is no available decryptor",
8253 qtdemux->preferred_protection_system_id);
8257 if (!selected_system) {
8258 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8259 selected_system = gst_protection_select_system ((const gchar **)
8260 qtdemux->protection_system_ids->pdata);
8261 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8262 qtdemux->protection_system_ids->len - 1);
8265 if (!selected_system) {
8266 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8267 "suitable decryptor element has been found");
8271 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8274 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8275 if (!gst_structure_has_name (s, "application/x-cenc")) {
8276 gst_structure_set (s,
8277 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8278 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8280 gst_structure_set_name (s, "application/x-cenc");
8286 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8288 if (stream->subtype == FOURCC_vide) {
8289 /* fps is calculated base on the duration of the average framerate since
8290 * qt does not have a fixed framerate. */
8291 gboolean fps_available = TRUE;
8292 guint32 first_duration = 0;
8294 if (stream->n_samples > 0)
8295 first_duration = stream->samples[0].duration;
8297 if ((stream->n_samples == 1 && first_duration == 0)
8298 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8300 CUR_STREAM (stream)->fps_n = 0;
8301 CUR_STREAM (stream)->fps_d = 1;
8303 if (stream->duration == 0 || stream->n_samples < 2) {
8304 CUR_STREAM (stream)->fps_n = stream->timescale;
8305 CUR_STREAM (stream)->fps_d = 1;
8306 fps_available = FALSE;
8308 GstClockTime avg_duration;
8312 /* duration and n_samples can be updated for fragmented format
8313 * so, framerate of fragmented format is calculated using data in a moof */
8314 if (qtdemux->fragmented && stream->n_samples_moof > 0
8315 && stream->duration_moof > 0) {
8316 n_samples = stream->n_samples_moof;
8317 duration = stream->duration_moof;
8319 n_samples = stream->n_samples;
8320 duration = stream->duration;
8323 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8324 /* stream->duration is guint64, timescale, n_samples are guint32 */
8326 gst_util_uint64_scale_round (duration -
8327 first_duration, GST_SECOND,
8328 (guint64) (stream->timescale) * (n_samples - 1));
8330 GST_LOG_OBJECT (qtdemux,
8331 "Calculating avg sample duration based on stream (or moof) duration %"
8333 " minus first sample %u, leaving %d samples gives %"
8334 GST_TIME_FORMAT, duration, first_duration,
8335 n_samples - 1, GST_TIME_ARGS (avg_duration));
8337 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
8338 &CUR_STREAM (stream)->fps_d);
8340 GST_DEBUG_OBJECT (qtdemux,
8341 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8342 stream->timescale, CUR_STREAM (stream)->fps_n,
8343 CUR_STREAM (stream)->fps_d);
8347 if (CUR_STREAM (stream)->caps) {
8348 CUR_STREAM (stream)->caps =
8349 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8351 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8352 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8353 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8354 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8356 /* set framerate if calculated framerate is reliable */
8357 if (fps_available) {
8358 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8359 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8360 CUR_STREAM (stream)->fps_d, NULL);
8363 /* calculate pixel-aspect-ratio using display width and height */
8364 GST_DEBUG_OBJECT (qtdemux,
8365 "video size %dx%d, target display size %dx%d",
8366 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8367 stream->display_width, stream->display_height);
8368 /* qt file might have pasp atom */
8369 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8370 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8371 CUR_STREAM (stream)->par_h);
8372 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8373 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8374 CUR_STREAM (stream)->par_h, NULL);
8375 } else if (stream->display_width > 0 && stream->display_height > 0
8376 && CUR_STREAM (stream)->width > 0
8377 && CUR_STREAM (stream)->height > 0) {
8380 /* calculate the pixel aspect ratio using the display and pixel w/h */
8381 n = stream->display_width * CUR_STREAM (stream)->height;
8382 d = stream->display_height * CUR_STREAM (stream)->width;
8385 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8386 CUR_STREAM (stream)->par_w = n;
8387 CUR_STREAM (stream)->par_h = d;
8388 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8389 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8390 CUR_STREAM (stream)->par_h, NULL);
8393 if (CUR_STREAM (stream)->interlace_mode > 0) {
8394 if (CUR_STREAM (stream)->interlace_mode == 1) {
8395 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8396 G_TYPE_STRING, "progressive", NULL);
8397 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8398 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8399 G_TYPE_STRING, "interleaved", NULL);
8400 if (CUR_STREAM (stream)->field_order == 9) {
8401 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8402 G_TYPE_STRING, "top-field-first", NULL);
8403 } else if (CUR_STREAM (stream)->field_order == 14) {
8404 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8405 G_TYPE_STRING, "bottom-field-first", NULL);
8410 /* Create incomplete colorimetry here if needed */
8411 if (CUR_STREAM (stream)->colorimetry.range ||
8412 CUR_STREAM (stream)->colorimetry.matrix ||
8413 CUR_STREAM (stream)->colorimetry.transfer
8414 || CUR_STREAM (stream)->colorimetry.primaries) {
8415 gchar *colorimetry =
8416 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8417 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8418 G_TYPE_STRING, colorimetry, NULL);
8419 g_free (colorimetry);
8422 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8423 guint par_w = 1, par_h = 1;
8425 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8426 par_w = CUR_STREAM (stream)->par_w;
8427 par_h = CUR_STREAM (stream)->par_h;
8430 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8431 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8433 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8436 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8437 "multiview-mode", G_TYPE_STRING,
8438 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8439 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8440 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8445 else if (stream->subtype == FOURCC_soun) {
8446 if (CUR_STREAM (stream)->caps) {
8447 CUR_STREAM (stream)->caps =
8448 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8449 if (CUR_STREAM (stream)->rate > 0)
8450 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8451 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8452 if (CUR_STREAM (stream)->n_channels > 0)
8453 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8454 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8455 if (CUR_STREAM (stream)->n_channels > 2) {
8456 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8457 * correctly; this is just the minimum we can do - assume
8458 * we don't actually have any channel positions. */
8459 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8460 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8466 GstCaps *prev_caps = NULL;
8468 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8469 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8470 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8471 gst_pad_set_active (stream->pad, TRUE);
8473 gst_pad_use_fixed_caps (stream->pad);
8475 if (stream->protected) {
8476 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8477 GST_ERROR_OBJECT (qtdemux,
8478 "Failed to configure protected stream caps.");
8483 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8484 CUR_STREAM (stream)->caps);
8485 if (stream->new_stream) {
8487 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8490 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8493 gst_event_parse_stream_flags (event, &stream_flags);
8494 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8495 qtdemux->have_group_id = TRUE;
8497 qtdemux->have_group_id = FALSE;
8498 gst_event_unref (event);
8499 } else if (!qtdemux->have_group_id) {
8500 qtdemux->have_group_id = TRUE;
8501 qtdemux->group_id = gst_util_group_id_next ();
8504 stream->new_stream = FALSE;
8505 event = gst_event_new_stream_start (stream->stream_id);
8506 if (qtdemux->have_group_id)
8507 gst_event_set_group_id (event, qtdemux->group_id);
8508 if (stream->disabled)
8509 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8510 if (CUR_STREAM (stream)->sparse) {
8511 stream_flags |= GST_STREAM_FLAG_SPARSE;
8513 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8515 gst_event_set_stream_flags (event, stream_flags);
8516 gst_pad_push_event (stream->pad, event);
8519 prev_caps = gst_pad_get_current_caps (stream->pad);
8521 if (CUR_STREAM (stream)->caps) {
8523 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8524 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8525 CUR_STREAM (stream)->caps);
8526 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8528 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8531 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8535 gst_caps_unref (prev_caps);
8536 stream->new_caps = FALSE;
8542 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8543 QtDemuxStream * stream)
8545 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8548 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8549 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8550 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8551 stream->stsd_entries_length)) {
8552 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8553 (_("This file is invalid and cannot be played.")),
8554 ("New sample description id is out of bounds (%d >= %d)",
8555 stream->stsd_sample_description_id, stream->stsd_entries_length));
8557 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8558 stream->new_caps = TRUE;
8563 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8564 QtDemuxStream * stream, GstTagList * list)
8566 gboolean ret = TRUE;
8567 /* consistent default for push based mode */
8568 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8570 if (stream->subtype == FOURCC_vide) {
8571 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8574 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8577 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8578 gst_object_unref (stream->pad);
8584 qtdemux->n_video_streams++;
8585 } else if (stream->subtype == FOURCC_soun) {
8586 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8589 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8591 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8592 gst_object_unref (stream->pad);
8597 qtdemux->n_audio_streams++;
8598 } else if (stream->subtype == FOURCC_strm) {
8599 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8600 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8601 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8602 || stream->subtype == FOURCC_clcp) {
8603 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8606 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8608 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8609 gst_object_unref (stream->pad);
8614 qtdemux->n_sub_streams++;
8615 } else if (CUR_STREAM (stream)->caps) {
8616 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8619 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8621 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8622 gst_object_unref (stream->pad);
8627 qtdemux->n_video_streams++;
8629 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8636 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8637 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8638 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8639 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8641 if (stream->stream_tags)
8642 gst_tag_list_unref (stream->stream_tags);
8643 stream->stream_tags = list;
8645 /* global tags go on each pad anyway */
8646 stream->send_global_tags = TRUE;
8647 /* send upstream GST_EVENT_PROTECTION events that were received before
8648 this source pad was created */
8649 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8650 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8654 gst_tag_list_unref (list);
8658 /* find next atom with @fourcc starting at @offset */
8659 static GstFlowReturn
8660 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8661 guint64 * length, guint32 fourcc)
8667 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8668 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8674 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8675 if (G_UNLIKELY (ret != GST_FLOW_OK))
8677 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8680 gst_buffer_unref (buf);
8683 gst_buffer_map (buf, &map, GST_MAP_READ);
8684 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8685 gst_buffer_unmap (buf, &map);
8686 gst_buffer_unref (buf);
8688 if (G_UNLIKELY (*length == 0)) {
8689 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8690 ret = GST_FLOW_ERROR;
8694 if (lfourcc == fourcc) {
8695 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8699 GST_LOG_OBJECT (qtdemux,
8700 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8701 GST_FOURCC_ARGS (fourcc), *offset);
8710 /* might simply have had last one */
8711 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8716 /* should only do something in pull mode */
8717 /* call with OBJECT lock */
8718 static GstFlowReturn
8719 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8721 guint64 length, offset;
8722 GstBuffer *buf = NULL;
8723 GstFlowReturn ret = GST_FLOW_OK;
8724 GstFlowReturn res = GST_FLOW_OK;
8727 offset = qtdemux->moof_offset;
8728 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8731 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8732 return GST_FLOW_EOS;
8735 /* best not do pull etc with lock held */
8736 GST_OBJECT_UNLOCK (qtdemux);
8738 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8739 if (ret != GST_FLOW_OK)
8742 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8743 if (G_UNLIKELY (ret != GST_FLOW_OK))
8745 gst_buffer_map (buf, &map, GST_MAP_READ);
8746 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8747 gst_buffer_unmap (buf, &map);
8748 gst_buffer_unref (buf);
8753 gst_buffer_unmap (buf, &map);
8754 gst_buffer_unref (buf);
8758 /* look for next moof */
8759 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8760 if (G_UNLIKELY (ret != GST_FLOW_OK))
8764 GST_OBJECT_LOCK (qtdemux);
8766 qtdemux->moof_offset = offset;
8772 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8774 res = GST_FLOW_ERROR;
8779 /* maybe upstream temporarily flushing */
8780 if (ret != GST_FLOW_FLUSHING) {
8781 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8784 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8785 /* resume at current position next time */
8792 /* initialise bytereaders for stbl sub-atoms */
8794 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8796 stream->stbl_index = -1; /* no samples have yet been parsed */
8797 stream->sample_index = -1;
8799 /* time-to-sample atom */
8800 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8803 /* copy atom data into a new buffer for later use */
8804 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8806 /* skip version + flags */
8807 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8808 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8810 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8812 /* make sure there's enough data */
8813 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8814 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8815 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8816 stream->n_sample_times);
8817 if (!stream->n_sample_times)
8821 /* sync sample atom */
8822 stream->stps_present = FALSE;
8823 if ((stream->stss_present =
8824 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8825 &stream->stss) ? TRUE : FALSE) == TRUE) {
8826 /* copy atom data into a new buffer for later use */
8827 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8829 /* skip version + flags */
8830 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8831 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8834 if (stream->n_sample_syncs) {
8835 /* make sure there's enough data */
8836 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8840 /* partial sync sample atom */
8841 if ((stream->stps_present =
8842 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8843 &stream->stps) ? TRUE : FALSE) == TRUE) {
8844 /* copy atom data into a new buffer for later use */
8845 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8847 /* skip version + flags */
8848 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8849 !gst_byte_reader_get_uint32_be (&stream->stps,
8850 &stream->n_sample_partial_syncs))
8853 /* if there are no entries, the stss table contains the real
8855 if (stream->n_sample_partial_syncs) {
8856 /* make sure there's enough data */
8857 if (!qt_atom_parser_has_chunks (&stream->stps,
8858 stream->n_sample_partial_syncs, 4))
8865 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8868 /* copy atom data into a new buffer for later use */
8869 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8871 /* skip version + flags */
8872 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8873 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8876 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8879 if (!stream->n_samples)
8882 /* sample-to-chunk atom */
8883 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8886 /* copy atom data into a new buffer for later use */
8887 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8889 /* skip version + flags */
8890 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8891 !gst_byte_reader_get_uint32_be (&stream->stsc,
8892 &stream->n_samples_per_chunk))
8895 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8896 stream->n_samples_per_chunk);
8898 /* make sure there's enough data */
8899 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8905 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8906 stream->co_size = sizeof (guint32);
8907 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8909 stream->co_size = sizeof (guint64);
8913 /* copy atom data into a new buffer for later use */
8914 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8916 /* skip version + flags */
8917 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8920 /* chunks_are_samples == TRUE means treat chunks as samples */
8921 stream->chunks_are_samples = stream->sample_size
8922 && !CUR_STREAM (stream)->sampled;
8923 if (stream->chunks_are_samples) {
8924 /* treat chunks as samples */
8925 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8928 /* skip number of entries */
8929 if (!gst_byte_reader_skip (&stream->stco, 4))
8932 /* make sure there are enough data in the stsz atom */
8933 if (!stream->sample_size) {
8934 /* different sizes for each sample */
8935 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8940 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8941 stream->n_samples, (guint) sizeof (QtDemuxSample),
8942 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8944 if (stream->n_samples >=
8945 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8946 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8947 "be larger than %uMB (broken file?)", stream->n_samples,
8948 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8952 g_assert (stream->samples == NULL);
8953 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8954 if (!stream->samples) {
8955 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8960 /* composition time-to-sample */
8961 if ((stream->ctts_present =
8962 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8963 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8964 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8966 /* copy atom data into a new buffer for later use */
8967 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8969 /* skip version + flags */
8970 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8971 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8972 &stream->n_composition_times))
8975 /* make sure there's enough data */
8976 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8980 /* This is optional, if missing we iterate the ctts */
8981 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8982 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8983 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8984 g_free ((gpointer) cslg.data);
8988 gint32 cslg_least = 0;
8989 guint num_entries, pos;
8992 pos = gst_byte_reader_get_pos (&stream->ctts);
8993 num_entries = stream->n_composition_times;
8995 stream->cslg_shift = 0;
8997 for (i = 0; i < num_entries; i++) {
9000 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9001 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9002 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9003 * slightly inaccurate PTS could be more usable than corrupted one */
9004 if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9005 GST_WARNING_OBJECT (qtdemux,
9006 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9007 " larger than duration %" G_GUINT64_FORMAT,
9008 offset, stream->duration);
9010 stream->cslg_shift = 0;
9011 stream->ctts_present = FALSE;
9015 if (offset < cslg_least)
9016 cslg_least = offset;
9020 stream->cslg_shift = ABS (cslg_least);
9022 stream->cslg_shift = 0;
9024 /* reset the reader so we can generate sample table */
9025 gst_byte_reader_set_pos (&stream->ctts, pos);
9028 /* Ensure the cslg_shift value is consistent so we can use it
9029 * unconditionnally to produce TS and Segment */
9030 stream->cslg_shift = 0;
9037 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9038 (_("This file is corrupt and cannot be played.")), (NULL));
9043 gst_qtdemux_stbl_free (stream);
9044 if (!qtdemux->fragmented) {
9045 /* not quite good */
9046 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9049 /* may pick up samples elsewhere */
9055 /* collect samples from the next sample to be parsed up to sample @n for @stream
9056 * by reading the info from @stbl
9058 * This code can be executed from both the streaming thread and the seeking
9059 * thread so it takes the object lock to protect itself
9062 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9065 QtDemuxSample *samples, *first, *cur, *last;
9066 guint32 n_samples_per_chunk;
9069 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9070 GST_FOURCC_FORMAT ", pad %s",
9071 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9072 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9074 n_samples = stream->n_samples;
9077 goto out_of_samples;
9079 GST_OBJECT_LOCK (qtdemux);
9080 if (n <= stream->stbl_index)
9081 goto already_parsed;
9083 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9085 if (!stream->stsz.data) {
9086 /* so we already parsed and passed all the moov samples;
9087 * onto fragmented ones */
9088 g_assert (qtdemux->fragmented);
9092 /* pointer to the sample table */
9093 samples = stream->samples;
9095 /* starts from -1, moves to the next sample index to parse */
9096 stream->stbl_index++;
9098 /* keep track of the first and last sample to fill */
9099 first = &samples[stream->stbl_index];
9102 if (!stream->chunks_are_samples) {
9103 /* set the sample sizes */
9104 if (stream->sample_size == 0) {
9105 /* different sizes for each sample */
9106 for (cur = first; cur <= last; cur++) {
9107 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9108 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9109 (guint) (cur - samples), cur->size);
9112 /* samples have the same size */
9113 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9114 for (cur = first; cur <= last; cur++)
9115 cur->size = stream->sample_size;
9119 n_samples_per_chunk = stream->n_samples_per_chunk;
9122 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9125 if (stream->stsc_chunk_index >= stream->last_chunk
9126 || stream->stsc_chunk_index < stream->first_chunk) {
9127 stream->first_chunk =
9128 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9129 stream->samples_per_chunk =
9130 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9132 stream->stsd_sample_description_id =
9133 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9135 /* chunk numbers are counted from 1 it seems */
9136 if (G_UNLIKELY (stream->first_chunk == 0))
9139 --stream->first_chunk;
9141 /* the last chunk of each entry is calculated by taking the first chunk
9142 * of the next entry; except if there is no next, where we fake it with
9144 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9145 stream->last_chunk = G_MAXUINT32;
9147 stream->last_chunk =
9148 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9149 if (G_UNLIKELY (stream->last_chunk == 0))
9152 --stream->last_chunk;
9155 GST_LOG_OBJECT (qtdemux,
9156 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9157 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9158 stream->samples_per_chunk, stream->stsd_sample_description_id);
9160 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9163 if (stream->last_chunk != G_MAXUINT32) {
9164 if (!qt_atom_parser_peek_sub (&stream->stco,
9165 stream->first_chunk * stream->co_size,
9166 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9171 stream->co_chunk = stream->stco;
9172 if (!gst_byte_reader_skip (&stream->co_chunk,
9173 stream->first_chunk * stream->co_size))
9177 stream->stsc_chunk_index = stream->first_chunk;
9180 last_chunk = stream->last_chunk;
9182 if (stream->chunks_are_samples) {
9183 cur = &samples[stream->stsc_chunk_index];
9185 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9188 stream->stsc_chunk_index = j;
9193 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9196 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9197 "%" G_GUINT64_FORMAT, j, cur->offset);
9199 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9200 CUR_STREAM (stream)->bytes_per_frame > 0) {
9202 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9203 CUR_STREAM (stream)->samples_per_frame *
9204 CUR_STREAM (stream)->bytes_per_frame;
9206 cur->size = stream->samples_per_chunk;
9209 GST_DEBUG_OBJECT (qtdemux,
9210 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9211 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9212 stream->stco_sample_index)), cur->size);
9214 cur->timestamp = stream->stco_sample_index;
9215 cur->duration = stream->samples_per_chunk;
9216 cur->keyframe = TRUE;
9219 stream->stco_sample_index += stream->samples_per_chunk;
9221 stream->stsc_chunk_index = j;
9223 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9224 guint32 samples_per_chunk;
9225 guint64 chunk_offset;
9227 if (!stream->stsc_sample_index
9228 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9229 &stream->chunk_offset))
9232 samples_per_chunk = stream->samples_per_chunk;
9233 chunk_offset = stream->chunk_offset;
9235 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9236 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9237 G_GUINT64_FORMAT " and size %d",
9238 (guint) (cur - samples), chunk_offset, cur->size);
9240 cur->offset = chunk_offset;
9241 chunk_offset += cur->size;
9244 if (G_UNLIKELY (cur > last)) {
9246 stream->stsc_sample_index = k + 1;
9247 stream->chunk_offset = chunk_offset;
9248 stream->stsc_chunk_index = j;
9252 stream->stsc_sample_index = 0;
9254 stream->stsc_chunk_index = j;
9256 stream->stsc_index++;
9259 if (stream->chunks_are_samples)
9263 guint32 n_sample_times;
9265 n_sample_times = stream->n_sample_times;
9268 for (i = stream->stts_index; i < n_sample_times; i++) {
9269 guint32 stts_samples;
9270 gint32 stts_duration;
9273 if (stream->stts_sample_index >= stream->stts_samples
9274 || !stream->stts_sample_index) {
9276 stream->stts_samples =
9277 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9278 stream->stts_duration =
9279 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9281 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9282 i, stream->stts_samples, stream->stts_duration);
9284 stream->stts_sample_index = 0;
9287 stts_samples = stream->stts_samples;
9288 stts_duration = stream->stts_duration;
9289 stts_time = stream->stts_time;
9291 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9292 GST_DEBUG_OBJECT (qtdemux,
9293 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9294 (guint) (cur - samples), j,
9295 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9297 cur->timestamp = stts_time;
9298 cur->duration = stts_duration;
9300 /* avoid 32-bit wrap-around,
9301 * but still mind possible 'negative' duration */
9302 stts_time += (gint64) stts_duration;
9305 if (G_UNLIKELY (cur > last)) {
9307 stream->stts_time = stts_time;
9308 stream->stts_sample_index = j + 1;
9309 if (stream->stts_sample_index >= stream->stts_samples)
9310 stream->stts_index++;
9314 stream->stts_sample_index = 0;
9315 stream->stts_time = stts_time;
9316 stream->stts_index++;
9318 /* fill up empty timestamps with the last timestamp, this can happen when
9319 * the last samples do not decode and so we don't have timestamps for them.
9320 * We however look at the last timestamp to estimate the track length so we
9321 * need something in here. */
9322 for (; cur < last; cur++) {
9323 GST_DEBUG_OBJECT (qtdemux,
9324 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9325 (guint) (cur - samples),
9326 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9327 cur->timestamp = stream->stts_time;
9333 /* sample sync, can be NULL */
9334 if (stream->stss_present == TRUE) {
9335 guint32 n_sample_syncs;
9337 n_sample_syncs = stream->n_sample_syncs;
9339 if (!n_sample_syncs) {
9340 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9341 stream->all_keyframe = TRUE;
9343 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9344 /* note that the first sample is index 1, not 0 */
9347 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9349 if (G_LIKELY (index > 0 && index <= n_samples)) {
9351 samples[index].keyframe = TRUE;
9352 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9353 /* and exit if we have enough samples */
9354 if (G_UNLIKELY (index >= n)) {
9361 stream->stss_index = i;
9364 /* stps marks partial sync frames like open GOP I-Frames */
9365 if (stream->stps_present == TRUE) {
9366 guint32 n_sample_partial_syncs;
9368 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9370 /* if there are no entries, the stss table contains the real
9372 if (n_sample_partial_syncs) {
9373 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9374 /* note that the first sample is index 1, not 0 */
9377 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9379 if (G_LIKELY (index > 0 && index <= n_samples)) {
9381 samples[index].keyframe = TRUE;
9382 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9383 /* and exit if we have enough samples */
9384 if (G_UNLIKELY (index >= n)) {
9391 stream->stps_index = i;
9395 /* no stss, all samples are keyframes */
9396 stream->all_keyframe = TRUE;
9397 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9402 /* composition time to sample */
9403 if (stream->ctts_present == TRUE) {
9404 guint32 n_composition_times;
9406 gint32 ctts_soffset;
9408 /* Fill in the pts_offsets */
9410 n_composition_times = stream->n_composition_times;
9412 for (i = stream->ctts_index; i < n_composition_times; i++) {
9413 if (stream->ctts_sample_index >= stream->ctts_count
9414 || !stream->ctts_sample_index) {
9415 stream->ctts_count =
9416 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9417 stream->ctts_soffset =
9418 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9419 stream->ctts_sample_index = 0;
9422 ctts_count = stream->ctts_count;
9423 ctts_soffset = stream->ctts_soffset;
9425 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9426 cur->pts_offset = ctts_soffset;
9429 if (G_UNLIKELY (cur > last)) {
9431 stream->ctts_sample_index = j + 1;
9435 stream->ctts_sample_index = 0;
9436 stream->ctts_index++;
9440 stream->stbl_index = n;
9441 /* if index has been completely parsed, free data that is no-longer needed */
9442 if (n + 1 == stream->n_samples) {
9443 gst_qtdemux_stbl_free (stream);
9444 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9445 if (qtdemux->pullbased) {
9446 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9447 while (n + 1 == stream->n_samples)
9448 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9452 GST_OBJECT_UNLOCK (qtdemux);
9459 GST_LOG_OBJECT (qtdemux,
9460 "Tried to parse up to sample %u but this sample has already been parsed",
9462 /* if fragmented, there may be more */
9463 if (qtdemux->fragmented && n == stream->stbl_index)
9465 GST_OBJECT_UNLOCK (qtdemux);
9471 GST_LOG_OBJECT (qtdemux,
9472 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9474 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9475 (_("This file is corrupt and cannot be played.")), (NULL));
9480 GST_OBJECT_UNLOCK (qtdemux);
9481 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9482 (_("This file is corrupt and cannot be played.")), (NULL));
9487 /* collect all segment info for @stream.
9490 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9494 /* accept edts if they contain gaps at start and there is only
9495 * one media segment */
9496 gboolean allow_pushbased_edts = TRUE;
9497 gint media_segments_count = 0;
9499 /* parse and prepare segment info from the edit list */
9500 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9501 stream->n_segments = 0;
9502 stream->segments = NULL;
9503 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9506 gint segment_number, entry_size;
9509 const guint8 *buffer;
9513 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9514 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9517 buffer = elst->data;
9519 size = QT_UINT32 (buffer);
9520 /* version, flags, n_segments */
9522 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9525 version = QT_UINT8 (buffer + 8);
9526 entry_size = (version == 1) ? 20 : 12;
9528 n_segments = QT_UINT32 (buffer + 12);
9530 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9531 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9535 /* we might allocate a bit too much, at least allocate 1 segment */
9536 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9538 /* segments always start from 0 */
9542 for (segment_number = 0; segment_number < n_segments; segment_number++) {
9545 gboolean empty_edit = FALSE;
9546 QtDemuxSegment *segment;
9548 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9551 media_time = QT_UINT64 (buffer + 8);
9552 duration = QT_UINT64 (buffer);
9553 if (media_time == G_MAXUINT64)
9556 media_time = QT_UINT32 (buffer + 4);
9557 duration = QT_UINT32 (buffer);
9558 if (media_time == G_MAXUINT32)
9563 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9565 segment = &stream->segments[segment_number];
9567 /* time and duration expressed in global timescale */
9568 segment->time = stime;
9569 if (duration != 0 || empty_edit) {
9570 /* edge case: empty edits with duration=zero are treated here.
9571 * (files should not have these anyway). */
9573 /* add non scaled values so we don't cause roundoff errors */
9575 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9576 segment->duration = stime - segment->time;
9578 /* zero duration does not imply media_start == media_stop
9579 * but, only specify media_start. The edit ends with the track. */
9580 stime = segment->duration = GST_CLOCK_TIME_NONE;
9581 /* Don't allow more edits after this one. */
9582 n_segments = segment_number + 1;
9584 segment->stop_time = stime;
9586 segment->trak_media_start = media_time;
9587 /* media_time expressed in stream timescale */
9589 segment->media_start = media_start;
9590 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9591 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9592 media_segments_count++;
9594 segment->media_start = GST_CLOCK_TIME_NONE;
9595 segment->media_stop = GST_CLOCK_TIME_NONE;
9597 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9599 if (rate_int <= 1) {
9600 /* 0 is not allowed, some programs write 1 instead of the floating point
9602 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9606 segment->rate = rate_int / 65536.0;
9609 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9610 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9611 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9612 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9613 segment_number, GST_TIME_ARGS (segment->time),
9614 GST_TIME_ARGS (segment->duration),
9615 GST_TIME_ARGS (segment->media_start), media_time,
9616 GST_TIME_ARGS (segment->media_stop),
9617 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9619 if (segment->stop_time > qtdemux->segment.stop &&
9620 !qtdemux->upstream_format_is_time) {
9621 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9622 " extends to %" GST_TIME_FORMAT
9623 " past the end of the declared movie duration %" GST_TIME_FORMAT
9624 " movie segment will be extended", segment_number,
9625 GST_TIME_ARGS (segment->stop_time),
9626 GST_TIME_ARGS (qtdemux->segment.stop));
9627 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
9630 buffer += entry_size;
9632 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
9633 stream->n_segments = n_segments;
9634 if (media_segments_count != 1)
9635 allow_pushbased_edts = FALSE;
9639 /* push based does not handle segments, so act accordingly here,
9640 * and warn if applicable */
9641 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9642 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9643 /* remove and use default one below, we stream like it anyway */
9644 g_free (stream->segments);
9645 stream->segments = NULL;
9646 stream->n_segments = 0;
9649 /* no segments, create one to play the complete trak */
9650 if (stream->n_segments == 0) {
9651 GstClockTime stream_duration =
9652 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9654 if (stream->segments == NULL)
9655 stream->segments = g_new (QtDemuxSegment, 1);
9657 /* represent unknown our way */
9658 if (stream_duration == 0)
9659 stream_duration = GST_CLOCK_TIME_NONE;
9661 stream->segments[0].time = 0;
9662 stream->segments[0].stop_time = stream_duration;
9663 stream->segments[0].duration = stream_duration;
9664 stream->segments[0].media_start = 0;
9665 stream->segments[0].media_stop = stream_duration;
9666 stream->segments[0].rate = 1.0;
9667 stream->segments[0].trak_media_start = 0;
9669 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9670 GST_TIME_ARGS (stream_duration));
9671 stream->n_segments = 1;
9672 stream->dummy_segment = TRUE;
9674 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9680 * Parses the stsd atom of a svq3 trak looking for
9681 * the SMI and gama atoms.
9684 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9685 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9687 const guint8 *_gamma = NULL;
9688 GstBuffer *_seqh = NULL;
9689 const guint8 *stsd_data = stsd_entry_data;
9690 guint32 length = QT_UINT32 (stsd_data);
9694 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9700 version = QT_UINT16 (stsd_data);
9705 while (length > 8) {
9706 guint32 fourcc, size;
9708 size = QT_UINT32 (stsd_data);
9709 fourcc = QT_FOURCC (stsd_data + 4);
9710 data = stsd_data + 8;
9713 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9714 "svq3 atom parsing");
9723 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9724 " for gama atom, expected 12", size);
9729 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9731 if (_seqh != NULL) {
9732 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9733 " found, ignoring");
9735 seqh_size = QT_UINT32 (data + 4);
9736 if (seqh_size > 0) {
9737 _seqh = gst_buffer_new_and_alloc (seqh_size);
9738 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9745 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9746 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9750 if (size <= length) {
9756 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9759 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9760 G_GUINT16_FORMAT, version);
9771 gst_buffer_unref (_seqh);
9776 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9783 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9784 * atom that might contain a 'data' atom with the rtsp uri.
9785 * This case was reported in bug #597497, some info about
9786 * the hndl atom can be found in TN1195
9788 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9789 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9792 guint32 dref_num_entries = 0;
9793 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9794 gst_byte_reader_skip (&dref, 4) &&
9795 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9798 /* search dref entries for hndl atom */
9799 for (i = 0; i < dref_num_entries; i++) {
9800 guint32 size = 0, type;
9801 guint8 string_len = 0;
9802 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9803 qt_atom_parser_get_fourcc (&dref, &type)) {
9804 if (type == FOURCC_hndl) {
9805 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9807 /* skip data reference handle bytes and the
9808 * following pascal string and some extra 4
9809 * bytes I have no idea what are */
9810 if (!gst_byte_reader_skip (&dref, 4) ||
9811 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9812 !gst_byte_reader_skip (&dref, string_len + 4)) {
9813 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9817 /* iterate over the atoms to find the data atom */
9818 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9822 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9823 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9824 if (atom_type == FOURCC_data) {
9825 const guint8 *uri_aux = NULL;
9827 /* found the data atom that might contain the rtsp uri */
9828 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9829 "hndl atom, interpreting it as an URI");
9830 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9832 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9833 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9835 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9836 "didn't contain a rtsp address");
9838 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9843 /* skipping to the next entry */
9844 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9847 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9854 /* skip to the next entry */
9855 if (!gst_byte_reader_skip (&dref, size - 8))
9858 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9861 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9867 #define AMR_NB_ALL_MODES 0x81ff
9868 #define AMR_WB_ALL_MODES 0x83ff
9870 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9872 /* The 'damr' atom is of the form:
9874 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9875 * 32 b 8 b 16 b 8 b 8 b
9877 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9878 * represents the highest mode used in the stream (and thus the maximum
9879 * bitrate), with a couple of special cases as seen below.
9882 /* Map of frame type ID -> bitrate */
9883 static const guint nb_bitrates[] = {
9884 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9886 static const guint wb_bitrates[] = {
9887 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9893 gst_buffer_map (buf, &map, GST_MAP_READ);
9895 if (map.size != 0x11) {
9896 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9900 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9901 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9902 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9906 mode_set = QT_UINT16 (map.data + 13);
9908 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9909 max_mode = 7 + (wb ? 1 : 0);
9911 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9912 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9914 if (max_mode == -1) {
9915 GST_DEBUG ("No mode indication was found (mode set) = %x",
9920 gst_buffer_unmap (buf, &map);
9921 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9924 gst_buffer_unmap (buf, &map);
9929 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9930 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9933 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9939 if (gst_byte_reader_get_remaining (reader) < 36)
9942 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9943 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9944 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9945 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9946 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9947 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9948 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9949 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9950 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9952 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9953 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9954 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9956 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9957 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9959 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9960 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9967 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9968 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9975 * This macro will only compare value abdegh, it expects cfi to have already
9978 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9979 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9981 /* only handle the cases where the last column has standard values */
9982 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9983 const gchar *rotation_tag = NULL;
9985 /* no rotation needed */
9986 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9988 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9989 rotation_tag = "rotate-90";
9990 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9991 rotation_tag = "rotate-180";
9992 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9993 rotation_tag = "rotate-270";
9995 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9998 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10000 if (rotation_tag != NULL) {
10001 if (*taglist == NULL)
10002 *taglist = gst_tag_list_new_empty ();
10003 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10004 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10007 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10011 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10012 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10013 * Common Encryption (cenc), the function will also parse the tenc box (defined
10014 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10015 * (typically an enc[v|a|t|s] sample entry); the function will set
10016 * @original_fmt to the fourcc of the original unencrypted stream format.
10017 * Returns TRUE if successful; FALSE otherwise. */
10019 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10020 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10026 QtDemuxCencSampleSetInfo *info;
10028 const guint8 *tenc_data;
10030 g_return_val_if_fail (qtdemux != NULL, FALSE);
10031 g_return_val_if_fail (stream != NULL, FALSE);
10032 g_return_val_if_fail (container != NULL, FALSE);
10033 g_return_val_if_fail (original_fmt != NULL, FALSE);
10035 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10036 if (G_UNLIKELY (!sinf)) {
10037 if (stream->protection_scheme_type == FOURCC_cenc) {
10038 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10039 "mandatory for Common Encryption");
10045 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10046 if (G_UNLIKELY (!frma)) {
10047 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10051 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10052 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10053 GST_FOURCC_ARGS (*original_fmt));
10055 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10057 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10060 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10061 stream->protection_scheme_version =
10062 QT_UINT32 ((const guint8 *) schm->data + 16);
10064 GST_DEBUG_OBJECT (qtdemux,
10065 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10066 "protection_scheme_version: %#010x",
10067 GST_FOURCC_ARGS (stream->protection_scheme_type),
10068 stream->protection_scheme_version);
10070 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10072 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10075 if (stream->protection_scheme_type != FOURCC_cenc &&
10076 stream->protection_scheme_type != FOURCC_piff) {
10077 GST_ERROR_OBJECT (qtdemux,
10078 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10079 GST_FOURCC_ARGS (stream->protection_scheme_type));
10083 if (G_UNLIKELY (!stream->protection_scheme_info))
10084 stream->protection_scheme_info =
10085 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10087 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10089 if (stream->protection_scheme_type == FOURCC_cenc) {
10090 guint32 is_encrypted;
10092 const guint8 *default_kid;
10094 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10096 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10097 "which is mandatory for Common Encryption");
10100 tenc_data = (const guint8 *) tenc->data + 12;
10101 is_encrypted = QT_UINT24 (tenc_data);
10102 iv_size = QT_UINT8 (tenc_data + 3);
10103 default_kid = (tenc_data + 4);
10104 qtdemux_update_default_sample_encryption_settings (qtdemux, info,
10105 is_encrypted, iv_size, default_kid);
10106 } else if (stream->protection_scheme_type == FOURCC_piff) {
10108 static const guint8 piff_track_encryption_uuid[] = {
10109 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10110 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10113 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10115 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10116 "which is mandatory for Common Encryption");
10120 tenc_data = (const guint8 *) tenc->data + 8;
10121 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10122 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10123 GST_ERROR_OBJECT (qtdemux,
10124 "Unsupported track encryption box with uuid: %s", box_uuid);
10128 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10129 gst_byte_reader_init (&br, tenc_data, 20);
10130 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10131 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10134 stream->protection_scheme_type = FOURCC_cenc;
10141 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10142 QtDemuxStream ** stream2)
10144 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10147 /* parse the traks.
10148 * With each track we associate a new QtDemuxStream that contains all the info
10150 * traks that do not decode to something (like strm traks) will not have a pad.
10153 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10155 GstByteReader tkhd;
10170 QtDemuxStream *stream = NULL;
10171 const guint8 *stsd_data;
10172 const guint8 *stsd_entry_data;
10173 guint remaining_stsd_len;
10174 guint stsd_entry_count;
10176 guint16 lang_code; /* quicktime lang code or packed iso code */
10178 guint32 tkhd_flags = 0;
10179 guint8 tkhd_version = 0;
10180 guint32 w = 0, h = 0;
10181 guint value_size, stsd_len, len;
10185 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10187 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10188 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10189 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10192 /* pick between 64 or 32 bits */
10193 value_size = tkhd_version == 1 ? 8 : 4;
10194 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10195 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10198 /* Check if current moov has duplicated track_id */
10199 if (qtdemux_find_stream (qtdemux, track_id))
10200 goto existing_stream;
10202 stream = _create_stream (qtdemux, track_id);
10203 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10205 /* need defaults for fragments */
10206 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10208 if ((tkhd_flags & 1) == 0)
10209 stream->disabled = TRUE;
10211 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10212 tkhd_version, tkhd_flags, stream->track_id);
10214 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10217 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10218 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10219 if (qtdemux->major_brand != FOURCC_mjp2 ||
10220 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10224 len = QT_UINT32 ((guint8 *) mdhd->data);
10225 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10226 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10227 if (version == 0x01000000) {
10230 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10231 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10232 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
10236 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10237 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10238 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10241 if (lang_code < 0x400) {
10242 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10243 } else if (lang_code == 0x7fff) {
10244 stream->lang_id[0] = 0; /* unspecified */
10246 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10247 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10248 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10249 stream->lang_id[3] = 0;
10252 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10253 stream->timescale);
10254 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10256 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10257 lang_code, stream->lang_id);
10259 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10262 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10263 /* chapters track reference */
10264 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10266 gsize length = GST_READ_UINT32_BE (chap->data);
10267 if (qtdemux->chapters_track_id)
10268 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10270 if (length >= 12) {
10271 qtdemux->chapters_track_id =
10272 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10277 /* fragmented files may have bogus duration in moov */
10278 if (!qtdemux->fragmented &&
10279 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10280 guint64 tdur1, tdur2;
10282 /* don't overflow */
10283 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10284 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10287 * some of those trailers, nowadays, have prologue images that are
10288 * themselves video tracks as well. I haven't really found a way to
10289 * identify those yet, except for just looking at their duration. */
10290 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10291 GST_WARNING_OBJECT (qtdemux,
10292 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10293 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10294 "found, assuming preview image or something; skipping track",
10295 stream->duration, stream->timescale, qtdemux->duration,
10296 qtdemux->timescale);
10297 gst_qtdemux_stream_unref (stream);
10302 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10305 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10306 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10308 len = QT_UINT32 ((guint8 *) hdlr->data);
10310 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10311 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10312 GST_FOURCC_ARGS (stream->subtype));
10314 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10317 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10320 /*parse svmi header if existing */
10321 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10323 len = QT_UINT32 ((guint8 *) svmi->data);
10324 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10326 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10327 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10328 guint8 frame_type, frame_layout;
10330 /* MPEG-A stereo video */
10331 if (qtdemux->major_brand == FOURCC_ss02)
10332 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10334 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10335 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10336 switch (frame_type) {
10338 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10341 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10344 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10347 /* mode 3 is primary/secondary view sequence, ie
10348 * left/right views in separate tracks. See section 7.2
10349 * of ISO/IEC 23000-11:2009 */
10350 GST_FIXME_OBJECT (qtdemux,
10351 "Implement stereo video in separate streams");
10354 if ((frame_layout & 0x1) == 0)
10355 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10357 GST_LOG_OBJECT (qtdemux,
10358 "StereoVideo: composition type: %u, is_left_first: %u",
10359 frame_type, frame_layout);
10360 stream->multiview_mode = mode;
10361 stream->multiview_flags = flags;
10365 /* parse rest of tkhd */
10366 if (stream->subtype == FOURCC_vide) {
10369 /* version 1 uses some 64-bit ints */
10370 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10373 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10376 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10377 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10380 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10381 &stream->stream_tags);
10385 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10387 stsd_data = (const guint8 *) stsd->data;
10389 /* stsd should at least have one entry */
10390 stsd_len = QT_UINT32 (stsd_data);
10391 if (stsd_len < 24) {
10392 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10393 if (stream->subtype == FOURCC_vivo) {
10394 gst_qtdemux_stream_unref (stream);
10401 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10402 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10403 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10404 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10406 stsd_entry_data = stsd_data + 16;
10407 remaining_stsd_len = stsd_len - 16;
10408 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10410 gchar *codec = NULL;
10411 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10413 /* and that entry should fit within stsd */
10414 len = QT_UINT32 (stsd_entry_data);
10415 if (len > remaining_stsd_len)
10418 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10419 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10420 GST_FOURCC_ARGS (entry->fourcc));
10421 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10423 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10424 goto error_encrypted;
10426 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10427 /* FIXME this looks wrong, there might be multiple children
10428 * with the same type */
10429 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10430 stream->protected = TRUE;
10431 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10432 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10435 if (stream->subtype == FOURCC_vide) {
10440 gint depth, palette_size, palette_count;
10441 guint32 *palette_data = NULL;
10443 entry->sampled = TRUE;
10445 stream->display_width = w >> 16;
10446 stream->display_height = h >> 16;
10449 if (len < 86) /* TODO verify */
10452 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10453 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10454 entry->fps_n = 0; /* this is filled in later */
10455 entry->fps_d = 0; /* this is filled in later */
10456 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10457 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10459 /* if color_table_id is 0, ctab atom must follow; however some files
10460 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10461 * if color table is not present we'll correct the value */
10462 if (entry->color_table_id == 0 &&
10464 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10465 entry->color_table_id = -1;
10468 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10469 entry->width, entry->height, entry->bits_per_sample,
10470 entry->color_table_id);
10472 depth = entry->bits_per_sample;
10474 /* more than 32 bits means grayscale */
10475 gray = (depth > 32);
10476 /* low 32 bits specify the depth */
10479 /* different number of palette entries is determined by depth. */
10481 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10482 palette_count = (1 << depth);
10483 palette_size = palette_count * 4;
10485 if (entry->color_table_id) {
10486 switch (palette_count) {
10490 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10493 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10498 g_memdup (ff_qt_grayscale_palette_16, palette_size);
10500 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10505 g_memdup (ff_qt_grayscale_palette_256, palette_size);
10507 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10510 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10511 (_("The video in this file might not play correctly.")),
10512 ("unsupported palette depth %d", depth));
10516 gint i, j, start, end;
10522 start = QT_UINT32 (stsd_entry_data + offset + 70);
10523 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10524 end = QT_UINT16 (stsd_entry_data + offset + 76);
10526 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10527 start, end, palette_count);
10534 if (len < 94 + (end - start) * 8)
10537 /* palette is always the same size */
10538 palette_data = g_malloc0 (256 * 4);
10539 palette_size = 256 * 4;
10541 for (j = 0, i = start; i <= end; j++, i++) {
10542 guint32 a, r, g, b;
10544 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10545 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10546 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10547 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10549 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10550 (g & 0xff00) | (b >> 8);
10555 gst_caps_unref (entry->caps);
10558 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10560 if (G_UNLIKELY (!entry->caps)) {
10561 g_free (palette_data);
10562 goto unknown_stream;
10566 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10567 GST_TAG_VIDEO_CODEC, codec, NULL);
10572 if (palette_data) {
10575 if (entry->rgb8_palette)
10576 gst_memory_unref (entry->rgb8_palette);
10577 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10578 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10580 s = gst_caps_get_structure (entry->caps, 0);
10582 /* non-raw video has a palette_data property. raw video has the palette as
10583 * an extra plane that we append to the output buffers before we push
10585 if (!gst_structure_has_name (s, "video/x-raw")) {
10586 GstBuffer *palette;
10588 palette = gst_buffer_new ();
10589 gst_buffer_append_memory (palette, entry->rgb8_palette);
10590 entry->rgb8_palette = NULL;
10592 gst_caps_set_simple (entry->caps, "palette_data",
10593 GST_TYPE_BUFFER, palette, NULL);
10594 gst_buffer_unref (palette);
10596 } else if (palette_count != 0) {
10597 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10598 (NULL), ("Unsupported palette depth %d", depth));
10601 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10602 QT_UINT16 (stsd_entry_data + offset + 32));
10608 /* pick 'the' stsd child */
10609 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10610 if (!stream->protected) {
10611 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10615 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10621 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10622 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10623 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10624 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10628 const guint8 *pasp_data = (const guint8 *) pasp->data;
10629 gint len = QT_UINT32 (pasp_data);
10632 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10633 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10635 CUR_STREAM (stream)->par_w = 0;
10636 CUR_STREAM (stream)->par_h = 0;
10639 CUR_STREAM (stream)->par_w = 0;
10640 CUR_STREAM (stream)->par_h = 0;
10644 const guint8 *fiel_data = (const guint8 *) fiel->data;
10645 gint len = QT_UINT32 (fiel_data);
10648 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10649 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10654 const guint8 *colr_data = (const guint8 *) colr->data;
10655 gint len = QT_UINT32 (colr_data);
10657 if (len == 19 || len == 18) {
10658 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10660 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10661 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10662 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10663 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10664 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10666 switch (primaries) {
10668 CUR_STREAM (stream)->colorimetry.primaries =
10669 GST_VIDEO_COLOR_PRIMARIES_BT709;
10672 CUR_STREAM (stream)->colorimetry.primaries =
10673 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10676 CUR_STREAM (stream)->colorimetry.primaries =
10677 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10680 CUR_STREAM (stream)->colorimetry.primaries =
10681 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10687 switch (transfer_function) {
10689 CUR_STREAM (stream)->colorimetry.transfer =
10690 GST_VIDEO_TRANSFER_BT709;
10693 CUR_STREAM (stream)->colorimetry.transfer =
10694 GST_VIDEO_TRANSFER_SMPTE240M;
10702 CUR_STREAM (stream)->colorimetry.matrix =
10703 GST_VIDEO_COLOR_MATRIX_BT709;
10706 CUR_STREAM (stream)->colorimetry.matrix =
10707 GST_VIDEO_COLOR_MATRIX_BT601;
10710 CUR_STREAM (stream)->colorimetry.matrix =
10711 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10714 CUR_STREAM (stream)->colorimetry.matrix =
10715 GST_VIDEO_COLOR_MATRIX_BT2020;
10721 CUR_STREAM (stream)->colorimetry.range =
10722 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10723 GST_VIDEO_COLOR_RANGE_16_235;
10725 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10728 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10733 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10734 stream->stream_tags);
10741 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10742 const guint8 *avc_data = stsd_entry_data + 0x56;
10745 while (len >= 0x8) {
10748 if (QT_UINT32 (avc_data) <= len)
10749 size = QT_UINT32 (avc_data) - 0x8;
10754 /* No real data, so break out */
10757 switch (QT_FOURCC (avc_data + 0x4)) {
10760 /* parse, if found */
10763 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10765 /* First 4 bytes are the length of the atom, the next 4 bytes
10766 * are the fourcc, the next 1 byte is the version, and the
10767 * subsequent bytes are profile_tier_level structure like data. */
10768 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10769 avc_data + 8 + 1, size - 1);
10770 buf = gst_buffer_new_and_alloc (size);
10771 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10772 gst_caps_set_simple (entry->caps,
10773 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10774 gst_buffer_unref (buf);
10782 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10784 /* First 4 bytes are the length of the atom, the next 4 bytes
10785 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10786 * next 1 byte is the version, and the
10787 * subsequent bytes are sequence parameter set like data. */
10789 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10791 gst_codec_utils_h264_caps_set_level_and_profile
10792 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10794 buf = gst_buffer_new_and_alloc (size);
10795 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10796 gst_caps_set_simple (entry->caps,
10797 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10798 gst_buffer_unref (buf);
10804 guint avg_bitrate, max_bitrate;
10806 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10810 max_bitrate = QT_UINT32 (avc_data + 0xc);
10811 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10813 if (!max_bitrate && !avg_bitrate)
10816 /* Some muxers seem to swap the average and maximum bitrates
10817 * (I'm looking at you, YouTube), so we swap for sanity. */
10818 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10819 guint temp = avg_bitrate;
10821 avg_bitrate = max_bitrate;
10822 max_bitrate = temp;
10825 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10826 gst_tag_list_add (stream->stream_tags,
10827 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10828 max_bitrate, NULL);
10830 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10831 gst_tag_list_add (stream->stream_tags,
10832 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10844 avc_data += size + 8;
10853 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10854 const guint8 *hevc_data = stsd_entry_data + 0x56;
10857 while (len >= 0x8) {
10860 if (QT_UINT32 (hevc_data) <= len)
10861 size = QT_UINT32 (hevc_data) - 0x8;
10866 /* No real data, so break out */
10869 switch (QT_FOURCC (hevc_data + 0x4)) {
10872 /* parse, if found */
10875 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
10877 /* First 4 bytes are the length of the atom, the next 4 bytes
10878 * are the fourcc, the next 1 byte is the version, and the
10879 * subsequent bytes are sequence parameter set like data. */
10880 gst_codec_utils_h265_caps_set_level_tier_and_profile
10881 (entry->caps, hevc_data + 8 + 1, size - 1);
10883 buf = gst_buffer_new_and_alloc (size);
10884 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10885 gst_caps_set_simple (entry->caps,
10886 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10887 gst_buffer_unref (buf);
10894 hevc_data += size + 8;
10907 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10908 GST_FOURCC_ARGS (fourcc));
10910 /* codec data might be in glbl extension atom */
10912 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10918 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10920 len = QT_UINT32 (data);
10923 buf = gst_buffer_new_and_alloc (len);
10924 gst_buffer_fill (buf, 0, data + 8, len);
10925 gst_caps_set_simple (entry->caps,
10926 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10927 gst_buffer_unref (buf);
10934 /* see annex I of the jpeg2000 spec */
10935 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10936 const guint8 *data;
10937 const gchar *colorspace = NULL;
10939 guint32 ncomp_map = 0;
10940 gint32 *comp_map = NULL;
10941 guint32 nchan_def = 0;
10942 gint32 *chan_def = NULL;
10944 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10945 /* some required atoms */
10946 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10949 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10953 /* number of components; redundant with info in codestream, but useful
10955 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10956 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10958 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10960 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10963 GST_DEBUG_OBJECT (qtdemux, "found colr");
10964 /* extract colour space info */
10965 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10966 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10968 colorspace = "sRGB";
10971 colorspace = "GRAY";
10974 colorspace = "sYUV";
10982 /* colr is required, and only values 16, 17, and 18 are specified,
10983 so error if we have no colorspace */
10986 /* extract component mapping */
10987 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10989 guint32 cmap_len = 0;
10991 cmap_len = QT_UINT32 (cmap->data);
10992 if (cmap_len >= 8) {
10993 /* normal box, subtract off header */
10995 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10996 if (cmap_len % 4 == 0) {
10997 ncomp_map = (cmap_len / 4);
10998 comp_map = g_new0 (gint32, ncomp_map);
10999 for (i = 0; i < ncomp_map; i++) {
11002 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11003 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11004 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11005 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11010 /* extract channel definitions */
11011 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11013 guint32 cdef_len = 0;
11015 cdef_len = QT_UINT32 (cdef->data);
11016 if (cdef_len >= 10) {
11017 /* normal box, subtract off header and len */
11019 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11020 if (cdef_len % 6 == 0) {
11021 nchan_def = (cdef_len / 6);
11022 chan_def = g_new0 (gint32, nchan_def);
11023 for (i = 0; i < nchan_def; i++)
11025 for (i = 0; i < nchan_def; i++) {
11026 guint16 cn, typ, asoc;
11027 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11028 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11029 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11030 if (cn < nchan_def) {
11033 chan_def[cn] = asoc;
11036 chan_def[cn] = 0; /* alpha */
11039 chan_def[cn] = -typ;
11047 gst_caps_set_simple (entry->caps,
11048 "num-components", G_TYPE_INT, ncomp, NULL);
11049 gst_caps_set_simple (entry->caps,
11050 "colorspace", G_TYPE_STRING, colorspace, NULL);
11053 GValue arr = { 0, };
11054 GValue elt = { 0, };
11056 g_value_init (&arr, GST_TYPE_ARRAY);
11057 g_value_init (&elt, G_TYPE_INT);
11058 for (i = 0; i < ncomp_map; i++) {
11059 g_value_set_int (&elt, comp_map[i]);
11060 gst_value_array_append_value (&arr, &elt);
11062 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11063 "component-map", &arr);
11064 g_value_unset (&elt);
11065 g_value_unset (&arr);
11070 GValue arr = { 0, };
11071 GValue elt = { 0, };
11073 g_value_init (&arr, GST_TYPE_ARRAY);
11074 g_value_init (&elt, G_TYPE_INT);
11075 for (i = 0; i < nchan_def; i++) {
11076 g_value_set_int (&elt, chan_def[i]);
11077 gst_value_array_append_value (&arr, &elt);
11079 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11080 "channel-definitions", &arr);
11081 g_value_unset (&elt);
11082 g_value_unset (&arr);
11086 /* some optional atoms */
11087 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11088 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11090 /* indicate possible fields in caps */
11092 data = (guint8 *) field->data + 8;
11094 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11095 (gint) * data, NULL);
11097 /* add codec_data if provided */
11102 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11103 data = prefix->data;
11104 len = QT_UINT32 (data);
11107 buf = gst_buffer_new_and_alloc (len);
11108 gst_buffer_fill (buf, 0, data + 8, len);
11109 gst_caps_set_simple (entry->caps,
11110 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11111 gst_buffer_unref (buf);
11120 GstBuffer *seqh = NULL;
11121 const guint8 *gamma_data = NULL;
11122 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11124 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11127 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11128 QT_FP32 (gamma_data), NULL);
11131 /* sorry for the bad name, but we don't know what this is, other
11132 * than its own fourcc */
11133 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11135 gst_buffer_unref (seqh);
11138 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11139 buf = gst_buffer_new_and_alloc (len);
11140 gst_buffer_fill (buf, 0, stsd_data, len);
11141 gst_caps_set_simple (entry->caps,
11142 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11143 gst_buffer_unref (buf);
11148 /* https://developer.apple.com/standards/qtff-2001.pdf,
11149 * page 92, "Video Sample Description", under table 3.1 */
11152 const gint compressor_offset =
11153 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11154 const gint min_size = compressor_offset + 32 + 2 + 2;
11157 guint16 color_table_id = 0;
11160 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11162 /* recover information on interlaced/progressive */
11163 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11167 len = QT_UINT32 (jpeg->data);
11168 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11170 if (len >= min_size) {
11171 gst_byte_reader_init (&br, jpeg->data, len);
11173 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11174 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11175 if (color_table_id != 0) {
11176 /* the spec says there can be concatenated chunks in the data, and we want
11177 * to find one called field. Walk through them. */
11178 gint offset = min_size;
11179 while (offset + 8 < len) {
11180 guint32 size = 0, tag;
11181 ok = gst_byte_reader_get_uint32_le (&br, &size);
11182 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11183 if (!ok || size < 8) {
11184 GST_WARNING_OBJECT (qtdemux,
11185 "Failed to walk optional chunk list");
11188 GST_DEBUG_OBJECT (qtdemux,
11189 "Found optional %4.4s chunk, size %u",
11190 (const char *) &tag, size);
11191 if (tag == FOURCC_fiel) {
11192 guint8 n_fields = 0, ordering = 0;
11193 gst_byte_reader_get_uint8 (&br, &n_fields);
11194 gst_byte_reader_get_uint8 (&br, &ordering);
11195 if (n_fields == 1 || n_fields == 2) {
11196 GST_DEBUG_OBJECT (qtdemux,
11197 "Found fiel tag with %u fields, ordering %u",
11198 n_fields, ordering);
11200 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11201 "interlace-mode", G_TYPE_STRING, "interleaved",
11204 GST_WARNING_OBJECT (qtdemux,
11205 "Found fiel tag with invalid fields (%u)", n_fields);
11211 GST_DEBUG_OBJECT (qtdemux,
11212 "Color table ID is 0, not trying to get interlacedness");
11215 GST_WARNING_OBJECT (qtdemux,
11216 "Length of jpeg chunk is too small, not trying to get interlacedness");
11224 gst_caps_set_simple (entry->caps,
11225 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11231 GNode *xith, *xdxt;
11233 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11234 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11238 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11242 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11243 /* collect the headers and store them in a stream list so that we can
11244 * send them out first */
11245 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11255 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11256 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11259 ovc1_data = ovc1->data;
11260 ovc1_len = QT_UINT32 (ovc1_data);
11261 if (ovc1_len <= 198) {
11262 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11265 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11266 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11267 gst_caps_set_simple (entry->caps,
11268 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11269 gst_buffer_unref (buf);
11274 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11275 const guint8 *vc1_data = stsd_entry_data + 0x56;
11281 if (QT_UINT32 (vc1_data) <= len)
11282 size = QT_UINT32 (vc1_data) - 8;
11287 /* No real data, so break out */
11290 switch (QT_FOURCC (vc1_data + 0x4)) {
11291 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11295 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11296 buf = gst_buffer_new_and_alloc (size);
11297 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11298 gst_caps_set_simple (entry->caps,
11299 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11300 gst_buffer_unref (buf);
11307 vc1_data += size + 8;
11313 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11314 const guint8 *av1_data = stsd_entry_data + 0x56;
11317 while (len >= 0x8) {
11320 if (QT_UINT32 (av1_data) <= len)
11321 size = QT_UINT32 (av1_data) - 0x8;
11326 /* No real data, so break out */
11329 switch (QT_FOURCC (av1_data + 0x4)) {
11332 /* parse, if found */
11334 guint8 pres_delay_field;
11336 GST_DEBUG_OBJECT (qtdemux,
11337 "found av1C codec_data in stsd of size %d", size);
11339 /* not enough data, just ignore and hope for the best */
11344 * 4 bytes: atom length
11349 * 1 bits: initial_presentation_delay_present
11350 * 4 bits: initial_presentation_delay (if present else reserved
11354 if (av1_data[9] != 0) {
11355 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11359 /* We skip initial_presentation_delay* for now */
11360 pres_delay_field = *(av1_data + 12);
11361 if (pres_delay_field & (1 << 5)) {
11362 gst_caps_set_simple (entry->caps,
11363 "presentation-delay", G_TYPE_INT,
11364 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11367 buf = gst_buffer_new_and_alloc (size - 5);
11368 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11369 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11370 gst_caps_set_simple (entry->caps,
11371 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11372 gst_buffer_unref (buf);
11381 av1_data += size + 8;
11391 GST_INFO_OBJECT (qtdemux,
11392 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11393 GST_FOURCC_ARGS (fourcc), entry->caps);
11395 } else if (stream->subtype == FOURCC_soun) {
11397 int version, samplesize;
11398 guint16 compression_id;
11399 gboolean amrwb = FALSE;
11402 /* sample description entry (16) + sound sample description v0 (20) */
11406 version = QT_UINT32 (stsd_entry_data + offset);
11407 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11408 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11409 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11410 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11412 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
11413 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
11414 QT_UINT32 (stsd_entry_data + offset + 4));
11415 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11416 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
11417 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
11418 GST_LOG_OBJECT (qtdemux, "packet size: %d",
11419 QT_UINT16 (stsd_entry_data + offset + 14));
11420 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11422 if (compression_id == 0xfffe)
11423 entry->sampled = TRUE;
11425 /* first assume uncompressed audio */
11426 entry->bytes_per_sample = samplesize / 8;
11427 entry->samples_per_frame = entry->n_channels;
11428 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11429 entry->samples_per_packet = entry->samples_per_frame;
11430 entry->bytes_per_packet = entry->bytes_per_sample;
11434 /* Yes, these have to be hard-coded */
11437 entry->samples_per_packet = 6;
11438 entry->bytes_per_packet = 1;
11439 entry->bytes_per_frame = 1 * entry->n_channels;
11440 entry->bytes_per_sample = 1;
11441 entry->samples_per_frame = 6 * entry->n_channels;
11446 entry->samples_per_packet = 3;
11447 entry->bytes_per_packet = 1;
11448 entry->bytes_per_frame = 1 * entry->n_channels;
11449 entry->bytes_per_sample = 1;
11450 entry->samples_per_frame = 3 * entry->n_channels;
11455 entry->samples_per_packet = 64;
11456 entry->bytes_per_packet = 34;
11457 entry->bytes_per_frame = 34 * entry->n_channels;
11458 entry->bytes_per_sample = 2;
11459 entry->samples_per_frame = 64 * entry->n_channels;
11465 entry->samples_per_packet = 1;
11466 entry->bytes_per_packet = 1;
11467 entry->bytes_per_frame = 1 * entry->n_channels;
11468 entry->bytes_per_sample = 1;
11469 entry->samples_per_frame = 1 * entry->n_channels;
11474 entry->samples_per_packet = 160;
11475 entry->bytes_per_packet = 33;
11476 entry->bytes_per_frame = 33 * entry->n_channels;
11477 entry->bytes_per_sample = 2;
11478 entry->samples_per_frame = 160 * entry->n_channels;
11485 if (version == 0x00010000) {
11486 /* sample description entry (16) + sound sample description v1 (20+16) */
11498 /* only parse extra decoding config for non-pcm audio */
11499 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11500 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11501 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11502 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11504 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
11505 entry->samples_per_packet);
11506 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11507 entry->bytes_per_packet);
11508 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
11509 entry->bytes_per_frame);
11510 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
11511 entry->bytes_per_sample);
11513 if (!entry->sampled && entry->bytes_per_packet) {
11514 entry->samples_per_frame = (entry->bytes_per_frame /
11515 entry->bytes_per_packet) * entry->samples_per_packet;
11516 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
11517 entry->samples_per_frame);
11522 } else if (version == 0x00020000) {
11529 /* sample description entry (16) + sound sample description v2 (56) */
11533 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
11534 entry->rate = qtfp.fp;
11535 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11537 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11538 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11539 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11540 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
11541 QT_UINT32 (stsd_entry_data + offset + 20));
11542 GST_LOG_OBJECT (qtdemux, "format flags: %X",
11543 QT_UINT32 (stsd_entry_data + offset + 24));
11544 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11545 QT_UINT32 (stsd_entry_data + offset + 28));
11546 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11547 QT_UINT32 (stsd_entry_data + offset + 32));
11548 } else if (version != 0x00000) {
11549 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11554 gst_caps_unref (entry->caps);
11556 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
11557 stsd_entry_data + 32, len - 16, &codec);
11565 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
11567 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
11569 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
11571 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
11574 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
11575 gst_caps_set_simple (entry->caps,
11576 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
11583 const guint8 *owma_data;
11584 const gchar *codec_name = NULL;
11588 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11589 /* FIXME this should also be gst_riff_strf_auds,
11590 * but the latter one is actually missing bits-per-sample :( */
11595 gint32 nSamplesPerSec;
11596 gint32 nAvgBytesPerSec;
11597 gint16 nBlockAlign;
11598 gint16 wBitsPerSample;
11601 WAVEFORMATEX *wfex;
11603 GST_DEBUG_OBJECT (qtdemux, "parse owma");
11604 owma_data = stsd_entry_data;
11605 owma_len = QT_UINT32 (owma_data);
11606 if (owma_len <= 54) {
11607 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11610 wfex = (WAVEFORMATEX *) (owma_data + 36);
11611 buf = gst_buffer_new_and_alloc (owma_len - 54);
11612 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11613 if (wfex->wFormatTag == 0x0161) {
11614 codec_name = "Windows Media Audio";
11616 } else if (wfex->wFormatTag == 0x0162) {
11617 codec_name = "Windows Media Audio 9 Pro";
11619 } else if (wfex->wFormatTag == 0x0163) {
11620 codec_name = "Windows Media Audio 9 Lossless";
11621 /* is that correct? gstffmpegcodecmap.c is missing it, but
11622 * fluendo codec seems to support it */
11626 gst_caps_set_simple (entry->caps,
11627 "codec_data", GST_TYPE_BUFFER, buf,
11628 "wmaversion", G_TYPE_INT, version,
11629 "block_align", G_TYPE_INT,
11630 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11631 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11632 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11633 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11634 gst_buffer_unref (buf);
11638 codec = g_strdup (codec_name);
11644 gint len = QT_UINT32 (stsd_entry_data) - offset;
11645 const guint8 *wfex_data = stsd_entry_data + offset;
11646 const gchar *codec_name = NULL;
11648 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11649 /* FIXME this should also be gst_riff_strf_auds,
11650 * but the latter one is actually missing bits-per-sample :( */
11655 gint32 nSamplesPerSec;
11656 gint32 nAvgBytesPerSec;
11657 gint16 nBlockAlign;
11658 gint16 wBitsPerSample;
11663 /* FIXME: unify with similar wavformatex parsing code above */
11664 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11670 if (QT_UINT32 (wfex_data) <= len)
11671 size = QT_UINT32 (wfex_data) - 8;
11676 /* No real data, so break out */
11679 switch (QT_FOURCC (wfex_data + 4)) {
11680 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11682 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11687 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11688 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11689 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11690 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11691 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11692 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11693 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11695 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11696 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11697 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11698 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11699 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11700 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11702 if (wfex.wFormatTag == 0x0161) {
11703 codec_name = "Windows Media Audio";
11705 } else if (wfex.wFormatTag == 0x0162) {
11706 codec_name = "Windows Media Audio 9 Pro";
11708 } else if (wfex.wFormatTag == 0x0163) {
11709 codec_name = "Windows Media Audio 9 Lossless";
11710 /* is that correct? gstffmpegcodecmap.c is missing it, but
11711 * fluendo codec seems to support it */
11715 gst_caps_set_simple (entry->caps,
11716 "wmaversion", G_TYPE_INT, version,
11717 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11718 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11719 "width", G_TYPE_INT, wfex.wBitsPerSample,
11720 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11722 if (size > wfex.cbSize) {
11725 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11726 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11727 size - wfex.cbSize);
11728 gst_caps_set_simple (entry->caps,
11729 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11730 gst_buffer_unref (buf);
11732 GST_WARNING_OBJECT (qtdemux, "no codec data");
11737 codec = g_strdup (codec_name);
11745 wfex_data += size + 8;
11751 const guint8 *opus_data;
11752 guint8 *channel_mapping = NULL;
11755 guint8 channel_mapping_family;
11756 guint8 stream_count;
11757 guint8 coupled_count;
11760 opus_data = stsd_entry_data;
11762 channels = GST_READ_UINT8 (opus_data + 45);
11763 rate = GST_READ_UINT32_LE (opus_data + 48);
11764 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11765 stream_count = GST_READ_UINT8 (opus_data + 55);
11766 coupled_count = GST_READ_UINT8 (opus_data + 56);
11768 if (channels > 0) {
11769 channel_mapping = g_malloc (channels * sizeof (guint8));
11770 for (i = 0; i < channels; i++)
11771 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11774 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11775 channel_mapping_family, stream_count, coupled_count,
11787 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11788 GST_TAG_AUDIO_CODEC, codec, NULL);
11792 /* some bitrate info may have ended up in caps */
11793 s = gst_caps_get_structure (entry->caps, 0);
11794 gst_structure_get_int (s, "bitrate", &bitrate);
11796 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11797 GST_TAG_BITRATE, bitrate, NULL);
11800 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11801 if (!stream->protected) {
11803 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11807 if (stream->protected && fourcc == FOURCC_mp4a) {
11808 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11812 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11820 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11822 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11824 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11828 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11829 16 bits is a byte-swapped wave-style codec identifier,
11830 and we can find a WAVE header internally to a 'wave' atom here.
11831 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11832 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11835 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11836 if (len < offset + 20) {
11837 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11839 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11840 const guint8 *data = stsd_entry_data + offset + 16;
11842 GNode *waveheadernode;
11844 wavenode = g_node_new ((guint8 *) data);
11845 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11846 const guint8 *waveheader;
11849 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11850 if (waveheadernode) {
11851 waveheader = (const guint8 *) waveheadernode->data;
11852 headerlen = QT_UINT32 (waveheader);
11854 if (headerlen > 8) {
11855 gst_riff_strf_auds *header = NULL;
11856 GstBuffer *headerbuf;
11862 headerbuf = gst_buffer_new_and_alloc (headerlen);
11863 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11865 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11866 headerbuf, &header, &extra)) {
11867 gst_caps_unref (entry->caps);
11868 /* FIXME: Need to do something with the channel reorder map */
11870 gst_riff_create_audio_caps (header->format, NULL, header,
11871 extra, NULL, NULL, NULL);
11874 gst_buffer_unref (extra);
11879 GST_DEBUG ("Didn't find waveheadernode for this codec");
11881 g_node_destroy (wavenode);
11884 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11885 stream->stream_tags);
11889 /* FIXME: what is in the chunk? */
11892 gint len = QT_UINT32 (stsd_data);
11894 /* seems to be always = 116 = 0x74 */
11900 gint len = QT_UINT32 (stsd_entry_data);
11903 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11905 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11906 gst_caps_set_simple (entry->caps,
11907 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11908 gst_buffer_unref (buf);
11910 gst_caps_set_simple (entry->caps,
11911 "samplesize", G_TYPE_INT, samplesize, NULL);
11916 GNode *alac, *wave = NULL;
11918 /* apparently, m4a has this atom appended directly in the stsd entry,
11919 * while mov has it in a wave atom */
11920 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11922 /* alac now refers to stsd entry atom */
11923 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11925 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11927 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11930 const guint8 *alac_data = alac->data;
11931 gint len = QT_UINT32 (alac->data);
11935 GST_DEBUG_OBJECT (qtdemux,
11936 "discarding alac atom with unexpected len %d", len);
11938 /* codec-data contains alac atom size and prefix,
11939 * ffmpeg likes it that way, not quite gst-ish though ...*/
11940 buf = gst_buffer_new_and_alloc (len);
11941 gst_buffer_fill (buf, 0, alac->data, len);
11942 gst_caps_set_simple (entry->caps,
11943 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11944 gst_buffer_unref (buf);
11946 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11947 entry->n_channels = QT_UINT8 (alac_data + 21);
11948 entry->rate = QT_UINT32 (alac_data + 32);
11951 gst_caps_set_simple (entry->caps,
11952 "samplesize", G_TYPE_INT, samplesize, NULL);
11957 /* The codingname of the sample entry is 'fLaC' */
11958 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11961 /* The 'dfLa' box is added to the sample entry to convey
11962 initializing information for the decoder. */
11963 const GNode *dfla =
11964 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11967 const guint32 len = QT_UINT32 (dfla->data);
11969 /* Must contain at least dfLa box header (12),
11970 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11972 GST_DEBUG_OBJECT (qtdemux,
11973 "discarding dfla atom with unexpected len %d", len);
11975 /* skip dfLa header to get the METADATA_BLOCKs */
11976 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11977 const guint32 metadata_blocks_len = len - 12;
11979 gchar *stream_marker = g_strdup ("fLaC");
11980 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11981 strlen (stream_marker));
11984 guint32 remainder = 0;
11985 guint32 block_size = 0;
11986 gboolean is_last = FALSE;
11988 GValue array = G_VALUE_INIT;
11989 GValue value = G_VALUE_INIT;
11991 g_value_init (&array, GST_TYPE_ARRAY);
11992 g_value_init (&value, GST_TYPE_BUFFER);
11994 gst_value_set_buffer (&value, block);
11995 gst_value_array_append_value (&array, &value);
11996 g_value_reset (&value);
11998 gst_buffer_unref (block);
12000 /* check there's at least one METADATA_BLOCK_HEADER's worth
12001 * of data, and we haven't already finished parsing */
12002 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12003 remainder = metadata_blocks_len - index;
12005 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12007 (metadata_blocks[index + 1] << 16) +
12008 (metadata_blocks[index + 2] << 8) +
12009 metadata_blocks[index + 3];
12011 /* be careful not to read off end of box */
12012 if (block_size > remainder) {
12016 is_last = metadata_blocks[index] >> 7;
12018 block = gst_buffer_new_and_alloc (block_size);
12020 gst_buffer_fill (block, 0, &metadata_blocks[index],
12023 gst_value_set_buffer (&value, block);
12024 gst_value_array_append_value (&array, &value);
12025 g_value_reset (&value);
12027 gst_buffer_unref (block);
12029 index += block_size;
12032 /* only append the metadata if we successfully read all of it */
12034 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12035 (stream)->caps, 0), "streamheader", &array);
12037 GST_WARNING_OBJECT (qtdemux,
12038 "discarding all METADATA_BLOCKs due to invalid "
12039 "block_size %d at idx %d, rem %d", block_size, index,
12043 g_value_unset (&value);
12044 g_value_unset (&array);
12046 /* The sample rate obtained from the stsd may not be accurate
12047 * since it cannot represent rates greater than 65535Hz, so
12048 * override that value with the sample rate from the
12049 * METADATA_BLOCK_STREAMINFO block */
12050 CUR_STREAM (stream)->rate =
12051 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12062 gint len = QT_UINT32 (stsd_entry_data);
12065 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12068 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12070 /* If we have enough data, let's try to get the 'damr' atom. See
12071 * the 3GPP container spec (26.244) for more details. */
12072 if ((len - 0x34) > 8 &&
12073 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12074 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12075 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12078 gst_caps_set_simple (entry->caps,
12079 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12080 gst_buffer_unref (buf);
12086 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12087 gint len = QT_UINT32 (stsd_entry_data);
12090 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12092 if (sound_version == 1) {
12093 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12094 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12095 guint8 codec_data[2];
12097 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12099 gint sample_rate_index =
12100 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12102 /* build AAC codec data */
12103 codec_data[0] = profile << 3;
12104 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12105 codec_data[1] = (sample_rate_index & 0x01) << 7;
12106 codec_data[1] |= (channels & 0xF) << 3;
12108 buf = gst_buffer_new_and_alloc (2);
12109 gst_buffer_fill (buf, 0, codec_data, 2);
12110 gst_caps_set_simple (entry->caps,
12111 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12112 gst_buffer_unref (buf);
12118 /* Fully handled elsewhere */
12121 GST_INFO_OBJECT (qtdemux,
12122 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12126 GST_INFO_OBJECT (qtdemux,
12127 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12128 GST_FOURCC_ARGS (fourcc), entry->caps);
12130 } else if (stream->subtype == FOURCC_strm) {
12131 if (fourcc == FOURCC_rtsp) {
12132 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12134 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12135 GST_FOURCC_ARGS (fourcc));
12136 goto unknown_stream;
12138 entry->sampled = TRUE;
12139 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12140 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12141 || stream->subtype == FOURCC_clcp) {
12143 entry->sampled = TRUE;
12144 entry->sparse = TRUE;
12147 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12150 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12151 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12156 /* hunt for sort-of codec data */
12160 GNode *mp4s = NULL;
12161 GNode *esds = NULL;
12163 /* look for palette in a stsd->mp4s->esds sub-atom */
12164 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12166 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12167 if (esds == NULL) {
12169 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12173 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12174 stream->stream_tags);
12178 GST_INFO_OBJECT (qtdemux,
12179 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12182 GST_INFO_OBJECT (qtdemux,
12183 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12184 GST_FOURCC_ARGS (fourcc), entry->caps);
12186 /* everything in 1 sample */
12187 entry->sampled = TRUE;
12190 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12193 if (entry->caps == NULL)
12194 goto unknown_stream;
12197 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12198 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12204 /* promote to sampled format */
12205 if (entry->fourcc == FOURCC_samr) {
12206 /* force mono 8000 Hz for AMR */
12207 entry->sampled = TRUE;
12208 entry->n_channels = 1;
12209 entry->rate = 8000;
12210 } else if (entry->fourcc == FOURCC_sawb) {
12211 /* force mono 16000 Hz for AMR-WB */
12212 entry->sampled = TRUE;
12213 entry->n_channels = 1;
12214 entry->rate = 16000;
12215 } else if (entry->fourcc == FOURCC_mp4a) {
12216 entry->sampled = TRUE;
12220 stsd_entry_data += len;
12221 remaining_stsd_len -= len;
12225 /* collect sample information */
12226 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12227 goto samples_failed;
12229 if (qtdemux->fragmented) {
12232 /* need all moov samples as basis; probably not many if any at all */
12233 /* prevent moof parsing taking of at this time */
12234 offset = qtdemux->moof_offset;
12235 qtdemux->moof_offset = 0;
12236 if (stream->n_samples &&
12237 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12238 qtdemux->moof_offset = offset;
12239 goto samples_failed;
12241 qtdemux->moof_offset = 0;
12242 /* movie duration more reliable in this case (e.g. mehd) */
12243 if (qtdemux->segment.duration &&
12244 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12246 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12249 /* configure segments */
12250 if (!qtdemux_parse_segments (qtdemux, stream, trak))
12251 goto segments_failed;
12253 /* add some language tag, if useful */
12254 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12255 strcmp (stream->lang_id, "und")) {
12256 const gchar *lang_code;
12258 /* convert ISO 639-2 code to ISO 639-1 */
12259 lang_code = gst_tag_get_language_code (stream->lang_id);
12260 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12261 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12264 /* Check for UDTA tags */
12265 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12266 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12269 /* Insert and sort new stream in track-id order.
12270 * This will help in comparing old/new streams during stream update check */
12271 g_ptr_array_add (qtdemux->active_streams, stream);
12272 g_ptr_array_sort (qtdemux->active_streams,
12273 (GCompareFunc) qtdemux_track_id_compare_func);
12274 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
12275 QTDEMUX_N_STREAMS (qtdemux));
12282 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12283 (_("This file is corrupt and cannot be played.")), (NULL));
12285 gst_qtdemux_stream_unref (stream);
12290 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12291 gst_qtdemux_stream_unref (stream);
12297 /* we posted an error already */
12298 /* free stbl sub-atoms */
12299 gst_qtdemux_stbl_free (stream);
12300 gst_qtdemux_stream_unref (stream);
12305 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12311 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12312 GST_FOURCC_ARGS (stream->subtype));
12313 gst_qtdemux_stream_unref (stream);
12318 /* If we can estimate the overall bitrate, and don't have information about the
12319 * stream bitrate for exactly one stream, this guesses the stream bitrate as
12320 * the overall bitrate minus the sum of the bitrates of all other streams. This
12321 * should be useful for the common case where we have one audio and one video
12322 * stream and can estimate the bitrate of one, but not the other. */
12324 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12326 QtDemuxStream *stream = NULL;
12327 gint64 size, sys_bitrate, sum_bitrate = 0;
12328 GstClockTime duration;
12332 if (qtdemux->fragmented)
12335 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12337 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12339 GST_DEBUG_OBJECT (qtdemux,
12340 "Size in bytes of the stream not known - bailing");
12344 /* Subtract the header size */
12345 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12346 size, qtdemux->header_size);
12348 if (size < qtdemux->header_size)
12351 size = size - qtdemux->header_size;
12353 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12354 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12358 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12359 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
12360 switch (str->subtype) {
12363 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12364 CUR_STREAM (str)->caps);
12365 /* retrieve bitrate, prefer avg then max */
12367 if (str->stream_tags) {
12368 if (gst_tag_list_get_uint (str->stream_tags,
12369 GST_TAG_MAXIMUM_BITRATE, &bitrate))
12370 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
12371 if (gst_tag_list_get_uint (str->stream_tags,
12372 GST_TAG_NOMINAL_BITRATE, &bitrate))
12373 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
12374 if (gst_tag_list_get_uint (str->stream_tags,
12375 GST_TAG_BITRATE, &bitrate))
12376 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12379 sum_bitrate += bitrate;
12382 GST_DEBUG_OBJECT (qtdemux,
12383 ">1 stream with unknown bitrate - bailing");
12390 /* For other subtypes, we assume no significant impact on bitrate */
12396 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12400 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12402 if (sys_bitrate < sum_bitrate) {
12403 /* This can happen, since sum_bitrate might be derived from maximum
12404 * bitrates and not average bitrates */
12405 GST_DEBUG_OBJECT (qtdemux,
12406 "System bitrate less than sum bitrate - bailing");
12410 bitrate = sys_bitrate - sum_bitrate;
12411 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12412 ", Stream bitrate = %u", sys_bitrate, bitrate);
12414 if (!stream->stream_tags)
12415 stream->stream_tags = gst_tag_list_new_empty ();
12417 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12419 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12420 GST_TAG_BITRATE, bitrate, NULL);
12423 static GstFlowReturn
12424 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12426 GstFlowReturn ret = GST_FLOW_OK;
12429 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
12431 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12432 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12433 guint32 sample_num = 0;
12435 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12436 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12438 if (qtdemux->fragmented) {
12439 /* need all moov samples first */
12440 GST_OBJECT_LOCK (qtdemux);
12441 while (stream->n_samples == 0)
12442 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12444 GST_OBJECT_UNLOCK (qtdemux);
12446 /* discard any stray moof */
12447 qtdemux->moof_offset = 0;
12450 /* prepare braking */
12451 if (ret != GST_FLOW_ERROR)
12454 /* in pull mode, we should have parsed some sample info by now;
12455 * and quite some code will not handle no samples.
12456 * in push mode, we'll just have to deal with it */
12457 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
12458 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
12459 g_ptr_array_remove_index (qtdemux->active_streams, i);
12462 } else if (stream->track_id == qtdemux->chapters_track_id &&
12463 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
12464 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
12465 so that it doesn't look like a subtitle track */
12466 g_ptr_array_remove_index (qtdemux->active_streams, i);
12471 /* parse the initial sample for use in setting the frame rate cap */
12472 while (sample_num == 0 && sample_num < stream->n_samples) {
12473 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
12483 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
12485 return g_strcmp0 (stream->stream_id, stream_id) == 0;
12489 qtdemux_is_streams_update (GstQTDemux * qtdemux)
12493 /* Different length, updated */
12494 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
12497 /* streams in list are sorted in track-id order */
12498 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12499 /* Different stream-id, updated */
12500 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
12501 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
12509 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
12510 QtDemuxStream * oldstream, QtDemuxStream * newstream)
12512 /* Connect old stream's srcpad to new stream */
12513 newstream->pad = oldstream->pad;
12514 oldstream->pad = NULL;
12516 /* unset new_stream to prevent stream-start event */
12517 newstream->new_stream = FALSE;
12519 return gst_qtdemux_configure_stream (qtdemux, newstream);
12522 /* g_ptr_array_find_with_equal_func is available since 2.54,
12523 * replacement until we can depend unconditionally on the real one in GLib */
12524 #if !GLIB_CHECK_VERSION(2,54,0)
12525 #define g_ptr_array_find_with_equal_func qtdemux_ptr_array_find_with_equal_func
12527 qtdemux_ptr_array_find_with_equal_func (GPtrArray * haystack,
12528 gconstpointer needle, GEqualFunc equal_func, guint * index_)
12532 g_return_val_if_fail (haystack != NULL, FALSE);
12534 if (equal_func == NULL)
12535 equal_func = g_direct_equal;
12537 for (i = 0; i < haystack->len; i++) {
12538 if (equal_func (g_ptr_array_index (haystack, i), needle)) {
12539 if (index_ != NULL)
12550 qtdemux_update_streams (GstQTDemux * qtdemux)
12553 g_assert (qtdemux->streams_aware);
12555 /* At below, figure out which stream in active_streams has identical stream-id
12556 * with that of in old_streams. If there is matching stream-id,
12557 * corresponding newstream will not be exposed again,
12558 * but demux will reuse srcpad of matched old stream
12560 * active_streams : newly created streams from the latest moov
12561 * old_streams : existing streams (belong to previous moov)
12564 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12565 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12566 QtDemuxStream *oldstream = NULL;
12569 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12570 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12572 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
12573 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
12574 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
12576 /* null pad stream cannot be reused */
12577 if (oldstream->pad == NULL)
12582 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
12584 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
12587 /* we don't need to preserve order of old streams */
12588 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
12592 /* now we have all info and can expose */
12593 list = stream->stream_tags;
12594 stream->stream_tags = NULL;
12595 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12603 /* Must be called with expose lock */
12604 static GstFlowReturn
12605 qtdemux_expose_streams (GstQTDemux * qtdemux)
12609 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
12611 if (!qtdemux_is_streams_update (qtdemux)) {
12612 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
12613 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12614 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12615 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
12616 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
12617 return GST_FLOW_ERROR;
12620 g_ptr_array_remove_range (qtdemux->old_streams,
12621 0, qtdemux->old_streams->len);
12623 return GST_FLOW_OK;
12626 if (qtdemux->streams_aware) {
12627 if (!qtdemux_update_streams (qtdemux))
12628 return GST_FLOW_ERROR;
12630 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12631 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12634 /* now we have all info and can expose */
12635 list = stream->stream_tags;
12636 stream->stream_tags = NULL;
12637 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12638 return GST_FLOW_ERROR;
12643 gst_qtdemux_guess_bitrate (qtdemux);
12645 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
12647 /* If we have still old_streams, it's no more used stream */
12648 for (i = 0; i < qtdemux->old_streams->len; i++) {
12649 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
12654 event = gst_event_new_eos ();
12655 if (qtdemux->segment_seqnum)
12656 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
12658 gst_pad_push_event (stream->pad, event);
12662 g_ptr_array_remove_range (qtdemux->old_streams, 0, qtdemux->old_streams->len);
12664 /* check if we should post a redirect in case there is a single trak
12665 * and it is a redirecting trak */
12666 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
12667 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
12670 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
12671 "an external content");
12672 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
12673 gst_structure_new ("redirect",
12674 "new-location", G_TYPE_STRING,
12675 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
12676 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
12677 qtdemux->posted_redirect = TRUE;
12680 g_ptr_array_foreach (qtdemux->active_streams,
12681 (GFunc) qtdemux_do_allocation, qtdemux);
12683 qtdemux->need_segment = TRUE;
12685 qtdemux->exposed = TRUE;
12686 return GST_FLOW_OK;
12689 /* check if major or compatible brand is 3GP */
12690 static inline gboolean
12691 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
12694 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12696 } else if (qtdemux->comp_brands != NULL) {
12700 gboolean res = FALSE;
12702 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
12705 while (size >= 4) {
12706 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12711 gst_buffer_unmap (qtdemux->comp_brands, &map);
12718 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12719 static inline gboolean
12720 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12722 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12723 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12724 || fourcc == FOURCC_albm;
12728 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12729 const char *tag, const char *dummy, GNode * node)
12731 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12735 gdouble longitude, latitude, altitude;
12738 len = QT_UINT32 (node->data);
12745 /* TODO: language code skipped */
12747 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12750 /* do not alarm in trivial case, but bail out otherwise */
12751 if (*(data + offset) != 0) {
12752 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12756 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12757 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12758 offset += strlen (name);
12762 if (len < offset + 2 + 4 + 4 + 4)
12765 /* +1 +1 = skip null-terminator and location role byte */
12767 /* table in spec says unsigned, semantics say negative has meaning ... */
12768 longitude = QT_SFP32 (data + offset);
12771 latitude = QT_SFP32 (data + offset);
12774 altitude = QT_SFP32 (data + offset);
12776 /* one invalid means all are invalid */
12777 if (longitude >= -180.0 && longitude <= 180.0 &&
12778 latitude >= -90.0 && latitude <= 90.0) {
12779 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12780 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12781 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12782 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12785 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12792 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12799 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12800 const char *tag, const char *dummy, GNode * node)
12806 len = QT_UINT32 (node->data);
12810 y = QT_UINT16 ((guint8 *) node->data + 12);
12812 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12815 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12817 date = g_date_new_dmy (1, 1, y);
12818 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12819 g_date_free (date);
12823 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12824 const char *tag, const char *dummy, GNode * node)
12827 char *tag_str = NULL;
12832 len = QT_UINT32 (node->data);
12837 entity = (guint8 *) node->data + offset;
12838 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12839 GST_DEBUG_OBJECT (qtdemux,
12840 "classification info: %c%c%c%c invalid classification entity",
12841 entity[0], entity[1], entity[2], entity[3]);
12846 table = QT_UINT16 ((guint8 *) node->data + offset);
12848 /* Language code skipped */
12852 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12853 * XXXX: classification entity, fixed length 4 chars.
12854 * Y[YYYY]: classification table, max 5 chars.
12856 tag_str = g_strdup_printf ("----://%u/%s",
12857 table, (char *) node->data + offset);
12859 /* memcpy To be sure we're preserving byte order */
12860 memcpy (tag_str, entity, 4);
12861 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12863 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12872 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12878 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12879 const char *tag, const char *dummy, GNode * node)
12881 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12887 gboolean ret = TRUE;
12888 const gchar *charset = NULL;
12890 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12892 len = QT_UINT32 (data->data);
12893 type = QT_UINT32 ((guint8 *) data->data + 8);
12894 if (type == 0x00000001 && len > 16) {
12895 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12898 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12899 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12902 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12906 len = QT_UINT32 (node->data);
12907 type = QT_UINT32 ((guint8 *) node->data + 4);
12908 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12912 /* Type starts with the (C) symbol, so the next data is a list
12913 * of (string size(16), language code(16), string) */
12915 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12916 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12918 /* the string + fourcc + size + 2 16bit fields,
12919 * means that there are more tags in this atom */
12920 if (len > str_len + 8 + 4) {
12921 /* TODO how to represent the same tag in different languages? */
12922 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12923 "text alternatives, reading only first one");
12927 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12928 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12930 if (lang_code < 0x800) { /* MAC encoded string */
12933 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12934 QT_FOURCC ((guint8 *) node->data + 4))) {
12935 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12937 /* we go for 3GP style encoding if major brands claims so,
12938 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12939 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12940 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12941 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12943 /* 16-bit Language code is ignored here as well */
12944 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12951 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12952 ret = FALSE; /* may have to fallback */
12955 GError *err = NULL;
12957 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12958 charset, NULL, NULL, &err);
12960 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12961 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12963 g_error_free (err);
12966 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12967 len - offset, env_vars);
12970 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12971 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12975 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12982 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12983 const char *tag, const char *dummy, GNode * node)
12985 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12989 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12990 const char *tag, const char *dummy, GNode * node)
12992 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12994 char *s, *t, *k = NULL;
12999 /* first try normal string tag if major brand not 3GP */
13000 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
13001 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
13002 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
13003 * let's try it 3gpp way after minor safety check */
13005 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
13011 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
13015 len = QT_UINT32 (data);
13019 count = QT_UINT8 (data + 14);
13021 for (; count; count--) {
13024 if (offset + 1 > len)
13026 slen = QT_UINT8 (data + offset);
13028 if (offset + slen > len)
13030 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
13033 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
13035 t = g_strjoin (",", k, s, NULL);
13043 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
13050 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
13051 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
13060 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
13066 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
13067 const char *tag1, const char *tag2, GNode * node)
13074 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13076 len = QT_UINT32 (data->data);
13077 type = QT_UINT32 ((guint8 *) data->data + 8);
13078 if (type == 0x00000000 && len >= 22) {
13079 n1 = QT_UINT16 ((guint8 *) data->data + 18);
13080 n2 = QT_UINT16 ((guint8 *) data->data + 20);
13082 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
13083 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
13086 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
13087 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
13094 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
13095 const char *tag1, const char *dummy, GNode * node)
13102 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13104 len = QT_UINT32 (data->data);
13105 type = QT_UINT32 ((guint8 *) data->data + 8);
13106 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
13107 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13108 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
13109 n1 = QT_UINT16 ((guint8 *) data->data + 16);
13111 /* do not add bpm=0 */
13112 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
13113 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
13121 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
13122 const char *tag1, const char *dummy, GNode * node)
13129 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13131 len = QT_UINT32 (data->data);
13132 type = QT_UINT32 ((guint8 *) data->data + 8);
13133 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
13134 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13135 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
13136 num = QT_UINT32 ((guint8 *) data->data + 16);
13138 /* do not add num=0 */
13139 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
13140 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
13147 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
13148 const char *tag1, const char *dummy, GNode * node)
13155 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13157 len = QT_UINT32 (data->data);
13158 type = QT_UINT32 ((guint8 *) data->data + 8);
13159 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
13160 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
13161 GstTagImageType image_type;
13163 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
13164 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
13166 image_type = GST_TAG_IMAGE_TYPE_NONE;
13169 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
13170 len - 16, image_type))) {
13171 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
13172 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
13173 gst_sample_unref (sample);
13180 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
13181 const char *tag, const char *dummy, GNode * node)
13184 GstDateTime *datetime = NULL;
13189 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13191 len = QT_UINT32 (data->data);
13192 type = QT_UINT32 ((guint8 *) data->data + 8);
13193 if (type == 0x00000001 && len > 16) {
13194 guint y, m = 1, d = 1;
13197 s = g_strndup ((char *) data->data + 16, len - 16);
13198 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
13199 datetime = gst_date_time_new_from_iso8601_string (s);
13200 if (datetime != NULL) {
13201 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
13203 gst_date_time_unref (datetime);
13206 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
13207 if (ret >= 1 && y > 1500 && y < 3000) {
13210 date = g_date_new_dmy (d, m, y);
13211 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13212 g_date_free (date);
13214 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
13222 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
13223 const char *tag, const char *dummy, GNode * node)
13227 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13229 /* re-route to normal string tag if major brand says so
13230 * or no data atom and compatible brand suggests so */
13231 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13232 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
13233 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
13238 guint len, type, n;
13240 len = QT_UINT32 (data->data);
13241 type = QT_UINT32 ((guint8 *) data->data + 8);
13242 if (type == 0x00000000 && len >= 18) {
13243 n = QT_UINT16 ((guint8 *) data->data + 16);
13245 const gchar *genre;
13247 genre = gst_tag_id3_genre_get (n - 1);
13248 if (genre != NULL) {
13249 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
13250 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
13258 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
13259 const gchar * tag, guint8 * data, guint32 datasize)
13264 /* make a copy to have \0 at the end */
13265 datacopy = g_strndup ((gchar *) data, datasize);
13267 /* convert the str to double */
13268 if (sscanf (datacopy, "%lf", &value) == 1) {
13269 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
13270 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
13272 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
13280 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
13281 const char *tag, const char *tag_bis, GNode * node)
13290 const gchar *meanstr;
13291 const gchar *namestr;
13293 /* checking the whole ---- atom size for consistency */
13294 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
13295 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
13299 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
13301 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
13305 meansize = QT_UINT32 (mean->data);
13306 if (meansize <= 12) {
13307 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
13310 meanstr = ((gchar *) mean->data) + 12;
13313 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
13315 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
13319 namesize = QT_UINT32 (name->data);
13320 if (namesize <= 12) {
13321 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
13324 namestr = ((gchar *) name->data) + 12;
13332 * uint24 - data type
13336 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13338 GST_WARNING_OBJECT (demux, "No data atom in this tag");
13341 datasize = QT_UINT32 (data->data);
13342 if (datasize <= 16) {
13343 GST_WARNING_OBJECT (demux, "Data atom too small");
13346 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
13348 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
13349 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
13350 static const struct
13352 const gchar name[28];
13353 const gchar tag[28];
13356 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
13357 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
13358 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
13359 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
13360 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
13361 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
13362 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
13363 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
13367 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
13368 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
13369 switch (gst_tag_get_type (tags[i].tag)) {
13370 case G_TYPE_DOUBLE:
13371 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
13372 ((guint8 *) data->data) + 16, datasize - 16);
13374 case G_TYPE_STRING:
13375 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
13384 if (i == G_N_ELEMENTS (tags))
13394 #ifndef GST_DISABLE_GST_DEBUG
13396 gchar *namestr_dbg;
13397 gchar *meanstr_dbg;
13399 meanstr_dbg = g_strndup (meanstr, meansize);
13400 namestr_dbg = g_strndup (namestr, namesize);
13402 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
13403 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
13405 g_free (namestr_dbg);
13406 g_free (meanstr_dbg);
13413 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
13414 const char *tag_bis, GNode * node)
13419 GstTagList *id32_taglist = NULL;
13421 GST_LOG_OBJECT (demux, "parsing ID32");
13424 len = GST_READ_UINT32_BE (data);
13426 /* need at least full box and language tag */
13430 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
13431 gst_buffer_fill (buf, 0, data + 14, len - 14);
13433 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
13434 if (id32_taglist) {
13435 GST_LOG_OBJECT (demux, "parsing ok");
13436 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
13437 gst_tag_list_unref (id32_taglist);
13439 GST_LOG_OBJECT (demux, "parsing failed");
13442 gst_buffer_unref (buf);
13445 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
13446 const char *tag, const char *tag_bis, GNode * node);
13449 FOURCC_pcst -> if media is a podcast -> bool
13450 FOURCC_cpil -> if media is part of a compilation -> bool
13451 FOURCC_pgap -> if media is part of a gapless context -> bool
13452 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
13455 static const struct
13458 const gchar *gst_tag;
13459 const gchar *gst_tag_bis;
13460 const GstQTDemuxAddTagFunc func;
13463 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13464 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13465 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
13466 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13467 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13468 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
13469 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13470 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13471 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13472 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13473 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13474 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13475 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13476 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13477 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13478 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13479 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
13480 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
13481 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
13482 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13483 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13484 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
13485 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13486 qtdemux_tag_add_num}, {
13487 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13488 qtdemux_tag_add_num}, {
13489 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
13490 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
13491 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
13492 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
13493 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
13494 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
13495 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13496 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13497 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
13498 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
13499 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
13500 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13501 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13502 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
13503 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
13504 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13505 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
13506 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
13507 qtdemux_tag_add_classification}, {
13508 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
13509 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
13510 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
13512 /* This is a special case, some tags are stored in this
13513 * 'reverse dns naming', according to:
13514 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
13517 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
13518 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
13519 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
13522 struct _GstQtDemuxTagList
13525 GstTagList *taglist;
13527 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
13530 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
13536 const gchar *style;
13541 GstQTDemux *demux = qtdemuxtaglist->demux;
13542 GstTagList *taglist = qtdemuxtaglist->taglist;
13545 len = QT_UINT32 (data);
13546 buf = gst_buffer_new_and_alloc (len);
13547 gst_buffer_fill (buf, 0, data, len);
13549 /* heuristic to determine style of tag */
13550 if (QT_FOURCC (data + 4) == FOURCC_____ ||
13551 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
13553 else if (demux->major_brand == FOURCC_qt__)
13554 style = "quicktime";
13555 /* fall back to assuming iso/3gp tag style */
13559 /* santize the name for the caps. */
13560 for (i = 0; i < 4; i++) {
13561 guint8 d = data[4 + i];
13562 if (g_ascii_isalnum (d))
13563 ndata[i] = g_ascii_tolower (d);
13568 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
13569 ndata[0], ndata[1], ndata[2], ndata[3]);
13570 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
13572 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
13573 sample = gst_sample_new (buf, NULL, NULL, s);
13574 gst_buffer_unref (buf);
13575 g_free (media_type);
13577 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
13580 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
13581 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
13583 gst_sample_unref (sample);
13587 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
13594 GstQtDemuxTagList demuxtaglist;
13596 demuxtaglist.demux = qtdemux;
13597 demuxtaglist.taglist = taglist;
13599 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
13600 if (meta != NULL) {
13601 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
13602 if (ilst == NULL) {
13603 GST_LOG_OBJECT (qtdemux, "no ilst");
13608 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
13612 while (i < G_N_ELEMENTS (add_funcs)) {
13613 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
13617 len = QT_UINT32 (node->data);
13619 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
13620 GST_FOURCC_ARGS (add_funcs[i].fourcc));
13622 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
13623 add_funcs[i].gst_tag_bis, node);
13625 g_node_destroy (node);
13631 /* parsed nodes have been removed, pass along remainder as blob */
13632 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
13633 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
13635 /* parse up XMP_ node if existing */
13636 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
13637 if (xmp_ != NULL) {
13639 GstTagList *xmptaglist;
13641 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
13642 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
13643 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
13644 gst_buffer_unref (buf);
13646 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
13648 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
13654 GstStructure *structure; /* helper for sort function */
13656 guint min_req_bitrate;
13657 guint min_req_qt_version;
13661 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13663 GstQtReference *ref_a = (GstQtReference *) a;
13664 GstQtReference *ref_b = (GstQtReference *) b;
13666 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13667 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13669 /* known bitrates go before unknown; higher bitrates go first */
13670 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13673 /* sort the redirects and post a message for the application.
13676 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13678 GstQtReference *best;
13681 GValue list_val = { 0, };
13684 g_assert (references != NULL);
13686 references = g_list_sort (references, qtdemux_redirects_sort_func);
13688 best = (GstQtReference *) references->data;
13690 g_value_init (&list_val, GST_TYPE_LIST);
13692 for (l = references; l != NULL; l = l->next) {
13693 GstQtReference *ref = (GstQtReference *) l->data;
13694 GValue struct_val = { 0, };
13696 ref->structure = gst_structure_new ("redirect",
13697 "new-location", G_TYPE_STRING, ref->location, NULL);
13699 if (ref->min_req_bitrate > 0) {
13700 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13701 ref->min_req_bitrate, NULL);
13704 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13705 g_value_set_boxed (&struct_val, ref->structure);
13706 gst_value_list_append_value (&list_val, &struct_val);
13707 g_value_unset (&struct_val);
13708 /* don't free anything here yet, since we need best->structure below */
13711 g_assert (best != NULL);
13712 s = gst_structure_copy (best->structure);
13714 if (g_list_length (references) > 1) {
13715 gst_structure_set_value (s, "locations", &list_val);
13718 g_value_unset (&list_val);
13720 for (l = references; l != NULL; l = l->next) {
13721 GstQtReference *ref = (GstQtReference *) l->data;
13723 gst_structure_free (ref->structure);
13724 g_free (ref->location);
13727 g_list_free (references);
13729 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13730 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13731 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13732 qtdemux->posted_redirect = TRUE;
13735 /* look for redirect nodes, collect all redirect information and
13739 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13741 GNode *rmra, *rmda, *rdrf;
13743 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13745 GList *redirects = NULL;
13747 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13749 GstQtReference ref = { NULL, NULL, 0, 0 };
13750 GNode *rmdr, *rmvc;
13752 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13753 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13754 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13755 ref.min_req_bitrate);
13758 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13759 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13760 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13762 #ifndef GST_DISABLE_GST_DEBUG
13763 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13765 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13767 GST_LOG_OBJECT (qtdemux,
13768 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13769 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13770 bitmask, check_type);
13771 if (package == FOURCC_qtim && check_type == 0) {
13772 ref.min_req_qt_version = version;
13776 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13782 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13783 if (ref_len > 20) {
13784 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13785 ref_data = (guint8 *) rdrf->data + 20;
13786 if (ref_type == FOURCC_alis) {
13787 guint record_len, record_version, fn_len;
13789 if (ref_len > 70) {
13790 /* MacOSX alias record, google for alias-layout.txt */
13791 record_len = QT_UINT16 (ref_data + 4);
13792 record_version = QT_UINT16 (ref_data + 4 + 2);
13793 fn_len = QT_UINT8 (ref_data + 50);
13794 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13795 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13798 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13801 } else if (ref_type == FOURCC_url_) {
13802 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13804 GST_DEBUG_OBJECT (qtdemux,
13805 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13806 GST_FOURCC_ARGS (ref_type));
13808 if (ref.location != NULL) {
13809 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13811 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13813 GST_WARNING_OBJECT (qtdemux,
13814 "Failed to extract redirect location from rdrf atom");
13817 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13821 /* look for others */
13822 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13825 if (redirects != NULL) {
13826 qtdemux_process_redirects (qtdemux, redirects);
13832 static GstTagList *
13833 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13837 if (tags == NULL) {
13838 tags = gst_tag_list_new_empty ();
13839 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13842 if (qtdemux->major_brand == FOURCC_mjp2)
13843 fmt = "Motion JPEG 2000";
13844 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13846 else if (qtdemux->major_brand == FOURCC_qt__)
13848 else if (qtdemux->fragmented)
13851 fmt = "ISO MP4/M4A";
13853 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13854 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13856 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13862 /* we have read the complete moov node now.
13863 * This function parses all of the relevant info, creates the traks and
13864 * prepares all data structures for playback
13867 qtdemux_parse_tree (GstQTDemux * qtdemux)
13874 guint64 creation_time;
13875 GstDateTime *datetime = NULL;
13878 /* make sure we have a usable taglist */
13879 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13881 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13882 if (mvhd == NULL) {
13883 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13884 return qtdemux_parse_redirects (qtdemux);
13887 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13888 if (version == 1) {
13889 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13890 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13891 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13892 } else if (version == 0) {
13893 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13894 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13895 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13897 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13901 /* Moving qt creation time (secs since 1904) to unix time */
13902 if (creation_time != 0) {
13903 /* Try to use epoch first as it should be faster and more commonly found */
13904 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13907 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13908 /* some data cleansing sanity */
13909 g_get_current_time (&now);
13910 if (now.tv_sec + 24 * 3600 < creation_time) {
13911 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13913 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13916 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13917 GDateTime *dt, *dt_local;
13919 dt = g_date_time_add_seconds (base_dt, creation_time);
13920 dt_local = g_date_time_to_local (dt);
13921 datetime = gst_date_time_new_from_g_date_time (dt_local);
13923 g_date_time_unref (base_dt);
13924 g_date_time_unref (dt);
13928 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13929 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13931 gst_date_time_unref (datetime);
13934 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13935 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13937 /* check for fragmented file and get some (default) data */
13938 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13941 GstByteReader mehd_data;
13943 /* let track parsing or anyone know weird stuff might happen ... */
13944 qtdemux->fragmented = TRUE;
13946 /* compensate for total duration */
13947 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13949 qtdemux_parse_mehd (qtdemux, &mehd_data);
13952 /* Update the movie segment duration, unless it was directly given to us
13953 * by upstream. Otherwise let it as is, as we don't want to mangle the
13954 * duration provided by upstream that may come e.g. from a MPD file. */
13955 if (!qtdemux->upstream_format_is_time) {
13956 GstClockTime duration;
13957 /* set duration in the segment info */
13958 gst_qtdemux_get_duration (qtdemux, &duration);
13959 qtdemux->segment.duration = duration;
13960 /* also do not exceed duration; stop is set that way post seek anyway,
13961 * and segment activation falls back to duration,
13962 * whereas loop only checks stop, so let's align this here as well */
13963 qtdemux->segment.stop = duration;
13966 /* parse all traks */
13967 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13969 qtdemux_parse_trak (qtdemux, trak);
13970 /* iterate all siblings */
13971 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13974 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13977 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13979 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13981 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13984 /* maybe also some tags in meta box */
13985 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13987 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13988 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13990 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13993 /* parse any protection system info */
13994 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13996 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13997 qtdemux_parse_pssh (qtdemux, pssh);
13998 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14001 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14006 /* taken from ffmpeg */
14008 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14020 len = (len << 7) | (c & 0x7f);
14029 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14030 gsize codec_data_size)
14032 GList *list = NULL;
14033 guint8 *p = codec_data;
14034 gint i, offset, num_packets;
14035 guint *length, last;
14037 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14039 if (codec_data == NULL || codec_data_size == 0)
14042 /* start of the stream and vorbis audio or theora video, need to
14043 * send the codec_priv data as first three packets */
14044 num_packets = p[0] + 1;
14045 GST_DEBUG_OBJECT (qtdemux,
14046 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14047 (guint) num_packets, codec_data_size);
14049 /* Let's put some limits, Don't think there even is a xiph codec
14050 * with more than 3-4 headers */
14051 if (G_UNLIKELY (num_packets > 16)) {
14052 GST_WARNING_OBJECT (qtdemux,
14053 "Unlikely number of xiph headers, most likely not valid");
14057 length = g_alloca (num_packets * sizeof (guint));
14061 /* first packets, read length values */
14062 for (i = 0; i < num_packets - 1; i++) {
14064 while (offset < codec_data_size) {
14065 length[i] += p[offset];
14066 if (p[offset++] != 0xff)
14071 if (offset + last > codec_data_size)
14074 /* last packet is the remaining size */
14075 length[i] = codec_data_size - offset - last;
14077 for (i = 0; i < num_packets; i++) {
14080 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14082 if (offset + length[i] > codec_data_size)
14085 hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
14086 list = g_list_append (list, hdr);
14088 offset += length[i];
14097 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14103 /* this can change the codec originally present in @list */
14105 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14106 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14108 int len = QT_UINT32 (esds->data);
14109 guint8 *ptr = esds->data;
14110 guint8 *end = ptr + len;
14112 guint8 *data_ptr = NULL;
14114 guint8 object_type_id = 0;
14115 guint8 stream_type = 0;
14116 const char *codec_name = NULL;
14117 GstCaps *caps = NULL;
14119 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14121 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14123 while (ptr + 1 < end) {
14124 tag = QT_UINT8 (ptr);
14125 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14127 len = read_descr_size (ptr, end, &ptr);
14128 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14130 /* Check the stated amount of data is available for reading */
14131 if (len < 0 || ptr + len > end)
14135 case ES_DESCRIPTOR_TAG:
14136 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14137 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14140 case DECODER_CONFIG_DESC_TAG:{
14141 guint max_bitrate, avg_bitrate;
14143 object_type_id = QT_UINT8 (ptr);
14144 stream_type = QT_UINT8 (ptr + 1) >> 2;
14145 max_bitrate = QT_UINT32 (ptr + 5);
14146 avg_bitrate = QT_UINT32 (ptr + 9);
14147 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14148 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14149 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14150 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14151 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14152 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14153 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14154 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14156 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14157 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14158 avg_bitrate, NULL);
14163 case DECODER_SPECIFIC_INFO_TAG:
14164 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14165 if (object_type_id == 0xe0 && len == 0x40) {
14171 GST_DEBUG_OBJECT (qtdemux,
14172 "Have VOBSUB palette. Creating palette event");
14173 /* move to decConfigDescr data and read palette */
14175 for (i = 0; i < 16; i++) {
14176 clut[i] = QT_UINT32 (data);
14180 s = gst_structure_new ("application/x-gst-dvd", "event",
14181 G_TYPE_STRING, "dvd-spu-clut-change",
14182 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14183 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14184 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14185 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14186 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14187 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14188 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14189 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14192 /* store event and trigger custom processing */
14193 stream->pending_event =
14194 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14196 /* Generic codec_data handler puts it on the caps */
14203 case SL_CONFIG_DESC_TAG:
14204 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14208 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14210 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14216 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14217 * in use, and should also be used to override some other parameters for some
14219 switch (object_type_id) {
14220 case 0x20: /* MPEG-4 */
14221 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14222 * profile_and_level_indication */
14223 if (data_ptr != NULL && data_len >= 5 &&
14224 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14225 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14226 data_ptr + 4, data_len - 4);
14228 break; /* Nothing special needed here */
14229 case 0x21: /* H.264 */
14230 codec_name = "H.264 / AVC";
14231 caps = gst_caps_new_simple ("video/x-h264",
14232 "stream-format", G_TYPE_STRING, "avc",
14233 "alignment", G_TYPE_STRING, "au", NULL);
14235 case 0x40: /* AAC (any) */
14236 case 0x66: /* AAC Main */
14237 case 0x67: /* AAC LC */
14238 case 0x68: /* AAC SSR */
14239 /* Override channels and rate based on the codec_data, as it's often
14241 /* Only do so for basic setup without HE-AAC extension */
14242 if (data_ptr && data_len == 2) {
14243 guint channels, rate;
14245 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14247 entry->n_channels = channels;
14249 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14251 entry->rate = rate;
14254 /* Set level and profile if possible */
14255 if (data_ptr != NULL && data_len >= 2) {
14256 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14257 data_ptr, data_len);
14259 const gchar *profile_str = NULL;
14262 guint8 *codec_data;
14263 gint rate_idx, profile;
14265 /* No codec_data, let's invent something.
14266 * FIXME: This is wrong for SBR! */
14268 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14270 buffer = gst_buffer_new_and_alloc (2);
14271 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14272 codec_data = map.data;
14275 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14278 switch (object_type_id) {
14280 profile_str = "main";
14284 profile_str = "lc";
14288 profile_str = "ssr";
14296 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14298 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14300 gst_buffer_unmap (buffer, &map);
14301 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14302 GST_TYPE_BUFFER, buffer, NULL);
14303 gst_buffer_unref (buffer);
14306 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14307 G_TYPE_STRING, profile_str, NULL);
14311 case 0x60: /* MPEG-2, various profiles */
14317 codec_name = "MPEG-2 video";
14318 caps = gst_caps_new_simple ("video/mpeg",
14319 "mpegversion", G_TYPE_INT, 2,
14320 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14322 case 0x69: /* MPEG-2 BC audio */
14323 case 0x6B: /* MPEG-1 audio */
14324 caps = gst_caps_new_simple ("audio/mpeg",
14325 "mpegversion", G_TYPE_INT, 1, NULL);
14326 codec_name = "MPEG-1 audio";
14328 case 0x6A: /* MPEG-1 */
14329 codec_name = "MPEG-1 video";
14330 caps = gst_caps_new_simple ("video/mpeg",
14331 "mpegversion", G_TYPE_INT, 1,
14332 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14334 case 0x6C: /* MJPEG */
14336 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14338 codec_name = "Motion-JPEG";
14340 case 0x6D: /* PNG */
14342 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14344 codec_name = "PNG still images";
14346 case 0x6E: /* JPEG2000 */
14347 codec_name = "JPEG-2000";
14348 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14350 case 0xA4: /* Dirac */
14351 codec_name = "Dirac";
14352 caps = gst_caps_new_empty_simple ("video/x-dirac");
14354 case 0xA5: /* AC3 */
14355 codec_name = "AC-3 audio";
14356 caps = gst_caps_new_simple ("audio/x-ac3",
14357 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14359 case 0xA9: /* AC3 */
14360 codec_name = "DTS audio";
14361 caps = gst_caps_new_simple ("audio/x-dts",
14362 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14365 if (stream_type == 0x05 && data_ptr) {
14367 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14370 GValue arr_val = G_VALUE_INIT;
14371 GValue buf_val = G_VALUE_INIT;
14374 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14375 codec_name = "Vorbis";
14376 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14377 g_value_init (&arr_val, GST_TYPE_ARRAY);
14378 g_value_init (&buf_val, GST_TYPE_BUFFER);
14379 for (tmp = headers; tmp; tmp = tmp->next) {
14380 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14381 gst_value_array_append_value (&arr_val, &buf_val);
14383 s = gst_caps_get_structure (caps, 0);
14384 gst_structure_take_value (s, "streamheader", &arr_val);
14385 g_value_unset (&buf_val);
14386 g_list_free (headers);
14393 case 0xE1: /* QCELP */
14394 /* QCELP, the codec_data is a riff tag (little endian) with
14395 * 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). */
14396 caps = gst_caps_new_empty_simple ("audio/qcelp");
14397 codec_name = "QCELP";
14403 /* If we have a replacement caps, then change our caps for this stream */
14405 gst_caps_unref (entry->caps);
14406 entry->caps = caps;
14409 if (codec_name && list)
14410 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14411 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14413 /* Add the codec_data attribute to caps, if we have it */
14417 buffer = gst_buffer_new_and_alloc (data_len);
14418 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14420 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14421 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14423 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14425 gst_buffer_unref (buffer);
14430 static inline GstCaps *
14431 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14435 char *s, fourstr[5];
14437 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14438 for (i = 0; i < 4; i++) {
14439 if (!g_ascii_isalnum (fourstr[i]))
14442 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14443 caps = gst_caps_new_empty_simple (s);
14448 #define _codec(name) \
14450 if (codec_name) { \
14451 *codec_name = g_strdup (name); \
14456 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14457 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14458 const guint8 * stsd_entry_data, gchar ** codec_name)
14460 GstCaps *caps = NULL;
14461 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14465 _codec ("PNG still images");
14466 caps = gst_caps_new_empty_simple ("image/png");
14469 _codec ("JPEG still images");
14471 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14474 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14475 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14476 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14477 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14478 _codec ("Motion-JPEG");
14480 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14483 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14484 _codec ("Motion-JPEG format B");
14485 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14488 _codec ("JPEG-2000");
14489 /* override to what it should be according to spec, avoid palette_data */
14490 entry->bits_per_sample = 24;
14491 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14494 _codec ("Sorensen video v.3");
14495 caps = gst_caps_new_simple ("video/x-svq",
14496 "svqversion", G_TYPE_INT, 3, NULL);
14498 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14499 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14500 _codec ("Sorensen video v.1");
14501 caps = gst_caps_new_simple ("video/x-svq",
14502 "svqversion", G_TYPE_INT, 1, NULL);
14504 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14505 caps = gst_caps_new_empty_simple ("video/x-raw");
14506 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14507 _codec ("Windows Raw RGB");
14508 stream->alignment = 32;
14514 bps = QT_UINT16 (stsd_entry_data + 82);
14517 format = GST_VIDEO_FORMAT_RGB15;
14520 format = GST_VIDEO_FORMAT_RGB16;
14523 format = GST_VIDEO_FORMAT_RGB;
14526 format = GST_VIDEO_FORMAT_ARGB;
14534 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14535 format = GST_VIDEO_FORMAT_I420;
14537 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14538 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14539 format = GST_VIDEO_FORMAT_I420;
14542 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14543 format = GST_VIDEO_FORMAT_UYVY;
14545 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14546 format = GST_VIDEO_FORMAT_v308;
14548 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14549 format = GST_VIDEO_FORMAT_v216;
14552 format = GST_VIDEO_FORMAT_v210;
14554 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14555 format = GST_VIDEO_FORMAT_r210;
14557 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14558 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14559 format = GST_VIDEO_FORMAT_v410;
14562 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14563 * but different order than AYUV
14564 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14565 format = GST_VIDEO_FORMAT_v408;
14568 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14569 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14570 _codec ("MPEG-1 video");
14571 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14572 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14574 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14575 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14576 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14577 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14578 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14579 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14580 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14581 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14582 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14583 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14584 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14585 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14586 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14587 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14588 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14589 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14590 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14591 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14592 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14593 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14594 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14595 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14596 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14597 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14598 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14599 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14600 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14601 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14602 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14603 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14604 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14605 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14606 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14607 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14608 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14609 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14610 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14611 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14612 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14613 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14614 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14615 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14616 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14617 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14618 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14619 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14620 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14621 _codec ("MPEG-2 video");
14622 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14623 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14625 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14626 _codec ("GIF still images");
14627 caps = gst_caps_new_empty_simple ("image/gif");
14630 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14632 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14634 /* ffmpeg uses the height/width props, don't know why */
14635 caps = gst_caps_new_simple ("video/x-h263",
14636 "variant", G_TYPE_STRING, "itu", NULL);
14640 _codec ("MPEG-4 video");
14641 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14642 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14644 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14645 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14646 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14647 caps = gst_caps_new_simple ("video/x-msmpeg",
14648 "msmpegversion", G_TYPE_INT, 43, NULL);
14650 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14652 caps = gst_caps_new_simple ("video/x-divx",
14653 "divxversion", G_TYPE_INT, 3, NULL);
14655 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14656 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14658 caps = gst_caps_new_simple ("video/x-divx",
14659 "divxversion", G_TYPE_INT, 4, NULL);
14661 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14663 caps = gst_caps_new_simple ("video/x-divx",
14664 "divxversion", G_TYPE_INT, 5, NULL);
14667 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14669 caps = gst_caps_new_simple ("video/x-ffv",
14670 "ffvversion", G_TYPE_INT, 1, NULL);
14673 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14674 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14679 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14680 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14681 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14685 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14686 _codec ("Cinepak");
14687 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14689 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14690 _codec ("Apple QuickDraw");
14691 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14693 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14694 _codec ("Apple video");
14695 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14699 _codec ("H.264 / AVC");
14700 caps = gst_caps_new_simple ("video/x-h264",
14701 "stream-format", G_TYPE_STRING, "avc",
14702 "alignment", G_TYPE_STRING, "au", NULL);
14705 _codec ("H.264 / AVC");
14706 caps = gst_caps_new_simple ("video/x-h264",
14707 "stream-format", G_TYPE_STRING, "avc3",
14708 "alignment", G_TYPE_STRING, "au", NULL);
14712 _codec ("H.265 / HEVC");
14713 caps = gst_caps_new_simple ("video/x-h265",
14714 "stream-format", G_TYPE_STRING, "hvc1",
14715 "alignment", G_TYPE_STRING, "au", NULL);
14718 _codec ("H.265 / HEVC");
14719 caps = gst_caps_new_simple ("video/x-h265",
14720 "stream-format", G_TYPE_STRING, "hev1",
14721 "alignment", G_TYPE_STRING, "au", NULL);
14724 _codec ("Run-length encoding");
14725 caps = gst_caps_new_simple ("video/x-rle",
14726 "layout", G_TYPE_STRING, "quicktime", NULL);
14729 _codec ("Run-length encoding");
14730 caps = gst_caps_new_simple ("video/x-rle",
14731 "layout", G_TYPE_STRING, "microsoft", NULL);
14733 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14734 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14735 _codec ("Indeo Video 3");
14736 caps = gst_caps_new_simple ("video/x-indeo",
14737 "indeoversion", G_TYPE_INT, 3, NULL);
14739 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14740 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14741 _codec ("Intel Video 4");
14742 caps = gst_caps_new_simple ("video/x-indeo",
14743 "indeoversion", G_TYPE_INT, 4, NULL);
14747 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14748 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14749 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14750 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14751 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14752 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14753 _codec ("DV Video");
14754 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14755 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14757 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14758 case FOURCC_dv5p: /* DVCPRO50 PAL */
14759 _codec ("DVCPro50 Video");
14760 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14761 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14763 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14764 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14765 _codec ("DVCProHD Video");
14766 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14767 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14769 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14770 _codec ("Apple Graphics (SMC)");
14771 caps = gst_caps_new_empty_simple ("video/x-smc");
14773 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14775 caps = gst_caps_new_empty_simple ("video/x-vp3");
14777 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14778 _codec ("VP6 Flash");
14779 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14783 caps = gst_caps_new_empty_simple ("video/x-theora");
14784 /* theora uses one byte of padding in the data stream because it does not
14785 * allow 0 sized packets while theora does */
14786 entry->padding = 1;
14790 caps = gst_caps_new_empty_simple ("video/x-dirac");
14792 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14793 _codec ("TIFF still images");
14794 caps = gst_caps_new_empty_simple ("image/tiff");
14796 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14797 _codec ("Apple Intermediate Codec");
14798 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14800 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14801 _codec ("AVID DNxHD");
14802 caps = gst_caps_from_string ("video/x-dnxhd");
14806 _codec ("On2 VP8");
14807 caps = gst_caps_from_string ("video/x-vp8");
14810 _codec ("Google VP9");
14811 caps = gst_caps_from_string ("video/x-vp9");
14814 _codec ("Apple ProRes LT");
14816 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14820 _codec ("Apple ProRes HQ");
14822 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14826 _codec ("Apple ProRes");
14828 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14832 _codec ("Apple ProRes Proxy");
14834 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14838 _codec ("Apple ProRes 4444");
14840 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14844 _codec ("Apple ProRes 4444 XQ");
14846 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14850 _codec ("GoPro CineForm");
14851 caps = gst_caps_from_string ("video/x-cineform");
14856 caps = gst_caps_new_simple ("video/x-wmv",
14857 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14861 caps = gst_caps_new_empty_simple ("video/x-av1");
14863 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14866 caps = _get_unknown_codec_name ("video", fourcc);
14871 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14874 gst_video_info_init (&info);
14875 gst_video_info_set_format (&info, format, entry->width, entry->height);
14877 caps = gst_video_info_to_caps (&info);
14878 *codec_name = gst_pb_utils_get_codec_description (caps);
14880 /* enable clipping for raw video streams */
14881 stream->need_clip = TRUE;
14882 stream->alignment = 32;
14889 round_up_pow2 (guint n)
14901 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14902 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14903 int len, gchar ** codec_name)
14906 const GstStructure *s;
14909 GstAudioFormat format = 0;
14912 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14914 depth = entry->bytes_per_packet * 8;
14917 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14919 /* 8-bit audio is unsigned */
14921 format = GST_AUDIO_FORMAT_U8;
14922 /* otherwise it's signed and big-endian just like 'twos' */
14924 endian = G_BIG_ENDIAN;
14931 endian = G_LITTLE_ENDIAN;
14934 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14936 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14940 caps = gst_caps_new_simple ("audio/x-raw",
14941 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14942 "layout", G_TYPE_STRING, "interleaved", NULL);
14943 stream->alignment = GST_ROUND_UP_8 (depth);
14944 stream->alignment = round_up_pow2 (stream->alignment);
14947 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14948 _codec ("Raw 64-bit floating-point audio");
14949 caps = gst_caps_new_simple ("audio/x-raw",
14950 "format", G_TYPE_STRING, "F64BE",
14951 "layout", G_TYPE_STRING, "interleaved", NULL);
14952 stream->alignment = 8;
14954 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14955 _codec ("Raw 32-bit floating-point audio");
14956 caps = gst_caps_new_simple ("audio/x-raw",
14957 "format", G_TYPE_STRING, "F32BE",
14958 "layout", G_TYPE_STRING, "interleaved", NULL);
14959 stream->alignment = 4;
14962 _codec ("Raw 24-bit PCM audio");
14963 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14965 caps = gst_caps_new_simple ("audio/x-raw",
14966 "format", G_TYPE_STRING, "S24BE",
14967 "layout", G_TYPE_STRING, "interleaved", NULL);
14968 stream->alignment = 4;
14970 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14971 _codec ("Raw 32-bit PCM audio");
14972 caps = gst_caps_new_simple ("audio/x-raw",
14973 "format", G_TYPE_STRING, "S32BE",
14974 "layout", G_TYPE_STRING, "interleaved", NULL);
14975 stream->alignment = 4;
14977 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14978 _codec ("Raw 16-bit PCM audio");
14979 caps = gst_caps_new_simple ("audio/x-raw",
14980 "format", G_TYPE_STRING, "S16LE",
14981 "layout", G_TYPE_STRING, "interleaved", NULL);
14982 stream->alignment = 2;
14985 _codec ("Mu-law audio");
14986 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14989 _codec ("A-law audio");
14990 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14994 _codec ("Microsoft ADPCM");
14995 /* Microsoft ADPCM-ACM code 2 */
14996 caps = gst_caps_new_simple ("audio/x-adpcm",
14997 "layout", G_TYPE_STRING, "microsoft", NULL);
15001 _codec ("DVI/IMA ADPCM");
15002 caps = gst_caps_new_simple ("audio/x-adpcm",
15003 "layout", G_TYPE_STRING, "dvi", NULL);
15007 _codec ("DVI/Intel IMA ADPCM");
15008 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15009 caps = gst_caps_new_simple ("audio/x-adpcm",
15010 "layout", G_TYPE_STRING, "quicktime", NULL);
15014 /* MPEG layer 3, CBR only (pre QT4.1) */
15016 _codec ("MPEG-1 layer 3");
15017 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15018 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15019 "mpegversion", G_TYPE_INT, 1, NULL);
15021 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15022 _codec ("MPEG-1 layer 2");
15024 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15025 "mpegversion", G_TYPE_INT, 1, NULL);
15028 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15029 _codec ("EAC-3 audio");
15030 caps = gst_caps_new_simple ("audio/x-eac3",
15031 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15032 entry->sampled = TRUE;
15034 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15036 _codec ("AC-3 audio");
15037 caps = gst_caps_new_simple ("audio/x-ac3",
15038 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15039 entry->sampled = TRUE;
15041 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15042 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15043 _codec ("DTS audio");
15044 caps = gst_caps_new_simple ("audio/x-dts",
15045 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15046 entry->sampled = TRUE;
15048 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15049 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15050 _codec ("DTS-HD audio");
15051 caps = gst_caps_new_simple ("audio/x-dts",
15052 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15053 entry->sampled = TRUE;
15057 caps = gst_caps_new_simple ("audio/x-mace",
15058 "maceversion", G_TYPE_INT, 3, NULL);
15062 caps = gst_caps_new_simple ("audio/x-mace",
15063 "maceversion", G_TYPE_INT, 6, NULL);
15065 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15067 caps = gst_caps_new_empty_simple ("application/ogg");
15069 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15070 _codec ("DV audio");
15071 caps = gst_caps_new_empty_simple ("audio/x-dv");
15074 _codec ("MPEG-4 AAC audio");
15075 caps = gst_caps_new_simple ("audio/mpeg",
15076 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15077 "stream-format", G_TYPE_STRING, "raw", NULL);
15079 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15080 _codec ("QDesign Music");
15081 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15084 _codec ("QDesign Music v.2");
15085 /* FIXME: QDesign music version 2 (no constant) */
15086 if (FALSE && data) {
15087 caps = gst_caps_new_simple ("audio/x-qdm2",
15088 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15089 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15090 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15092 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15096 _codec ("GSM audio");
15097 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15100 _codec ("AMR audio");
15101 caps = gst_caps_new_empty_simple ("audio/AMR");
15104 _codec ("AMR-WB audio");
15105 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15108 _codec ("Quicktime IMA ADPCM");
15109 caps = gst_caps_new_simple ("audio/x-adpcm",
15110 "layout", G_TYPE_STRING, "quicktime", NULL);
15113 _codec ("Apple lossless audio");
15114 caps = gst_caps_new_empty_simple ("audio/x-alac");
15117 _codec ("Free Lossless Audio Codec");
15118 caps = gst_caps_new_simple ("audio/x-flac",
15119 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15121 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15122 _codec ("QualComm PureVoice");
15123 caps = gst_caps_from_string ("audio/qcelp");
15128 caps = gst_caps_new_empty_simple ("audio/x-wma");
15132 caps = gst_caps_new_empty_simple ("audio/x-opus");
15139 GstAudioFormat format;
15142 FLAG_IS_FLOAT = 0x1,
15143 FLAG_IS_BIG_ENDIAN = 0x2,
15144 FLAG_IS_SIGNED = 0x4,
15145 FLAG_IS_PACKED = 0x8,
15146 FLAG_IS_ALIGNED_HIGH = 0x10,
15147 FLAG_IS_NON_INTERLEAVED = 0x20
15149 _codec ("Raw LPCM audio");
15151 if (data && len >= 36) {
15152 depth = QT_UINT32 (data + 24);
15153 flags = QT_UINT32 (data + 28);
15154 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15156 if ((flags & FLAG_IS_FLOAT) == 0) {
15161 if ((flags & FLAG_IS_ALIGNED_HIGH))
15164 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15165 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15166 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15167 caps = gst_caps_new_simple ("audio/x-raw",
15168 "format", G_TYPE_STRING,
15170 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15171 "UNKNOWN", "layout", G_TYPE_STRING,
15172 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15173 "interleaved", NULL);
15174 stream->alignment = GST_ROUND_UP_8 (depth);
15175 stream->alignment = round_up_pow2 (stream->alignment);
15180 if (flags & FLAG_IS_BIG_ENDIAN)
15181 format = GST_AUDIO_FORMAT_F64BE;
15183 format = GST_AUDIO_FORMAT_F64LE;
15185 if (flags & FLAG_IS_BIG_ENDIAN)
15186 format = GST_AUDIO_FORMAT_F32BE;
15188 format = GST_AUDIO_FORMAT_F32LE;
15190 caps = gst_caps_new_simple ("audio/x-raw",
15191 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15192 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15193 "non-interleaved" : "interleaved", NULL);
15194 stream->alignment = width / 8;
15198 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15202 caps = _get_unknown_codec_name ("audio", fourcc);
15208 GstCaps *templ_caps =
15209 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15210 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15211 gst_caps_unref (caps);
15212 gst_caps_unref (templ_caps);
15213 caps = intersection;
15216 /* enable clipping for raw audio streams */
15217 s = gst_caps_get_structure (caps, 0);
15218 name = gst_structure_get_name (s);
15219 if (g_str_has_prefix (name, "audio/x-raw")) {
15220 stream->need_clip = TRUE;
15221 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15222 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
15228 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15229 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15230 const guint8 * stsd_entry_data, gchar ** codec_name)
15234 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15238 _codec ("DVD subtitle");
15239 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15240 stream->need_process = TRUE;
15243 _codec ("Quicktime timed text");
15246 _codec ("3GPP timed text");
15248 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15250 /* actual text piece needs to be extracted */
15251 stream->need_process = TRUE;
15254 _codec ("XML subtitles");
15255 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15258 _codec ("CEA 608 Closed Caption");
15260 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15261 G_TYPE_STRING, "cc_data", NULL);
15262 stream->need_process = TRUE;
15265 _codec ("CEA 708 Closed Caption");
15267 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15268 G_TYPE_STRING, "cdp", NULL);
15269 stream->need_process = TRUE;
15274 caps = _get_unknown_codec_name ("text", fourcc);
15282 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15283 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15284 const guint8 * stsd_entry_data, gchar ** codec_name)
15290 _codec ("MPEG 1 video");
15291 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15292 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15302 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15303 const gchar * system_id)
15307 if (!qtdemux->protection_system_ids)
15308 qtdemux->protection_system_ids =
15309 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15310 /* Check whether we already have an entry for this system ID. */
15311 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15312 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15313 if (g_ascii_strcasecmp (system_id, id) == 0) {
15317 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15318 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,