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) {
4820 stream->to_sample = G_MAXUINT32;
4824 /* We don't need to look for a sample in push-based */
4825 if (!qtdemux->pullbased)
4828 /* and move to the keyframe before the indicated media time of the
4830 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4831 if (qtdemux->segment.rate >= 0) {
4832 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4833 stream->to_sample = G_MAXUINT32;
4834 GST_DEBUG_OBJECT (stream->pad,
4835 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4836 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4837 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4839 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4840 stream->to_sample = index;
4841 GST_DEBUG_OBJECT (stream->pad,
4842 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4843 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4844 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4847 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4848 "this is an empty segment");
4852 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4853 * encountered an error and printed a message so we return appropriately */
4857 /* we're at the right spot */
4858 if (index == stream->sample_index) {
4859 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4863 /* find keyframe of the target index */
4864 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4867 /* indent does stupid stuff with stream->samples[].timestamp */
4869 /* if we move forwards, we don't have to go back to the previous
4870 * keyframe since we already sent that. We can also just jump to
4871 * the keyframe right before the target index if there is one. */
4872 if (index > stream->sample_index) {
4873 /* moving forwards check if we move past a keyframe */
4874 if (kf_index > stream->sample_index) {
4875 GST_DEBUG_OBJECT (stream->pad,
4876 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4877 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4878 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4879 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4881 GST_DEBUG_OBJECT (stream->pad,
4882 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4883 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4884 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4887 GST_DEBUG_OBJECT (stream->pad,
4888 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4889 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4890 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4891 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4899 /* prepare to get the current sample of @stream, getting essential values.
4901 * This function will also prepare and send the segment when needed.
4903 * Return FALSE if the stream is EOS.
4908 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4909 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4910 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4911 gboolean * keyframe)
4913 QtDemuxSample *sample;
4914 GstClockTime time_position;
4917 g_return_val_if_fail (stream != NULL, FALSE);
4919 time_position = stream->time_position;
4920 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4923 seg_idx = stream->segment_index;
4924 if (G_UNLIKELY (seg_idx == -1)) {
4925 /* find segment corresponding to time_position if we are looking
4927 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4930 /* different segment, activate it, sample_index will be set. */
4931 if (G_UNLIKELY (stream->segment_index != seg_idx))
4932 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4934 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4936 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4938 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4939 " prepare empty sample");
4942 *pts = *dts = time_position;
4943 *duration = seg->duration - (time_position - seg->time);
4950 if (stream->sample_index == -1)
4951 stream->sample_index = 0;
4953 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4954 stream->sample_index, stream->n_samples);
4956 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4957 if (!qtdemux->fragmented)
4960 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4964 GST_OBJECT_LOCK (qtdemux);
4965 flow = qtdemux_add_fragmented_samples (qtdemux);
4966 GST_OBJECT_UNLOCK (qtdemux);
4968 if (flow != GST_FLOW_OK)
4971 while (stream->sample_index >= stream->n_samples);
4974 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4975 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4976 stream->sample_index);
4980 /* now get the info for the sample we're at */
4981 sample = &stream->samples[stream->sample_index];
4983 *dts = QTSAMPLE_DTS (stream, sample);
4984 *pts = QTSAMPLE_PTS (stream, sample);
4985 *offset = sample->offset;
4986 *size = sample->size;
4987 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4988 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4995 stream->time_position = GST_CLOCK_TIME_NONE;
5000 /* move to the next sample in @stream.
5002 * Moves to the next segment when needed.
5005 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5007 QtDemuxSample *sample;
5008 QtDemuxSegment *segment;
5010 /* get current segment */
5011 segment = &stream->segments[stream->segment_index];
5013 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5014 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5018 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5019 /* Mark the stream as EOS */
5020 GST_DEBUG_OBJECT (qtdemux,
5021 "reached max allowed sample %u, mark EOS", stream->to_sample);
5022 stream->time_position = GST_CLOCK_TIME_NONE;
5026 /* move to next sample */
5027 stream->sample_index++;
5028 stream->offset_in_sample = 0;
5030 /* reached the last sample, we need the next segment */
5031 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5034 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5035 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5036 stream->sample_index);
5040 /* get next sample */
5041 sample = &stream->samples[stream->sample_index];
5043 /* see if we are past the segment */
5044 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5047 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5048 /* inside the segment, update time_position, looks very familiar to
5049 * GStreamer segments, doesn't it? */
5050 stream->time_position =
5051 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5053 /* not yet in segment, time does not yet increment. This means
5054 * that we are still prerolling keyframes to the decoder so it can
5055 * decode the first sample of the segment. */
5056 stream->time_position = segment->time;
5060 /* move to the next segment */
5063 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5065 if (stream->segment_index == stream->n_segments - 1) {
5066 /* are we at the end of the last segment, we're EOS */
5067 stream->time_position = GST_CLOCK_TIME_NONE;
5069 /* else we're only at the end of the current segment */
5070 stream->time_position = segment->stop_time;
5072 /* make sure we select a new segment */
5074 /* accumulate previous segments */
5075 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5076 stream->accumulated_base +=
5077 (stream->segment.stop -
5078 stream->segment.start) / ABS (stream->segment.rate);
5080 stream->segment_index = -1;
5085 gst_qtdemux_sync_streams (GstQTDemux * demux)
5089 if (demux->n_streams <= 1)
5092 for (i = 0; i < demux->n_streams; i++) {
5093 QtDemuxStream *stream;
5094 GstClockTime end_time;
5096 stream = demux->streams[i];
5101 /* TODO advance time on subtitle streams here, if any some day */
5103 /* some clips/trailers may have unbalanced streams at the end,
5104 * so send EOS on shorter stream to prevent stalling others */
5106 /* do not mess with EOS if SEGMENT seeking */
5107 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5110 if (demux->pullbased) {
5111 /* loop mode is sample time based */
5112 if (!STREAM_IS_EOS (stream))
5115 /* push mode is byte position based */
5116 if (stream->n_samples &&
5117 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5121 if (stream->sent_eos)
5124 /* only act if some gap */
5125 end_time = stream->segments[stream->n_segments - 1].stop_time;
5126 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5127 ", stream end: %" GST_TIME_FORMAT,
5128 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5129 if (GST_CLOCK_TIME_IS_VALID (end_time)
5130 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5133 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5134 GST_PAD_NAME (stream->pad));
5135 stream->sent_eos = TRUE;
5136 event = gst_event_new_eos ();
5137 if (demux->segment_seqnum)
5138 gst_event_set_seqnum (event, demux->segment_seqnum);
5139 gst_pad_push_event (stream->pad, event);
5144 /* EOS and NOT_LINKED need to be combined. This means that we return:
5146 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5147 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5149 static GstFlowReturn
5150 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5153 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5156 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5159 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5161 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5165 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5166 * completely clipped
5168 * Should be used only with raw buffers */
5170 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5173 guint64 start, stop, cstart, cstop, diff;
5174 GstClockTime pts, duration;
5176 gint num_rate, denom_rate;
5181 osize = size = gst_buffer_get_size (buf);
5184 /* depending on the type, setup the clip parameters */
5185 if (stream->subtype == FOURCC_soun) {
5186 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5187 num_rate = GST_SECOND;
5188 denom_rate = (gint) CUR_STREAM (stream)->rate;
5190 } else if (stream->subtype == FOURCC_vide) {
5192 num_rate = CUR_STREAM (stream)->fps_n;
5193 denom_rate = CUR_STREAM (stream)->fps_d;
5198 if (frame_size <= 0)
5199 goto bad_frame_size;
5201 /* we can only clip if we have a valid pts */
5202 pts = GST_BUFFER_PTS (buf);
5203 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5206 duration = GST_BUFFER_DURATION (buf);
5208 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5210 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5214 stop = start + duration;
5216 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5217 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5220 /* see if some clipping happened */
5221 diff = cstart - start;
5227 /* bring clipped time to samples and to bytes */
5228 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5231 GST_DEBUG_OBJECT (qtdemux,
5232 "clipping start to %" GST_TIME_FORMAT " %"
5233 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5239 diff = stop - cstop;
5244 /* bring clipped time to samples and then to bytes */
5245 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5247 GST_DEBUG_OBJECT (qtdemux,
5248 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5249 " bytes", GST_TIME_ARGS (cstop), diff);
5254 if (offset != 0 || size != osize)
5255 gst_buffer_resize (buf, offset, size);
5257 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5258 GST_BUFFER_PTS (buf) = pts;
5259 GST_BUFFER_DURATION (buf) = duration;
5263 /* dropped buffer */
5266 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5271 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5276 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5281 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5282 gst_buffer_unref (buf);
5288 gst_qtdemux_align_buffer (GstQTDemux * demux,
5289 GstBuffer * buffer, gsize alignment)
5293 gst_buffer_map (buffer, &map, GST_MAP_READ);
5295 if (map.size < sizeof (guintptr)) {
5296 gst_buffer_unmap (buffer, &map);
5300 if (((guintptr) map.data) & (alignment - 1)) {
5301 GstBuffer *new_buffer;
5302 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5304 new_buffer = gst_buffer_new_allocate (NULL,
5305 gst_buffer_get_size (buffer), ¶ms);
5307 /* Copy data "by hand", so ensure alignment is kept: */
5308 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5310 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5311 GST_DEBUG_OBJECT (demux,
5312 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5315 gst_buffer_unmap (buffer, &map);
5316 gst_buffer_unref (buffer);
5321 gst_buffer_unmap (buffer, &map);
5325 /* the input buffer metadata must be writable,
5326 * but time/duration etc not yet set and need not be preserved */
5328 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5335 /* not many cases for now */
5336 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5337 /* send a one time dvd clut event */
5338 if (stream->pending_event && stream->pad)
5339 gst_pad_push_event (stream->pad, stream->pending_event);
5340 stream->pending_event = NULL;
5343 if (G_UNLIKELY (stream->subtype != FOURCC_text
5344 && stream->subtype != FOURCC_sbtl &&
5345 stream->subtype != FOURCC_subp)) {
5349 gst_buffer_map (buf, &map, GST_MAP_READ);
5351 /* empty buffer is sent to terminate previous subtitle */
5352 if (map.size <= 2) {
5353 gst_buffer_unmap (buf, &map);
5354 gst_buffer_unref (buf);
5357 if (stream->subtype == FOURCC_subp) {
5358 /* That's all the processing needed for subpictures */
5359 gst_buffer_unmap (buf, &map);
5363 nsize = GST_READ_UINT16_BE (map.data);
5364 nsize = MIN (nsize, map.size - 2);
5366 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5369 /* takes care of UTF-8 validation or UTF-16 recognition,
5370 * no other encoding expected */
5371 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5372 gst_buffer_unmap (buf, &map);
5374 gst_buffer_unref (buf);
5375 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5377 /* this should not really happen unless the subtitle is corrupted */
5378 gst_buffer_unref (buf);
5382 /* FIXME ? convert optional subsequent style info to markup */
5387 /* Sets a buffer's attributes properly and pushes it downstream.
5388 * Also checks for additional actions and custom processing that may
5389 * need to be done first.
5391 static GstFlowReturn
5392 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5393 QtDemuxStream * stream, GstBuffer * buf,
5394 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5395 gboolean keyframe, GstClockTime position, guint64 byte_position)
5397 GstFlowReturn ret = GST_FLOW_OK;
5399 /* offset the timestamps according to the edit list */
5401 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5405 gst_buffer_map (buf, &map, GST_MAP_READ);
5406 url = g_strndup ((gchar *) map.data, map.size);
5407 gst_buffer_unmap (buf, &map);
5408 if (url != NULL && strlen (url) != 0) {
5409 /* we have RTSP redirect now */
5410 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5411 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5412 gst_structure_new ("redirect",
5413 "new-location", G_TYPE_STRING, url, NULL)));
5414 qtdemux->posted_redirect = TRUE;
5416 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5422 /* position reporting */
5423 if (qtdemux->segment.rate >= 0) {
5424 qtdemux->segment.position = position;
5425 gst_qtdemux_sync_streams (qtdemux);
5428 if (G_UNLIKELY (!stream->pad)) {
5429 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5430 gst_buffer_unref (buf);
5434 /* send out pending buffers */
5435 while (stream->buffers) {
5436 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5438 if (G_UNLIKELY (stream->discont)) {
5439 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5440 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5441 stream->discont = FALSE;
5443 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5446 if (stream->alignment > 1)
5447 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5448 gst_pad_push (stream->pad, buffer);
5450 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5453 /* we're going to modify the metadata */
5454 buf = gst_buffer_make_writable (buf);
5456 if (G_UNLIKELY (stream->need_process))
5457 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5463 GST_BUFFER_DTS (buf) = dts;
5464 GST_BUFFER_PTS (buf) = pts;
5465 GST_BUFFER_DURATION (buf) = duration;
5466 GST_BUFFER_OFFSET (buf) = -1;
5467 GST_BUFFER_OFFSET_END (buf) = -1;
5469 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5470 gst_buffer_append_memory (buf,
5471 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5473 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5474 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5477 if (G_UNLIKELY (qtdemux->element_index)) {
5478 GstClockTime stream_time;
5481 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5483 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5484 GST_LOG_OBJECT (qtdemux,
5485 "adding association %" GST_TIME_FORMAT "-> %"
5486 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5487 gst_index_add_association (qtdemux->element_index,
5489 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5490 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5491 GST_FORMAT_BYTES, byte_position, NULL);
5496 if (stream->need_clip)
5497 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5499 if (G_UNLIKELY (buf == NULL))
5502 if (G_UNLIKELY (stream->discont)) {
5503 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5504 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5505 stream->discont = FALSE;
5507 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5511 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5512 stream->on_keyframe = FALSE;
5514 stream->on_keyframe = TRUE;
5518 GST_LOG_OBJECT (qtdemux,
5519 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5520 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5521 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5522 GST_PAD_NAME (stream->pad));
5524 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5525 GstStructure *crypto_info;
5526 QtDemuxCencSampleSetInfo *info =
5527 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5531 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5532 gst_pad_push_event (stream->pad, event);
5535 if (info->crypto_info == NULL) {
5536 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5537 gst_buffer_unref (buf);
5541 /* The end of the crypto_info array matches our n_samples position,
5542 * so count backward from there */
5543 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5544 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5545 /* steal structure from array */
5546 crypto_info = g_ptr_array_index (info->crypto_info, index);
5547 g_ptr_array_index (info->crypto_info, index) = NULL;
5548 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5549 info->crypto_info->len);
5550 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5551 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5553 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5554 index, stream->sample_index);
5558 if (stream->alignment > 1)
5559 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5561 ret = gst_pad_push (stream->pad, buf);
5563 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5564 /* mark position in stream, we'll need this to know when to send GAP event */
5565 stream->segment.position = pts + duration;
5572 static const QtDemuxRandomAccessEntry *
5573 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5574 GstClockTime pos, gboolean after)
5576 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5577 guint n_entries = stream->n_ra_entries;
5580 /* we assume the table is sorted */
5581 for (i = 0; i < n_entries; ++i) {
5582 if (entries[i].ts > pos)
5586 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5587 * probably okay to assume that the index lists the very first fragment */
5594 return &entries[i - 1];
5598 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5600 const QtDemuxRandomAccessEntry *best_entry = NULL;
5603 GST_OBJECT_LOCK (qtdemux);
5605 g_assert (qtdemux->n_streams > 0);
5607 for (i = 0; i < qtdemux->n_streams; i++) {
5608 const QtDemuxRandomAccessEntry *entry;
5609 QtDemuxStream *stream;
5610 gboolean is_audio_or_video;
5612 stream = qtdemux->streams[i];
5614 g_free (stream->samples);
5615 stream->samples = NULL;
5616 stream->n_samples = 0;
5617 stream->stbl_index = -1; /* no samples have yet been parsed */
5618 stream->sample_index = -1;
5620 if (stream->protection_scheme_info) {
5621 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5622 if (stream->protection_scheme_type == FOURCC_cenc) {
5623 QtDemuxCencSampleSetInfo *info =
5624 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5625 if (info->crypto_info) {
5626 g_ptr_array_free (info->crypto_info, TRUE);
5627 info->crypto_info = NULL;
5632 if (stream->ra_entries == NULL)
5635 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5636 is_audio_or_video = TRUE;
5638 is_audio_or_video = FALSE;
5641 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5642 stream->time_position, !is_audio_or_video);
5644 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5645 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5647 stream->pending_seek = entry;
5649 /* decide position to jump to just based on audio/video tracks, not subs */
5650 if (!is_audio_or_video)
5653 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5657 if (best_entry == NULL) {
5658 GST_OBJECT_UNLOCK (qtdemux);
5662 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5663 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5664 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5665 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5667 qtdemux->moof_offset = best_entry->moof_offset;
5669 qtdemux_add_fragmented_samples (qtdemux);
5671 GST_OBJECT_UNLOCK (qtdemux);
5675 static GstFlowReturn
5676 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5678 GstFlowReturn ret = GST_FLOW_OK;
5679 GstBuffer *buf = NULL;
5680 QtDemuxStream *stream;
5681 GstClockTime min_time;
5683 GstClockTime dts = GST_CLOCK_TIME_NONE;
5684 GstClockTime pts = GST_CLOCK_TIME_NONE;
5685 GstClockTime duration = 0;
5686 gboolean keyframe = FALSE;
5687 guint sample_size = 0;
5693 gst_qtdemux_push_pending_newsegment (qtdemux);
5695 if (qtdemux->fragmented_seek_pending) {
5696 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5697 gst_qtdemux_do_fragmented_seek (qtdemux);
5698 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5699 qtdemux->fragmented_seek_pending = FALSE;
5702 /* Figure out the next stream sample to output, min_time is expressed in
5703 * global time and runs over the edit list segments. */
5704 min_time = G_MAXUINT64;
5706 for (i = 0; i < qtdemux->n_streams; i++) {
5707 GstClockTime position;
5709 stream = qtdemux->streams[i];
5710 position = stream->time_position;
5712 /* position of -1 is EOS */
5713 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5714 min_time = position;
5719 if (G_UNLIKELY (index == -1)) {
5720 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5724 /* check for segment end */
5725 if (G_UNLIKELY (qtdemux->segment.stop != -1
5726 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5727 || (qtdemux->segment.rate < 0
5728 && qtdemux->segment.start > min_time))
5729 && qtdemux->streams[index]->on_keyframe)) {
5730 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5731 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5735 /* gap events for subtitle streams */
5736 for (i = 0; i < qtdemux->n_streams; i++) {
5737 stream = qtdemux->streams[i];
5738 if (stream->pad && (stream->subtype == FOURCC_subp
5739 || stream->subtype == FOURCC_text
5740 || stream->subtype == FOURCC_sbtl)) {
5741 /* send one second gap events until the stream catches up */
5742 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5743 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5744 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5745 stream->segment.position + GST_SECOND < min_time) {
5747 gst_event_new_gap (stream->segment.position, GST_SECOND);
5748 gst_pad_push_event (stream->pad, gap);
5749 stream->segment.position += GST_SECOND;
5754 stream = qtdemux->streams[index];
5755 /* fetch info for the current sample of this stream */
5756 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5757 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5760 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
5761 if (stream->new_caps) {
5762 gst_qtdemux_configure_stream (qtdemux, stream);
5763 qtdemux_do_allocation (qtdemux, stream);
5766 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5767 if (G_UNLIKELY (qtdemux->
5768 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5769 if (stream->subtype == FOURCC_vide && !keyframe) {
5770 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5775 GST_DEBUG_OBJECT (qtdemux,
5776 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5777 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5778 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5779 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5781 if (G_UNLIKELY (empty)) {
5782 /* empty segment, push a gap and move to the next one */
5783 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5784 stream->segment.position = pts + duration;
5788 /* hmm, empty sample, skip and move to next sample */
5789 if (G_UNLIKELY (sample_size <= 0))
5792 /* last pushed sample was out of boundary, goto next sample */
5793 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5796 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5799 GST_DEBUG_OBJECT (qtdemux,
5800 "size %d larger than stream max_buffer_size %d, trimming",
5801 sample_size, stream->max_buffer_size);
5803 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5806 if (qtdemux->cenc_aux_info_offset > 0) {
5809 GstBuffer *aux_info = NULL;
5811 /* pull the data stored before the sample */
5813 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5814 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5815 if (G_UNLIKELY (ret != GST_FLOW_OK))
5817 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5818 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5819 gst_byte_reader_init (&br, map.data + 8, map.size);
5820 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5821 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5822 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5823 gst_buffer_unmap (aux_info, &map);
5824 gst_buffer_unref (aux_info);
5825 ret = GST_FLOW_ERROR;
5828 gst_buffer_unmap (aux_info, &map);
5829 gst_buffer_unref (aux_info);
5832 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5835 if (stream->use_allocator) {
5836 /* if we have a per-stream allocator, use it */
5837 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5840 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5842 if (G_UNLIKELY (ret != GST_FLOW_OK))
5845 if (size != sample_size) {
5846 pts += gst_util_uint64_scale_int (GST_SECOND,
5847 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5850 gst_util_uint64_scale_int (GST_SECOND,
5851 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5854 gst_util_uint64_scale_int (GST_SECOND,
5855 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
5858 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5859 dts, pts, duration, keyframe, min_time, offset);
5861 if (size != sample_size) {
5862 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5863 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5865 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5867 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
5868 if (time_position >= segment->media_start) {
5869 /* inside the segment, update time_position, looks very familiar to
5870 * GStreamer segments, doesn't it? */
5871 stream->time_position = (time_position - segment->media_start) +
5874 /* not yet in segment, time does not yet increment. This means
5875 * that we are still prerolling keyframes to the decoder so it can
5876 * decode the first sample of the segment. */
5877 stream->time_position = segment->time;
5882 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5883 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5884 * we have no more data for the pad to push */
5885 if (ret == GST_FLOW_EOS)
5888 stream->offset_in_sample += size;
5889 if (stream->offset_in_sample >= sample_size) {
5890 gst_qtdemux_advance_sample (qtdemux, stream);
5895 gst_qtdemux_advance_sample (qtdemux, stream);
5903 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5909 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5910 /* EOS will be raised if all are EOS */
5917 gst_qtdemux_loop (GstPad * pad)
5919 GstQTDemux *qtdemux;
5923 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5925 cur_offset = qtdemux->offset;
5926 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5927 cur_offset, qt_demux_state_string (qtdemux->state));
5929 switch (qtdemux->state) {
5930 case QTDEMUX_STATE_INITIAL:
5931 case QTDEMUX_STATE_HEADER:
5932 ret = gst_qtdemux_loop_state_header (qtdemux);
5934 case QTDEMUX_STATE_MOVIE:
5935 ret = gst_qtdemux_loop_state_movie (qtdemux);
5936 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5937 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5945 /* if something went wrong, pause */
5946 if (ret != GST_FLOW_OK)
5950 gst_object_unref (qtdemux);
5956 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5957 (NULL), ("streaming stopped, invalid state"));
5958 gst_pad_pause_task (pad);
5959 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5964 const gchar *reason = gst_flow_get_name (ret);
5966 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5968 gst_pad_pause_task (pad);
5970 /* fatal errors need special actions */
5972 if (ret == GST_FLOW_EOS) {
5973 if (qtdemux->n_streams == 0) {
5974 /* we have no streams, post an error */
5975 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5977 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5980 if ((stop = qtdemux->segment.stop) == -1)
5981 stop = qtdemux->segment.duration;
5983 if (qtdemux->segment.rate >= 0) {
5984 GstMessage *message;
5987 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5988 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5989 GST_FORMAT_TIME, stop);
5990 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5991 if (qtdemux->segment_seqnum) {
5992 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5993 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5995 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5996 gst_qtdemux_push_event (qtdemux, event);
5998 GstMessage *message;
6001 /* For Reverse Playback */
6002 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6003 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6004 GST_FORMAT_TIME, qtdemux->segment.start);
6005 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6006 qtdemux->segment.start);
6007 if (qtdemux->segment_seqnum) {
6008 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6009 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6011 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6012 gst_qtdemux_push_event (qtdemux, event);
6017 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6018 event = gst_event_new_eos ();
6019 if (qtdemux->segment_seqnum)
6020 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6021 gst_qtdemux_push_event (qtdemux, event);
6023 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6024 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6025 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6034 * Returns if there are samples to be played.
6037 has_next_entry (GstQTDemux * demux)
6039 QtDemuxStream *stream;
6042 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6044 for (i = 0; i < demux->n_streams; i++) {
6045 stream = demux->streams[i];
6047 if (stream->sample_index == -1) {
6048 stream->sample_index = 0;
6049 stream->offset_in_sample = 0;
6052 if (stream->sample_index >= stream->n_samples) {
6053 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6056 GST_DEBUG_OBJECT (demux, "Found a sample");
6060 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6067 * Returns the size of the first entry at the current offset.
6068 * If -1, there are none (which means EOS or empty file).
6071 next_entry_size (GstQTDemux * demux)
6073 QtDemuxStream *stream;
6076 guint64 smalloffs = (guint64) - 1;
6077 QtDemuxSample *sample;
6079 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6082 for (i = 0; i < demux->n_streams; i++) {
6083 stream = demux->streams[i];
6085 if (stream->sample_index == -1) {
6086 stream->sample_index = 0;
6087 stream->offset_in_sample = 0;
6090 if (stream->sample_index >= stream->n_samples) {
6091 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6095 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6096 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6097 stream->sample_index);
6101 sample = &stream->samples[stream->sample_index];
6103 GST_LOG_OBJECT (demux,
6104 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6105 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6106 sample->offset, sample->size);
6108 if (((smalloffs == -1)
6109 || (sample->offset < smalloffs)) && (sample->size)) {
6111 smalloffs = sample->offset;
6115 GST_LOG_OBJECT (demux,
6116 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6117 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6122 stream = demux->streams[smallidx];
6123 sample = &stream->samples[stream->sample_index];
6125 if (sample->offset >= demux->offset) {
6126 demux->todrop = sample->offset - demux->offset;
6127 return sample->size + demux->todrop;
6130 GST_DEBUG_OBJECT (demux,
6131 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6136 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6138 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6140 gst_element_post_message (GST_ELEMENT_CAST (demux),
6141 gst_message_new_element (GST_OBJECT_CAST (demux),
6142 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6146 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6151 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6154 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6155 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6156 GST_SEEK_TYPE_NONE, -1);
6158 /* store seqnum to drop flush events, they don't need to reach downstream */
6159 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6160 res = gst_pad_push_event (demux->sinkpad, event);
6161 demux->offset_seek_seqnum = 0;
6166 /* check for seekable upstream, above and beyond a mere query */
6168 gst_qtdemux_check_seekability (GstQTDemux * demux)
6171 gboolean seekable = FALSE;
6172 gint64 start = -1, stop = -1;
6174 if (demux->upstream_size)
6177 if (demux->upstream_format_is_time)
6180 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6181 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6182 GST_DEBUG_OBJECT (demux, "seeking query failed");
6186 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6188 /* try harder to query upstream size if we didn't get it the first time */
6189 if (seekable && stop == -1) {
6190 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6191 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6194 /* if upstream doesn't know the size, it's likely that it's not seekable in
6195 * practice even if it technically may be seekable */
6196 if (seekable && (start != 0 || stop <= start)) {
6197 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6202 gst_query_unref (query);
6204 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6205 G_GUINT64_FORMAT ")", seekable, start, stop);
6206 demux->upstream_seekable = seekable;
6207 demux->upstream_size = seekable ? stop : -1;
6211 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6213 g_return_if_fail (bytes <= demux->todrop);
6215 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6216 gst_adapter_flush (demux->adapter, bytes);
6217 demux->neededbytes -= bytes;
6218 demux->offset += bytes;
6219 demux->todrop -= bytes;
6223 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6225 if (G_UNLIKELY (demux->pending_newsegment)) {
6228 gst_qtdemux_push_pending_newsegment (demux);
6229 /* clear to send tags on all streams */
6230 for (i = 0; i < demux->n_streams; i++) {
6231 QtDemuxStream *stream;
6232 stream = demux->streams[i];
6233 gst_qtdemux_push_tags (demux, stream);
6234 if (CUR_STREAM (stream)->sparse) {
6235 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6236 gst_pad_push_event (stream->pad,
6237 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6244 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6245 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6247 GstClockTime ts, dur;
6252 stream->segments[segment_index].duration - (pos -
6253 stream->segments[segment_index].time);
6254 gap = gst_event_new_gap (ts, dur);
6255 stream->time_position += dur;
6257 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6258 "segment: %" GST_PTR_FORMAT, gap);
6259 gst_pad_push_event (stream->pad, gap);
6263 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6264 QtDemuxStream * stream)
6268 /* Push any initial gap segments before proceeding to the
6270 for (i = 0; i < stream->n_segments; i++) {
6271 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6273 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6274 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6275 stream->time_position);
6277 /* Only support empty segment at the beginning followed by
6278 * one non-empty segment, this was checked when parsing the
6279 * edts atom, arriving here is unexpected */
6280 g_assert (i + 1 == stream->n_segments);
6286 static GstFlowReturn
6287 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6291 demux = GST_QTDEMUX (parent);
6293 GST_DEBUG_OBJECT (demux,
6294 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6295 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6296 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6297 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6298 gst_buffer_get_size (inbuf), demux->offset);
6300 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6301 gboolean is_gap_input = FALSE;
6304 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6306 for (i = 0; i < demux->n_streams; i++) {
6307 demux->streams[i]->discont = TRUE;
6310 /* Check if we can land back on our feet in the case where upstream is
6311 * handling the seeking/pushing of samples with gaps in between (like
6312 * in the case of trick-mode DASH for example) */
6313 if (demux->upstream_format_is_time
6314 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6316 for (i = 0; i < demux->n_streams; i++) {
6318 GST_LOG_OBJECT (demux,
6319 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6320 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6322 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6323 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6325 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6326 GST_LOG_OBJECT (demux,
6327 "Checking if sample %d from stream %d is valid (offset:%"
6328 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6329 sample->offset, sample->size);
6330 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6331 GST_LOG_OBJECT (demux,
6332 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6334 is_gap_input = TRUE;
6335 /* We can go back to standard playback mode */
6336 demux->state = QTDEMUX_STATE_MOVIE;
6337 /* Remember which sample this stream is at */
6338 demux->streams[i]->sample_index = res;
6339 /* Finally update all push-based values to the expected values */
6340 demux->neededbytes = demux->streams[i]->samples[res].size;
6341 demux->offset = GST_BUFFER_OFFSET (inbuf);
6343 demux->mdatsize - demux->offset + demux->mdatoffset;
6348 if (!is_gap_input) {
6349 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6350 /* Reset state if it's a real discont */
6351 demux->neededbytes = 16;
6352 demux->state = QTDEMUX_STATE_INITIAL;
6353 demux->offset = GST_BUFFER_OFFSET (inbuf);
6354 gst_adapter_clear (demux->adapter);
6357 /* Reverse fragmented playback, need to flush all we have before
6358 * consuming a new fragment.
6359 * The samples array have the timestamps calculated by accumulating the
6360 * durations but this won't work for reverse playback of fragments as
6361 * the timestamps of a subsequent fragment should be smaller than the
6362 * previously received one. */
6363 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6364 gst_qtdemux_process_adapter (demux, TRUE);
6365 for (i = 0; i < demux->n_streams; i++)
6366 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6370 gst_adapter_push (demux->adapter, inbuf);
6372 GST_DEBUG_OBJECT (demux,
6373 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6374 demux->neededbytes, gst_adapter_available (demux->adapter));
6376 return gst_qtdemux_process_adapter (demux, FALSE);
6379 static GstFlowReturn
6380 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6382 GstFlowReturn ret = GST_FLOW_OK;
6384 /* we never really mean to buffer that much */
6385 if (demux->neededbytes == -1) {
6389 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6390 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6392 #ifndef GST_DISABLE_GST_DEBUG
6394 guint64 discont_offset, distance_from_discont;
6396 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6397 distance_from_discont =
6398 gst_adapter_distance_from_discont (demux->adapter);
6400 GST_DEBUG_OBJECT (demux,
6401 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6402 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6403 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6404 demux->offset, discont_offset, distance_from_discont);
6408 switch (demux->state) {
6409 case QTDEMUX_STATE_INITIAL:{
6414 gst_qtdemux_check_seekability (demux);
6416 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6418 /* get fourcc/length, set neededbytes */
6419 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6421 gst_adapter_unmap (demux->adapter);
6423 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6424 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6426 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6427 (_("This file is invalid and cannot be played.")),
6428 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6429 GST_FOURCC_ARGS (fourcc)));
6430 ret = GST_FLOW_ERROR;
6433 if (fourcc == FOURCC_mdat) {
6434 gint next_entry = next_entry_size (demux);
6435 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6436 /* we have the headers, start playback */
6437 demux->state = QTDEMUX_STATE_MOVIE;
6438 demux->neededbytes = next_entry;
6439 demux->mdatleft = size;
6440 demux->mdatsize = demux->mdatleft;
6442 /* no headers yet, try to get them */
6445 guint64 old, target;
6448 old = demux->offset;
6449 target = old + size;
6451 /* try to jump over the atom with a seek */
6452 /* only bother if it seems worth doing so,
6453 * and avoids possible upstream/server problems */
6454 if (demux->upstream_seekable &&
6455 demux->upstream_size > 4 * (1 << 20)) {
6456 res = qtdemux_seek_offset (demux, target);
6458 GST_DEBUG_OBJECT (demux, "skipping seek");
6463 GST_DEBUG_OBJECT (demux, "seek success");
6464 /* remember the offset fo the first mdat so we can seek back to it
6465 * after we have the headers */
6466 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6467 demux->first_mdat = old;
6468 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6471 /* seek worked, continue reading */
6472 demux->offset = target;
6473 demux->neededbytes = 16;
6474 demux->state = QTDEMUX_STATE_INITIAL;
6476 /* seek failed, need to buffer */
6477 demux->offset = old;
6478 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6479 /* there may be multiple mdat (or alike) buffers */
6481 if (demux->mdatbuffer)
6482 bs = gst_buffer_get_size (demux->mdatbuffer);
6485 if (size + bs > 10 * (1 << 20))
6487 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6488 demux->neededbytes = size;
6489 if (!demux->mdatbuffer)
6490 demux->mdatoffset = demux->offset;
6493 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6494 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6495 (_("This file is invalid and cannot be played.")),
6496 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6497 GST_FOURCC_ARGS (fourcc), size));
6498 ret = GST_FLOW_ERROR;
6501 /* this means we already started buffering and still no moov header,
6502 * let's continue buffering everything till we get moov */
6503 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6504 || fourcc == FOURCC_moof))
6506 demux->neededbytes = size;
6507 demux->state = QTDEMUX_STATE_HEADER;
6511 case QTDEMUX_STATE_HEADER:{
6515 GST_DEBUG_OBJECT (demux, "In header");
6517 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6519 /* parse the header */
6520 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6522 if (fourcc == FOURCC_moov) {
6525 /* in usual fragmented setup we could try to scan for more
6526 * and end up at the the moov (after mdat) again */
6527 if (demux->got_moov && demux->n_streams > 0 &&
6529 || demux->last_moov_offset == demux->offset)) {
6530 GST_DEBUG_OBJECT (demux,
6531 "Skipping moov atom as we have (this) one already");
6533 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6535 if (demux->got_moov && demux->fragmented) {
6536 GST_DEBUG_OBJECT (demux,
6537 "Got a second moov, clean up data from old one");
6538 if (demux->moov_node_compressed) {
6539 g_node_destroy (demux->moov_node_compressed);
6540 if (demux->moov_node)
6541 g_free (demux->moov_node->data);
6543 demux->moov_node_compressed = NULL;
6544 if (demux->moov_node)
6545 g_node_destroy (demux->moov_node);
6546 demux->moov_node = NULL;
6548 /* prepare newsegment to send when streaming actually starts */
6549 if (!demux->pending_newsegment) {
6550 demux->pending_newsegment =
6551 gst_event_new_segment (&demux->segment);
6552 if (demux->segment_seqnum)
6553 gst_event_set_seqnum (demux->pending_newsegment,
6554 demux->segment_seqnum);
6558 demux->last_moov_offset = demux->offset;
6560 qtdemux_parse_moov (demux, data, demux->neededbytes);
6561 qtdemux_node_dump (demux, demux->moov_node);
6562 qtdemux_parse_tree (demux);
6563 qtdemux_prepare_streams (demux);
6564 if (!demux->got_moov)
6565 qtdemux_expose_streams (demux);
6568 for (n = 0; n < demux->n_streams; n++) {
6569 QtDemuxStream *stream = demux->streams[n];
6571 gst_qtdemux_configure_stream (demux, stream);
6575 demux->got_moov = TRUE;
6576 gst_qtdemux_check_send_pending_segment (demux);
6578 /* fragmented streams headers shouldn't contain edts atoms */
6579 if (!demux->fragmented) {
6580 for (n = 0; n < demux->n_streams; n++) {
6581 gst_qtdemux_stream_send_initial_gap_segments (demux,
6586 if (demux->moov_node_compressed) {
6587 g_node_destroy (demux->moov_node_compressed);
6588 g_free (demux->moov_node->data);
6590 demux->moov_node_compressed = NULL;
6591 g_node_destroy (demux->moov_node);
6592 demux->moov_node = NULL;
6593 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6595 } else if (fourcc == FOURCC_moof) {
6596 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6598 GstClockTime prev_pts;
6599 guint64 prev_offset;
6600 guint64 adapter_discont_offset, adapter_discont_dist;
6602 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6605 * The timestamp of the moof buffer is relevant as some scenarios
6606 * won't have the initial timestamp in the atoms. Whenever a new
6607 * buffer has started, we get that buffer's PTS and use it as a base
6608 * timestamp for the trun entries.
6610 * To keep track of the current buffer timestamp and starting point
6611 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6612 * from the beggining of the buffer, with the distance and demux->offset
6613 * we know if it is still the same buffer or not.
6615 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6616 prev_offset = demux->offset - dist;
6617 if (demux->fragment_start_offset == -1
6618 || prev_offset > demux->fragment_start_offset) {
6619 demux->fragment_start_offset = prev_offset;
6620 demux->fragment_start = prev_pts;
6621 GST_DEBUG_OBJECT (demux,
6622 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6623 GST_TIME_FORMAT, demux->fragment_start_offset,
6624 GST_TIME_ARGS (demux->fragment_start));
6627 /* We can't use prev_offset() here because this would require
6628 * upstream to set consistent and correct offsets on all buffers
6629 * since the discont. Nothing ever did that in the past and we
6630 * would break backwards compatibility here then.
6631 * Instead take the offset we had at the last discont and count
6632 * the bytes from there. This works with old code as there would
6633 * be no discont between moov and moof, and also works with
6634 * adaptivedemux which correctly sets offset and will set the
6635 * DISCONT flag accordingly when needed.
6637 * We also only do this for upstream TIME segments as otherwise
6638 * there are potential backwards compatibility problems with
6639 * seeking in PUSH mode and upstream providing inconsistent
6641 adapter_discont_offset =
6642 gst_adapter_offset_at_discont (demux->adapter);
6643 adapter_discont_dist =
6644 gst_adapter_distance_from_discont (demux->adapter);
6646 GST_DEBUG_OBJECT (demux,
6647 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6648 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6649 demux->offset, adapter_discont_offset, adapter_discont_dist);
6651 if (demux->upstream_format_is_time) {
6652 demux->moof_offset = adapter_discont_offset;
6653 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6654 demux->moof_offset += adapter_discont_dist;
6655 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6656 demux->moof_offset = demux->offset;
6658 demux->moof_offset = demux->offset;
6661 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6662 demux->moof_offset, NULL)) {
6663 gst_adapter_unmap (demux->adapter);
6664 ret = GST_FLOW_ERROR;
6667 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6668 if (demux->mss_mode && !demux->exposed) {
6669 if (!demux->pending_newsegment) {
6670 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6671 demux->pending_newsegment =
6672 gst_event_new_segment (&demux->segment);
6673 if (demux->segment_seqnum)
6674 gst_event_set_seqnum (demux->pending_newsegment,
6675 demux->segment_seqnum);
6677 qtdemux_expose_streams (demux);
6680 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6682 } else if (fourcc == FOURCC_ftyp) {
6683 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6684 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6685 } else if (fourcc == FOURCC_uuid) {
6686 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6687 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6688 } else if (fourcc == FOURCC_sidx) {
6689 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6690 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6694 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6698 /* [free] and [skip] are padding atoms */
6699 GST_DEBUG_OBJECT (demux,
6700 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6701 GST_FOURCC_ARGS (fourcc));
6704 GST_WARNING_OBJECT (demux,
6705 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6706 GST_FOURCC_ARGS (fourcc));
6707 /* Let's jump that one and go back to initial state */
6711 gst_adapter_unmap (demux->adapter);
6714 if (demux->mdatbuffer && demux->n_streams) {
6715 gsize remaining_data_size = 0;
6717 /* the mdat was before the header */
6718 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6719 demux->n_streams, demux->mdatbuffer);
6720 /* restore our adapter/offset view of things with upstream;
6721 * put preceding buffered data ahead of current moov data.
6722 * This should also handle evil mdat, moov, mdat cases and alike */
6723 gst_adapter_flush (demux->adapter, demux->neededbytes);
6725 /* Store any remaining data after the mdat for later usage */
6726 remaining_data_size = gst_adapter_available (demux->adapter);
6727 if (remaining_data_size > 0) {
6728 g_assert (demux->restoredata_buffer == NULL);
6729 demux->restoredata_buffer =
6730 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6731 demux->restoredata_offset = demux->offset + demux->neededbytes;
6732 GST_DEBUG_OBJECT (demux,
6733 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6734 G_GUINT64_FORMAT, remaining_data_size,
6735 demux->restoredata_offset);
6738 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6739 demux->mdatbuffer = NULL;
6740 demux->offset = demux->mdatoffset;
6741 demux->neededbytes = next_entry_size (demux);
6742 demux->state = QTDEMUX_STATE_MOVIE;
6743 demux->mdatleft = gst_adapter_available (demux->adapter);
6744 demux->mdatsize = demux->mdatleft;
6746 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6747 gst_adapter_flush (demux->adapter, demux->neededbytes);
6749 /* only go back to the mdat if there are samples to play */
6750 if (demux->got_moov && demux->first_mdat != -1
6751 && has_next_entry (demux)) {
6754 /* we need to seek back */
6755 res = qtdemux_seek_offset (demux, demux->first_mdat);
6757 demux->offset = demux->first_mdat;
6759 GST_DEBUG_OBJECT (demux, "Seek back failed");
6762 demux->offset += demux->neededbytes;
6764 demux->neededbytes = 16;
6765 demux->state = QTDEMUX_STATE_INITIAL;
6770 case QTDEMUX_STATE_BUFFER_MDAT:{
6774 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6776 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6777 gst_buffer_extract (buf, 0, fourcc, 4);
6778 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6779 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6780 if (demux->mdatbuffer)
6781 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6783 demux->mdatbuffer = buf;
6784 demux->offset += demux->neededbytes;
6785 demux->neededbytes = 16;
6786 demux->state = QTDEMUX_STATE_INITIAL;
6787 gst_qtdemux_post_progress (demux, 1, 1);
6791 case QTDEMUX_STATE_MOVIE:{
6792 QtDemuxStream *stream = NULL;
6793 QtDemuxSample *sample;
6795 GstClockTime dts, pts, duration;
6798 GST_DEBUG_OBJECT (demux,
6799 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6801 if (demux->fragmented) {
6802 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6804 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6805 /* if needed data starts within this atom,
6806 * then it should not exceed this atom */
6807 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6808 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6809 (_("This file is invalid and cannot be played.")),
6810 ("sample data crosses atom boundary"));
6811 ret = GST_FLOW_ERROR;
6814 demux->mdatleft -= demux->neededbytes;
6816 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6817 /* so we are dropping more than left in this atom */
6818 gst_qtdemux_drop_data (demux, demux->mdatleft);
6819 demux->mdatleft = 0;
6821 /* need to resume atom parsing so we do not miss any other pieces */
6822 demux->state = QTDEMUX_STATE_INITIAL;
6823 demux->neededbytes = 16;
6825 /* check if there was any stored post mdat data from previous buffers */
6826 if (demux->restoredata_buffer) {
6827 g_assert (gst_adapter_available (demux->adapter) == 0);
6829 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6830 demux->restoredata_buffer = NULL;
6831 demux->offset = demux->restoredata_offset;
6838 if (demux->todrop) {
6839 if (demux->cenc_aux_info_offset > 0) {
6843 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6844 data = gst_adapter_map (demux->adapter, demux->todrop);
6845 gst_byte_reader_init (&br, data + 8, demux->todrop);
6846 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6847 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6848 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6849 ret = GST_FLOW_ERROR;
6850 gst_adapter_unmap (demux->adapter);
6851 g_free (demux->cenc_aux_info_sizes);
6852 demux->cenc_aux_info_sizes = NULL;
6855 demux->cenc_aux_info_offset = 0;
6856 g_free (demux->cenc_aux_info_sizes);
6857 demux->cenc_aux_info_sizes = NULL;
6858 gst_adapter_unmap (demux->adapter);
6860 gst_qtdemux_drop_data (demux, demux->todrop);
6864 /* initial newsegment sent here after having added pads,
6865 * possible others in sink_event */
6866 gst_qtdemux_check_send_pending_segment (demux);
6868 /* Figure out which stream this packet belongs to */
6869 for (i = 0; i < demux->n_streams; i++) {
6870 stream = demux->streams[i];
6871 if (stream->sample_index >= stream->n_samples)
6873 GST_LOG_OBJECT (demux,
6874 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6875 " / size:%d)", i, stream->sample_index,
6876 stream->samples[stream->sample_index].offset,
6877 stream->samples[stream->sample_index].size);
6879 if (stream->samples[stream->sample_index].offset == demux->offset)
6883 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6884 goto unknown_stream;
6886 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
6888 if (stream->new_caps) {
6889 gst_qtdemux_configure_stream (demux, stream);
6892 /* Put data in a buffer, set timestamps, caps, ... */
6893 sample = &stream->samples[stream->sample_index];
6895 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6896 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6897 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
6899 dts = QTSAMPLE_DTS (stream, sample);
6900 pts = QTSAMPLE_PTS (stream, sample);
6901 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6902 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6904 /* check for segment end */
6905 if (G_UNLIKELY (demux->segment.stop != -1
6906 && demux->segment.stop <= pts && stream->on_keyframe)) {
6907 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6908 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6910 /* skip this data, stream is EOS */
6911 gst_adapter_flush (demux->adapter, demux->neededbytes);
6912 demux->offset += demux->neededbytes;
6914 /* check if all streams are eos */
6916 for (i = 0; i < demux->n_streams; i++) {
6917 if (!STREAM_IS_EOS (demux->streams[i])) {
6926 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6928 /* FIXME: should either be an assert or a plain check */
6929 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6931 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6932 dts, pts, duration, keyframe, dts, demux->offset);
6936 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6938 /* skip this data, stream is EOS */
6939 gst_adapter_flush (demux->adapter, demux->neededbytes);
6942 stream->sample_index++;
6943 stream->offset_in_sample = 0;
6945 /* update current offset and figure out size of next buffer */
6946 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6947 demux->offset, demux->neededbytes);
6948 demux->offset += demux->neededbytes;
6949 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6953 if (ret == GST_FLOW_EOS) {
6954 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6955 demux->neededbytes = -1;
6959 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6960 if (demux->fragmented) {
6961 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6962 /* there may be more to follow, only finish this atom */
6963 demux->todrop = demux->mdatleft;
6964 demux->neededbytes = demux->todrop;
6969 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
6970 goto non_ok_unlinked_flow;
6979 /* when buffering movie data, at least show user something is happening */
6980 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6981 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6982 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6983 demux->neededbytes);
6990 non_ok_unlinked_flow:
6992 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6993 gst_flow_get_name (ret));
6998 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6999 ret = GST_FLOW_ERROR;
7004 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7010 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7011 (NULL), ("qtdemuxer invalid state %d", demux->state));
7012 ret = GST_FLOW_ERROR;
7017 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7018 (NULL), ("no 'moov' atom within the first 10 MB"));
7019 ret = GST_FLOW_ERROR;
7025 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7030 query = gst_query_new_scheduling ();
7032 if (!gst_pad_peer_query (sinkpad, query)) {
7033 gst_query_unref (query);
7037 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7038 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7039 gst_query_unref (query);
7044 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7045 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7049 GST_DEBUG_OBJECT (sinkpad, "activating push");
7050 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7055 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7056 GstPadMode mode, gboolean active)
7059 GstQTDemux *demux = GST_QTDEMUX (parent);
7062 case GST_PAD_MODE_PUSH:
7063 demux->pullbased = FALSE;
7066 case GST_PAD_MODE_PULL:
7068 demux->pullbased = TRUE;
7069 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7072 res = gst_pad_stop_task (sinkpad);
7084 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7090 memset (&z, 0, sizeof (z));
7095 if ((ret = inflateInit (&z)) != Z_OK) {
7096 GST_ERROR ("inflateInit() returned %d", ret);
7100 z.next_in = z_buffer;
7101 z.avail_in = z_length;
7103 buffer = (guint8 *) g_malloc (*length);
7104 z.avail_out = *length;
7105 z.next_out = (Bytef *) buffer;
7107 ret = inflate (&z, Z_NO_FLUSH);
7108 if (ret == Z_STREAM_END) {
7110 } else if (ret != Z_OK) {
7111 GST_WARNING ("inflate() returned %d", ret);
7116 buffer = (guint8 *) g_realloc (buffer, *length);
7117 z.next_out = (Bytef *) (buffer + z.total_out);
7118 z.avail_out += 4096;
7119 } while (z.avail_in > 0);
7121 if (ret != Z_STREAM_END) {
7126 *length = z.total_out;
7133 #endif /* HAVE_ZLIB */
7136 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7140 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7142 /* counts as header data */
7143 qtdemux->header_size += length;
7145 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7146 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7148 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7155 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7156 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7157 if (dcom == NULL || cmvd == NULL)
7158 goto invalid_compression;
7160 dcom_len = QT_UINT32 (dcom->data);
7162 goto invalid_compression;
7164 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7168 guint uncompressed_length;
7169 guint compressed_length;
7173 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7175 goto invalid_compression;
7177 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7178 compressed_length = cmvd_len - 12;
7179 GST_LOG ("length = %u", uncompressed_length);
7182 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7183 compressed_length, &uncompressed_length);
7186 qtdemux->moov_node_compressed = qtdemux->moov_node;
7187 qtdemux->moov_node = g_node_new (buf);
7189 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7190 uncompressed_length);
7194 #endif /* HAVE_ZLIB */
7196 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7197 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7204 invalid_compression:
7206 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7212 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7215 while (G_UNLIKELY (buf < end)) {
7219 if (G_UNLIKELY (buf + 4 > end)) {
7220 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7223 len = QT_UINT32 (buf);
7224 if (G_UNLIKELY (len == 0)) {
7225 GST_LOG_OBJECT (qtdemux, "empty container");
7228 if (G_UNLIKELY (len < 8)) {
7229 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7232 if (G_UNLIKELY (len > (end - buf))) {
7233 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7234 (gint) (end - buf));
7238 child = g_node_new ((guint8 *) buf);
7239 g_node_append (node, child);
7240 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7241 qtdemux_parse_node (qtdemux, child, buf, len);
7249 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7252 int len = QT_UINT32 (xdxt->data);
7253 guint8 *buf = xdxt->data;
7254 guint8 *end = buf + len;
7257 /* skip size and type */
7265 size = QT_UINT32 (buf);
7266 type = QT_FOURCC (buf + 4);
7268 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7270 if (buf + size > end || size <= 0)
7276 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7277 GST_FOURCC_ARGS (type));
7281 buffer = gst_buffer_new_and_alloc (size);
7282 gst_buffer_fill (buffer, 0, buf, size);
7283 stream->buffers = g_slist_append (stream->buffers, buffer);
7284 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7287 buffer = gst_buffer_new_and_alloc (size);
7288 gst_buffer_fill (buffer, 0, buf, size);
7289 stream->buffers = g_slist_append (stream->buffers, buffer);
7290 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7293 buffer = gst_buffer_new_and_alloc (size);
7294 gst_buffer_fill (buffer, 0, buf, size);
7295 stream->buffers = g_slist_append (stream->buffers, buffer);
7296 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7299 GST_WARNING_OBJECT (qtdemux,
7300 "unknown theora cookie %" GST_FOURCC_FORMAT,
7301 GST_FOURCC_ARGS (type));
7310 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7314 guint32 node_length = 0;
7315 const QtNodeType *type;
7318 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7320 if (G_UNLIKELY (length < 8))
7321 goto not_enough_data;
7323 node_length = QT_UINT32 (buffer);
7324 fourcc = QT_FOURCC (buffer + 4);
7326 /* ignore empty nodes */
7327 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7330 type = qtdemux_type_get (fourcc);
7332 end = buffer + length;
7334 GST_LOG_OBJECT (qtdemux,
7335 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7336 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7338 if (node_length > length)
7339 goto broken_atom_size;
7341 if (type->flags & QT_FLAG_CONTAINER) {
7342 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7347 if (node_length < 20) {
7348 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7351 GST_DEBUG_OBJECT (qtdemux,
7352 "parsing stsd (sample table, sample description) atom");
7353 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7354 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7365 /* also read alac (or whatever) in stead of mp4a in the following,
7366 * since a similar layout is used in other cases as well */
7367 if (fourcc == FOURCC_mp4a)
7369 else if (fourcc == FOURCC_fLaC)
7374 /* There are two things we might encounter here: a true mp4a atom, and
7375 an mp4a entry in an stsd atom. The latter is what we're interested
7376 in, and it looks like an atom, but isn't really one. The true mp4a
7377 atom is short, so we detect it based on length here. */
7378 if (length < min_size) {
7379 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7380 GST_FOURCC_ARGS (fourcc));
7384 /* 'version' here is the sound sample description version. Types 0 and
7385 1 are documented in the QTFF reference, but type 2 is not: it's
7386 described in Apple header files instead (struct SoundDescriptionV2
7388 version = QT_UINT16 (buffer + 16);
7390 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7391 GST_FOURCC_ARGS (fourcc), version);
7393 /* parse any esds descriptors */
7405 GST_WARNING_OBJECT (qtdemux,
7406 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7407 GST_FOURCC_ARGS (fourcc), version);
7412 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7438 /* codec_data is contained inside these atoms, which all have
7439 * the same format. */
7440 /* video sample description size is 86 bytes without extension.
7441 * node_length have to be bigger than 86 bytes because video sample
7442 * description can include extenstions such as esds, fiel, glbl, etc. */
7443 if (node_length < 86) {
7444 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7445 " sample description length too short (%u < 86)",
7446 GST_FOURCC_ARGS (fourcc), node_length);
7450 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7451 GST_FOURCC_ARGS (fourcc));
7453 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7455 * revision level (2 bytes) : must be set to 0. */
7456 version = QT_UINT32 (buffer + 16);
7457 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7459 /* compressor name : PASCAL string and informative purposes
7460 * first byte : the number of bytes to be displayed.
7461 * it has to be less than 32 because it is reserved
7462 * space of 32 bytes total including itself. */
7463 str_len = QT_UINT8 (buffer + 50);
7465 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7466 (char *) buffer + 51);
7468 GST_WARNING_OBJECT (qtdemux,
7469 "compressorname length too big (%u > 31)", str_len);
7471 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7473 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7478 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7479 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7484 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7485 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7486 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7495 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7496 GST_FOURCC_ARGS (fourcc));
7500 version = QT_UINT32 (buffer + 12);
7501 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7508 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7513 if (length < offset) {
7514 GST_WARNING_OBJECT (qtdemux,
7515 "skipping too small %" GST_FOURCC_FORMAT " box",
7516 GST_FOURCC_ARGS (fourcc));
7519 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7525 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7530 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7535 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7539 if (!strcmp (type->name, "unknown"))
7540 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7544 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7545 GST_FOURCC_ARGS (fourcc));
7551 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7552 (_("This file is corrupt and cannot be played.")),
7553 ("Not enough data for an atom header, got only %u bytes", length));
7558 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7559 (_("This file is corrupt and cannot be played.")),
7560 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7561 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7568 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7572 guint32 child_fourcc;
7574 for (child = g_node_first_child (node); child;
7575 child = g_node_next_sibling (child)) {
7576 buffer = (guint8 *) child->data;
7578 child_fourcc = QT_FOURCC (buffer + 4);
7580 if (G_UNLIKELY (child_fourcc == fourcc)) {
7588 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7589 GstByteReader * parser)
7593 guint32 child_fourcc, child_len;
7595 for (child = g_node_first_child (node); child;
7596 child = g_node_next_sibling (child)) {
7597 buffer = (guint8 *) child->data;
7599 child_len = QT_UINT32 (buffer);
7600 child_fourcc = QT_FOURCC (buffer + 4);
7602 if (G_UNLIKELY (child_fourcc == fourcc)) {
7603 if (G_UNLIKELY (child_len < (4 + 4)))
7605 /* FIXME: must verify if atom length < parent atom length */
7606 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7614 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7616 return g_node_nth_child (node, index);
7620 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7621 GstByteReader * parser)
7625 guint32 child_fourcc, child_len;
7627 for (child = g_node_next_sibling (node); child;
7628 child = g_node_next_sibling (child)) {
7629 buffer = (guint8 *) child->data;
7631 child_fourcc = QT_FOURCC (buffer + 4);
7633 if (child_fourcc == fourcc) {
7635 child_len = QT_UINT32 (buffer);
7636 if (G_UNLIKELY (child_len < (4 + 4)))
7638 /* FIXME: must verify if atom length < parent atom length */
7639 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7648 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7650 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7654 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7656 /* FIXME: This can only reliably work if demuxers have a
7657 * separate streaming thread per srcpad. This should be
7658 * done in a demuxer base class, which integrates parts
7661 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7666 query = gst_query_new_allocation (stream->caps, FALSE);
7668 if (!gst_pad_peer_query (stream->pad, query)) {
7669 /* not a problem, just debug a little */
7670 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7673 if (stream->allocator)
7674 gst_object_unref (stream->allocator);
7676 if (gst_query_get_n_allocation_params (query) > 0) {
7677 /* try the allocator */
7678 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7680 stream->use_allocator = TRUE;
7682 stream->allocator = NULL;
7683 gst_allocation_params_init (&stream->params);
7684 stream->use_allocator = FALSE;
7686 gst_query_unref (query);
7691 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7692 QtDemuxStream * stream)
7695 const gchar *selected_system;
7697 g_return_val_if_fail (qtdemux != NULL, FALSE);
7698 g_return_val_if_fail (stream != NULL, FALSE);
7699 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
7702 if (stream->protection_scheme_type != FOURCC_cenc) {
7703 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7706 if (qtdemux->protection_system_ids == NULL) {
7707 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7708 "cenc protection system information has been found");
7711 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7712 selected_system = gst_protection_select_system ((const gchar **)
7713 qtdemux->protection_system_ids->pdata);
7714 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7715 qtdemux->protection_system_ids->len - 1);
7716 if (!selected_system) {
7717 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7718 "suitable decryptor element has been found");
7722 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
7723 if (!gst_structure_has_name (s, "application/x-cenc")) {
7724 gst_structure_set (s,
7725 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7726 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7728 gst_structure_set_name (s, "application/x-cenc");
7734 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7736 if (stream->subtype == FOURCC_vide) {
7737 /* fps is calculated base on the duration of the average framerate since
7738 * qt does not have a fixed framerate. */
7739 gboolean fps_available = TRUE;
7741 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7743 CUR_STREAM (stream)->fps_n = 0;
7744 CUR_STREAM (stream)->fps_d = 1;
7746 if (stream->duration == 0 || stream->n_samples < 2) {
7747 CUR_STREAM (stream)->fps_n = stream->timescale;
7748 CUR_STREAM (stream)->fps_d = 1;
7749 fps_available = FALSE;
7751 GstClockTime avg_duration;
7755 /* duration and n_samples can be updated for fragmented format
7756 * so, framerate of fragmented format is calculated using data in a moof */
7757 if (qtdemux->fragmented && stream->n_samples_moof > 0
7758 && stream->duration_moof > 0) {
7759 n_samples = stream->n_samples_moof;
7760 duration = stream->duration_moof;
7762 n_samples = stream->n_samples;
7763 duration = stream->duration;
7766 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7767 /* stream->duration is guint64, timescale, n_samples are guint32 */
7769 gst_util_uint64_scale_round (duration -
7770 stream->first_duration, GST_SECOND,
7771 (guint64) (stream->timescale) * (n_samples - 1));
7773 GST_LOG_OBJECT (qtdemux,
7774 "Calculating avg sample duration based on stream (or moof) duration %"
7776 " minus first sample %u, leaving %d samples gives %"
7777 GST_TIME_FORMAT, duration, stream->first_duration,
7778 n_samples - 1, GST_TIME_ARGS (avg_duration));
7780 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
7781 &CUR_STREAM (stream)->fps_d);
7783 GST_DEBUG_OBJECT (qtdemux,
7784 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7785 stream->timescale, CUR_STREAM (stream)->fps_n,
7786 CUR_STREAM (stream)->fps_d);
7790 if (CUR_STREAM (stream)->caps) {
7791 CUR_STREAM (stream)->caps =
7792 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7794 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7795 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
7796 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
7798 /* set framerate if calculated framerate is reliable */
7799 if (fps_available) {
7800 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7801 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
7802 CUR_STREAM (stream)->fps_d, NULL);
7805 /* calculate pixel-aspect-ratio using display width and height */
7806 GST_DEBUG_OBJECT (qtdemux,
7807 "video size %dx%d, target display size %dx%d",
7808 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
7809 stream->display_width, stream->display_height);
7810 /* qt file might have pasp atom */
7811 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7812 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
7813 CUR_STREAM (stream)->par_h);
7814 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7815 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7816 CUR_STREAM (stream)->par_h, NULL);
7817 } else if (stream->display_width > 0 && stream->display_height > 0
7818 && CUR_STREAM (stream)->width > 0
7819 && CUR_STREAM (stream)->height > 0) {
7822 /* calculate the pixel aspect ratio using the display and pixel w/h */
7823 n = stream->display_width * CUR_STREAM (stream)->height;
7824 d = stream->display_height * CUR_STREAM (stream)->width;
7827 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7828 CUR_STREAM (stream)->par_w = n;
7829 CUR_STREAM (stream)->par_h = d;
7830 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7831 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7832 CUR_STREAM (stream)->par_h, NULL);
7835 if (CUR_STREAM (stream)->interlace_mode > 0) {
7836 if (CUR_STREAM (stream)->interlace_mode == 1) {
7837 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7838 G_TYPE_STRING, "progressive", NULL);
7839 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
7840 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7841 G_TYPE_STRING, "interleaved", NULL);
7842 if (CUR_STREAM (stream)->field_order == 9) {
7843 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7844 G_TYPE_STRING, "top-field-first", NULL);
7845 } else if (CUR_STREAM (stream)->field_order == 14) {
7846 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7847 G_TYPE_STRING, "bottom-field-first", NULL);
7852 /* Create incomplete colorimetry here if needed */
7853 if (CUR_STREAM (stream)->colorimetry.range ||
7854 CUR_STREAM (stream)->colorimetry.matrix ||
7855 CUR_STREAM (stream)->colorimetry.transfer
7856 || CUR_STREAM (stream)->colorimetry.primaries) {
7857 gchar *colorimetry =
7858 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
7859 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
7860 G_TYPE_STRING, colorimetry, NULL);
7861 g_free (colorimetry);
7864 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7865 guint par_w = 1, par_h = 1;
7867 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7868 par_w = CUR_STREAM (stream)->par_w;
7869 par_h = CUR_STREAM (stream)->par_h;
7872 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7873 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
7875 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7878 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7879 "multiview-mode", G_TYPE_STRING,
7880 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7881 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7882 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7887 else if (stream->subtype == FOURCC_soun) {
7888 if (CUR_STREAM (stream)->caps) {
7889 CUR_STREAM (stream)->caps =
7890 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7891 if (CUR_STREAM (stream)->rate > 0)
7892 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7893 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
7894 if (CUR_STREAM (stream)->n_channels > 0)
7895 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7896 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
7897 if (CUR_STREAM (stream)->n_channels > 2) {
7898 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7899 * correctly; this is just the minimum we can do - assume
7900 * we don't actually have any channel positions. */
7901 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7902 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7908 GstCaps *prev_caps = NULL;
7910 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7911 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7912 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7913 gst_pad_set_active (stream->pad, TRUE);
7915 gst_pad_use_fixed_caps (stream->pad);
7917 if (stream->protected) {
7918 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7919 GST_ERROR_OBJECT (qtdemux,
7920 "Failed to configure protected stream caps.");
7925 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7926 CUR_STREAM (stream)->caps);
7927 if (stream->new_stream) {
7930 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
7933 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7936 gst_event_parse_stream_flags (event, &stream_flags);
7937 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7938 qtdemux->have_group_id = TRUE;
7940 qtdemux->have_group_id = FALSE;
7941 gst_event_unref (event);
7942 } else if (!qtdemux->have_group_id) {
7943 qtdemux->have_group_id = TRUE;
7944 qtdemux->group_id = gst_util_group_id_next ();
7947 stream->new_stream = FALSE;
7949 gst_pad_create_stream_id_printf (stream->pad,
7950 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7951 event = gst_event_new_stream_start (stream_id);
7952 if (qtdemux->have_group_id)
7953 gst_event_set_group_id (event, qtdemux->group_id);
7954 if (stream->disabled)
7955 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7956 if (CUR_STREAM (stream)->sparse) {
7957 stream_flags |= GST_STREAM_FLAG_SPARSE;
7959 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
7961 gst_event_set_stream_flags (event, stream_flags);
7962 gst_pad_push_event (stream->pad, event);
7966 prev_caps = gst_pad_get_current_caps (stream->pad);
7968 if (CUR_STREAM (stream)->caps) {
7970 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
7971 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7972 CUR_STREAM (stream)->caps);
7973 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
7975 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7978 GST_WARNING_OBJECT (qtdemux, "stream without caps");
7982 gst_caps_unref (prev_caps);
7983 stream->new_caps = FALSE;
7989 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
7990 QtDemuxStream * stream)
7992 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
7995 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
7996 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
7997 if (G_UNLIKELY (stream->stsd_sample_description_id >=
7998 stream->stsd_entries_length)) {
7999 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8000 (_("This file is invalid and cannot be played.")),
8001 ("New sample description id is out of bounds (%d >= %d)",
8002 stream->stsd_sample_description_id, stream->stsd_entries_length));
8004 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8005 stream->new_caps = TRUE;
8010 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8011 QtDemuxStream * stream, GstTagList * list)
8013 gboolean ret = TRUE;
8014 /* consistent default for push based mode */
8015 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8017 if (stream->subtype == FOURCC_vide) {
8018 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8021 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8024 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8025 gst_object_unref (stream->pad);
8031 qtdemux->n_video_streams++;
8032 } else if (stream->subtype == FOURCC_soun) {
8033 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8036 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8038 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8039 gst_object_unref (stream->pad);
8044 qtdemux->n_audio_streams++;
8045 } else if (stream->subtype == FOURCC_strm) {
8046 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8047 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8048 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8049 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8052 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8054 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8055 gst_object_unref (stream->pad);
8060 qtdemux->n_sub_streams++;
8061 } else if (CUR_STREAM (stream)->caps) {
8062 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8065 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8067 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8068 gst_object_unref (stream->pad);
8073 qtdemux->n_video_streams++;
8075 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8082 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8083 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8084 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8085 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8087 if (stream->stream_tags)
8088 gst_tag_list_unref (stream->stream_tags);
8089 stream->stream_tags = list;
8091 /* global tags go on each pad anyway */
8092 stream->send_global_tags = TRUE;
8093 /* send upstream GST_EVENT_PROTECTION events that were received before
8094 this source pad was created */
8095 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8096 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8100 gst_tag_list_unref (list);
8104 /* find next atom with @fourcc starting at @offset */
8105 static GstFlowReturn
8106 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8107 guint64 * length, guint32 fourcc)
8113 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8114 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8120 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8121 if (G_UNLIKELY (ret != GST_FLOW_OK))
8123 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8126 gst_buffer_unref (buf);
8129 gst_buffer_map (buf, &map, GST_MAP_READ);
8130 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8131 gst_buffer_unmap (buf, &map);
8132 gst_buffer_unref (buf);
8134 if (G_UNLIKELY (*length == 0)) {
8135 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8136 ret = GST_FLOW_ERROR;
8140 if (lfourcc == fourcc) {
8141 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8145 GST_LOG_OBJECT (qtdemux,
8146 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8147 GST_FOURCC_ARGS (fourcc), *offset);
8156 /* might simply have had last one */
8157 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8162 /* should only do something in pull mode */
8163 /* call with OBJECT lock */
8164 static GstFlowReturn
8165 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8167 guint64 length, offset;
8168 GstBuffer *buf = NULL;
8169 GstFlowReturn ret = GST_FLOW_OK;
8170 GstFlowReturn res = GST_FLOW_OK;
8173 offset = qtdemux->moof_offset;
8174 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8177 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8178 return GST_FLOW_EOS;
8181 /* best not do pull etc with lock held */
8182 GST_OBJECT_UNLOCK (qtdemux);
8184 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8185 if (ret != GST_FLOW_OK)
8188 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8189 if (G_UNLIKELY (ret != GST_FLOW_OK))
8191 gst_buffer_map (buf, &map, GST_MAP_READ);
8192 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8193 gst_buffer_unmap (buf, &map);
8194 gst_buffer_unref (buf);
8199 gst_buffer_unmap (buf, &map);
8200 gst_buffer_unref (buf);
8204 /* look for next moof */
8205 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8206 if (G_UNLIKELY (ret != GST_FLOW_OK))
8210 GST_OBJECT_LOCK (qtdemux);
8212 qtdemux->moof_offset = offset;
8218 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8220 res = GST_FLOW_ERROR;
8225 /* maybe upstream temporarily flushing */
8226 if (ret != GST_FLOW_FLUSHING) {
8227 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8230 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8231 /* resume at current position next time */
8238 /* initialise bytereaders for stbl sub-atoms */
8240 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8242 stream->stbl_index = -1; /* no samples have yet been parsed */
8243 stream->sample_index = -1;
8245 /* time-to-sample atom */
8246 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8249 /* copy atom data into a new buffer for later use */
8250 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8252 /* skip version + flags */
8253 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8254 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8256 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8258 /* make sure there's enough data */
8259 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8260 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8261 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8262 stream->n_sample_times);
8263 if (!stream->n_sample_times)
8267 /* sync sample atom */
8268 stream->stps_present = FALSE;
8269 if ((stream->stss_present =
8270 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8271 &stream->stss) ? TRUE : FALSE) == TRUE) {
8272 /* copy atom data into a new buffer for later use */
8273 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8275 /* skip version + flags */
8276 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8277 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8280 if (stream->n_sample_syncs) {
8281 /* make sure there's enough data */
8282 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8286 /* partial sync sample atom */
8287 if ((stream->stps_present =
8288 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8289 &stream->stps) ? TRUE : FALSE) == TRUE) {
8290 /* copy atom data into a new buffer for later use */
8291 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8293 /* skip version + flags */
8294 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8295 !gst_byte_reader_get_uint32_be (&stream->stps,
8296 &stream->n_sample_partial_syncs))
8299 /* if there are no entries, the stss table contains the real
8301 if (stream->n_sample_partial_syncs) {
8302 /* make sure there's enough data */
8303 if (!qt_atom_parser_has_chunks (&stream->stps,
8304 stream->n_sample_partial_syncs, 4))
8311 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8314 /* copy atom data into a new buffer for later use */
8315 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8317 /* skip version + flags */
8318 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8319 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8322 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8325 if (!stream->n_samples)
8328 /* sample-to-chunk atom */
8329 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8332 /* copy atom data into a new buffer for later use */
8333 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8335 /* skip version + flags */
8336 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8337 !gst_byte_reader_get_uint32_be (&stream->stsc,
8338 &stream->n_samples_per_chunk))
8341 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8342 stream->n_samples_per_chunk);
8344 /* make sure there's enough data */
8345 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8351 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8352 stream->co_size = sizeof (guint32);
8353 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8355 stream->co_size = sizeof (guint64);
8359 /* copy atom data into a new buffer for later use */
8360 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8362 /* skip version + flags */
8363 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8366 /* chunks_are_samples == TRUE means treat chunks as samples */
8367 stream->chunks_are_samples = stream->sample_size
8368 && !CUR_STREAM (stream)->sampled;
8369 if (stream->chunks_are_samples) {
8370 /* treat chunks as samples */
8371 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8374 /* skip number of entries */
8375 if (!gst_byte_reader_skip (&stream->stco, 4))
8378 /* make sure there are enough data in the stsz atom */
8379 if (!stream->sample_size) {
8380 /* different sizes for each sample */
8381 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8386 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8387 stream->n_samples, (guint) sizeof (QtDemuxSample),
8388 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8390 if (stream->n_samples >=
8391 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8392 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8393 "be larger than %uMB (broken file?)", stream->n_samples,
8394 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8398 g_assert (stream->samples == NULL);
8399 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8400 if (!stream->samples) {
8401 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8406 /* composition time-to-sample */
8407 if ((stream->ctts_present =
8408 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8409 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8410 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8412 /* copy atom data into a new buffer for later use */
8413 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8415 /* skip version + flags */
8416 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8417 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8418 &stream->n_composition_times))
8421 /* make sure there's enough data */
8422 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8426 /* This is optional, if missing we iterate the ctts */
8427 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8428 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8429 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8430 g_free ((gpointer) cslg.data);
8434 gint32 cslg_least = 0;
8435 guint num_entries, pos;
8438 pos = gst_byte_reader_get_pos (&stream->ctts);
8439 num_entries = stream->n_composition_times;
8441 stream->cslg_shift = 0;
8443 for (i = 0; i < num_entries; i++) {
8446 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8447 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8449 if (offset < cslg_least)
8450 cslg_least = offset;
8454 stream->cslg_shift = ABS (cslg_least);
8456 stream->cslg_shift = 0;
8458 /* reset the reader so we can generate sample table */
8459 gst_byte_reader_set_pos (&stream->ctts, pos);
8462 /* Ensure the cslg_shift value is consistent so we can use it
8463 * unconditionnally to produce TS and Segment */
8464 stream->cslg_shift = 0;
8471 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8472 (_("This file is corrupt and cannot be played.")), (NULL));
8477 gst_qtdemux_stbl_free (stream);
8478 if (!qtdemux->fragmented) {
8479 /* not quite good */
8480 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8483 /* may pick up samples elsewhere */
8489 /* collect samples from the next sample to be parsed up to sample @n for @stream
8490 * by reading the info from @stbl
8492 * This code can be executed from both the streaming thread and the seeking
8493 * thread so it takes the object lock to protect itself
8496 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8499 QtDemuxSample *samples, *first, *cur, *last;
8500 guint32 n_samples_per_chunk;
8503 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8504 GST_FOURCC_FORMAT ", pad %s",
8505 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8506 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8508 n_samples = stream->n_samples;
8511 goto out_of_samples;
8513 GST_OBJECT_LOCK (qtdemux);
8514 if (n <= stream->stbl_index)
8515 goto already_parsed;
8517 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8519 if (!stream->stsz.data) {
8520 /* so we already parsed and passed all the moov samples;
8521 * onto fragmented ones */
8522 g_assert (qtdemux->fragmented);
8526 /* pointer to the sample table */
8527 samples = stream->samples;
8529 /* starts from -1, moves to the next sample index to parse */
8530 stream->stbl_index++;
8532 /* keep track of the first and last sample to fill */
8533 first = &samples[stream->stbl_index];
8536 if (!stream->chunks_are_samples) {
8537 /* set the sample sizes */
8538 if (stream->sample_size == 0) {
8539 /* different sizes for each sample */
8540 for (cur = first; cur <= last; cur++) {
8541 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8542 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8543 (guint) (cur - samples), cur->size);
8546 /* samples have the same size */
8547 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8548 for (cur = first; cur <= last; cur++)
8549 cur->size = stream->sample_size;
8553 n_samples_per_chunk = stream->n_samples_per_chunk;
8556 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8559 if (stream->stsc_chunk_index >= stream->last_chunk
8560 || stream->stsc_chunk_index < stream->first_chunk) {
8561 stream->first_chunk =
8562 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8563 stream->samples_per_chunk =
8564 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8566 stream->stsd_sample_description_id =
8567 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
8569 /* chunk numbers are counted from 1 it seems */
8570 if (G_UNLIKELY (stream->first_chunk == 0))
8573 --stream->first_chunk;
8575 /* the last chunk of each entry is calculated by taking the first chunk
8576 * of the next entry; except if there is no next, where we fake it with
8578 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8579 stream->last_chunk = G_MAXUINT32;
8581 stream->last_chunk =
8582 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8583 if (G_UNLIKELY (stream->last_chunk == 0))
8586 --stream->last_chunk;
8589 GST_LOG_OBJECT (qtdemux,
8590 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
8591 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
8592 stream->samples_per_chunk, stream->stsd_sample_description_id);
8594 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8597 if (stream->last_chunk != G_MAXUINT32) {
8598 if (!qt_atom_parser_peek_sub (&stream->stco,
8599 stream->first_chunk * stream->co_size,
8600 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8605 stream->co_chunk = stream->stco;
8606 if (!gst_byte_reader_skip (&stream->co_chunk,
8607 stream->first_chunk * stream->co_size))
8611 stream->stsc_chunk_index = stream->first_chunk;
8614 last_chunk = stream->last_chunk;
8616 if (stream->chunks_are_samples) {
8617 cur = &samples[stream->stsc_chunk_index];
8619 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8622 stream->stsc_chunk_index = j;
8627 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8630 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8631 "%" G_GUINT64_FORMAT, j, cur->offset);
8633 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
8634 CUR_STREAM (stream)->bytes_per_frame > 0) {
8636 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
8637 CUR_STREAM (stream)->samples_per_frame *
8638 CUR_STREAM (stream)->bytes_per_frame;
8640 cur->size = stream->samples_per_chunk;
8643 GST_DEBUG_OBJECT (qtdemux,
8644 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8645 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8646 stream->stco_sample_index)), cur->size);
8648 cur->timestamp = stream->stco_sample_index;
8649 cur->duration = stream->samples_per_chunk;
8650 cur->keyframe = TRUE;
8653 stream->stco_sample_index += stream->samples_per_chunk;
8655 stream->stsc_chunk_index = j;
8657 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8658 guint32 samples_per_chunk;
8659 guint64 chunk_offset;
8661 if (!stream->stsc_sample_index
8662 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8663 &stream->chunk_offset))
8666 samples_per_chunk = stream->samples_per_chunk;
8667 chunk_offset = stream->chunk_offset;
8669 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8670 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8671 G_GUINT64_FORMAT " and size %d",
8672 (guint) (cur - samples), chunk_offset, cur->size);
8674 cur->offset = chunk_offset;
8675 chunk_offset += cur->size;
8678 if (G_UNLIKELY (cur > last)) {
8680 stream->stsc_sample_index = k + 1;
8681 stream->chunk_offset = chunk_offset;
8682 stream->stsc_chunk_index = j;
8686 stream->stsc_sample_index = 0;
8688 stream->stsc_chunk_index = j;
8690 stream->stsc_index++;
8693 if (stream->chunks_are_samples)
8697 guint32 n_sample_times;
8699 n_sample_times = stream->n_sample_times;
8702 for (i = stream->stts_index; i < n_sample_times; i++) {
8703 guint32 stts_samples;
8704 gint32 stts_duration;
8707 if (stream->stts_sample_index >= stream->stts_samples
8708 || !stream->stts_sample_index) {
8710 stream->stts_samples =
8711 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8712 stream->stts_duration =
8713 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8715 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8716 i, stream->stts_samples, stream->stts_duration);
8718 stream->stts_sample_index = 0;
8721 stts_samples = stream->stts_samples;
8722 stts_duration = stream->stts_duration;
8723 stts_time = stream->stts_time;
8725 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8726 GST_DEBUG_OBJECT (qtdemux,
8727 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8728 (guint) (cur - samples), j,
8729 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8731 cur->timestamp = stts_time;
8732 cur->duration = stts_duration;
8734 /* avoid 32-bit wrap-around,
8735 * but still mind possible 'negative' duration */
8736 stts_time += (gint64) stts_duration;
8739 if (G_UNLIKELY (cur > last)) {
8741 stream->stts_time = stts_time;
8742 stream->stts_sample_index = j + 1;
8743 if (stream->stts_sample_index >= stream->stts_samples)
8744 stream->stts_index++;
8748 stream->stts_sample_index = 0;
8749 stream->stts_time = stts_time;
8750 stream->stts_index++;
8752 /* fill up empty timestamps with the last timestamp, this can happen when
8753 * the last samples do not decode and so we don't have timestamps for them.
8754 * We however look at the last timestamp to estimate the track length so we
8755 * need something in here. */
8756 for (; cur < last; cur++) {
8757 GST_DEBUG_OBJECT (qtdemux,
8758 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8759 (guint) (cur - samples),
8760 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8761 cur->timestamp = stream->stts_time;
8767 /* sample sync, can be NULL */
8768 if (stream->stss_present == TRUE) {
8769 guint32 n_sample_syncs;
8771 n_sample_syncs = stream->n_sample_syncs;
8773 if (!n_sample_syncs) {
8774 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8775 stream->all_keyframe = TRUE;
8777 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8778 /* note that the first sample is index 1, not 0 */
8781 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8783 if (G_LIKELY (index > 0 && index <= n_samples)) {
8785 samples[index].keyframe = TRUE;
8786 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8787 /* and exit if we have enough samples */
8788 if (G_UNLIKELY (index >= n)) {
8795 stream->stss_index = i;
8798 /* stps marks partial sync frames like open GOP I-Frames */
8799 if (stream->stps_present == TRUE) {
8800 guint32 n_sample_partial_syncs;
8802 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8804 /* if there are no entries, the stss table contains the real
8806 if (n_sample_partial_syncs) {
8807 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8808 /* note that the first sample is index 1, not 0 */
8811 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8813 if (G_LIKELY (index > 0 && index <= n_samples)) {
8815 samples[index].keyframe = TRUE;
8816 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8817 /* and exit if we have enough samples */
8818 if (G_UNLIKELY (index >= n)) {
8825 stream->stps_index = i;
8829 /* no stss, all samples are keyframes */
8830 stream->all_keyframe = TRUE;
8831 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8836 /* composition time to sample */
8837 if (stream->ctts_present == TRUE) {
8838 guint32 n_composition_times;
8840 gint32 ctts_soffset;
8842 /* Fill in the pts_offsets */
8844 n_composition_times = stream->n_composition_times;
8846 for (i = stream->ctts_index; i < n_composition_times; i++) {
8847 if (stream->ctts_sample_index >= stream->ctts_count
8848 || !stream->ctts_sample_index) {
8849 stream->ctts_count =
8850 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8851 stream->ctts_soffset =
8852 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8853 stream->ctts_sample_index = 0;
8856 ctts_count = stream->ctts_count;
8857 ctts_soffset = stream->ctts_soffset;
8859 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8860 cur->pts_offset = ctts_soffset;
8863 if (G_UNLIKELY (cur > last)) {
8865 stream->ctts_sample_index = j + 1;
8869 stream->ctts_sample_index = 0;
8870 stream->ctts_index++;
8874 stream->stbl_index = n;
8875 /* if index has been completely parsed, free data that is no-longer needed */
8876 if (n + 1 == stream->n_samples) {
8877 gst_qtdemux_stbl_free (stream);
8878 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8879 if (qtdemux->pullbased) {
8880 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8881 while (n + 1 == stream->n_samples)
8882 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8886 GST_OBJECT_UNLOCK (qtdemux);
8893 GST_LOG_OBJECT (qtdemux,
8894 "Tried to parse up to sample %u but this sample has already been parsed",
8896 /* if fragmented, there may be more */
8897 if (qtdemux->fragmented && n == stream->stbl_index)
8899 GST_OBJECT_UNLOCK (qtdemux);
8905 GST_LOG_OBJECT (qtdemux,
8906 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8908 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8909 (_("This file is corrupt and cannot be played.")), (NULL));
8914 GST_OBJECT_UNLOCK (qtdemux);
8915 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8916 (_("This file is corrupt and cannot be played.")), (NULL));
8921 /* collect all segment info for @stream.
8924 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8928 /* accept edts if they contain gaps at start and there is only
8929 * one media segment */
8930 gboolean allow_pushbased_edts = TRUE;
8931 gint media_segments_count = 0;
8933 /* parse and prepare segment info from the edit list */
8934 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8935 stream->n_segments = 0;
8936 stream->segments = NULL;
8937 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8940 gint i, count, entry_size;
8943 const guint8 *buffer;
8947 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8948 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8951 buffer = elst->data;
8953 size = QT_UINT32 (buffer);
8954 /* version, flags, n_segments */
8956 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8959 version = QT_UINT8 (buffer + 8);
8960 entry_size = (version == 1) ? 20 : 12;
8962 n_segments = QT_UINT32 (buffer + 12);
8964 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
8965 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8969 /* we might allocate a bit too much, at least allocate 1 segment */
8970 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8972 /* segments always start from 0 */
8977 for (i = 0; i < n_segments; i++) {
8980 gboolean time_valid = TRUE;
8981 QtDemuxSegment *segment;
8983 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8986 media_time = QT_UINT64 (buffer + 8);
8987 duration = QT_UINT64 (buffer);
8988 if (media_time == G_MAXUINT64)
8991 media_time = QT_UINT32 (buffer + 4);
8992 duration = QT_UINT32 (buffer);
8993 if (media_time == G_MAXUINT32)
8998 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9000 segment = &stream->segments[count++];
9002 /* time and duration expressed in global timescale */
9003 segment->time = stime;
9004 /* add non scaled values so we don't cause roundoff errors */
9005 if (duration || media_start == GST_CLOCK_TIME_NONE) {
9007 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9008 segment->duration = stime - segment->time;
9010 /* zero duration does not imply media_start == media_stop
9011 * but, only specify media_start.*/
9012 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
9013 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
9014 && stime >= media_start) {
9015 segment->duration = stime - media_start;
9017 segment->duration = GST_CLOCK_TIME_NONE;
9020 segment->stop_time = stime;
9022 segment->trak_media_start = media_time;
9023 /* media_time expressed in stream timescale */
9025 segment->media_start = media_start;
9026 segment->media_stop = segment->media_start + segment->duration;
9027 media_segments_count++;
9029 segment->media_start = GST_CLOCK_TIME_NONE;
9030 segment->media_stop = GST_CLOCK_TIME_NONE;
9032 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9034 if (rate_int <= 1) {
9035 /* 0 is not allowed, some programs write 1 instead of the floating point
9037 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9041 segment->rate = rate_int / 65536.0;
9044 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9045 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9046 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9047 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9048 i, GST_TIME_ARGS (segment->time),
9049 GST_TIME_ARGS (segment->duration),
9050 GST_TIME_ARGS (segment->media_start), media_time,
9051 GST_TIME_ARGS (segment->media_stop),
9052 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9054 if (segment->stop_time > qtdemux->segment.stop) {
9055 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9056 " extends to %" GST_TIME_FORMAT
9057 " past the end of the file duration %" GST_TIME_FORMAT
9058 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9059 GST_TIME_ARGS (qtdemux->segment.stop));
9060 qtdemux->segment.stop = segment->stop_time;
9063 buffer += entry_size;
9065 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9066 stream->n_segments = count;
9067 if (media_segments_count != 1)
9068 allow_pushbased_edts = FALSE;
9072 /* push based does not handle segments, so act accordingly here,
9073 * and warn if applicable */
9074 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9075 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9076 /* remove and use default one below, we stream like it anyway */
9077 g_free (stream->segments);
9078 stream->segments = NULL;
9079 stream->n_segments = 0;
9082 /* no segments, create one to play the complete trak */
9083 if (stream->n_segments == 0) {
9084 GstClockTime stream_duration =
9085 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9087 if (stream->segments == NULL)
9088 stream->segments = g_new (QtDemuxSegment, 1);
9090 /* represent unknown our way */
9091 if (stream_duration == 0)
9092 stream_duration = GST_CLOCK_TIME_NONE;
9094 stream->segments[0].time = 0;
9095 stream->segments[0].stop_time = stream_duration;
9096 stream->segments[0].duration = stream_duration;
9097 stream->segments[0].media_start = 0;
9098 stream->segments[0].media_stop = stream_duration;
9099 stream->segments[0].rate = 1.0;
9100 stream->segments[0].trak_media_start = 0;
9102 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9103 GST_TIME_ARGS (stream_duration));
9104 stream->n_segments = 1;
9105 stream->dummy_segment = TRUE;
9107 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9113 * Parses the stsd atom of a svq3 trak looking for
9114 * the SMI and gama atoms.
9117 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9118 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9120 const guint8 *_gamma = NULL;
9121 GstBuffer *_seqh = NULL;
9122 const guint8 *stsd_data = stsd_entry_data;
9123 guint32 length = QT_UINT32 (stsd_data);
9127 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9133 version = QT_UINT16 (stsd_data);
9138 while (length > 8) {
9139 guint32 fourcc, size;
9141 size = QT_UINT32 (stsd_data);
9142 fourcc = QT_FOURCC (stsd_data + 4);
9143 data = stsd_data + 8;
9146 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9147 "svq3 atom parsing");
9156 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9157 " for gama atom, expected 12", size);
9162 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9164 if (_seqh != NULL) {
9165 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9166 " found, ignoring");
9168 seqh_size = QT_UINT32 (data + 4);
9169 if (seqh_size > 0) {
9170 _seqh = gst_buffer_new_and_alloc (seqh_size);
9171 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9178 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9179 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9183 if (size <= length) {
9189 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9192 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9193 G_GUINT16_FORMAT, version);
9204 gst_buffer_unref (_seqh);
9209 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9216 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9217 * atom that might contain a 'data' atom with the rtsp uri.
9218 * This case was reported in bug #597497, some info about
9219 * the hndl atom can be found in TN1195
9221 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9222 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9225 guint32 dref_num_entries = 0;
9226 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9227 gst_byte_reader_skip (&dref, 4) &&
9228 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9231 /* search dref entries for hndl atom */
9232 for (i = 0; i < dref_num_entries; i++) {
9233 guint32 size = 0, type;
9234 guint8 string_len = 0;
9235 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9236 qt_atom_parser_get_fourcc (&dref, &type)) {
9237 if (type == FOURCC_hndl) {
9238 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9240 /* skip data reference handle bytes and the
9241 * following pascal string and some extra 4
9242 * bytes I have no idea what are */
9243 if (!gst_byte_reader_skip (&dref, 4) ||
9244 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9245 !gst_byte_reader_skip (&dref, string_len + 4)) {
9246 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9250 /* iterate over the atoms to find the data atom */
9251 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9255 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9256 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9257 if (atom_type == FOURCC_data) {
9258 const guint8 *uri_aux = NULL;
9260 /* found the data atom that might contain the rtsp uri */
9261 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9262 "hndl atom, interpreting it as an URI");
9263 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9265 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9266 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9268 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9269 "didn't contain a rtsp address");
9271 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9276 /* skipping to the next entry */
9277 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9280 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9287 /* skip to the next entry */
9288 if (!gst_byte_reader_skip (&dref, size - 8))
9291 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9294 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9300 #define AMR_NB_ALL_MODES 0x81ff
9301 #define AMR_WB_ALL_MODES 0x83ff
9303 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9305 /* The 'damr' atom is of the form:
9307 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9308 * 32 b 8 b 16 b 8 b 8 b
9310 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9311 * represents the highest mode used in the stream (and thus the maximum
9312 * bitrate), with a couple of special cases as seen below.
9315 /* Map of frame type ID -> bitrate */
9316 static const guint nb_bitrates[] = {
9317 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9319 static const guint wb_bitrates[] = {
9320 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9326 gst_buffer_map (buf, &map, GST_MAP_READ);
9328 if (map.size != 0x11) {
9329 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9333 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9334 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9335 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9339 mode_set = QT_UINT16 (map.data + 13);
9341 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9342 max_mode = 7 + (wb ? 1 : 0);
9344 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9345 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9347 if (max_mode == -1) {
9348 GST_DEBUG ("No mode indication was found (mode set) = %x",
9353 gst_buffer_unmap (buf, &map);
9354 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9357 gst_buffer_unmap (buf, &map);
9362 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9363 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9366 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9372 if (gst_byte_reader_get_remaining (reader) < 36)
9375 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9376 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9377 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9378 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9379 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9380 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9381 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9382 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9383 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9385 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9386 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9387 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9389 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9390 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9392 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9393 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9400 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9401 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9408 * This macro will only compare value abdegh, it expects cfi to have already
9411 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9412 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9414 /* only handle the cases where the last column has standard values */
9415 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9416 const gchar *rotation_tag = NULL;
9418 /* no rotation needed */
9419 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9421 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9422 rotation_tag = "rotate-90";
9423 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9424 rotation_tag = "rotate-180";
9425 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9426 rotation_tag = "rotate-270";
9428 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9431 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9433 if (rotation_tag != NULL) {
9434 if (*taglist == NULL)
9435 *taglist = gst_tag_list_new_empty ();
9436 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9437 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9440 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9444 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9445 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9446 * Common Encryption (cenc), the function will also parse the tenc box (defined
9447 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9448 * (typically an enc[v|a|t|s] sample entry); the function will set
9449 * @original_fmt to the fourcc of the original unencrypted stream format.
9450 * Returns TRUE if successful; FALSE otherwise. */
9452 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9453 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9460 g_return_val_if_fail (qtdemux != NULL, FALSE);
9461 g_return_val_if_fail (stream != NULL, FALSE);
9462 g_return_val_if_fail (container != NULL, FALSE);
9463 g_return_val_if_fail (original_fmt != NULL, FALSE);
9465 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9466 if (G_UNLIKELY (!sinf)) {
9467 if (stream->protection_scheme_type == FOURCC_cenc) {
9468 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9469 "mandatory for Common Encryption");
9475 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9476 if (G_UNLIKELY (!frma)) {
9477 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9481 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9482 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9483 GST_FOURCC_ARGS (*original_fmt));
9485 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9487 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9490 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9491 stream->protection_scheme_version =
9492 QT_UINT32 ((const guint8 *) schm->data + 16);
9494 GST_DEBUG_OBJECT (qtdemux,
9495 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9496 "protection_scheme_version: %#010x",
9497 GST_FOURCC_ARGS (stream->protection_scheme_type),
9498 stream->protection_scheme_version);
9500 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9502 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9505 if (stream->protection_scheme_type == FOURCC_cenc) {
9506 QtDemuxCencSampleSetInfo *info;
9508 const guint8 *tenc_data;
9509 guint32 isEncrypted;
9511 const guint8 *default_kid;
9514 if (G_UNLIKELY (!stream->protection_scheme_info))
9515 stream->protection_scheme_info =
9516 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9518 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9520 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9522 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9523 "which is mandatory for Common Encryption");
9526 tenc_data = (const guint8 *) tenc->data + 12;
9527 isEncrypted = QT_UINT24 (tenc_data);
9528 iv_size = QT_UINT8 (tenc_data + 3);
9529 default_kid = (tenc_data + 4);
9530 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9531 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9532 if (info->default_properties)
9533 gst_structure_free (info->default_properties);
9534 info->default_properties =
9535 gst_structure_new ("application/x-cenc",
9536 "iv_size", G_TYPE_UINT, iv_size,
9537 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9538 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9539 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9540 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9541 gst_buffer_unref (kid_buf);
9547 * With each track we associate a new QtDemuxStream that contains all the info
9549 * traks that do not decode to something (like strm traks) will not have a pad.
9552 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9573 QtDemuxStream *stream = NULL;
9574 gboolean new_stream = FALSE;
9575 gchar *codec = NULL;
9576 const guint8 *stsd_data;
9577 const guint8 *stsd_entry_data;
9578 guint remaining_stsd_len;
9579 guint stsd_entry_count;
9581 guint16 lang_code; /* quicktime lang code or packed iso code */
9583 guint32 tkhd_flags = 0;
9584 guint8 tkhd_version = 0;
9585 guint32 w = 0, h = 0;
9587 guint value_size, stsd_len, len;
9591 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9593 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9594 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9595 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9598 /* pick between 64 or 32 bits */
9599 value_size = tkhd_version == 1 ? 8 : 4;
9600 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9601 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9604 if (!qtdemux->got_moov) {
9605 if (qtdemux_find_stream (qtdemux, track_id))
9606 goto existing_stream;
9607 stream = _create_stream ();
9608 stream->track_id = track_id;
9611 stream = qtdemux_find_stream (qtdemux, track_id);
9613 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9617 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
9619 /* flush samples data from this track from previous moov */
9620 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9621 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9623 /* need defaults for fragments */
9624 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9626 if ((tkhd_flags & 1) == 0)
9627 stream->disabled = TRUE;
9629 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9630 tkhd_version, tkhd_flags, stream->track_id);
9632 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9635 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9636 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9637 if (qtdemux->major_brand != FOURCC_mjp2 ||
9638 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9642 len = QT_UINT32 ((guint8 *) mdhd->data);
9643 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9644 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9645 if (version == 0x01000000) {
9648 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9649 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9650 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9654 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9655 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9656 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9659 if (lang_code < 0x400) {
9660 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9661 } else if (lang_code == 0x7fff) {
9662 stream->lang_id[0] = 0; /* unspecified */
9664 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9665 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9666 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9667 stream->lang_id[3] = 0;
9670 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9672 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9674 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9675 lang_code, stream->lang_id);
9677 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9680 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9681 /* chapters track reference */
9682 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9684 gsize length = GST_READ_UINT32_BE (chap->data);
9685 if (qtdemux->chapters_track_id)
9686 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9689 qtdemux->chapters_track_id =
9690 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9695 /* fragmented files may have bogus duration in moov */
9696 if (!qtdemux->fragmented &&
9697 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9698 guint64 tdur1, tdur2;
9700 /* don't overflow */
9701 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9702 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9705 * some of those trailers, nowadays, have prologue images that are
9706 * themselves video tracks as well. I haven't really found a way to
9707 * identify those yet, except for just looking at their duration. */
9708 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9709 GST_WARNING_OBJECT (qtdemux,
9710 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9711 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9712 "found, assuming preview image or something; skipping track",
9713 stream->duration, stream->timescale, qtdemux->duration,
9714 qtdemux->timescale);
9716 gst_qtdemux_stream_free (qtdemux, stream);
9721 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9724 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9725 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9727 len = QT_UINT32 ((guint8 *) hdlr->data);
9729 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9730 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9731 GST_FOURCC_ARGS (stream->subtype));
9733 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9736 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9739 /*parse svmi header if existing */
9740 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9742 len = QT_UINT32 ((guint8 *) svmi->data);
9743 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9745 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9746 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9747 guint8 frame_type, frame_layout;
9749 /* MPEG-A stereo video */
9750 if (qtdemux->major_brand == FOURCC_ss02)
9751 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9753 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9754 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9755 switch (frame_type) {
9757 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9760 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9763 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9766 /* mode 3 is primary/secondary view sequence, ie
9767 * left/right views in separate tracks. See section 7.2
9768 * of ISO/IEC 23000-11:2009 */
9769 GST_FIXME_OBJECT (qtdemux,
9770 "Implement stereo video in separate streams");
9773 if ((frame_layout & 0x1) == 0)
9774 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9776 GST_LOG_OBJECT (qtdemux,
9777 "StereoVideo: composition type: %u, is_left_first: %u",
9778 frame_type, frame_layout);
9779 stream->multiview_mode = mode;
9780 stream->multiview_flags = flags;
9784 /* parse rest of tkhd */
9785 if (stream->subtype == FOURCC_vide) {
9788 /* version 1 uses some 64-bit ints */
9789 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9792 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9795 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9796 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9799 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9800 &stream->stream_tags);
9804 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9806 stsd_data = (const guint8 *) stsd->data;
9808 /* stsd should at least have one entry */
9809 stsd_len = QT_UINT32 (stsd_data);
9810 if (stsd_len < 24) {
9811 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9812 if (stream->subtype == FOURCC_vivo) {
9814 gst_qtdemux_stream_free (qtdemux, stream);
9821 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
9822 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
9823 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9824 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
9826 stsd_entry_data = stsd_data + 16;
9827 remaining_stsd_len = stsd_len - 16;
9828 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
9829 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
9831 /* and that entry should fit within stsd */
9832 len = QT_UINT32 (stsd_entry_data);
9833 if (len > remaining_stsd_len)
9836 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
9837 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9838 GST_FOURCC_ARGS (entry->fourcc));
9839 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9841 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9842 goto error_encrypted;
9844 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9845 /* FIXME this looks wrong, there might be multiple children
9846 * with the same type */
9847 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9848 stream->protected = TRUE;
9849 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9850 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9853 if (stream->subtype == FOURCC_vide) {
9855 gint depth, palette_size, palette_count;
9856 guint32 *palette_data = NULL;
9858 entry->sampled = TRUE;
9860 stream->display_width = w >> 16;
9861 stream->display_height = h >> 16;
9864 if (len < 86) /* TODO verify */
9867 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
9868 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
9869 entry->fps_n = 0; /* this is filled in later */
9870 entry->fps_d = 0; /* this is filled in later */
9871 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
9872 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
9874 /* if color_table_id is 0, ctab atom must follow; however some files
9875 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9876 * if color table is not present we'll correct the value */
9877 if (entry->color_table_id == 0 &&
9879 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
9880 entry->color_table_id = -1;
9883 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9884 entry->width, entry->height, entry->bits_per_sample,
9885 entry->color_table_id);
9887 depth = entry->bits_per_sample;
9889 /* more than 32 bits means grayscale */
9890 gray = (depth > 32);
9891 /* low 32 bits specify the depth */
9894 /* different number of palette entries is determined by depth. */
9896 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9897 palette_count = (1 << depth);
9898 palette_size = palette_count * 4;
9900 if (entry->color_table_id) {
9901 switch (palette_count) {
9905 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9908 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9913 g_memdup (ff_qt_grayscale_palette_16, palette_size);
9915 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9920 g_memdup (ff_qt_grayscale_palette_256, palette_size);
9922 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9925 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9926 (_("The video in this file might not play correctly.")),
9927 ("unsupported palette depth %d", depth));
9931 gint i, j, start, end;
9937 start = QT_UINT32 (stsd_entry_data + offset + 70);
9938 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
9939 end = QT_UINT16 (stsd_entry_data + offset + 76);
9941 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9942 start, end, palette_count);
9949 if (len < 94 + (end - start) * 8)
9952 /* palette is always the same size */
9953 palette_data = g_malloc0 (256 * 4);
9954 palette_size = 256 * 4;
9956 for (j = 0, i = start; i <= end; j++, i++) {
9959 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
9960 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
9961 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
9962 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
9964 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9965 (g & 0xff00) | (b >> 8);
9970 gst_caps_unref (entry->caps);
9973 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
9975 if (G_UNLIKELY (!entry->caps)) {
9976 g_free (palette_data);
9977 goto unknown_stream;
9981 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
9982 GST_TAG_VIDEO_CODEC, codec, NULL);
9990 if (entry->rgb8_palette)
9991 gst_memory_unref (entry->rgb8_palette);
9992 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9993 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9995 s = gst_caps_get_structure (entry->caps, 0);
9997 /* non-raw video has a palette_data property. raw video has the palette as
9998 * an extra plane that we append to the output buffers before we push
10000 if (!gst_structure_has_name (s, "video/x-raw")) {
10001 GstBuffer *palette;
10003 palette = gst_buffer_new ();
10004 gst_buffer_append_memory (palette, entry->rgb8_palette);
10005 entry->rgb8_palette = NULL;
10007 gst_caps_set_simple (entry->caps, "palette_data",
10008 GST_TYPE_BUFFER, palette, NULL);
10009 gst_buffer_unref (palette);
10011 } else if (palette_count != 0) {
10012 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10013 (NULL), ("Unsupported palette depth %d", depth));
10016 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10017 QT_UINT16 (stsd_entry_data + offset + 32));
10023 /* pick 'the' stsd child */
10024 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10025 if (!stream->protected) {
10026 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10030 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10036 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10037 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10038 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10039 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10043 const guint8 *pasp_data = (const guint8 *) pasp->data;
10044 gint len = QT_UINT32 (pasp_data);
10047 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10048 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10050 CUR_STREAM (stream)->par_w = 0;
10051 CUR_STREAM (stream)->par_h = 0;
10054 CUR_STREAM (stream)->par_w = 0;
10055 CUR_STREAM (stream)->par_h = 0;
10059 const guint8 *fiel_data = (const guint8 *) fiel->data;
10060 gint len = QT_UINT32 (fiel_data);
10063 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10064 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10069 const guint8 *colr_data = (const guint8 *) colr->data;
10070 gint len = QT_UINT32 (colr_data);
10072 if (len == 19 || len == 18) {
10073 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10075 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10076 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10077 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10078 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10079 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10081 switch (primaries) {
10083 CUR_STREAM (stream)->colorimetry.primaries =
10084 GST_VIDEO_COLOR_PRIMARIES_BT709;
10087 CUR_STREAM (stream)->colorimetry.primaries =
10088 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10091 CUR_STREAM (stream)->colorimetry.primaries =
10092 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10095 CUR_STREAM (stream)->colorimetry.primaries =
10096 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10102 switch (transfer_function) {
10104 CUR_STREAM (stream)->colorimetry.transfer =
10105 GST_VIDEO_TRANSFER_BT709;
10108 CUR_STREAM (stream)->colorimetry.transfer =
10109 GST_VIDEO_TRANSFER_SMPTE240M;
10117 CUR_STREAM (stream)->colorimetry.matrix =
10118 GST_VIDEO_COLOR_MATRIX_BT709;
10121 CUR_STREAM (stream)->colorimetry.matrix =
10122 GST_VIDEO_COLOR_MATRIX_BT601;
10125 CUR_STREAM (stream)->colorimetry.matrix =
10126 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10129 CUR_STREAM (stream)->colorimetry.matrix =
10130 GST_VIDEO_COLOR_MATRIX_BT2020;
10136 CUR_STREAM (stream)->colorimetry.range =
10137 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10138 GST_VIDEO_COLOR_RANGE_16_235;
10140 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10143 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10148 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10149 stream->stream_tags);
10156 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10157 const guint8 *avc_data = stsd_entry_data + 0x56;
10160 while (len >= 0x8) {
10163 if (QT_UINT32 (avc_data) <= len)
10164 size = QT_UINT32 (avc_data) - 0x8;
10169 /* No real data, so break out */
10172 switch (QT_FOURCC (avc_data + 0x4)) {
10175 /* parse, if found */
10178 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10180 /* First 4 bytes are the length of the atom, the next 4 bytes
10181 * are the fourcc, the next 1 byte is the version, and the
10182 * subsequent bytes are profile_tier_level structure like data. */
10183 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10184 avc_data + 8 + 1, size - 1);
10185 buf = gst_buffer_new_and_alloc (size);
10186 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10187 gst_caps_set_simple (entry->caps,
10188 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10189 gst_buffer_unref (buf);
10197 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10199 /* First 4 bytes are the length of the atom, the next 4 bytes
10200 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10201 * next 1 byte is the version, and the
10202 * subsequent bytes are sequence parameter set like data. */
10204 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10206 gst_codec_utils_h264_caps_set_level_and_profile
10207 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10209 buf = gst_buffer_new_and_alloc (size);
10210 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10211 gst_caps_set_simple (entry->caps,
10212 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10213 gst_buffer_unref (buf);
10219 guint avg_bitrate, max_bitrate;
10221 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10225 max_bitrate = QT_UINT32 (avc_data + 0xc);
10226 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10228 if (!max_bitrate && !avg_bitrate)
10231 /* Some muxers seem to swap the average and maximum bitrates
10232 * (I'm looking at you, YouTube), so we swap for sanity. */
10233 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10234 guint temp = avg_bitrate;
10236 avg_bitrate = max_bitrate;
10237 max_bitrate = temp;
10240 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10241 gst_tag_list_add (stream->stream_tags,
10242 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10243 max_bitrate, NULL);
10245 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10246 gst_tag_list_add (stream->stream_tags,
10247 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10259 avc_data += size + 8;
10268 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10269 const guint8 *hevc_data = stsd_entry_data + 0x56;
10272 while (len >= 0x8) {
10275 if (QT_UINT32 (hevc_data) <= len)
10276 size = QT_UINT32 (hevc_data) - 0x8;
10281 /* No real data, so break out */
10284 switch (QT_FOURCC (hevc_data + 0x4)) {
10287 /* parse, if found */
10290 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10292 /* First 4 bytes are the length of the atom, the next 4 bytes
10293 * are the fourcc, the next 1 byte is the version, and the
10294 * subsequent bytes are sequence parameter set like data. */
10295 gst_codec_utils_h265_caps_set_level_tier_and_profile
10296 (entry->caps, hevc_data + 8 + 1, size - 1);
10298 buf = gst_buffer_new_and_alloc (size);
10299 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10300 gst_caps_set_simple (entry->caps,
10301 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10302 gst_buffer_unref (buf);
10309 hevc_data += size + 8;
10322 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10323 GST_FOURCC_ARGS (fourcc));
10325 /* codec data might be in glbl extension atom */
10327 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10333 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10335 len = QT_UINT32 (data);
10338 buf = gst_buffer_new_and_alloc (len);
10339 gst_buffer_fill (buf, 0, data + 8, len);
10340 gst_caps_set_simple (entry->caps,
10341 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10342 gst_buffer_unref (buf);
10349 /* see annex I of the jpeg2000 spec */
10350 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10351 const guint8 *data;
10352 const gchar *colorspace = NULL;
10354 guint32 ncomp_map = 0;
10355 gint32 *comp_map = NULL;
10356 guint32 nchan_def = 0;
10357 gint32 *chan_def = NULL;
10359 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10360 /* some required atoms */
10361 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10364 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10368 /* number of components; redundant with info in codestream, but useful
10370 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10371 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10373 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10375 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10378 GST_DEBUG_OBJECT (qtdemux, "found colr");
10379 /* extract colour space info */
10380 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10381 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10383 colorspace = "sRGB";
10386 colorspace = "GRAY";
10389 colorspace = "sYUV";
10397 /* colr is required, and only values 16, 17, and 18 are specified,
10398 so error if we have no colorspace */
10401 /* extract component mapping */
10402 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10404 guint32 cmap_len = 0;
10406 cmap_len = QT_UINT32 (cmap->data);
10407 if (cmap_len >= 8) {
10408 /* normal box, subtract off header */
10410 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10411 if (cmap_len % 4 == 0) {
10412 ncomp_map = (cmap_len / 4);
10413 comp_map = g_new0 (gint32, ncomp_map);
10414 for (i = 0; i < ncomp_map; i++) {
10417 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10418 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10419 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10420 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10425 /* extract channel definitions */
10426 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10428 guint32 cdef_len = 0;
10430 cdef_len = QT_UINT32 (cdef->data);
10431 if (cdef_len >= 10) {
10432 /* normal box, subtract off header and len */
10434 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10435 if (cdef_len % 6 == 0) {
10436 nchan_def = (cdef_len / 6);
10437 chan_def = g_new0 (gint32, nchan_def);
10438 for (i = 0; i < nchan_def; i++)
10440 for (i = 0; i < nchan_def; i++) {
10441 guint16 cn, typ, asoc;
10442 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10443 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10444 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10445 if (cn < nchan_def) {
10448 chan_def[cn] = asoc;
10451 chan_def[cn] = 0; /* alpha */
10454 chan_def[cn] = -typ;
10462 gst_caps_set_simple (entry->caps,
10463 "num-components", G_TYPE_INT, ncomp, NULL);
10464 gst_caps_set_simple (entry->caps,
10465 "colorspace", G_TYPE_STRING, colorspace, NULL);
10468 GValue arr = { 0, };
10469 GValue elt = { 0, };
10471 g_value_init (&arr, GST_TYPE_ARRAY);
10472 g_value_init (&elt, G_TYPE_INT);
10473 for (i = 0; i < ncomp_map; i++) {
10474 g_value_set_int (&elt, comp_map[i]);
10475 gst_value_array_append_value (&arr, &elt);
10477 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10478 "component-map", &arr);
10479 g_value_unset (&elt);
10480 g_value_unset (&arr);
10485 GValue arr = { 0, };
10486 GValue elt = { 0, };
10488 g_value_init (&arr, GST_TYPE_ARRAY);
10489 g_value_init (&elt, G_TYPE_INT);
10490 for (i = 0; i < nchan_def; i++) {
10491 g_value_set_int (&elt, chan_def[i]);
10492 gst_value_array_append_value (&arr, &elt);
10494 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10495 "channel-definitions", &arr);
10496 g_value_unset (&elt);
10497 g_value_unset (&arr);
10501 /* some optional atoms */
10502 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10503 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10505 /* indicate possible fields in caps */
10507 data = (guint8 *) field->data + 8;
10509 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10510 (gint) * data, NULL);
10512 /* add codec_data if provided */
10517 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10518 data = prefix->data;
10519 len = QT_UINT32 (data);
10522 buf = gst_buffer_new_and_alloc (len);
10523 gst_buffer_fill (buf, 0, data + 8, len);
10524 gst_caps_set_simple (entry->caps,
10525 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10526 gst_buffer_unref (buf);
10535 GstBuffer *seqh = NULL;
10536 const guint8 *gamma_data = NULL;
10537 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
10539 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
10542 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
10543 QT_FP32 (gamma_data), NULL);
10546 /* sorry for the bad name, but we don't know what this is, other
10547 * than its own fourcc */
10548 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
10550 gst_buffer_unref (seqh);
10553 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10554 buf = gst_buffer_new_and_alloc (len);
10555 gst_buffer_fill (buf, 0, stsd_data, len);
10556 gst_caps_set_simple (entry->caps,
10557 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10558 gst_buffer_unref (buf);
10563 /* https://developer.apple.com/standards/qtff-2001.pdf,
10564 * page 92, "Video Sample Description", under table 3.1 */
10567 const gint compressor_offset =
10568 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10569 const gint min_size = compressor_offset + 32 + 2 + 2;
10572 guint16 color_table_id = 0;
10575 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10577 /* recover information on interlaced/progressive */
10578 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10582 len = QT_UINT32 (jpeg->data);
10583 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10585 if (len >= min_size) {
10586 gst_byte_reader_init (&br, jpeg->data, len);
10588 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10589 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10590 if (color_table_id != 0) {
10591 /* the spec says there can be concatenated chunks in the data, and we want
10592 * to find one called field. Walk through them. */
10593 gint offset = min_size;
10594 while (offset + 8 < len) {
10595 guint32 size = 0, tag;
10596 ok = gst_byte_reader_get_uint32_le (&br, &size);
10597 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10598 if (!ok || size < 8) {
10599 GST_WARNING_OBJECT (qtdemux,
10600 "Failed to walk optional chunk list");
10603 GST_DEBUG_OBJECT (qtdemux,
10604 "Found optional %4.4s chunk, size %u",
10605 (const char *) &tag, size);
10606 if (tag == FOURCC_fiel) {
10607 guint8 n_fields = 0, ordering = 0;
10608 gst_byte_reader_get_uint8 (&br, &n_fields);
10609 gst_byte_reader_get_uint8 (&br, &ordering);
10610 if (n_fields == 1 || n_fields == 2) {
10611 GST_DEBUG_OBJECT (qtdemux,
10612 "Found fiel tag with %u fields, ordering %u",
10613 n_fields, ordering);
10615 gst_caps_set_simple (CUR_STREAM (stream)->caps,
10616 "interlace-mode", G_TYPE_STRING, "interleaved",
10619 GST_WARNING_OBJECT (qtdemux,
10620 "Found fiel tag with invalid fields (%u)", n_fields);
10626 GST_DEBUG_OBJECT (qtdemux,
10627 "Color table ID is 0, not trying to get interlacedness");
10630 GST_WARNING_OBJECT (qtdemux,
10631 "Length of jpeg chunk is too small, not trying to get interlacedness");
10639 gst_caps_set_simple (entry->caps,
10640 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
10646 GNode *xith, *xdxt;
10648 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10649 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10653 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10657 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10658 /* collect the headers and store them in a stream list so that we can
10659 * send them out first */
10660 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10670 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10671 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10674 ovc1_data = ovc1->data;
10675 ovc1_len = QT_UINT32 (ovc1_data);
10676 if (ovc1_len <= 198) {
10677 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10680 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10681 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10682 gst_caps_set_simple (entry->caps,
10683 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10684 gst_buffer_unref (buf);
10689 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10690 const guint8 *vc1_data = stsd_entry_data + 0x56;
10696 if (QT_UINT32 (vc1_data) <= len)
10697 size = QT_UINT32 (vc1_data) - 8;
10702 /* No real data, so break out */
10705 switch (QT_FOURCC (vc1_data + 0x4)) {
10706 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10710 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10711 buf = gst_buffer_new_and_alloc (size);
10712 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10713 gst_caps_set_simple (entry->caps,
10714 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10715 gst_buffer_unref (buf);
10722 vc1_data += size + 8;
10731 GST_INFO_OBJECT (qtdemux,
10732 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10733 GST_FOURCC_ARGS (fourcc), entry->caps);
10735 } else if (stream->subtype == FOURCC_soun) {
10736 int version, samplesize;
10737 guint16 compression_id;
10738 gboolean amrwb = FALSE;
10741 /* sample description entry (16) + sound sample description v0 (20) */
10745 version = QT_UINT32 (stsd_entry_data + offset);
10746 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
10747 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
10748 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
10749 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
10751 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10752 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10753 QT_UINT32 (stsd_entry_data + offset + 4));
10754 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10755 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10756 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10757 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10758 QT_UINT16 (stsd_entry_data + offset + 14));
10759 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10761 if (compression_id == 0xfffe)
10762 entry->sampled = TRUE;
10764 /* first assume uncompressed audio */
10765 entry->bytes_per_sample = samplesize / 8;
10766 entry->samples_per_frame = entry->n_channels;
10767 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
10768 entry->samples_per_packet = entry->samples_per_frame;
10769 entry->bytes_per_packet = entry->bytes_per_sample;
10773 /* Yes, these have to be hard-coded */
10776 entry->samples_per_packet = 6;
10777 entry->bytes_per_packet = 1;
10778 entry->bytes_per_frame = 1 * entry->n_channels;
10779 entry->bytes_per_sample = 1;
10780 entry->samples_per_frame = 6 * entry->n_channels;
10785 entry->samples_per_packet = 3;
10786 entry->bytes_per_packet = 1;
10787 entry->bytes_per_frame = 1 * entry->n_channels;
10788 entry->bytes_per_sample = 1;
10789 entry->samples_per_frame = 3 * entry->n_channels;
10794 entry->samples_per_packet = 64;
10795 entry->bytes_per_packet = 34;
10796 entry->bytes_per_frame = 34 * entry->n_channels;
10797 entry->bytes_per_sample = 2;
10798 entry->samples_per_frame = 64 * entry->n_channels;
10804 entry->samples_per_packet = 1;
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 = 1 * entry->n_channels;
10813 entry->samples_per_packet = 160;
10814 entry->bytes_per_packet = 33;
10815 entry->bytes_per_frame = 33 * entry->n_channels;
10816 entry->bytes_per_sample = 2;
10817 entry->samples_per_frame = 160 * entry->n_channels;
10824 if (version == 0x00010000) {
10825 /* sample description entry (16) + sound sample description v1 (20+16) */
10836 /* only parse extra decoding config for non-pcm audio */
10837 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
10838 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
10839 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
10840 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
10842 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10843 entry->samples_per_packet);
10844 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10845 entry->bytes_per_packet);
10846 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10847 entry->bytes_per_frame);
10848 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10849 entry->bytes_per_sample);
10851 if (!entry->sampled && entry->bytes_per_packet) {
10852 entry->samples_per_frame = (entry->bytes_per_frame /
10853 entry->bytes_per_packet) * entry->samples_per_packet;
10854 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10855 entry->samples_per_frame);
10860 } else if (version == 0x00020000) {
10867 /* sample description entry (16) + sound sample description v2 (56) */
10871 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
10872 entry->rate = qtfp.fp;
10873 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
10875 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10876 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10877 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10878 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10879 QT_UINT32 (stsd_entry_data + offset + 20));
10880 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10881 QT_UINT32 (stsd_entry_data + offset + 24));
10882 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10883 QT_UINT32 (stsd_entry_data + offset + 28));
10884 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10885 QT_UINT32 (stsd_entry_data + offset + 32));
10886 } else if (version != 0x00000) {
10887 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
10892 gst_caps_unref (entry->caps);
10894 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
10895 stsd_entry_data + 32, len - 16, &codec);
10903 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10905 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10907 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10909 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10912 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10913 gst_caps_set_simple (entry->caps,
10914 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
10921 const guint8 *owma_data;
10922 const gchar *codec_name = NULL;
10926 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10927 /* FIXME this should also be gst_riff_strf_auds,
10928 * but the latter one is actually missing bits-per-sample :( */
10933 gint32 nSamplesPerSec;
10934 gint32 nAvgBytesPerSec;
10935 gint16 nBlockAlign;
10936 gint16 wBitsPerSample;
10939 WAVEFORMATEX *wfex;
10941 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10942 owma_data = stsd_entry_data;
10943 owma_len = QT_UINT32 (owma_data);
10944 if (owma_len <= 54) {
10945 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10948 wfex = (WAVEFORMATEX *) (owma_data + 36);
10949 buf = gst_buffer_new_and_alloc (owma_len - 54);
10950 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10951 if (wfex->wFormatTag == 0x0161) {
10952 codec_name = "Windows Media Audio";
10954 } else if (wfex->wFormatTag == 0x0162) {
10955 codec_name = "Windows Media Audio 9 Pro";
10957 } else if (wfex->wFormatTag == 0x0163) {
10958 codec_name = "Windows Media Audio 9 Lossless";
10959 /* is that correct? gstffmpegcodecmap.c is missing it, but
10960 * fluendo codec seems to support it */
10964 gst_caps_set_simple (entry->caps,
10965 "codec_data", GST_TYPE_BUFFER, buf,
10966 "wmaversion", G_TYPE_INT, version,
10967 "block_align", G_TYPE_INT,
10968 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
10969 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
10970 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
10971 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
10972 gst_buffer_unref (buf);
10976 codec = g_strdup (codec_name);
10982 gint len = QT_UINT32 (stsd_entry_data) - offset;
10983 const guint8 *wfex_data = stsd_entry_data + offset;
10984 const gchar *codec_name = NULL;
10986 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10987 /* FIXME this should also be gst_riff_strf_auds,
10988 * but the latter one is actually missing bits-per-sample :( */
10993 gint32 nSamplesPerSec;
10994 gint32 nAvgBytesPerSec;
10995 gint16 nBlockAlign;
10996 gint16 wBitsPerSample;
11001 /* FIXME: unify with similar wavformatex parsing code above */
11002 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11008 if (QT_UINT32 (wfex_data) <= len)
11009 size = QT_UINT32 (wfex_data) - 8;
11014 /* No real data, so break out */
11017 switch (QT_FOURCC (wfex_data + 4)) {
11018 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11020 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11025 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11026 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11027 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11028 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11029 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11030 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11031 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11033 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11034 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11035 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11036 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11037 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11038 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11040 if (wfex.wFormatTag == 0x0161) {
11041 codec_name = "Windows Media Audio";
11043 } else if (wfex.wFormatTag == 0x0162) {
11044 codec_name = "Windows Media Audio 9 Pro";
11046 } else if (wfex.wFormatTag == 0x0163) {
11047 codec_name = "Windows Media Audio 9 Lossless";
11048 /* is that correct? gstffmpegcodecmap.c is missing it, but
11049 * fluendo codec seems to support it */
11053 gst_caps_set_simple (entry->caps,
11054 "wmaversion", G_TYPE_INT, version,
11055 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11056 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11057 "width", G_TYPE_INT, wfex.wBitsPerSample,
11058 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11060 if (size > wfex.cbSize) {
11063 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11064 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11065 size - wfex.cbSize);
11066 gst_caps_set_simple (entry->caps,
11067 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11068 gst_buffer_unref (buf);
11070 GST_WARNING_OBJECT (qtdemux, "no codec data");
11075 codec = g_strdup (codec_name);
11083 wfex_data += size + 8;
11089 const guint8 *opus_data;
11090 guint8 *channel_mapping = NULL;
11093 guint8 channel_mapping_family;
11094 guint8 stream_count;
11095 guint8 coupled_count;
11098 opus_data = stsd_entry_data;
11100 channels = GST_READ_UINT8 (opus_data + 45);
11101 rate = GST_READ_UINT32_LE (opus_data + 48);
11102 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11103 stream_count = GST_READ_UINT8 (opus_data + 55);
11104 coupled_count = GST_READ_UINT8 (opus_data + 56);
11106 if (channels > 0) {
11107 channel_mapping = g_malloc (channels * sizeof (guint8));
11108 for (i = 0; i < channels; i++)
11109 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11112 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11113 channel_mapping_family, stream_count, coupled_count,
11125 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11126 GST_TAG_AUDIO_CODEC, codec, NULL);
11130 /* some bitrate info may have ended up in caps */
11131 s = gst_caps_get_structure (entry->caps, 0);
11132 gst_structure_get_int (s, "bitrate", &bitrate);
11134 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11135 GST_TAG_BITRATE, bitrate, NULL);
11138 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11139 if (!stream->protected) {
11141 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11145 if (stream->protected && fourcc == FOURCC_mp4a) {
11146 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11150 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11158 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11160 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11162 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11166 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11167 16 bits is a byte-swapped wave-style codec identifier,
11168 and we can find a WAVE header internally to a 'wave' atom here.
11169 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11170 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11173 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11174 if (len < offset + 20) {
11175 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11177 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11178 const guint8 *data = stsd_entry_data + offset + 16;
11180 GNode *waveheadernode;
11182 wavenode = g_node_new ((guint8 *) data);
11183 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11184 const guint8 *waveheader;
11187 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11188 if (waveheadernode) {
11189 waveheader = (const guint8 *) waveheadernode->data;
11190 headerlen = QT_UINT32 (waveheader);
11192 if (headerlen > 8) {
11193 gst_riff_strf_auds *header = NULL;
11194 GstBuffer *headerbuf;
11200 headerbuf = gst_buffer_new_and_alloc (headerlen);
11201 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11203 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11204 headerbuf, &header, &extra)) {
11205 gst_caps_unref (entry->caps);
11206 /* FIXME: Need to do something with the channel reorder map */
11208 gst_riff_create_audio_caps (header->format, NULL, header,
11209 extra, NULL, NULL, NULL);
11212 gst_buffer_unref (extra);
11217 GST_DEBUG ("Didn't find waveheadernode for this codec");
11219 g_node_destroy (wavenode);
11222 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11223 stream->stream_tags);
11227 /* FIXME: what is in the chunk? */
11230 gint len = QT_UINT32 (stsd_data);
11232 /* seems to be always = 116 = 0x74 */
11238 gint len = QT_UINT32 (stsd_entry_data);
11241 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11243 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11244 gst_caps_set_simple (entry->caps,
11245 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11246 gst_buffer_unref (buf);
11248 gst_caps_set_simple (entry->caps,
11249 "samplesize", G_TYPE_INT, samplesize, NULL);
11254 GNode *alac, *wave = NULL;
11256 /* apparently, m4a has this atom appended directly in the stsd entry,
11257 * while mov has it in a wave atom */
11258 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11260 /* alac now refers to stsd entry atom */
11261 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11263 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11265 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11268 const guint8 *alac_data = alac->data;
11269 gint len = QT_UINT32 (alac->data);
11273 GST_DEBUG_OBJECT (qtdemux,
11274 "discarding alac atom with unexpected len %d", len);
11276 /* codec-data contains alac atom size and prefix,
11277 * ffmpeg likes it that way, not quite gst-ish though ...*/
11278 buf = gst_buffer_new_and_alloc (len);
11279 gst_buffer_fill (buf, 0, alac->data, len);
11280 gst_caps_set_simple (entry->caps,
11281 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11282 gst_buffer_unref (buf);
11284 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11285 entry->n_channels = QT_UINT8 (alac_data + 21);
11286 entry->rate = QT_UINT32 (alac_data + 32);
11289 gst_caps_set_simple (entry->caps,
11290 "samplesize", G_TYPE_INT, samplesize, NULL);
11295 /* The codingname of the sample entry is 'fLaC' */
11296 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11299 /* The 'dfLa' box is added to the sample entry to convey
11300 initializing information for the decoder. */
11301 const GNode *dfla =
11302 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11305 const guint32 len = QT_UINT32 (dfla->data);
11307 /* Must contain at least dfLa box header (12),
11308 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11310 GST_DEBUG_OBJECT (qtdemux,
11311 "discarding dfla atom with unexpected len %d", len);
11313 /* skip dfLa header to get the METADATA_BLOCKs */
11314 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11315 const guint32 metadata_blocks_len = len - 12;
11317 gchar *stream_marker = g_strdup ("fLaC");
11318 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11319 strlen (stream_marker));
11322 guint32 remainder = 0;
11323 guint32 block_size = 0;
11324 gboolean is_last = FALSE;
11326 GValue array = G_VALUE_INIT;
11327 GValue value = G_VALUE_INIT;
11329 g_value_init (&array, GST_TYPE_ARRAY);
11330 g_value_init (&value, GST_TYPE_BUFFER);
11332 gst_value_set_buffer (&value, block);
11333 gst_value_array_append_value (&array, &value);
11334 g_value_reset (&value);
11336 gst_buffer_unref (block);
11338 /* check there's at least one METADATA_BLOCK_HEADER's worth
11339 * of data, and we haven't already finished parsing */
11340 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11341 remainder = metadata_blocks_len - index;
11343 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11345 (metadata_blocks[index + 1] << 16) +
11346 (metadata_blocks[index + 2] << 8) +
11347 metadata_blocks[index + 3];
11349 /* be careful not to read off end of box */
11350 if (block_size > remainder) {
11354 is_last = metadata_blocks[index] >> 7;
11356 block = gst_buffer_new_and_alloc (block_size);
11358 gst_buffer_fill (block, 0, &metadata_blocks[index],
11361 gst_value_set_buffer (&value, block);
11362 gst_value_array_append_value (&array, &value);
11363 g_value_reset (&value);
11365 gst_buffer_unref (block);
11367 index += block_size;
11370 /* only append the metadata if we successfully read all of it */
11372 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11373 (stream)->caps, 0), "streamheader", &array);
11375 GST_WARNING_OBJECT (qtdemux,
11376 "discarding all METADATA_BLOCKs due to invalid "
11377 "block_size %d at idx %d, rem %d", block_size, index,
11381 g_value_unset (&value);
11382 g_value_unset (&array);
11384 /* The sample rate obtained from the stsd may not be accurate
11385 * since it cannot represent rates greater than 65535Hz, so
11386 * override that value with the sample rate from the
11387 * METADATA_BLOCK_STREAMINFO block */
11388 CUR_STREAM (stream)->rate =
11389 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11400 gint len = QT_UINT32 (stsd_entry_data);
11403 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11406 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11408 /* If we have enough data, let's try to get the 'damr' atom. See
11409 * the 3GPP container spec (26.244) for more details. */
11410 if ((len - 0x34) > 8 &&
11411 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11412 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11413 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11416 gst_caps_set_simple (entry->caps,
11417 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11418 gst_buffer_unref (buf);
11424 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11425 gint len = QT_UINT32 (stsd_entry_data);
11428 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11430 if (sound_version == 1) {
11431 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11432 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11433 guint8 codec_data[2];
11435 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11437 gint sample_rate_index =
11438 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11440 /* build AAC codec data */
11441 codec_data[0] = profile << 3;
11442 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11443 codec_data[1] = (sample_rate_index & 0x01) << 7;
11444 codec_data[1] |= (channels & 0xF) << 3;
11446 buf = gst_buffer_new_and_alloc (2);
11447 gst_buffer_fill (buf, 0, codec_data, 2);
11448 gst_caps_set_simple (entry->caps,
11449 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11450 gst_buffer_unref (buf);
11456 GST_INFO_OBJECT (qtdemux,
11457 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11461 GST_INFO_OBJECT (qtdemux,
11462 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11463 GST_FOURCC_ARGS (fourcc), entry->caps);
11465 } else if (stream->subtype == FOURCC_strm) {
11466 if (fourcc == FOURCC_rtsp) {
11467 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11469 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11470 GST_FOURCC_ARGS (fourcc));
11471 goto unknown_stream;
11473 entry->sampled = TRUE;
11474 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11475 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11477 entry->sampled = TRUE;
11478 entry->sparse = TRUE;
11481 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11484 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11485 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11490 /* hunt for sort-of codec data */
11494 GNode *mp4s = NULL;
11495 GNode *esds = NULL;
11497 /* look for palette in a stsd->mp4s->esds sub-atom */
11498 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11500 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11501 if (esds == NULL) {
11503 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11507 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11508 stream->stream_tags);
11512 GST_INFO_OBJECT (qtdemux,
11513 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11516 GST_INFO_OBJECT (qtdemux,
11517 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11518 GST_FOURCC_ARGS (fourcc), entry->caps);
11520 /* everything in 1 sample */
11521 entry->sampled = TRUE;
11524 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11527 if (entry->caps == NULL)
11528 goto unknown_stream;
11531 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11532 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11538 /* promote to sampled format */
11539 if (entry->fourcc == FOURCC_samr) {
11540 /* force mono 8000 Hz for AMR */
11541 entry->sampled = TRUE;
11542 entry->n_channels = 1;
11543 entry->rate = 8000;
11544 } else if (entry->fourcc == FOURCC_sawb) {
11545 /* force mono 16000 Hz for AMR-WB */
11546 entry->sampled = TRUE;
11547 entry->n_channels = 1;
11548 entry->rate = 16000;
11549 } else if (entry->fourcc == FOURCC_mp4a) {
11550 entry->sampled = TRUE;
11554 stsd_entry_data += len;
11555 remaining_stsd_len -= len;
11559 /* collect sample information */
11560 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11561 goto samples_failed;
11563 if (qtdemux->fragmented) {
11566 /* need all moov samples as basis; probably not many if any at all */
11567 /* prevent moof parsing taking of at this time */
11568 offset = qtdemux->moof_offset;
11569 qtdemux->moof_offset = 0;
11570 if (stream->n_samples &&
11571 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11572 qtdemux->moof_offset = offset;
11573 goto samples_failed;
11575 qtdemux->moof_offset = 0;
11576 /* movie duration more reliable in this case (e.g. mehd) */
11577 if (qtdemux->segment.duration &&
11578 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11580 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11583 /* configure segments */
11584 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11585 goto segments_failed;
11587 /* add some language tag, if useful */
11588 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11589 strcmp (stream->lang_id, "und")) {
11590 const gchar *lang_code;
11592 /* convert ISO 639-2 code to ISO 639-1 */
11593 lang_code = gst_tag_get_language_code (stream->lang_id);
11594 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11595 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11598 /* Check for UDTA tags */
11599 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11600 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11603 /* now we are ready to add the stream */
11604 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11605 goto too_many_streams;
11607 if (!qtdemux->got_moov) {
11608 qtdemux->streams[qtdemux->n_streams] = stream;
11609 qtdemux->n_streams++;
11610 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11618 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11620 gst_qtdemux_stream_free (qtdemux, stream);
11625 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11626 (_("This file is corrupt and cannot be played.")), (NULL));
11628 gst_qtdemux_stream_free (qtdemux, stream);
11633 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11635 gst_qtdemux_stream_free (qtdemux, stream);
11641 /* we posted an error already */
11642 /* free stbl sub-atoms */
11643 gst_qtdemux_stbl_free (stream);
11645 gst_qtdemux_stream_free (qtdemux, stream);
11650 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11653 gst_qtdemux_stream_free (qtdemux, stream);
11658 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11659 GST_FOURCC_ARGS (stream->subtype));
11661 gst_qtdemux_stream_free (qtdemux, stream);
11666 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11667 (_("This file contains too many streams. Only playing first %d"),
11668 GST_QTDEMUX_MAX_STREAMS), (NULL));
11673 /* If we can estimate the overall bitrate, and don't have information about the
11674 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11675 * the overall bitrate minus the sum of the bitrates of all other streams. This
11676 * should be useful for the common case where we have one audio and one video
11677 * stream and can estimate the bitrate of one, but not the other. */
11679 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11681 QtDemuxStream *stream = NULL;
11682 gint64 size, sys_bitrate, sum_bitrate = 0;
11683 GstClockTime duration;
11687 if (qtdemux->fragmented)
11690 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11692 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11694 GST_DEBUG_OBJECT (qtdemux,
11695 "Size in bytes of the stream not known - bailing");
11699 /* Subtract the header size */
11700 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11701 size, qtdemux->header_size);
11703 if (size < qtdemux->header_size)
11706 size = size - qtdemux->header_size;
11708 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11709 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11713 for (i = 0; i < qtdemux->n_streams; i++) {
11714 switch (qtdemux->streams[i]->subtype) {
11717 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11718 CUR_STREAM (qtdemux->streams[i])->caps);
11719 /* retrieve bitrate, prefer avg then max */
11721 if (qtdemux->streams[i]->stream_tags) {
11722 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11723 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11724 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11725 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11726 GST_TAG_NOMINAL_BITRATE, &bitrate);
11727 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11728 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11729 GST_TAG_BITRATE, &bitrate);
11730 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11733 sum_bitrate += bitrate;
11736 GST_DEBUG_OBJECT (qtdemux,
11737 ">1 stream with unknown bitrate - bailing");
11740 stream = qtdemux->streams[i];
11744 /* For other subtypes, we assume no significant impact on bitrate */
11750 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11754 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11756 if (sys_bitrate < sum_bitrate) {
11757 /* This can happen, since sum_bitrate might be derived from maximum
11758 * bitrates and not average bitrates */
11759 GST_DEBUG_OBJECT (qtdemux,
11760 "System bitrate less than sum bitrate - bailing");
11764 bitrate = sys_bitrate - sum_bitrate;
11765 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11766 ", Stream bitrate = %u", sys_bitrate, bitrate);
11768 if (!stream->stream_tags)
11769 stream->stream_tags = gst_tag_list_new_empty ();
11771 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11773 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11774 GST_TAG_BITRATE, bitrate, NULL);
11777 static GstFlowReturn
11778 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11781 GstFlowReturn ret = GST_FLOW_OK;
11783 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11785 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11786 QtDemuxStream *stream = qtdemux->streams[i];
11787 guint32 sample_num = 0;
11789 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11790 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11792 if (qtdemux->fragmented) {
11793 /* need all moov samples first */
11794 GST_OBJECT_LOCK (qtdemux);
11795 while (stream->n_samples == 0)
11796 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11798 GST_OBJECT_UNLOCK (qtdemux);
11800 /* discard any stray moof */
11801 qtdemux->moof_offset = 0;
11804 /* prepare braking */
11805 if (ret != GST_FLOW_ERROR)
11808 /* in pull mode, we should have parsed some sample info by now;
11809 * and quite some code will not handle no samples.
11810 * in push mode, we'll just have to deal with it */
11811 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11812 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11813 gst_qtdemux_remove_stream (qtdemux, i);
11818 /* parse the initial sample for use in setting the frame rate cap */
11819 while (sample_num == 0 && sample_num < stream->n_samples) {
11820 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11824 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11825 stream->first_duration = stream->samples[0].duration;
11826 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11827 stream->track_id, stream->first_duration);
11834 static GstFlowReturn
11835 qtdemux_expose_streams (GstQTDemux * qtdemux)
11838 GSList *oldpads = NULL;
11841 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11843 for (i = 0; i < qtdemux->n_streams; i++) {
11844 QtDemuxStream *stream = qtdemux->streams[i];
11845 GstPad *oldpad = stream->pad;
11848 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11849 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11851 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11852 stream->track_id == qtdemux->chapters_track_id) {
11853 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11854 so that it doesn't look like a subtitle track */
11855 gst_qtdemux_remove_stream (qtdemux, i);
11860 /* now we have all info and can expose */
11861 list = stream->stream_tags;
11862 stream->stream_tags = NULL;
11864 oldpads = g_slist_prepend (oldpads, oldpad);
11865 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11866 return GST_FLOW_ERROR;
11869 gst_qtdemux_guess_bitrate (qtdemux);
11871 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11873 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11874 GstPad *oldpad = iter->data;
11877 event = gst_event_new_eos ();
11878 if (qtdemux->segment_seqnum)
11879 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11881 gst_pad_push_event (oldpad, event);
11882 gst_pad_set_active (oldpad, FALSE);
11883 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11884 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11885 gst_object_unref (oldpad);
11888 /* check if we should post a redirect in case there is a single trak
11889 * and it is a redirecting trak */
11890 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11893 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11894 "an external content");
11895 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11896 gst_structure_new ("redirect",
11897 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11899 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11900 qtdemux->posted_redirect = TRUE;
11903 for (i = 0; i < qtdemux->n_streams; i++) {
11904 QtDemuxStream *stream = qtdemux->streams[i];
11906 qtdemux_do_allocation (qtdemux, stream);
11909 qtdemux->exposed = TRUE;
11910 return GST_FLOW_OK;
11913 /* check if major or compatible brand is 3GP */
11914 static inline gboolean
11915 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11918 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11920 } else if (qtdemux->comp_brands != NULL) {
11924 gboolean res = FALSE;
11926 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11929 while (size >= 4) {
11930 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11935 gst_buffer_unmap (qtdemux->comp_brands, &map);
11942 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11943 static inline gboolean
11944 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11946 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11947 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11948 || fourcc == FOURCC_albm;
11952 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11953 const char *tag, const char *dummy, GNode * node)
11955 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11959 gdouble longitude, latitude, altitude;
11962 len = QT_UINT32 (node->data);
11969 /* TODO: language code skipped */
11971 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11974 /* do not alarm in trivial case, but bail out otherwise */
11975 if (*(data + offset) != 0) {
11976 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11980 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11981 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11982 offset += strlen (name);
11986 if (len < offset + 2 + 4 + 4 + 4)
11989 /* +1 +1 = skip null-terminator and location role byte */
11991 /* table in spec says unsigned, semantics say negative has meaning ... */
11992 longitude = QT_SFP32 (data + offset);
11995 latitude = QT_SFP32 (data + offset);
11998 altitude = QT_SFP32 (data + offset);
12000 /* one invalid means all are invalid */
12001 if (longitude >= -180.0 && longitude <= 180.0 &&
12002 latitude >= -90.0 && latitude <= 90.0) {
12003 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12004 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12005 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12006 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12009 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12016 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12023 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12024 const char *tag, const char *dummy, GNode * node)
12030 len = QT_UINT32 (node->data);
12034 y = QT_UINT16 ((guint8 *) node->data + 12);
12036 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12039 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12041 date = g_date_new_dmy (1, 1, y);
12042 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12043 g_date_free (date);
12047 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12048 const char *tag, const char *dummy, GNode * node)
12051 char *tag_str = NULL;
12056 len = QT_UINT32 (node->data);
12061 entity = (guint8 *) node->data + offset;
12062 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12063 GST_DEBUG_OBJECT (qtdemux,
12064 "classification info: %c%c%c%c invalid classification entity",
12065 entity[0], entity[1], entity[2], entity[3]);
12070 table = QT_UINT16 ((guint8 *) node->data + offset);
12072 /* Language code skipped */
12076 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12077 * XXXX: classification entity, fixed length 4 chars.
12078 * Y[YYYY]: classification table, max 5 chars.
12080 tag_str = g_strdup_printf ("----://%u/%s",
12081 table, (char *) node->data + offset);
12083 /* memcpy To be sure we're preserving byte order */
12084 memcpy (tag_str, entity, 4);
12085 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12087 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12096 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12102 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12103 const char *tag, const char *dummy, GNode * node)
12105 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12111 gboolean ret = TRUE;
12112 const gchar *charset = NULL;
12114 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12116 len = QT_UINT32 (data->data);
12117 type = QT_UINT32 ((guint8 *) data->data + 8);
12118 if (type == 0x00000001 && len > 16) {
12119 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12122 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12123 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12126 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12130 len = QT_UINT32 (node->data);
12131 type = QT_UINT32 ((guint8 *) node->data + 4);
12132 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12136 /* Type starts with the (C) symbol, so the next data is a list
12137 * of (string size(16), language code(16), string) */
12139 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12140 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12142 /* the string + fourcc + size + 2 16bit fields,
12143 * means that there are more tags in this atom */
12144 if (len > str_len + 8 + 4) {
12145 /* TODO how to represent the same tag in different languages? */
12146 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12147 "text alternatives, reading only first one");
12151 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12152 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12154 if (lang_code < 0x800) { /* MAC encoded string */
12157 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12158 QT_FOURCC ((guint8 *) node->data + 4))) {
12159 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12161 /* we go for 3GP style encoding if major brands claims so,
12162 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12163 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12164 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12165 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12167 /* 16-bit Language code is ignored here as well */
12168 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12175 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12176 ret = FALSE; /* may have to fallback */
12179 GError *err = NULL;
12181 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12182 charset, NULL, NULL, &err);
12184 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12185 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12187 g_error_free (err);
12190 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12191 len - offset, env_vars);
12194 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12195 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12199 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12206 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12207 const char *tag, const char *dummy, GNode * node)
12209 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12213 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12214 const char *tag, const char *dummy, GNode * node)
12216 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12218 char *s, *t, *k = NULL;
12223 /* first try normal string tag if major brand not 3GP */
12224 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12225 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12226 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12227 * let's try it 3gpp way after minor safety check */
12229 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12235 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12239 len = QT_UINT32 (data);
12243 count = QT_UINT8 (data + 14);
12245 for (; count; count--) {
12248 if (offset + 1 > len)
12250 slen = QT_UINT8 (data + offset);
12252 if (offset + slen > len)
12254 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12257 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12259 t = g_strjoin (",", k, s, NULL);
12267 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12274 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12275 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12284 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12290 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12291 const char *tag1, const char *tag2, GNode * node)
12298 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12300 len = QT_UINT32 (data->data);
12301 type = QT_UINT32 ((guint8 *) data->data + 8);
12302 if (type == 0x00000000 && len >= 22) {
12303 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12304 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12306 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12307 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12310 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12311 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12318 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12319 const char *tag1, const char *dummy, GNode * node)
12326 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12328 len = QT_UINT32 (data->data);
12329 type = QT_UINT32 ((guint8 *) data->data + 8);
12330 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12331 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12332 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12333 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12335 /* do not add bpm=0 */
12336 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12337 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12345 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12346 const char *tag1, const char *dummy, GNode * node)
12353 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12355 len = QT_UINT32 (data->data);
12356 type = QT_UINT32 ((guint8 *) data->data + 8);
12357 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12358 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12359 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12360 num = QT_UINT32 ((guint8 *) data->data + 16);
12362 /* do not add num=0 */
12363 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12364 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12371 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12372 const char *tag1, const char *dummy, GNode * node)
12379 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12381 len = QT_UINT32 (data->data);
12382 type = QT_UINT32 ((guint8 *) data->data + 8);
12383 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12384 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12385 GstTagImageType image_type;
12387 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12388 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12390 image_type = GST_TAG_IMAGE_TYPE_NONE;
12393 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12394 len - 16, image_type))) {
12395 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12396 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12397 gst_sample_unref (sample);
12404 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12405 const char *tag, const char *dummy, GNode * node)
12412 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12414 len = QT_UINT32 (data->data);
12415 type = QT_UINT32 ((guint8 *) data->data + 8);
12416 if (type == 0x00000001 && len > 16) {
12417 guint y, m = 1, d = 1;
12420 s = g_strndup ((char *) data->data + 16, len - 16);
12421 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12422 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12423 if (ret >= 1 && y > 1500 && y < 3000) {
12426 date = g_date_new_dmy (d, m, y);
12427 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12428 g_date_free (date);
12430 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12438 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12439 const char *tag, const char *dummy, GNode * node)
12443 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12445 /* re-route to normal string tag if major brand says so
12446 * or no data atom and compatible brand suggests so */
12447 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12448 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12449 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12454 guint len, type, n;
12456 len = QT_UINT32 (data->data);
12457 type = QT_UINT32 ((guint8 *) data->data + 8);
12458 if (type == 0x00000000 && len >= 18) {
12459 n = QT_UINT16 ((guint8 *) data->data + 16);
12461 const gchar *genre;
12463 genre = gst_tag_id3_genre_get (n - 1);
12464 if (genre != NULL) {
12465 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12466 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12474 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12475 const gchar * tag, guint8 * data, guint32 datasize)
12480 /* make a copy to have \0 at the end */
12481 datacopy = g_strndup ((gchar *) data, datasize);
12483 /* convert the str to double */
12484 if (sscanf (datacopy, "%lf", &value) == 1) {
12485 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12486 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12488 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12496 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12497 const char *tag, const char *tag_bis, GNode * node)
12506 const gchar *meanstr;
12507 const gchar *namestr;
12509 /* checking the whole ---- atom size for consistency */
12510 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12511 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12515 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12517 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12521 meansize = QT_UINT32 (mean->data);
12522 if (meansize <= 12) {
12523 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12526 meanstr = ((gchar *) mean->data) + 12;
12529 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12531 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12535 namesize = QT_UINT32 (name->data);
12536 if (namesize <= 12) {
12537 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12540 namestr = ((gchar *) name->data) + 12;
12548 * uint24 - data type
12552 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12554 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12557 datasize = QT_UINT32 (data->data);
12558 if (datasize <= 16) {
12559 GST_WARNING_OBJECT (demux, "Data atom too small");
12562 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12564 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12565 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12566 static const struct
12568 const gchar name[28];
12569 const gchar tag[28];
12572 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12573 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12574 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12575 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12576 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12577 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12578 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12579 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12583 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12584 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12585 switch (gst_tag_get_type (tags[i].tag)) {
12586 case G_TYPE_DOUBLE:
12587 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12588 ((guint8 *) data->data) + 16, datasize - 16);
12590 case G_TYPE_STRING:
12591 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12600 if (i == G_N_ELEMENTS (tags))
12610 #ifndef GST_DISABLE_GST_DEBUG
12612 gchar *namestr_dbg;
12613 gchar *meanstr_dbg;
12615 meanstr_dbg = g_strndup (meanstr, meansize);
12616 namestr_dbg = g_strndup (namestr, namesize);
12618 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12619 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12621 g_free (namestr_dbg);
12622 g_free (meanstr_dbg);
12629 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12630 const char *tag_bis, GNode * node)
12635 GstTagList *id32_taglist = NULL;
12637 GST_LOG_OBJECT (demux, "parsing ID32");
12640 len = GST_READ_UINT32_BE (data);
12642 /* need at least full box and language tag */
12646 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12647 gst_buffer_fill (buf, 0, data + 14, len - 14);
12649 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12650 if (id32_taglist) {
12651 GST_LOG_OBJECT (demux, "parsing ok");
12652 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12653 gst_tag_list_unref (id32_taglist);
12655 GST_LOG_OBJECT (demux, "parsing failed");
12658 gst_buffer_unref (buf);
12661 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12662 const char *tag, const char *tag_bis, GNode * node);
12665 FOURCC_pcst -> if media is a podcast -> bool
12666 FOURCC_cpil -> if media is part of a compilation -> bool
12667 FOURCC_pgap -> if media is part of a gapless context -> bool
12668 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12671 static const struct
12674 const gchar *gst_tag;
12675 const gchar *gst_tag_bis;
12676 const GstQTDemuxAddTagFunc func;
12679 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12680 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12681 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12682 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12683 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12684 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12685 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12686 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12687 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12688 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12689 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12690 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12691 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12692 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12693 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12694 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12695 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12696 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12697 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12698 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12699 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12700 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12701 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12702 qtdemux_tag_add_num}, {
12703 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12704 qtdemux_tag_add_num}, {
12705 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12706 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12707 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12708 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12709 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12710 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12711 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12712 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12713 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12714 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12715 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12716 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12717 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12718 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12719 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12720 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12721 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12722 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12723 qtdemux_tag_add_classification}, {
12724 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12725 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12726 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12728 /* This is a special case, some tags are stored in this
12729 * 'reverse dns naming', according to:
12730 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12733 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12734 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12735 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12738 struct _GstQtDemuxTagList
12741 GstTagList *taglist;
12743 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12746 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12752 const gchar *style;
12757 GstQTDemux *demux = qtdemuxtaglist->demux;
12758 GstTagList *taglist = qtdemuxtaglist->taglist;
12761 len = QT_UINT32 (data);
12762 buf = gst_buffer_new_and_alloc (len);
12763 gst_buffer_fill (buf, 0, data, len);
12765 /* heuristic to determine style of tag */
12766 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12767 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12769 else if (demux->major_brand == FOURCC_qt__)
12770 style = "quicktime";
12771 /* fall back to assuming iso/3gp tag style */
12775 /* santize the name for the caps. */
12776 for (i = 0; i < 4; i++) {
12777 guint8 d = data[4 + i];
12778 if (g_ascii_isalnum (d))
12779 ndata[i] = g_ascii_tolower (d);
12784 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12785 ndata[0], ndata[1], ndata[2], ndata[3]);
12786 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12788 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12789 sample = gst_sample_new (buf, NULL, NULL, s);
12790 gst_buffer_unref (buf);
12791 g_free (media_type);
12793 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12796 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12797 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12799 gst_sample_unref (sample);
12803 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12810 GstQtDemuxTagList demuxtaglist;
12812 demuxtaglist.demux = qtdemux;
12813 demuxtaglist.taglist = taglist;
12815 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12816 if (meta != NULL) {
12817 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12818 if (ilst == NULL) {
12819 GST_LOG_OBJECT (qtdemux, "no ilst");
12824 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12828 while (i < G_N_ELEMENTS (add_funcs)) {
12829 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12833 len = QT_UINT32 (node->data);
12835 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12836 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12838 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12839 add_funcs[i].gst_tag_bis, node);
12841 g_node_destroy (node);
12847 /* parsed nodes have been removed, pass along remainder as blob */
12848 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12849 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12851 /* parse up XMP_ node if existing */
12852 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12853 if (xmp_ != NULL) {
12855 GstTagList *xmptaglist;
12857 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12858 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12859 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12860 gst_buffer_unref (buf);
12862 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12864 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12870 GstStructure *structure; /* helper for sort function */
12872 guint min_req_bitrate;
12873 guint min_req_qt_version;
12877 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12879 GstQtReference *ref_a = (GstQtReference *) a;
12880 GstQtReference *ref_b = (GstQtReference *) b;
12882 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12883 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12885 /* known bitrates go before unknown; higher bitrates go first */
12886 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12889 /* sort the redirects and post a message for the application.
12892 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12894 GstQtReference *best;
12897 GValue list_val = { 0, };
12900 g_assert (references != NULL);
12902 references = g_list_sort (references, qtdemux_redirects_sort_func);
12904 best = (GstQtReference *) references->data;
12906 g_value_init (&list_val, GST_TYPE_LIST);
12908 for (l = references; l != NULL; l = l->next) {
12909 GstQtReference *ref = (GstQtReference *) l->data;
12910 GValue struct_val = { 0, };
12912 ref->structure = gst_structure_new ("redirect",
12913 "new-location", G_TYPE_STRING, ref->location, NULL);
12915 if (ref->min_req_bitrate > 0) {
12916 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12917 ref->min_req_bitrate, NULL);
12920 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12921 g_value_set_boxed (&struct_val, ref->structure);
12922 gst_value_list_append_value (&list_val, &struct_val);
12923 g_value_unset (&struct_val);
12924 /* don't free anything here yet, since we need best->structure below */
12927 g_assert (best != NULL);
12928 s = gst_structure_copy (best->structure);
12930 if (g_list_length (references) > 1) {
12931 gst_structure_set_value (s, "locations", &list_val);
12934 g_value_unset (&list_val);
12936 for (l = references; l != NULL; l = l->next) {
12937 GstQtReference *ref = (GstQtReference *) l->data;
12939 gst_structure_free (ref->structure);
12940 g_free (ref->location);
12943 g_list_free (references);
12945 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12946 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12947 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12948 qtdemux->posted_redirect = TRUE;
12951 /* look for redirect nodes, collect all redirect information and
12955 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12957 GNode *rmra, *rmda, *rdrf;
12959 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12961 GList *redirects = NULL;
12963 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12965 GstQtReference ref = { NULL, NULL, 0, 0 };
12966 GNode *rmdr, *rmvc;
12968 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12969 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12970 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12971 ref.min_req_bitrate);
12974 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12975 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12976 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12978 #ifndef GST_DISABLE_GST_DEBUG
12979 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12981 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12983 GST_LOG_OBJECT (qtdemux,
12984 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12985 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12986 bitmask, check_type);
12987 if (package == FOURCC_qtim && check_type == 0) {
12988 ref.min_req_qt_version = version;
12992 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12998 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12999 if (ref_len > 20) {
13000 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13001 ref_data = (guint8 *) rdrf->data + 20;
13002 if (ref_type == FOURCC_alis) {
13003 guint record_len, record_version, fn_len;
13005 if (ref_len > 70) {
13006 /* MacOSX alias record, google for alias-layout.txt */
13007 record_len = QT_UINT16 (ref_data + 4);
13008 record_version = QT_UINT16 (ref_data + 4 + 2);
13009 fn_len = QT_UINT8 (ref_data + 50);
13010 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13011 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13014 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13017 } else if (ref_type == FOURCC_url_) {
13018 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13020 GST_DEBUG_OBJECT (qtdemux,
13021 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13022 GST_FOURCC_ARGS (ref_type));
13024 if (ref.location != NULL) {
13025 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13027 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13029 GST_WARNING_OBJECT (qtdemux,
13030 "Failed to extract redirect location from rdrf atom");
13033 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13037 /* look for others */
13038 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13041 if (redirects != NULL) {
13042 qtdemux_process_redirects (qtdemux, redirects);
13048 static GstTagList *
13049 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13053 if (tags == NULL) {
13054 tags = gst_tag_list_new_empty ();
13055 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13058 if (qtdemux->major_brand == FOURCC_mjp2)
13059 fmt = "Motion JPEG 2000";
13060 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13062 else if (qtdemux->major_brand == FOURCC_qt__)
13064 else if (qtdemux->fragmented)
13067 fmt = "ISO MP4/M4A";
13069 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13070 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13072 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13078 /* we have read the complete moov node now.
13079 * This function parses all of the relevant info, creates the traks and
13080 * prepares all data structures for playback
13083 qtdemux_parse_tree (GstQTDemux * qtdemux)
13089 GstClockTime duration;
13091 guint64 creation_time;
13092 GstDateTime *datetime = NULL;
13095 /* make sure we have a usable taglist */
13096 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13098 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13099 if (mvhd == NULL) {
13100 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13101 return qtdemux_parse_redirects (qtdemux);
13104 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13105 if (version == 1) {
13106 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13107 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13108 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13109 } else if (version == 0) {
13110 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13111 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13112 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13114 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13118 /* Moving qt creation time (secs since 1904) to unix time */
13119 if (creation_time != 0) {
13120 /* Try to use epoch first as it should be faster and more commonly found */
13121 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13124 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13125 /* some data cleansing sanity */
13126 g_get_current_time (&now);
13127 if (now.tv_sec + 24 * 3600 < creation_time) {
13128 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13130 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13133 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13134 GDateTime *dt, *dt_local;
13136 dt = g_date_time_add_seconds (base_dt, creation_time);
13137 dt_local = g_date_time_to_local (dt);
13138 datetime = gst_date_time_new_from_g_date_time (dt_local);
13140 g_date_time_unref (base_dt);
13141 g_date_time_unref (dt);
13145 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13146 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13148 gst_date_time_unref (datetime);
13151 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13152 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13154 /* check for fragmented file and get some (default) data */
13155 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13158 GstByteReader mehd_data;
13160 /* let track parsing or anyone know weird stuff might happen ... */
13161 qtdemux->fragmented = TRUE;
13163 /* compensate for total duration */
13164 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13166 qtdemux_parse_mehd (qtdemux, &mehd_data);
13169 /* set duration in the segment info */
13170 gst_qtdemux_get_duration (qtdemux, &duration);
13172 qtdemux->segment.duration = duration;
13173 /* also do not exceed duration; stop is set that way post seek anyway,
13174 * and segment activation falls back to duration,
13175 * whereas loop only checks stop, so let's align this here as well */
13176 qtdemux->segment.stop = duration;
13179 /* parse all traks */
13180 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13182 qtdemux_parse_trak (qtdemux, trak);
13183 /* iterate all siblings */
13184 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13187 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13190 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13192 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13194 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13197 /* maybe also some tags in meta box */
13198 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13200 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13201 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13203 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13206 /* parse any protection system info */
13207 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13209 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13210 qtdemux_parse_pssh (qtdemux, pssh);
13211 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13214 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13219 /* taken from ffmpeg */
13221 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13233 len = (len << 7) | (c & 0x7f);
13241 /* this can change the codec originally present in @list */
13243 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13244 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13246 int len = QT_UINT32 (esds->data);
13247 guint8 *ptr = esds->data;
13248 guint8 *end = ptr + len;
13250 guint8 *data_ptr = NULL;
13252 guint8 object_type_id = 0;
13253 const char *codec_name = NULL;
13254 GstCaps *caps = NULL;
13256 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13258 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13260 while (ptr + 1 < end) {
13261 tag = QT_UINT8 (ptr);
13262 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13264 len = read_descr_size (ptr, end, &ptr);
13265 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13267 /* Check the stated amount of data is available for reading */
13268 if (len < 0 || ptr + len > end)
13272 case ES_DESCRIPTOR_TAG:
13273 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13274 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13277 case DECODER_CONFIG_DESC_TAG:{
13278 guint max_bitrate, avg_bitrate;
13280 object_type_id = QT_UINT8 (ptr);
13281 max_bitrate = QT_UINT32 (ptr + 5);
13282 avg_bitrate = QT_UINT32 (ptr + 9);
13283 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13284 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13285 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13286 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13287 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13288 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13289 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13290 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13292 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13293 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13294 avg_bitrate, NULL);
13299 case DECODER_SPECIFIC_INFO_TAG:
13300 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13301 if (object_type_id == 0xe0 && len == 0x40) {
13307 GST_DEBUG_OBJECT (qtdemux,
13308 "Have VOBSUB palette. Creating palette event");
13309 /* move to decConfigDescr data and read palette */
13311 for (i = 0; i < 16; i++) {
13312 clut[i] = QT_UINT32 (data);
13316 s = gst_structure_new ("application/x-gst-dvd", "event",
13317 G_TYPE_STRING, "dvd-spu-clut-change",
13318 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13319 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13320 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13321 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13322 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13323 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13324 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13325 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13328 /* store event and trigger custom processing */
13329 stream->pending_event =
13330 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13332 /* Generic codec_data handler puts it on the caps */
13339 case SL_CONFIG_DESC_TAG:
13340 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13344 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13346 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13352 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13353 * in use, and should also be used to override some other parameters for some
13355 switch (object_type_id) {
13356 case 0x20: /* MPEG-4 */
13357 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13358 * profile_and_level_indication */
13359 if (data_ptr != NULL && data_len >= 5 &&
13360 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13361 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13362 data_ptr + 4, data_len - 4);
13364 break; /* Nothing special needed here */
13365 case 0x21: /* H.264 */
13366 codec_name = "H.264 / AVC";
13367 caps = gst_caps_new_simple ("video/x-h264",
13368 "stream-format", G_TYPE_STRING, "avc",
13369 "alignment", G_TYPE_STRING, "au", NULL);
13371 case 0x40: /* AAC (any) */
13372 case 0x66: /* AAC Main */
13373 case 0x67: /* AAC LC */
13374 case 0x68: /* AAC SSR */
13375 /* Override channels and rate based on the codec_data, as it's often
13377 /* Only do so for basic setup without HE-AAC extension */
13378 if (data_ptr && data_len == 2) {
13379 guint channels, rate;
13381 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13383 entry->n_channels = channels;
13385 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13387 entry->rate = rate;
13390 /* Set level and profile if possible */
13391 if (data_ptr != NULL && data_len >= 2) {
13392 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13393 data_ptr, data_len);
13395 const gchar *profile_str = NULL;
13398 guint8 *codec_data;
13399 gint rate_idx, profile;
13401 /* No codec_data, let's invent something.
13402 * FIXME: This is wrong for SBR! */
13404 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13406 buffer = gst_buffer_new_and_alloc (2);
13407 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13408 codec_data = map.data;
13411 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13414 switch (object_type_id) {
13416 profile_str = "main";
13420 profile_str = "lc";
13424 profile_str = "ssr";
13432 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13434 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13436 gst_buffer_unmap (buffer, &map);
13437 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13438 GST_TYPE_BUFFER, buffer, NULL);
13439 gst_buffer_unref (buffer);
13442 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13443 G_TYPE_STRING, profile_str, NULL);
13447 case 0x60: /* MPEG-2, various profiles */
13453 codec_name = "MPEG-2 video";
13454 caps = gst_caps_new_simple ("video/mpeg",
13455 "mpegversion", G_TYPE_INT, 2,
13456 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13458 case 0x69: /* MPEG-2 BC audio */
13459 case 0x6B: /* MPEG-1 audio */
13460 caps = gst_caps_new_simple ("audio/mpeg",
13461 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13462 codec_name = "MPEG-1 audio";
13464 case 0x6A: /* MPEG-1 */
13465 codec_name = "MPEG-1 video";
13466 caps = gst_caps_new_simple ("video/mpeg",
13467 "mpegversion", G_TYPE_INT, 1,
13468 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13470 case 0x6C: /* MJPEG */
13472 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13474 codec_name = "Motion-JPEG";
13476 case 0x6D: /* PNG */
13478 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13480 codec_name = "PNG still images";
13482 case 0x6E: /* JPEG2000 */
13483 codec_name = "JPEG-2000";
13484 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13486 case 0xA4: /* Dirac */
13487 codec_name = "Dirac";
13488 caps = gst_caps_new_empty_simple ("video/x-dirac");
13490 case 0xA5: /* AC3 */
13491 codec_name = "AC-3 audio";
13492 caps = gst_caps_new_simple ("audio/x-ac3",
13493 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13495 case 0xA9: /* AC3 */
13496 codec_name = "DTS audio";
13497 caps = gst_caps_new_simple ("audio/x-dts",
13498 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13500 case 0xE1: /* QCELP */
13501 /* QCELP, the codec_data is a riff tag (little endian) with
13502 * 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). */
13503 caps = gst_caps_new_empty_simple ("audio/qcelp");
13504 codec_name = "QCELP";
13510 /* If we have a replacement caps, then change our caps for this stream */
13512 gst_caps_unref (entry->caps);
13513 entry->caps = caps;
13516 if (codec_name && list)
13517 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13518 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13520 /* Add the codec_data attribute to caps, if we have it */
13524 buffer = gst_buffer_new_and_alloc (data_len);
13525 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13527 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13528 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13530 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13532 gst_buffer_unref (buffer);
13537 static inline GstCaps *
13538 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13542 char *s, fourstr[5];
13544 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13545 for (i = 0; i < 4; i++) {
13546 if (!g_ascii_isalnum (fourstr[i]))
13549 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13550 caps = gst_caps_new_empty_simple (s);
13555 #define _codec(name) \
13557 if (codec_name) { \
13558 *codec_name = g_strdup (name); \
13563 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13564 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
13565 const guint8 * stsd_entry_data, gchar ** codec_name)
13567 GstCaps *caps = NULL;
13568 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13572 _codec ("PNG still images");
13573 caps = gst_caps_new_empty_simple ("image/png");
13576 _codec ("JPEG still images");
13578 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13581 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13582 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13583 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13584 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13585 _codec ("Motion-JPEG");
13587 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13590 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13591 _codec ("Motion-JPEG format B");
13592 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13595 _codec ("JPEG-2000");
13596 /* override to what it should be according to spec, avoid palette_data */
13597 entry->bits_per_sample = 24;
13598 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13601 _codec ("Sorensen video v.3");
13602 caps = gst_caps_new_simple ("video/x-svq",
13603 "svqversion", G_TYPE_INT, 3, NULL);
13605 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13606 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13607 _codec ("Sorensen video v.1");
13608 caps = gst_caps_new_simple ("video/x-svq",
13609 "svqversion", G_TYPE_INT, 1, NULL);
13611 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13612 caps = gst_caps_new_empty_simple ("video/x-raw");
13613 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13614 _codec ("Windows Raw RGB");
13615 stream->alignment = 32;
13621 bps = QT_UINT16 (stsd_entry_data + 82);
13624 format = GST_VIDEO_FORMAT_RGB15;
13627 format = GST_VIDEO_FORMAT_RGB16;
13630 format = GST_VIDEO_FORMAT_RGB;
13633 format = GST_VIDEO_FORMAT_ARGB;
13641 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13642 format = GST_VIDEO_FORMAT_I420;
13644 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13645 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13646 format = GST_VIDEO_FORMAT_I420;
13649 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13650 format = GST_VIDEO_FORMAT_UYVY;
13652 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13653 format = GST_VIDEO_FORMAT_v308;
13655 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13656 format = GST_VIDEO_FORMAT_v216;
13659 format = GST_VIDEO_FORMAT_v210;
13661 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13662 format = GST_VIDEO_FORMAT_r210;
13664 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13665 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13666 format = GST_VIDEO_FORMAT_v410;
13669 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13670 * but different order than AYUV
13671 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13672 format = GST_VIDEO_FORMAT_v408;
13675 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13676 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13677 _codec ("MPEG-1 video");
13678 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13679 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13681 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13682 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13683 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13684 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13685 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13686 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13687 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13688 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13689 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13690 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13691 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13692 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13693 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13694 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13695 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13696 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13697 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13698 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13699 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13700 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13701 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13702 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13703 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13704 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13705 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13706 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13707 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13708 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13709 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13710 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13711 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13712 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13713 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13714 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13715 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13716 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13717 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13718 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13719 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13720 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13721 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13722 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13723 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13724 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13725 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13726 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13727 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13728 _codec ("MPEG-2 video");
13729 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13730 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13732 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13733 _codec ("GIF still images");
13734 caps = gst_caps_new_empty_simple ("image/gif");
13737 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13739 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13741 /* ffmpeg uses the height/width props, don't know why */
13742 caps = gst_caps_new_simple ("video/x-h263",
13743 "variant", G_TYPE_STRING, "itu", NULL);
13747 _codec ("MPEG-4 video");
13748 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13749 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13751 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13752 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13753 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13754 caps = gst_caps_new_simple ("video/x-msmpeg",
13755 "msmpegversion", G_TYPE_INT, 43, NULL);
13757 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13759 caps = gst_caps_new_simple ("video/x-divx",
13760 "divxversion", G_TYPE_INT, 3, NULL);
13762 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13763 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13765 caps = gst_caps_new_simple ("video/x-divx",
13766 "divxversion", G_TYPE_INT, 4, NULL);
13768 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13770 caps = gst_caps_new_simple ("video/x-divx",
13771 "divxversion", G_TYPE_INT, 5, NULL);
13774 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13776 caps = gst_caps_new_simple ("video/x-ffv",
13777 "ffvversion", G_TYPE_INT, 1, NULL);
13780 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13781 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13786 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13787 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13788 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13792 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13793 _codec ("Cinepak");
13794 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13796 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13797 _codec ("Apple QuickDraw");
13798 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13800 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13801 _codec ("Apple video");
13802 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13806 _codec ("H.264 / AVC");
13807 caps = gst_caps_new_simple ("video/x-h264",
13808 "stream-format", G_TYPE_STRING, "avc",
13809 "alignment", G_TYPE_STRING, "au", NULL);
13812 _codec ("H.264 / AVC");
13813 caps = gst_caps_new_simple ("video/x-h264",
13814 "stream-format", G_TYPE_STRING, "avc3",
13815 "alignment", G_TYPE_STRING, "au", NULL);
13819 _codec ("H.265 / HEVC");
13820 caps = gst_caps_new_simple ("video/x-h265",
13821 "stream-format", G_TYPE_STRING, "hvc1",
13822 "alignment", G_TYPE_STRING, "au", NULL);
13825 _codec ("H.265 / HEVC");
13826 caps = gst_caps_new_simple ("video/x-h265",
13827 "stream-format", G_TYPE_STRING, "hev1",
13828 "alignment", G_TYPE_STRING, "au", NULL);
13831 _codec ("Run-length encoding");
13832 caps = gst_caps_new_simple ("video/x-rle",
13833 "layout", G_TYPE_STRING, "quicktime", NULL);
13836 _codec ("Run-length encoding");
13837 caps = gst_caps_new_simple ("video/x-rle",
13838 "layout", G_TYPE_STRING, "microsoft", NULL);
13840 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13841 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13842 _codec ("Indeo Video 3");
13843 caps = gst_caps_new_simple ("video/x-indeo",
13844 "indeoversion", G_TYPE_INT, 3, NULL);
13846 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13847 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13848 _codec ("Intel Video 4");
13849 caps = gst_caps_new_simple ("video/x-indeo",
13850 "indeoversion", G_TYPE_INT, 4, NULL);
13854 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13855 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13856 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13857 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13858 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13859 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13860 _codec ("DV Video");
13861 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13862 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13864 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13865 case FOURCC_dv5p: /* DVCPRO50 PAL */
13866 _codec ("DVCPro50 Video");
13867 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13868 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13870 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13871 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13872 _codec ("DVCProHD Video");
13873 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13874 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13876 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13877 _codec ("Apple Graphics (SMC)");
13878 caps = gst_caps_new_empty_simple ("video/x-smc");
13880 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13882 caps = gst_caps_new_empty_simple ("video/x-vp3");
13884 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13885 _codec ("VP6 Flash");
13886 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13890 caps = gst_caps_new_empty_simple ("video/x-theora");
13891 /* theora uses one byte of padding in the data stream because it does not
13892 * allow 0 sized packets while theora does */
13893 entry->padding = 1;
13897 caps = gst_caps_new_empty_simple ("video/x-dirac");
13899 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13900 _codec ("TIFF still images");
13901 caps = gst_caps_new_empty_simple ("image/tiff");
13903 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13904 _codec ("Apple Intermediate Codec");
13905 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13907 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13908 _codec ("AVID DNxHD");
13909 caps = gst_caps_from_string ("video/x-dnxhd");
13912 _codec ("On2 VP8");
13913 caps = gst_caps_from_string ("video/x-vp8");
13916 _codec ("Apple ProRes LT");
13918 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13922 _codec ("Apple ProRes HQ");
13924 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13928 _codec ("Apple ProRes");
13930 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13934 _codec ("Apple ProRes Proxy");
13936 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13940 _codec ("Apple ProRes 4444");
13942 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13946 _codec ("Apple ProRes 4444 XQ");
13948 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13952 _codec ("GoPro CineForm");
13953 caps = gst_caps_from_string ("video/x-cineform");
13958 caps = gst_caps_new_simple ("video/x-wmv",
13959 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13961 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13964 caps = _get_unknown_codec_name ("video", fourcc);
13969 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13972 gst_video_info_init (&info);
13973 gst_video_info_set_format (&info, format, entry->width, entry->height);
13975 caps = gst_video_info_to_caps (&info);
13976 *codec_name = gst_pb_utils_get_codec_description (caps);
13978 /* enable clipping for raw video streams */
13979 stream->need_clip = TRUE;
13980 stream->alignment = 32;
13987 round_up_pow2 (guint n)
13999 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14000 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14001 int len, gchar ** codec_name)
14004 const GstStructure *s;
14007 GstAudioFormat format = 0;
14010 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14012 depth = entry->bytes_per_packet * 8;
14015 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14017 /* 8-bit audio is unsigned */
14019 format = GST_AUDIO_FORMAT_U8;
14020 /* otherwise it's signed and big-endian just like 'twos' */
14022 endian = G_BIG_ENDIAN;
14029 endian = G_LITTLE_ENDIAN;
14032 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14034 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14038 caps = gst_caps_new_simple ("audio/x-raw",
14039 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14040 "layout", G_TYPE_STRING, "interleaved", NULL);
14041 stream->alignment = GST_ROUND_UP_8 (depth);
14042 stream->alignment = round_up_pow2 (stream->alignment);
14045 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14046 _codec ("Raw 64-bit floating-point audio");
14047 caps = gst_caps_new_simple ("audio/x-raw",
14048 "format", G_TYPE_STRING, "F64BE",
14049 "layout", G_TYPE_STRING, "interleaved", NULL);
14050 stream->alignment = 8;
14052 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14053 _codec ("Raw 32-bit floating-point audio");
14054 caps = gst_caps_new_simple ("audio/x-raw",
14055 "format", G_TYPE_STRING, "F32BE",
14056 "layout", G_TYPE_STRING, "interleaved", NULL);
14057 stream->alignment = 4;
14060 _codec ("Raw 24-bit PCM audio");
14061 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14063 caps = gst_caps_new_simple ("audio/x-raw",
14064 "format", G_TYPE_STRING, "S24BE",
14065 "layout", G_TYPE_STRING, "interleaved", NULL);
14066 stream->alignment = 4;
14068 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14069 _codec ("Raw 32-bit PCM audio");
14070 caps = gst_caps_new_simple ("audio/x-raw",
14071 "format", G_TYPE_STRING, "S32BE",
14072 "layout", G_TYPE_STRING, "interleaved", NULL);
14073 stream->alignment = 4;
14075 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14076 _codec ("Raw 16-bit PCM audio");
14077 caps = gst_caps_new_simple ("audio/x-raw",
14078 "format", G_TYPE_STRING, "S16LE",
14079 "layout", G_TYPE_STRING, "interleaved", NULL);
14080 stream->alignment = 2;
14083 _codec ("Mu-law audio");
14084 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14087 _codec ("A-law audio");
14088 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14092 _codec ("Microsoft ADPCM");
14093 /* Microsoft ADPCM-ACM code 2 */
14094 caps = gst_caps_new_simple ("audio/x-adpcm",
14095 "layout", G_TYPE_STRING, "microsoft", NULL);
14099 _codec ("DVI/IMA ADPCM");
14100 caps = gst_caps_new_simple ("audio/x-adpcm",
14101 "layout", G_TYPE_STRING, "dvi", NULL);
14105 _codec ("DVI/Intel IMA ADPCM");
14106 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14107 caps = gst_caps_new_simple ("audio/x-adpcm",
14108 "layout", G_TYPE_STRING, "quicktime", NULL);
14112 /* MPEG layer 3, CBR only (pre QT4.1) */
14114 _codec ("MPEG-1 layer 3");
14115 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14116 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14117 "mpegversion", G_TYPE_INT, 1, NULL);
14119 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14120 _codec ("MPEG-1 layer 2");
14122 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14123 "mpegversion", G_TYPE_INT, 1, NULL);
14126 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14127 _codec ("EAC-3 audio");
14128 caps = gst_caps_new_simple ("audio/x-eac3",
14129 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14130 entry->sampled = TRUE;
14132 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14134 _codec ("AC-3 audio");
14135 caps = gst_caps_new_simple ("audio/x-ac3",
14136 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14137 entry->sampled = TRUE;
14139 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14140 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14141 _codec ("DTS audio");
14142 caps = gst_caps_new_simple ("audio/x-dts",
14143 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14144 entry->sampled = TRUE;
14146 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14147 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14148 _codec ("DTS-HD audio");
14149 caps = gst_caps_new_simple ("audio/x-dts",
14150 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14151 entry->sampled = TRUE;
14155 caps = gst_caps_new_simple ("audio/x-mace",
14156 "maceversion", G_TYPE_INT, 3, NULL);
14160 caps = gst_caps_new_simple ("audio/x-mace",
14161 "maceversion", G_TYPE_INT, 6, NULL);
14163 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14165 caps = gst_caps_new_empty_simple ("application/ogg");
14167 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14168 _codec ("DV audio");
14169 caps = gst_caps_new_empty_simple ("audio/x-dv");
14172 _codec ("MPEG-4 AAC audio");
14173 caps = gst_caps_new_simple ("audio/mpeg",
14174 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14175 "stream-format", G_TYPE_STRING, "raw", NULL);
14177 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14178 _codec ("QDesign Music");
14179 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14182 _codec ("QDesign Music v.2");
14183 /* FIXME: QDesign music version 2 (no constant) */
14184 if (FALSE && data) {
14185 caps = gst_caps_new_simple ("audio/x-qdm2",
14186 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14187 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14188 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14190 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14194 _codec ("GSM audio");
14195 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14198 _codec ("AMR audio");
14199 caps = gst_caps_new_empty_simple ("audio/AMR");
14202 _codec ("AMR-WB audio");
14203 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14206 _codec ("Quicktime IMA ADPCM");
14207 caps = gst_caps_new_simple ("audio/x-adpcm",
14208 "layout", G_TYPE_STRING, "quicktime", NULL);
14211 _codec ("Apple lossless audio");
14212 caps = gst_caps_new_empty_simple ("audio/x-alac");
14215 _codec ("Free Lossless Audio Codec");
14216 caps = gst_caps_new_simple ("audio/x-flac",
14217 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14219 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14220 _codec ("QualComm PureVoice");
14221 caps = gst_caps_from_string ("audio/qcelp");
14226 caps = gst_caps_new_empty_simple ("audio/x-wma");
14230 caps = gst_caps_new_empty_simple ("audio/x-opus");
14232 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
14237 GstAudioFormat format;
14240 FLAG_IS_FLOAT = 0x1,
14241 FLAG_IS_BIG_ENDIAN = 0x2,
14242 FLAG_IS_SIGNED = 0x4,
14243 FLAG_IS_PACKED = 0x8,
14244 FLAG_IS_ALIGNED_HIGH = 0x10,
14245 FLAG_IS_NON_INTERLEAVED = 0x20
14247 _codec ("Raw LPCM audio");
14249 if (data && len >= 56) {
14250 depth = QT_UINT32 (data + 40);
14251 flags = QT_UINT32 (data + 44);
14252 width = QT_UINT32 (data + 48) * 8 / entry->n_channels;
14254 if ((flags & FLAG_IS_FLOAT) == 0) {
14259 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14260 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14261 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14262 caps = gst_caps_new_simple ("audio/x-raw",
14263 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14264 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14265 "non-interleaved" : "interleaved", NULL);
14266 stream->alignment = GST_ROUND_UP_8 (depth);
14267 stream->alignment = round_up_pow2 (stream->alignment);
14272 if (flags & FLAG_IS_BIG_ENDIAN)
14273 format = GST_AUDIO_FORMAT_F64BE;
14275 format = GST_AUDIO_FORMAT_F64LE;
14277 if (flags & FLAG_IS_BIG_ENDIAN)
14278 format = GST_AUDIO_FORMAT_F32BE;
14280 format = GST_AUDIO_FORMAT_F32LE;
14282 caps = gst_caps_new_simple ("audio/x-raw",
14283 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14284 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14285 "non-interleaved" : "interleaved", NULL);
14286 stream->alignment = width / 8;
14290 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14294 caps = _get_unknown_codec_name ("audio", fourcc);
14300 GstCaps *templ_caps =
14301 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14302 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14303 gst_caps_unref (caps);
14304 gst_caps_unref (templ_caps);
14305 caps = intersection;
14308 /* enable clipping for raw audio streams */
14309 s = gst_caps_get_structure (caps, 0);
14310 name = gst_structure_get_name (s);
14311 if (g_str_has_prefix (name, "audio/x-raw")) {
14312 stream->need_clip = TRUE;
14313 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14314 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14320 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14321 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14322 const guint8 * stsd_entry_data, gchar ** codec_name)
14326 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14330 _codec ("DVD subtitle");
14331 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14332 stream->need_process = TRUE;
14335 _codec ("Quicktime timed text");
14338 _codec ("3GPP timed text");
14340 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14342 /* actual text piece needs to be extracted */
14343 stream->need_process = TRUE;
14346 _codec ("XML subtitles");
14347 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14351 caps = _get_unknown_codec_name ("text", fourcc);
14359 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14360 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14361 const guint8 * stsd_entry_data, gchar ** codec_name)
14367 _codec ("MPEG 1 video");
14368 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14369 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14379 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14380 const gchar * system_id)
14384 if (!qtdemux->protection_system_ids)
14385 qtdemux->protection_system_ids =
14386 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14387 /* Check whether we already have an entry for this system ID. */
14388 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14389 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14390 if (g_ascii_strcasecmp (system_id, id) == 0) {
14394 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14395 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,