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>
60 #include "qtatomparser.h"
61 #include "qtdemux_types.h"
62 #include "qtdemux_dump.h"
64 #include "descriptors.h"
65 #include "qtdemux_lang.h"
67 #include "qtpalette.h"
69 #include "gst/riff/riff-media.h"
70 #include "gst/riff/riff-read.h"
72 #include <gst/pbutils/pbutils.h>
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
99 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
103 GST_DEBUG_CATEGORY (qtdemux_debug);
105 typedef struct _QtDemuxSegment QtDemuxSegment;
106 typedef struct _QtDemuxSample QtDemuxSample;
108 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
110 struct _QtDemuxSample
113 gint32 pts_offset; /* Add this value to timestamp to get the pts */
115 guint64 timestamp; /* DTS In mov time */
116 guint32 duration; /* In mov time */
117 gboolean keyframe; /* TRUE when this packet is a keyframe */
120 /* Macros for converting to/from timescale */
121 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
122 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
124 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
125 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
127 /* timestamp is the DTS */
128 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
129 /* timestamp + offset + cslg_shift is the outgoing PTS */
130 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
131 /* timestamp + offset is the PTS used for internal seek calcuations */
132 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
133 /* timestamp + duration - dts is the duration */
134 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
136 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
139 * Quicktime has tracks and segments. A track is a continuous piece of
140 * multimedia content. The track is not always played from start to finish but
141 * instead, pieces of the track are 'cut out' and played in sequence. This is
142 * what the segments do.
144 * Inside the track we have keyframes (K) and delta frames. The track has its
145 * own timing, which starts from 0 and extends to end. The position in the track
146 * is called the media_time.
148 * The segments now describe the pieces that should be played from this track
149 * and are basically tuples of media_time/duration/rate entries. We can have
150 * multiple segments and they are all played after one another. An example:
152 * segment 1: media_time: 1 second, duration: 1 second, rate 1
153 * segment 2: media_time: 3 second, duration: 2 second, rate 2
155 * To correctly play back this track, one must play: 1 second of media starting
156 * from media_time 1 followed by 2 seconds of media starting from media_time 3
159 * Each of the segments will be played at a specific time, the first segment at
160 * time 0, the second one after the duration of the first one, etc.. Note that
161 * the time in resulting playback is not identical to the media_time of the
164 * Visually, assuming the track has 4 second of media_time:
167 * .-----------------------------------------------------------.
168 * track: | K.....K.........K........K.......K.......K...........K... |
169 * '-----------------------------------------------------------'
171 * .------------^ ^ .----------^ ^
172 * / .-------------' / .------------------'
174 * .--------------. .--------------.
175 * | segment 1 | | segment 2 |
176 * '--------------' '--------------'
178 * The challenge here is to cut out the right pieces of the track for each of
179 * the playback segments. This fortunately can easily be done with the SEGMENT
180 * events of GStreamer.
182 * For playback of segment 1, we need to provide the decoder with the keyframe
183 * (a), in the above figure, but we must instruct it only to output the decoded
184 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
185 * position set to the time of the segment: 0.
187 * We then proceed to push data from keyframe (a) to frame (b). The decoder
188 * decodes but clips all before media_time 1.
190 * After finishing a segment, we push out a new SEGMENT event with the clipping
191 * boundaries of the new data.
193 * This is a good usecase for the GStreamer accumulated SEGMENT events.
196 struct _QtDemuxSegment
198 /* global time and duration, all gst time */
200 GstClockTime stop_time;
201 GstClockTime duration;
202 /* media time of trak, all gst time */
203 GstClockTime media_start;
204 GstClockTime media_stop;
206 /* Media start time in trak timescale units */
207 guint32 trak_media_start;
210 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
212 /* Used with fragmented MP4 files (mfra atom) */
217 } QtDemuxRandomAccessEntry;
219 typedef struct _QtDemuxStreamStsdEntry
230 /* Numerator/denominator framerate */
233 GstVideoColorimetry colorimetry;
234 guint16 bits_per_sample;
235 guint16 color_table_id;
236 GstMemory *rgb8_palette;
237 guint interlace_mode;
243 guint samples_per_packet;
244 guint samples_per_frame;
245 guint bytes_per_packet;
246 guint bytes_per_sample;
247 guint bytes_per_frame;
250 /* if we use chunks or samples */
254 } QtDemuxStreamStsdEntry;
256 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
258 struct _QtDemuxStream
262 QtDemuxStreamStsdEntry *stsd_entries;
263 guint stsd_entries_length;
264 guint cur_stsd_entry_index;
269 gboolean new_caps; /* If TRUE, caps need to be generated (by
270 * calling _configure_stream()) This happens
271 * for MSS and fragmented streams */
273 gboolean new_stream; /* signals that a stream_start is required */
274 gboolean on_keyframe; /* if this stream last pushed buffer was a
275 * keyframe. This is important to identify
276 * where to stop pushing buffers after a
277 * segment stop time */
279 /* if the stream has a redirect URI in its headers, we store it here */
286 guint64 duration; /* in timescale units */
290 gchar lang_id[4]; /* ISO 639-2T language code */
294 QtDemuxSample *samples;
295 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
296 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
298 guint32 n_samples_moof; /* sample count in a moof */
299 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
300 * the framerate of fragmented format stream */
301 guint64 duration_last_moof;
303 guint32 offset_in_sample; /* Offset in the current sample, used for
304 * streams which have got exceedingly big
305 * sample size (such as 24s of raw audio).
306 * Only used when max_buffer_size is non-NULL */
307 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
308 * Currently only set for raw audio streams*/
316 gboolean use_allocator;
317 GstAllocator *allocator;
318 GstAllocationParams params;
322 /* when a discontinuity is pending */
325 /* list of buffers to push first */
328 /* if we need to clip this buffer. This is only needed for uncompressed
332 /* buffer needs some custom processing, e.g. subtitles */
333 gboolean need_process;
335 /* current position */
336 guint32 segment_index;
337 guint32 sample_index;
338 GstClockTime time_position; /* in gst time */
339 guint64 accumulated_base;
341 /* the Gst segment we are processing out, used for clipping */
344 /* quicktime segments */
346 QtDemuxSegment *segments;
347 gboolean dummy_segment;
352 GstTagList *stream_tags;
353 gboolean send_global_tags;
355 GstEvent *pending_event;
365 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
369 GstByteReader co_chunk;
371 guint32 current_chunk;
373 guint32 samples_per_chunk;
374 guint32 stsd_sample_description_id;
375 guint32 stco_sample_index;
377 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
380 guint32 n_samples_per_chunk;
381 guint32 stsc_chunk_index;
382 guint32 stsc_sample_index;
383 guint64 chunk_offset;
386 guint32 stts_samples;
387 guint32 n_sample_times;
388 guint32 stts_sample_index;
390 guint32 stts_duration;
392 gboolean stss_present;
393 guint32 n_sample_syncs;
396 gboolean stps_present;
397 guint32 n_sample_partial_syncs;
399 QtDemuxRandomAccessEntry *ra_entries;
402 const QtDemuxRandomAccessEntry *pending_seek;
405 gboolean ctts_present;
406 guint32 n_composition_times;
408 guint32 ctts_sample_index;
416 gboolean parsed_trex;
417 guint32 def_sample_description_index; /* index is 1-based */
418 guint32 def_sample_duration;
419 guint32 def_sample_size;
420 guint32 def_sample_flags;
424 /* stereoscopic video streams */
425 GstVideoMultiviewMode multiview_mode;
426 GstVideoMultiviewFlags multiview_flags;
428 /* protected streams */
430 guint32 protection_scheme_type;
431 guint32 protection_scheme_version;
432 gpointer protection_scheme_info; /* specific to the protection scheme */
433 GQueue protection_scheme_event_queue;
436 /* Contains properties and cryptographic info for a set of samples from a
437 * track protected using Common Encryption (cenc) */
438 struct _QtDemuxCencSampleSetInfo
440 GstStructure *default_properties;
442 /* @crypto_info holds one GstStructure per sample */
443 GPtrArray *crypto_info;
447 qt_demux_state_string (enum QtDemuxState state)
450 case QTDEMUX_STATE_INITIAL:
452 case QTDEMUX_STATE_HEADER:
454 case QTDEMUX_STATE_MOVIE:
456 case QTDEMUX_STATE_BUFFER_MDAT:
457 return "<BUFFER_MDAT>";
463 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
464 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
465 guint32 fourcc, GstByteReader * parser);
466 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
467 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
468 guint32 fourcc, GstByteReader * parser);
470 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
472 static GstStaticPadTemplate gst_qtdemux_sink_template =
473 GST_STATIC_PAD_TEMPLATE ("sink",
476 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
480 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
481 GST_STATIC_PAD_TEMPLATE ("video_%u",
484 GST_STATIC_CAPS_ANY);
486 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
487 GST_STATIC_PAD_TEMPLATE ("audio_%u",
490 GST_STATIC_CAPS_ANY);
492 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
493 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
496 GST_STATIC_CAPS_ANY);
498 #define gst_qtdemux_parent_class parent_class
499 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
501 static void gst_qtdemux_dispose (GObject * object);
504 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
505 GstClockTime media_time);
507 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
508 QtDemuxStream * str, gint64 media_offset);
511 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
512 static GstIndex *gst_qtdemux_get_index (GstElement * element);
514 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
515 GstStateChange transition);
516 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
517 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
518 GstObject * parent, GstPadMode mode, gboolean active);
520 static void gst_qtdemux_loop (GstPad * pad);
521 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
523 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
525 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
526 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
527 QtDemuxStream * stream);
528 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
529 QtDemuxStream * stream);
530 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
533 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
534 const guint8 * buffer, guint length);
535 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
536 const guint8 * buffer, guint length);
537 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
538 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
541 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
542 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
544 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
545 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
546 const guint8 * stsd_entry_data, gchar ** codec_name);
547 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
548 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
549 const guint8 * data, int len, gchar ** codec_name);
550 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
551 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
552 gchar ** codec_name);
553 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
554 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
555 const guint8 * stsd_entry_data, gchar ** codec_name);
557 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
558 QtDemuxStream * stream, guint32 n);
559 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
560 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
561 QtDemuxStream * stream);
562 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
563 QtDemuxStream * stream);
564 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
565 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
566 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
567 QtDemuxStream * stream);
568 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
569 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
570 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
571 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
572 GstClockTime * _start, GstClockTime * _stop);
573 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
574 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
576 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
577 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
579 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
581 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
582 QtDemuxStream * stream, guint sample_index);
583 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
585 static void qtdemux_gst_structure_free (GstStructure * gststructure);
588 gst_qtdemux_class_init (GstQTDemuxClass * klass)
590 GObjectClass *gobject_class;
591 GstElementClass *gstelement_class;
593 gobject_class = (GObjectClass *) klass;
594 gstelement_class = (GstElementClass *) klass;
596 parent_class = g_type_class_peek_parent (klass);
598 gobject_class->dispose = gst_qtdemux_dispose;
600 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
602 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
603 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
606 gst_tag_register_musicbrainz_tags ();
608 gst_element_class_add_static_pad_template (gstelement_class,
609 &gst_qtdemux_sink_template);
610 gst_element_class_add_static_pad_template (gstelement_class,
611 &gst_qtdemux_videosrc_template);
612 gst_element_class_add_static_pad_template (gstelement_class,
613 &gst_qtdemux_audiosrc_template);
614 gst_element_class_add_static_pad_template (gstelement_class,
615 &gst_qtdemux_subsrc_template);
616 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
618 "Demultiplex a QuickTime file into audio and video streams",
619 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
621 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
626 gst_qtdemux_init (GstQTDemux * qtdemux)
629 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
630 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
631 gst_pad_set_activatemode_function (qtdemux->sinkpad,
632 qtdemux_sink_activate_mode);
633 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
634 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
635 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
637 qtdemux->state = QTDEMUX_STATE_INITIAL;
638 qtdemux->pullbased = FALSE;
639 qtdemux->posted_redirect = FALSE;
640 qtdemux->neededbytes = 16;
642 qtdemux->adapter = gst_adapter_new ();
644 qtdemux->first_mdat = -1;
645 qtdemux->got_moov = FALSE;
646 qtdemux->mdatoffset = -1;
647 qtdemux->mdatbuffer = NULL;
648 qtdemux->restoredata_buffer = NULL;
649 qtdemux->restoredata_offset = -1;
650 qtdemux->fragment_start = -1;
651 qtdemux->fragment_start_offset = -1;
652 qtdemux->media_caps = NULL;
653 qtdemux->exposed = FALSE;
654 qtdemux->mss_mode = FALSE;
655 qtdemux->pending_newsegment = NULL;
656 qtdemux->upstream_format_is_time = FALSE;
657 qtdemux->have_group_id = FALSE;
658 qtdemux->group_id = G_MAXUINT;
659 qtdemux->cenc_aux_info_offset = 0;
660 qtdemux->cenc_aux_info_sizes = NULL;
661 qtdemux->cenc_aux_sample_count = 0;
662 qtdemux->protection_system_ids = NULL;
663 g_queue_init (&qtdemux->protection_event_queue);
664 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
665 qtdemux->tag_list = gst_tag_list_new_empty ();
666 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
667 qtdemux->flowcombiner = gst_flow_combiner_new ();
669 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
673 gst_qtdemux_dispose (GObject * object)
675 GstQTDemux *qtdemux = GST_QTDEMUX (object);
677 if (qtdemux->adapter) {
678 g_object_unref (G_OBJECT (qtdemux->adapter));
679 qtdemux->adapter = NULL;
681 gst_tag_list_unref (qtdemux->tag_list);
682 gst_flow_combiner_free (qtdemux->flowcombiner);
683 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
685 g_queue_clear (&qtdemux->protection_event_queue);
687 g_free (qtdemux->cenc_aux_info_sizes);
688 qtdemux->cenc_aux_info_sizes = NULL;
690 G_OBJECT_CLASS (parent_class)->dispose (object);
694 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
696 if (qtdemux->posted_redirect) {
697 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
698 (_("This file contains no playable streams.")),
699 ("no known streams found, a redirect message has been posted"));
701 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
702 (_("This file contains no playable streams.")),
703 ("no known streams found"));
708 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
710 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
711 mem, size, 0, size, mem, free_func);
715 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
722 if (G_UNLIKELY (size == 0)) {
724 GstBuffer *tmp = NULL;
726 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
727 if (ret != GST_FLOW_OK)
730 gst_buffer_map (tmp, &map, GST_MAP_READ);
731 size = QT_UINT32 (map.data);
732 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
734 gst_buffer_unmap (tmp, &map);
735 gst_buffer_unref (tmp);
738 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
739 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
740 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
741 /* we're pulling header but already got most interesting bits,
742 * so never mind the rest (e.g. tags) (that much) */
743 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
747 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
748 (_("This file is invalid and cannot be played.")),
749 ("atom has bogus size %" G_GUINT64_FORMAT, size));
750 return GST_FLOW_ERROR;
754 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
756 if (G_UNLIKELY (flow != GST_FLOW_OK))
759 bsize = gst_buffer_get_size (*buf);
760 /* Catch short reads - we don't want any partial atoms */
761 if (G_UNLIKELY (bsize < size)) {
762 GST_WARNING_OBJECT (qtdemux,
763 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
764 gst_buffer_unref (*buf);
774 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
775 GstFormat src_format, gint64 src_value, GstFormat dest_format,
779 QtDemuxStream *stream = gst_pad_get_element_private (pad);
782 if (stream->subtype != FOURCC_vide) {
787 switch (src_format) {
788 case GST_FORMAT_TIME:
789 switch (dest_format) {
790 case GST_FORMAT_BYTES:{
791 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
797 *dest_value = stream->samples[index].offset;
799 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
800 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
801 GST_TIME_ARGS (src_value), *dest_value);
809 case GST_FORMAT_BYTES:
810 switch (dest_format) {
811 case GST_FORMAT_TIME:{
813 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
822 QTSTREAMTIME_TO_GSTTIME (stream,
823 stream->samples[index].timestamp);
824 GST_DEBUG_OBJECT (qtdemux,
825 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
826 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
845 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
847 gboolean res = FALSE;
849 *duration = GST_CLOCK_TIME_NONE;
851 if (qtdemux->duration != 0 &&
852 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
853 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
856 *duration = GST_CLOCK_TIME_NONE;
863 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
866 gboolean res = FALSE;
867 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
869 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
871 switch (GST_QUERY_TYPE (query)) {
872 case GST_QUERY_POSITION:{
875 gst_query_parse_position (query, &fmt, NULL);
876 if (fmt == GST_FORMAT_TIME
877 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
878 gst_query_set_position (query, GST_FORMAT_TIME,
879 qtdemux->segment.position);
884 case GST_QUERY_DURATION:{
887 gst_query_parse_duration (query, &fmt, NULL);
888 if (fmt == GST_FORMAT_TIME) {
889 /* First try to query upstream */
890 res = gst_pad_query_default (pad, parent, query);
892 GstClockTime duration;
893 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
894 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
901 case GST_QUERY_CONVERT:{
902 GstFormat src_fmt, dest_fmt;
903 gint64 src_value, dest_value = 0;
905 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
907 res = gst_qtdemux_src_convert (qtdemux, pad,
908 src_fmt, src_value, dest_fmt, &dest_value);
910 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
914 case GST_QUERY_FORMATS:
915 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
918 case GST_QUERY_SEEKING:{
922 /* try upstream first */
923 res = gst_pad_query_default (pad, parent, query);
926 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
927 if (fmt == GST_FORMAT_TIME) {
928 GstClockTime duration;
930 gst_qtdemux_get_duration (qtdemux, &duration);
932 if (!qtdemux->pullbased) {
935 /* we might be able with help from upstream */
937 q = gst_query_new_seeking (GST_FORMAT_BYTES);
938 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
939 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
940 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
944 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
950 case GST_QUERY_SEGMENT:
955 format = qtdemux->segment.format;
958 gst_segment_to_stream_time (&qtdemux->segment, format,
959 qtdemux->segment.start);
960 if ((stop = qtdemux->segment.stop) == -1)
961 stop = qtdemux->segment.duration;
963 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
965 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
970 res = gst_pad_query_default (pad, parent, query);
978 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
980 if (G_LIKELY (stream->pad)) {
981 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
982 GST_DEBUG_PAD_NAME (stream->pad));
984 if (!gst_tag_list_is_empty (stream->stream_tags)) {
985 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
986 stream->stream_tags);
987 gst_pad_push_event (stream->pad,
988 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
991 if (G_UNLIKELY (stream->send_global_tags)) {
992 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
994 gst_pad_push_event (stream->pad,
995 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
996 stream->send_global_tags = FALSE;
1001 /* push event on all source pads; takes ownership of the event */
1003 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1006 gboolean has_valid_stream = FALSE;
1007 GstEventType etype = GST_EVENT_TYPE (event);
1009 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1010 GST_EVENT_TYPE_NAME (event));
1012 for (n = 0; n < qtdemux->n_streams; n++) {
1014 QtDemuxStream *stream = qtdemux->streams[n];
1015 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
1017 if ((pad = stream->pad)) {
1018 has_valid_stream = TRUE;
1020 if (etype == GST_EVENT_EOS) {
1021 /* let's not send twice */
1022 if (stream->sent_eos)
1024 stream->sent_eos = TRUE;
1027 gst_pad_push_event (pad, gst_event_ref (event));
1031 gst_event_unref (event);
1033 /* if it is EOS and there are no pads, post an error */
1034 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1035 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1039 /* push a pending newsegment event, if any from the streaming thread */
1041 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1043 if (qtdemux->pending_newsegment) {
1044 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1045 qtdemux->pending_newsegment = NULL;
1055 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1057 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1059 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1065 /* find the index of the sample that includes the data for @media_time using a
1066 * binary search. Only to be called in optimized cases of linear search below.
1068 * Returns the index of the sample.
1071 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1074 QtDemuxSample *result;
1077 /* convert media_time to mov format */
1079 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1081 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1082 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1083 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1085 if (G_LIKELY (result))
1086 index = result - str->samples;
1095 /* find the index of the sample that includes the data for @media_offset using a
1098 * Returns the index of the sample.
1101 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1102 QtDemuxStream * str, gint64 media_offset)
1104 QtDemuxSample *result = str->samples;
1107 if (result == NULL || str->n_samples == 0)
1110 if (media_offset == result->offset)
1114 while (index < str->n_samples - 1) {
1115 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1118 if (media_offset < result->offset)
1129 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1134 /* find the index of the sample that includes the data for @media_time using a
1135 * linear search, and keeping in mind that not all samples may have been parsed
1136 * yet. If possible, it will delegate to binary search.
1138 * Returns the index of the sample.
1141 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1142 GstClockTime media_time)
1146 QtDemuxSample *sample;
1148 /* convert media_time to mov format */
1150 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1152 sample = str->samples;
1153 if (mov_time == sample->timestamp + sample->pts_offset)
1156 /* use faster search if requested time in already parsed range */
1157 sample = str->samples + str->stbl_index;
1158 if (str->stbl_index >= 0 &&
1159 mov_time <= (sample->timestamp + sample->pts_offset))
1160 return gst_qtdemux_find_index (qtdemux, str, media_time);
1162 while (index < str->n_samples - 1) {
1163 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1166 sample = str->samples + index + 1;
1167 if (mov_time < (sample->timestamp + sample->pts_offset))
1177 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1182 /* find the index of the keyframe needed to decode the sample at @index
1183 * of stream @str, or of a subsequent keyframe (depending on @next)
1185 * Returns the index of the keyframe.
1188 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1189 guint32 index, gboolean next)
1191 guint32 new_index = index;
1193 if (index >= str->n_samples) {
1194 new_index = str->n_samples;
1198 /* all keyframes, return index */
1199 if (str->all_keyframe) {
1204 /* else search until we have a keyframe */
1205 while (new_index < str->n_samples) {
1206 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1209 if (str->samples[new_index].keyframe)
1221 if (new_index == str->n_samples) {
1222 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1227 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1228 "gave %u", next ? "after" : "before", index, new_index);
1235 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1240 /* find the segment for @time_position for @stream
1242 * Returns the index of the segment containing @time_position.
1243 * Returns the last segment and sets the @eos variable to TRUE
1244 * if the time is beyond the end. @eos may be NULL
1247 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1248 GstClockTime time_position)
1253 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1254 GST_TIME_ARGS (time_position));
1257 for (i = 0; i < stream->n_segments; i++) {
1258 QtDemuxSegment *segment = &stream->segments[i];
1260 GST_LOG_OBJECT (stream->pad,
1261 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1262 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1264 /* For the last segment we include stop_time in the last segment */
1265 if (i < stream->n_segments - 1) {
1266 if (segment->time <= time_position && time_position < segment->stop_time) {
1267 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1272 /* Last segment always matches */
1280 /* move the stream @str to the sample position @index.
1282 * Updates @str->sample_index and marks discontinuity if needed.
1285 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1288 /* no change needed */
1289 if (index == str->sample_index)
1292 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1295 /* position changed, we have a discont */
1296 str->sample_index = index;
1297 str->offset_in_sample = 0;
1298 /* Each time we move in the stream we store the position where we are
1300 str->from_sample = index;
1301 str->discont = TRUE;
1305 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1306 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1309 gint64 min_byte_offset = -1;
1312 min_offset = desired_time;
1314 /* for each stream, find the index of the sample in the segment
1315 * and move back to the previous keyframe. */
1316 for (n = 0; n < qtdemux->n_streams; n++) {
1318 guint32 index, kindex;
1320 GstClockTime media_start;
1321 GstClockTime media_time;
1322 GstClockTime seg_time;
1323 QtDemuxSegment *seg;
1324 gboolean empty_segment = FALSE;
1326 str = qtdemux->streams[n];
1328 if (CUR_STREAM (str)->sparse && !use_sparse)
1331 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1332 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1334 /* get segment and time in the segment */
1335 seg = &str->segments[seg_idx];
1336 seg_time = (desired_time - seg->time) * seg->rate;
1338 while (QTSEGMENT_IS_EMPTY (seg)) {
1340 empty_segment = TRUE;
1341 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1344 if (seg_idx == str->n_segments)
1346 seg = &str->segments[seg_idx];
1349 if (seg_idx == str->n_segments) {
1350 /* FIXME track shouldn't have the last segment as empty, but if it
1351 * happens we better handle it */
1355 /* get the media time in the segment */
1356 media_start = seg->media_start + seg_time;
1358 /* get the index of the sample with media time */
1359 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1360 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1361 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1362 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1365 /* shift to next frame if we are looking for next keyframe */
1366 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1367 && index < str->stbl_index)
1370 if (!empty_segment) {
1371 /* find previous keyframe */
1372 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1374 /* we will settle for one before if none found after */
1375 if (next && kindex == -1)
1376 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1378 /* if the keyframe is at a different position, we need to update the
1379 * requested seek time */
1380 if (index != kindex) {
1383 /* get timestamp of keyframe */
1384 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1385 GST_DEBUG_OBJECT (qtdemux,
1386 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1387 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1388 str->samples[kindex].offset);
1390 /* keyframes in the segment get a chance to change the
1391 * desired_offset. keyframes out of the segment are
1393 if (media_time >= seg->media_start) {
1394 GstClockTime seg_time;
1396 /* this keyframe is inside the segment, convert back to
1398 seg_time = (media_time - seg->media_start) + seg->time;
1399 if ((!next && (seg_time < min_offset)) ||
1400 (next && (seg_time > min_offset)))
1401 min_offset = seg_time;
1406 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1407 min_byte_offset = str->samples[index].offset;
1411 *key_time = min_offset;
1413 *key_offset = min_byte_offset;
1417 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1418 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1422 g_return_val_if_fail (format != NULL, FALSE);
1423 g_return_val_if_fail (cur != NULL, FALSE);
1424 g_return_val_if_fail (stop != NULL, FALSE);
1426 if (*format == GST_FORMAT_TIME)
1430 if (cur_type != GST_SEEK_TYPE_NONE)
1431 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1432 if (res && stop_type != GST_SEEK_TYPE_NONE)
1433 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1436 *format = GST_FORMAT_TIME;
1441 /* perform seek in push based mode:
1442 find BYTE position to move to based on time and delegate to upstream
1445 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1450 GstSeekType cur_type, stop_type;
1451 gint64 cur, stop, key_cur;
1454 gint64 original_stop;
1457 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1459 gst_event_parse_seek (event, &rate, &format, &flags,
1460 &cur_type, &cur, &stop_type, &stop);
1461 seqnum = gst_event_get_seqnum (event);
1463 /* only forward streaming and seeking is possible */
1465 goto unsupported_seek;
1467 /* convert to TIME if needed and possible */
1468 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1472 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1473 * the original stop position to use when upstream pushes the new segment
1475 original_stop = stop;
1478 /* find reasonable corresponding BYTE position,
1479 * also try to mind about keyframes, since we can not go back a bit for them
1481 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1482 * mostly just work, but let's not yet boldly go there ... */
1483 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1488 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1489 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1492 GST_OBJECT_LOCK (qtdemux);
1493 qtdemux->seek_offset = byte_cur;
1494 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1495 qtdemux->push_seek_start = cur;
1497 qtdemux->push_seek_start = key_cur;
1500 if (stop_type == GST_SEEK_TYPE_NONE) {
1501 qtdemux->push_seek_stop = qtdemux->segment.stop;
1503 qtdemux->push_seek_stop = original_stop;
1505 GST_OBJECT_UNLOCK (qtdemux);
1507 /* BYTE seek event */
1508 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1510 gst_event_set_seqnum (event, seqnum);
1511 res = gst_pad_push_event (qtdemux->sinkpad, event);
1518 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1524 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1529 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1534 /* perform the seek.
1536 * We set all segment_indexes in the streams to unknown and
1537 * adjust the time_position to the desired position. this is enough
1538 * to trigger a segment switch in the streaming thread to start
1539 * streaming from the desired position.
1541 * Keyframe seeking is a little more complicated when dealing with
1542 * segments. Ideally we want to move to the previous keyframe in
1543 * the segment but there might not be a keyframe in the segment. In
1544 * fact, none of the segments could contain a keyframe. We take a
1545 * practical approach: seek to the previous keyframe in the segment,
1546 * if there is none, seek to the beginning of the segment.
1548 * Called with STREAM_LOCK
1551 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1552 guint32 seqnum, GstSeekFlags flags)
1554 gint64 desired_offset;
1557 desired_offset = segment->position;
1559 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1560 GST_TIME_ARGS (desired_offset));
1562 /* may not have enough fragmented info to do this adjustment,
1563 * and we can't scan (and probably should not) at this time with
1564 * possibly flushing upstream */
1565 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1567 gboolean next, before, after;
1569 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1570 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1571 next = after && !before;
1572 if (segment->rate < 0)
1575 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1577 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1578 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1579 desired_offset = min_offset;
1582 /* and set all streams to the final position */
1583 gst_flow_combiner_reset (qtdemux->flowcombiner);
1584 qtdemux->segment_seqnum = seqnum;
1585 for (n = 0; n < qtdemux->n_streams; n++) {
1586 QtDemuxStream *stream = qtdemux->streams[n];
1588 stream->time_position = desired_offset;
1589 stream->accumulated_base = 0;
1590 stream->sample_index = -1;
1591 stream->offset_in_sample = 0;
1592 stream->segment_index = -1;
1593 stream->sent_eos = FALSE;
1595 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1596 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1598 segment->position = desired_offset;
1599 segment->time = desired_offset;
1600 if (segment->rate >= 0) {
1601 segment->start = desired_offset;
1603 /* we stop at the end */
1604 if (segment->stop == -1)
1605 segment->stop = segment->duration;
1607 segment->stop = desired_offset;
1610 if (qtdemux->fragmented)
1611 qtdemux->fragmented_seek_pending = TRUE;
1616 /* do a seek in pull based mode */
1618 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1623 GstSeekType cur_type, stop_type;
1627 GstSegment seeksegment;
1629 GstEvent *flush_event;
1633 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1635 gst_event_parse_seek (event, &rate, &format, &flags,
1636 &cur_type, &cur, &stop_type, &stop);
1637 seqnum = gst_event_get_seqnum (event);
1639 /* we have to have a format as the segment format. Try to convert
1641 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1645 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1647 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1651 flush = flags & GST_SEEK_FLAG_FLUSH;
1653 /* stop streaming, either by flushing or by pausing the task */
1655 flush_event = gst_event_new_flush_start ();
1657 gst_event_set_seqnum (flush_event, seqnum);
1658 /* unlock upstream pull_range */
1659 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1660 /* make sure out loop function exits */
1661 gst_qtdemux_push_event (qtdemux, flush_event);
1663 /* non flushing seek, pause the task */
1664 gst_pad_pause_task (qtdemux->sinkpad);
1667 /* wait for streaming to finish */
1668 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1670 /* copy segment, we need this because we still need the old
1671 * segment when we close the current segment. */
1672 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1675 /* configure the segment with the seek variables */
1676 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1677 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1678 cur_type, cur, stop_type, stop, &update)) {
1680 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1682 /* now do the seek */
1683 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1686 /* now do the seek */
1687 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1690 /* prepare for streaming again */
1692 flush_event = gst_event_new_flush_stop (TRUE);
1694 gst_event_set_seqnum (flush_event, seqnum);
1696 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1697 gst_qtdemux_push_event (qtdemux, flush_event);
1700 /* commit the new segment */
1701 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1703 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1704 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1705 qtdemux->segment.format, qtdemux->segment.position);
1707 gst_message_set_seqnum (msg, seqnum);
1708 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1711 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1712 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1713 qtdemux->sinkpad, NULL);
1715 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1722 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1728 qtdemux_ensure_index (GstQTDemux * qtdemux)
1732 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1734 /* Build complete index */
1735 for (i = 0; i < qtdemux->n_streams; i++) {
1736 QtDemuxStream *stream = qtdemux->streams[i];
1738 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1746 GST_LOG_OBJECT (qtdemux,
1747 "Building complete index of stream %u for seeking failed!", i);
1753 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1756 gboolean res = TRUE;
1757 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1759 switch (GST_EVENT_TYPE (event)) {
1760 case GST_EVENT_SEEK:
1762 #ifndef GST_DISABLE_GST_DEBUG
1763 GstClockTime ts = gst_util_get_timestamp ();
1765 guint32 seqnum = gst_event_get_seqnum (event);
1767 if (seqnum == qtdemux->segment_seqnum) {
1768 GST_LOG_OBJECT (pad,
1769 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1770 gst_event_unref (event);
1774 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1775 /* seek should be handled by upstream, we might need to re-download fragments */
1776 GST_DEBUG_OBJECT (qtdemux,
1777 "let upstream handle seek for fragmented playback");
1781 /* Build complete index for seeking;
1782 * if not a fragmented file at least */
1783 if (!qtdemux->fragmented)
1784 if (!qtdemux_ensure_index (qtdemux))
1786 #ifndef GST_DISABLE_GST_DEBUG
1787 ts = gst_util_get_timestamp () - ts;
1788 GST_INFO_OBJECT (qtdemux,
1789 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1792 if (qtdemux->pullbased) {
1793 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1794 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1795 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1797 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1798 && !qtdemux->fragmented) {
1799 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1801 GST_DEBUG_OBJECT (qtdemux,
1802 "ignoring seek in push mode in current state");
1805 gst_event_unref (event);
1809 res = gst_pad_event_default (pad, parent, event);
1819 GST_ERROR_OBJECT (qtdemux, "Index failed");
1820 gst_event_unref (event);
1826 /* stream/index return sample that is min/max w.r.t. byte position,
1827 * time is min/max w.r.t. time of samples,
1828 * the latter need not be time of the former sample */
1830 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1831 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1834 gint64 time, min_time;
1835 QtDemuxStream *stream;
1841 for (n = 0; n < qtdemux->n_streams; ++n) {
1844 gboolean set_sample;
1846 str = qtdemux->streams[n];
1853 i = str->n_samples - 1;
1857 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1858 if (str->samples[i].size == 0)
1861 if (fw && (str->samples[i].offset < byte_pos))
1864 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1867 /* move stream to first available sample */
1869 gst_qtdemux_move_stream (qtdemux, str, i);
1873 /* avoid index from sparse streams since they might be far away */
1874 if (!CUR_STREAM (str)->sparse) {
1875 /* determine min/max time */
1876 time = QTSAMPLE_PTS (str, &str->samples[i]);
1877 if (min_time == -1 || (!fw && time > min_time) ||
1878 (fw && time < min_time)) {
1882 /* determine stream with leading sample, to get its position */
1884 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1885 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1893 /* no sample for this stream, mark eos */
1895 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1906 static QtDemuxStream *
1907 _create_stream (void)
1909 QtDemuxStream *stream;
1911 stream = g_new0 (QtDemuxStream, 1);
1912 /* new streams always need a discont */
1913 stream->discont = TRUE;
1914 /* we enable clipping for raw audio/video streams */
1915 stream->need_clip = FALSE;
1916 stream->need_process = FALSE;
1917 stream->segment_index = -1;
1918 stream->time_position = 0;
1919 stream->sample_index = -1;
1920 stream->offset_in_sample = 0;
1921 stream->new_stream = TRUE;
1922 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1923 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1924 stream->protected = FALSE;
1925 stream->protection_scheme_type = 0;
1926 stream->protection_scheme_version = 0;
1927 stream->protection_scheme_info = NULL;
1928 stream->n_samples_moof = 0;
1929 stream->duration_moof = 0;
1930 stream->duration_last_moof = 0;
1931 stream->alignment = 1;
1932 stream->stream_tags = gst_tag_list_new_empty ();
1933 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1934 g_queue_init (&stream->protection_scheme_event_queue);
1939 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1941 GstStructure *structure;
1942 const gchar *variant;
1943 const GstCaps *mediacaps = NULL;
1945 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1947 structure = gst_caps_get_structure (caps, 0);
1948 variant = gst_structure_get_string (structure, "variant");
1950 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1951 QtDemuxStream *stream;
1952 const GValue *value;
1954 demux->fragmented = TRUE;
1955 demux->mss_mode = TRUE;
1957 if (demux->n_streams > 1) {
1958 /* can't do this, we can only renegotiate for another mss format */
1962 value = gst_structure_get_value (structure, "media-caps");
1965 const GValue *timescale_v;
1967 /* TODO update when stream changes during playback */
1969 if (demux->n_streams == 0) {
1970 stream = _create_stream ();
1971 demux->streams[demux->n_streams] = stream;
1972 demux->n_streams = 1;
1973 /* mss has no stsd/stsd entry, use id 0 as default */
1974 stream->stsd_entries_length = 1;
1975 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1976 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1978 stream = demux->streams[0];
1981 timescale_v = gst_structure_get_value (structure, "timescale");
1983 stream->timescale = g_value_get_uint64 (timescale_v);
1985 /* default mss timescale */
1986 stream->timescale = 10000000;
1988 demux->timescale = stream->timescale;
1990 mediacaps = gst_value_get_caps (value);
1991 if (!CUR_STREAM (stream)->caps
1992 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1993 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1995 stream->new_caps = TRUE;
1997 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1998 structure = gst_caps_get_structure (mediacaps, 0);
1999 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2000 stream->subtype = FOURCC_vide;
2002 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2003 gst_structure_get_int (structure, "height",
2004 &CUR_STREAM (stream)->height);
2005 gst_structure_get_fraction (structure, "framerate",
2006 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2007 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2009 stream->subtype = FOURCC_soun;
2010 gst_structure_get_int (structure, "channels",
2011 &CUR_STREAM (stream)->n_channels);
2012 gst_structure_get_int (structure, "rate", &rate);
2013 CUR_STREAM (stream)->rate = rate;
2016 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2018 demux->mss_mode = FALSE;
2025 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2029 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2030 gst_pad_stop_task (qtdemux->sinkpad);
2032 if (hard || qtdemux->upstream_format_is_time) {
2033 qtdemux->state = QTDEMUX_STATE_INITIAL;
2034 qtdemux->neededbytes = 16;
2035 qtdemux->todrop = 0;
2036 qtdemux->pullbased = FALSE;
2037 qtdemux->posted_redirect = FALSE;
2038 qtdemux->first_mdat = -1;
2039 qtdemux->header_size = 0;
2040 qtdemux->mdatoffset = -1;
2041 qtdemux->restoredata_offset = -1;
2042 if (qtdemux->mdatbuffer)
2043 gst_buffer_unref (qtdemux->mdatbuffer);
2044 if (qtdemux->restoredata_buffer)
2045 gst_buffer_unref (qtdemux->restoredata_buffer);
2046 qtdemux->mdatbuffer = NULL;
2047 qtdemux->restoredata_buffer = NULL;
2048 qtdemux->mdatleft = 0;
2049 qtdemux->mdatsize = 0;
2050 if (qtdemux->comp_brands)
2051 gst_buffer_unref (qtdemux->comp_brands);
2052 qtdemux->comp_brands = NULL;
2053 qtdemux->last_moov_offset = -1;
2054 if (qtdemux->moov_node_compressed) {
2055 g_node_destroy (qtdemux->moov_node_compressed);
2056 if (qtdemux->moov_node)
2057 g_free (qtdemux->moov_node->data);
2059 qtdemux->moov_node_compressed = NULL;
2060 if (qtdemux->moov_node)
2061 g_node_destroy (qtdemux->moov_node);
2062 qtdemux->moov_node = NULL;
2063 if (qtdemux->tag_list)
2064 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2065 qtdemux->tag_list = gst_tag_list_new_empty ();
2066 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2068 if (qtdemux->element_index)
2069 gst_object_unref (qtdemux->element_index);
2070 qtdemux->element_index = NULL;
2072 qtdemux->major_brand = 0;
2073 if (qtdemux->pending_newsegment)
2074 gst_event_unref (qtdemux->pending_newsegment);
2075 qtdemux->pending_newsegment = NULL;
2076 qtdemux->upstream_format_is_time = FALSE;
2077 qtdemux->upstream_seekable = FALSE;
2078 qtdemux->upstream_size = 0;
2080 qtdemux->fragment_start = -1;
2081 qtdemux->fragment_start_offset = -1;
2082 qtdemux->duration = 0;
2083 qtdemux->moof_offset = 0;
2084 qtdemux->chapters_track_id = 0;
2085 qtdemux->have_group_id = FALSE;
2086 qtdemux->group_id = G_MAXUINT;
2088 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2090 g_queue_clear (&qtdemux->protection_event_queue);
2092 qtdemux->offset = 0;
2093 gst_adapter_clear (qtdemux->adapter);
2094 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2095 qtdemux->segment_seqnum = 0;
2098 for (n = 0; n < qtdemux->n_streams; n++) {
2099 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2100 qtdemux->streams[n] = NULL;
2102 qtdemux->n_streams = 0;
2103 qtdemux->n_video_streams = 0;
2104 qtdemux->n_audio_streams = 0;
2105 qtdemux->n_sub_streams = 0;
2106 qtdemux->exposed = FALSE;
2107 qtdemux->fragmented = FALSE;
2108 qtdemux->mss_mode = FALSE;
2109 gst_caps_replace (&qtdemux->media_caps, NULL);
2110 qtdemux->timescale = 0;
2111 qtdemux->got_moov = FALSE;
2112 if (qtdemux->protection_system_ids) {
2113 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2114 qtdemux->protection_system_ids = NULL;
2116 } else if (qtdemux->mss_mode) {
2117 gst_flow_combiner_reset (qtdemux->flowcombiner);
2118 for (n = 0; n < qtdemux->n_streams; n++)
2119 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2121 gst_flow_combiner_reset (qtdemux->flowcombiner);
2122 for (n = 0; n < qtdemux->n_streams; n++) {
2123 qtdemux->streams[n]->sent_eos = FALSE;
2124 qtdemux->streams[n]->time_position = 0;
2125 qtdemux->streams[n]->accumulated_base = 0;
2127 if (!qtdemux->pending_newsegment) {
2128 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2129 if (qtdemux->segment_seqnum)
2130 gst_event_set_seqnum (qtdemux->pending_newsegment,
2131 qtdemux->segment_seqnum);
2137 /* Maps the @segment to the qt edts internal segments and pushes
2138 * the correspnding segment event.
2140 * If it ends up being at a empty segment, a gap will be pushed and the next
2141 * edts segment will be activated in sequence.
2143 * To be used in push-mode only */
2145 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2149 for (n = 0; n < qtdemux->n_streams; n++) {
2150 QtDemuxStream *stream = qtdemux->streams[n];
2152 stream->time_position = segment->start;
2154 /* in push mode we should be guaranteed that we will have empty segments
2155 * at the beginning and then one segment after, other scenarios are not
2156 * supported and are discarded when parsing the edts */
2157 for (i = 0; i < stream->n_segments; i++) {
2158 if (stream->segments[i].stop_time > segment->start) {
2159 gst_qtdemux_activate_segment (qtdemux, stream, i,
2160 stream->time_position);
2161 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2162 /* push the empty segment and move to the next one */
2163 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2164 stream->time_position);
2168 g_assert (i == stream->n_segments - 1);
2175 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2178 GstQTDemux *demux = GST_QTDEMUX (parent);
2179 gboolean res = TRUE;
2181 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2183 switch (GST_EVENT_TYPE (event)) {
2184 case GST_EVENT_SEGMENT:
2187 QtDemuxStream *stream;
2191 /* some debug output */
2192 gst_event_copy_segment (event, &segment);
2193 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2196 /* erase any previously set segment */
2197 gst_event_replace (&demux->pending_newsegment, NULL);
2199 if (segment.format == GST_FORMAT_TIME) {
2200 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2201 gst_event_replace (&demux->pending_newsegment, event);
2202 demux->upstream_format_is_time = TRUE;
2204 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2205 "not in time format");
2207 /* chain will send initial newsegment after pads have been added */
2208 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2209 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2214 /* check if this matches a time seek we received previously
2215 * FIXME for backwards compatibility reasons we use the
2216 * seek_offset here to compare. In the future we might want to
2217 * change this to use the seqnum as it uniquely should identify
2218 * the segment that corresponds to the seek. */
2219 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2220 ", received segment offset %" G_GINT64_FORMAT,
2221 demux->seek_offset, segment.start);
2222 if (segment.format == GST_FORMAT_BYTES
2223 && demux->seek_offset == segment.start) {
2224 GST_OBJECT_LOCK (demux);
2225 offset = segment.start;
2227 segment.format = GST_FORMAT_TIME;
2228 segment.start = demux->push_seek_start;
2229 segment.stop = demux->push_seek_stop;
2230 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2231 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2232 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2233 GST_OBJECT_UNLOCK (demux);
2236 /* we only expect a BYTE segment, e.g. following a seek */
2237 if (segment.format == GST_FORMAT_BYTES) {
2238 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2239 offset = segment.start;
2241 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2242 NULL, (gint64 *) & segment.start);
2243 if ((gint64) segment.start < 0)
2246 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2247 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2248 NULL, (gint64 *) & segment.stop);
2249 /* keyframe seeking should already arrange for start >= stop,
2250 * but make sure in other rare cases */
2251 segment.stop = MAX (segment.stop, segment.start);
2253 } else if (segment.format == GST_FORMAT_TIME) {
2254 /* push all data on the adapter before starting this
2256 gst_qtdemux_process_adapter (demux, TRUE);
2258 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2262 /* We shouldn't modify upstream driven TIME FORMAT segment */
2263 if (!demux->upstream_format_is_time) {
2264 /* accept upstream's notion of segment and distribute along */
2265 segment.format = GST_FORMAT_TIME;
2266 segment.position = segment.time = segment.start;
2267 segment.duration = demux->segment.duration;
2268 segment.base = gst_segment_to_running_time (&demux->segment,
2269 GST_FORMAT_TIME, demux->segment.position);
2272 gst_segment_copy_into (&segment, &demux->segment);
2273 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2275 /* map segment to internal qt segments and push on each stream */
2276 if (demux->n_streams) {
2277 if (demux->fragmented) {
2278 GstEvent *segment_event = gst_event_new_segment (&segment);
2280 gst_event_replace (&demux->pending_newsegment, NULL);
2281 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2282 gst_qtdemux_push_event (demux, segment_event);
2284 gst_event_replace (&demux->pending_newsegment, NULL);
2285 gst_qtdemux_map_and_push_segments (demux, &segment);
2289 /* clear leftover in current segment, if any */
2290 gst_adapter_clear (demux->adapter);
2292 /* set up streaming thread */
2293 demux->offset = offset;
2294 if (demux->upstream_format_is_time) {
2295 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2296 "set values to restart reading from a new atom");
2297 demux->neededbytes = 16;
2300 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2303 demux->todrop = stream->samples[idx].offset - offset;
2304 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2306 /* set up for EOS */
2307 demux->neededbytes = -1;
2312 gst_event_unref (event);
2316 case GST_EVENT_FLUSH_START:
2318 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2319 gst_event_unref (event);
2324 case GST_EVENT_FLUSH_STOP:
2328 dur = demux->segment.duration;
2329 gst_qtdemux_reset (demux, FALSE);
2330 demux->segment.duration = dur;
2332 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2333 gst_event_unref (event);
2339 /* If we are in push mode, and get an EOS before we've seen any streams,
2340 * then error out - we have nowhere to send the EOS */
2341 if (!demux->pullbased) {
2343 gboolean has_valid_stream = FALSE;
2344 for (i = 0; i < demux->n_streams; i++) {
2345 if (demux->streams[i]->pad != NULL) {
2346 has_valid_stream = TRUE;
2350 if (!has_valid_stream)
2351 gst_qtdemux_post_no_playable_stream_error (demux);
2353 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2354 (guint) gst_adapter_available (demux->adapter));
2355 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2361 case GST_EVENT_CAPS:{
2362 GstCaps *caps = NULL;
2364 gst_event_parse_caps (event, &caps);
2365 gst_qtdemux_setcaps (demux, caps);
2367 gst_event_unref (event);
2370 case GST_EVENT_PROTECTION:
2372 const gchar *system_id = NULL;
2374 gst_event_parse_protection (event, &system_id, NULL, NULL);
2375 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2377 gst_qtdemux_append_protection_system_id (demux, system_id);
2378 /* save the event for later, for source pads that have not been created */
2379 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2380 /* send it to all pads that already exist */
2381 gst_qtdemux_push_event (demux, event);
2389 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2397 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2399 GstQTDemux *demux = GST_QTDEMUX (element);
2401 GST_OBJECT_LOCK (demux);
2402 if (demux->element_index)
2403 gst_object_unref (demux->element_index);
2405 demux->element_index = gst_object_ref (index);
2407 demux->element_index = NULL;
2409 GST_OBJECT_UNLOCK (demux);
2410 /* object lock might be taken again */
2412 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2413 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2414 demux->element_index, demux->index_id);
2418 gst_qtdemux_get_index (GstElement * element)
2420 GstIndex *result = NULL;
2421 GstQTDemux *demux = GST_QTDEMUX (element);
2423 GST_OBJECT_LOCK (demux);
2424 if (demux->element_index)
2425 result = gst_object_ref (demux->element_index);
2426 GST_OBJECT_UNLOCK (demux);
2428 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2435 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2437 g_free ((gpointer) stream->stco.data);
2438 stream->stco.data = NULL;
2439 g_free ((gpointer) stream->stsz.data);
2440 stream->stsz.data = NULL;
2441 g_free ((gpointer) stream->stsc.data);
2442 stream->stsc.data = NULL;
2443 g_free ((gpointer) stream->stts.data);
2444 stream->stts.data = NULL;
2445 g_free ((gpointer) stream->stss.data);
2446 stream->stss.data = NULL;
2447 g_free ((gpointer) stream->stps.data);
2448 stream->stps.data = NULL;
2449 g_free ((gpointer) stream->ctts.data);
2450 stream->ctts.data = NULL;
2454 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2455 QtDemuxStream * stream)
2457 g_free (stream->segments);
2458 stream->segments = NULL;
2459 stream->segment_index = -1;
2460 stream->accumulated_base = 0;
2464 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2465 QtDemuxStream * stream)
2467 g_free (stream->samples);
2468 stream->samples = NULL;
2469 gst_qtdemux_stbl_free (stream);
2472 g_free (stream->ra_entries);
2473 stream->ra_entries = NULL;
2474 stream->n_ra_entries = 0;
2476 stream->sample_index = -1;
2477 stream->stbl_index = -1;
2478 stream->n_samples = 0;
2479 stream->time_position = 0;
2481 stream->n_samples_moof = 0;
2482 stream->duration_moof = 0;
2483 stream->duration_last_moof = 0;
2487 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2490 if (stream->allocator)
2491 gst_object_unref (stream->allocator);
2492 while (stream->buffers) {
2493 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2494 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2496 for (i = 0; i < stream->stsd_entries_length; i++) {
2497 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2498 if (entry->rgb8_palette) {
2499 gst_memory_unref (entry->rgb8_palette);
2500 entry->rgb8_palette = NULL;
2502 entry->sparse = FALSE;
2505 gst_tag_list_unref (stream->stream_tags);
2506 stream->stream_tags = gst_tag_list_new_empty ();
2507 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2508 g_free (stream->redirect_uri);
2509 stream->redirect_uri = NULL;
2510 stream->sent_eos = FALSE;
2511 stream->protected = FALSE;
2512 if (stream->protection_scheme_info) {
2513 if (stream->protection_scheme_type == FOURCC_cenc) {
2514 QtDemuxCencSampleSetInfo *info =
2515 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2516 if (info->default_properties)
2517 gst_structure_free (info->default_properties);
2518 if (info->crypto_info)
2519 g_ptr_array_free (info->crypto_info, TRUE);
2521 g_free (stream->protection_scheme_info);
2522 stream->protection_scheme_info = NULL;
2524 stream->protection_scheme_type = 0;
2525 stream->protection_scheme_version = 0;
2526 g_queue_foreach (&stream->protection_scheme_event_queue,
2527 (GFunc) gst_event_unref, NULL);
2528 g_queue_clear (&stream->protection_scheme_event_queue);
2529 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2530 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2534 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2537 gst_qtdemux_stream_clear (qtdemux, stream);
2538 for (i = 0; i < stream->stsd_entries_length; i++) {
2539 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2541 gst_caps_unref (entry->caps);
2545 gst_tag_list_unref (stream->stream_tags);
2547 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2548 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2550 g_free (stream->stsd_entries);
2555 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2557 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2559 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2560 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2561 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2562 qtdemux->n_streams--;
2565 static GstStateChangeReturn
2566 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2568 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2569 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2571 switch (transition) {
2572 case GST_STATE_CHANGE_PAUSED_TO_READY:
2578 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2580 switch (transition) {
2581 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2582 gst_qtdemux_reset (qtdemux, TRUE);
2593 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2595 /* counts as header data */
2596 qtdemux->header_size += length;
2598 /* only consider at least a sufficiently complete ftyp atom */
2602 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2603 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2604 GST_FOURCC_ARGS (qtdemux->major_brand));
2605 if (qtdemux->comp_brands)
2606 gst_buffer_unref (qtdemux->comp_brands);
2607 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2608 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2613 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2614 GstTagList * xmptaglist)
2616 /* Strip out bogus fields */
2618 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2619 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2620 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2622 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2625 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2627 /* prioritize native tags using _KEEP mode */
2628 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2629 gst_tag_list_unref (xmptaglist);
2634 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2642 QtDemuxStream *stream;
2643 GstStructure *structure;
2644 QtDemuxCencSampleSetInfo *ss_info = NULL;
2645 const gchar *system_id;
2646 gboolean uses_sub_sample_encryption = FALSE;
2648 if (qtdemux->n_streams == 0)
2651 stream = qtdemux->streams[0];
2653 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2654 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2655 GST_WARNING_OBJECT (qtdemux,
2656 "Attempting PIFF box parsing on an unencrypted stream.");
2660 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2661 G_TYPE_STRING, &system_id, NULL);
2662 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2664 stream->protected = TRUE;
2665 stream->protection_scheme_type = FOURCC_cenc;
2667 if (!stream->protection_scheme_info)
2668 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2670 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2672 if (ss_info->default_properties)
2673 gst_structure_free (ss_info->default_properties);
2675 ss_info->default_properties =
2676 gst_structure_new ("application/x-cenc",
2677 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2679 if (ss_info->crypto_info) {
2680 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2681 g_ptr_array_free (ss_info->crypto_info, TRUE);
2682 ss_info->crypto_info = NULL;
2686 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2688 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2689 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2693 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2694 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2698 if ((flags & 0x000001)) {
2699 guint32 algorithm_id = 0;
2702 gboolean is_encrypted = TRUE;
2704 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2705 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2710 if (algorithm_id == 0) {
2711 is_encrypted = FALSE;
2712 } else if (algorithm_id == 1) {
2713 /* FIXME: maybe store this in properties? */
2714 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2715 } else if (algorithm_id == 2) {
2716 /* FIXME: maybe store this in properties? */
2717 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2720 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2723 if (!gst_byte_reader_get_data (&br, 16, &kid))
2726 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2727 gst_buffer_fill (kid_buf, 0, kid, 16);
2728 if (ss_info->default_properties)
2729 gst_structure_free (ss_info->default_properties);
2730 ss_info->default_properties =
2731 gst_structure_new ("application/x-cenc",
2732 "iv_size", G_TYPE_UINT, iv_size,
2733 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2734 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2735 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2736 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2737 gst_buffer_unref (kid_buf);
2738 } else if ((flags & 0x000002)) {
2739 uses_sub_sample_encryption = TRUE;
2742 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2743 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2747 ss_info->crypto_info =
2748 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2749 (GDestroyNotify) qtdemux_gst_structure_free);
2751 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2752 GstStructure *properties;
2756 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2757 if (properties == NULL) {
2758 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2762 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2763 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2764 gst_structure_free (properties);
2767 buf = gst_buffer_new_wrapped (data, iv_size);
2768 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2769 gst_buffer_unref (buf);
2771 if (uses_sub_sample_encryption) {
2772 guint16 n_subsamples;
2774 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2775 || n_subsamples == 0) {
2776 GST_ERROR_OBJECT (qtdemux,
2777 "failed to get subsample count for sample %u", i);
2778 gst_structure_free (properties);
2781 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2782 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2783 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2785 gst_structure_free (properties);
2788 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2789 gst_structure_set (properties,
2790 "subsample_count", G_TYPE_UINT, n_subsamples,
2791 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2792 gst_buffer_unref (buf);
2794 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2797 g_ptr_array_add (ss_info->crypto_info, properties);
2802 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2804 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2805 0x97, 0xA9, 0x42, 0xE8,
2806 0x9C, 0x71, 0x99, 0x94,
2807 0x91, 0xE3, 0xAF, 0xAC
2809 static const guint8 playready_uuid[] = {
2810 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2811 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2814 static const guint8 piff_sample_encryption_uuid[] = {
2815 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2816 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2821 /* counts as header data */
2822 qtdemux->header_size += length;
2824 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2826 if (length <= offset + 16) {
2827 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2831 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2833 GstTagList *taglist;
2835 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2836 length - offset - 16, NULL);
2837 taglist = gst_tag_list_from_xmp_buffer (buf);
2838 gst_buffer_unref (buf);
2840 /* make sure we have a usable taglist */
2841 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2843 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2845 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2847 const gunichar2 *s_utf16;
2850 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2851 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2852 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2853 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2857 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2858 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2860 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2861 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2863 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2864 GST_READ_UINT32_LE (buffer + offset),
2865 GST_READ_UINT32_LE (buffer + offset + 4),
2866 GST_READ_UINT32_LE (buffer + offset + 8),
2867 GST_READ_UINT32_LE (buffer + offset + 12));
2872 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2874 GstSidxParser sidx_parser;
2875 GstIsoffParserResult res;
2878 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2881 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2883 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2884 if (res == GST_ISOFF_QT_PARSER_DONE) {
2885 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2887 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2890 /* caller verifies at least 8 bytes in buf */
2892 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2893 guint64 * plength, guint32 * pfourcc)
2898 length = QT_UINT32 (data);
2899 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2900 fourcc = QT_FOURCC (data + 4);
2901 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2904 length = G_MAXUINT64;
2905 } else if (length == 1 && size >= 16) {
2906 /* this means we have an extended size, which is the 64 bit value of
2907 * the next 8 bytes */
2908 length = QT_UINT64 (data + 8);
2909 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2919 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2921 guint32 version = 0;
2922 GstClockTime duration = 0;
2924 if (!gst_byte_reader_get_uint32_be (br, &version))
2929 if (!gst_byte_reader_get_uint64_be (br, &duration))
2934 if (!gst_byte_reader_get_uint32_be (br, &dur))
2939 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2940 qtdemux->duration = duration;
2946 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2952 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2953 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2955 if (!stream->parsed_trex && qtdemux->moov_node) {
2957 GstByteReader trex_data;
2959 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2961 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2964 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
2966 /* skip version/flags */
2967 if (!gst_byte_reader_skip (&trex_data, 4))
2969 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2971 if (id != stream->track_id)
2973 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
2975 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2977 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2979 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2982 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2983 "duration %d, size %d, flags 0x%x", stream->track_id,
2986 stream->parsed_trex = TRUE;
2987 stream->def_sample_description_index = sdi;
2988 stream->def_sample_duration = dur;
2989 stream->def_sample_size = size;
2990 stream->def_sample_flags = flags;
2993 /* iterate all siblings */
2994 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3000 *ds_duration = stream->def_sample_duration;
3001 *ds_size = stream->def_sample_size;
3002 *ds_flags = stream->def_sample_flags;
3004 /* even then, above values are better than random ... */
3005 if (G_UNLIKELY (!stream->parsed_trex)) {
3006 GST_WARNING_OBJECT (qtdemux,
3007 "failed to find fragment defaults for stream %d", stream->track_id);
3014 /* This method should be called whenever a more accurate duration might
3015 * have been found. It will update all relevant variables if/where needed
3018 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3022 GstClockTime prevdur;
3024 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3026 if (movdur > qtdemux->duration) {
3027 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3028 GST_DEBUG_OBJECT (qtdemux,
3029 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3030 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3031 qtdemux->duration = movdur;
3032 GST_DEBUG_OBJECT (qtdemux,
3033 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3034 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3035 GST_TIME_ARGS (qtdemux->segment.stop));
3036 if (qtdemux->segment.duration == prevdur) {
3037 /* If the current segment has duration/stop identical to previous duration
3038 * update them also (because they were set at that point in time with
3039 * the wrong duration */
3040 /* We convert the value *from* the timescale version to avoid rounding errors */
3041 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3042 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3043 qtdemux->segment.duration = fixeddur;
3044 qtdemux->segment.stop = fixeddur;
3047 for (i = 0; i < qtdemux->n_streams; i++) {
3048 QtDemuxStream *stream = qtdemux->streams[i];
3050 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3051 if (movdur > stream->duration) {
3052 GST_DEBUG_OBJECT (qtdemux,
3053 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3054 GST_TIME_ARGS (duration));
3055 stream->duration = movdur;
3056 if (stream->dummy_segment) {
3057 /* Update all dummy values to new duration */
3058 stream->segments[0].stop_time = duration;
3059 stream->segments[0].duration = duration;
3060 stream->segments[0].media_stop = duration;
3062 /* let downstream know we possibly have a new stop time */
3063 if (stream->segment_index != -1) {
3066 if (qtdemux->segment.rate >= 0) {
3067 pos = stream->segment.start;
3069 pos = stream->segment.stop;
3072 gst_qtdemux_stream_update_segment (qtdemux, stream,
3073 stream->segment_index, pos, NULL, NULL);
3082 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3083 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3084 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3085 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3088 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3090 gint32 data_offset = 0;
3091 guint32 flags = 0, first_flags = 0, samples_count = 0;
3094 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3095 QtDemuxSample *sample;
3096 gboolean ismv = FALSE;
3097 gint64 initial_offset;
3099 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3100 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3101 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3102 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3104 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3105 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3109 /* presence of stss or not can't really tell us much,
3110 * and flags and so on tend to be marginally reliable in these files */
3111 if (stream->subtype == FOURCC_soun) {
3112 GST_DEBUG_OBJECT (qtdemux,
3113 "sound track in fragmented file; marking all keyframes");
3114 stream->all_keyframe = TRUE;
3117 if (!gst_byte_reader_skip (trun, 1) ||
3118 !gst_byte_reader_get_uint24_be (trun, &flags))
3121 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3124 if (flags & TR_DATA_OFFSET) {
3125 /* note this is really signed */
3126 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3128 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3129 /* default base offset = first byte of moof */
3130 if (*base_offset == -1) {
3131 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3132 *base_offset = moof_offset;
3134 *running_offset = *base_offset + data_offset;
3136 /* if no offset at all, that would mean data starts at moof start,
3137 * which is a bit wrong and is ismv crappy way, so compensate
3138 * assuming data is in mdat following moof */
3139 if (*base_offset == -1) {
3140 *base_offset = moof_offset + moof_length + 8;
3141 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3144 if (*running_offset == -1)
3145 *running_offset = *base_offset;
3148 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3150 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3151 data_offset, flags, samples_count);
3153 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3154 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3155 GST_DEBUG_OBJECT (qtdemux,
3156 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3157 flags ^= TR_FIRST_SAMPLE_FLAGS;
3159 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3161 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3165 /* FIXME ? spec says other bits should also be checked to determine
3166 * entry size (and prefix size for that matter) */
3168 dur_offset = size_offset = 0;
3169 if (flags & TR_SAMPLE_DURATION) {
3170 GST_LOG_OBJECT (qtdemux, "entry duration present");
3171 dur_offset = entry_size;
3174 if (flags & TR_SAMPLE_SIZE) {
3175 GST_LOG_OBJECT (qtdemux, "entry size present");
3176 size_offset = entry_size;
3179 if (flags & TR_SAMPLE_FLAGS) {
3180 GST_LOG_OBJECT (qtdemux, "entry flags present");
3181 flags_offset = entry_size;
3184 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3185 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3186 ct_offset = entry_size;
3190 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3192 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3194 if (stream->n_samples + samples_count >=
3195 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3198 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3199 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3200 (stream->n_samples + samples_count) *
3201 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3203 /* create a new array of samples if it's the first sample parsed */
3204 if (stream->n_samples == 0) {
3205 g_assert (stream->samples == NULL);
3206 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3207 /* or try to reallocate it with space enough to insert the new samples */
3209 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3210 stream->n_samples + samples_count);
3211 if (stream->samples == NULL)
3214 if (qtdemux->fragment_start != -1) {
3215 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3216 qtdemux->fragment_start = -1;
3218 if (stream->n_samples == 0) {
3219 if (decode_ts > 0) {
3220 timestamp = decode_ts;
3221 } else if (stream->pending_seek != NULL) {
3222 /* if we don't have a timestamp from a tfdt box, we'll use the one
3223 * from the mfra seek table */
3224 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3225 GST_TIME_ARGS (stream->pending_seek->ts));
3227 /* FIXME: this is not fully correct, the timestamp refers to the random
3228 * access sample refered to in the tfra entry, which may not necessarily
3229 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3230 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3235 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3236 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3237 GST_TIME_ARGS (gst_ts));
3239 /* subsequent fragments extend stream */
3241 stream->samples[stream->n_samples - 1].timestamp +
3242 stream->samples[stream->n_samples - 1].duration;
3244 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3245 * difference (1 sec.) between decode_ts and timestamp, prefer the
3247 if (has_tfdt && !qtdemux->upstream_format_is_time
3248 && ABSDIFF (decode_ts, timestamp) >
3249 MAX (stream->duration_last_moof / 2,
3250 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3251 GST_INFO_OBJECT (qtdemux,
3252 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3253 ") are significantly different (more than %" GST_TIME_FORMAT
3254 "), using decode_ts",
3255 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3256 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3257 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3258 MAX (stream->duration_last_moof / 2,
3259 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3260 timestamp = decode_ts;
3263 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3264 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3265 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3269 initial_offset = *running_offset;
3271 sample = stream->samples + stream->n_samples;
3272 for (i = 0; i < samples_count; i++) {
3273 guint32 dur, size, sflags, ct;
3275 /* first read sample data */
3276 if (flags & TR_SAMPLE_DURATION) {
3277 dur = QT_UINT32 (data + dur_offset);
3279 dur = d_sample_duration;
3281 if (flags & TR_SAMPLE_SIZE) {
3282 size = QT_UINT32 (data + size_offset);
3284 size = d_sample_size;
3286 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3288 sflags = first_flags;
3290 sflags = d_sample_flags;
3292 } else if (flags & TR_SAMPLE_FLAGS) {
3293 sflags = QT_UINT32 (data + flags_offset);
3295 sflags = d_sample_flags;
3297 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3298 ct = QT_UINT32 (data + ct_offset);
3304 /* fill the sample information */
3305 sample->offset = *running_offset;
3306 sample->pts_offset = ct;
3307 sample->size = size;
3308 sample->timestamp = timestamp;
3309 sample->duration = dur;
3310 /* sample-is-difference-sample */
3311 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3312 * now idea how it relates to bitfield other than massive LE/BE confusion */
3313 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3314 *running_offset += size;
3316 stream->duration_moof += dur;
3320 /* Update total duration if needed */
3321 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3323 /* Pre-emptively figure out size of mdat based on trun information.
3324 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3325 * size, else we will still be able to use this when dealing with gap'ed
3327 qtdemux->mdatleft = *running_offset - initial_offset;
3328 qtdemux->mdatoffset = initial_offset;
3329 qtdemux->mdatsize = qtdemux->mdatleft;
3331 stream->n_samples += samples_count;
3332 stream->n_samples_moof += samples_count;
3334 if (stream->pending_seek != NULL)
3335 stream->pending_seek = NULL;
3341 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3346 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3352 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3353 "be larger than %uMB (broken file?)", stream->n_samples,
3354 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3359 /* find stream with @id */
3360 static inline QtDemuxStream *
3361 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3363 QtDemuxStream *stream;
3367 if (G_UNLIKELY (!id)) {
3368 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3372 /* try to get it fast and simple */
3373 if (G_LIKELY (id <= qtdemux->n_streams)) {
3374 stream = qtdemux->streams[id - 1];
3375 if (G_LIKELY (stream->track_id == id))
3379 /* linear search otherwise */
3380 for (i = 0; i < qtdemux->n_streams; i++) {
3381 stream = qtdemux->streams[i];
3382 if (stream->track_id == id)
3385 if (qtdemux->mss_mode) {
3386 /* mss should have only 1 stream anyway */
3387 return qtdemux->streams[0];
3394 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3395 guint32 * fragment_number)
3397 if (!gst_byte_reader_skip (mfhd, 4))
3399 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3404 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3410 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3411 QtDemuxStream ** stream, guint32 * default_sample_duration,
3412 guint32 * default_sample_size, guint32 * default_sample_flags,
3413 gint64 * base_offset)
3416 guint32 track_id = 0;
3418 if (!gst_byte_reader_skip (tfhd, 1) ||
3419 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3422 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3425 *stream = qtdemux_find_stream (qtdemux, track_id);
3426 if (G_UNLIKELY (!*stream))
3427 goto unknown_stream;
3429 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3430 *base_offset = qtdemux->moof_offset;
3432 if (flags & TF_BASE_DATA_OFFSET)
3433 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3436 /* obtain stream defaults */
3437 qtdemux_parse_trex (qtdemux, *stream,
3438 default_sample_duration, default_sample_size, default_sample_flags);
3440 (*stream)->stsd_sample_description_id =
3441 (*stream)->def_sample_description_index - 1;
3443 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3444 guint32 sample_description_index;
3445 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3447 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3450 if (qtdemux->mss_mode) {
3451 /* mss has no stsd entry */
3452 (*stream)->stsd_sample_description_id = 0;
3455 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3456 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3459 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3460 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3463 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3464 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3471 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3476 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3482 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3483 guint64 * decode_time)
3485 guint32 version = 0;
3487 if (!gst_byte_reader_get_uint32_be (br, &version))
3492 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3495 guint32 dec_time = 0;
3496 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3498 *decode_time = dec_time;
3501 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3508 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3513 /* Returns a pointer to a GstStructure containing the properties of
3514 * the stream sample identified by @sample_index. The caller must unref
3515 * the returned object after use. Returns NULL if unsuccessful. */
3516 static GstStructure *
3517 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3518 QtDemuxStream * stream, guint sample_index)
3520 QtDemuxCencSampleSetInfo *info = NULL;
3522 g_return_val_if_fail (stream != NULL, NULL);
3523 g_return_val_if_fail (stream->protected, NULL);
3524 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3526 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3528 /* Currently, cenc properties for groups of samples are not supported, so
3529 * simply return a copy of the default sample properties */
3530 return gst_structure_copy (info->default_properties);
3533 /* Parses the sizes of sample auxiliary information contained within a stream,
3534 * as given in a saiz box. Returns array of sample_count guint8 size values,
3535 * or NULL on failure */
3537 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3538 GstByteReader * br, guint32 * sample_count)
3542 guint8 default_info_size;
3544 g_return_val_if_fail (qtdemux != NULL, NULL);
3545 g_return_val_if_fail (stream != NULL, NULL);
3546 g_return_val_if_fail (br != NULL, NULL);
3547 g_return_val_if_fail (sample_count != NULL, NULL);
3549 if (!gst_byte_reader_get_uint32_be (br, &flags))
3553 /* aux_info_type and aux_info_type_parameter are ignored */
3554 if (!gst_byte_reader_skip (br, 8))
3558 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3560 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3562 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3564 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3567 if (default_info_size == 0) {
3568 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3572 info_sizes = g_new (guint8, *sample_count);
3573 memset (info_sizes, default_info_size, *sample_count);
3579 /* Parses the offset of sample auxiliary information contained within a stream,
3580 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3582 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3583 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3588 guint32 aux_info_type = 0;
3589 guint32 aux_info_type_parameter = 0;
3590 guint32 entry_count;
3593 const guint8 *aux_info_type_data = NULL;
3595 g_return_val_if_fail (qtdemux != NULL, FALSE);
3596 g_return_val_if_fail (stream != NULL, FALSE);
3597 g_return_val_if_fail (br != NULL, FALSE);
3598 g_return_val_if_fail (offset != NULL, FALSE);
3600 if (!gst_byte_reader_get_uint8 (br, &version))
3603 if (!gst_byte_reader_get_uint24_be (br, &flags))
3608 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3610 aux_info_type = QT_FOURCC (aux_info_type_data);
3612 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3614 } else if (stream->protected) {
3615 aux_info_type = stream->protection_scheme_type;
3617 aux_info_type = CUR_STREAM (stream)->fourcc;
3621 *info_type = aux_info_type;
3622 if (info_type_parameter)
3623 *info_type_parameter = aux_info_type_parameter;
3625 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3626 "aux_info_type_parameter: %#06x",
3627 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3629 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3632 if (entry_count != 1) {
3633 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3638 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3640 *offset = (guint64) off_32;
3642 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3647 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3652 qtdemux_gst_structure_free (GstStructure * gststructure)
3655 gst_structure_free (gststructure);
3659 /* Parses auxiliary information relating to samples protected using Common
3660 * Encryption (cenc); the format of this information is defined in
3661 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3663 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3664 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3666 QtDemuxCencSampleSetInfo *ss_info = NULL;
3669 GPtrArray *old_crypto_info = NULL;
3670 guint old_entries = 0;
3672 g_return_val_if_fail (qtdemux != NULL, FALSE);
3673 g_return_val_if_fail (stream != NULL, FALSE);
3674 g_return_val_if_fail (br != NULL, FALSE);
3675 g_return_val_if_fail (stream->protected, FALSE);
3676 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3678 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3680 if (ss_info->crypto_info) {
3681 old_crypto_info = ss_info->crypto_info;
3682 /* Count number of non-null entries remaining at the tail end */
3683 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3684 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3690 ss_info->crypto_info =
3691 g_ptr_array_new_full (sample_count + old_entries,
3692 (GDestroyNotify) qtdemux_gst_structure_free);
3694 /* We preserve old entries because we parse the next moof in advance
3695 * of consuming all samples from the previous moof, and otherwise
3696 * we'd discard the corresponding crypto info for the samples
3697 * from the previous fragment. */
3699 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3701 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3702 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3704 g_ptr_array_index (old_crypto_info, i) = NULL;
3708 if (old_crypto_info) {
3709 /* Everything now belongs to the new array */
3710 g_ptr_array_free (old_crypto_info, TRUE);
3713 for (i = 0; i < sample_count; ++i) {
3714 GstStructure *properties;
3715 guint16 n_subsamples = 0;
3720 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3721 if (properties == NULL) {
3722 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3725 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3726 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3727 gst_structure_free (properties);
3730 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3731 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3732 gst_structure_free (properties);
3735 buf = gst_buffer_new_wrapped (data, iv_size);
3736 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3737 gst_buffer_unref (buf);
3738 size = info_sizes[i];
3739 if (size > iv_size) {
3740 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3741 || !(n_subsamples > 0)) {
3742 gst_structure_free (properties);
3743 GST_ERROR_OBJECT (qtdemux,
3744 "failed to get subsample count for sample %u", i);
3747 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3748 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3749 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3751 gst_structure_free (properties);
3754 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3756 gst_structure_free (properties);
3759 gst_structure_set (properties,
3760 "subsample_count", G_TYPE_UINT, n_subsamples,
3761 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3762 gst_buffer_unref (buf);
3764 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3766 g_ptr_array_add (ss_info->crypto_info, properties);
3771 /* Converts a UUID in raw byte form to a string representation, as defined in
3772 * RFC 4122. The caller takes ownership of the returned string and is
3773 * responsible for freeing it after use. */
3775 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3777 const guint8 *uuid = (const guint8 *) uuid_bytes;
3779 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3780 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3781 uuid[0], uuid[1], uuid[2], uuid[3],
3782 uuid[4], uuid[5], uuid[6], uuid[7],
3783 uuid[8], uuid[9], uuid[10], uuid[11],
3784 uuid[12], uuid[13], uuid[14], uuid[15]);
3787 /* Parses a Protection System Specific Header box (pssh), as defined in the
3788 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3789 * information needed by a specific content protection system in order to
3790 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3793 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3795 gchar *sysid_string;
3796 guint32 pssh_size = QT_UINT32 (node->data);
3797 GstBuffer *pssh = NULL;
3798 GstEvent *event = NULL;
3799 guint32 parent_box_type;
3802 if (G_UNLIKELY (pssh_size < 32U)) {
3803 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3808 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3810 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3812 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3813 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3814 gst_buffer_get_size (pssh));
3816 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3818 /* Push an event containing the pssh box onto the queues of all streams. */
3819 event = gst_event_new_protection (sysid_string, pssh,
3820 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3821 for (i = 0; i < qtdemux->n_streams; ++i) {
3822 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3823 gst_event_ref (event));
3825 g_free (sysid_string);
3826 gst_event_unref (event);
3827 gst_buffer_unref (pssh);
3832 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3833 guint64 moof_offset, QtDemuxStream * stream)
3835 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3837 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3838 GNode *saiz_node, *saio_node, *pssh_node;
3839 GstByteReader saiz_data, saio_data;
3840 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3841 gint64 base_offset, running_offset;
3844 /* NOTE @stream ignored */
3846 moof_node = g_node_new ((guint8 *) buffer);
3847 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3848 qtdemux_node_dump (qtdemux, moof_node);
3850 /* Get fragment number from mfhd and check it's valid */
3852 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3853 if (mfhd_node == NULL)
3855 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3857 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3859 /* unknown base_offset to start with */
3860 base_offset = running_offset = -1;
3861 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3863 guint64 decode_time = 0;
3865 /* Fragment Header node */
3867 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3871 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3872 &ds_size, &ds_flags, &base_offset))
3875 /* The following code assumes at most a single set of sample auxiliary
3876 * data in the fragment (consisting of a saiz box and a corresponding saio
3877 * box); in theory, however, there could be multiple sets of sample
3878 * auxiliary data in a fragment. */
3880 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3883 guint32 info_type = 0;
3885 guint32 info_type_parameter = 0;
3887 g_free (qtdemux->cenc_aux_info_sizes);
3889 qtdemux->cenc_aux_info_sizes =
3890 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3891 &qtdemux->cenc_aux_sample_count);
3892 if (qtdemux->cenc_aux_info_sizes == NULL) {
3893 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3897 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3900 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3901 g_free (qtdemux->cenc_aux_info_sizes);
3902 qtdemux->cenc_aux_info_sizes = NULL;
3906 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3907 &info_type, &info_type_parameter, &offset))) {
3908 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3909 g_free (qtdemux->cenc_aux_info_sizes);
3910 qtdemux->cenc_aux_info_sizes = NULL;
3913 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3914 offset += (guint64) (base_offset - qtdemux->moof_offset);
3915 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3917 if (offset > length) {
3918 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3919 qtdemux->cenc_aux_info_offset = offset;
3921 gst_byte_reader_init (&br, buffer + offset, length - offset);
3922 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3923 qtdemux->cenc_aux_info_sizes,
3924 qtdemux->cenc_aux_sample_count)) {
3925 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3926 g_free (qtdemux->cenc_aux_info_sizes);
3927 qtdemux->cenc_aux_info_sizes = NULL;
3935 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3938 /* We'll use decode_time to interpolate timestamps
3939 * in case the input timestamps are missing */
3940 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3942 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3943 " (%" GST_TIME_FORMAT ")", decode_time,
3944 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
3945 decode_time) : GST_CLOCK_TIME_NONE));
3947 /* Discard the fragment buffer timestamp info to avoid using it.
3948 * Rely on tfdt instead as it is more accurate than the timestamp
3949 * that is fetched from a manifest/playlist and is usually
3951 qtdemux->fragment_start = -1;
3954 if (G_UNLIKELY (!stream)) {
3955 /* we lost track of offset, we'll need to regain it,
3956 * but can delay complaining until later or avoid doing so altogether */
3960 if (G_UNLIKELY (base_offset < -1))
3963 if (qtdemux->upstream_format_is_time)
3964 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3966 /* initialise moof sample data */
3967 stream->n_samples_moof = 0;
3968 stream->duration_last_moof = stream->duration_moof;
3969 stream->duration_moof = 0;
3971 /* Track Run node */
3973 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3976 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3977 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3978 &running_offset, decode_time, (tfdt_node != NULL));
3979 /* iterate all siblings */
3980 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3984 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3986 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3987 guint32 box_length = QT_UINT32 (uuid_buffer);
3989 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3992 /* if no new base_offset provided for next traf,
3993 * base is end of current traf */
3994 base_offset = running_offset;
3995 running_offset = -1;
3997 if (stream->n_samples_moof && stream->duration_moof)
3998 stream->new_caps = TRUE;
4001 /* iterate all siblings */
4002 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4005 /* parse any protection system info */
4006 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4008 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4009 qtdemux_parse_pssh (qtdemux, pssh_node);
4010 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4013 g_node_destroy (moof_node);
4018 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4023 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4028 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4033 g_node_destroy (moof_node);
4034 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4035 (_("This file is corrupt and cannot be played.")), (NULL));
4041 /* might be used if some day we actually use mfra & co
4042 * for random access to fragments,
4043 * but that will require quite some modifications and much less relying
4044 * on a sample array */
4048 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4050 QtDemuxStream *stream;
4051 guint32 ver_flags, track_id, len, num_entries, i;
4052 guint value_size, traf_size, trun_size, sample_size;
4053 guint64 time = 0, moof_offset = 0;
4055 GstBuffer *buf = NULL;
4060 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4062 if (!gst_byte_reader_skip (&tfra, 8))
4065 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4068 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4069 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4070 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4073 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4075 stream = qtdemux_find_stream (qtdemux, track_id);
4077 goto unknown_trackid;
4079 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4080 sample_size = (len & 3) + 1;
4081 trun_size = ((len & 12) >> 2) + 1;
4082 traf_size = ((len & 48) >> 4) + 1;
4084 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4085 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4087 if (num_entries == 0)
4090 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4091 value_size + value_size + traf_size + trun_size + sample_size))
4094 g_free (stream->ra_entries);
4095 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4096 stream->n_ra_entries = num_entries;
4098 for (i = 0; i < num_entries; i++) {
4099 qt_atom_parser_get_offset (&tfra, value_size, &time);
4100 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4101 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4102 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4103 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4105 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4107 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4108 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4110 stream->ra_entries[i].ts = time;
4111 stream->ra_entries[i].moof_offset = moof_offset;
4113 /* don't want to go through the entire file and read all moofs at startup */
4115 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4116 if (ret != GST_FLOW_OK)
4118 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4119 moof_offset, stream);
4120 gst_buffer_unref (buf);
4124 check_update_duration (qtdemux, time);
4131 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4136 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4141 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4147 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4149 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4150 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4151 GstBuffer *mfro = NULL, *mfra = NULL;
4153 gboolean ret = FALSE;
4154 GNode *mfra_node, *tfra_node;
4155 guint64 mfra_offset = 0;
4156 guint32 fourcc, mfra_size;
4159 /* query upstream size in bytes */
4160 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4161 goto size_query_failed;
4163 /* mfro box should be at the very end of the file */
4164 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4165 if (flow != GST_FLOW_OK)
4168 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4170 fourcc = QT_FOURCC (mfro_map.data + 4);
4171 if (fourcc != FOURCC_mfro)
4174 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4175 if (mfro_map.size < 16)
4176 goto invalid_mfro_size;
4178 mfra_size = QT_UINT32 (mfro_map.data + 12);
4179 if (mfra_size >= len)
4180 goto invalid_mfra_size;
4182 mfra_offset = len - mfra_size;
4184 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4185 mfra_offset, mfra_size);
4187 /* now get and parse mfra box */
4188 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4189 if (flow != GST_FLOW_OK)
4192 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4194 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4195 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4197 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4200 qtdemux_parse_tfra (qtdemux, tfra_node);
4201 /* iterate all siblings */
4202 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4204 g_node_destroy (mfra_node);
4206 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4212 if (mfro_map.memory != NULL)
4213 gst_buffer_unmap (mfro, &mfro_map);
4214 gst_buffer_unref (mfro);
4217 if (mfra_map.memory != NULL)
4218 gst_buffer_unmap (mfra, &mfra_map);
4219 gst_buffer_unref (mfra);
4226 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4231 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4236 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4241 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4247 add_offset (guint64 offset, guint64 advance)
4249 /* Avoid 64-bit overflow by clamping */
4250 if (offset > G_MAXUINT64 - advance)
4252 return offset + advance;
4255 static GstFlowReturn
4256 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4260 GstBuffer *buf = NULL;
4261 GstFlowReturn ret = GST_FLOW_OK;
4262 guint64 cur_offset = qtdemux->offset;
4265 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4266 if (G_UNLIKELY (ret != GST_FLOW_OK))
4268 gst_buffer_map (buf, &map, GST_MAP_READ);
4269 if (G_LIKELY (map.size >= 8))
4270 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4271 gst_buffer_unmap (buf, &map);
4272 gst_buffer_unref (buf);
4274 /* maybe we already got most we needed, so only consider this eof */
4275 if (G_UNLIKELY (length == 0)) {
4276 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4277 (_("Invalid atom size.")),
4278 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4279 GST_FOURCC_ARGS (fourcc)));
4286 /* record for later parsing when needed */
4287 if (!qtdemux->moof_offset) {
4288 qtdemux->moof_offset = qtdemux->offset;
4290 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4293 qtdemux->offset += length; /* skip moof and keep going */
4295 if (qtdemux->got_moov) {
4296 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4308 GST_LOG_OBJECT (qtdemux,
4309 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4310 GST_FOURCC_ARGS (fourcc), cur_offset);
4311 qtdemux->offset = add_offset (qtdemux->offset, length);
4316 GstBuffer *moov = NULL;
4318 if (qtdemux->got_moov) {
4319 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4320 qtdemux->offset = add_offset (qtdemux->offset, length);
4324 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4325 if (ret != GST_FLOW_OK)
4327 gst_buffer_map (moov, &map, GST_MAP_READ);
4329 if (length != map.size) {
4330 /* Some files have a 'moov' atom at the end of the file which contains
4331 * a terminal 'free' atom where the body of the atom is missing.
4332 * Check for, and permit, this special case.
4334 if (map.size >= 8) {
4335 guint8 *final_data = map.data + (map.size - 8);
4336 guint32 final_length = QT_UINT32 (final_data);
4337 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4339 if (final_fourcc == FOURCC_free
4340 && map.size + final_length - 8 == length) {
4341 /* Ok, we've found that special case. Allocate a new buffer with
4342 * that free atom actually present. */
4343 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4344 gst_buffer_fill (newmoov, 0, map.data, map.size);
4345 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4346 gst_buffer_unmap (moov, &map);
4347 gst_buffer_unref (moov);
4349 gst_buffer_map (moov, &map, GST_MAP_READ);
4354 if (length != map.size) {
4355 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4356 (_("This file is incomplete and cannot be played.")),
4357 ("We got less than expected (received %" G_GSIZE_FORMAT
4358 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4359 (guint) length, cur_offset));
4360 gst_buffer_unmap (moov, &map);
4361 gst_buffer_unref (moov);
4362 ret = GST_FLOW_ERROR;
4365 qtdemux->offset += length;
4367 qtdemux_parse_moov (qtdemux, map.data, length);
4368 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4370 qtdemux_parse_tree (qtdemux);
4371 if (qtdemux->moov_node_compressed) {
4372 g_node_destroy (qtdemux->moov_node_compressed);
4373 g_free (qtdemux->moov_node->data);
4375 qtdemux->moov_node_compressed = NULL;
4376 g_node_destroy (qtdemux->moov_node);
4377 qtdemux->moov_node = NULL;
4378 gst_buffer_unmap (moov, &map);
4379 gst_buffer_unref (moov);
4380 qtdemux->got_moov = TRUE;
4386 GstBuffer *ftyp = NULL;
4388 /* extract major brand; might come in handy for ISO vs QT issues */
4389 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4390 if (ret != GST_FLOW_OK)
4392 qtdemux->offset += length;
4393 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4394 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4395 gst_buffer_unmap (ftyp, &map);
4396 gst_buffer_unref (ftyp);
4401 GstBuffer *uuid = NULL;
4403 /* uuid are extension atoms */
4404 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4405 if (ret != GST_FLOW_OK)
4407 qtdemux->offset += length;
4408 gst_buffer_map (uuid, &map, GST_MAP_READ);
4409 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4410 gst_buffer_unmap (uuid, &map);
4411 gst_buffer_unref (uuid);
4416 GstBuffer *sidx = NULL;
4417 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4418 if (ret != GST_FLOW_OK)
4420 qtdemux->offset += length;
4421 gst_buffer_map (sidx, &map, GST_MAP_READ);
4422 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4423 gst_buffer_unmap (sidx, &map);
4424 gst_buffer_unref (sidx);
4429 GstBuffer *unknown = NULL;
4431 GST_LOG_OBJECT (qtdemux,
4432 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4433 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4435 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4436 if (ret != GST_FLOW_OK)
4438 gst_buffer_map (unknown, &map, GST_MAP_READ);
4439 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4440 gst_buffer_unmap (unknown, &map);
4441 gst_buffer_unref (unknown);
4442 qtdemux->offset += length;
4448 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4449 /* digested all data, show what we have */
4450 qtdemux_prepare_streams (qtdemux);
4451 ret = qtdemux_expose_streams (qtdemux);
4453 qtdemux->state = QTDEMUX_STATE_MOVIE;
4454 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4461 /* Seeks to the previous keyframe of the indexed stream and
4462 * aligns other streams with respect to the keyframe timestamp
4463 * of indexed stream. Only called in case of Reverse Playback
4465 static GstFlowReturn
4466 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4469 guint32 seg_idx = 0, k_index = 0;
4470 guint32 ref_seg_idx, ref_k_index;
4471 GstClockTime k_pos = 0, last_stop = 0;
4472 QtDemuxSegment *seg = NULL;
4473 QtDemuxStream *ref_str = NULL;
4474 guint64 seg_media_start_mov; /* segment media start time in mov format */
4477 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4478 * and finally align all the other streams on that timestamp with their
4479 * respective keyframes */
4480 for (n = 0; n < qtdemux->n_streams; n++) {
4481 QtDemuxStream *str = qtdemux->streams[n];
4483 /* No candidate yet, take the first stream */
4489 /* So that stream has a segment, we prefer video streams */
4490 if (str->subtype == FOURCC_vide) {
4496 if (G_UNLIKELY (!ref_str)) {
4497 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4501 if (G_UNLIKELY (!ref_str->from_sample)) {
4502 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4506 /* So that stream has been playing from from_sample to to_sample. We will
4507 * get the timestamp of the previous sample and search for a keyframe before
4508 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4509 if (ref_str->subtype == FOURCC_vide) {
4510 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4511 ref_str->from_sample - 1, FALSE);
4513 if (ref_str->from_sample >= 10)
4514 k_index = ref_str->from_sample - 10;
4520 ref_str->samples[k_index].timestamp +
4521 ref_str->samples[k_index].pts_offset;
4523 /* get current segment for that stream */
4524 seg = &ref_str->segments[ref_str->segment_index];
4525 /* Use segment start in original timescale for comparisons */
4526 seg_media_start_mov = seg->trak_media_start;
4528 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4529 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4530 k_index, target_ts, seg_media_start_mov,
4531 GST_TIME_ARGS (seg->media_start));
4533 /* Crawl back through segments to find the one containing this I frame */
4534 while (target_ts < seg_media_start_mov) {
4535 GST_DEBUG_OBJECT (qtdemux,
4536 "keyframe position (sample %u) is out of segment %u " " target %"
4537 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4538 ref_str->segment_index, target_ts, seg_media_start_mov);
4540 if (G_UNLIKELY (!ref_str->segment_index)) {
4541 /* Reached first segment, let's consider it's EOS */
4544 ref_str->segment_index--;
4545 seg = &ref_str->segments[ref_str->segment_index];
4546 /* Use segment start in original timescale for comparisons */
4547 seg_media_start_mov = seg->trak_media_start;
4549 /* Calculate time position of the keyframe and where we should stop */
4551 QTSTREAMTIME_TO_GSTTIME (ref_str,
4552 target_ts - seg->trak_media_start) + seg->time;
4554 QTSTREAMTIME_TO_GSTTIME (ref_str,
4555 ref_str->samples[ref_str->from_sample].timestamp -
4556 seg->trak_media_start) + seg->time;
4558 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4559 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4560 k_index, GST_TIME_ARGS (k_pos));
4562 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4563 qtdemux->segment.position = last_stop;
4564 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4565 GST_TIME_ARGS (last_stop));
4567 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4568 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4572 ref_seg_idx = ref_str->segment_index;
4573 ref_k_index = k_index;
4575 /* Align them all on this */
4576 for (n = 0; n < qtdemux->n_streams; n++) {
4578 GstClockTime seg_time = 0;
4579 QtDemuxStream *str = qtdemux->streams[n];
4581 /* aligning reference stream again might lead to backing up to yet another
4582 * keyframe (due to timestamp rounding issues),
4583 * potentially putting more load on downstream; so let's try to avoid */
4584 if (str == ref_str) {
4585 seg_idx = ref_seg_idx;
4586 seg = &str->segments[seg_idx];
4587 k_index = ref_k_index;
4588 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4589 "sample at index %d", n, ref_str->segment_index, k_index);
4591 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4592 GST_DEBUG_OBJECT (qtdemux,
4593 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4594 seg_idx, GST_TIME_ARGS (k_pos));
4596 /* get segment and time in the segment */
4597 seg = &str->segments[seg_idx];
4598 seg_time = k_pos - seg->time;
4600 /* get the media time in the segment.
4601 * No adjustment for empty "filler" segments */
4602 if (seg->media_start != GST_CLOCK_TIME_NONE)
4603 seg_time += seg->media_start;
4605 /* get the index of the sample with media time */
4606 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4607 GST_DEBUG_OBJECT (qtdemux,
4608 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4609 GST_TIME_ARGS (seg_time), index);
4611 /* find previous keyframe */
4612 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4615 /* Remember until where we want to go */
4616 str->to_sample = str->from_sample - 1;
4617 /* Define our time position */
4619 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4620 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4621 if (seg->media_start != GST_CLOCK_TIME_NONE)
4622 str->time_position -= seg->media_start;
4624 /* Now seek back in time */
4625 gst_qtdemux_move_stream (qtdemux, str, k_index);
4626 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4627 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4628 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4634 return GST_FLOW_EOS;
4638 * Gets the current qt segment start, stop and position for the
4639 * given time offset. This is used in update_segment()
4642 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4643 QtDemuxStream * stream, GstClockTime offset,
4644 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4646 GstClockTime seg_time;
4647 GstClockTime start, stop, time;
4648 QtDemuxSegment *segment;
4650 segment = &stream->segments[stream->segment_index];
4652 /* get time in this segment */
4653 seg_time = (offset - segment->time) * segment->rate;
4655 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4656 GST_TIME_ARGS (seg_time));
4658 if (G_UNLIKELY (seg_time > segment->duration)) {
4659 GST_LOG_OBJECT (stream->pad,
4660 "seg_time > segment->duration %" GST_TIME_FORMAT,
4661 GST_TIME_ARGS (segment->duration));
4662 seg_time = segment->duration;
4665 /* qtdemux->segment.stop is in outside-time-realm, whereas
4666 * segment->media_stop is in track-time-realm.
4668 * In order to compare the two, we need to bring segment.stop
4669 * into the track-time-realm
4671 * FIXME - does this comment still hold? Don't see any conversion here */
4673 stop = qtdemux->segment.stop;
4674 if (stop == GST_CLOCK_TIME_NONE)
4675 stop = qtdemux->segment.duration;
4676 if (stop == GST_CLOCK_TIME_NONE)
4677 stop = segment->media_stop;
4680 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4682 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4683 start = segment->time + seg_time;
4685 stop = start - seg_time + segment->duration;
4686 } else if (qtdemux->segment.rate >= 0) {
4687 start = MIN (segment->media_start + seg_time, stop);
4690 if (segment->media_start >= qtdemux->segment.start) {
4691 time = segment->time;
4693 time = segment->time + (qtdemux->segment.start - segment->media_start);
4696 start = MAX (segment->media_start, qtdemux->segment.start);
4697 stop = MIN (segment->media_start + seg_time, stop);
4706 * Updates the qt segment used for the stream and pushes a new segment event
4707 * downstream on this stream's pad.
4710 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4711 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4712 GstClockTime * _stop)
4714 QtDemuxSegment *segment;
4715 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4719 /* update the current segment */
4720 stream->segment_index = seg_idx;
4722 /* get the segment */
4723 segment = &stream->segments[seg_idx];
4725 if (G_UNLIKELY (offset < segment->time)) {
4726 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4727 GST_TIME_ARGS (segment->time));
4731 /* segment lies beyond total indicated duration */
4732 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4733 segment->time > qtdemux->segment.duration)) {
4734 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4735 " < segment->time %" GST_TIME_FORMAT,
4736 GST_TIME_ARGS (qtdemux->segment.duration),
4737 GST_TIME_ARGS (segment->time));
4741 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4742 &start, &stop, &time);
4744 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4745 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4746 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4748 /* combine global rate with that of the segment */
4749 rate = segment->rate * qtdemux->segment.rate;
4751 /* Copy flags from main segment */
4752 stream->segment.flags = qtdemux->segment.flags;
4754 /* update the segment values used for clipping */
4755 stream->segment.offset = qtdemux->segment.offset;
4756 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4757 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4758 stream->segment.rate = rate;
4759 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4760 stream->cslg_shift);
4761 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4762 stream->cslg_shift);
4763 stream->segment.time = time;
4764 stream->segment.position = stream->segment.start;
4766 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4769 /* now prepare and send the segment */
4771 event = gst_event_new_segment (&stream->segment);
4772 if (qtdemux->segment_seqnum) {
4773 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4775 gst_pad_push_event (stream->pad, event);
4776 /* assume we can send more data now */
4777 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4778 /* clear to send tags on this pad now */
4779 gst_qtdemux_push_tags (qtdemux, stream);
4790 /* activate the given segment number @seg_idx of @stream at time @offset.
4791 * @offset is an absolute global position over all the segments.
4793 * This will push out a NEWSEGMENT event with the right values and
4794 * position the stream index to the first decodable sample before
4798 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4799 guint32 seg_idx, GstClockTime offset)
4801 QtDemuxSegment *segment;
4802 guint32 index, kf_index;
4803 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4805 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4806 seg_idx, GST_TIME_ARGS (offset));
4808 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4812 segment = &stream->segments[stream->segment_index];
4814 /* in the fragmented case, we pick a fragment that starts before our
4815 * desired position and rely on downstream to wait for a keyframe
4816 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4817 * tfra entries tells us which trun/sample the key unit is in, but we don't
4818 * make use of this additional information at the moment) */
4819 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4820 stream->to_sample = G_MAXUINT32;
4823 /* well, it will be taken care of below */
4824 qtdemux->fragmented_seek_pending = FALSE;
4825 /* FIXME ideally the do_fragmented_seek can be done right here,
4826 * rather than at loop level
4827 * (which might even allow handling edit lists in a fragmented file) */
4830 /* We don't need to look for a sample in push-based */
4831 if (!qtdemux->pullbased)
4834 /* and move to the keyframe before the indicated media time of the
4836 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4837 if (qtdemux->segment.rate >= 0) {
4838 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4839 stream->to_sample = G_MAXUINT32;
4840 GST_DEBUG_OBJECT (stream->pad,
4841 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4842 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4843 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4845 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4846 stream->to_sample = index;
4847 GST_DEBUG_OBJECT (stream->pad,
4848 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4849 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4850 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4853 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4854 "this is an empty segment");
4858 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4859 * encountered an error and printed a message so we return appropriately */
4863 /* we're at the right spot */
4864 if (index == stream->sample_index) {
4865 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4869 /* find keyframe of the target index */
4870 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4873 /* indent does stupid stuff with stream->samples[].timestamp */
4875 /* if we move forwards, we don't have to go back to the previous
4876 * keyframe since we already sent that. We can also just jump to
4877 * the keyframe right before the target index if there is one. */
4878 if (index > stream->sample_index) {
4879 /* moving forwards check if we move past a keyframe */
4880 if (kf_index > stream->sample_index) {
4881 GST_DEBUG_OBJECT (stream->pad,
4882 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4883 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4884 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4885 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4887 GST_DEBUG_OBJECT (stream->pad,
4888 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4889 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4890 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4893 GST_DEBUG_OBJECT (stream->pad,
4894 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4895 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4896 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4897 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4905 /* prepare to get the current sample of @stream, getting essential values.
4907 * This function will also prepare and send the segment when needed.
4909 * Return FALSE if the stream is EOS.
4914 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4915 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4916 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4917 gboolean * keyframe)
4919 QtDemuxSample *sample;
4920 GstClockTime time_position;
4923 g_return_val_if_fail (stream != NULL, FALSE);
4925 time_position = stream->time_position;
4926 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4929 seg_idx = stream->segment_index;
4930 if (G_UNLIKELY (seg_idx == -1)) {
4931 /* find segment corresponding to time_position if we are looking
4933 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4936 /* different segment, activate it, sample_index will be set. */
4937 if (G_UNLIKELY (stream->segment_index != seg_idx))
4938 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4940 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4942 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4944 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4945 " prepare empty sample");
4948 *pts = *dts = time_position;
4949 *duration = seg->duration - (time_position - seg->time);
4956 if (stream->sample_index == -1)
4957 stream->sample_index = 0;
4959 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4960 stream->sample_index, stream->n_samples);
4962 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4963 if (!qtdemux->fragmented)
4966 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4970 GST_OBJECT_LOCK (qtdemux);
4971 flow = qtdemux_add_fragmented_samples (qtdemux);
4972 GST_OBJECT_UNLOCK (qtdemux);
4974 if (flow != GST_FLOW_OK)
4977 while (stream->sample_index >= stream->n_samples);
4980 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4981 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4982 stream->sample_index);
4986 /* now get the info for the sample we're at */
4987 sample = &stream->samples[stream->sample_index];
4989 *dts = QTSAMPLE_DTS (stream, sample);
4990 *pts = QTSAMPLE_PTS (stream, sample);
4991 *offset = sample->offset;
4992 *size = sample->size;
4993 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4994 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5001 stream->time_position = GST_CLOCK_TIME_NONE;
5006 /* move to the next sample in @stream.
5008 * Moves to the next segment when needed.
5011 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5013 QtDemuxSample *sample;
5014 QtDemuxSegment *segment;
5016 /* get current segment */
5017 segment = &stream->segments[stream->segment_index];
5019 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5020 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5024 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5025 /* Mark the stream as EOS */
5026 GST_DEBUG_OBJECT (qtdemux,
5027 "reached max allowed sample %u, mark EOS", stream->to_sample);
5028 stream->time_position = GST_CLOCK_TIME_NONE;
5032 /* move to next sample */
5033 stream->sample_index++;
5034 stream->offset_in_sample = 0;
5036 /* reached the last sample, we need the next segment */
5037 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5040 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5041 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5042 stream->sample_index);
5046 /* get next sample */
5047 sample = &stream->samples[stream->sample_index];
5049 /* see if we are past the segment */
5050 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5053 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5054 /* inside the segment, update time_position, looks very familiar to
5055 * GStreamer segments, doesn't it? */
5056 stream->time_position =
5057 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5059 /* not yet in segment, time does not yet increment. This means
5060 * that we are still prerolling keyframes to the decoder so it can
5061 * decode the first sample of the segment. */
5062 stream->time_position = segment->time;
5066 /* move to the next segment */
5069 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5071 if (stream->segment_index == stream->n_segments - 1) {
5072 /* are we at the end of the last segment, we're EOS */
5073 stream->time_position = GST_CLOCK_TIME_NONE;
5075 /* else we're only at the end of the current segment */
5076 stream->time_position = segment->stop_time;
5078 /* make sure we select a new segment */
5080 /* accumulate previous segments */
5081 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5082 stream->accumulated_base +=
5083 (stream->segment.stop -
5084 stream->segment.start) / ABS (stream->segment.rate);
5086 stream->segment_index = -1;
5091 gst_qtdemux_sync_streams (GstQTDemux * demux)
5095 if (demux->n_streams <= 1)
5098 for (i = 0; i < demux->n_streams; i++) {
5099 QtDemuxStream *stream;
5100 GstClockTime end_time;
5102 stream = demux->streams[i];
5107 /* TODO advance time on subtitle streams here, if any some day */
5109 /* some clips/trailers may have unbalanced streams at the end,
5110 * so send EOS on shorter stream to prevent stalling others */
5112 /* do not mess with EOS if SEGMENT seeking */
5113 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5116 if (demux->pullbased) {
5117 /* loop mode is sample time based */
5118 if (!STREAM_IS_EOS (stream))
5121 /* push mode is byte position based */
5122 if (stream->n_samples &&
5123 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5127 if (stream->sent_eos)
5130 /* only act if some gap */
5131 end_time = stream->segments[stream->n_segments - 1].stop_time;
5132 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5133 ", stream end: %" GST_TIME_FORMAT,
5134 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5135 if (GST_CLOCK_TIME_IS_VALID (end_time)
5136 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5139 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5140 GST_PAD_NAME (stream->pad));
5141 stream->sent_eos = TRUE;
5142 event = gst_event_new_eos ();
5143 if (demux->segment_seqnum)
5144 gst_event_set_seqnum (event, demux->segment_seqnum);
5145 gst_pad_push_event (stream->pad, event);
5150 /* EOS and NOT_LINKED need to be combined. This means that we return:
5152 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5153 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5155 static GstFlowReturn
5156 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5159 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5162 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5165 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5167 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5171 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5172 * completely clipped
5174 * Should be used only with raw buffers */
5176 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5179 guint64 start, stop, cstart, cstop, diff;
5180 GstClockTime pts, duration;
5182 gint num_rate, denom_rate;
5187 osize = size = gst_buffer_get_size (buf);
5190 /* depending on the type, setup the clip parameters */
5191 if (stream->subtype == FOURCC_soun) {
5192 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5193 num_rate = GST_SECOND;
5194 denom_rate = (gint) CUR_STREAM (stream)->rate;
5196 } else if (stream->subtype == FOURCC_vide) {
5198 num_rate = CUR_STREAM (stream)->fps_n;
5199 denom_rate = CUR_STREAM (stream)->fps_d;
5204 if (frame_size <= 0)
5205 goto bad_frame_size;
5207 /* we can only clip if we have a valid pts */
5208 pts = GST_BUFFER_PTS (buf);
5209 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5212 duration = GST_BUFFER_DURATION (buf);
5214 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5216 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5220 stop = start + duration;
5222 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5223 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5226 /* see if some clipping happened */
5227 diff = cstart - start;
5233 /* bring clipped time to samples and to bytes */
5234 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5237 GST_DEBUG_OBJECT (qtdemux,
5238 "clipping start to %" GST_TIME_FORMAT " %"
5239 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5245 diff = stop - cstop;
5250 /* bring clipped time to samples and then to bytes */
5251 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5253 GST_DEBUG_OBJECT (qtdemux,
5254 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5255 " bytes", GST_TIME_ARGS (cstop), diff);
5260 if (offset != 0 || size != osize)
5261 gst_buffer_resize (buf, offset, size);
5263 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5264 GST_BUFFER_PTS (buf) = pts;
5265 GST_BUFFER_DURATION (buf) = duration;
5269 /* dropped buffer */
5272 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5277 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5282 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5287 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5288 gst_buffer_unref (buf);
5294 gst_qtdemux_align_buffer (GstQTDemux * demux,
5295 GstBuffer * buffer, gsize alignment)
5299 gst_buffer_map (buffer, &map, GST_MAP_READ);
5301 if (map.size < sizeof (guintptr)) {
5302 gst_buffer_unmap (buffer, &map);
5306 if (((guintptr) map.data) & (alignment - 1)) {
5307 GstBuffer *new_buffer;
5308 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5310 new_buffer = gst_buffer_new_allocate (NULL,
5311 gst_buffer_get_size (buffer), ¶ms);
5313 /* Copy data "by hand", so ensure alignment is kept: */
5314 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5316 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5317 GST_DEBUG_OBJECT (demux,
5318 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5321 gst_buffer_unmap (buffer, &map);
5322 gst_buffer_unref (buffer);
5327 gst_buffer_unmap (buffer, &map);
5331 /* the input buffer metadata must be writable,
5332 * but time/duration etc not yet set and need not be preserved */
5334 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5341 /* not many cases for now */
5342 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5343 /* send a one time dvd clut event */
5344 if (stream->pending_event && stream->pad)
5345 gst_pad_push_event (stream->pad, stream->pending_event);
5346 stream->pending_event = NULL;
5349 if (G_UNLIKELY (stream->subtype != FOURCC_text
5350 && stream->subtype != FOURCC_sbtl &&
5351 stream->subtype != FOURCC_subp)) {
5355 gst_buffer_map (buf, &map, GST_MAP_READ);
5357 /* empty buffer is sent to terminate previous subtitle */
5358 if (map.size <= 2) {
5359 gst_buffer_unmap (buf, &map);
5360 gst_buffer_unref (buf);
5363 if (stream->subtype == FOURCC_subp) {
5364 /* That's all the processing needed for subpictures */
5365 gst_buffer_unmap (buf, &map);
5369 nsize = GST_READ_UINT16_BE (map.data);
5370 nsize = MIN (nsize, map.size - 2);
5372 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5375 /* takes care of UTF-8 validation or UTF-16 recognition,
5376 * no other encoding expected */
5377 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5378 gst_buffer_unmap (buf, &map);
5380 gst_buffer_unref (buf);
5381 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5383 /* this should not really happen unless the subtitle is corrupted */
5384 gst_buffer_unref (buf);
5388 /* FIXME ? convert optional subsequent style info to markup */
5393 /* Sets a buffer's attributes properly and pushes it downstream.
5394 * Also checks for additional actions and custom processing that may
5395 * need to be done first.
5397 static GstFlowReturn
5398 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5399 QtDemuxStream * stream, GstBuffer * buf,
5400 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5401 gboolean keyframe, GstClockTime position, guint64 byte_position)
5403 GstFlowReturn ret = GST_FLOW_OK;
5405 /* offset the timestamps according to the edit list */
5407 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5411 gst_buffer_map (buf, &map, GST_MAP_READ);
5412 url = g_strndup ((gchar *) map.data, map.size);
5413 gst_buffer_unmap (buf, &map);
5414 if (url != NULL && strlen (url) != 0) {
5415 /* we have RTSP redirect now */
5416 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5417 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5418 gst_structure_new ("redirect",
5419 "new-location", G_TYPE_STRING, url, NULL)));
5420 qtdemux->posted_redirect = TRUE;
5422 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5428 /* position reporting */
5429 if (qtdemux->segment.rate >= 0) {
5430 qtdemux->segment.position = position;
5431 gst_qtdemux_sync_streams (qtdemux);
5434 if (G_UNLIKELY (!stream->pad)) {
5435 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5436 gst_buffer_unref (buf);
5440 /* send out pending buffers */
5441 while (stream->buffers) {
5442 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5444 if (G_UNLIKELY (stream->discont)) {
5445 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5446 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5447 stream->discont = FALSE;
5449 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5452 if (stream->alignment > 1)
5453 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5454 gst_pad_push (stream->pad, buffer);
5456 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5459 /* we're going to modify the metadata */
5460 buf = gst_buffer_make_writable (buf);
5462 if (G_UNLIKELY (stream->need_process))
5463 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5469 GST_BUFFER_DTS (buf) = dts;
5470 GST_BUFFER_PTS (buf) = pts;
5471 GST_BUFFER_DURATION (buf) = duration;
5472 GST_BUFFER_OFFSET (buf) = -1;
5473 GST_BUFFER_OFFSET_END (buf) = -1;
5475 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5476 gst_buffer_append_memory (buf,
5477 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5479 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5480 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5483 if (G_UNLIKELY (qtdemux->element_index)) {
5484 GstClockTime stream_time;
5487 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5489 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5490 GST_LOG_OBJECT (qtdemux,
5491 "adding association %" GST_TIME_FORMAT "-> %"
5492 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5493 gst_index_add_association (qtdemux->element_index,
5495 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5496 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5497 GST_FORMAT_BYTES, byte_position, NULL);
5502 if (stream->need_clip)
5503 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5505 if (G_UNLIKELY (buf == NULL))
5508 if (G_UNLIKELY (stream->discont)) {
5509 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5510 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5511 stream->discont = FALSE;
5513 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5517 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5518 stream->on_keyframe = FALSE;
5520 stream->on_keyframe = TRUE;
5524 GST_LOG_OBJECT (qtdemux,
5525 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5526 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5527 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5528 GST_PAD_NAME (stream->pad));
5530 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5531 GstStructure *crypto_info;
5532 QtDemuxCencSampleSetInfo *info =
5533 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5537 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5538 gst_pad_push_event (stream->pad, event);
5541 if (info->crypto_info == NULL) {
5542 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5543 gst_buffer_unref (buf);
5547 /* The end of the crypto_info array matches our n_samples position,
5548 * so count backward from there */
5549 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5550 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5551 /* steal structure from array */
5552 crypto_info = g_ptr_array_index (info->crypto_info, index);
5553 g_ptr_array_index (info->crypto_info, index) = NULL;
5554 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5555 info->crypto_info->len);
5556 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5557 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5559 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5560 index, stream->sample_index);
5564 if (stream->alignment > 1)
5565 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5567 ret = gst_pad_push (stream->pad, buf);
5569 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5570 /* mark position in stream, we'll need this to know when to send GAP event */
5571 stream->segment.position = pts + duration;
5578 static const QtDemuxRandomAccessEntry *
5579 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5580 GstClockTime pos, gboolean after)
5582 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5583 guint n_entries = stream->n_ra_entries;
5586 /* we assume the table is sorted */
5587 for (i = 0; i < n_entries; ++i) {
5588 if (entries[i].ts > pos)
5592 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5593 * probably okay to assume that the index lists the very first fragment */
5600 return &entries[i - 1];
5604 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5606 const QtDemuxRandomAccessEntry *best_entry = NULL;
5609 GST_OBJECT_LOCK (qtdemux);
5611 g_assert (qtdemux->n_streams > 0);
5613 /* first see if we can determine where to go to using mfra,
5614 * before we start clearing things */
5615 for (i = 0; i < qtdemux->n_streams; i++) {
5616 const QtDemuxRandomAccessEntry *entry;
5617 QtDemuxStream *stream;
5618 gboolean is_audio_or_video;
5620 stream = qtdemux->streams[i];
5622 if (stream->ra_entries == NULL)
5625 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5626 is_audio_or_video = TRUE;
5628 is_audio_or_video = FALSE;
5631 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5632 stream->time_position, !is_audio_or_video);
5634 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5635 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5637 stream->pending_seek = entry;
5639 /* decide position to jump to just based on audio/video tracks, not subs */
5640 if (!is_audio_or_video)
5643 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5647 /* no luck, will handle seek otherwise */
5648 if (best_entry == NULL) {
5649 GST_OBJECT_UNLOCK (qtdemux);
5653 /* ok, now we can prepare for processing as of located moof */
5654 for (i = 0; i < qtdemux->n_streams; i++) {
5655 QtDemuxStream *stream;
5657 stream = qtdemux->streams[i];
5659 g_free (stream->samples);
5660 stream->samples = NULL;
5661 stream->n_samples = 0;
5662 stream->stbl_index = -1; /* no samples have yet been parsed */
5663 stream->sample_index = -1;
5665 if (stream->protection_scheme_info) {
5666 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5667 if (stream->protection_scheme_type == FOURCC_cenc) {
5668 QtDemuxCencSampleSetInfo *info =
5669 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5670 if (info->crypto_info) {
5671 g_ptr_array_free (info->crypto_info, TRUE);
5672 info->crypto_info = NULL;
5678 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5679 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5680 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5681 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5683 qtdemux->moof_offset = best_entry->moof_offset;
5685 qtdemux_add_fragmented_samples (qtdemux);
5687 GST_OBJECT_UNLOCK (qtdemux);
5691 static GstFlowReturn
5692 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5694 GstFlowReturn ret = GST_FLOW_OK;
5695 GstBuffer *buf = NULL;
5696 QtDemuxStream *stream;
5697 GstClockTime min_time;
5699 GstClockTime dts = GST_CLOCK_TIME_NONE;
5700 GstClockTime pts = GST_CLOCK_TIME_NONE;
5701 GstClockTime duration = 0;
5702 gboolean keyframe = FALSE;
5703 guint sample_size = 0;
5709 gst_qtdemux_push_pending_newsegment (qtdemux);
5711 if (qtdemux->fragmented_seek_pending) {
5712 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5713 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
5714 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5715 qtdemux->fragmented_seek_pending = FALSE;
5717 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
5721 /* Figure out the next stream sample to output, min_time is expressed in
5722 * global time and runs over the edit list segments. */
5723 min_time = G_MAXUINT64;
5725 for (i = 0; i < qtdemux->n_streams; i++) {
5726 GstClockTime position;
5728 stream = qtdemux->streams[i];
5729 position = stream->time_position;
5731 /* position of -1 is EOS */
5732 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5733 min_time = position;
5738 if (G_UNLIKELY (index == -1)) {
5739 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5743 /* check for segment end */
5744 if (G_UNLIKELY (qtdemux->segment.stop != -1
5745 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5746 || (qtdemux->segment.rate < 0
5747 && qtdemux->segment.start > min_time))
5748 && qtdemux->streams[index]->on_keyframe)) {
5749 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5750 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5754 /* gap events for subtitle streams */
5755 for (i = 0; i < qtdemux->n_streams; i++) {
5756 stream = qtdemux->streams[i];
5757 if (stream->pad && (stream->subtype == FOURCC_subp
5758 || stream->subtype == FOURCC_text
5759 || stream->subtype == FOURCC_sbtl)) {
5760 /* send one second gap events until the stream catches up */
5761 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5762 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5763 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5764 stream->segment.position + GST_SECOND < min_time) {
5766 gst_event_new_gap (stream->segment.position, GST_SECOND);
5767 gst_pad_push_event (stream->pad, gap);
5768 stream->segment.position += GST_SECOND;
5773 stream = qtdemux->streams[index];
5774 /* fetch info for the current sample of this stream */
5775 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5776 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5779 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
5780 if (stream->new_caps) {
5781 gst_qtdemux_configure_stream (qtdemux, stream);
5782 qtdemux_do_allocation (qtdemux, stream);
5785 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5786 if (G_UNLIKELY (qtdemux->
5787 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5788 if (stream->subtype == FOURCC_vide && !keyframe) {
5789 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5794 GST_DEBUG_OBJECT (qtdemux,
5795 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5796 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5797 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5798 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5800 if (G_UNLIKELY (empty)) {
5801 /* empty segment, push a gap and move to the next one */
5802 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5803 stream->segment.position = pts + duration;
5807 /* hmm, empty sample, skip and move to next sample */
5808 if (G_UNLIKELY (sample_size <= 0))
5811 /* last pushed sample was out of boundary, goto next sample */
5812 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5815 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5818 GST_DEBUG_OBJECT (qtdemux,
5819 "size %d larger than stream max_buffer_size %d, trimming",
5820 sample_size, stream->max_buffer_size);
5822 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5825 if (qtdemux->cenc_aux_info_offset > 0) {
5828 GstBuffer *aux_info = NULL;
5830 /* pull the data stored before the sample */
5832 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5833 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5834 if (G_UNLIKELY (ret != GST_FLOW_OK))
5836 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5837 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5838 gst_byte_reader_init (&br, map.data + 8, map.size);
5839 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5840 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5841 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5842 gst_buffer_unmap (aux_info, &map);
5843 gst_buffer_unref (aux_info);
5844 ret = GST_FLOW_ERROR;
5847 gst_buffer_unmap (aux_info, &map);
5848 gst_buffer_unref (aux_info);
5851 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5854 if (stream->use_allocator) {
5855 /* if we have a per-stream allocator, use it */
5856 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5859 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5861 if (G_UNLIKELY (ret != GST_FLOW_OK))
5864 if (size != sample_size) {
5865 pts += gst_util_uint64_scale_int (GST_SECOND,
5866 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5869 gst_util_uint64_scale_int (GST_SECOND,
5870 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5873 gst_util_uint64_scale_int (GST_SECOND,
5874 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
5877 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5878 dts, pts, duration, keyframe, min_time, offset);
5880 if (size != sample_size) {
5881 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5882 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5884 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5886 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
5887 if (time_position >= segment->media_start) {
5888 /* inside the segment, update time_position, looks very familiar to
5889 * GStreamer segments, doesn't it? */
5890 stream->time_position = (time_position - segment->media_start) +
5893 /* not yet in segment, time does not yet increment. This means
5894 * that we are still prerolling keyframes to the decoder so it can
5895 * decode the first sample of the segment. */
5896 stream->time_position = segment->time;
5901 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5902 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5903 * we have no more data for the pad to push */
5904 if (ret == GST_FLOW_EOS)
5907 stream->offset_in_sample += size;
5908 if (stream->offset_in_sample >= sample_size) {
5909 gst_qtdemux_advance_sample (qtdemux, stream);
5914 gst_qtdemux_advance_sample (qtdemux, stream);
5922 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5928 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5929 /* EOS will be raised if all are EOS */
5936 gst_qtdemux_loop (GstPad * pad)
5938 GstQTDemux *qtdemux;
5942 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5944 cur_offset = qtdemux->offset;
5945 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5946 cur_offset, qt_demux_state_string (qtdemux->state));
5948 switch (qtdemux->state) {
5949 case QTDEMUX_STATE_INITIAL:
5950 case QTDEMUX_STATE_HEADER:
5951 ret = gst_qtdemux_loop_state_header (qtdemux);
5953 case QTDEMUX_STATE_MOVIE:
5954 ret = gst_qtdemux_loop_state_movie (qtdemux);
5955 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5956 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5964 /* if something went wrong, pause */
5965 if (ret != GST_FLOW_OK)
5969 gst_object_unref (qtdemux);
5975 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5976 (NULL), ("streaming stopped, invalid state"));
5977 gst_pad_pause_task (pad);
5978 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5983 const gchar *reason = gst_flow_get_name (ret);
5985 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5987 gst_pad_pause_task (pad);
5989 /* fatal errors need special actions */
5991 if (ret == GST_FLOW_EOS) {
5992 if (qtdemux->n_streams == 0) {
5993 /* we have no streams, post an error */
5994 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5996 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5999 if ((stop = qtdemux->segment.stop) == -1)
6000 stop = qtdemux->segment.duration;
6002 if (qtdemux->segment.rate >= 0) {
6003 GstMessage *message;
6006 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6007 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6008 GST_FORMAT_TIME, stop);
6009 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6010 if (qtdemux->segment_seqnum) {
6011 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6012 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6014 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6015 gst_qtdemux_push_event (qtdemux, event);
6017 GstMessage *message;
6020 /* For Reverse Playback */
6021 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6022 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6023 GST_FORMAT_TIME, qtdemux->segment.start);
6024 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6025 qtdemux->segment.start);
6026 if (qtdemux->segment_seqnum) {
6027 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6028 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6030 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6031 gst_qtdemux_push_event (qtdemux, event);
6036 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6037 event = gst_event_new_eos ();
6038 if (qtdemux->segment_seqnum)
6039 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6040 gst_qtdemux_push_event (qtdemux, event);
6042 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6043 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6044 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6053 * Returns if there are samples to be played.
6056 has_next_entry (GstQTDemux * demux)
6058 QtDemuxStream *stream;
6061 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6063 for (i = 0; i < demux->n_streams; i++) {
6064 stream = demux->streams[i];
6066 if (stream->sample_index == -1) {
6067 stream->sample_index = 0;
6068 stream->offset_in_sample = 0;
6071 if (stream->sample_index >= stream->n_samples) {
6072 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6075 GST_DEBUG_OBJECT (demux, "Found a sample");
6079 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6086 * Returns the size of the first entry at the current offset.
6087 * If -1, there are none (which means EOS or empty file).
6090 next_entry_size (GstQTDemux * demux)
6092 QtDemuxStream *stream;
6095 guint64 smalloffs = (guint64) - 1;
6096 QtDemuxSample *sample;
6098 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6101 for (i = 0; i < demux->n_streams; i++) {
6102 stream = demux->streams[i];
6104 if (stream->sample_index == -1) {
6105 stream->sample_index = 0;
6106 stream->offset_in_sample = 0;
6109 if (stream->sample_index >= stream->n_samples) {
6110 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6114 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6115 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6116 stream->sample_index);
6120 sample = &stream->samples[stream->sample_index];
6122 GST_LOG_OBJECT (demux,
6123 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6124 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6125 sample->offset, sample->size);
6127 if (((smalloffs == -1)
6128 || (sample->offset < smalloffs)) && (sample->size)) {
6130 smalloffs = sample->offset;
6134 GST_LOG_OBJECT (demux,
6135 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6136 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6141 stream = demux->streams[smallidx];
6142 sample = &stream->samples[stream->sample_index];
6144 if (sample->offset >= demux->offset) {
6145 demux->todrop = sample->offset - demux->offset;
6146 return sample->size + demux->todrop;
6149 GST_DEBUG_OBJECT (demux,
6150 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6155 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6157 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6159 gst_element_post_message (GST_ELEMENT_CAST (demux),
6160 gst_message_new_element (GST_OBJECT_CAST (demux),
6161 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6165 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6170 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6173 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6174 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6175 GST_SEEK_TYPE_NONE, -1);
6177 /* store seqnum to drop flush events, they don't need to reach downstream */
6178 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6179 res = gst_pad_push_event (demux->sinkpad, event);
6180 demux->offset_seek_seqnum = 0;
6185 /* check for seekable upstream, above and beyond a mere query */
6187 gst_qtdemux_check_seekability (GstQTDemux * demux)
6190 gboolean seekable = FALSE;
6191 gint64 start = -1, stop = -1;
6193 if (demux->upstream_size)
6196 if (demux->upstream_format_is_time)
6199 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6200 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6201 GST_DEBUG_OBJECT (demux, "seeking query failed");
6205 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6207 /* try harder to query upstream size if we didn't get it the first time */
6208 if (seekable && stop == -1) {
6209 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6210 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6213 /* if upstream doesn't know the size, it's likely that it's not seekable in
6214 * practice even if it technically may be seekable */
6215 if (seekable && (start != 0 || stop <= start)) {
6216 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6221 gst_query_unref (query);
6223 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6224 G_GUINT64_FORMAT ")", seekable, start, stop);
6225 demux->upstream_seekable = seekable;
6226 demux->upstream_size = seekable ? stop : -1;
6230 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6232 g_return_if_fail (bytes <= demux->todrop);
6234 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6235 gst_adapter_flush (demux->adapter, bytes);
6236 demux->neededbytes -= bytes;
6237 demux->offset += bytes;
6238 demux->todrop -= bytes;
6242 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6244 if (G_UNLIKELY (demux->pending_newsegment)) {
6247 gst_qtdemux_push_pending_newsegment (demux);
6248 /* clear to send tags on all streams */
6249 for (i = 0; i < demux->n_streams; i++) {
6250 QtDemuxStream *stream;
6251 stream = demux->streams[i];
6252 gst_qtdemux_push_tags (demux, stream);
6253 if (CUR_STREAM (stream)->sparse) {
6254 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6255 gst_pad_push_event (stream->pad,
6256 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6263 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6264 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6266 GstClockTime ts, dur;
6271 stream->segments[segment_index].duration - (pos -
6272 stream->segments[segment_index].time);
6273 gap = gst_event_new_gap (ts, dur);
6274 stream->time_position += dur;
6276 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6277 "segment: %" GST_PTR_FORMAT, gap);
6278 gst_pad_push_event (stream->pad, gap);
6282 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6283 QtDemuxStream * stream)
6287 /* Push any initial gap segments before proceeding to the
6289 for (i = 0; i < stream->n_segments; i++) {
6290 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6292 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6293 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6294 stream->time_position);
6296 /* Only support empty segment at the beginning followed by
6297 * one non-empty segment, this was checked when parsing the
6298 * edts atom, arriving here is unexpected */
6299 g_assert (i + 1 == stream->n_segments);
6305 static GstFlowReturn
6306 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6310 demux = GST_QTDEMUX (parent);
6312 GST_DEBUG_OBJECT (demux,
6313 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6314 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6315 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6316 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6317 gst_buffer_get_size (inbuf), demux->offset);
6319 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6320 gboolean is_gap_input = FALSE;
6323 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6325 for (i = 0; i < demux->n_streams; i++) {
6326 demux->streams[i]->discont = TRUE;
6329 /* Check if we can land back on our feet in the case where upstream is
6330 * handling the seeking/pushing of samples with gaps in between (like
6331 * in the case of trick-mode DASH for example) */
6332 if (demux->upstream_format_is_time
6333 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6335 for (i = 0; i < demux->n_streams; i++) {
6337 GST_LOG_OBJECT (demux,
6338 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6339 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6341 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6342 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6344 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6345 GST_LOG_OBJECT (demux,
6346 "Checking if sample %d from stream %d is valid (offset:%"
6347 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6348 sample->offset, sample->size);
6349 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6350 GST_LOG_OBJECT (demux,
6351 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6353 is_gap_input = TRUE;
6354 /* We can go back to standard playback mode */
6355 demux->state = QTDEMUX_STATE_MOVIE;
6356 /* Remember which sample this stream is at */
6357 demux->streams[i]->sample_index = res;
6358 /* Finally update all push-based values to the expected values */
6359 demux->neededbytes = demux->streams[i]->samples[res].size;
6360 demux->offset = GST_BUFFER_OFFSET (inbuf);
6362 demux->mdatsize - demux->offset + demux->mdatoffset;
6367 if (!is_gap_input) {
6368 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6369 /* Reset state if it's a real discont */
6370 demux->neededbytes = 16;
6371 demux->state = QTDEMUX_STATE_INITIAL;
6372 demux->offset = GST_BUFFER_OFFSET (inbuf);
6373 gst_adapter_clear (demux->adapter);
6376 /* Reverse fragmented playback, need to flush all we have before
6377 * consuming a new fragment.
6378 * The samples array have the timestamps calculated by accumulating the
6379 * durations but this won't work for reverse playback of fragments as
6380 * the timestamps of a subsequent fragment should be smaller than the
6381 * previously received one. */
6382 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6383 gst_qtdemux_process_adapter (demux, TRUE);
6384 for (i = 0; i < demux->n_streams; i++)
6385 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6389 gst_adapter_push (demux->adapter, inbuf);
6391 GST_DEBUG_OBJECT (demux,
6392 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6393 demux->neededbytes, gst_adapter_available (demux->adapter));
6395 return gst_qtdemux_process_adapter (demux, FALSE);
6398 static GstFlowReturn
6399 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6401 GstFlowReturn ret = GST_FLOW_OK;
6403 /* we never really mean to buffer that much */
6404 if (demux->neededbytes == -1) {
6408 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6409 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6411 #ifndef GST_DISABLE_GST_DEBUG
6413 guint64 discont_offset, distance_from_discont;
6415 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6416 distance_from_discont =
6417 gst_adapter_distance_from_discont (demux->adapter);
6419 GST_DEBUG_OBJECT (demux,
6420 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6421 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6422 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6423 demux->offset, discont_offset, distance_from_discont);
6427 switch (demux->state) {
6428 case QTDEMUX_STATE_INITIAL:{
6433 gst_qtdemux_check_seekability (demux);
6435 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6437 /* get fourcc/length, set neededbytes */
6438 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6440 gst_adapter_unmap (demux->adapter);
6442 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6443 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6445 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6446 (_("This file is invalid and cannot be played.")),
6447 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6448 GST_FOURCC_ARGS (fourcc)));
6449 ret = GST_FLOW_ERROR;
6452 if (fourcc == FOURCC_mdat) {
6453 gint next_entry = next_entry_size (demux);
6454 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6455 /* we have the headers, start playback */
6456 demux->state = QTDEMUX_STATE_MOVIE;
6457 demux->neededbytes = next_entry;
6458 demux->mdatleft = size;
6459 demux->mdatsize = demux->mdatleft;
6461 /* no headers yet, try to get them */
6464 guint64 old, target;
6467 old = demux->offset;
6468 target = old + size;
6470 /* try to jump over the atom with a seek */
6471 /* only bother if it seems worth doing so,
6472 * and avoids possible upstream/server problems */
6473 if (demux->upstream_seekable &&
6474 demux->upstream_size > 4 * (1 << 20)) {
6475 res = qtdemux_seek_offset (demux, target);
6477 GST_DEBUG_OBJECT (demux, "skipping seek");
6482 GST_DEBUG_OBJECT (demux, "seek success");
6483 /* remember the offset fo the first mdat so we can seek back to it
6484 * after we have the headers */
6485 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6486 demux->first_mdat = old;
6487 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6490 /* seek worked, continue reading */
6491 demux->offset = target;
6492 demux->neededbytes = 16;
6493 demux->state = QTDEMUX_STATE_INITIAL;
6495 /* seek failed, need to buffer */
6496 demux->offset = old;
6497 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6498 /* there may be multiple mdat (or alike) buffers */
6500 if (demux->mdatbuffer)
6501 bs = gst_buffer_get_size (demux->mdatbuffer);
6504 if (size + bs > 10 * (1 << 20))
6506 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6507 demux->neededbytes = size;
6508 if (!demux->mdatbuffer)
6509 demux->mdatoffset = demux->offset;
6512 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6513 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6514 (_("This file is invalid and cannot be played.")),
6515 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6516 GST_FOURCC_ARGS (fourcc), size));
6517 ret = GST_FLOW_ERROR;
6520 /* this means we already started buffering and still no moov header,
6521 * let's continue buffering everything till we get moov */
6522 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6523 || fourcc == FOURCC_moof))
6525 demux->neededbytes = size;
6526 demux->state = QTDEMUX_STATE_HEADER;
6530 case QTDEMUX_STATE_HEADER:{
6534 GST_DEBUG_OBJECT (demux, "In header");
6536 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6538 /* parse the header */
6539 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6541 if (fourcc == FOURCC_moov) {
6544 /* in usual fragmented setup we could try to scan for more
6545 * and end up at the the moov (after mdat) again */
6546 if (demux->got_moov && demux->n_streams > 0 &&
6548 || demux->last_moov_offset == demux->offset)) {
6549 GST_DEBUG_OBJECT (demux,
6550 "Skipping moov atom as we have (this) one already");
6552 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6554 if (demux->got_moov && demux->fragmented) {
6555 GST_DEBUG_OBJECT (demux,
6556 "Got a second moov, clean up data from old one");
6557 if (demux->moov_node_compressed) {
6558 g_node_destroy (demux->moov_node_compressed);
6559 if (demux->moov_node)
6560 g_free (demux->moov_node->data);
6562 demux->moov_node_compressed = NULL;
6563 if (demux->moov_node)
6564 g_node_destroy (demux->moov_node);
6565 demux->moov_node = NULL;
6567 /* prepare newsegment to send when streaming actually starts */
6568 if (!demux->pending_newsegment) {
6569 demux->pending_newsegment =
6570 gst_event_new_segment (&demux->segment);
6571 if (demux->segment_seqnum)
6572 gst_event_set_seqnum (demux->pending_newsegment,
6573 demux->segment_seqnum);
6577 demux->last_moov_offset = demux->offset;
6579 qtdemux_parse_moov (demux, data, demux->neededbytes);
6580 qtdemux_node_dump (demux, demux->moov_node);
6581 qtdemux_parse_tree (demux);
6582 qtdemux_prepare_streams (demux);
6583 if (!demux->got_moov)
6584 qtdemux_expose_streams (demux);
6587 for (n = 0; n < demux->n_streams; n++) {
6588 QtDemuxStream *stream = demux->streams[n];
6590 gst_qtdemux_configure_stream (demux, stream);
6594 demux->got_moov = TRUE;
6595 gst_qtdemux_check_send_pending_segment (demux);
6597 /* fragmented streams headers shouldn't contain edts atoms */
6598 if (!demux->fragmented) {
6599 for (n = 0; n < demux->n_streams; n++) {
6600 gst_qtdemux_stream_send_initial_gap_segments (demux,
6605 if (demux->moov_node_compressed) {
6606 g_node_destroy (demux->moov_node_compressed);
6607 g_free (demux->moov_node->data);
6609 demux->moov_node_compressed = NULL;
6610 g_node_destroy (demux->moov_node);
6611 demux->moov_node = NULL;
6612 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6614 } else if (fourcc == FOURCC_moof) {
6615 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6617 GstClockTime prev_pts;
6618 guint64 prev_offset;
6619 guint64 adapter_discont_offset, adapter_discont_dist;
6621 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6624 * The timestamp of the moof buffer is relevant as some scenarios
6625 * won't have the initial timestamp in the atoms. Whenever a new
6626 * buffer has started, we get that buffer's PTS and use it as a base
6627 * timestamp for the trun entries.
6629 * To keep track of the current buffer timestamp and starting point
6630 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6631 * from the beggining of the buffer, with the distance and demux->offset
6632 * we know if it is still the same buffer or not.
6634 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6635 prev_offset = demux->offset - dist;
6636 if (demux->fragment_start_offset == -1
6637 || prev_offset > demux->fragment_start_offset) {
6638 demux->fragment_start_offset = prev_offset;
6639 demux->fragment_start = prev_pts;
6640 GST_DEBUG_OBJECT (demux,
6641 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6642 GST_TIME_FORMAT, demux->fragment_start_offset,
6643 GST_TIME_ARGS (demux->fragment_start));
6646 /* We can't use prev_offset() here because this would require
6647 * upstream to set consistent and correct offsets on all buffers
6648 * since the discont. Nothing ever did that in the past and we
6649 * would break backwards compatibility here then.
6650 * Instead take the offset we had at the last discont and count
6651 * the bytes from there. This works with old code as there would
6652 * be no discont between moov and moof, and also works with
6653 * adaptivedemux which correctly sets offset and will set the
6654 * DISCONT flag accordingly when needed.
6656 * We also only do this for upstream TIME segments as otherwise
6657 * there are potential backwards compatibility problems with
6658 * seeking in PUSH mode and upstream providing inconsistent
6660 adapter_discont_offset =
6661 gst_adapter_offset_at_discont (demux->adapter);
6662 adapter_discont_dist =
6663 gst_adapter_distance_from_discont (demux->adapter);
6665 GST_DEBUG_OBJECT (demux,
6666 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6667 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6668 demux->offset, adapter_discont_offset, adapter_discont_dist);
6670 if (demux->upstream_format_is_time) {
6671 demux->moof_offset = adapter_discont_offset;
6672 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6673 demux->moof_offset += adapter_discont_dist;
6674 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6675 demux->moof_offset = demux->offset;
6677 demux->moof_offset = demux->offset;
6680 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6681 demux->moof_offset, NULL)) {
6682 gst_adapter_unmap (demux->adapter);
6683 ret = GST_FLOW_ERROR;
6686 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6687 if (demux->mss_mode && !demux->exposed) {
6688 if (!demux->pending_newsegment) {
6689 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6690 demux->pending_newsegment =
6691 gst_event_new_segment (&demux->segment);
6692 if (demux->segment_seqnum)
6693 gst_event_set_seqnum (demux->pending_newsegment,
6694 demux->segment_seqnum);
6696 qtdemux_expose_streams (demux);
6699 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6701 } else if (fourcc == FOURCC_ftyp) {
6702 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6703 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6704 } else if (fourcc == FOURCC_uuid) {
6705 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6706 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6707 } else if (fourcc == FOURCC_sidx) {
6708 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6709 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6713 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6717 /* [free] and [skip] are padding atoms */
6718 GST_DEBUG_OBJECT (demux,
6719 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6720 GST_FOURCC_ARGS (fourcc));
6723 GST_WARNING_OBJECT (demux,
6724 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6725 GST_FOURCC_ARGS (fourcc));
6726 /* Let's jump that one and go back to initial state */
6730 gst_adapter_unmap (demux->adapter);
6733 if (demux->mdatbuffer && demux->n_streams) {
6734 gsize remaining_data_size = 0;
6736 /* the mdat was before the header */
6737 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6738 demux->n_streams, demux->mdatbuffer);
6739 /* restore our adapter/offset view of things with upstream;
6740 * put preceding buffered data ahead of current moov data.
6741 * This should also handle evil mdat, moov, mdat cases and alike */
6742 gst_adapter_flush (demux->adapter, demux->neededbytes);
6744 /* Store any remaining data after the mdat for later usage */
6745 remaining_data_size = gst_adapter_available (demux->adapter);
6746 if (remaining_data_size > 0) {
6747 g_assert (demux->restoredata_buffer == NULL);
6748 demux->restoredata_buffer =
6749 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6750 demux->restoredata_offset = demux->offset + demux->neededbytes;
6751 GST_DEBUG_OBJECT (demux,
6752 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6753 G_GUINT64_FORMAT, remaining_data_size,
6754 demux->restoredata_offset);
6757 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6758 demux->mdatbuffer = NULL;
6759 demux->offset = demux->mdatoffset;
6760 demux->neededbytes = next_entry_size (demux);
6761 demux->state = QTDEMUX_STATE_MOVIE;
6762 demux->mdatleft = gst_adapter_available (demux->adapter);
6763 demux->mdatsize = demux->mdatleft;
6765 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6766 gst_adapter_flush (demux->adapter, demux->neededbytes);
6768 /* only go back to the mdat if there are samples to play */
6769 if (demux->got_moov && demux->first_mdat != -1
6770 && has_next_entry (demux)) {
6773 /* we need to seek back */
6774 res = qtdemux_seek_offset (demux, demux->first_mdat);
6776 demux->offset = demux->first_mdat;
6778 GST_DEBUG_OBJECT (demux, "Seek back failed");
6781 demux->offset += demux->neededbytes;
6783 demux->neededbytes = 16;
6784 demux->state = QTDEMUX_STATE_INITIAL;
6789 case QTDEMUX_STATE_BUFFER_MDAT:{
6793 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6795 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6796 gst_buffer_extract (buf, 0, fourcc, 4);
6797 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6798 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6799 if (demux->mdatbuffer)
6800 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6802 demux->mdatbuffer = buf;
6803 demux->offset += demux->neededbytes;
6804 demux->neededbytes = 16;
6805 demux->state = QTDEMUX_STATE_INITIAL;
6806 gst_qtdemux_post_progress (demux, 1, 1);
6810 case QTDEMUX_STATE_MOVIE:{
6811 QtDemuxStream *stream = NULL;
6812 QtDemuxSample *sample;
6814 GstClockTime dts, pts, duration;
6817 GST_DEBUG_OBJECT (demux,
6818 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6820 if (demux->fragmented) {
6821 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6823 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6824 /* if needed data starts within this atom,
6825 * then it should not exceed this atom */
6826 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6827 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6828 (_("This file is invalid and cannot be played.")),
6829 ("sample data crosses atom boundary"));
6830 ret = GST_FLOW_ERROR;
6833 demux->mdatleft -= demux->neededbytes;
6835 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6836 /* so we are dropping more than left in this atom */
6837 gst_qtdemux_drop_data (demux, demux->mdatleft);
6838 demux->mdatleft = 0;
6840 /* need to resume atom parsing so we do not miss any other pieces */
6841 demux->state = QTDEMUX_STATE_INITIAL;
6842 demux->neededbytes = 16;
6844 /* check if there was any stored post mdat data from previous buffers */
6845 if (demux->restoredata_buffer) {
6846 g_assert (gst_adapter_available (demux->adapter) == 0);
6848 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6849 demux->restoredata_buffer = NULL;
6850 demux->offset = demux->restoredata_offset;
6857 if (demux->todrop) {
6858 if (demux->cenc_aux_info_offset > 0) {
6862 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6863 data = gst_adapter_map (demux->adapter, demux->todrop);
6864 gst_byte_reader_init (&br, data + 8, demux->todrop);
6865 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6866 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6867 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6868 ret = GST_FLOW_ERROR;
6869 gst_adapter_unmap (demux->adapter);
6870 g_free (demux->cenc_aux_info_sizes);
6871 demux->cenc_aux_info_sizes = NULL;
6874 demux->cenc_aux_info_offset = 0;
6875 g_free (demux->cenc_aux_info_sizes);
6876 demux->cenc_aux_info_sizes = NULL;
6877 gst_adapter_unmap (demux->adapter);
6879 gst_qtdemux_drop_data (demux, demux->todrop);
6883 /* initial newsegment sent here after having added pads,
6884 * possible others in sink_event */
6885 gst_qtdemux_check_send_pending_segment (demux);
6887 /* Figure out which stream this packet belongs to */
6888 for (i = 0; i < demux->n_streams; i++) {
6889 stream = demux->streams[i];
6890 if (stream->sample_index >= stream->n_samples)
6892 GST_LOG_OBJECT (demux,
6893 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6894 " / size:%d)", i, stream->sample_index,
6895 stream->samples[stream->sample_index].offset,
6896 stream->samples[stream->sample_index].size);
6898 if (stream->samples[stream->sample_index].offset == demux->offset)
6902 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6903 goto unknown_stream;
6905 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
6907 if (stream->new_caps) {
6908 gst_qtdemux_configure_stream (demux, stream);
6911 /* Put data in a buffer, set timestamps, caps, ... */
6912 sample = &stream->samples[stream->sample_index];
6914 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6915 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6916 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
6918 dts = QTSAMPLE_DTS (stream, sample);
6919 pts = QTSAMPLE_PTS (stream, sample);
6920 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6921 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6923 /* check for segment end */
6924 if (G_UNLIKELY (demux->segment.stop != -1
6925 && demux->segment.stop <= pts && stream->on_keyframe)) {
6926 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6927 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6929 /* skip this data, stream is EOS */
6930 gst_adapter_flush (demux->adapter, demux->neededbytes);
6931 demux->offset += demux->neededbytes;
6933 /* check if all streams are eos */
6935 for (i = 0; i < demux->n_streams; i++) {
6936 if (!STREAM_IS_EOS (demux->streams[i])) {
6945 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6947 /* FIXME: should either be an assert or a plain check */
6948 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6950 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6951 dts, pts, duration, keyframe, dts, demux->offset);
6955 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6957 /* skip this data, stream is EOS */
6958 gst_adapter_flush (demux->adapter, demux->neededbytes);
6961 stream->sample_index++;
6962 stream->offset_in_sample = 0;
6964 /* update current offset and figure out size of next buffer */
6965 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6966 demux->offset, demux->neededbytes);
6967 demux->offset += demux->neededbytes;
6968 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6972 if (ret == GST_FLOW_EOS) {
6973 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6974 demux->neededbytes = -1;
6978 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6979 if (demux->fragmented) {
6980 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6981 /* there may be more to follow, only finish this atom */
6982 demux->todrop = demux->mdatleft;
6983 demux->neededbytes = demux->todrop;
6988 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
6989 goto non_ok_unlinked_flow;
6998 /* when buffering movie data, at least show user something is happening */
6999 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7000 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7001 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7002 demux->neededbytes);
7009 non_ok_unlinked_flow:
7011 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7012 gst_flow_get_name (ret));
7017 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7018 ret = GST_FLOW_ERROR;
7023 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7029 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7030 (NULL), ("qtdemuxer invalid state %d", demux->state));
7031 ret = GST_FLOW_ERROR;
7036 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7037 (NULL), ("no 'moov' atom within the first 10 MB"));
7038 ret = GST_FLOW_ERROR;
7044 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7049 query = gst_query_new_scheduling ();
7051 if (!gst_pad_peer_query (sinkpad, query)) {
7052 gst_query_unref (query);
7056 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7057 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7058 gst_query_unref (query);
7063 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7064 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7068 GST_DEBUG_OBJECT (sinkpad, "activating push");
7069 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7074 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7075 GstPadMode mode, gboolean active)
7078 GstQTDemux *demux = GST_QTDEMUX (parent);
7081 case GST_PAD_MODE_PUSH:
7082 demux->pullbased = FALSE;
7085 case GST_PAD_MODE_PULL:
7087 demux->pullbased = TRUE;
7088 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7091 res = gst_pad_stop_task (sinkpad);
7103 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7109 memset (&z, 0, sizeof (z));
7114 if ((ret = inflateInit (&z)) != Z_OK) {
7115 GST_ERROR ("inflateInit() returned %d", ret);
7119 z.next_in = z_buffer;
7120 z.avail_in = z_length;
7122 buffer = (guint8 *) g_malloc (*length);
7123 z.avail_out = *length;
7124 z.next_out = (Bytef *) buffer;
7126 ret = inflate (&z, Z_NO_FLUSH);
7127 if (ret == Z_STREAM_END) {
7129 } else if (ret != Z_OK) {
7130 GST_WARNING ("inflate() returned %d", ret);
7135 buffer = (guint8 *) g_realloc (buffer, *length);
7136 z.next_out = (Bytef *) (buffer + z.total_out);
7137 z.avail_out += 4096;
7138 } while (z.avail_in > 0);
7140 if (ret != Z_STREAM_END) {
7145 *length = z.total_out;
7152 #endif /* HAVE_ZLIB */
7155 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7159 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7161 /* counts as header data */
7162 qtdemux->header_size += length;
7164 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7165 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7167 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7174 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7175 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7176 if (dcom == NULL || cmvd == NULL)
7177 goto invalid_compression;
7179 dcom_len = QT_UINT32 (dcom->data);
7181 goto invalid_compression;
7183 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7187 guint uncompressed_length;
7188 guint compressed_length;
7192 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7194 goto invalid_compression;
7196 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7197 compressed_length = cmvd_len - 12;
7198 GST_LOG ("length = %u", uncompressed_length);
7201 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7202 compressed_length, &uncompressed_length);
7205 qtdemux->moov_node_compressed = qtdemux->moov_node;
7206 qtdemux->moov_node = g_node_new (buf);
7208 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7209 uncompressed_length);
7213 #endif /* HAVE_ZLIB */
7215 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7216 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7223 invalid_compression:
7225 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7231 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7234 while (G_UNLIKELY (buf < end)) {
7238 if (G_UNLIKELY (buf + 4 > end)) {
7239 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7242 len = QT_UINT32 (buf);
7243 if (G_UNLIKELY (len == 0)) {
7244 GST_LOG_OBJECT (qtdemux, "empty container");
7247 if (G_UNLIKELY (len < 8)) {
7248 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7251 if (G_UNLIKELY (len > (end - buf))) {
7252 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7253 (gint) (end - buf));
7257 child = g_node_new ((guint8 *) buf);
7258 g_node_append (node, child);
7259 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7260 qtdemux_parse_node (qtdemux, child, buf, len);
7268 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7271 int len = QT_UINT32 (xdxt->data);
7272 guint8 *buf = xdxt->data;
7273 guint8 *end = buf + len;
7276 /* skip size and type */
7284 size = QT_UINT32 (buf);
7285 type = QT_FOURCC (buf + 4);
7287 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7289 if (buf + size > end || size <= 0)
7295 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7296 GST_FOURCC_ARGS (type));
7300 buffer = gst_buffer_new_and_alloc (size);
7301 gst_buffer_fill (buffer, 0, buf, size);
7302 stream->buffers = g_slist_append (stream->buffers, buffer);
7303 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7306 buffer = gst_buffer_new_and_alloc (size);
7307 gst_buffer_fill (buffer, 0, buf, size);
7308 stream->buffers = g_slist_append (stream->buffers, buffer);
7309 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7312 buffer = gst_buffer_new_and_alloc (size);
7313 gst_buffer_fill (buffer, 0, buf, size);
7314 stream->buffers = g_slist_append (stream->buffers, buffer);
7315 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7318 GST_WARNING_OBJECT (qtdemux,
7319 "unknown theora cookie %" GST_FOURCC_FORMAT,
7320 GST_FOURCC_ARGS (type));
7329 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7333 guint32 node_length = 0;
7334 const QtNodeType *type;
7337 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7339 if (G_UNLIKELY (length < 8))
7340 goto not_enough_data;
7342 node_length = QT_UINT32 (buffer);
7343 fourcc = QT_FOURCC (buffer + 4);
7345 /* ignore empty nodes */
7346 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7349 type = qtdemux_type_get (fourcc);
7351 end = buffer + length;
7353 GST_LOG_OBJECT (qtdemux,
7354 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7355 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7357 if (node_length > length)
7358 goto broken_atom_size;
7360 if (type->flags & QT_FLAG_CONTAINER) {
7361 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7366 if (node_length < 20) {
7367 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7370 GST_DEBUG_OBJECT (qtdemux,
7371 "parsing stsd (sample table, sample description) atom");
7372 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7373 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7384 /* also read alac (or whatever) in stead of mp4a in the following,
7385 * since a similar layout is used in other cases as well */
7386 if (fourcc == FOURCC_mp4a)
7388 else if (fourcc == FOURCC_fLaC)
7393 /* There are two things we might encounter here: a true mp4a atom, and
7394 an mp4a entry in an stsd atom. The latter is what we're interested
7395 in, and it looks like an atom, but isn't really one. The true mp4a
7396 atom is short, so we detect it based on length here. */
7397 if (length < min_size) {
7398 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7399 GST_FOURCC_ARGS (fourcc));
7403 /* 'version' here is the sound sample description version. Types 0 and
7404 1 are documented in the QTFF reference, but type 2 is not: it's
7405 described in Apple header files instead (struct SoundDescriptionV2
7407 version = QT_UINT16 (buffer + 16);
7409 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7410 GST_FOURCC_ARGS (fourcc), version);
7412 /* parse any esds descriptors */
7424 GST_WARNING_OBJECT (qtdemux,
7425 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7426 GST_FOURCC_ARGS (fourcc), version);
7431 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7457 /* codec_data is contained inside these atoms, which all have
7458 * the same format. */
7459 /* video sample description size is 86 bytes without extension.
7460 * node_length have to be bigger than 86 bytes because video sample
7461 * description can include extenstions such as esds, fiel, glbl, etc. */
7462 if (node_length < 86) {
7463 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7464 " sample description length too short (%u < 86)",
7465 GST_FOURCC_ARGS (fourcc), node_length);
7469 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7470 GST_FOURCC_ARGS (fourcc));
7472 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7474 * revision level (2 bytes) : must be set to 0. */
7475 version = QT_UINT32 (buffer + 16);
7476 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7478 /* compressor name : PASCAL string and informative purposes
7479 * first byte : the number of bytes to be displayed.
7480 * it has to be less than 32 because it is reserved
7481 * space of 32 bytes total including itself. */
7482 str_len = QT_UINT8 (buffer + 50);
7484 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7485 (char *) buffer + 51);
7487 GST_WARNING_OBJECT (qtdemux,
7488 "compressorname length too big (%u > 31)", str_len);
7490 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7492 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7497 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7498 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7503 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7504 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7505 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7514 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7515 GST_FOURCC_ARGS (fourcc));
7519 version = QT_UINT32 (buffer + 12);
7520 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7527 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7532 if (length < offset) {
7533 GST_WARNING_OBJECT (qtdemux,
7534 "skipping too small %" GST_FOURCC_FORMAT " box",
7535 GST_FOURCC_ARGS (fourcc));
7538 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7544 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7549 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7554 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7558 if (!strcmp (type->name, "unknown"))
7559 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7563 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7564 GST_FOURCC_ARGS (fourcc));
7570 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7571 (_("This file is corrupt and cannot be played.")),
7572 ("Not enough data for an atom header, got only %u bytes", length));
7577 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7578 (_("This file is corrupt and cannot be played.")),
7579 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7580 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7587 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7591 guint32 child_fourcc;
7593 for (child = g_node_first_child (node); child;
7594 child = g_node_next_sibling (child)) {
7595 buffer = (guint8 *) child->data;
7597 child_fourcc = QT_FOURCC (buffer + 4);
7599 if (G_UNLIKELY (child_fourcc == fourcc)) {
7607 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7608 GstByteReader * parser)
7612 guint32 child_fourcc, child_len;
7614 for (child = g_node_first_child (node); child;
7615 child = g_node_next_sibling (child)) {
7616 buffer = (guint8 *) child->data;
7618 child_len = QT_UINT32 (buffer);
7619 child_fourcc = QT_FOURCC (buffer + 4);
7621 if (G_UNLIKELY (child_fourcc == fourcc)) {
7622 if (G_UNLIKELY (child_len < (4 + 4)))
7624 /* FIXME: must verify if atom length < parent atom length */
7625 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7633 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7635 return g_node_nth_child (node, index);
7639 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7640 GstByteReader * parser)
7644 guint32 child_fourcc, child_len;
7646 for (child = g_node_next_sibling (node); child;
7647 child = g_node_next_sibling (child)) {
7648 buffer = (guint8 *) child->data;
7650 child_fourcc = QT_FOURCC (buffer + 4);
7652 if (child_fourcc == fourcc) {
7654 child_len = QT_UINT32 (buffer);
7655 if (G_UNLIKELY (child_len < (4 + 4)))
7657 /* FIXME: must verify if atom length < parent atom length */
7658 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7667 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7669 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7673 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7675 /* FIXME: This can only reliably work if demuxers have a
7676 * separate streaming thread per srcpad. This should be
7677 * done in a demuxer base class, which integrates parts
7680 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7685 query = gst_query_new_allocation (stream->caps, FALSE);
7687 if (!gst_pad_peer_query (stream->pad, query)) {
7688 /* not a problem, just debug a little */
7689 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7692 if (stream->allocator)
7693 gst_object_unref (stream->allocator);
7695 if (gst_query_get_n_allocation_params (query) > 0) {
7696 /* try the allocator */
7697 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7699 stream->use_allocator = TRUE;
7701 stream->allocator = NULL;
7702 gst_allocation_params_init (&stream->params);
7703 stream->use_allocator = FALSE;
7705 gst_query_unref (query);
7710 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7711 QtDemuxStream * stream)
7714 const gchar *selected_system;
7716 g_return_val_if_fail (qtdemux != NULL, FALSE);
7717 g_return_val_if_fail (stream != NULL, FALSE);
7718 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
7721 if (stream->protection_scheme_type != FOURCC_cenc) {
7722 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7725 if (qtdemux->protection_system_ids == NULL) {
7726 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7727 "cenc protection system information has been found");
7730 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7731 selected_system = gst_protection_select_system ((const gchar **)
7732 qtdemux->protection_system_ids->pdata);
7733 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7734 qtdemux->protection_system_ids->len - 1);
7735 if (!selected_system) {
7736 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7737 "suitable decryptor element has been found");
7741 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
7742 if (!gst_structure_has_name (s, "application/x-cenc")) {
7743 gst_structure_set (s,
7744 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7745 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7747 gst_structure_set_name (s, "application/x-cenc");
7753 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7755 if (stream->subtype == FOURCC_vide) {
7756 /* fps is calculated base on the duration of the average framerate since
7757 * qt does not have a fixed framerate. */
7758 gboolean fps_available = TRUE;
7760 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7762 CUR_STREAM (stream)->fps_n = 0;
7763 CUR_STREAM (stream)->fps_d = 1;
7765 if (stream->duration == 0 || stream->n_samples < 2) {
7766 CUR_STREAM (stream)->fps_n = stream->timescale;
7767 CUR_STREAM (stream)->fps_d = 1;
7768 fps_available = FALSE;
7770 GstClockTime avg_duration;
7774 /* duration and n_samples can be updated for fragmented format
7775 * so, framerate of fragmented format is calculated using data in a moof */
7776 if (qtdemux->fragmented && stream->n_samples_moof > 0
7777 && stream->duration_moof > 0) {
7778 n_samples = stream->n_samples_moof;
7779 duration = stream->duration_moof;
7781 n_samples = stream->n_samples;
7782 duration = stream->duration;
7785 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7786 /* stream->duration is guint64, timescale, n_samples are guint32 */
7788 gst_util_uint64_scale_round (duration -
7789 stream->first_duration, GST_SECOND,
7790 (guint64) (stream->timescale) * (n_samples - 1));
7792 GST_LOG_OBJECT (qtdemux,
7793 "Calculating avg sample duration based on stream (or moof) duration %"
7795 " minus first sample %u, leaving %d samples gives %"
7796 GST_TIME_FORMAT, duration, stream->first_duration,
7797 n_samples - 1, GST_TIME_ARGS (avg_duration));
7799 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
7800 &CUR_STREAM (stream)->fps_d);
7802 GST_DEBUG_OBJECT (qtdemux,
7803 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7804 stream->timescale, CUR_STREAM (stream)->fps_n,
7805 CUR_STREAM (stream)->fps_d);
7809 if (CUR_STREAM (stream)->caps) {
7810 CUR_STREAM (stream)->caps =
7811 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7813 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7814 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
7815 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
7817 /* set framerate if calculated framerate is reliable */
7818 if (fps_available) {
7819 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7820 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
7821 CUR_STREAM (stream)->fps_d, NULL);
7824 /* calculate pixel-aspect-ratio using display width and height */
7825 GST_DEBUG_OBJECT (qtdemux,
7826 "video size %dx%d, target display size %dx%d",
7827 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
7828 stream->display_width, stream->display_height);
7829 /* qt file might have pasp atom */
7830 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7831 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
7832 CUR_STREAM (stream)->par_h);
7833 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7834 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7835 CUR_STREAM (stream)->par_h, NULL);
7836 } else if (stream->display_width > 0 && stream->display_height > 0
7837 && CUR_STREAM (stream)->width > 0
7838 && CUR_STREAM (stream)->height > 0) {
7841 /* calculate the pixel aspect ratio using the display and pixel w/h */
7842 n = stream->display_width * CUR_STREAM (stream)->height;
7843 d = stream->display_height * CUR_STREAM (stream)->width;
7846 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7847 CUR_STREAM (stream)->par_w = n;
7848 CUR_STREAM (stream)->par_h = d;
7849 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7850 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7851 CUR_STREAM (stream)->par_h, NULL);
7854 if (CUR_STREAM (stream)->interlace_mode > 0) {
7855 if (CUR_STREAM (stream)->interlace_mode == 1) {
7856 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7857 G_TYPE_STRING, "progressive", NULL);
7858 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
7859 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7860 G_TYPE_STRING, "interleaved", NULL);
7861 if (CUR_STREAM (stream)->field_order == 9) {
7862 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7863 G_TYPE_STRING, "top-field-first", NULL);
7864 } else if (CUR_STREAM (stream)->field_order == 14) {
7865 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7866 G_TYPE_STRING, "bottom-field-first", NULL);
7871 /* Create incomplete colorimetry here if needed */
7872 if (CUR_STREAM (stream)->colorimetry.range ||
7873 CUR_STREAM (stream)->colorimetry.matrix ||
7874 CUR_STREAM (stream)->colorimetry.transfer
7875 || CUR_STREAM (stream)->colorimetry.primaries) {
7876 gchar *colorimetry =
7877 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
7878 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
7879 G_TYPE_STRING, colorimetry, NULL);
7880 g_free (colorimetry);
7883 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7884 guint par_w = 1, par_h = 1;
7886 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7887 par_w = CUR_STREAM (stream)->par_w;
7888 par_h = CUR_STREAM (stream)->par_h;
7891 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7892 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
7894 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7897 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7898 "multiview-mode", G_TYPE_STRING,
7899 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7900 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7901 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7906 else if (stream->subtype == FOURCC_soun) {
7907 if (CUR_STREAM (stream)->caps) {
7908 CUR_STREAM (stream)->caps =
7909 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7910 if (CUR_STREAM (stream)->rate > 0)
7911 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7912 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
7913 if (CUR_STREAM (stream)->n_channels > 0)
7914 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7915 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
7916 if (CUR_STREAM (stream)->n_channels > 2) {
7917 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7918 * correctly; this is just the minimum we can do - assume
7919 * we don't actually have any channel positions. */
7920 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7921 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7927 GstCaps *prev_caps = NULL;
7929 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7930 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7931 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7932 gst_pad_set_active (stream->pad, TRUE);
7934 gst_pad_use_fixed_caps (stream->pad);
7936 if (stream->protected) {
7937 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7938 GST_ERROR_OBJECT (qtdemux,
7939 "Failed to configure protected stream caps.");
7944 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7945 CUR_STREAM (stream)->caps);
7946 if (stream->new_stream) {
7949 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
7952 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7955 gst_event_parse_stream_flags (event, &stream_flags);
7956 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7957 qtdemux->have_group_id = TRUE;
7959 qtdemux->have_group_id = FALSE;
7960 gst_event_unref (event);
7961 } else if (!qtdemux->have_group_id) {
7962 qtdemux->have_group_id = TRUE;
7963 qtdemux->group_id = gst_util_group_id_next ();
7966 stream->new_stream = FALSE;
7968 gst_pad_create_stream_id_printf (stream->pad,
7969 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7970 event = gst_event_new_stream_start (stream_id);
7971 if (qtdemux->have_group_id)
7972 gst_event_set_group_id (event, qtdemux->group_id);
7973 if (stream->disabled)
7974 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7975 if (CUR_STREAM (stream)->sparse) {
7976 stream_flags |= GST_STREAM_FLAG_SPARSE;
7978 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
7980 gst_event_set_stream_flags (event, stream_flags);
7981 gst_pad_push_event (stream->pad, event);
7985 prev_caps = gst_pad_get_current_caps (stream->pad);
7987 if (CUR_STREAM (stream)->caps) {
7989 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
7990 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7991 CUR_STREAM (stream)->caps);
7992 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
7994 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7997 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8001 gst_caps_unref (prev_caps);
8002 stream->new_caps = FALSE;
8008 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8009 QtDemuxStream * stream)
8011 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8014 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8015 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8016 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8017 stream->stsd_entries_length)) {
8018 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8019 (_("This file is invalid and cannot be played.")),
8020 ("New sample description id is out of bounds (%d >= %d)",
8021 stream->stsd_sample_description_id, stream->stsd_entries_length));
8023 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8024 stream->new_caps = TRUE;
8029 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8030 QtDemuxStream * stream, GstTagList * list)
8032 gboolean ret = TRUE;
8033 /* consistent default for push based mode */
8034 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8036 if (stream->subtype == FOURCC_vide) {
8037 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8040 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8043 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8044 gst_object_unref (stream->pad);
8050 qtdemux->n_video_streams++;
8051 } else if (stream->subtype == FOURCC_soun) {
8052 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8055 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8057 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8058 gst_object_unref (stream->pad);
8063 qtdemux->n_audio_streams++;
8064 } else if (stream->subtype == FOURCC_strm) {
8065 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8066 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8067 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8068 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8071 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8073 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8074 gst_object_unref (stream->pad);
8079 qtdemux->n_sub_streams++;
8080 } else if (CUR_STREAM (stream)->caps) {
8081 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8084 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8086 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8087 gst_object_unref (stream->pad);
8092 qtdemux->n_video_streams++;
8094 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8101 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8102 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8103 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8104 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8106 if (stream->stream_tags)
8107 gst_tag_list_unref (stream->stream_tags);
8108 stream->stream_tags = list;
8110 /* global tags go on each pad anyway */
8111 stream->send_global_tags = TRUE;
8112 /* send upstream GST_EVENT_PROTECTION events that were received before
8113 this source pad was created */
8114 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8115 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8119 gst_tag_list_unref (list);
8123 /* find next atom with @fourcc starting at @offset */
8124 static GstFlowReturn
8125 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8126 guint64 * length, guint32 fourcc)
8132 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8133 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8139 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8140 if (G_UNLIKELY (ret != GST_FLOW_OK))
8142 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8145 gst_buffer_unref (buf);
8148 gst_buffer_map (buf, &map, GST_MAP_READ);
8149 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8150 gst_buffer_unmap (buf, &map);
8151 gst_buffer_unref (buf);
8153 if (G_UNLIKELY (*length == 0)) {
8154 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8155 ret = GST_FLOW_ERROR;
8159 if (lfourcc == fourcc) {
8160 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8164 GST_LOG_OBJECT (qtdemux,
8165 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8166 GST_FOURCC_ARGS (fourcc), *offset);
8175 /* might simply have had last one */
8176 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8181 /* should only do something in pull mode */
8182 /* call with OBJECT lock */
8183 static GstFlowReturn
8184 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8186 guint64 length, offset;
8187 GstBuffer *buf = NULL;
8188 GstFlowReturn ret = GST_FLOW_OK;
8189 GstFlowReturn res = GST_FLOW_OK;
8192 offset = qtdemux->moof_offset;
8193 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8196 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8197 return GST_FLOW_EOS;
8200 /* best not do pull etc with lock held */
8201 GST_OBJECT_UNLOCK (qtdemux);
8203 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8204 if (ret != GST_FLOW_OK)
8207 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8208 if (G_UNLIKELY (ret != GST_FLOW_OK))
8210 gst_buffer_map (buf, &map, GST_MAP_READ);
8211 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8212 gst_buffer_unmap (buf, &map);
8213 gst_buffer_unref (buf);
8218 gst_buffer_unmap (buf, &map);
8219 gst_buffer_unref (buf);
8223 /* look for next moof */
8224 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8225 if (G_UNLIKELY (ret != GST_FLOW_OK))
8229 GST_OBJECT_LOCK (qtdemux);
8231 qtdemux->moof_offset = offset;
8237 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8239 res = GST_FLOW_ERROR;
8244 /* maybe upstream temporarily flushing */
8245 if (ret != GST_FLOW_FLUSHING) {
8246 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8249 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8250 /* resume at current position next time */
8257 /* initialise bytereaders for stbl sub-atoms */
8259 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8261 stream->stbl_index = -1; /* no samples have yet been parsed */
8262 stream->sample_index = -1;
8264 /* time-to-sample atom */
8265 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8268 /* copy atom data into a new buffer for later use */
8269 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8271 /* skip version + flags */
8272 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8273 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8275 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8277 /* make sure there's enough data */
8278 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8279 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8280 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8281 stream->n_sample_times);
8282 if (!stream->n_sample_times)
8286 /* sync sample atom */
8287 stream->stps_present = FALSE;
8288 if ((stream->stss_present =
8289 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8290 &stream->stss) ? TRUE : FALSE) == TRUE) {
8291 /* copy atom data into a new buffer for later use */
8292 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8294 /* skip version + flags */
8295 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8296 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8299 if (stream->n_sample_syncs) {
8300 /* make sure there's enough data */
8301 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8305 /* partial sync sample atom */
8306 if ((stream->stps_present =
8307 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8308 &stream->stps) ? TRUE : FALSE) == TRUE) {
8309 /* copy atom data into a new buffer for later use */
8310 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8312 /* skip version + flags */
8313 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8314 !gst_byte_reader_get_uint32_be (&stream->stps,
8315 &stream->n_sample_partial_syncs))
8318 /* if there are no entries, the stss table contains the real
8320 if (stream->n_sample_partial_syncs) {
8321 /* make sure there's enough data */
8322 if (!qt_atom_parser_has_chunks (&stream->stps,
8323 stream->n_sample_partial_syncs, 4))
8330 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8333 /* copy atom data into a new buffer for later use */
8334 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8336 /* skip version + flags */
8337 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8338 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8341 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8344 if (!stream->n_samples)
8347 /* sample-to-chunk atom */
8348 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8351 /* copy atom data into a new buffer for later use */
8352 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8354 /* skip version + flags */
8355 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8356 !gst_byte_reader_get_uint32_be (&stream->stsc,
8357 &stream->n_samples_per_chunk))
8360 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8361 stream->n_samples_per_chunk);
8363 /* make sure there's enough data */
8364 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8370 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8371 stream->co_size = sizeof (guint32);
8372 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8374 stream->co_size = sizeof (guint64);
8378 /* copy atom data into a new buffer for later use */
8379 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8381 /* skip version + flags */
8382 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8385 /* chunks_are_samples == TRUE means treat chunks as samples */
8386 stream->chunks_are_samples = stream->sample_size
8387 && !CUR_STREAM (stream)->sampled;
8388 if (stream->chunks_are_samples) {
8389 /* treat chunks as samples */
8390 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8393 /* skip number of entries */
8394 if (!gst_byte_reader_skip (&stream->stco, 4))
8397 /* make sure there are enough data in the stsz atom */
8398 if (!stream->sample_size) {
8399 /* different sizes for each sample */
8400 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8405 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8406 stream->n_samples, (guint) sizeof (QtDemuxSample),
8407 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8409 if (stream->n_samples >=
8410 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8411 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8412 "be larger than %uMB (broken file?)", stream->n_samples,
8413 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8417 g_assert (stream->samples == NULL);
8418 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8419 if (!stream->samples) {
8420 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8425 /* composition time-to-sample */
8426 if ((stream->ctts_present =
8427 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8428 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8429 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8431 /* copy atom data into a new buffer for later use */
8432 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8434 /* skip version + flags */
8435 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8436 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8437 &stream->n_composition_times))
8440 /* make sure there's enough data */
8441 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8445 /* This is optional, if missing we iterate the ctts */
8446 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8447 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8448 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8449 g_free ((gpointer) cslg.data);
8453 gint32 cslg_least = 0;
8454 guint num_entries, pos;
8457 pos = gst_byte_reader_get_pos (&stream->ctts);
8458 num_entries = stream->n_composition_times;
8460 stream->cslg_shift = 0;
8462 for (i = 0; i < num_entries; i++) {
8465 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8466 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8468 if (offset < cslg_least)
8469 cslg_least = offset;
8473 stream->cslg_shift = ABS (cslg_least);
8475 stream->cslg_shift = 0;
8477 /* reset the reader so we can generate sample table */
8478 gst_byte_reader_set_pos (&stream->ctts, pos);
8481 /* Ensure the cslg_shift value is consistent so we can use it
8482 * unconditionnally to produce TS and Segment */
8483 stream->cslg_shift = 0;
8490 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8491 (_("This file is corrupt and cannot be played.")), (NULL));
8496 gst_qtdemux_stbl_free (stream);
8497 if (!qtdemux->fragmented) {
8498 /* not quite good */
8499 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8502 /* may pick up samples elsewhere */
8508 /* collect samples from the next sample to be parsed up to sample @n for @stream
8509 * by reading the info from @stbl
8511 * This code can be executed from both the streaming thread and the seeking
8512 * thread so it takes the object lock to protect itself
8515 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8518 QtDemuxSample *samples, *first, *cur, *last;
8519 guint32 n_samples_per_chunk;
8522 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8523 GST_FOURCC_FORMAT ", pad %s",
8524 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8525 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8527 n_samples = stream->n_samples;
8530 goto out_of_samples;
8532 GST_OBJECT_LOCK (qtdemux);
8533 if (n <= stream->stbl_index)
8534 goto already_parsed;
8536 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8538 if (!stream->stsz.data) {
8539 /* so we already parsed and passed all the moov samples;
8540 * onto fragmented ones */
8541 g_assert (qtdemux->fragmented);
8545 /* pointer to the sample table */
8546 samples = stream->samples;
8548 /* starts from -1, moves to the next sample index to parse */
8549 stream->stbl_index++;
8551 /* keep track of the first and last sample to fill */
8552 first = &samples[stream->stbl_index];
8555 if (!stream->chunks_are_samples) {
8556 /* set the sample sizes */
8557 if (stream->sample_size == 0) {
8558 /* different sizes for each sample */
8559 for (cur = first; cur <= last; cur++) {
8560 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8561 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8562 (guint) (cur - samples), cur->size);
8565 /* samples have the same size */
8566 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8567 for (cur = first; cur <= last; cur++)
8568 cur->size = stream->sample_size;
8572 n_samples_per_chunk = stream->n_samples_per_chunk;
8575 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8578 if (stream->stsc_chunk_index >= stream->last_chunk
8579 || stream->stsc_chunk_index < stream->first_chunk) {
8580 stream->first_chunk =
8581 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8582 stream->samples_per_chunk =
8583 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8585 stream->stsd_sample_description_id =
8586 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
8588 /* chunk numbers are counted from 1 it seems */
8589 if (G_UNLIKELY (stream->first_chunk == 0))
8592 --stream->first_chunk;
8594 /* the last chunk of each entry is calculated by taking the first chunk
8595 * of the next entry; except if there is no next, where we fake it with
8597 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8598 stream->last_chunk = G_MAXUINT32;
8600 stream->last_chunk =
8601 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8602 if (G_UNLIKELY (stream->last_chunk == 0))
8605 --stream->last_chunk;
8608 GST_LOG_OBJECT (qtdemux,
8609 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
8610 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
8611 stream->samples_per_chunk, stream->stsd_sample_description_id);
8613 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8616 if (stream->last_chunk != G_MAXUINT32) {
8617 if (!qt_atom_parser_peek_sub (&stream->stco,
8618 stream->first_chunk * stream->co_size,
8619 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8624 stream->co_chunk = stream->stco;
8625 if (!gst_byte_reader_skip (&stream->co_chunk,
8626 stream->first_chunk * stream->co_size))
8630 stream->stsc_chunk_index = stream->first_chunk;
8633 last_chunk = stream->last_chunk;
8635 if (stream->chunks_are_samples) {
8636 cur = &samples[stream->stsc_chunk_index];
8638 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8641 stream->stsc_chunk_index = j;
8646 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8649 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8650 "%" G_GUINT64_FORMAT, j, cur->offset);
8652 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
8653 CUR_STREAM (stream)->bytes_per_frame > 0) {
8655 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
8656 CUR_STREAM (stream)->samples_per_frame *
8657 CUR_STREAM (stream)->bytes_per_frame;
8659 cur->size = stream->samples_per_chunk;
8662 GST_DEBUG_OBJECT (qtdemux,
8663 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8664 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8665 stream->stco_sample_index)), cur->size);
8667 cur->timestamp = stream->stco_sample_index;
8668 cur->duration = stream->samples_per_chunk;
8669 cur->keyframe = TRUE;
8672 stream->stco_sample_index += stream->samples_per_chunk;
8674 stream->stsc_chunk_index = j;
8676 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8677 guint32 samples_per_chunk;
8678 guint64 chunk_offset;
8680 if (!stream->stsc_sample_index
8681 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8682 &stream->chunk_offset))
8685 samples_per_chunk = stream->samples_per_chunk;
8686 chunk_offset = stream->chunk_offset;
8688 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8689 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8690 G_GUINT64_FORMAT " and size %d",
8691 (guint) (cur - samples), chunk_offset, cur->size);
8693 cur->offset = chunk_offset;
8694 chunk_offset += cur->size;
8697 if (G_UNLIKELY (cur > last)) {
8699 stream->stsc_sample_index = k + 1;
8700 stream->chunk_offset = chunk_offset;
8701 stream->stsc_chunk_index = j;
8705 stream->stsc_sample_index = 0;
8707 stream->stsc_chunk_index = j;
8709 stream->stsc_index++;
8712 if (stream->chunks_are_samples)
8716 guint32 n_sample_times;
8718 n_sample_times = stream->n_sample_times;
8721 for (i = stream->stts_index; i < n_sample_times; i++) {
8722 guint32 stts_samples;
8723 gint32 stts_duration;
8726 if (stream->stts_sample_index >= stream->stts_samples
8727 || !stream->stts_sample_index) {
8729 stream->stts_samples =
8730 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8731 stream->stts_duration =
8732 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8734 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8735 i, stream->stts_samples, stream->stts_duration);
8737 stream->stts_sample_index = 0;
8740 stts_samples = stream->stts_samples;
8741 stts_duration = stream->stts_duration;
8742 stts_time = stream->stts_time;
8744 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8745 GST_DEBUG_OBJECT (qtdemux,
8746 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8747 (guint) (cur - samples), j,
8748 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8750 cur->timestamp = stts_time;
8751 cur->duration = stts_duration;
8753 /* avoid 32-bit wrap-around,
8754 * but still mind possible 'negative' duration */
8755 stts_time += (gint64) stts_duration;
8758 if (G_UNLIKELY (cur > last)) {
8760 stream->stts_time = stts_time;
8761 stream->stts_sample_index = j + 1;
8762 if (stream->stts_sample_index >= stream->stts_samples)
8763 stream->stts_index++;
8767 stream->stts_sample_index = 0;
8768 stream->stts_time = stts_time;
8769 stream->stts_index++;
8771 /* fill up empty timestamps with the last timestamp, this can happen when
8772 * the last samples do not decode and so we don't have timestamps for them.
8773 * We however look at the last timestamp to estimate the track length so we
8774 * need something in here. */
8775 for (; cur < last; cur++) {
8776 GST_DEBUG_OBJECT (qtdemux,
8777 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8778 (guint) (cur - samples),
8779 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8780 cur->timestamp = stream->stts_time;
8786 /* sample sync, can be NULL */
8787 if (stream->stss_present == TRUE) {
8788 guint32 n_sample_syncs;
8790 n_sample_syncs = stream->n_sample_syncs;
8792 if (!n_sample_syncs) {
8793 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8794 stream->all_keyframe = TRUE;
8796 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8797 /* note that the first sample is index 1, not 0 */
8800 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8802 if (G_LIKELY (index > 0 && index <= n_samples)) {
8804 samples[index].keyframe = TRUE;
8805 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8806 /* and exit if we have enough samples */
8807 if (G_UNLIKELY (index >= n)) {
8814 stream->stss_index = i;
8817 /* stps marks partial sync frames like open GOP I-Frames */
8818 if (stream->stps_present == TRUE) {
8819 guint32 n_sample_partial_syncs;
8821 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8823 /* if there are no entries, the stss table contains the real
8825 if (n_sample_partial_syncs) {
8826 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8827 /* note that the first sample is index 1, not 0 */
8830 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8832 if (G_LIKELY (index > 0 && index <= n_samples)) {
8834 samples[index].keyframe = TRUE;
8835 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8836 /* and exit if we have enough samples */
8837 if (G_UNLIKELY (index >= n)) {
8844 stream->stps_index = i;
8848 /* no stss, all samples are keyframes */
8849 stream->all_keyframe = TRUE;
8850 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8855 /* composition time to sample */
8856 if (stream->ctts_present == TRUE) {
8857 guint32 n_composition_times;
8859 gint32 ctts_soffset;
8861 /* Fill in the pts_offsets */
8863 n_composition_times = stream->n_composition_times;
8865 for (i = stream->ctts_index; i < n_composition_times; i++) {
8866 if (stream->ctts_sample_index >= stream->ctts_count
8867 || !stream->ctts_sample_index) {
8868 stream->ctts_count =
8869 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8870 stream->ctts_soffset =
8871 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8872 stream->ctts_sample_index = 0;
8875 ctts_count = stream->ctts_count;
8876 ctts_soffset = stream->ctts_soffset;
8878 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8879 cur->pts_offset = ctts_soffset;
8882 if (G_UNLIKELY (cur > last)) {
8884 stream->ctts_sample_index = j + 1;
8888 stream->ctts_sample_index = 0;
8889 stream->ctts_index++;
8893 stream->stbl_index = n;
8894 /* if index has been completely parsed, free data that is no-longer needed */
8895 if (n + 1 == stream->n_samples) {
8896 gst_qtdemux_stbl_free (stream);
8897 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8898 if (qtdemux->pullbased) {
8899 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8900 while (n + 1 == stream->n_samples)
8901 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8905 GST_OBJECT_UNLOCK (qtdemux);
8912 GST_LOG_OBJECT (qtdemux,
8913 "Tried to parse up to sample %u but this sample has already been parsed",
8915 /* if fragmented, there may be more */
8916 if (qtdemux->fragmented && n == stream->stbl_index)
8918 GST_OBJECT_UNLOCK (qtdemux);
8924 GST_LOG_OBJECT (qtdemux,
8925 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8927 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8928 (_("This file is corrupt and cannot be played.")), (NULL));
8933 GST_OBJECT_UNLOCK (qtdemux);
8934 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8935 (_("This file is corrupt and cannot be played.")), (NULL));
8940 /* collect all segment info for @stream.
8943 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8947 /* accept edts if they contain gaps at start and there is only
8948 * one media segment */
8949 gboolean allow_pushbased_edts = TRUE;
8950 gint media_segments_count = 0;
8952 /* parse and prepare segment info from the edit list */
8953 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8954 stream->n_segments = 0;
8955 stream->segments = NULL;
8956 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8959 gint i, count, entry_size;
8962 const guint8 *buffer;
8966 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8967 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8970 buffer = elst->data;
8972 size = QT_UINT32 (buffer);
8973 /* version, flags, n_segments */
8975 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8978 version = QT_UINT8 (buffer + 8);
8979 entry_size = (version == 1) ? 20 : 12;
8981 n_segments = QT_UINT32 (buffer + 12);
8983 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
8984 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8988 /* we might allocate a bit too much, at least allocate 1 segment */
8989 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8991 /* segments always start from 0 */
8996 for (i = 0; i < n_segments; i++) {
8999 gboolean time_valid = TRUE;
9000 QtDemuxSegment *segment;
9002 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9005 media_time = QT_UINT64 (buffer + 8);
9006 duration = QT_UINT64 (buffer);
9007 if (media_time == G_MAXUINT64)
9010 media_time = QT_UINT32 (buffer + 4);
9011 duration = QT_UINT32 (buffer);
9012 if (media_time == G_MAXUINT32)
9017 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9019 segment = &stream->segments[count++];
9021 /* time and duration expressed in global timescale */
9022 segment->time = stime;
9023 /* add non scaled values so we don't cause roundoff errors */
9024 if (duration || media_start == GST_CLOCK_TIME_NONE) {
9026 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9027 segment->duration = stime - segment->time;
9029 /* zero duration does not imply media_start == media_stop
9030 * but, only specify media_start.*/
9031 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
9032 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
9033 && stime >= media_start) {
9034 segment->duration = stime - media_start;
9036 segment->duration = GST_CLOCK_TIME_NONE;
9039 segment->stop_time = stime;
9041 segment->trak_media_start = media_time;
9042 /* media_time expressed in stream timescale */
9044 segment->media_start = media_start;
9045 segment->media_stop = segment->media_start + segment->duration;
9046 media_segments_count++;
9048 segment->media_start = GST_CLOCK_TIME_NONE;
9049 segment->media_stop = GST_CLOCK_TIME_NONE;
9051 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9053 if (rate_int <= 1) {
9054 /* 0 is not allowed, some programs write 1 instead of the floating point
9056 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9060 segment->rate = rate_int / 65536.0;
9063 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9064 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9065 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9066 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9067 i, GST_TIME_ARGS (segment->time),
9068 GST_TIME_ARGS (segment->duration),
9069 GST_TIME_ARGS (segment->media_start), media_time,
9070 GST_TIME_ARGS (segment->media_stop),
9071 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9073 if (segment->stop_time > qtdemux->segment.stop) {
9074 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9075 " extends to %" GST_TIME_FORMAT
9076 " past the end of the file duration %" GST_TIME_FORMAT
9077 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9078 GST_TIME_ARGS (qtdemux->segment.stop));
9079 qtdemux->segment.stop = segment->stop_time;
9082 buffer += entry_size;
9084 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9085 stream->n_segments = count;
9086 if (media_segments_count != 1)
9087 allow_pushbased_edts = FALSE;
9091 /* push based does not handle segments, so act accordingly here,
9092 * and warn if applicable */
9093 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9094 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9095 /* remove and use default one below, we stream like it anyway */
9096 g_free (stream->segments);
9097 stream->segments = NULL;
9098 stream->n_segments = 0;
9101 /* no segments, create one to play the complete trak */
9102 if (stream->n_segments == 0) {
9103 GstClockTime stream_duration =
9104 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9106 if (stream->segments == NULL)
9107 stream->segments = g_new (QtDemuxSegment, 1);
9109 /* represent unknown our way */
9110 if (stream_duration == 0)
9111 stream_duration = GST_CLOCK_TIME_NONE;
9113 stream->segments[0].time = 0;
9114 stream->segments[0].stop_time = stream_duration;
9115 stream->segments[0].duration = stream_duration;
9116 stream->segments[0].media_start = 0;
9117 stream->segments[0].media_stop = stream_duration;
9118 stream->segments[0].rate = 1.0;
9119 stream->segments[0].trak_media_start = 0;
9121 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9122 GST_TIME_ARGS (stream_duration));
9123 stream->n_segments = 1;
9124 stream->dummy_segment = TRUE;
9126 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9132 * Parses the stsd atom of a svq3 trak looking for
9133 * the SMI and gama atoms.
9136 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9137 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9139 const guint8 *_gamma = NULL;
9140 GstBuffer *_seqh = NULL;
9141 const guint8 *stsd_data = stsd_entry_data;
9142 guint32 length = QT_UINT32 (stsd_data);
9146 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9152 version = QT_UINT16 (stsd_data);
9157 while (length > 8) {
9158 guint32 fourcc, size;
9160 size = QT_UINT32 (stsd_data);
9161 fourcc = QT_FOURCC (stsd_data + 4);
9162 data = stsd_data + 8;
9165 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9166 "svq3 atom parsing");
9175 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9176 " for gama atom, expected 12", size);
9181 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9183 if (_seqh != NULL) {
9184 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9185 " found, ignoring");
9187 seqh_size = QT_UINT32 (data + 4);
9188 if (seqh_size > 0) {
9189 _seqh = gst_buffer_new_and_alloc (seqh_size);
9190 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9197 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9198 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9202 if (size <= length) {
9208 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9211 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9212 G_GUINT16_FORMAT, version);
9223 gst_buffer_unref (_seqh);
9228 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9235 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9236 * atom that might contain a 'data' atom with the rtsp uri.
9237 * This case was reported in bug #597497, some info about
9238 * the hndl atom can be found in TN1195
9240 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9241 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9244 guint32 dref_num_entries = 0;
9245 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9246 gst_byte_reader_skip (&dref, 4) &&
9247 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9250 /* search dref entries for hndl atom */
9251 for (i = 0; i < dref_num_entries; i++) {
9252 guint32 size = 0, type;
9253 guint8 string_len = 0;
9254 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9255 qt_atom_parser_get_fourcc (&dref, &type)) {
9256 if (type == FOURCC_hndl) {
9257 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9259 /* skip data reference handle bytes and the
9260 * following pascal string and some extra 4
9261 * bytes I have no idea what are */
9262 if (!gst_byte_reader_skip (&dref, 4) ||
9263 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9264 !gst_byte_reader_skip (&dref, string_len + 4)) {
9265 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9269 /* iterate over the atoms to find the data atom */
9270 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9274 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9275 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9276 if (atom_type == FOURCC_data) {
9277 const guint8 *uri_aux = NULL;
9279 /* found the data atom that might contain the rtsp uri */
9280 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9281 "hndl atom, interpreting it as an URI");
9282 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9284 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9285 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9287 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9288 "didn't contain a rtsp address");
9290 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9295 /* skipping to the next entry */
9296 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9299 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9306 /* skip to the next entry */
9307 if (!gst_byte_reader_skip (&dref, size - 8))
9310 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9313 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9319 #define AMR_NB_ALL_MODES 0x81ff
9320 #define AMR_WB_ALL_MODES 0x83ff
9322 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9324 /* The 'damr' atom is of the form:
9326 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9327 * 32 b 8 b 16 b 8 b 8 b
9329 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9330 * represents the highest mode used in the stream (and thus the maximum
9331 * bitrate), with a couple of special cases as seen below.
9334 /* Map of frame type ID -> bitrate */
9335 static const guint nb_bitrates[] = {
9336 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9338 static const guint wb_bitrates[] = {
9339 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9345 gst_buffer_map (buf, &map, GST_MAP_READ);
9347 if (map.size != 0x11) {
9348 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9352 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9353 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9354 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9358 mode_set = QT_UINT16 (map.data + 13);
9360 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9361 max_mode = 7 + (wb ? 1 : 0);
9363 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9364 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9366 if (max_mode == -1) {
9367 GST_DEBUG ("No mode indication was found (mode set) = %x",
9372 gst_buffer_unmap (buf, &map);
9373 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9376 gst_buffer_unmap (buf, &map);
9381 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9382 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9385 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9391 if (gst_byte_reader_get_remaining (reader) < 36)
9394 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9395 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9396 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9397 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9398 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9399 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9400 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9401 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9402 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9404 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9405 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9406 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9408 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9409 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9411 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9412 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9419 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9420 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9427 * This macro will only compare value abdegh, it expects cfi to have already
9430 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9431 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9433 /* only handle the cases where the last column has standard values */
9434 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9435 const gchar *rotation_tag = NULL;
9437 /* no rotation needed */
9438 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9440 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9441 rotation_tag = "rotate-90";
9442 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9443 rotation_tag = "rotate-180";
9444 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9445 rotation_tag = "rotate-270";
9447 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9450 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9452 if (rotation_tag != NULL) {
9453 if (*taglist == NULL)
9454 *taglist = gst_tag_list_new_empty ();
9455 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9456 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9459 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9463 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9464 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9465 * Common Encryption (cenc), the function will also parse the tenc box (defined
9466 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9467 * (typically an enc[v|a|t|s] sample entry); the function will set
9468 * @original_fmt to the fourcc of the original unencrypted stream format.
9469 * Returns TRUE if successful; FALSE otherwise. */
9471 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9472 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9479 g_return_val_if_fail (qtdemux != NULL, FALSE);
9480 g_return_val_if_fail (stream != NULL, FALSE);
9481 g_return_val_if_fail (container != NULL, FALSE);
9482 g_return_val_if_fail (original_fmt != NULL, FALSE);
9484 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9485 if (G_UNLIKELY (!sinf)) {
9486 if (stream->protection_scheme_type == FOURCC_cenc) {
9487 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9488 "mandatory for Common Encryption");
9494 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9495 if (G_UNLIKELY (!frma)) {
9496 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9500 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9501 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9502 GST_FOURCC_ARGS (*original_fmt));
9504 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9506 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9509 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9510 stream->protection_scheme_version =
9511 QT_UINT32 ((const guint8 *) schm->data + 16);
9513 GST_DEBUG_OBJECT (qtdemux,
9514 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9515 "protection_scheme_version: %#010x",
9516 GST_FOURCC_ARGS (stream->protection_scheme_type),
9517 stream->protection_scheme_version);
9519 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9521 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9524 if (stream->protection_scheme_type == FOURCC_cenc) {
9525 QtDemuxCencSampleSetInfo *info;
9527 const guint8 *tenc_data;
9528 guint32 isEncrypted;
9530 const guint8 *default_kid;
9533 if (G_UNLIKELY (!stream->protection_scheme_info))
9534 stream->protection_scheme_info =
9535 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9537 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9539 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9541 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9542 "which is mandatory for Common Encryption");
9545 tenc_data = (const guint8 *) tenc->data + 12;
9546 isEncrypted = QT_UINT24 (tenc_data);
9547 iv_size = QT_UINT8 (tenc_data + 3);
9548 default_kid = (tenc_data + 4);
9549 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9550 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9551 if (info->default_properties)
9552 gst_structure_free (info->default_properties);
9553 info->default_properties =
9554 gst_structure_new ("application/x-cenc",
9555 "iv_size", G_TYPE_UINT, iv_size,
9556 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9557 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9558 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9559 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9560 gst_buffer_unref (kid_buf);
9566 * With each track we associate a new QtDemuxStream that contains all the info
9568 * traks that do not decode to something (like strm traks) will not have a pad.
9571 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9592 QtDemuxStream *stream = NULL;
9593 gboolean new_stream = FALSE;
9594 gchar *codec = NULL;
9595 const guint8 *stsd_data;
9596 const guint8 *stsd_entry_data;
9597 guint remaining_stsd_len;
9598 guint stsd_entry_count;
9600 guint16 lang_code; /* quicktime lang code or packed iso code */
9602 guint32 tkhd_flags = 0;
9603 guint8 tkhd_version = 0;
9604 guint32 w = 0, h = 0;
9606 guint value_size, stsd_len, len;
9610 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9612 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9613 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9614 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9617 /* pick between 64 or 32 bits */
9618 value_size = tkhd_version == 1 ? 8 : 4;
9619 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9620 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9623 if (!qtdemux->got_moov) {
9624 if (qtdemux_find_stream (qtdemux, track_id))
9625 goto existing_stream;
9626 stream = _create_stream ();
9627 stream->track_id = track_id;
9630 stream = qtdemux_find_stream (qtdemux, track_id);
9632 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9636 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
9638 /* flush samples data from this track from previous moov */
9639 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9640 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9642 /* need defaults for fragments */
9643 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9645 if ((tkhd_flags & 1) == 0)
9646 stream->disabled = TRUE;
9648 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9649 tkhd_version, tkhd_flags, stream->track_id);
9651 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9654 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9655 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9656 if (qtdemux->major_brand != FOURCC_mjp2 ||
9657 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9661 len = QT_UINT32 ((guint8 *) mdhd->data);
9662 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9663 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9664 if (version == 0x01000000) {
9667 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9668 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9669 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9673 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9674 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9675 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9678 if (lang_code < 0x400) {
9679 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9680 } else if (lang_code == 0x7fff) {
9681 stream->lang_id[0] = 0; /* unspecified */
9683 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9684 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9685 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9686 stream->lang_id[3] = 0;
9689 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9691 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9693 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9694 lang_code, stream->lang_id);
9696 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9699 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9700 /* chapters track reference */
9701 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9703 gsize length = GST_READ_UINT32_BE (chap->data);
9704 if (qtdemux->chapters_track_id)
9705 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9708 qtdemux->chapters_track_id =
9709 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9714 /* fragmented files may have bogus duration in moov */
9715 if (!qtdemux->fragmented &&
9716 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9717 guint64 tdur1, tdur2;
9719 /* don't overflow */
9720 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9721 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9724 * some of those trailers, nowadays, have prologue images that are
9725 * themselves video tracks as well. I haven't really found a way to
9726 * identify those yet, except for just looking at their duration. */
9727 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9728 GST_WARNING_OBJECT (qtdemux,
9729 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9730 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9731 "found, assuming preview image or something; skipping track",
9732 stream->duration, stream->timescale, qtdemux->duration,
9733 qtdemux->timescale);
9735 gst_qtdemux_stream_free (qtdemux, stream);
9740 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9743 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9744 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9746 len = QT_UINT32 ((guint8 *) hdlr->data);
9748 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9749 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9750 GST_FOURCC_ARGS (stream->subtype));
9752 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9755 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9758 /*parse svmi header if existing */
9759 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9761 len = QT_UINT32 ((guint8 *) svmi->data);
9762 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9764 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9765 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9766 guint8 frame_type, frame_layout;
9768 /* MPEG-A stereo video */
9769 if (qtdemux->major_brand == FOURCC_ss02)
9770 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9772 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9773 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9774 switch (frame_type) {
9776 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9779 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9782 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9785 /* mode 3 is primary/secondary view sequence, ie
9786 * left/right views in separate tracks. See section 7.2
9787 * of ISO/IEC 23000-11:2009 */
9788 GST_FIXME_OBJECT (qtdemux,
9789 "Implement stereo video in separate streams");
9792 if ((frame_layout & 0x1) == 0)
9793 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9795 GST_LOG_OBJECT (qtdemux,
9796 "StereoVideo: composition type: %u, is_left_first: %u",
9797 frame_type, frame_layout);
9798 stream->multiview_mode = mode;
9799 stream->multiview_flags = flags;
9803 /* parse rest of tkhd */
9804 if (stream->subtype == FOURCC_vide) {
9807 /* version 1 uses some 64-bit ints */
9808 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9811 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9814 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9815 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9818 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9819 &stream->stream_tags);
9823 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9825 stsd_data = (const guint8 *) stsd->data;
9827 /* stsd should at least have one entry */
9828 stsd_len = QT_UINT32 (stsd_data);
9829 if (stsd_len < 24) {
9830 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9831 if (stream->subtype == FOURCC_vivo) {
9833 gst_qtdemux_stream_free (qtdemux, stream);
9840 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
9841 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
9842 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9843 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
9845 stsd_entry_data = stsd_data + 16;
9846 remaining_stsd_len = stsd_len - 16;
9847 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
9848 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
9850 /* and that entry should fit within stsd */
9851 len = QT_UINT32 (stsd_entry_data);
9852 if (len > remaining_stsd_len)
9855 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
9856 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9857 GST_FOURCC_ARGS (entry->fourcc));
9858 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9860 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9861 goto error_encrypted;
9863 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9864 /* FIXME this looks wrong, there might be multiple children
9865 * with the same type */
9866 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9867 stream->protected = TRUE;
9868 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9869 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9872 if (stream->subtype == FOURCC_vide) {
9874 gint depth, palette_size, palette_count;
9875 guint32 *palette_data = NULL;
9877 entry->sampled = TRUE;
9879 stream->display_width = w >> 16;
9880 stream->display_height = h >> 16;
9883 if (len < 86) /* TODO verify */
9886 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
9887 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
9888 entry->fps_n = 0; /* this is filled in later */
9889 entry->fps_d = 0; /* this is filled in later */
9890 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
9891 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
9893 /* if color_table_id is 0, ctab atom must follow; however some files
9894 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9895 * if color table is not present we'll correct the value */
9896 if (entry->color_table_id == 0 &&
9898 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
9899 entry->color_table_id = -1;
9902 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9903 entry->width, entry->height, entry->bits_per_sample,
9904 entry->color_table_id);
9906 depth = entry->bits_per_sample;
9908 /* more than 32 bits means grayscale */
9909 gray = (depth > 32);
9910 /* low 32 bits specify the depth */
9913 /* different number of palette entries is determined by depth. */
9915 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9916 palette_count = (1 << depth);
9917 palette_size = palette_count * 4;
9919 if (entry->color_table_id) {
9920 switch (palette_count) {
9924 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9927 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9932 g_memdup (ff_qt_grayscale_palette_16, palette_size);
9934 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9939 g_memdup (ff_qt_grayscale_palette_256, palette_size);
9941 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9944 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9945 (_("The video in this file might not play correctly.")),
9946 ("unsupported palette depth %d", depth));
9950 gint i, j, start, end;
9956 start = QT_UINT32 (stsd_entry_data + offset + 70);
9957 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
9958 end = QT_UINT16 (stsd_entry_data + offset + 76);
9960 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9961 start, end, palette_count);
9968 if (len < 94 + (end - start) * 8)
9971 /* palette is always the same size */
9972 palette_data = g_malloc0 (256 * 4);
9973 palette_size = 256 * 4;
9975 for (j = 0, i = start; i <= end; j++, i++) {
9978 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
9979 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
9980 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
9981 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
9983 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9984 (g & 0xff00) | (b >> 8);
9989 gst_caps_unref (entry->caps);
9992 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
9994 if (G_UNLIKELY (!entry->caps)) {
9995 g_free (palette_data);
9996 goto unknown_stream;
10000 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10001 GST_TAG_VIDEO_CODEC, codec, NULL);
10006 if (palette_data) {
10009 if (entry->rgb8_palette)
10010 gst_memory_unref (entry->rgb8_palette);
10011 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10012 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10014 s = gst_caps_get_structure (entry->caps, 0);
10016 /* non-raw video has a palette_data property. raw video has the palette as
10017 * an extra plane that we append to the output buffers before we push
10019 if (!gst_structure_has_name (s, "video/x-raw")) {
10020 GstBuffer *palette;
10022 palette = gst_buffer_new ();
10023 gst_buffer_append_memory (palette, entry->rgb8_palette);
10024 entry->rgb8_palette = NULL;
10026 gst_caps_set_simple (entry->caps, "palette_data",
10027 GST_TYPE_BUFFER, palette, NULL);
10028 gst_buffer_unref (palette);
10030 } else if (palette_count != 0) {
10031 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10032 (NULL), ("Unsupported palette depth %d", depth));
10035 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10036 QT_UINT16 (stsd_entry_data + offset + 32));
10042 /* pick 'the' stsd child */
10043 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10044 if (!stream->protected) {
10045 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10049 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10055 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10056 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10057 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10058 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10062 const guint8 *pasp_data = (const guint8 *) pasp->data;
10063 gint len = QT_UINT32 (pasp_data);
10066 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10067 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10069 CUR_STREAM (stream)->par_w = 0;
10070 CUR_STREAM (stream)->par_h = 0;
10073 CUR_STREAM (stream)->par_w = 0;
10074 CUR_STREAM (stream)->par_h = 0;
10078 const guint8 *fiel_data = (const guint8 *) fiel->data;
10079 gint len = QT_UINT32 (fiel_data);
10082 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10083 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10088 const guint8 *colr_data = (const guint8 *) colr->data;
10089 gint len = QT_UINT32 (colr_data);
10091 if (len == 19 || len == 18) {
10092 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10094 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10095 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10096 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10097 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10098 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10100 switch (primaries) {
10102 CUR_STREAM (stream)->colorimetry.primaries =
10103 GST_VIDEO_COLOR_PRIMARIES_BT709;
10106 CUR_STREAM (stream)->colorimetry.primaries =
10107 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10110 CUR_STREAM (stream)->colorimetry.primaries =
10111 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10114 CUR_STREAM (stream)->colorimetry.primaries =
10115 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10121 switch (transfer_function) {
10123 CUR_STREAM (stream)->colorimetry.transfer =
10124 GST_VIDEO_TRANSFER_BT709;
10127 CUR_STREAM (stream)->colorimetry.transfer =
10128 GST_VIDEO_TRANSFER_SMPTE240M;
10136 CUR_STREAM (stream)->colorimetry.matrix =
10137 GST_VIDEO_COLOR_MATRIX_BT709;
10140 CUR_STREAM (stream)->colorimetry.matrix =
10141 GST_VIDEO_COLOR_MATRIX_BT601;
10144 CUR_STREAM (stream)->colorimetry.matrix =
10145 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10148 CUR_STREAM (stream)->colorimetry.matrix =
10149 GST_VIDEO_COLOR_MATRIX_BT2020;
10155 CUR_STREAM (stream)->colorimetry.range =
10156 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10157 GST_VIDEO_COLOR_RANGE_16_235;
10159 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10162 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10167 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10168 stream->stream_tags);
10175 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10176 const guint8 *avc_data = stsd_entry_data + 0x56;
10179 while (len >= 0x8) {
10182 if (QT_UINT32 (avc_data) <= len)
10183 size = QT_UINT32 (avc_data) - 0x8;
10188 /* No real data, so break out */
10191 switch (QT_FOURCC (avc_data + 0x4)) {
10194 /* parse, if found */
10197 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10199 /* First 4 bytes are the length of the atom, the next 4 bytes
10200 * are the fourcc, the next 1 byte is the version, and the
10201 * subsequent bytes are profile_tier_level structure like data. */
10202 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10203 avc_data + 8 + 1, size - 1);
10204 buf = gst_buffer_new_and_alloc (size);
10205 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10206 gst_caps_set_simple (entry->caps,
10207 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10208 gst_buffer_unref (buf);
10216 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10218 /* First 4 bytes are the length of the atom, the next 4 bytes
10219 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10220 * next 1 byte is the version, and the
10221 * subsequent bytes are sequence parameter set like data. */
10223 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10225 gst_codec_utils_h264_caps_set_level_and_profile
10226 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10228 buf = gst_buffer_new_and_alloc (size);
10229 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10230 gst_caps_set_simple (entry->caps,
10231 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10232 gst_buffer_unref (buf);
10238 guint avg_bitrate, max_bitrate;
10240 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10244 max_bitrate = QT_UINT32 (avc_data + 0xc);
10245 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10247 if (!max_bitrate && !avg_bitrate)
10250 /* Some muxers seem to swap the average and maximum bitrates
10251 * (I'm looking at you, YouTube), so we swap for sanity. */
10252 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10253 guint temp = avg_bitrate;
10255 avg_bitrate = max_bitrate;
10256 max_bitrate = temp;
10259 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10260 gst_tag_list_add (stream->stream_tags,
10261 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10262 max_bitrate, NULL);
10264 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10265 gst_tag_list_add (stream->stream_tags,
10266 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10278 avc_data += size + 8;
10287 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10288 const guint8 *hevc_data = stsd_entry_data + 0x56;
10291 while (len >= 0x8) {
10294 if (QT_UINT32 (hevc_data) <= len)
10295 size = QT_UINT32 (hevc_data) - 0x8;
10300 /* No real data, so break out */
10303 switch (QT_FOURCC (hevc_data + 0x4)) {
10306 /* parse, if found */
10309 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10311 /* First 4 bytes are the length of the atom, the next 4 bytes
10312 * are the fourcc, the next 1 byte is the version, and the
10313 * subsequent bytes are sequence parameter set like data. */
10314 gst_codec_utils_h265_caps_set_level_tier_and_profile
10315 (entry->caps, hevc_data + 8 + 1, size - 1);
10317 buf = gst_buffer_new_and_alloc (size);
10318 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10319 gst_caps_set_simple (entry->caps,
10320 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10321 gst_buffer_unref (buf);
10328 hevc_data += size + 8;
10341 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10342 GST_FOURCC_ARGS (fourcc));
10344 /* codec data might be in glbl extension atom */
10346 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10352 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10354 len = QT_UINT32 (data);
10357 buf = gst_buffer_new_and_alloc (len);
10358 gst_buffer_fill (buf, 0, data + 8, len);
10359 gst_caps_set_simple (entry->caps,
10360 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10361 gst_buffer_unref (buf);
10368 /* see annex I of the jpeg2000 spec */
10369 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10370 const guint8 *data;
10371 const gchar *colorspace = NULL;
10373 guint32 ncomp_map = 0;
10374 gint32 *comp_map = NULL;
10375 guint32 nchan_def = 0;
10376 gint32 *chan_def = NULL;
10378 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10379 /* some required atoms */
10380 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10383 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10387 /* number of components; redundant with info in codestream, but useful
10389 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10390 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10392 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10394 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10397 GST_DEBUG_OBJECT (qtdemux, "found colr");
10398 /* extract colour space info */
10399 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10400 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10402 colorspace = "sRGB";
10405 colorspace = "GRAY";
10408 colorspace = "sYUV";
10416 /* colr is required, and only values 16, 17, and 18 are specified,
10417 so error if we have no colorspace */
10420 /* extract component mapping */
10421 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10423 guint32 cmap_len = 0;
10425 cmap_len = QT_UINT32 (cmap->data);
10426 if (cmap_len >= 8) {
10427 /* normal box, subtract off header */
10429 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10430 if (cmap_len % 4 == 0) {
10431 ncomp_map = (cmap_len / 4);
10432 comp_map = g_new0 (gint32, ncomp_map);
10433 for (i = 0; i < ncomp_map; i++) {
10436 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10437 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10438 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10439 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10444 /* extract channel definitions */
10445 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10447 guint32 cdef_len = 0;
10449 cdef_len = QT_UINT32 (cdef->data);
10450 if (cdef_len >= 10) {
10451 /* normal box, subtract off header and len */
10453 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10454 if (cdef_len % 6 == 0) {
10455 nchan_def = (cdef_len / 6);
10456 chan_def = g_new0 (gint32, nchan_def);
10457 for (i = 0; i < nchan_def; i++)
10459 for (i = 0; i < nchan_def; i++) {
10460 guint16 cn, typ, asoc;
10461 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10462 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10463 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10464 if (cn < nchan_def) {
10467 chan_def[cn] = asoc;
10470 chan_def[cn] = 0; /* alpha */
10473 chan_def[cn] = -typ;
10481 gst_caps_set_simple (entry->caps,
10482 "num-components", G_TYPE_INT, ncomp, NULL);
10483 gst_caps_set_simple (entry->caps,
10484 "colorspace", G_TYPE_STRING, colorspace, NULL);
10487 GValue arr = { 0, };
10488 GValue elt = { 0, };
10490 g_value_init (&arr, GST_TYPE_ARRAY);
10491 g_value_init (&elt, G_TYPE_INT);
10492 for (i = 0; i < ncomp_map; i++) {
10493 g_value_set_int (&elt, comp_map[i]);
10494 gst_value_array_append_value (&arr, &elt);
10496 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10497 "component-map", &arr);
10498 g_value_unset (&elt);
10499 g_value_unset (&arr);
10504 GValue arr = { 0, };
10505 GValue elt = { 0, };
10507 g_value_init (&arr, GST_TYPE_ARRAY);
10508 g_value_init (&elt, G_TYPE_INT);
10509 for (i = 0; i < nchan_def; i++) {
10510 g_value_set_int (&elt, chan_def[i]);
10511 gst_value_array_append_value (&arr, &elt);
10513 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10514 "channel-definitions", &arr);
10515 g_value_unset (&elt);
10516 g_value_unset (&arr);
10520 /* some optional atoms */
10521 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10522 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10524 /* indicate possible fields in caps */
10526 data = (guint8 *) field->data + 8;
10528 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10529 (gint) * data, NULL);
10531 /* add codec_data if provided */
10536 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10537 data = prefix->data;
10538 len = QT_UINT32 (data);
10541 buf = gst_buffer_new_and_alloc (len);
10542 gst_buffer_fill (buf, 0, data + 8, len);
10543 gst_caps_set_simple (entry->caps,
10544 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10545 gst_buffer_unref (buf);
10554 GstBuffer *seqh = NULL;
10555 const guint8 *gamma_data = NULL;
10556 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
10558 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
10561 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
10562 QT_FP32 (gamma_data), NULL);
10565 /* sorry for the bad name, but we don't know what this is, other
10566 * than its own fourcc */
10567 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
10569 gst_buffer_unref (seqh);
10572 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10573 buf = gst_buffer_new_and_alloc (len);
10574 gst_buffer_fill (buf, 0, stsd_data, len);
10575 gst_caps_set_simple (entry->caps,
10576 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10577 gst_buffer_unref (buf);
10582 /* https://developer.apple.com/standards/qtff-2001.pdf,
10583 * page 92, "Video Sample Description", under table 3.1 */
10586 const gint compressor_offset =
10587 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10588 const gint min_size = compressor_offset + 32 + 2 + 2;
10591 guint16 color_table_id = 0;
10594 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10596 /* recover information on interlaced/progressive */
10597 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10601 len = QT_UINT32 (jpeg->data);
10602 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10604 if (len >= min_size) {
10605 gst_byte_reader_init (&br, jpeg->data, len);
10607 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10608 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10609 if (color_table_id != 0) {
10610 /* the spec says there can be concatenated chunks in the data, and we want
10611 * to find one called field. Walk through them. */
10612 gint offset = min_size;
10613 while (offset + 8 < len) {
10614 guint32 size = 0, tag;
10615 ok = gst_byte_reader_get_uint32_le (&br, &size);
10616 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10617 if (!ok || size < 8) {
10618 GST_WARNING_OBJECT (qtdemux,
10619 "Failed to walk optional chunk list");
10622 GST_DEBUG_OBJECT (qtdemux,
10623 "Found optional %4.4s chunk, size %u",
10624 (const char *) &tag, size);
10625 if (tag == FOURCC_fiel) {
10626 guint8 n_fields = 0, ordering = 0;
10627 gst_byte_reader_get_uint8 (&br, &n_fields);
10628 gst_byte_reader_get_uint8 (&br, &ordering);
10629 if (n_fields == 1 || n_fields == 2) {
10630 GST_DEBUG_OBJECT (qtdemux,
10631 "Found fiel tag with %u fields, ordering %u",
10632 n_fields, ordering);
10634 gst_caps_set_simple (CUR_STREAM (stream)->caps,
10635 "interlace-mode", G_TYPE_STRING, "interleaved",
10638 GST_WARNING_OBJECT (qtdemux,
10639 "Found fiel tag with invalid fields (%u)", n_fields);
10645 GST_DEBUG_OBJECT (qtdemux,
10646 "Color table ID is 0, not trying to get interlacedness");
10649 GST_WARNING_OBJECT (qtdemux,
10650 "Length of jpeg chunk is too small, not trying to get interlacedness");
10658 gst_caps_set_simple (entry->caps,
10659 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
10665 GNode *xith, *xdxt;
10667 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10668 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10672 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10676 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10677 /* collect the headers and store them in a stream list so that we can
10678 * send them out first */
10679 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10689 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10690 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10693 ovc1_data = ovc1->data;
10694 ovc1_len = QT_UINT32 (ovc1_data);
10695 if (ovc1_len <= 198) {
10696 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10699 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10700 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10701 gst_caps_set_simple (entry->caps,
10702 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10703 gst_buffer_unref (buf);
10708 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10709 const guint8 *vc1_data = stsd_entry_data + 0x56;
10715 if (QT_UINT32 (vc1_data) <= len)
10716 size = QT_UINT32 (vc1_data) - 8;
10721 /* No real data, so break out */
10724 switch (QT_FOURCC (vc1_data + 0x4)) {
10725 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10729 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10730 buf = gst_buffer_new_and_alloc (size);
10731 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10732 gst_caps_set_simple (entry->caps,
10733 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10734 gst_buffer_unref (buf);
10741 vc1_data += size + 8;
10750 GST_INFO_OBJECT (qtdemux,
10751 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10752 GST_FOURCC_ARGS (fourcc), entry->caps);
10754 } else if (stream->subtype == FOURCC_soun) {
10755 int version, samplesize;
10756 guint16 compression_id;
10757 gboolean amrwb = FALSE;
10760 /* sample description entry (16) + sound sample description v0 (20) */
10764 version = QT_UINT32 (stsd_entry_data + offset);
10765 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
10766 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
10767 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
10768 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
10770 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10771 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10772 QT_UINT32 (stsd_entry_data + offset + 4));
10773 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10774 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10775 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10776 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10777 QT_UINT16 (stsd_entry_data + offset + 14));
10778 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10780 if (compression_id == 0xfffe)
10781 entry->sampled = TRUE;
10783 /* first assume uncompressed audio */
10784 entry->bytes_per_sample = samplesize / 8;
10785 entry->samples_per_frame = entry->n_channels;
10786 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
10787 entry->samples_per_packet = entry->samples_per_frame;
10788 entry->bytes_per_packet = entry->bytes_per_sample;
10792 /* Yes, these have to be hard-coded */
10795 entry->samples_per_packet = 6;
10796 entry->bytes_per_packet = 1;
10797 entry->bytes_per_frame = 1 * entry->n_channels;
10798 entry->bytes_per_sample = 1;
10799 entry->samples_per_frame = 6 * entry->n_channels;
10804 entry->samples_per_packet = 3;
10805 entry->bytes_per_packet = 1;
10806 entry->bytes_per_frame = 1 * entry->n_channels;
10807 entry->bytes_per_sample = 1;
10808 entry->samples_per_frame = 3 * entry->n_channels;
10813 entry->samples_per_packet = 64;
10814 entry->bytes_per_packet = 34;
10815 entry->bytes_per_frame = 34 * entry->n_channels;
10816 entry->bytes_per_sample = 2;
10817 entry->samples_per_frame = 64 * entry->n_channels;
10823 entry->samples_per_packet = 1;
10824 entry->bytes_per_packet = 1;
10825 entry->bytes_per_frame = 1 * entry->n_channels;
10826 entry->bytes_per_sample = 1;
10827 entry->samples_per_frame = 1 * entry->n_channels;
10832 entry->samples_per_packet = 160;
10833 entry->bytes_per_packet = 33;
10834 entry->bytes_per_frame = 33 * entry->n_channels;
10835 entry->bytes_per_sample = 2;
10836 entry->samples_per_frame = 160 * entry->n_channels;
10843 if (version == 0x00010000) {
10844 /* sample description entry (16) + sound sample description v1 (20+16) */
10855 /* only parse extra decoding config for non-pcm audio */
10856 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
10857 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
10858 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
10859 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
10861 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10862 entry->samples_per_packet);
10863 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10864 entry->bytes_per_packet);
10865 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10866 entry->bytes_per_frame);
10867 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10868 entry->bytes_per_sample);
10870 if (!entry->sampled && entry->bytes_per_packet) {
10871 entry->samples_per_frame = (entry->bytes_per_frame /
10872 entry->bytes_per_packet) * entry->samples_per_packet;
10873 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10874 entry->samples_per_frame);
10879 } else if (version == 0x00020000) {
10886 /* sample description entry (16) + sound sample description v2 (56) */
10890 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
10891 entry->rate = qtfp.fp;
10892 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
10894 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10895 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10896 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10897 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10898 QT_UINT32 (stsd_entry_data + offset + 20));
10899 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10900 QT_UINT32 (stsd_entry_data + offset + 24));
10901 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10902 QT_UINT32 (stsd_entry_data + offset + 28));
10903 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10904 QT_UINT32 (stsd_entry_data + offset + 32));
10905 } else if (version != 0x00000) {
10906 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
10911 gst_caps_unref (entry->caps);
10913 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
10914 stsd_entry_data + 32, len - 16, &codec);
10922 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10924 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10926 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10928 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10931 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10932 gst_caps_set_simple (entry->caps,
10933 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
10940 const guint8 *owma_data;
10941 const gchar *codec_name = NULL;
10945 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10946 /* FIXME this should also be gst_riff_strf_auds,
10947 * but the latter one is actually missing bits-per-sample :( */
10952 gint32 nSamplesPerSec;
10953 gint32 nAvgBytesPerSec;
10954 gint16 nBlockAlign;
10955 gint16 wBitsPerSample;
10958 WAVEFORMATEX *wfex;
10960 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10961 owma_data = stsd_entry_data;
10962 owma_len = QT_UINT32 (owma_data);
10963 if (owma_len <= 54) {
10964 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10967 wfex = (WAVEFORMATEX *) (owma_data + 36);
10968 buf = gst_buffer_new_and_alloc (owma_len - 54);
10969 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10970 if (wfex->wFormatTag == 0x0161) {
10971 codec_name = "Windows Media Audio";
10973 } else if (wfex->wFormatTag == 0x0162) {
10974 codec_name = "Windows Media Audio 9 Pro";
10976 } else if (wfex->wFormatTag == 0x0163) {
10977 codec_name = "Windows Media Audio 9 Lossless";
10978 /* is that correct? gstffmpegcodecmap.c is missing it, but
10979 * fluendo codec seems to support it */
10983 gst_caps_set_simple (entry->caps,
10984 "codec_data", GST_TYPE_BUFFER, buf,
10985 "wmaversion", G_TYPE_INT, version,
10986 "block_align", G_TYPE_INT,
10987 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
10988 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
10989 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
10990 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
10991 gst_buffer_unref (buf);
10995 codec = g_strdup (codec_name);
11001 gint len = QT_UINT32 (stsd_entry_data) - offset;
11002 const guint8 *wfex_data = stsd_entry_data + offset;
11003 const gchar *codec_name = NULL;
11005 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11006 /* FIXME this should also be gst_riff_strf_auds,
11007 * but the latter one is actually missing bits-per-sample :( */
11012 gint32 nSamplesPerSec;
11013 gint32 nAvgBytesPerSec;
11014 gint16 nBlockAlign;
11015 gint16 wBitsPerSample;
11020 /* FIXME: unify with similar wavformatex parsing code above */
11021 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11027 if (QT_UINT32 (wfex_data) <= len)
11028 size = QT_UINT32 (wfex_data) - 8;
11033 /* No real data, so break out */
11036 switch (QT_FOURCC (wfex_data + 4)) {
11037 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11039 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11044 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11045 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11046 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11047 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11048 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11049 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11050 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11052 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11053 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11054 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11055 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11056 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11057 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11059 if (wfex.wFormatTag == 0x0161) {
11060 codec_name = "Windows Media Audio";
11062 } else if (wfex.wFormatTag == 0x0162) {
11063 codec_name = "Windows Media Audio 9 Pro";
11065 } else if (wfex.wFormatTag == 0x0163) {
11066 codec_name = "Windows Media Audio 9 Lossless";
11067 /* is that correct? gstffmpegcodecmap.c is missing it, but
11068 * fluendo codec seems to support it */
11072 gst_caps_set_simple (entry->caps,
11073 "wmaversion", G_TYPE_INT, version,
11074 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11075 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11076 "width", G_TYPE_INT, wfex.wBitsPerSample,
11077 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11079 if (size > wfex.cbSize) {
11082 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11083 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11084 size - wfex.cbSize);
11085 gst_caps_set_simple (entry->caps,
11086 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11087 gst_buffer_unref (buf);
11089 GST_WARNING_OBJECT (qtdemux, "no codec data");
11094 codec = g_strdup (codec_name);
11102 wfex_data += size + 8;
11108 const guint8 *opus_data;
11109 guint8 *channel_mapping = NULL;
11112 guint8 channel_mapping_family;
11113 guint8 stream_count;
11114 guint8 coupled_count;
11117 opus_data = stsd_entry_data;
11119 channels = GST_READ_UINT8 (opus_data + 45);
11120 rate = GST_READ_UINT32_LE (opus_data + 48);
11121 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11122 stream_count = GST_READ_UINT8 (opus_data + 55);
11123 coupled_count = GST_READ_UINT8 (opus_data + 56);
11125 if (channels > 0) {
11126 channel_mapping = g_malloc (channels * sizeof (guint8));
11127 for (i = 0; i < channels; i++)
11128 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11131 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11132 channel_mapping_family, stream_count, coupled_count,
11144 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11145 GST_TAG_AUDIO_CODEC, codec, NULL);
11149 /* some bitrate info may have ended up in caps */
11150 s = gst_caps_get_structure (entry->caps, 0);
11151 gst_structure_get_int (s, "bitrate", &bitrate);
11153 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11154 GST_TAG_BITRATE, bitrate, NULL);
11157 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11158 if (!stream->protected) {
11160 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11164 if (stream->protected && fourcc == FOURCC_mp4a) {
11165 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11169 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11177 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11179 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11181 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11185 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11186 16 bits is a byte-swapped wave-style codec identifier,
11187 and we can find a WAVE header internally to a 'wave' atom here.
11188 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11189 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11192 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11193 if (len < offset + 20) {
11194 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11196 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11197 const guint8 *data = stsd_entry_data + offset + 16;
11199 GNode *waveheadernode;
11201 wavenode = g_node_new ((guint8 *) data);
11202 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11203 const guint8 *waveheader;
11206 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11207 if (waveheadernode) {
11208 waveheader = (const guint8 *) waveheadernode->data;
11209 headerlen = QT_UINT32 (waveheader);
11211 if (headerlen > 8) {
11212 gst_riff_strf_auds *header = NULL;
11213 GstBuffer *headerbuf;
11219 headerbuf = gst_buffer_new_and_alloc (headerlen);
11220 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11222 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11223 headerbuf, &header, &extra)) {
11224 gst_caps_unref (entry->caps);
11225 /* FIXME: Need to do something with the channel reorder map */
11227 gst_riff_create_audio_caps (header->format, NULL, header,
11228 extra, NULL, NULL, NULL);
11231 gst_buffer_unref (extra);
11236 GST_DEBUG ("Didn't find waveheadernode for this codec");
11238 g_node_destroy (wavenode);
11241 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11242 stream->stream_tags);
11246 /* FIXME: what is in the chunk? */
11249 gint len = QT_UINT32 (stsd_data);
11251 /* seems to be always = 116 = 0x74 */
11257 gint len = QT_UINT32 (stsd_entry_data);
11260 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11262 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11263 gst_caps_set_simple (entry->caps,
11264 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11265 gst_buffer_unref (buf);
11267 gst_caps_set_simple (entry->caps,
11268 "samplesize", G_TYPE_INT, samplesize, NULL);
11273 GNode *alac, *wave = NULL;
11275 /* apparently, m4a has this atom appended directly in the stsd entry,
11276 * while mov has it in a wave atom */
11277 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11279 /* alac now refers to stsd entry atom */
11280 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11282 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11284 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11287 const guint8 *alac_data = alac->data;
11288 gint len = QT_UINT32 (alac->data);
11292 GST_DEBUG_OBJECT (qtdemux,
11293 "discarding alac atom with unexpected len %d", len);
11295 /* codec-data contains alac atom size and prefix,
11296 * ffmpeg likes it that way, not quite gst-ish though ...*/
11297 buf = gst_buffer_new_and_alloc (len);
11298 gst_buffer_fill (buf, 0, alac->data, len);
11299 gst_caps_set_simple (entry->caps,
11300 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11301 gst_buffer_unref (buf);
11303 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11304 entry->n_channels = QT_UINT8 (alac_data + 21);
11305 entry->rate = QT_UINT32 (alac_data + 32);
11308 gst_caps_set_simple (entry->caps,
11309 "samplesize", G_TYPE_INT, samplesize, NULL);
11314 /* The codingname of the sample entry is 'fLaC' */
11315 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11318 /* The 'dfLa' box is added to the sample entry to convey
11319 initializing information for the decoder. */
11320 const GNode *dfla =
11321 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11324 const guint32 len = QT_UINT32 (dfla->data);
11326 /* Must contain at least dfLa box header (12),
11327 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11329 GST_DEBUG_OBJECT (qtdemux,
11330 "discarding dfla atom with unexpected len %d", len);
11332 /* skip dfLa header to get the METADATA_BLOCKs */
11333 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11334 const guint32 metadata_blocks_len = len - 12;
11336 gchar *stream_marker = g_strdup ("fLaC");
11337 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11338 strlen (stream_marker));
11341 guint32 remainder = 0;
11342 guint32 block_size = 0;
11343 gboolean is_last = FALSE;
11345 GValue array = G_VALUE_INIT;
11346 GValue value = G_VALUE_INIT;
11348 g_value_init (&array, GST_TYPE_ARRAY);
11349 g_value_init (&value, GST_TYPE_BUFFER);
11351 gst_value_set_buffer (&value, block);
11352 gst_value_array_append_value (&array, &value);
11353 g_value_reset (&value);
11355 gst_buffer_unref (block);
11357 /* check there's at least one METADATA_BLOCK_HEADER's worth
11358 * of data, and we haven't already finished parsing */
11359 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11360 remainder = metadata_blocks_len - index;
11362 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11364 (metadata_blocks[index + 1] << 16) +
11365 (metadata_blocks[index + 2] << 8) +
11366 metadata_blocks[index + 3];
11368 /* be careful not to read off end of box */
11369 if (block_size > remainder) {
11373 is_last = metadata_blocks[index] >> 7;
11375 block = gst_buffer_new_and_alloc (block_size);
11377 gst_buffer_fill (block, 0, &metadata_blocks[index],
11380 gst_value_set_buffer (&value, block);
11381 gst_value_array_append_value (&array, &value);
11382 g_value_reset (&value);
11384 gst_buffer_unref (block);
11386 index += block_size;
11389 /* only append the metadata if we successfully read all of it */
11391 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11392 (stream)->caps, 0), "streamheader", &array);
11394 GST_WARNING_OBJECT (qtdemux,
11395 "discarding all METADATA_BLOCKs due to invalid "
11396 "block_size %d at idx %d, rem %d", block_size, index,
11400 g_value_unset (&value);
11401 g_value_unset (&array);
11403 /* The sample rate obtained from the stsd may not be accurate
11404 * since it cannot represent rates greater than 65535Hz, so
11405 * override that value with the sample rate from the
11406 * METADATA_BLOCK_STREAMINFO block */
11407 CUR_STREAM (stream)->rate =
11408 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11419 gint len = QT_UINT32 (stsd_entry_data);
11422 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11425 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11427 /* If we have enough data, let's try to get the 'damr' atom. See
11428 * the 3GPP container spec (26.244) for more details. */
11429 if ((len - 0x34) > 8 &&
11430 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11431 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11432 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11435 gst_caps_set_simple (entry->caps,
11436 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11437 gst_buffer_unref (buf);
11443 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11444 gint len = QT_UINT32 (stsd_entry_data);
11447 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11449 if (sound_version == 1) {
11450 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11451 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11452 guint8 codec_data[2];
11454 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11456 gint sample_rate_index =
11457 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11459 /* build AAC codec data */
11460 codec_data[0] = profile << 3;
11461 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11462 codec_data[1] = (sample_rate_index & 0x01) << 7;
11463 codec_data[1] |= (channels & 0xF) << 3;
11465 buf = gst_buffer_new_and_alloc (2);
11466 gst_buffer_fill (buf, 0, codec_data, 2);
11467 gst_caps_set_simple (entry->caps,
11468 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11469 gst_buffer_unref (buf);
11475 GST_INFO_OBJECT (qtdemux,
11476 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11480 GST_INFO_OBJECT (qtdemux,
11481 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11482 GST_FOURCC_ARGS (fourcc), entry->caps);
11484 } else if (stream->subtype == FOURCC_strm) {
11485 if (fourcc == FOURCC_rtsp) {
11486 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11488 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11489 GST_FOURCC_ARGS (fourcc));
11490 goto unknown_stream;
11492 entry->sampled = TRUE;
11493 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11494 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11496 entry->sampled = TRUE;
11497 entry->sparse = TRUE;
11500 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11503 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11504 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11509 /* hunt for sort-of codec data */
11513 GNode *mp4s = NULL;
11514 GNode *esds = NULL;
11516 /* look for palette in a stsd->mp4s->esds sub-atom */
11517 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11519 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11520 if (esds == NULL) {
11522 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11526 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11527 stream->stream_tags);
11531 GST_INFO_OBJECT (qtdemux,
11532 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11535 GST_INFO_OBJECT (qtdemux,
11536 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11537 GST_FOURCC_ARGS (fourcc), entry->caps);
11539 /* everything in 1 sample */
11540 entry->sampled = TRUE;
11543 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11546 if (entry->caps == NULL)
11547 goto unknown_stream;
11550 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11551 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11557 /* promote to sampled format */
11558 if (entry->fourcc == FOURCC_samr) {
11559 /* force mono 8000 Hz for AMR */
11560 entry->sampled = TRUE;
11561 entry->n_channels = 1;
11562 entry->rate = 8000;
11563 } else if (entry->fourcc == FOURCC_sawb) {
11564 /* force mono 16000 Hz for AMR-WB */
11565 entry->sampled = TRUE;
11566 entry->n_channels = 1;
11567 entry->rate = 16000;
11568 } else if (entry->fourcc == FOURCC_mp4a) {
11569 entry->sampled = TRUE;
11573 stsd_entry_data += len;
11574 remaining_stsd_len -= len;
11578 /* collect sample information */
11579 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11580 goto samples_failed;
11582 if (qtdemux->fragmented) {
11585 /* need all moov samples as basis; probably not many if any at all */
11586 /* prevent moof parsing taking of at this time */
11587 offset = qtdemux->moof_offset;
11588 qtdemux->moof_offset = 0;
11589 if (stream->n_samples &&
11590 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11591 qtdemux->moof_offset = offset;
11592 goto samples_failed;
11594 qtdemux->moof_offset = 0;
11595 /* movie duration more reliable in this case (e.g. mehd) */
11596 if (qtdemux->segment.duration &&
11597 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11599 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11602 /* configure segments */
11603 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11604 goto segments_failed;
11606 /* add some language tag, if useful */
11607 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11608 strcmp (stream->lang_id, "und")) {
11609 const gchar *lang_code;
11611 /* convert ISO 639-2 code to ISO 639-1 */
11612 lang_code = gst_tag_get_language_code (stream->lang_id);
11613 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11614 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11617 /* Check for UDTA tags */
11618 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11619 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11622 /* now we are ready to add the stream */
11623 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11624 goto too_many_streams;
11626 if (!qtdemux->got_moov) {
11627 qtdemux->streams[qtdemux->n_streams] = stream;
11628 qtdemux->n_streams++;
11629 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11637 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11639 gst_qtdemux_stream_free (qtdemux, stream);
11644 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11645 (_("This file is corrupt and cannot be played.")), (NULL));
11647 gst_qtdemux_stream_free (qtdemux, stream);
11652 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11654 gst_qtdemux_stream_free (qtdemux, stream);
11660 /* we posted an error already */
11661 /* free stbl sub-atoms */
11662 gst_qtdemux_stbl_free (stream);
11664 gst_qtdemux_stream_free (qtdemux, stream);
11669 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11672 gst_qtdemux_stream_free (qtdemux, stream);
11677 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11678 GST_FOURCC_ARGS (stream->subtype));
11680 gst_qtdemux_stream_free (qtdemux, stream);
11685 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11686 (_("This file contains too many streams. Only playing first %d"),
11687 GST_QTDEMUX_MAX_STREAMS), (NULL));
11692 /* If we can estimate the overall bitrate, and don't have information about the
11693 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11694 * the overall bitrate minus the sum of the bitrates of all other streams. This
11695 * should be useful for the common case where we have one audio and one video
11696 * stream and can estimate the bitrate of one, but not the other. */
11698 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11700 QtDemuxStream *stream = NULL;
11701 gint64 size, sys_bitrate, sum_bitrate = 0;
11702 GstClockTime duration;
11706 if (qtdemux->fragmented)
11709 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11711 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11713 GST_DEBUG_OBJECT (qtdemux,
11714 "Size in bytes of the stream not known - bailing");
11718 /* Subtract the header size */
11719 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11720 size, qtdemux->header_size);
11722 if (size < qtdemux->header_size)
11725 size = size - qtdemux->header_size;
11727 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11728 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11732 for (i = 0; i < qtdemux->n_streams; i++) {
11733 switch (qtdemux->streams[i]->subtype) {
11736 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11737 CUR_STREAM (qtdemux->streams[i])->caps);
11738 /* retrieve bitrate, prefer avg then max */
11740 if (qtdemux->streams[i]->stream_tags) {
11741 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11742 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11743 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11744 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11745 GST_TAG_NOMINAL_BITRATE, &bitrate);
11746 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11747 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11748 GST_TAG_BITRATE, &bitrate);
11749 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11752 sum_bitrate += bitrate;
11755 GST_DEBUG_OBJECT (qtdemux,
11756 ">1 stream with unknown bitrate - bailing");
11759 stream = qtdemux->streams[i];
11763 /* For other subtypes, we assume no significant impact on bitrate */
11769 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11773 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11775 if (sys_bitrate < sum_bitrate) {
11776 /* This can happen, since sum_bitrate might be derived from maximum
11777 * bitrates and not average bitrates */
11778 GST_DEBUG_OBJECT (qtdemux,
11779 "System bitrate less than sum bitrate - bailing");
11783 bitrate = sys_bitrate - sum_bitrate;
11784 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11785 ", Stream bitrate = %u", sys_bitrate, bitrate);
11787 if (!stream->stream_tags)
11788 stream->stream_tags = gst_tag_list_new_empty ();
11790 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11792 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11793 GST_TAG_BITRATE, bitrate, NULL);
11796 static GstFlowReturn
11797 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11800 GstFlowReturn ret = GST_FLOW_OK;
11802 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11804 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11805 QtDemuxStream *stream = qtdemux->streams[i];
11806 guint32 sample_num = 0;
11808 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11809 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11811 if (qtdemux->fragmented) {
11812 /* need all moov samples first */
11813 GST_OBJECT_LOCK (qtdemux);
11814 while (stream->n_samples == 0)
11815 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11817 GST_OBJECT_UNLOCK (qtdemux);
11819 /* discard any stray moof */
11820 qtdemux->moof_offset = 0;
11823 /* prepare braking */
11824 if (ret != GST_FLOW_ERROR)
11827 /* in pull mode, we should have parsed some sample info by now;
11828 * and quite some code will not handle no samples.
11829 * in push mode, we'll just have to deal with it */
11830 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11831 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11832 gst_qtdemux_remove_stream (qtdemux, i);
11837 /* parse the initial sample for use in setting the frame rate cap */
11838 while (sample_num == 0 && sample_num < stream->n_samples) {
11839 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11843 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11844 stream->first_duration = stream->samples[0].duration;
11845 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11846 stream->track_id, stream->first_duration);
11853 static GstFlowReturn
11854 qtdemux_expose_streams (GstQTDemux * qtdemux)
11857 GSList *oldpads = NULL;
11860 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11862 for (i = 0; i < qtdemux->n_streams; i++) {
11863 QtDemuxStream *stream = qtdemux->streams[i];
11864 GstPad *oldpad = stream->pad;
11867 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11868 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11870 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11871 stream->track_id == qtdemux->chapters_track_id) {
11872 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11873 so that it doesn't look like a subtitle track */
11874 gst_qtdemux_remove_stream (qtdemux, i);
11879 /* now we have all info and can expose */
11880 list = stream->stream_tags;
11881 stream->stream_tags = NULL;
11883 oldpads = g_slist_prepend (oldpads, oldpad);
11884 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11885 return GST_FLOW_ERROR;
11888 gst_qtdemux_guess_bitrate (qtdemux);
11890 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11892 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11893 GstPad *oldpad = iter->data;
11896 event = gst_event_new_eos ();
11897 if (qtdemux->segment_seqnum)
11898 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11900 gst_pad_push_event (oldpad, event);
11901 gst_pad_set_active (oldpad, FALSE);
11902 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11903 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11904 gst_object_unref (oldpad);
11907 /* check if we should post a redirect in case there is a single trak
11908 * and it is a redirecting trak */
11909 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11912 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11913 "an external content");
11914 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11915 gst_structure_new ("redirect",
11916 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11918 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11919 qtdemux->posted_redirect = TRUE;
11922 for (i = 0; i < qtdemux->n_streams; i++) {
11923 QtDemuxStream *stream = qtdemux->streams[i];
11925 qtdemux_do_allocation (qtdemux, stream);
11928 qtdemux->exposed = TRUE;
11929 return GST_FLOW_OK;
11932 /* check if major or compatible brand is 3GP */
11933 static inline gboolean
11934 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11937 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11939 } else if (qtdemux->comp_brands != NULL) {
11943 gboolean res = FALSE;
11945 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11948 while (size >= 4) {
11949 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11954 gst_buffer_unmap (qtdemux->comp_brands, &map);
11961 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11962 static inline gboolean
11963 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11965 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11966 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11967 || fourcc == FOURCC_albm;
11971 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11972 const char *tag, const char *dummy, GNode * node)
11974 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11978 gdouble longitude, latitude, altitude;
11981 len = QT_UINT32 (node->data);
11988 /* TODO: language code skipped */
11990 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11993 /* do not alarm in trivial case, but bail out otherwise */
11994 if (*(data + offset) != 0) {
11995 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11999 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12000 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12001 offset += strlen (name);
12005 if (len < offset + 2 + 4 + 4 + 4)
12008 /* +1 +1 = skip null-terminator and location role byte */
12010 /* table in spec says unsigned, semantics say negative has meaning ... */
12011 longitude = QT_SFP32 (data + offset);
12014 latitude = QT_SFP32 (data + offset);
12017 altitude = QT_SFP32 (data + offset);
12019 /* one invalid means all are invalid */
12020 if (longitude >= -180.0 && longitude <= 180.0 &&
12021 latitude >= -90.0 && latitude <= 90.0) {
12022 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12023 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12024 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12025 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12028 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12035 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12042 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12043 const char *tag, const char *dummy, GNode * node)
12049 len = QT_UINT32 (node->data);
12053 y = QT_UINT16 ((guint8 *) node->data + 12);
12055 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12058 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12060 date = g_date_new_dmy (1, 1, y);
12061 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12062 g_date_free (date);
12066 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12067 const char *tag, const char *dummy, GNode * node)
12070 char *tag_str = NULL;
12075 len = QT_UINT32 (node->data);
12080 entity = (guint8 *) node->data + offset;
12081 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12082 GST_DEBUG_OBJECT (qtdemux,
12083 "classification info: %c%c%c%c invalid classification entity",
12084 entity[0], entity[1], entity[2], entity[3]);
12089 table = QT_UINT16 ((guint8 *) node->data + offset);
12091 /* Language code skipped */
12095 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12096 * XXXX: classification entity, fixed length 4 chars.
12097 * Y[YYYY]: classification table, max 5 chars.
12099 tag_str = g_strdup_printf ("----://%u/%s",
12100 table, (char *) node->data + offset);
12102 /* memcpy To be sure we're preserving byte order */
12103 memcpy (tag_str, entity, 4);
12104 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12106 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12115 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12121 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12122 const char *tag, const char *dummy, GNode * node)
12124 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12130 gboolean ret = TRUE;
12131 const gchar *charset = NULL;
12133 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12135 len = QT_UINT32 (data->data);
12136 type = QT_UINT32 ((guint8 *) data->data + 8);
12137 if (type == 0x00000001 && len > 16) {
12138 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12141 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12142 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12145 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12149 len = QT_UINT32 (node->data);
12150 type = QT_UINT32 ((guint8 *) node->data + 4);
12151 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12155 /* Type starts with the (C) symbol, so the next data is a list
12156 * of (string size(16), language code(16), string) */
12158 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12159 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12161 /* the string + fourcc + size + 2 16bit fields,
12162 * means that there are more tags in this atom */
12163 if (len > str_len + 8 + 4) {
12164 /* TODO how to represent the same tag in different languages? */
12165 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12166 "text alternatives, reading only first one");
12170 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12171 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12173 if (lang_code < 0x800) { /* MAC encoded string */
12176 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12177 QT_FOURCC ((guint8 *) node->data + 4))) {
12178 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12180 /* we go for 3GP style encoding if major brands claims so,
12181 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12182 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12183 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12184 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12186 /* 16-bit Language code is ignored here as well */
12187 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12194 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12195 ret = FALSE; /* may have to fallback */
12198 GError *err = NULL;
12200 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12201 charset, NULL, NULL, &err);
12203 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12204 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12206 g_error_free (err);
12209 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12210 len - offset, env_vars);
12213 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12214 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12218 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12225 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12226 const char *tag, const char *dummy, GNode * node)
12228 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12232 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12233 const char *tag, const char *dummy, GNode * node)
12235 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12237 char *s, *t, *k = NULL;
12242 /* first try normal string tag if major brand not 3GP */
12243 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12244 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12245 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12246 * let's try it 3gpp way after minor safety check */
12248 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12254 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12258 len = QT_UINT32 (data);
12262 count = QT_UINT8 (data + 14);
12264 for (; count; count--) {
12267 if (offset + 1 > len)
12269 slen = QT_UINT8 (data + offset);
12271 if (offset + slen > len)
12273 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12276 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12278 t = g_strjoin (",", k, s, NULL);
12286 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12293 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12294 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12303 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12309 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12310 const char *tag1, const char *tag2, GNode * node)
12317 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12319 len = QT_UINT32 (data->data);
12320 type = QT_UINT32 ((guint8 *) data->data + 8);
12321 if (type == 0x00000000 && len >= 22) {
12322 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12323 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12325 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12326 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12329 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12330 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12337 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12338 const char *tag1, const char *dummy, GNode * node)
12345 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12347 len = QT_UINT32 (data->data);
12348 type = QT_UINT32 ((guint8 *) data->data + 8);
12349 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12350 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12351 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12352 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12354 /* do not add bpm=0 */
12355 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12356 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12364 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12365 const char *tag1, const char *dummy, GNode * node)
12372 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12374 len = QT_UINT32 (data->data);
12375 type = QT_UINT32 ((guint8 *) data->data + 8);
12376 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12377 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12378 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12379 num = QT_UINT32 ((guint8 *) data->data + 16);
12381 /* do not add num=0 */
12382 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12383 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12390 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12391 const char *tag1, const char *dummy, GNode * node)
12398 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12400 len = QT_UINT32 (data->data);
12401 type = QT_UINT32 ((guint8 *) data->data + 8);
12402 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12403 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12404 GstTagImageType image_type;
12406 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12407 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12409 image_type = GST_TAG_IMAGE_TYPE_NONE;
12412 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12413 len - 16, image_type))) {
12414 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12415 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12416 gst_sample_unref (sample);
12423 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12424 const char *tag, const char *dummy, GNode * node)
12431 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12433 len = QT_UINT32 (data->data);
12434 type = QT_UINT32 ((guint8 *) data->data + 8);
12435 if (type == 0x00000001 && len > 16) {
12436 guint y, m = 1, d = 1;
12439 s = g_strndup ((char *) data->data + 16, len - 16);
12440 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12441 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12442 if (ret >= 1 && y > 1500 && y < 3000) {
12445 date = g_date_new_dmy (d, m, y);
12446 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12447 g_date_free (date);
12449 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12457 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12458 const char *tag, const char *dummy, GNode * node)
12462 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12464 /* re-route to normal string tag if major brand says so
12465 * or no data atom and compatible brand suggests so */
12466 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12467 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12468 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12473 guint len, type, n;
12475 len = QT_UINT32 (data->data);
12476 type = QT_UINT32 ((guint8 *) data->data + 8);
12477 if (type == 0x00000000 && len >= 18) {
12478 n = QT_UINT16 ((guint8 *) data->data + 16);
12480 const gchar *genre;
12482 genre = gst_tag_id3_genre_get (n - 1);
12483 if (genre != NULL) {
12484 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12485 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12493 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12494 const gchar * tag, guint8 * data, guint32 datasize)
12499 /* make a copy to have \0 at the end */
12500 datacopy = g_strndup ((gchar *) data, datasize);
12502 /* convert the str to double */
12503 if (sscanf (datacopy, "%lf", &value) == 1) {
12504 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12505 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12507 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12515 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12516 const char *tag, const char *tag_bis, GNode * node)
12525 const gchar *meanstr;
12526 const gchar *namestr;
12528 /* checking the whole ---- atom size for consistency */
12529 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12530 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12534 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12536 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12540 meansize = QT_UINT32 (mean->data);
12541 if (meansize <= 12) {
12542 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12545 meanstr = ((gchar *) mean->data) + 12;
12548 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12550 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12554 namesize = QT_UINT32 (name->data);
12555 if (namesize <= 12) {
12556 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12559 namestr = ((gchar *) name->data) + 12;
12567 * uint24 - data type
12571 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12573 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12576 datasize = QT_UINT32 (data->data);
12577 if (datasize <= 16) {
12578 GST_WARNING_OBJECT (demux, "Data atom too small");
12581 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12583 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12584 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12585 static const struct
12587 const gchar name[28];
12588 const gchar tag[28];
12591 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12592 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12593 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12594 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12595 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12596 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12597 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12598 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12602 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12603 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12604 switch (gst_tag_get_type (tags[i].tag)) {
12605 case G_TYPE_DOUBLE:
12606 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12607 ((guint8 *) data->data) + 16, datasize - 16);
12609 case G_TYPE_STRING:
12610 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12619 if (i == G_N_ELEMENTS (tags))
12629 #ifndef GST_DISABLE_GST_DEBUG
12631 gchar *namestr_dbg;
12632 gchar *meanstr_dbg;
12634 meanstr_dbg = g_strndup (meanstr, meansize);
12635 namestr_dbg = g_strndup (namestr, namesize);
12637 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12638 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12640 g_free (namestr_dbg);
12641 g_free (meanstr_dbg);
12648 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12649 const char *tag_bis, GNode * node)
12654 GstTagList *id32_taglist = NULL;
12656 GST_LOG_OBJECT (demux, "parsing ID32");
12659 len = GST_READ_UINT32_BE (data);
12661 /* need at least full box and language tag */
12665 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12666 gst_buffer_fill (buf, 0, data + 14, len - 14);
12668 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12669 if (id32_taglist) {
12670 GST_LOG_OBJECT (demux, "parsing ok");
12671 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12672 gst_tag_list_unref (id32_taglist);
12674 GST_LOG_OBJECT (demux, "parsing failed");
12677 gst_buffer_unref (buf);
12680 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12681 const char *tag, const char *tag_bis, GNode * node);
12684 FOURCC_pcst -> if media is a podcast -> bool
12685 FOURCC_cpil -> if media is part of a compilation -> bool
12686 FOURCC_pgap -> if media is part of a gapless context -> bool
12687 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12690 static const struct
12693 const gchar *gst_tag;
12694 const gchar *gst_tag_bis;
12695 const GstQTDemuxAddTagFunc func;
12698 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12699 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12700 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12701 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12702 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12703 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12704 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12705 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12706 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12707 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12708 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12709 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12710 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12711 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12712 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12713 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12714 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12715 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12716 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12717 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12718 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12719 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12720 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12721 qtdemux_tag_add_num}, {
12722 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12723 qtdemux_tag_add_num}, {
12724 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12725 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12726 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12727 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12728 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12729 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12730 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12731 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12732 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12733 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12734 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12735 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12736 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12737 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12738 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12739 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12740 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12741 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12742 qtdemux_tag_add_classification}, {
12743 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12744 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12745 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12747 /* This is a special case, some tags are stored in this
12748 * 'reverse dns naming', according to:
12749 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12752 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12753 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12754 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12757 struct _GstQtDemuxTagList
12760 GstTagList *taglist;
12762 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12765 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12771 const gchar *style;
12776 GstQTDemux *demux = qtdemuxtaglist->demux;
12777 GstTagList *taglist = qtdemuxtaglist->taglist;
12780 len = QT_UINT32 (data);
12781 buf = gst_buffer_new_and_alloc (len);
12782 gst_buffer_fill (buf, 0, data, len);
12784 /* heuristic to determine style of tag */
12785 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12786 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12788 else if (demux->major_brand == FOURCC_qt__)
12789 style = "quicktime";
12790 /* fall back to assuming iso/3gp tag style */
12794 /* santize the name for the caps. */
12795 for (i = 0; i < 4; i++) {
12796 guint8 d = data[4 + i];
12797 if (g_ascii_isalnum (d))
12798 ndata[i] = g_ascii_tolower (d);
12803 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12804 ndata[0], ndata[1], ndata[2], ndata[3]);
12805 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12807 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12808 sample = gst_sample_new (buf, NULL, NULL, s);
12809 gst_buffer_unref (buf);
12810 g_free (media_type);
12812 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12815 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12816 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12818 gst_sample_unref (sample);
12822 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12829 GstQtDemuxTagList demuxtaglist;
12831 demuxtaglist.demux = qtdemux;
12832 demuxtaglist.taglist = taglist;
12834 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12835 if (meta != NULL) {
12836 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12837 if (ilst == NULL) {
12838 GST_LOG_OBJECT (qtdemux, "no ilst");
12843 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12847 while (i < G_N_ELEMENTS (add_funcs)) {
12848 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12852 len = QT_UINT32 (node->data);
12854 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12855 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12857 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12858 add_funcs[i].gst_tag_bis, node);
12860 g_node_destroy (node);
12866 /* parsed nodes have been removed, pass along remainder as blob */
12867 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12868 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12870 /* parse up XMP_ node if existing */
12871 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12872 if (xmp_ != NULL) {
12874 GstTagList *xmptaglist;
12876 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12877 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12878 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12879 gst_buffer_unref (buf);
12881 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12883 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12889 GstStructure *structure; /* helper for sort function */
12891 guint min_req_bitrate;
12892 guint min_req_qt_version;
12896 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12898 GstQtReference *ref_a = (GstQtReference *) a;
12899 GstQtReference *ref_b = (GstQtReference *) b;
12901 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12902 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12904 /* known bitrates go before unknown; higher bitrates go first */
12905 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12908 /* sort the redirects and post a message for the application.
12911 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12913 GstQtReference *best;
12916 GValue list_val = { 0, };
12919 g_assert (references != NULL);
12921 references = g_list_sort (references, qtdemux_redirects_sort_func);
12923 best = (GstQtReference *) references->data;
12925 g_value_init (&list_val, GST_TYPE_LIST);
12927 for (l = references; l != NULL; l = l->next) {
12928 GstQtReference *ref = (GstQtReference *) l->data;
12929 GValue struct_val = { 0, };
12931 ref->structure = gst_structure_new ("redirect",
12932 "new-location", G_TYPE_STRING, ref->location, NULL);
12934 if (ref->min_req_bitrate > 0) {
12935 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12936 ref->min_req_bitrate, NULL);
12939 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12940 g_value_set_boxed (&struct_val, ref->structure);
12941 gst_value_list_append_value (&list_val, &struct_val);
12942 g_value_unset (&struct_val);
12943 /* don't free anything here yet, since we need best->structure below */
12946 g_assert (best != NULL);
12947 s = gst_structure_copy (best->structure);
12949 if (g_list_length (references) > 1) {
12950 gst_structure_set_value (s, "locations", &list_val);
12953 g_value_unset (&list_val);
12955 for (l = references; l != NULL; l = l->next) {
12956 GstQtReference *ref = (GstQtReference *) l->data;
12958 gst_structure_free (ref->structure);
12959 g_free (ref->location);
12962 g_list_free (references);
12964 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12965 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12966 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12967 qtdemux->posted_redirect = TRUE;
12970 /* look for redirect nodes, collect all redirect information and
12974 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12976 GNode *rmra, *rmda, *rdrf;
12978 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12980 GList *redirects = NULL;
12982 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12984 GstQtReference ref = { NULL, NULL, 0, 0 };
12985 GNode *rmdr, *rmvc;
12987 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12988 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12989 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12990 ref.min_req_bitrate);
12993 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12994 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12995 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12997 #ifndef GST_DISABLE_GST_DEBUG
12998 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13000 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13002 GST_LOG_OBJECT (qtdemux,
13003 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13004 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13005 bitmask, check_type);
13006 if (package == FOURCC_qtim && check_type == 0) {
13007 ref.min_req_qt_version = version;
13011 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13017 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13018 if (ref_len > 20) {
13019 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13020 ref_data = (guint8 *) rdrf->data + 20;
13021 if (ref_type == FOURCC_alis) {
13022 guint record_len, record_version, fn_len;
13024 if (ref_len > 70) {
13025 /* MacOSX alias record, google for alias-layout.txt */
13026 record_len = QT_UINT16 (ref_data + 4);
13027 record_version = QT_UINT16 (ref_data + 4 + 2);
13028 fn_len = QT_UINT8 (ref_data + 50);
13029 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13030 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13033 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13036 } else if (ref_type == FOURCC_url_) {
13037 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13039 GST_DEBUG_OBJECT (qtdemux,
13040 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13041 GST_FOURCC_ARGS (ref_type));
13043 if (ref.location != NULL) {
13044 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13046 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13048 GST_WARNING_OBJECT (qtdemux,
13049 "Failed to extract redirect location from rdrf atom");
13052 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13056 /* look for others */
13057 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13060 if (redirects != NULL) {
13061 qtdemux_process_redirects (qtdemux, redirects);
13067 static GstTagList *
13068 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13072 if (tags == NULL) {
13073 tags = gst_tag_list_new_empty ();
13074 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13077 if (qtdemux->major_brand == FOURCC_mjp2)
13078 fmt = "Motion JPEG 2000";
13079 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13081 else if (qtdemux->major_brand == FOURCC_qt__)
13083 else if (qtdemux->fragmented)
13086 fmt = "ISO MP4/M4A";
13088 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13089 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13091 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13097 /* we have read the complete moov node now.
13098 * This function parses all of the relevant info, creates the traks and
13099 * prepares all data structures for playback
13102 qtdemux_parse_tree (GstQTDemux * qtdemux)
13108 GstClockTime duration;
13110 guint64 creation_time;
13111 GstDateTime *datetime = NULL;
13114 /* make sure we have a usable taglist */
13115 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13117 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13118 if (mvhd == NULL) {
13119 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13120 return qtdemux_parse_redirects (qtdemux);
13123 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13124 if (version == 1) {
13125 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13126 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13127 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13128 } else if (version == 0) {
13129 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13130 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13131 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13133 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13137 /* Moving qt creation time (secs since 1904) to unix time */
13138 if (creation_time != 0) {
13139 /* Try to use epoch first as it should be faster and more commonly found */
13140 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13143 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13144 /* some data cleansing sanity */
13145 g_get_current_time (&now);
13146 if (now.tv_sec + 24 * 3600 < creation_time) {
13147 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13149 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13152 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13153 GDateTime *dt, *dt_local;
13155 dt = g_date_time_add_seconds (base_dt, creation_time);
13156 dt_local = g_date_time_to_local (dt);
13157 datetime = gst_date_time_new_from_g_date_time (dt_local);
13159 g_date_time_unref (base_dt);
13160 g_date_time_unref (dt);
13164 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13165 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13167 gst_date_time_unref (datetime);
13170 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13171 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13173 /* check for fragmented file and get some (default) data */
13174 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13177 GstByteReader mehd_data;
13179 /* let track parsing or anyone know weird stuff might happen ... */
13180 qtdemux->fragmented = TRUE;
13182 /* compensate for total duration */
13183 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13185 qtdemux_parse_mehd (qtdemux, &mehd_data);
13188 /* set duration in the segment info */
13189 gst_qtdemux_get_duration (qtdemux, &duration);
13191 qtdemux->segment.duration = duration;
13192 /* also do not exceed duration; stop is set that way post seek anyway,
13193 * and segment activation falls back to duration,
13194 * whereas loop only checks stop, so let's align this here as well */
13195 qtdemux->segment.stop = duration;
13198 /* parse all traks */
13199 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13201 qtdemux_parse_trak (qtdemux, trak);
13202 /* iterate all siblings */
13203 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13206 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13209 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13211 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13213 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13216 /* maybe also some tags in meta box */
13217 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13219 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13220 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13222 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13225 /* parse any protection system info */
13226 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13228 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13229 qtdemux_parse_pssh (qtdemux, pssh);
13230 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13233 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13238 /* taken from ffmpeg */
13240 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13252 len = (len << 7) | (c & 0x7f);
13260 /* this can change the codec originally present in @list */
13262 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13263 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13265 int len = QT_UINT32 (esds->data);
13266 guint8 *ptr = esds->data;
13267 guint8 *end = ptr + len;
13269 guint8 *data_ptr = NULL;
13271 guint8 object_type_id = 0;
13272 const char *codec_name = NULL;
13273 GstCaps *caps = NULL;
13275 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13277 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13279 while (ptr + 1 < end) {
13280 tag = QT_UINT8 (ptr);
13281 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13283 len = read_descr_size (ptr, end, &ptr);
13284 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13286 /* Check the stated amount of data is available for reading */
13287 if (len < 0 || ptr + len > end)
13291 case ES_DESCRIPTOR_TAG:
13292 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13293 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13296 case DECODER_CONFIG_DESC_TAG:{
13297 guint max_bitrate, avg_bitrate;
13299 object_type_id = QT_UINT8 (ptr);
13300 max_bitrate = QT_UINT32 (ptr + 5);
13301 avg_bitrate = QT_UINT32 (ptr + 9);
13302 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13303 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13304 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13305 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13306 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13307 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13308 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13309 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13311 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13312 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13313 avg_bitrate, NULL);
13318 case DECODER_SPECIFIC_INFO_TAG:
13319 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13320 if (object_type_id == 0xe0 && len == 0x40) {
13326 GST_DEBUG_OBJECT (qtdemux,
13327 "Have VOBSUB palette. Creating palette event");
13328 /* move to decConfigDescr data and read palette */
13330 for (i = 0; i < 16; i++) {
13331 clut[i] = QT_UINT32 (data);
13335 s = gst_structure_new ("application/x-gst-dvd", "event",
13336 G_TYPE_STRING, "dvd-spu-clut-change",
13337 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13338 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13339 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13340 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13341 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13342 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13343 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13344 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13347 /* store event and trigger custom processing */
13348 stream->pending_event =
13349 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13351 /* Generic codec_data handler puts it on the caps */
13358 case SL_CONFIG_DESC_TAG:
13359 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13363 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13365 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13371 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13372 * in use, and should also be used to override some other parameters for some
13374 switch (object_type_id) {
13375 case 0x20: /* MPEG-4 */
13376 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13377 * profile_and_level_indication */
13378 if (data_ptr != NULL && data_len >= 5 &&
13379 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13380 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13381 data_ptr + 4, data_len - 4);
13383 break; /* Nothing special needed here */
13384 case 0x21: /* H.264 */
13385 codec_name = "H.264 / AVC";
13386 caps = gst_caps_new_simple ("video/x-h264",
13387 "stream-format", G_TYPE_STRING, "avc",
13388 "alignment", G_TYPE_STRING, "au", NULL);
13390 case 0x40: /* AAC (any) */
13391 case 0x66: /* AAC Main */
13392 case 0x67: /* AAC LC */
13393 case 0x68: /* AAC SSR */
13394 /* Override channels and rate based on the codec_data, as it's often
13396 /* Only do so for basic setup without HE-AAC extension */
13397 if (data_ptr && data_len == 2) {
13398 guint channels, rate;
13400 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13402 entry->n_channels = channels;
13404 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13406 entry->rate = rate;
13409 /* Set level and profile if possible */
13410 if (data_ptr != NULL && data_len >= 2) {
13411 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13412 data_ptr, data_len);
13414 const gchar *profile_str = NULL;
13417 guint8 *codec_data;
13418 gint rate_idx, profile;
13420 /* No codec_data, let's invent something.
13421 * FIXME: This is wrong for SBR! */
13423 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13425 buffer = gst_buffer_new_and_alloc (2);
13426 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13427 codec_data = map.data;
13430 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13433 switch (object_type_id) {
13435 profile_str = "main";
13439 profile_str = "lc";
13443 profile_str = "ssr";
13451 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13453 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13455 gst_buffer_unmap (buffer, &map);
13456 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13457 GST_TYPE_BUFFER, buffer, NULL);
13458 gst_buffer_unref (buffer);
13461 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13462 G_TYPE_STRING, profile_str, NULL);
13466 case 0x60: /* MPEG-2, various profiles */
13472 codec_name = "MPEG-2 video";
13473 caps = gst_caps_new_simple ("video/mpeg",
13474 "mpegversion", G_TYPE_INT, 2,
13475 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13477 case 0x69: /* MPEG-2 BC audio */
13478 case 0x6B: /* MPEG-1 audio */
13479 caps = gst_caps_new_simple ("audio/mpeg",
13480 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13481 codec_name = "MPEG-1 audio";
13483 case 0x6A: /* MPEG-1 */
13484 codec_name = "MPEG-1 video";
13485 caps = gst_caps_new_simple ("video/mpeg",
13486 "mpegversion", G_TYPE_INT, 1,
13487 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13489 case 0x6C: /* MJPEG */
13491 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13493 codec_name = "Motion-JPEG";
13495 case 0x6D: /* PNG */
13497 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13499 codec_name = "PNG still images";
13501 case 0x6E: /* JPEG2000 */
13502 codec_name = "JPEG-2000";
13503 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13505 case 0xA4: /* Dirac */
13506 codec_name = "Dirac";
13507 caps = gst_caps_new_empty_simple ("video/x-dirac");
13509 case 0xA5: /* AC3 */
13510 codec_name = "AC-3 audio";
13511 caps = gst_caps_new_simple ("audio/x-ac3",
13512 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13514 case 0xA9: /* AC3 */
13515 codec_name = "DTS audio";
13516 caps = gst_caps_new_simple ("audio/x-dts",
13517 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13519 case 0xE1: /* QCELP */
13520 /* QCELP, the codec_data is a riff tag (little endian) with
13521 * 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). */
13522 caps = gst_caps_new_empty_simple ("audio/qcelp");
13523 codec_name = "QCELP";
13529 /* If we have a replacement caps, then change our caps for this stream */
13531 gst_caps_unref (entry->caps);
13532 entry->caps = caps;
13535 if (codec_name && list)
13536 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13537 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13539 /* Add the codec_data attribute to caps, if we have it */
13543 buffer = gst_buffer_new_and_alloc (data_len);
13544 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13546 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13547 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13549 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13551 gst_buffer_unref (buffer);
13556 static inline GstCaps *
13557 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13561 char *s, fourstr[5];
13563 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13564 for (i = 0; i < 4; i++) {
13565 if (!g_ascii_isalnum (fourstr[i]))
13568 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13569 caps = gst_caps_new_empty_simple (s);
13574 #define _codec(name) \
13576 if (codec_name) { \
13577 *codec_name = g_strdup (name); \
13582 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13583 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
13584 const guint8 * stsd_entry_data, gchar ** codec_name)
13586 GstCaps *caps = NULL;
13587 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13591 _codec ("PNG still images");
13592 caps = gst_caps_new_empty_simple ("image/png");
13595 _codec ("JPEG still images");
13597 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13600 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13601 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13602 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13603 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13604 _codec ("Motion-JPEG");
13606 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13609 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13610 _codec ("Motion-JPEG format B");
13611 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13614 _codec ("JPEG-2000");
13615 /* override to what it should be according to spec, avoid palette_data */
13616 entry->bits_per_sample = 24;
13617 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13620 _codec ("Sorensen video v.3");
13621 caps = gst_caps_new_simple ("video/x-svq",
13622 "svqversion", G_TYPE_INT, 3, NULL);
13624 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13625 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13626 _codec ("Sorensen video v.1");
13627 caps = gst_caps_new_simple ("video/x-svq",
13628 "svqversion", G_TYPE_INT, 1, NULL);
13630 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13631 caps = gst_caps_new_empty_simple ("video/x-raw");
13632 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13633 _codec ("Windows Raw RGB");
13634 stream->alignment = 32;
13640 bps = QT_UINT16 (stsd_entry_data + 82);
13643 format = GST_VIDEO_FORMAT_RGB15;
13646 format = GST_VIDEO_FORMAT_RGB16;
13649 format = GST_VIDEO_FORMAT_RGB;
13652 format = GST_VIDEO_FORMAT_ARGB;
13660 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13661 format = GST_VIDEO_FORMAT_I420;
13663 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13664 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13665 format = GST_VIDEO_FORMAT_I420;
13668 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13669 format = GST_VIDEO_FORMAT_UYVY;
13671 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13672 format = GST_VIDEO_FORMAT_v308;
13674 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13675 format = GST_VIDEO_FORMAT_v216;
13678 format = GST_VIDEO_FORMAT_v210;
13680 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13681 format = GST_VIDEO_FORMAT_r210;
13683 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13684 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13685 format = GST_VIDEO_FORMAT_v410;
13688 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13689 * but different order than AYUV
13690 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13691 format = GST_VIDEO_FORMAT_v408;
13694 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13695 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13696 _codec ("MPEG-1 video");
13697 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13698 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13700 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13701 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13702 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13703 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13704 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13705 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13706 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13707 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13708 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13709 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13710 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13711 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13712 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13713 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13714 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13715 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13716 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13717 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13718 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13719 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13720 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13721 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13722 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13723 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13724 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13725 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13726 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13727 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13728 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13729 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13730 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13731 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13732 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13733 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13734 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13735 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13736 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13737 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13738 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13739 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13740 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13741 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13742 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13743 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13744 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13745 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13746 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13747 _codec ("MPEG-2 video");
13748 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13749 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13751 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13752 _codec ("GIF still images");
13753 caps = gst_caps_new_empty_simple ("image/gif");
13756 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13758 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13760 /* ffmpeg uses the height/width props, don't know why */
13761 caps = gst_caps_new_simple ("video/x-h263",
13762 "variant", G_TYPE_STRING, "itu", NULL);
13766 _codec ("MPEG-4 video");
13767 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13768 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13770 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13771 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13772 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13773 caps = gst_caps_new_simple ("video/x-msmpeg",
13774 "msmpegversion", G_TYPE_INT, 43, NULL);
13776 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13778 caps = gst_caps_new_simple ("video/x-divx",
13779 "divxversion", G_TYPE_INT, 3, NULL);
13781 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13782 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13784 caps = gst_caps_new_simple ("video/x-divx",
13785 "divxversion", G_TYPE_INT, 4, NULL);
13787 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13789 caps = gst_caps_new_simple ("video/x-divx",
13790 "divxversion", G_TYPE_INT, 5, NULL);
13793 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13795 caps = gst_caps_new_simple ("video/x-ffv",
13796 "ffvversion", G_TYPE_INT, 1, NULL);
13799 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13800 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13805 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13806 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13807 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13811 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13812 _codec ("Cinepak");
13813 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13815 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13816 _codec ("Apple QuickDraw");
13817 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13819 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13820 _codec ("Apple video");
13821 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13825 _codec ("H.264 / AVC");
13826 caps = gst_caps_new_simple ("video/x-h264",
13827 "stream-format", G_TYPE_STRING, "avc",
13828 "alignment", G_TYPE_STRING, "au", NULL);
13831 _codec ("H.264 / AVC");
13832 caps = gst_caps_new_simple ("video/x-h264",
13833 "stream-format", G_TYPE_STRING, "avc3",
13834 "alignment", G_TYPE_STRING, "au", NULL);
13838 _codec ("H.265 / HEVC");
13839 caps = gst_caps_new_simple ("video/x-h265",
13840 "stream-format", G_TYPE_STRING, "hvc1",
13841 "alignment", G_TYPE_STRING, "au", NULL);
13844 _codec ("H.265 / HEVC");
13845 caps = gst_caps_new_simple ("video/x-h265",
13846 "stream-format", G_TYPE_STRING, "hev1",
13847 "alignment", G_TYPE_STRING, "au", NULL);
13850 _codec ("Run-length encoding");
13851 caps = gst_caps_new_simple ("video/x-rle",
13852 "layout", G_TYPE_STRING, "quicktime", NULL);
13855 _codec ("Run-length encoding");
13856 caps = gst_caps_new_simple ("video/x-rle",
13857 "layout", G_TYPE_STRING, "microsoft", NULL);
13859 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13860 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13861 _codec ("Indeo Video 3");
13862 caps = gst_caps_new_simple ("video/x-indeo",
13863 "indeoversion", G_TYPE_INT, 3, NULL);
13865 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13866 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13867 _codec ("Intel Video 4");
13868 caps = gst_caps_new_simple ("video/x-indeo",
13869 "indeoversion", G_TYPE_INT, 4, NULL);
13873 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13874 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13875 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13876 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13877 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13878 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13879 _codec ("DV Video");
13880 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13881 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13883 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13884 case FOURCC_dv5p: /* DVCPRO50 PAL */
13885 _codec ("DVCPro50 Video");
13886 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13887 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13889 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13890 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13891 _codec ("DVCProHD Video");
13892 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13893 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13895 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13896 _codec ("Apple Graphics (SMC)");
13897 caps = gst_caps_new_empty_simple ("video/x-smc");
13899 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13901 caps = gst_caps_new_empty_simple ("video/x-vp3");
13903 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13904 _codec ("VP6 Flash");
13905 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13909 caps = gst_caps_new_empty_simple ("video/x-theora");
13910 /* theora uses one byte of padding in the data stream because it does not
13911 * allow 0 sized packets while theora does */
13912 entry->padding = 1;
13916 caps = gst_caps_new_empty_simple ("video/x-dirac");
13918 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13919 _codec ("TIFF still images");
13920 caps = gst_caps_new_empty_simple ("image/tiff");
13922 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13923 _codec ("Apple Intermediate Codec");
13924 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13926 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13927 _codec ("AVID DNxHD");
13928 caps = gst_caps_from_string ("video/x-dnxhd");
13931 _codec ("On2 VP8");
13932 caps = gst_caps_from_string ("video/x-vp8");
13935 _codec ("Apple ProRes LT");
13937 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13941 _codec ("Apple ProRes HQ");
13943 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13947 _codec ("Apple ProRes");
13949 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13953 _codec ("Apple ProRes Proxy");
13955 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13959 _codec ("Apple ProRes 4444");
13961 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13965 _codec ("Apple ProRes 4444 XQ");
13967 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13971 _codec ("GoPro CineForm");
13972 caps = gst_caps_from_string ("video/x-cineform");
13977 caps = gst_caps_new_simple ("video/x-wmv",
13978 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13980 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13983 caps = _get_unknown_codec_name ("video", fourcc);
13988 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13991 gst_video_info_init (&info);
13992 gst_video_info_set_format (&info, format, entry->width, entry->height);
13994 caps = gst_video_info_to_caps (&info);
13995 *codec_name = gst_pb_utils_get_codec_description (caps);
13997 /* enable clipping for raw video streams */
13998 stream->need_clip = TRUE;
13999 stream->alignment = 32;
14006 round_up_pow2 (guint n)
14018 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14019 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14020 int len, gchar ** codec_name)
14023 const GstStructure *s;
14026 GstAudioFormat format = 0;
14029 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14031 depth = entry->bytes_per_packet * 8;
14034 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14036 /* 8-bit audio is unsigned */
14038 format = GST_AUDIO_FORMAT_U8;
14039 /* otherwise it's signed and big-endian just like 'twos' */
14041 endian = G_BIG_ENDIAN;
14048 endian = G_LITTLE_ENDIAN;
14051 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14053 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14057 caps = gst_caps_new_simple ("audio/x-raw",
14058 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14059 "layout", G_TYPE_STRING, "interleaved", NULL);
14060 stream->alignment = GST_ROUND_UP_8 (depth);
14061 stream->alignment = round_up_pow2 (stream->alignment);
14064 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14065 _codec ("Raw 64-bit floating-point audio");
14066 caps = gst_caps_new_simple ("audio/x-raw",
14067 "format", G_TYPE_STRING, "F64BE",
14068 "layout", G_TYPE_STRING, "interleaved", NULL);
14069 stream->alignment = 8;
14071 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14072 _codec ("Raw 32-bit floating-point audio");
14073 caps = gst_caps_new_simple ("audio/x-raw",
14074 "format", G_TYPE_STRING, "F32BE",
14075 "layout", G_TYPE_STRING, "interleaved", NULL);
14076 stream->alignment = 4;
14079 _codec ("Raw 24-bit PCM audio");
14080 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14082 caps = gst_caps_new_simple ("audio/x-raw",
14083 "format", G_TYPE_STRING, "S24BE",
14084 "layout", G_TYPE_STRING, "interleaved", NULL);
14085 stream->alignment = 4;
14087 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14088 _codec ("Raw 32-bit PCM audio");
14089 caps = gst_caps_new_simple ("audio/x-raw",
14090 "format", G_TYPE_STRING, "S32BE",
14091 "layout", G_TYPE_STRING, "interleaved", NULL);
14092 stream->alignment = 4;
14094 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14095 _codec ("Raw 16-bit PCM audio");
14096 caps = gst_caps_new_simple ("audio/x-raw",
14097 "format", G_TYPE_STRING, "S16LE",
14098 "layout", G_TYPE_STRING, "interleaved", NULL);
14099 stream->alignment = 2;
14102 _codec ("Mu-law audio");
14103 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14106 _codec ("A-law audio");
14107 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14111 _codec ("Microsoft ADPCM");
14112 /* Microsoft ADPCM-ACM code 2 */
14113 caps = gst_caps_new_simple ("audio/x-adpcm",
14114 "layout", G_TYPE_STRING, "microsoft", NULL);
14118 _codec ("DVI/IMA ADPCM");
14119 caps = gst_caps_new_simple ("audio/x-adpcm",
14120 "layout", G_TYPE_STRING, "dvi", NULL);
14124 _codec ("DVI/Intel IMA ADPCM");
14125 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14126 caps = gst_caps_new_simple ("audio/x-adpcm",
14127 "layout", G_TYPE_STRING, "quicktime", NULL);
14131 /* MPEG layer 3, CBR only (pre QT4.1) */
14133 _codec ("MPEG-1 layer 3");
14134 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14135 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14136 "mpegversion", G_TYPE_INT, 1, NULL);
14138 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14139 _codec ("MPEG-1 layer 2");
14141 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14142 "mpegversion", G_TYPE_INT, 1, NULL);
14145 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14146 _codec ("EAC-3 audio");
14147 caps = gst_caps_new_simple ("audio/x-eac3",
14148 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14149 entry->sampled = TRUE;
14151 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14153 _codec ("AC-3 audio");
14154 caps = gst_caps_new_simple ("audio/x-ac3",
14155 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14156 entry->sampled = TRUE;
14158 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14159 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14160 _codec ("DTS audio");
14161 caps = gst_caps_new_simple ("audio/x-dts",
14162 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14163 entry->sampled = TRUE;
14165 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14166 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14167 _codec ("DTS-HD audio");
14168 caps = gst_caps_new_simple ("audio/x-dts",
14169 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14170 entry->sampled = TRUE;
14174 caps = gst_caps_new_simple ("audio/x-mace",
14175 "maceversion", G_TYPE_INT, 3, NULL);
14179 caps = gst_caps_new_simple ("audio/x-mace",
14180 "maceversion", G_TYPE_INT, 6, NULL);
14182 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14184 caps = gst_caps_new_empty_simple ("application/ogg");
14186 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14187 _codec ("DV audio");
14188 caps = gst_caps_new_empty_simple ("audio/x-dv");
14191 _codec ("MPEG-4 AAC audio");
14192 caps = gst_caps_new_simple ("audio/mpeg",
14193 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14194 "stream-format", G_TYPE_STRING, "raw", NULL);
14196 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14197 _codec ("QDesign Music");
14198 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14201 _codec ("QDesign Music v.2");
14202 /* FIXME: QDesign music version 2 (no constant) */
14203 if (FALSE && data) {
14204 caps = gst_caps_new_simple ("audio/x-qdm2",
14205 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14206 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14207 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14209 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14213 _codec ("GSM audio");
14214 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14217 _codec ("AMR audio");
14218 caps = gst_caps_new_empty_simple ("audio/AMR");
14221 _codec ("AMR-WB audio");
14222 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14225 _codec ("Quicktime IMA ADPCM");
14226 caps = gst_caps_new_simple ("audio/x-adpcm",
14227 "layout", G_TYPE_STRING, "quicktime", NULL);
14230 _codec ("Apple lossless audio");
14231 caps = gst_caps_new_empty_simple ("audio/x-alac");
14234 _codec ("Free Lossless Audio Codec");
14235 caps = gst_caps_new_simple ("audio/x-flac",
14236 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14238 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14239 _codec ("QualComm PureVoice");
14240 caps = gst_caps_from_string ("audio/qcelp");
14245 caps = gst_caps_new_empty_simple ("audio/x-wma");
14249 caps = gst_caps_new_empty_simple ("audio/x-opus");
14251 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
14256 GstAudioFormat format;
14259 FLAG_IS_FLOAT = 0x1,
14260 FLAG_IS_BIG_ENDIAN = 0x2,
14261 FLAG_IS_SIGNED = 0x4,
14262 FLAG_IS_PACKED = 0x8,
14263 FLAG_IS_ALIGNED_HIGH = 0x10,
14264 FLAG_IS_NON_INTERLEAVED = 0x20
14266 _codec ("Raw LPCM audio");
14268 if (data && len >= 56) {
14269 depth = QT_UINT32 (data + 40);
14270 flags = QT_UINT32 (data + 44);
14271 width = QT_UINT32 (data + 48) * 8 / entry->n_channels;
14273 if ((flags & FLAG_IS_FLOAT) == 0) {
14278 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14279 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14280 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14281 caps = gst_caps_new_simple ("audio/x-raw",
14282 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14283 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14284 "non-interleaved" : "interleaved", NULL);
14285 stream->alignment = GST_ROUND_UP_8 (depth);
14286 stream->alignment = round_up_pow2 (stream->alignment);
14291 if (flags & FLAG_IS_BIG_ENDIAN)
14292 format = GST_AUDIO_FORMAT_F64BE;
14294 format = GST_AUDIO_FORMAT_F64LE;
14296 if (flags & FLAG_IS_BIG_ENDIAN)
14297 format = GST_AUDIO_FORMAT_F32BE;
14299 format = GST_AUDIO_FORMAT_F32LE;
14301 caps = gst_caps_new_simple ("audio/x-raw",
14302 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14303 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14304 "non-interleaved" : "interleaved", NULL);
14305 stream->alignment = width / 8;
14309 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14313 caps = _get_unknown_codec_name ("audio", fourcc);
14319 GstCaps *templ_caps =
14320 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14321 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14322 gst_caps_unref (caps);
14323 gst_caps_unref (templ_caps);
14324 caps = intersection;
14327 /* enable clipping for raw audio streams */
14328 s = gst_caps_get_structure (caps, 0);
14329 name = gst_structure_get_name (s);
14330 if (g_str_has_prefix (name, "audio/x-raw")) {
14331 stream->need_clip = TRUE;
14332 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14333 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14339 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14340 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14341 const guint8 * stsd_entry_data, gchar ** codec_name)
14345 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14349 _codec ("DVD subtitle");
14350 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14351 stream->need_process = TRUE;
14354 _codec ("Quicktime timed text");
14357 _codec ("3GPP timed text");
14359 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14361 /* actual text piece needs to be extracted */
14362 stream->need_process = TRUE;
14365 _codec ("XML subtitles");
14366 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14370 caps = _get_unknown_codec_name ("text", fourcc);
14378 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14379 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14380 const guint8 * stsd_entry_data, gchar ** codec_name)
14386 _codec ("MPEG 1 video");
14387 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14388 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14398 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14399 const gchar * system_id)
14403 if (!qtdemux->protection_system_ids)
14404 qtdemux->protection_system_ids =
14405 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14406 /* Check whether we already have an entry for this system ID. */
14407 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14408 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14409 if (g_ascii_strcasecmp (system_id, id) == 0) {
14413 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14414 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,