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);
915 case GST_QUERY_FORMATS:
916 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
919 case GST_QUERY_SEEKING:{
923 /* try upstream first */
924 res = gst_pad_query_default (pad, parent, query);
927 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
928 if (fmt == GST_FORMAT_TIME) {
929 GstClockTime duration;
931 gst_qtdemux_get_duration (qtdemux, &duration);
933 if (!qtdemux->pullbased) {
936 /* we might be able with help from upstream */
938 q = gst_query_new_seeking (GST_FORMAT_BYTES);
939 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
940 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
941 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
945 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
951 case GST_QUERY_SEGMENT:
956 format = qtdemux->segment.format;
959 gst_segment_to_stream_time (&qtdemux->segment, format,
960 qtdemux->segment.start);
961 if ((stop = qtdemux->segment.stop) == -1)
962 stop = qtdemux->segment.duration;
964 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
966 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
971 res = gst_pad_query_default (pad, parent, query);
979 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
981 if (G_LIKELY (stream->pad)) {
982 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
983 GST_DEBUG_PAD_NAME (stream->pad));
985 if (!gst_tag_list_is_empty (stream->stream_tags)) {
986 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
987 stream->stream_tags);
988 gst_pad_push_event (stream->pad,
989 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
992 if (G_UNLIKELY (stream->send_global_tags)) {
993 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
995 gst_pad_push_event (stream->pad,
996 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
997 stream->send_global_tags = FALSE;
1002 /* push event on all source pads; takes ownership of the event */
1004 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1007 gboolean has_valid_stream = FALSE;
1008 GstEventType etype = GST_EVENT_TYPE (event);
1010 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1011 GST_EVENT_TYPE_NAME (event));
1013 for (n = 0; n < qtdemux->n_streams; n++) {
1015 QtDemuxStream *stream = qtdemux->streams[n];
1016 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
1018 if ((pad = stream->pad)) {
1019 has_valid_stream = TRUE;
1021 if (etype == GST_EVENT_EOS) {
1022 /* let's not send twice */
1023 if (stream->sent_eos)
1025 stream->sent_eos = TRUE;
1028 gst_pad_push_event (pad, gst_event_ref (event));
1032 gst_event_unref (event);
1034 /* if it is EOS and there are no pads, post an error */
1035 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1036 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1040 /* push a pending newsegment event, if any from the streaming thread */
1042 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1044 if (qtdemux->pending_newsegment) {
1045 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1046 qtdemux->pending_newsegment = NULL;
1056 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1058 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1060 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1066 /* find the index of the sample that includes the data for @media_time using a
1067 * binary search. Only to be called in optimized cases of linear search below.
1069 * Returns the index of the sample.
1072 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1075 QtDemuxSample *result;
1078 /* convert media_time to mov format */
1080 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1082 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1083 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1084 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1086 if (G_LIKELY (result))
1087 index = result - str->samples;
1096 /* find the index of the sample that includes the data for @media_offset using a
1099 * Returns the index of the sample.
1102 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1103 QtDemuxStream * str, gint64 media_offset)
1105 QtDemuxSample *result = str->samples;
1108 if (result == NULL || str->n_samples == 0)
1111 if (media_offset == result->offset)
1115 while (index < str->n_samples - 1) {
1116 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1119 if (media_offset < result->offset)
1130 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1135 /* find the index of the sample that includes the data for @media_time using a
1136 * linear search, and keeping in mind that not all samples may have been parsed
1137 * yet. If possible, it will delegate to binary search.
1139 * Returns the index of the sample.
1142 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1143 GstClockTime media_time)
1147 QtDemuxSample *sample;
1149 /* convert media_time to mov format */
1151 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1153 sample = str->samples;
1154 if (mov_time == sample->timestamp + sample->pts_offset)
1157 /* use faster search if requested time in already parsed range */
1158 sample = str->samples + str->stbl_index;
1159 if (str->stbl_index >= 0 &&
1160 mov_time <= (sample->timestamp + sample->pts_offset))
1161 return gst_qtdemux_find_index (qtdemux, str, media_time);
1163 while (index < str->n_samples - 1) {
1164 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1167 sample = str->samples + index + 1;
1168 if (mov_time < (sample->timestamp + sample->pts_offset))
1178 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1183 /* find the index of the keyframe needed to decode the sample at @index
1184 * of stream @str, or of a subsequent keyframe (depending on @next)
1186 * Returns the index of the keyframe.
1189 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1190 guint32 index, gboolean next)
1192 guint32 new_index = index;
1194 if (index >= str->n_samples) {
1195 new_index = str->n_samples;
1199 /* all keyframes, return index */
1200 if (str->all_keyframe) {
1205 /* else search until we have a keyframe */
1206 while (new_index < str->n_samples) {
1207 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1210 if (str->samples[new_index].keyframe)
1222 if (new_index == str->n_samples) {
1223 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1228 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1229 "gave %u", next ? "after" : "before", index, new_index);
1236 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1241 /* find the segment for @time_position for @stream
1243 * Returns the index of the segment containing @time_position.
1244 * Returns the last segment and sets the @eos variable to TRUE
1245 * if the time is beyond the end. @eos may be NULL
1248 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1249 GstClockTime time_position)
1254 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1255 GST_TIME_ARGS (time_position));
1258 for (i = 0; i < stream->n_segments; i++) {
1259 QtDemuxSegment *segment = &stream->segments[i];
1261 GST_LOG_OBJECT (stream->pad,
1262 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1263 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1265 /* For the last segment we include stop_time in the last segment */
1266 if (i < stream->n_segments - 1) {
1267 if (segment->time <= time_position && time_position < segment->stop_time) {
1268 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1273 /* Last segment always matches */
1281 /* move the stream @str to the sample position @index.
1283 * Updates @str->sample_index and marks discontinuity if needed.
1286 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1289 /* no change needed */
1290 if (index == str->sample_index)
1293 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1296 /* position changed, we have a discont */
1297 str->sample_index = index;
1298 str->offset_in_sample = 0;
1299 /* Each time we move in the stream we store the position where we are
1301 str->from_sample = index;
1302 str->discont = TRUE;
1306 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1307 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1310 gint64 min_byte_offset = -1;
1313 min_offset = desired_time;
1315 /* for each stream, find the index of the sample in the segment
1316 * and move back to the previous keyframe. */
1317 for (n = 0; n < qtdemux->n_streams; n++) {
1319 guint32 index, kindex;
1321 GstClockTime media_start;
1322 GstClockTime media_time;
1323 GstClockTime seg_time;
1324 QtDemuxSegment *seg;
1325 gboolean empty_segment = FALSE;
1327 str = qtdemux->streams[n];
1329 if (CUR_STREAM (str)->sparse && !use_sparse)
1332 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1333 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1335 /* get segment and time in the segment */
1336 seg = &str->segments[seg_idx];
1337 seg_time = (desired_time - seg->time) * seg->rate;
1339 while (QTSEGMENT_IS_EMPTY (seg)) {
1341 empty_segment = TRUE;
1342 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1345 if (seg_idx == str->n_segments)
1347 seg = &str->segments[seg_idx];
1350 if (seg_idx == str->n_segments) {
1351 /* FIXME track shouldn't have the last segment as empty, but if it
1352 * happens we better handle it */
1356 /* get the media time in the segment */
1357 media_start = seg->media_start + seg_time;
1359 /* get the index of the sample with media time */
1360 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1361 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1362 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1363 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1366 /* shift to next frame if we are looking for next keyframe */
1367 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1368 && index < str->stbl_index)
1371 if (!empty_segment) {
1372 /* find previous keyframe */
1373 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1375 /* we will settle for one before if none found after */
1376 if (next && kindex == -1)
1377 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1379 /* if the keyframe is at a different position, we need to update the
1380 * requested seek time */
1381 if (index != kindex) {
1384 /* get timestamp of keyframe */
1385 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1386 GST_DEBUG_OBJECT (qtdemux,
1387 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1388 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1389 str->samples[kindex].offset);
1391 /* keyframes in the segment get a chance to change the
1392 * desired_offset. keyframes out of the segment are
1394 if (media_time >= seg->media_start) {
1395 GstClockTime seg_time;
1397 /* this keyframe is inside the segment, convert back to
1399 seg_time = (media_time - seg->media_start) + seg->time;
1400 if ((!next && (seg_time < min_offset)) ||
1401 (next && (seg_time > min_offset)))
1402 min_offset = seg_time;
1407 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1408 min_byte_offset = str->samples[index].offset;
1412 *key_time = min_offset;
1414 *key_offset = min_byte_offset;
1418 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1419 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1423 g_return_val_if_fail (format != NULL, FALSE);
1424 g_return_val_if_fail (cur != NULL, FALSE);
1425 g_return_val_if_fail (stop != NULL, FALSE);
1427 if (*format == GST_FORMAT_TIME)
1431 if (cur_type != GST_SEEK_TYPE_NONE)
1432 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1433 if (res && stop_type != GST_SEEK_TYPE_NONE)
1434 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1437 *format = GST_FORMAT_TIME;
1442 /* perform seek in push based mode:
1443 find BYTE position to move to based on time and delegate to upstream
1446 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1451 GstSeekType cur_type, stop_type;
1452 gint64 cur, stop, key_cur;
1455 gint64 original_stop;
1458 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1460 gst_event_parse_seek (event, &rate, &format, &flags,
1461 &cur_type, &cur, &stop_type, &stop);
1462 seqnum = gst_event_get_seqnum (event);
1464 /* only forward streaming and seeking is possible */
1466 goto unsupported_seek;
1468 /* convert to TIME if needed and possible */
1469 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1473 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1474 * the original stop position to use when upstream pushes the new segment
1476 original_stop = stop;
1479 /* find reasonable corresponding BYTE position,
1480 * also try to mind about keyframes, since we can not go back a bit for them
1482 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1483 * mostly just work, but let's not yet boldly go there ... */
1484 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1489 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1490 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1493 GST_OBJECT_LOCK (qtdemux);
1494 qtdemux->seek_offset = byte_cur;
1495 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1496 qtdemux->push_seek_start = cur;
1498 qtdemux->push_seek_start = key_cur;
1501 if (stop_type == GST_SEEK_TYPE_NONE) {
1502 qtdemux->push_seek_stop = qtdemux->segment.stop;
1504 qtdemux->push_seek_stop = original_stop;
1506 GST_OBJECT_UNLOCK (qtdemux);
1508 /* BYTE seek event */
1509 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1511 gst_event_set_seqnum (event, seqnum);
1512 res = gst_pad_push_event (qtdemux->sinkpad, event);
1519 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1525 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1530 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1535 /* perform the seek.
1537 * We set all segment_indexes in the streams to unknown and
1538 * adjust the time_position to the desired position. this is enough
1539 * to trigger a segment switch in the streaming thread to start
1540 * streaming from the desired position.
1542 * Keyframe seeking is a little more complicated when dealing with
1543 * segments. Ideally we want to move to the previous keyframe in
1544 * the segment but there might not be a keyframe in the segment. In
1545 * fact, none of the segments could contain a keyframe. We take a
1546 * practical approach: seek to the previous keyframe in the segment,
1547 * if there is none, seek to the beginning of the segment.
1549 * Called with STREAM_LOCK
1552 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1553 guint32 seqnum, GstSeekFlags flags)
1555 gint64 desired_offset;
1558 desired_offset = segment->position;
1560 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1561 GST_TIME_ARGS (desired_offset));
1563 /* may not have enough fragmented info to do this adjustment,
1564 * and we can't scan (and probably should not) at this time with
1565 * possibly flushing upstream */
1566 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1568 gboolean next, before, after;
1570 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1571 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1572 next = after && !before;
1573 if (segment->rate < 0)
1576 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1578 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1579 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1580 desired_offset = min_offset;
1583 /* and set all streams to the final position */
1584 gst_flow_combiner_reset (qtdemux->flowcombiner);
1585 qtdemux->segment_seqnum = seqnum;
1586 for (n = 0; n < qtdemux->n_streams; n++) {
1587 QtDemuxStream *stream = qtdemux->streams[n];
1589 stream->time_position = desired_offset;
1590 stream->accumulated_base = 0;
1591 stream->sample_index = -1;
1592 stream->offset_in_sample = 0;
1593 stream->segment_index = -1;
1594 stream->sent_eos = FALSE;
1596 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1597 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1599 segment->position = desired_offset;
1600 segment->time = desired_offset;
1601 if (segment->rate >= 0) {
1602 segment->start = desired_offset;
1604 /* we stop at the end */
1605 if (segment->stop == -1)
1606 segment->stop = segment->duration;
1608 segment->stop = desired_offset;
1611 if (qtdemux->fragmented)
1612 qtdemux->fragmented_seek_pending = TRUE;
1617 /* do a seek in pull based mode */
1619 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1624 GstSeekType cur_type, stop_type;
1628 GstSegment seeksegment;
1630 GstEvent *flush_event;
1634 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1636 gst_event_parse_seek (event, &rate, &format, &flags,
1637 &cur_type, &cur, &stop_type, &stop);
1638 seqnum = gst_event_get_seqnum (event);
1640 /* we have to have a format as the segment format. Try to convert
1642 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1646 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1648 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1652 flush = flags & GST_SEEK_FLAG_FLUSH;
1654 /* stop streaming, either by flushing or by pausing the task */
1656 flush_event = gst_event_new_flush_start ();
1658 gst_event_set_seqnum (flush_event, seqnum);
1659 /* unlock upstream pull_range */
1660 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1661 /* make sure out loop function exits */
1662 gst_qtdemux_push_event (qtdemux, flush_event);
1664 /* non flushing seek, pause the task */
1665 gst_pad_pause_task (qtdemux->sinkpad);
1668 /* wait for streaming to finish */
1669 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1671 /* copy segment, we need this because we still need the old
1672 * segment when we close the current segment. */
1673 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1676 /* configure the segment with the seek variables */
1677 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1678 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1679 cur_type, cur, stop_type, stop, &update)) {
1681 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1683 /* now do the seek */
1684 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1687 /* now do the seek */
1688 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1691 /* prepare for streaming again */
1693 flush_event = gst_event_new_flush_stop (TRUE);
1695 gst_event_set_seqnum (flush_event, seqnum);
1697 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1698 gst_qtdemux_push_event (qtdemux, flush_event);
1701 /* commit the new segment */
1702 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1704 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1705 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1706 qtdemux->segment.format, qtdemux->segment.position);
1708 gst_message_set_seqnum (msg, seqnum);
1709 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1712 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1713 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1714 qtdemux->sinkpad, NULL);
1716 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1723 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1729 qtdemux_ensure_index (GstQTDemux * qtdemux)
1733 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1735 /* Build complete index */
1736 for (i = 0; i < qtdemux->n_streams; i++) {
1737 QtDemuxStream *stream = qtdemux->streams[i];
1739 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1747 GST_LOG_OBJECT (qtdemux,
1748 "Building complete index of stream %u for seeking failed!", i);
1754 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1757 gboolean res = TRUE;
1758 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1760 switch (GST_EVENT_TYPE (event)) {
1761 case GST_EVENT_SEEK:
1763 #ifndef GST_DISABLE_GST_DEBUG
1764 GstClockTime ts = gst_util_get_timestamp ();
1766 guint32 seqnum = gst_event_get_seqnum (event);
1768 if (seqnum == qtdemux->segment_seqnum) {
1769 GST_LOG_OBJECT (pad,
1770 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1771 gst_event_unref (event);
1775 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1776 /* seek should be handled by upstream, we might need to re-download fragments */
1777 GST_DEBUG_OBJECT (qtdemux,
1778 "let upstream handle seek for fragmented playback");
1782 /* Build complete index for seeking;
1783 * if not a fragmented file at least */
1784 if (!qtdemux->fragmented)
1785 if (!qtdemux_ensure_index (qtdemux))
1787 #ifndef GST_DISABLE_GST_DEBUG
1788 ts = gst_util_get_timestamp () - ts;
1789 GST_INFO_OBJECT (qtdemux,
1790 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1793 if (qtdemux->pullbased) {
1794 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1795 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1796 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1798 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1799 && !qtdemux->fragmented) {
1800 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1802 GST_DEBUG_OBJECT (qtdemux,
1803 "ignoring seek in push mode in current state");
1806 gst_event_unref (event);
1810 res = gst_pad_event_default (pad, parent, event);
1820 GST_ERROR_OBJECT (qtdemux, "Index failed");
1821 gst_event_unref (event);
1827 /* stream/index return sample that is min/max w.r.t. byte position,
1828 * time is min/max w.r.t. time of samples,
1829 * the latter need not be time of the former sample */
1831 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1832 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1835 gint64 time, min_time;
1836 QtDemuxStream *stream;
1842 for (n = 0; n < qtdemux->n_streams; ++n) {
1845 gboolean set_sample;
1847 str = qtdemux->streams[n];
1854 i = str->n_samples - 1;
1858 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1859 if (str->samples[i].size == 0)
1862 if (fw && (str->samples[i].offset < byte_pos))
1865 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1868 /* move stream to first available sample */
1870 gst_qtdemux_move_stream (qtdemux, str, i);
1874 /* avoid index from sparse streams since they might be far away */
1875 if (!CUR_STREAM (str)->sparse) {
1876 /* determine min/max time */
1877 time = QTSAMPLE_PTS (str, &str->samples[i]);
1878 if (min_time == -1 || (!fw && time > min_time) ||
1879 (fw && time < min_time)) {
1883 /* determine stream with leading sample, to get its position */
1885 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1886 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1894 /* no sample for this stream, mark eos */
1896 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1907 static QtDemuxStream *
1908 _create_stream (void)
1910 QtDemuxStream *stream;
1912 stream = g_new0 (QtDemuxStream, 1);
1913 /* new streams always need a discont */
1914 stream->discont = TRUE;
1915 /* we enable clipping for raw audio/video streams */
1916 stream->need_clip = FALSE;
1917 stream->need_process = FALSE;
1918 stream->segment_index = -1;
1919 stream->time_position = 0;
1920 stream->sample_index = -1;
1921 stream->offset_in_sample = 0;
1922 stream->new_stream = TRUE;
1923 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1924 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1925 stream->protected = FALSE;
1926 stream->protection_scheme_type = 0;
1927 stream->protection_scheme_version = 0;
1928 stream->protection_scheme_info = NULL;
1929 stream->n_samples_moof = 0;
1930 stream->duration_moof = 0;
1931 stream->duration_last_moof = 0;
1932 stream->alignment = 1;
1933 stream->stream_tags = gst_tag_list_new_empty ();
1934 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1935 g_queue_init (&stream->protection_scheme_event_queue);
1940 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1942 GstStructure *structure;
1943 const gchar *variant;
1944 const GstCaps *mediacaps = NULL;
1946 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1948 structure = gst_caps_get_structure (caps, 0);
1949 variant = gst_structure_get_string (structure, "variant");
1951 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1952 QtDemuxStream *stream;
1953 const GValue *value;
1955 demux->fragmented = TRUE;
1956 demux->mss_mode = TRUE;
1958 if (demux->n_streams > 1) {
1959 /* can't do this, we can only renegotiate for another mss format */
1963 value = gst_structure_get_value (structure, "media-caps");
1966 const GValue *timescale_v;
1968 /* TODO update when stream changes during playback */
1970 if (demux->n_streams == 0) {
1971 stream = _create_stream ();
1972 demux->streams[demux->n_streams] = stream;
1973 demux->n_streams = 1;
1975 stream = demux->streams[0];
1978 timescale_v = gst_structure_get_value (structure, "timescale");
1980 stream->timescale = g_value_get_uint64 (timescale_v);
1982 /* default mss timescale */
1983 stream->timescale = 10000000;
1985 demux->timescale = stream->timescale;
1987 mediacaps = gst_value_get_caps (value);
1988 if (!CUR_STREAM (stream)->caps
1989 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1990 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1992 stream->new_caps = TRUE;
1994 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1995 structure = gst_caps_get_structure (mediacaps, 0);
1996 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1997 stream->subtype = FOURCC_vide;
1999 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2000 gst_structure_get_int (structure, "height",
2001 &CUR_STREAM (stream)->height);
2002 gst_structure_get_fraction (structure, "framerate",
2003 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2004 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2006 stream->subtype = FOURCC_soun;
2007 gst_structure_get_int (structure, "channels",
2008 &CUR_STREAM (stream)->n_channels);
2009 gst_structure_get_int (structure, "rate", &rate);
2010 CUR_STREAM (stream)->rate = rate;
2013 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2015 demux->mss_mode = FALSE;
2022 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2026 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2027 gst_pad_stop_task (qtdemux->sinkpad);
2029 if (hard || qtdemux->upstream_format_is_time) {
2030 qtdemux->state = QTDEMUX_STATE_INITIAL;
2031 qtdemux->neededbytes = 16;
2032 qtdemux->todrop = 0;
2033 qtdemux->pullbased = FALSE;
2034 qtdemux->posted_redirect = FALSE;
2035 qtdemux->first_mdat = -1;
2036 qtdemux->header_size = 0;
2037 qtdemux->mdatoffset = -1;
2038 qtdemux->restoredata_offset = -1;
2039 if (qtdemux->mdatbuffer)
2040 gst_buffer_unref (qtdemux->mdatbuffer);
2041 if (qtdemux->restoredata_buffer)
2042 gst_buffer_unref (qtdemux->restoredata_buffer);
2043 qtdemux->mdatbuffer = NULL;
2044 qtdemux->restoredata_buffer = NULL;
2045 qtdemux->mdatleft = 0;
2046 qtdemux->mdatsize = 0;
2047 if (qtdemux->comp_brands)
2048 gst_buffer_unref (qtdemux->comp_brands);
2049 qtdemux->comp_brands = NULL;
2050 qtdemux->last_moov_offset = -1;
2051 if (qtdemux->moov_node_compressed) {
2052 g_node_destroy (qtdemux->moov_node_compressed);
2053 if (qtdemux->moov_node)
2054 g_free (qtdemux->moov_node->data);
2056 qtdemux->moov_node_compressed = NULL;
2057 if (qtdemux->moov_node)
2058 g_node_destroy (qtdemux->moov_node);
2059 qtdemux->moov_node = NULL;
2060 if (qtdemux->tag_list)
2061 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2062 qtdemux->tag_list = gst_tag_list_new_empty ();
2063 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2065 if (qtdemux->element_index)
2066 gst_object_unref (qtdemux->element_index);
2067 qtdemux->element_index = NULL;
2069 qtdemux->major_brand = 0;
2070 if (qtdemux->pending_newsegment)
2071 gst_event_unref (qtdemux->pending_newsegment);
2072 qtdemux->pending_newsegment = NULL;
2073 qtdemux->upstream_format_is_time = FALSE;
2074 qtdemux->upstream_seekable = FALSE;
2075 qtdemux->upstream_size = 0;
2077 qtdemux->fragment_start = -1;
2078 qtdemux->fragment_start_offset = -1;
2079 qtdemux->duration = 0;
2080 qtdemux->moof_offset = 0;
2081 qtdemux->chapters_track_id = 0;
2082 qtdemux->have_group_id = FALSE;
2083 qtdemux->group_id = G_MAXUINT;
2085 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2087 g_queue_clear (&qtdemux->protection_event_queue);
2089 qtdemux->offset = 0;
2090 gst_adapter_clear (qtdemux->adapter);
2091 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2092 qtdemux->segment_seqnum = 0;
2095 for (n = 0; n < qtdemux->n_streams; n++) {
2096 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2097 qtdemux->streams[n] = NULL;
2099 qtdemux->n_streams = 0;
2100 qtdemux->n_video_streams = 0;
2101 qtdemux->n_audio_streams = 0;
2102 qtdemux->n_sub_streams = 0;
2103 qtdemux->exposed = FALSE;
2104 qtdemux->fragmented = FALSE;
2105 qtdemux->mss_mode = FALSE;
2106 gst_caps_replace (&qtdemux->media_caps, NULL);
2107 qtdemux->timescale = 0;
2108 qtdemux->got_moov = FALSE;
2109 if (qtdemux->protection_system_ids) {
2110 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2111 qtdemux->protection_system_ids = NULL;
2113 } else if (qtdemux->mss_mode) {
2114 gst_flow_combiner_reset (qtdemux->flowcombiner);
2115 for (n = 0; n < qtdemux->n_streams; n++)
2116 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2118 gst_flow_combiner_reset (qtdemux->flowcombiner);
2119 for (n = 0; n < qtdemux->n_streams; n++) {
2120 qtdemux->streams[n]->sent_eos = FALSE;
2121 qtdemux->streams[n]->time_position = 0;
2122 qtdemux->streams[n]->accumulated_base = 0;
2124 if (!qtdemux->pending_newsegment) {
2125 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2126 if (qtdemux->segment_seqnum)
2127 gst_event_set_seqnum (qtdemux->pending_newsegment,
2128 qtdemux->segment_seqnum);
2134 /* Maps the @segment to the qt edts internal segments and pushes
2135 * the correspnding segment event.
2137 * If it ends up being at a empty segment, a gap will be pushed and the next
2138 * edts segment will be activated in sequence.
2140 * To be used in push-mode only */
2142 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2146 for (n = 0; n < qtdemux->n_streams; n++) {
2147 QtDemuxStream *stream = qtdemux->streams[n];
2149 stream->time_position = segment->start;
2151 /* in push mode we should be guaranteed that we will have empty segments
2152 * at the beginning and then one segment after, other scenarios are not
2153 * supported and are discarded when parsing the edts */
2154 for (i = 0; i < stream->n_segments; i++) {
2155 if (stream->segments[i].stop_time > segment->start) {
2156 gst_qtdemux_activate_segment (qtdemux, stream, i,
2157 stream->time_position);
2158 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2159 /* push the empty segment and move to the next one */
2160 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2161 stream->time_position);
2165 g_assert (i == stream->n_segments - 1);
2172 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2175 GstQTDemux *demux = GST_QTDEMUX (parent);
2176 gboolean res = TRUE;
2178 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2180 switch (GST_EVENT_TYPE (event)) {
2181 case GST_EVENT_SEGMENT:
2184 QtDemuxStream *stream;
2188 /* some debug output */
2189 gst_event_copy_segment (event, &segment);
2190 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2193 /* erase any previously set segment */
2194 gst_event_replace (&demux->pending_newsegment, NULL);
2196 if (segment.format == GST_FORMAT_TIME) {
2197 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2198 gst_event_replace (&demux->pending_newsegment, event);
2199 demux->upstream_format_is_time = TRUE;
2201 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2202 "not in time format");
2204 /* chain will send initial newsegment after pads have been added */
2205 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2206 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2211 /* check if this matches a time seek we received previously
2212 * FIXME for backwards compatibility reasons we use the
2213 * seek_offset here to compare. In the future we might want to
2214 * change this to use the seqnum as it uniquely should identify
2215 * the segment that corresponds to the seek. */
2216 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2217 ", received segment offset %" G_GINT64_FORMAT,
2218 demux->seek_offset, segment.start);
2219 if (segment.format == GST_FORMAT_BYTES
2220 && demux->seek_offset == segment.start) {
2221 GST_OBJECT_LOCK (demux);
2222 offset = segment.start;
2224 segment.format = GST_FORMAT_TIME;
2225 segment.start = demux->push_seek_start;
2226 segment.stop = demux->push_seek_stop;
2227 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2228 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2229 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2230 GST_OBJECT_UNLOCK (demux);
2233 /* we only expect a BYTE segment, e.g. following a seek */
2234 if (segment.format == GST_FORMAT_BYTES) {
2235 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2236 offset = segment.start;
2238 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2239 NULL, (gint64 *) & segment.start);
2240 if ((gint64) segment.start < 0)
2243 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2244 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2245 NULL, (gint64 *) & segment.stop);
2246 /* keyframe seeking should already arrange for start >= stop,
2247 * but make sure in other rare cases */
2248 segment.stop = MAX (segment.stop, segment.start);
2250 } else if (segment.format == GST_FORMAT_TIME) {
2251 /* push all data on the adapter before starting this
2253 gst_qtdemux_process_adapter (demux, TRUE);
2255 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2259 /* We shouldn't modify upstream driven TIME FORMAT segment */
2260 if (!demux->upstream_format_is_time) {
2261 /* accept upstream's notion of segment and distribute along */
2262 segment.format = GST_FORMAT_TIME;
2263 segment.position = segment.time = segment.start;
2264 segment.duration = demux->segment.duration;
2265 segment.base = gst_segment_to_running_time (&demux->segment,
2266 GST_FORMAT_TIME, demux->segment.position);
2269 gst_segment_copy_into (&segment, &demux->segment);
2270 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2272 /* map segment to internal qt segments and push on each stream */
2273 if (demux->n_streams) {
2274 if (demux->fragmented) {
2275 GstEvent *segment_event = gst_event_new_segment (&segment);
2277 gst_event_replace (&demux->pending_newsegment, NULL);
2278 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2279 gst_qtdemux_push_event (demux, segment_event);
2281 gst_event_replace (&demux->pending_newsegment, NULL);
2282 gst_qtdemux_map_and_push_segments (demux, &segment);
2286 /* clear leftover in current segment, if any */
2287 gst_adapter_clear (demux->adapter);
2289 /* set up streaming thread */
2290 demux->offset = offset;
2291 if (demux->upstream_format_is_time) {
2292 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2293 "set values to restart reading from a new atom");
2294 demux->neededbytes = 16;
2297 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2300 demux->todrop = stream->samples[idx].offset - offset;
2301 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2303 /* set up for EOS */
2304 demux->neededbytes = -1;
2309 gst_event_unref (event);
2313 case GST_EVENT_FLUSH_START:
2315 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2316 gst_event_unref (event);
2321 case GST_EVENT_FLUSH_STOP:
2325 dur = demux->segment.duration;
2326 gst_qtdemux_reset (demux, FALSE);
2327 demux->segment.duration = dur;
2329 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2330 gst_event_unref (event);
2336 /* If we are in push mode, and get an EOS before we've seen any streams,
2337 * then error out - we have nowhere to send the EOS */
2338 if (!demux->pullbased) {
2340 gboolean has_valid_stream = FALSE;
2341 for (i = 0; i < demux->n_streams; i++) {
2342 if (demux->streams[i]->pad != NULL) {
2343 has_valid_stream = TRUE;
2347 if (!has_valid_stream)
2348 gst_qtdemux_post_no_playable_stream_error (demux);
2350 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2351 (guint) gst_adapter_available (demux->adapter));
2352 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2358 case GST_EVENT_CAPS:{
2359 GstCaps *caps = NULL;
2361 gst_event_parse_caps (event, &caps);
2362 gst_qtdemux_setcaps (demux, caps);
2364 gst_event_unref (event);
2367 case GST_EVENT_PROTECTION:
2369 const gchar *system_id = NULL;
2371 gst_event_parse_protection (event, &system_id, NULL, NULL);
2372 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2374 gst_qtdemux_append_protection_system_id (demux, system_id);
2375 /* save the event for later, for source pads that have not been created */
2376 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2377 /* send it to all pads that already exist */
2378 gst_qtdemux_push_event (demux, event);
2386 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2394 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2396 GstQTDemux *demux = GST_QTDEMUX (element);
2398 GST_OBJECT_LOCK (demux);
2399 if (demux->element_index)
2400 gst_object_unref (demux->element_index);
2402 demux->element_index = gst_object_ref (index);
2404 demux->element_index = NULL;
2406 GST_OBJECT_UNLOCK (demux);
2407 /* object lock might be taken again */
2409 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2410 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2411 demux->element_index, demux->index_id);
2415 gst_qtdemux_get_index (GstElement * element)
2417 GstIndex *result = NULL;
2418 GstQTDemux *demux = GST_QTDEMUX (element);
2420 GST_OBJECT_LOCK (demux);
2421 if (demux->element_index)
2422 result = gst_object_ref (demux->element_index);
2423 GST_OBJECT_UNLOCK (demux);
2425 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2432 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2434 g_free ((gpointer) stream->stco.data);
2435 stream->stco.data = NULL;
2436 g_free ((gpointer) stream->stsz.data);
2437 stream->stsz.data = NULL;
2438 g_free ((gpointer) stream->stsc.data);
2439 stream->stsc.data = NULL;
2440 g_free ((gpointer) stream->stts.data);
2441 stream->stts.data = NULL;
2442 g_free ((gpointer) stream->stss.data);
2443 stream->stss.data = NULL;
2444 g_free ((gpointer) stream->stps.data);
2445 stream->stps.data = NULL;
2446 g_free ((gpointer) stream->ctts.data);
2447 stream->ctts.data = NULL;
2451 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2452 QtDemuxStream * stream)
2454 g_free (stream->segments);
2455 stream->segments = NULL;
2456 stream->segment_index = -1;
2457 stream->accumulated_base = 0;
2461 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2462 QtDemuxStream * stream)
2464 g_free (stream->samples);
2465 stream->samples = NULL;
2466 gst_qtdemux_stbl_free (stream);
2469 g_free (stream->ra_entries);
2470 stream->ra_entries = NULL;
2471 stream->n_ra_entries = 0;
2473 stream->sample_index = -1;
2474 stream->stbl_index = -1;
2475 stream->n_samples = 0;
2476 stream->time_position = 0;
2478 stream->n_samples_moof = 0;
2479 stream->duration_moof = 0;
2480 stream->duration_last_moof = 0;
2484 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2487 if (stream->allocator)
2488 gst_object_unref (stream->allocator);
2489 while (stream->buffers) {
2490 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2491 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2493 for (i = 0; i < stream->stsd_entries_length; i++) {
2494 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2495 if (entry->rgb8_palette) {
2496 gst_memory_unref (entry->rgb8_palette);
2497 entry->rgb8_palette = NULL;
2499 entry->sparse = FALSE;
2502 gst_tag_list_unref (stream->stream_tags);
2503 stream->stream_tags = gst_tag_list_new_empty ();
2504 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2505 g_free (stream->redirect_uri);
2506 stream->redirect_uri = NULL;
2507 stream->sent_eos = FALSE;
2508 stream->protected = FALSE;
2509 if (stream->protection_scheme_info) {
2510 if (stream->protection_scheme_type == FOURCC_cenc) {
2511 QtDemuxCencSampleSetInfo *info =
2512 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2513 if (info->default_properties)
2514 gst_structure_free (info->default_properties);
2515 if (info->crypto_info)
2516 g_ptr_array_free (info->crypto_info, TRUE);
2518 g_free (stream->protection_scheme_info);
2519 stream->protection_scheme_info = NULL;
2521 stream->protection_scheme_type = 0;
2522 stream->protection_scheme_version = 0;
2523 g_queue_foreach (&stream->protection_scheme_event_queue,
2524 (GFunc) gst_event_unref, NULL);
2525 g_queue_clear (&stream->protection_scheme_event_queue);
2526 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2527 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2531 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2534 gst_qtdemux_stream_clear (qtdemux, stream);
2535 for (i = 0; i < stream->stsd_entries_length; i++) {
2536 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2538 gst_caps_unref (entry->caps);
2542 gst_tag_list_unref (stream->stream_tags);
2544 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2545 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2547 g_free (stream->stsd_entries);
2552 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2554 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2556 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2557 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2558 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2559 qtdemux->n_streams--;
2562 static GstStateChangeReturn
2563 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2565 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2566 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2568 switch (transition) {
2569 case GST_STATE_CHANGE_PAUSED_TO_READY:
2575 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2577 switch (transition) {
2578 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2579 gst_qtdemux_reset (qtdemux, TRUE);
2590 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2592 /* counts as header data */
2593 qtdemux->header_size += length;
2595 /* only consider at least a sufficiently complete ftyp atom */
2599 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2600 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2601 GST_FOURCC_ARGS (qtdemux->major_brand));
2602 if (qtdemux->comp_brands)
2603 gst_buffer_unref (qtdemux->comp_brands);
2604 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2605 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2610 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2611 GstTagList * xmptaglist)
2613 /* Strip out bogus fields */
2615 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2616 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2617 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2619 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2622 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2624 /* prioritize native tags using _KEEP mode */
2625 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2626 gst_tag_list_unref (xmptaglist);
2631 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2639 QtDemuxStream *stream;
2640 GstStructure *structure;
2641 QtDemuxCencSampleSetInfo *ss_info = NULL;
2642 const gchar *system_id;
2643 gboolean uses_sub_sample_encryption = FALSE;
2645 if (qtdemux->n_streams == 0)
2648 stream = qtdemux->streams[0];
2650 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2651 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2652 GST_WARNING_OBJECT (qtdemux,
2653 "Attempting PIFF box parsing on an unencrypted stream.");
2657 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2658 G_TYPE_STRING, &system_id, NULL);
2659 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2661 stream->protected = TRUE;
2662 stream->protection_scheme_type = FOURCC_cenc;
2664 if (!stream->protection_scheme_info)
2665 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2667 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2669 if (ss_info->default_properties)
2670 gst_structure_free (ss_info->default_properties);
2672 ss_info->default_properties =
2673 gst_structure_new ("application/x-cenc",
2674 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2676 if (ss_info->crypto_info) {
2677 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2678 g_ptr_array_free (ss_info->crypto_info, TRUE);
2679 ss_info->crypto_info = NULL;
2683 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2685 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2686 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2690 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2691 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2695 if ((flags & 0x000001)) {
2696 guint32 algorithm_id = 0;
2699 gboolean is_encrypted = TRUE;
2701 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2702 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2707 if (algorithm_id == 0) {
2708 is_encrypted = FALSE;
2709 } else if (algorithm_id == 1) {
2710 /* FIXME: maybe store this in properties? */
2711 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2712 } else if (algorithm_id == 2) {
2713 /* FIXME: maybe store this in properties? */
2714 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2717 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2720 if (!gst_byte_reader_get_data (&br, 16, &kid))
2723 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2724 gst_buffer_fill (kid_buf, 0, kid, 16);
2725 if (ss_info->default_properties)
2726 gst_structure_free (ss_info->default_properties);
2727 ss_info->default_properties =
2728 gst_structure_new ("application/x-cenc",
2729 "iv_size", G_TYPE_UINT, iv_size,
2730 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2731 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2732 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2733 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2734 gst_buffer_unref (kid_buf);
2735 } else if ((flags & 0x000002)) {
2736 uses_sub_sample_encryption = TRUE;
2739 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2740 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2744 ss_info->crypto_info =
2745 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2746 (GDestroyNotify) qtdemux_gst_structure_free);
2748 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2749 GstStructure *properties;
2753 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2754 if (properties == NULL) {
2755 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2759 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2760 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2761 gst_structure_free (properties);
2764 buf = gst_buffer_new_wrapped (data, iv_size);
2765 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2766 gst_buffer_unref (buf);
2768 if (uses_sub_sample_encryption) {
2769 guint16 n_subsamples;
2771 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2772 || n_subsamples == 0) {
2773 GST_ERROR_OBJECT (qtdemux,
2774 "failed to get subsample count for sample %u", i);
2775 gst_structure_free (properties);
2778 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2779 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2780 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2782 gst_structure_free (properties);
2785 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2786 gst_structure_set (properties,
2787 "subsample_count", G_TYPE_UINT, n_subsamples,
2788 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2789 gst_buffer_unref (buf);
2791 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2794 g_ptr_array_add (ss_info->crypto_info, properties);
2799 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2801 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2802 0x97, 0xA9, 0x42, 0xE8,
2803 0x9C, 0x71, 0x99, 0x94,
2804 0x91, 0xE3, 0xAF, 0xAC
2806 static const guint8 playready_uuid[] = {
2807 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2808 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2811 static const guint8 piff_sample_encryption_uuid[] = {
2812 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2813 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2818 /* counts as header data */
2819 qtdemux->header_size += length;
2821 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2823 if (length <= offset + 16) {
2824 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2828 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2830 GstTagList *taglist;
2832 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2833 length - offset - 16, NULL);
2834 taglist = gst_tag_list_from_xmp_buffer (buf);
2835 gst_buffer_unref (buf);
2837 /* make sure we have a usable taglist */
2838 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2840 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2842 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2844 const gunichar2 *s_utf16;
2847 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2848 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2849 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2850 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2854 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2855 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2857 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2858 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2860 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2861 GST_READ_UINT32_LE (buffer + offset),
2862 GST_READ_UINT32_LE (buffer + offset + 4),
2863 GST_READ_UINT32_LE (buffer + offset + 8),
2864 GST_READ_UINT32_LE (buffer + offset + 12));
2869 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2871 GstSidxParser sidx_parser;
2872 GstIsoffParserResult res;
2875 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2878 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2880 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2881 if (res == GST_ISOFF_QT_PARSER_DONE) {
2882 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2884 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2887 /* caller verifies at least 8 bytes in buf */
2889 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2890 guint64 * plength, guint32 * pfourcc)
2895 length = QT_UINT32 (data);
2896 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2897 fourcc = QT_FOURCC (data + 4);
2898 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2901 length = G_MAXUINT64;
2902 } else if (length == 1 && size >= 16) {
2903 /* this means we have an extended size, which is the 64 bit value of
2904 * the next 8 bytes */
2905 length = QT_UINT64 (data + 8);
2906 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2916 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2918 guint32 version = 0;
2919 GstClockTime duration = 0;
2921 if (!gst_byte_reader_get_uint32_be (br, &version))
2926 if (!gst_byte_reader_get_uint64_be (br, &duration))
2931 if (!gst_byte_reader_get_uint32_be (br, &dur))
2936 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2937 qtdemux->duration = duration;
2943 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2949 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2950 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2952 if (!stream->parsed_trex && qtdemux->moov_node) {
2954 GstByteReader trex_data;
2956 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2958 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2961 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
2963 /* skip version/flags */
2964 if (!gst_byte_reader_skip (&trex_data, 4))
2966 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2968 if (id != stream->track_id)
2970 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
2972 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2974 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2976 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2979 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2980 "duration %d, size %d, flags 0x%x", stream->track_id,
2983 stream->parsed_trex = TRUE;
2984 stream->def_sample_description_index = sdi;
2985 stream->def_sample_duration = dur;
2986 stream->def_sample_size = size;
2987 stream->def_sample_flags = flags;
2990 /* iterate all siblings */
2991 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2997 *ds_duration = stream->def_sample_duration;
2998 *ds_size = stream->def_sample_size;
2999 *ds_flags = stream->def_sample_flags;
3001 /* even then, above values are better than random ... */
3002 if (G_UNLIKELY (!stream->parsed_trex)) {
3003 GST_WARNING_OBJECT (qtdemux,
3004 "failed to find fragment defaults for stream %d", stream->track_id);
3011 /* This method should be called whenever a more accurate duration might
3012 * have been found. It will update all relevant variables if/where needed
3015 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3019 GstClockTime prevdur;
3021 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3023 if (movdur > qtdemux->duration) {
3024 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3025 GST_DEBUG_OBJECT (qtdemux,
3026 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3027 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3028 qtdemux->duration = movdur;
3029 GST_DEBUG_OBJECT (qtdemux,
3030 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3031 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3032 GST_TIME_ARGS (qtdemux->segment.stop));
3033 if (qtdemux->segment.duration == prevdur) {
3034 /* If the current segment has duration/stop identical to previous duration
3035 * update them also (because they were set at that point in time with
3036 * the wrong duration */
3037 /* We convert the value *from* the timescale version to avoid rounding errors */
3038 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3039 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3040 qtdemux->segment.duration = fixeddur;
3041 qtdemux->segment.stop = fixeddur;
3044 for (i = 0; i < qtdemux->n_streams; i++) {
3045 QtDemuxStream *stream = qtdemux->streams[i];
3047 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3048 if (movdur > stream->duration) {
3049 GST_DEBUG_OBJECT (qtdemux,
3050 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3051 GST_TIME_ARGS (duration));
3052 stream->duration = movdur;
3053 if (stream->dummy_segment) {
3054 /* Update all dummy values to new duration */
3055 stream->segments[0].stop_time = duration;
3056 stream->segments[0].duration = duration;
3057 stream->segments[0].media_stop = duration;
3059 /* let downstream know we possibly have a new stop time */
3060 if (stream->segment_index != -1) {
3063 if (qtdemux->segment.rate >= 0) {
3064 pos = stream->segment.start;
3066 pos = stream->segment.stop;
3069 gst_qtdemux_stream_update_segment (qtdemux, stream,
3070 stream->segment_index, pos, NULL, NULL);
3079 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3080 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3081 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3082 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3085 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3087 gint32 data_offset = 0;
3088 guint32 flags = 0, first_flags = 0, samples_count = 0;
3091 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3092 QtDemuxSample *sample;
3093 gboolean ismv = FALSE;
3094 gint64 initial_offset;
3096 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3097 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3098 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3099 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3101 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3102 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3106 /* presence of stss or not can't really tell us much,
3107 * and flags and so on tend to be marginally reliable in these files */
3108 if (stream->subtype == FOURCC_soun) {
3109 GST_DEBUG_OBJECT (qtdemux,
3110 "sound track in fragmented file; marking all keyframes");
3111 stream->all_keyframe = TRUE;
3114 if (!gst_byte_reader_skip (trun, 1) ||
3115 !gst_byte_reader_get_uint24_be (trun, &flags))
3118 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3121 if (flags & TR_DATA_OFFSET) {
3122 /* note this is really signed */
3123 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3125 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3126 /* default base offset = first byte of moof */
3127 if (*base_offset == -1) {
3128 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3129 *base_offset = moof_offset;
3131 *running_offset = *base_offset + data_offset;
3133 /* if no offset at all, that would mean data starts at moof start,
3134 * which is a bit wrong and is ismv crappy way, so compensate
3135 * assuming data is in mdat following moof */
3136 if (*base_offset == -1) {
3137 *base_offset = moof_offset + moof_length + 8;
3138 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3141 if (*running_offset == -1)
3142 *running_offset = *base_offset;
3145 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3147 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3148 data_offset, flags, samples_count);
3150 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3151 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3152 GST_DEBUG_OBJECT (qtdemux,
3153 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3154 flags ^= TR_FIRST_SAMPLE_FLAGS;
3156 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3158 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3162 /* FIXME ? spec says other bits should also be checked to determine
3163 * entry size (and prefix size for that matter) */
3165 dur_offset = size_offset = 0;
3166 if (flags & TR_SAMPLE_DURATION) {
3167 GST_LOG_OBJECT (qtdemux, "entry duration present");
3168 dur_offset = entry_size;
3171 if (flags & TR_SAMPLE_SIZE) {
3172 GST_LOG_OBJECT (qtdemux, "entry size present");
3173 size_offset = entry_size;
3176 if (flags & TR_SAMPLE_FLAGS) {
3177 GST_LOG_OBJECT (qtdemux, "entry flags present");
3178 flags_offset = entry_size;
3181 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3182 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3183 ct_offset = entry_size;
3187 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3189 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3191 if (stream->n_samples + samples_count >=
3192 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3195 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3196 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3197 (stream->n_samples + samples_count) *
3198 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3200 /* create a new array of samples if it's the first sample parsed */
3201 if (stream->n_samples == 0) {
3202 g_assert (stream->samples == NULL);
3203 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3204 /* or try to reallocate it with space enough to insert the new samples */
3206 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3207 stream->n_samples + samples_count);
3208 if (stream->samples == NULL)
3211 if (qtdemux->fragment_start != -1) {
3212 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3213 qtdemux->fragment_start = -1;
3215 if (stream->n_samples == 0) {
3216 if (decode_ts > 0) {
3217 timestamp = decode_ts;
3218 } else if (stream->pending_seek != NULL) {
3219 /* if we don't have a timestamp from a tfdt box, we'll use the one
3220 * from the mfra seek table */
3221 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3222 GST_TIME_ARGS (stream->pending_seek->ts));
3224 /* FIXME: this is not fully correct, the timestamp refers to the random
3225 * access sample refered to in the tfra entry, which may not necessarily
3226 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3227 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3232 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3233 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3234 GST_TIME_ARGS (gst_ts));
3236 /* subsequent fragments extend stream */
3238 stream->samples[stream->n_samples - 1].timestamp +
3239 stream->samples[stream->n_samples - 1].duration;
3241 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3242 * difference (1 sec.) between decode_ts and timestamp, prefer the
3244 if (has_tfdt && !qtdemux->upstream_format_is_time
3245 && ABSDIFF (decode_ts, timestamp) >
3246 MAX (stream->duration_last_moof / 2,
3247 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3248 GST_INFO_OBJECT (qtdemux,
3249 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3250 ") are significantly different (more than %" GST_TIME_FORMAT
3251 "), using decode_ts",
3252 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3253 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3254 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3255 MAX (stream->duration_last_moof / 2,
3256 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3257 timestamp = decode_ts;
3260 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3261 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3262 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3266 initial_offset = *running_offset;
3268 sample = stream->samples + stream->n_samples;
3269 for (i = 0; i < samples_count; i++) {
3270 guint32 dur, size, sflags, ct;
3272 /* first read sample data */
3273 if (flags & TR_SAMPLE_DURATION) {
3274 dur = QT_UINT32 (data + dur_offset);
3276 dur = d_sample_duration;
3278 if (flags & TR_SAMPLE_SIZE) {
3279 size = QT_UINT32 (data + size_offset);
3281 size = d_sample_size;
3283 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3285 sflags = first_flags;
3287 sflags = d_sample_flags;
3289 } else if (flags & TR_SAMPLE_FLAGS) {
3290 sflags = QT_UINT32 (data + flags_offset);
3292 sflags = d_sample_flags;
3294 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3295 ct = QT_UINT32 (data + ct_offset);
3301 /* fill the sample information */
3302 sample->offset = *running_offset;
3303 sample->pts_offset = ct;
3304 sample->size = size;
3305 sample->timestamp = timestamp;
3306 sample->duration = dur;
3307 /* sample-is-difference-sample */
3308 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3309 * now idea how it relates to bitfield other than massive LE/BE confusion */
3310 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3311 *running_offset += size;
3313 stream->duration_moof += dur;
3317 /* Update total duration if needed */
3318 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3320 /* Pre-emptively figure out size of mdat based on trun information.
3321 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3322 * size, else we will still be able to use this when dealing with gap'ed
3324 qtdemux->mdatleft = *running_offset - initial_offset;
3325 qtdemux->mdatoffset = initial_offset;
3326 qtdemux->mdatsize = qtdemux->mdatleft;
3328 stream->n_samples += samples_count;
3329 stream->n_samples_moof += samples_count;
3331 if (stream->pending_seek != NULL)
3332 stream->pending_seek = NULL;
3338 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3343 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3349 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3350 "be larger than %uMB (broken file?)", stream->n_samples,
3351 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3356 /* find stream with @id */
3357 static inline QtDemuxStream *
3358 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3360 QtDemuxStream *stream;
3364 if (G_UNLIKELY (!id)) {
3365 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3369 /* try to get it fast and simple */
3370 if (G_LIKELY (id <= qtdemux->n_streams)) {
3371 stream = qtdemux->streams[id - 1];
3372 if (G_LIKELY (stream->track_id == id))
3376 /* linear search otherwise */
3377 for (i = 0; i < qtdemux->n_streams; i++) {
3378 stream = qtdemux->streams[i];
3379 if (stream->track_id == id)
3382 if (qtdemux->mss_mode) {
3383 /* mss should have only 1 stream anyway */
3384 return qtdemux->streams[0];
3391 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3392 guint32 * fragment_number)
3394 if (!gst_byte_reader_skip (mfhd, 4))
3396 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3401 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3407 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3408 QtDemuxStream ** stream, guint32 * default_sample_duration,
3409 guint32 * default_sample_size, guint32 * default_sample_flags,
3410 gint64 * base_offset)
3413 guint32 track_id = 0;
3415 if (!gst_byte_reader_skip (tfhd, 1) ||
3416 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3419 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3422 *stream = qtdemux_find_stream (qtdemux, track_id);
3423 if (G_UNLIKELY (!*stream))
3424 goto unknown_stream;
3426 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3427 *base_offset = qtdemux->moof_offset;
3429 if (flags & TF_BASE_DATA_OFFSET)
3430 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3433 /* obtain stream defaults */
3434 qtdemux_parse_trex (qtdemux, *stream,
3435 default_sample_duration, default_sample_size, default_sample_flags);
3437 (*stream)->stsd_sample_description_id =
3438 (*stream)->def_sample_description_index - 1;
3440 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3441 guint32 sample_description_index;
3442 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3444 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3447 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3448 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3451 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3452 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3455 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3456 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3463 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3468 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3474 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3475 guint64 * decode_time)
3477 guint32 version = 0;
3479 if (!gst_byte_reader_get_uint32_be (br, &version))
3484 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3487 guint32 dec_time = 0;
3488 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3490 *decode_time = dec_time;
3493 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3500 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3505 /* Returns a pointer to a GstStructure containing the properties of
3506 * the stream sample identified by @sample_index. The caller must unref
3507 * the returned object after use. Returns NULL if unsuccessful. */
3508 static GstStructure *
3509 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3510 QtDemuxStream * stream, guint sample_index)
3512 QtDemuxCencSampleSetInfo *info = NULL;
3514 g_return_val_if_fail (stream != NULL, NULL);
3515 g_return_val_if_fail (stream->protected, NULL);
3516 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3518 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3520 /* Currently, cenc properties for groups of samples are not supported, so
3521 * simply return a copy of the default sample properties */
3522 return gst_structure_copy (info->default_properties);
3525 /* Parses the sizes of sample auxiliary information contained within a stream,
3526 * as given in a saiz box. Returns array of sample_count guint8 size values,
3527 * or NULL on failure */
3529 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3530 GstByteReader * br, guint32 * sample_count)
3534 guint8 default_info_size;
3536 g_return_val_if_fail (qtdemux != NULL, NULL);
3537 g_return_val_if_fail (stream != NULL, NULL);
3538 g_return_val_if_fail (br != NULL, NULL);
3539 g_return_val_if_fail (sample_count != NULL, NULL);
3541 if (!gst_byte_reader_get_uint32_be (br, &flags))
3545 /* aux_info_type and aux_info_type_parameter are ignored */
3546 if (!gst_byte_reader_skip (br, 8))
3550 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3552 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3554 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3556 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3559 if (default_info_size == 0) {
3560 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3564 info_sizes = g_new (guint8, *sample_count);
3565 memset (info_sizes, default_info_size, *sample_count);
3571 /* Parses the offset of sample auxiliary information contained within a stream,
3572 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3574 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3575 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3580 guint32 aux_info_type = 0;
3581 guint32 aux_info_type_parameter = 0;
3582 guint32 entry_count;
3585 const guint8 *aux_info_type_data = NULL;
3587 g_return_val_if_fail (qtdemux != NULL, FALSE);
3588 g_return_val_if_fail (stream != NULL, FALSE);
3589 g_return_val_if_fail (br != NULL, FALSE);
3590 g_return_val_if_fail (offset != NULL, FALSE);
3592 if (!gst_byte_reader_get_uint8 (br, &version))
3595 if (!gst_byte_reader_get_uint24_be (br, &flags))
3600 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3602 aux_info_type = QT_FOURCC (aux_info_type_data);
3604 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3606 } else if (stream->protected) {
3607 aux_info_type = stream->protection_scheme_type;
3609 aux_info_type = CUR_STREAM (stream)->fourcc;
3613 *info_type = aux_info_type;
3614 if (info_type_parameter)
3615 *info_type_parameter = aux_info_type_parameter;
3617 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3618 "aux_info_type_parameter: %#06x",
3619 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3621 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3624 if (entry_count != 1) {
3625 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3630 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3632 *offset = (guint64) off_32;
3634 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3639 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3644 qtdemux_gst_structure_free (GstStructure * gststructure)
3647 gst_structure_free (gststructure);
3651 /* Parses auxiliary information relating to samples protected using Common
3652 * Encryption (cenc); the format of this information is defined in
3653 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3655 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3656 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3658 QtDemuxCencSampleSetInfo *ss_info = NULL;
3661 GPtrArray *old_crypto_info = NULL;
3662 guint old_entries = 0;
3664 g_return_val_if_fail (qtdemux != NULL, FALSE);
3665 g_return_val_if_fail (stream != NULL, FALSE);
3666 g_return_val_if_fail (br != NULL, FALSE);
3667 g_return_val_if_fail (stream->protected, FALSE);
3668 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3670 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3672 if (ss_info->crypto_info) {
3673 old_crypto_info = ss_info->crypto_info;
3674 /* Count number of non-null entries remaining at the tail end */
3675 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3676 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3682 ss_info->crypto_info =
3683 g_ptr_array_new_full (sample_count + old_entries,
3684 (GDestroyNotify) qtdemux_gst_structure_free);
3686 /* We preserve old entries because we parse the next moof in advance
3687 * of consuming all samples from the previous moof, and otherwise
3688 * we'd discard the corresponding crypto info for the samples
3689 * from the previous fragment. */
3691 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3693 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3694 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3696 g_ptr_array_index (old_crypto_info, i) = NULL;
3700 if (old_crypto_info) {
3701 /* Everything now belongs to the new array */
3702 g_ptr_array_free (old_crypto_info, TRUE);
3705 for (i = 0; i < sample_count; ++i) {
3706 GstStructure *properties;
3707 guint16 n_subsamples = 0;
3712 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3713 if (properties == NULL) {
3714 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3717 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3718 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3719 gst_structure_free (properties);
3722 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3723 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3724 gst_structure_free (properties);
3727 buf = gst_buffer_new_wrapped (data, iv_size);
3728 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3729 gst_buffer_unref (buf);
3730 size = info_sizes[i];
3731 if (size > iv_size) {
3732 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3733 || !(n_subsamples > 0)) {
3734 gst_structure_free (properties);
3735 GST_ERROR_OBJECT (qtdemux,
3736 "failed to get subsample count for sample %u", i);
3739 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3740 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3741 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3743 gst_structure_free (properties);
3746 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3748 gst_structure_free (properties);
3751 gst_structure_set (properties,
3752 "subsample_count", G_TYPE_UINT, n_subsamples,
3753 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3754 gst_buffer_unref (buf);
3756 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3758 g_ptr_array_add (ss_info->crypto_info, properties);
3763 /* Converts a UUID in raw byte form to a string representation, as defined in
3764 * RFC 4122. The caller takes ownership of the returned string and is
3765 * responsible for freeing it after use. */
3767 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3769 const guint8 *uuid = (const guint8 *) uuid_bytes;
3771 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3772 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3773 uuid[0], uuid[1], uuid[2], uuid[3],
3774 uuid[4], uuid[5], uuid[6], uuid[7],
3775 uuid[8], uuid[9], uuid[10], uuid[11],
3776 uuid[12], uuid[13], uuid[14], uuid[15]);
3779 /* Parses a Protection System Specific Header box (pssh), as defined in the
3780 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3781 * information needed by a specific content protection system in order to
3782 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3785 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3787 gchar *sysid_string;
3788 guint32 pssh_size = QT_UINT32 (node->data);
3789 GstBuffer *pssh = NULL;
3790 GstEvent *event = NULL;
3791 guint32 parent_box_type;
3794 if (G_UNLIKELY (pssh_size < 32U)) {
3795 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3800 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3802 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3804 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3805 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3806 gst_buffer_get_size (pssh));
3808 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3810 /* Push an event containing the pssh box onto the queues of all streams. */
3811 event = gst_event_new_protection (sysid_string, pssh,
3812 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3813 for (i = 0; i < qtdemux->n_streams; ++i) {
3814 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3815 gst_event_ref (event));
3817 g_free (sysid_string);
3818 gst_event_unref (event);
3819 gst_buffer_unref (pssh);
3824 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3825 guint64 moof_offset, QtDemuxStream * stream)
3827 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3829 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3830 GNode *saiz_node, *saio_node, *pssh_node;
3831 GstByteReader saiz_data, saio_data;
3832 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3833 gint64 base_offset, running_offset;
3836 /* NOTE @stream ignored */
3838 moof_node = g_node_new ((guint8 *) buffer);
3839 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3840 qtdemux_node_dump (qtdemux, moof_node);
3842 /* Get fragment number from mfhd and check it's valid */
3844 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3845 if (mfhd_node == NULL)
3847 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3849 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3851 /* unknown base_offset to start with */
3852 base_offset = running_offset = -1;
3853 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3855 guint64 decode_time = 0;
3857 /* Fragment Header node */
3859 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3863 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3864 &ds_size, &ds_flags, &base_offset))
3867 /* The following code assumes at most a single set of sample auxiliary
3868 * data in the fragment (consisting of a saiz box and a corresponding saio
3869 * box); in theory, however, there could be multiple sets of sample
3870 * auxiliary data in a fragment. */
3872 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3875 guint32 info_type = 0;
3877 guint32 info_type_parameter = 0;
3879 g_free (qtdemux->cenc_aux_info_sizes);
3881 qtdemux->cenc_aux_info_sizes =
3882 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3883 &qtdemux->cenc_aux_sample_count);
3884 if (qtdemux->cenc_aux_info_sizes == NULL) {
3885 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3889 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3892 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3893 g_free (qtdemux->cenc_aux_info_sizes);
3894 qtdemux->cenc_aux_info_sizes = NULL;
3898 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3899 &info_type, &info_type_parameter, &offset))) {
3900 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3901 g_free (qtdemux->cenc_aux_info_sizes);
3902 qtdemux->cenc_aux_info_sizes = NULL;
3905 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3906 offset += (guint64) (base_offset - qtdemux->moof_offset);
3907 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3909 if (offset > length) {
3910 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3911 qtdemux->cenc_aux_info_offset = offset;
3913 gst_byte_reader_init (&br, buffer + offset, length - offset);
3914 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3915 qtdemux->cenc_aux_info_sizes,
3916 qtdemux->cenc_aux_sample_count)) {
3917 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3918 g_free (qtdemux->cenc_aux_info_sizes);
3919 qtdemux->cenc_aux_info_sizes = NULL;
3927 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3930 /* We'll use decode_time to interpolate timestamps
3931 * in case the input timestamps are missing */
3932 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3934 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3935 " (%" GST_TIME_FORMAT ")", decode_time,
3936 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_time)));
3938 /* Discard the fragment buffer timestamp info to avoid using it.
3939 * Rely on tfdt instead as it is more accurate than the timestamp
3940 * that is fetched from a manifest/playlist and is usually
3942 qtdemux->fragment_start = -1;
3945 if (G_UNLIKELY (!stream)) {
3946 /* we lost track of offset, we'll need to regain it,
3947 * but can delay complaining until later or avoid doing so altogether */
3951 if (G_UNLIKELY (base_offset < -1))
3954 if (qtdemux->upstream_format_is_time)
3955 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3957 /* initialise moof sample data */
3958 stream->n_samples_moof = 0;
3959 stream->duration_last_moof = stream->duration_moof;
3960 stream->duration_moof = 0;
3962 /* Track Run node */
3964 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3967 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3968 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3969 &running_offset, decode_time, (tfdt_node != NULL));
3970 /* iterate all siblings */
3971 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3975 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3977 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3978 guint32 box_length = QT_UINT32 (uuid_buffer);
3980 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3983 /* if no new base_offset provided for next traf,
3984 * base is end of current traf */
3985 base_offset = running_offset;
3986 running_offset = -1;
3988 if (stream->n_samples_moof && stream->duration_moof)
3989 stream->new_caps = TRUE;
3992 /* iterate all siblings */
3993 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3996 /* parse any protection system info */
3997 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3999 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4000 qtdemux_parse_pssh (qtdemux, pssh_node);
4001 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4004 g_node_destroy (moof_node);
4009 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4014 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4019 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4024 g_node_destroy (moof_node);
4025 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4026 (_("This file is corrupt and cannot be played.")), (NULL));
4032 /* might be used if some day we actually use mfra & co
4033 * for random access to fragments,
4034 * but that will require quite some modifications and much less relying
4035 * on a sample array */
4039 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4041 QtDemuxStream *stream;
4042 guint32 ver_flags, track_id, len, num_entries, i;
4043 guint value_size, traf_size, trun_size, sample_size;
4044 guint64 time = 0, moof_offset = 0;
4046 GstBuffer *buf = NULL;
4051 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4053 if (!gst_byte_reader_skip (&tfra, 8))
4056 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4059 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4060 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4061 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4064 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4066 stream = qtdemux_find_stream (qtdemux, track_id);
4068 goto unknown_trackid;
4070 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4071 sample_size = (len & 3) + 1;
4072 trun_size = ((len & 12) >> 2) + 1;
4073 traf_size = ((len & 48) >> 4) + 1;
4075 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4076 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4078 if (num_entries == 0)
4081 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4082 value_size + value_size + traf_size + trun_size + sample_size))
4085 g_free (stream->ra_entries);
4086 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4087 stream->n_ra_entries = num_entries;
4089 for (i = 0; i < num_entries; i++) {
4090 qt_atom_parser_get_offset (&tfra, value_size, &time);
4091 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4092 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4093 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4094 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4096 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4098 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4099 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4101 stream->ra_entries[i].ts = time;
4102 stream->ra_entries[i].moof_offset = moof_offset;
4104 /* don't want to go through the entire file and read all moofs at startup */
4106 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4107 if (ret != GST_FLOW_OK)
4109 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4110 moof_offset, stream);
4111 gst_buffer_unref (buf);
4115 check_update_duration (qtdemux, time);
4122 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4127 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4132 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4138 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4140 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4141 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4142 GstBuffer *mfro = NULL, *mfra = NULL;
4144 gboolean ret = FALSE;
4145 GNode *mfra_node, *tfra_node;
4146 guint64 mfra_offset = 0;
4147 guint32 fourcc, mfra_size;
4150 /* query upstream size in bytes */
4151 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4152 goto size_query_failed;
4154 /* mfro box should be at the very end of the file */
4155 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4156 if (flow != GST_FLOW_OK)
4159 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4161 fourcc = QT_FOURCC (mfro_map.data + 4);
4162 if (fourcc != FOURCC_mfro)
4165 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4166 if (mfro_map.size < 16)
4167 goto invalid_mfro_size;
4169 mfra_size = QT_UINT32 (mfro_map.data + 12);
4170 if (mfra_size >= len)
4171 goto invalid_mfra_size;
4173 mfra_offset = len - mfra_size;
4175 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4176 mfra_offset, mfra_size);
4178 /* now get and parse mfra box */
4179 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4180 if (flow != GST_FLOW_OK)
4183 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4185 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4186 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4188 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4191 qtdemux_parse_tfra (qtdemux, tfra_node);
4192 /* iterate all siblings */
4193 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4195 g_node_destroy (mfra_node);
4197 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4203 if (mfro_map.memory != NULL)
4204 gst_buffer_unmap (mfro, &mfro_map);
4205 gst_buffer_unref (mfro);
4208 if (mfra_map.memory != NULL)
4209 gst_buffer_unmap (mfra, &mfra_map);
4210 gst_buffer_unref (mfra);
4217 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4222 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4227 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4232 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4238 add_offset (guint64 offset, guint64 advance)
4240 /* Avoid 64-bit overflow by clamping */
4241 if (offset > G_MAXUINT64 - advance)
4243 return offset + advance;
4246 static GstFlowReturn
4247 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4251 GstBuffer *buf = NULL;
4252 GstFlowReturn ret = GST_FLOW_OK;
4253 guint64 cur_offset = qtdemux->offset;
4256 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4257 if (G_UNLIKELY (ret != GST_FLOW_OK))
4259 gst_buffer_map (buf, &map, GST_MAP_READ);
4260 if (G_LIKELY (map.size >= 8))
4261 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4262 gst_buffer_unmap (buf, &map);
4263 gst_buffer_unref (buf);
4265 /* maybe we already got most we needed, so only consider this eof */
4266 if (G_UNLIKELY (length == 0)) {
4267 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4268 (_("Invalid atom size.")),
4269 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4270 GST_FOURCC_ARGS (fourcc)));
4277 /* record for later parsing when needed */
4278 if (!qtdemux->moof_offset) {
4279 qtdemux->moof_offset = qtdemux->offset;
4281 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4284 qtdemux->offset += length; /* skip moof and keep going */
4286 if (qtdemux->got_moov) {
4287 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4298 GST_LOG_OBJECT (qtdemux,
4299 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4300 GST_FOURCC_ARGS (fourcc), cur_offset);
4301 qtdemux->offset = add_offset (qtdemux->offset, length);
4306 GstBuffer *moov = NULL;
4308 if (qtdemux->got_moov) {
4309 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4310 qtdemux->offset = add_offset (qtdemux->offset, length);
4314 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4315 if (ret != GST_FLOW_OK)
4317 gst_buffer_map (moov, &map, GST_MAP_READ);
4319 if (length != map.size) {
4320 /* Some files have a 'moov' atom at the end of the file which contains
4321 * a terminal 'free' atom where the body of the atom is missing.
4322 * Check for, and permit, this special case.
4324 if (map.size >= 8) {
4325 guint8 *final_data = map.data + (map.size - 8);
4326 guint32 final_length = QT_UINT32 (final_data);
4327 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4329 if (final_fourcc == FOURCC_free
4330 && map.size + final_length - 8 == length) {
4331 /* Ok, we've found that special case. Allocate a new buffer with
4332 * that free atom actually present. */
4333 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4334 gst_buffer_fill (newmoov, 0, map.data, map.size);
4335 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4336 gst_buffer_unmap (moov, &map);
4337 gst_buffer_unref (moov);
4339 gst_buffer_map (moov, &map, GST_MAP_READ);
4344 if (length != map.size) {
4345 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4346 (_("This file is incomplete and cannot be played.")),
4347 ("We got less than expected (received %" G_GSIZE_FORMAT
4348 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4349 (guint) length, cur_offset));
4350 gst_buffer_unmap (moov, &map);
4351 gst_buffer_unref (moov);
4352 ret = GST_FLOW_ERROR;
4355 qtdemux->offset += length;
4357 qtdemux_parse_moov (qtdemux, map.data, length);
4358 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4360 qtdemux_parse_tree (qtdemux);
4361 if (qtdemux->moov_node_compressed) {
4362 g_node_destroy (qtdemux->moov_node_compressed);
4363 g_free (qtdemux->moov_node->data);
4365 qtdemux->moov_node_compressed = NULL;
4366 g_node_destroy (qtdemux->moov_node);
4367 qtdemux->moov_node = NULL;
4368 gst_buffer_unmap (moov, &map);
4369 gst_buffer_unref (moov);
4370 qtdemux->got_moov = TRUE;
4376 GstBuffer *ftyp = NULL;
4378 /* extract major brand; might come in handy for ISO vs QT issues */
4379 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4380 if (ret != GST_FLOW_OK)
4382 qtdemux->offset += length;
4383 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4384 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4385 gst_buffer_unmap (ftyp, &map);
4386 gst_buffer_unref (ftyp);
4391 GstBuffer *uuid = NULL;
4393 /* uuid are extension atoms */
4394 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4395 if (ret != GST_FLOW_OK)
4397 qtdemux->offset += length;
4398 gst_buffer_map (uuid, &map, GST_MAP_READ);
4399 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4400 gst_buffer_unmap (uuid, &map);
4401 gst_buffer_unref (uuid);
4406 GstBuffer *sidx = NULL;
4407 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4408 if (ret != GST_FLOW_OK)
4410 qtdemux->offset += length;
4411 gst_buffer_map (sidx, &map, GST_MAP_READ);
4412 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4413 gst_buffer_unmap (sidx, &map);
4414 gst_buffer_unref (sidx);
4419 GstBuffer *unknown = NULL;
4421 GST_LOG_OBJECT (qtdemux,
4422 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4423 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4425 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4426 if (ret != GST_FLOW_OK)
4428 gst_buffer_map (unknown, &map, GST_MAP_READ);
4429 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4430 gst_buffer_unmap (unknown, &map);
4431 gst_buffer_unref (unknown);
4432 qtdemux->offset += length;
4438 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4439 /* digested all data, show what we have */
4440 qtdemux_prepare_streams (qtdemux);
4441 ret = qtdemux_expose_streams (qtdemux);
4443 qtdemux->state = QTDEMUX_STATE_MOVIE;
4444 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4451 /* Seeks to the previous keyframe of the indexed stream and
4452 * aligns other streams with respect to the keyframe timestamp
4453 * of indexed stream. Only called in case of Reverse Playback
4455 static GstFlowReturn
4456 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4459 guint32 seg_idx = 0, k_index = 0;
4460 guint32 ref_seg_idx, ref_k_index;
4461 GstClockTime k_pos = 0, last_stop = 0;
4462 QtDemuxSegment *seg = NULL;
4463 QtDemuxStream *ref_str = NULL;
4464 guint64 seg_media_start_mov; /* segment media start time in mov format */
4467 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4468 * and finally align all the other streams on that timestamp with their
4469 * respective keyframes */
4470 for (n = 0; n < qtdemux->n_streams; n++) {
4471 QtDemuxStream *str = qtdemux->streams[n];
4473 /* No candidate yet, take the first stream */
4479 /* So that stream has a segment, we prefer video streams */
4480 if (str->subtype == FOURCC_vide) {
4486 if (G_UNLIKELY (!ref_str)) {
4487 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4491 if (G_UNLIKELY (!ref_str->from_sample)) {
4492 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4496 /* So that stream has been playing from from_sample to to_sample. We will
4497 * get the timestamp of the previous sample and search for a keyframe before
4498 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4499 if (ref_str->subtype == FOURCC_vide) {
4500 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4501 ref_str->from_sample - 1, FALSE);
4503 if (ref_str->from_sample >= 10)
4504 k_index = ref_str->from_sample - 10;
4510 ref_str->samples[k_index].timestamp +
4511 ref_str->samples[k_index].pts_offset;
4513 /* get current segment for that stream */
4514 seg = &ref_str->segments[ref_str->segment_index];
4515 /* Use segment start in original timescale for comparisons */
4516 seg_media_start_mov = seg->trak_media_start;
4518 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4519 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4520 k_index, target_ts, seg_media_start_mov,
4521 GST_TIME_ARGS (seg->media_start));
4523 /* Crawl back through segments to find the one containing this I frame */
4524 while (target_ts < seg_media_start_mov) {
4525 GST_DEBUG_OBJECT (qtdemux,
4526 "keyframe position (sample %u) is out of segment %u " " target %"
4527 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4528 ref_str->segment_index, target_ts, seg_media_start_mov);
4530 if (G_UNLIKELY (!ref_str->segment_index)) {
4531 /* Reached first segment, let's consider it's EOS */
4534 ref_str->segment_index--;
4535 seg = &ref_str->segments[ref_str->segment_index];
4536 /* Use segment start in original timescale for comparisons */
4537 seg_media_start_mov = seg->trak_media_start;
4539 /* Calculate time position of the keyframe and where we should stop */
4541 QTSTREAMTIME_TO_GSTTIME (ref_str,
4542 target_ts - seg->trak_media_start) + seg->time;
4544 QTSTREAMTIME_TO_GSTTIME (ref_str,
4545 ref_str->samples[ref_str->from_sample].timestamp -
4546 seg->trak_media_start) + seg->time;
4548 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4549 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4550 k_index, GST_TIME_ARGS (k_pos));
4552 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4553 qtdemux->segment.position = last_stop;
4554 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4555 GST_TIME_ARGS (last_stop));
4557 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4558 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4562 ref_seg_idx = ref_str->segment_index;
4563 ref_k_index = k_index;
4565 /* Align them all on this */
4566 for (n = 0; n < qtdemux->n_streams; n++) {
4568 GstClockTime seg_time = 0;
4569 QtDemuxStream *str = qtdemux->streams[n];
4571 /* aligning reference stream again might lead to backing up to yet another
4572 * keyframe (due to timestamp rounding issues),
4573 * potentially putting more load on downstream; so let's try to avoid */
4574 if (str == ref_str) {
4575 seg_idx = ref_seg_idx;
4576 seg = &str->segments[seg_idx];
4577 k_index = ref_k_index;
4578 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4579 "sample at index %d", n, ref_str->segment_index, k_index);
4581 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4582 GST_DEBUG_OBJECT (qtdemux,
4583 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4584 seg_idx, GST_TIME_ARGS (k_pos));
4586 /* get segment and time in the segment */
4587 seg = &str->segments[seg_idx];
4588 seg_time = k_pos - seg->time;
4590 /* get the media time in the segment.
4591 * No adjustment for empty "filler" segments */
4592 if (seg->media_start != GST_CLOCK_TIME_NONE)
4593 seg_time += seg->media_start;
4595 /* get the index of the sample with media time */
4596 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4597 GST_DEBUG_OBJECT (qtdemux,
4598 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4599 GST_TIME_ARGS (seg_time), index);
4601 /* find previous keyframe */
4602 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4605 /* Remember until where we want to go */
4606 str->to_sample = str->from_sample - 1;
4607 /* Define our time position */
4609 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4610 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4611 if (seg->media_start != GST_CLOCK_TIME_NONE)
4612 str->time_position -= seg->media_start;
4614 /* Now seek back in time */
4615 gst_qtdemux_move_stream (qtdemux, str, k_index);
4616 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4617 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4618 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4624 return GST_FLOW_EOS;
4628 * Gets the current qt segment start, stop and position for the
4629 * given time offset. This is used in update_segment()
4632 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4633 QtDemuxStream * stream, GstClockTime offset,
4634 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4636 GstClockTime seg_time;
4637 GstClockTime start, stop, time;
4638 QtDemuxSegment *segment;
4640 segment = &stream->segments[stream->segment_index];
4642 /* get time in this segment */
4643 seg_time = (offset - segment->time) * segment->rate;
4645 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4646 GST_TIME_ARGS (seg_time));
4648 if (G_UNLIKELY (seg_time > segment->duration)) {
4649 GST_LOG_OBJECT (stream->pad,
4650 "seg_time > segment->duration %" GST_TIME_FORMAT,
4651 GST_TIME_ARGS (segment->duration));
4652 seg_time = segment->duration;
4655 /* qtdemux->segment.stop is in outside-time-realm, whereas
4656 * segment->media_stop is in track-time-realm.
4658 * In order to compare the two, we need to bring segment.stop
4659 * into the track-time-realm
4661 * FIXME - does this comment still hold? Don't see any conversion here */
4663 stop = qtdemux->segment.stop;
4664 if (stop == GST_CLOCK_TIME_NONE)
4665 stop = qtdemux->segment.duration;
4666 if (stop == GST_CLOCK_TIME_NONE)
4667 stop = segment->media_stop;
4670 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4672 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4673 start = segment->time + seg_time;
4675 stop = start - seg_time + segment->duration;
4676 } else if (qtdemux->segment.rate >= 0) {
4677 start = MIN (segment->media_start + seg_time, stop);
4680 if (segment->media_start >= qtdemux->segment.start) {
4681 time = segment->time;
4683 time = segment->time + (qtdemux->segment.start - segment->media_start);
4686 start = MAX (segment->media_start, qtdemux->segment.start);
4687 stop = MIN (segment->media_start + seg_time, stop);
4696 * Updates the qt segment used for the stream and pushes a new segment event
4697 * downstream on this stream's pad.
4700 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4701 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4702 GstClockTime * _stop)
4704 QtDemuxSegment *segment;
4705 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4709 /* update the current segment */
4710 stream->segment_index = seg_idx;
4712 /* get the segment */
4713 segment = &stream->segments[seg_idx];
4715 if (G_UNLIKELY (offset < segment->time)) {
4716 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4717 GST_TIME_ARGS (segment->time));
4721 /* segment lies beyond total indicated duration */
4722 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4723 segment->time > qtdemux->segment.duration)) {
4724 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4725 " < segment->time %" GST_TIME_FORMAT,
4726 GST_TIME_ARGS (qtdemux->segment.duration),
4727 GST_TIME_ARGS (segment->time));
4731 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4732 &start, &stop, &time);
4734 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4735 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4736 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4738 /* combine global rate with that of the segment */
4739 rate = segment->rate * qtdemux->segment.rate;
4741 /* Copy flags from main segment */
4742 stream->segment.flags = qtdemux->segment.flags;
4744 /* update the segment values used for clipping */
4745 stream->segment.offset = qtdemux->segment.offset;
4746 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4747 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4748 stream->segment.rate = rate;
4749 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4750 stream->cslg_shift);
4751 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4752 stream->cslg_shift);
4753 stream->segment.time = time;
4754 stream->segment.position = stream->segment.start;
4756 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4759 /* now prepare and send the segment */
4761 event = gst_event_new_segment (&stream->segment);
4762 if (qtdemux->segment_seqnum) {
4763 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4765 gst_pad_push_event (stream->pad, event);
4766 /* assume we can send more data now */
4767 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4768 /* clear to send tags on this pad now */
4769 gst_qtdemux_push_tags (qtdemux, stream);
4780 /* activate the given segment number @seg_idx of @stream at time @offset.
4781 * @offset is an absolute global position over all the segments.
4783 * This will push out a NEWSEGMENT event with the right values and
4784 * position the stream index to the first decodable sample before
4788 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4789 guint32 seg_idx, GstClockTime offset)
4791 QtDemuxSegment *segment;
4792 guint32 index, kf_index;
4793 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4795 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4796 seg_idx, GST_TIME_ARGS (offset));
4798 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4802 segment = &stream->segments[stream->segment_index];
4804 /* in the fragmented case, we pick a fragment that starts before our
4805 * desired position and rely on downstream to wait for a keyframe
4806 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4807 * tfra entries tells us which trun/sample the key unit is in, but we don't
4808 * make use of this additional information at the moment) */
4809 if (qtdemux->fragmented) {
4810 stream->to_sample = G_MAXUINT32;
4814 /* We don't need to look for a sample in push-based */
4815 if (!qtdemux->pullbased)
4818 /* and move to the keyframe before the indicated media time of the
4820 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4821 if (qtdemux->segment.rate >= 0) {
4822 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4823 stream->to_sample = G_MAXUINT32;
4824 GST_DEBUG_OBJECT (stream->pad,
4825 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4826 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4827 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4829 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4830 stream->to_sample = index;
4831 GST_DEBUG_OBJECT (stream->pad,
4832 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4833 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4834 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4837 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4838 "this is an empty segment");
4842 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4843 * encountered an error and printed a message so we return appropriately */
4847 /* we're at the right spot */
4848 if (index == stream->sample_index) {
4849 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4853 /* find keyframe of the target index */
4854 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4857 /* indent does stupid stuff with stream->samples[].timestamp */
4859 /* if we move forwards, we don't have to go back to the previous
4860 * keyframe since we already sent that. We can also just jump to
4861 * the keyframe right before the target index if there is one. */
4862 if (index > stream->sample_index) {
4863 /* moving forwards check if we move past a keyframe */
4864 if (kf_index > stream->sample_index) {
4865 GST_DEBUG_OBJECT (stream->pad,
4866 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4867 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4868 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4869 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4871 GST_DEBUG_OBJECT (stream->pad,
4872 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4873 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4874 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4877 GST_DEBUG_OBJECT (stream->pad,
4878 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4879 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4880 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4881 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4889 /* prepare to get the current sample of @stream, getting essential values.
4891 * This function will also prepare and send the segment when needed.
4893 * Return FALSE if the stream is EOS.
4898 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4899 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4900 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4901 gboolean * keyframe)
4903 QtDemuxSample *sample;
4904 GstClockTime time_position;
4907 g_return_val_if_fail (stream != NULL, FALSE);
4909 time_position = stream->time_position;
4910 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4913 seg_idx = stream->segment_index;
4914 if (G_UNLIKELY (seg_idx == -1)) {
4915 /* find segment corresponding to time_position if we are looking
4917 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4920 /* different segment, activate it, sample_index will be set. */
4921 if (G_UNLIKELY (stream->segment_index != seg_idx))
4922 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4924 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4926 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4928 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4929 " prepare empty sample");
4932 *pts = *dts = time_position;
4933 *duration = seg->duration - (time_position - seg->time);
4940 if (stream->sample_index == -1)
4941 stream->sample_index = 0;
4943 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4944 stream->sample_index, stream->n_samples);
4946 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4947 if (!qtdemux->fragmented)
4950 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4954 GST_OBJECT_LOCK (qtdemux);
4955 flow = qtdemux_add_fragmented_samples (qtdemux);
4956 GST_OBJECT_UNLOCK (qtdemux);
4958 if (flow != GST_FLOW_OK)
4961 while (stream->sample_index >= stream->n_samples);
4964 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4965 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4966 stream->sample_index);
4970 /* now get the info for the sample we're at */
4971 sample = &stream->samples[stream->sample_index];
4973 *dts = QTSAMPLE_DTS (stream, sample);
4974 *pts = QTSAMPLE_PTS (stream, sample);
4975 *offset = sample->offset;
4976 *size = sample->size;
4977 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4978 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4985 stream->time_position = GST_CLOCK_TIME_NONE;
4990 /* move to the next sample in @stream.
4992 * Moves to the next segment when needed.
4995 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4997 QtDemuxSample *sample;
4998 QtDemuxSegment *segment;
5000 /* get current segment */
5001 segment = &stream->segments[stream->segment_index];
5003 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5004 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5008 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5009 /* Mark the stream as EOS */
5010 GST_DEBUG_OBJECT (qtdemux,
5011 "reached max allowed sample %u, mark EOS", stream->to_sample);
5012 stream->time_position = GST_CLOCK_TIME_NONE;
5016 /* move to next sample */
5017 stream->sample_index++;
5018 stream->offset_in_sample = 0;
5020 /* reached the last sample, we need the next segment */
5021 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5024 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5025 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5026 stream->sample_index);
5030 /* get next sample */
5031 sample = &stream->samples[stream->sample_index];
5033 /* see if we are past the segment */
5034 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5037 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5038 /* inside the segment, update time_position, looks very familiar to
5039 * GStreamer segments, doesn't it? */
5040 stream->time_position =
5041 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5043 /* not yet in segment, time does not yet increment. This means
5044 * that we are still prerolling keyframes to the decoder so it can
5045 * decode the first sample of the segment. */
5046 stream->time_position = segment->time;
5050 /* move to the next segment */
5053 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5055 if (stream->segment_index == stream->n_segments - 1) {
5056 /* are we at the end of the last segment, we're EOS */
5057 stream->time_position = GST_CLOCK_TIME_NONE;
5059 /* else we're only at the end of the current segment */
5060 stream->time_position = segment->stop_time;
5062 /* make sure we select a new segment */
5064 /* accumulate previous segments */
5065 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5066 stream->accumulated_base +=
5067 (stream->segment.stop -
5068 stream->segment.start) / ABS (stream->segment.rate);
5070 stream->segment_index = -1;
5075 gst_qtdemux_sync_streams (GstQTDemux * demux)
5079 if (demux->n_streams <= 1)
5082 for (i = 0; i < demux->n_streams; i++) {
5083 QtDemuxStream *stream;
5084 GstClockTime end_time;
5086 stream = demux->streams[i];
5091 /* TODO advance time on subtitle streams here, if any some day */
5093 /* some clips/trailers may have unbalanced streams at the end,
5094 * so send EOS on shorter stream to prevent stalling others */
5096 /* do not mess with EOS if SEGMENT seeking */
5097 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5100 if (demux->pullbased) {
5101 /* loop mode is sample time based */
5102 if (!STREAM_IS_EOS (stream))
5105 /* push mode is byte position based */
5106 if (stream->n_samples &&
5107 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5111 if (stream->sent_eos)
5114 /* only act if some gap */
5115 end_time = stream->segments[stream->n_segments - 1].stop_time;
5116 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5117 ", stream end: %" GST_TIME_FORMAT,
5118 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5119 if (GST_CLOCK_TIME_IS_VALID (end_time)
5120 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5123 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5124 GST_PAD_NAME (stream->pad));
5125 stream->sent_eos = TRUE;
5126 event = gst_event_new_eos ();
5127 if (demux->segment_seqnum)
5128 gst_event_set_seqnum (event, demux->segment_seqnum);
5129 gst_pad_push_event (stream->pad, event);
5134 /* EOS and NOT_LINKED need to be combined. This means that we return:
5136 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5137 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5139 static GstFlowReturn
5140 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5143 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5146 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5149 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5151 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5155 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5156 * completely clipped
5158 * Should be used only with raw buffers */
5160 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5163 guint64 start, stop, cstart, cstop, diff;
5164 GstClockTime pts, duration;
5166 gint num_rate, denom_rate;
5171 osize = size = gst_buffer_get_size (buf);
5174 /* depending on the type, setup the clip parameters */
5175 if (stream->subtype == FOURCC_soun) {
5176 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5177 num_rate = GST_SECOND;
5178 denom_rate = (gint) CUR_STREAM (stream)->rate;
5180 } else if (stream->subtype == FOURCC_vide) {
5182 num_rate = CUR_STREAM (stream)->fps_n;
5183 denom_rate = CUR_STREAM (stream)->fps_d;
5188 if (frame_size <= 0)
5189 goto bad_frame_size;
5191 /* we can only clip if we have a valid pts */
5192 pts = GST_BUFFER_PTS (buf);
5193 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5196 duration = GST_BUFFER_DURATION (buf);
5198 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5200 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5204 stop = start + duration;
5206 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5207 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5210 /* see if some clipping happened */
5211 diff = cstart - start;
5217 /* bring clipped time to samples and to bytes */
5218 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5221 GST_DEBUG_OBJECT (qtdemux,
5222 "clipping start to %" GST_TIME_FORMAT " %"
5223 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5229 diff = stop - cstop;
5234 /* bring clipped time to samples and then to bytes */
5235 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5237 GST_DEBUG_OBJECT (qtdemux,
5238 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5239 " bytes", GST_TIME_ARGS (cstop), diff);
5244 if (offset != 0 || size != osize)
5245 gst_buffer_resize (buf, offset, size);
5247 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5248 GST_BUFFER_PTS (buf) = pts;
5249 GST_BUFFER_DURATION (buf) = duration;
5253 /* dropped buffer */
5256 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5261 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5266 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5271 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5272 gst_buffer_unref (buf);
5278 gst_qtdemux_align_buffer (GstQTDemux * demux,
5279 GstBuffer * buffer, gsize alignment)
5283 gst_buffer_map (buffer, &map, GST_MAP_READ);
5285 if (map.size < sizeof (guintptr)) {
5286 gst_buffer_unmap (buffer, &map);
5290 if (((guintptr) map.data) & (alignment - 1)) {
5291 GstBuffer *new_buffer;
5292 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5294 new_buffer = gst_buffer_new_allocate (NULL,
5295 gst_buffer_get_size (buffer), ¶ms);
5297 /* Copy data "by hand", so ensure alignment is kept: */
5298 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5300 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5301 GST_DEBUG_OBJECT (demux,
5302 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5305 gst_buffer_unmap (buffer, &map);
5306 gst_buffer_unref (buffer);
5311 gst_buffer_unmap (buffer, &map);
5315 /* the input buffer metadata must be writable,
5316 * but time/duration etc not yet set and need not be preserved */
5318 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5325 /* not many cases for now */
5326 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5327 /* send a one time dvd clut event */
5328 if (stream->pending_event && stream->pad)
5329 gst_pad_push_event (stream->pad, stream->pending_event);
5330 stream->pending_event = NULL;
5333 if (G_UNLIKELY (stream->subtype != FOURCC_text
5334 && stream->subtype != FOURCC_sbtl &&
5335 stream->subtype != FOURCC_subp)) {
5339 gst_buffer_map (buf, &map, GST_MAP_READ);
5341 /* empty buffer is sent to terminate previous subtitle */
5342 if (map.size <= 2) {
5343 gst_buffer_unmap (buf, &map);
5344 gst_buffer_unref (buf);
5347 if (stream->subtype == FOURCC_subp) {
5348 /* That's all the processing needed for subpictures */
5349 gst_buffer_unmap (buf, &map);
5353 nsize = GST_READ_UINT16_BE (map.data);
5354 nsize = MIN (nsize, map.size - 2);
5356 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5359 /* takes care of UTF-8 validation or UTF-16 recognition,
5360 * no other encoding expected */
5361 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5362 gst_buffer_unmap (buf, &map);
5364 gst_buffer_unref (buf);
5365 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5367 /* this should not really happen unless the subtitle is corrupted */
5368 gst_buffer_unref (buf);
5372 /* FIXME ? convert optional subsequent style info to markup */
5377 /* Sets a buffer's attributes properly and pushes it downstream.
5378 * Also checks for additional actions and custom processing that may
5379 * need to be done first.
5381 static GstFlowReturn
5382 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5383 QtDemuxStream * stream, GstBuffer * buf,
5384 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5385 gboolean keyframe, GstClockTime position, guint64 byte_position)
5387 GstFlowReturn ret = GST_FLOW_OK;
5389 /* offset the timestamps according to the edit list */
5391 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5395 gst_buffer_map (buf, &map, GST_MAP_READ);
5396 url = g_strndup ((gchar *) map.data, map.size);
5397 gst_buffer_unmap (buf, &map);
5398 if (url != NULL && strlen (url) != 0) {
5399 /* we have RTSP redirect now */
5400 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5401 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5402 gst_structure_new ("redirect",
5403 "new-location", G_TYPE_STRING, url, NULL)));
5404 qtdemux->posted_redirect = TRUE;
5406 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5412 /* position reporting */
5413 if (qtdemux->segment.rate >= 0) {
5414 qtdemux->segment.position = position;
5415 gst_qtdemux_sync_streams (qtdemux);
5418 if (G_UNLIKELY (!stream->pad)) {
5419 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5420 gst_buffer_unref (buf);
5424 /* send out pending buffers */
5425 while (stream->buffers) {
5426 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5428 if (G_UNLIKELY (stream->discont)) {
5429 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5430 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5431 stream->discont = FALSE;
5433 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5436 if (stream->alignment > 1)
5437 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5438 gst_pad_push (stream->pad, buffer);
5440 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5443 /* we're going to modify the metadata */
5444 buf = gst_buffer_make_writable (buf);
5446 if (G_UNLIKELY (stream->need_process))
5447 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5453 GST_BUFFER_DTS (buf) = dts;
5454 GST_BUFFER_PTS (buf) = pts;
5455 GST_BUFFER_DURATION (buf) = duration;
5456 GST_BUFFER_OFFSET (buf) = -1;
5457 GST_BUFFER_OFFSET_END (buf) = -1;
5459 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5460 gst_buffer_append_memory (buf,
5461 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5463 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5464 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5467 if (G_UNLIKELY (qtdemux->element_index)) {
5468 GstClockTime stream_time;
5471 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5473 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5474 GST_LOG_OBJECT (qtdemux,
5475 "adding association %" GST_TIME_FORMAT "-> %"
5476 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5477 gst_index_add_association (qtdemux->element_index,
5479 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5480 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5481 GST_FORMAT_BYTES, byte_position, NULL);
5486 if (stream->need_clip)
5487 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5489 if (G_UNLIKELY (buf == NULL))
5492 if (G_UNLIKELY (stream->discont)) {
5493 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5494 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5495 stream->discont = FALSE;
5497 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5501 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5502 stream->on_keyframe = FALSE;
5504 stream->on_keyframe = TRUE;
5508 GST_LOG_OBJECT (qtdemux,
5509 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5510 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5511 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5512 GST_PAD_NAME (stream->pad));
5514 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5515 GstStructure *crypto_info;
5516 QtDemuxCencSampleSetInfo *info =
5517 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5521 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5522 gst_pad_push_event (stream->pad, event);
5525 if (info->crypto_info == NULL) {
5526 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5527 gst_buffer_unref (buf);
5531 /* The end of the crypto_info array matches our n_samples position,
5532 * so count backward from there */
5533 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5534 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5535 /* steal structure from array */
5536 crypto_info = g_ptr_array_index (info->crypto_info, index);
5537 g_ptr_array_index (info->crypto_info, index) = NULL;
5538 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5539 info->crypto_info->len);
5540 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5541 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5543 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5544 index, stream->sample_index);
5548 if (stream->alignment > 1)
5549 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5551 ret = gst_pad_push (stream->pad, buf);
5553 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5554 /* mark position in stream, we'll need this to know when to send GAP event */
5555 stream->segment.position = pts + duration;
5562 static const QtDemuxRandomAccessEntry *
5563 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5564 GstClockTime pos, gboolean after)
5566 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5567 guint n_entries = stream->n_ra_entries;
5570 /* we assume the table is sorted */
5571 for (i = 0; i < n_entries; ++i) {
5572 if (entries[i].ts > pos)
5576 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5577 * probably okay to assume that the index lists the very first fragment */
5584 return &entries[i - 1];
5588 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5590 const QtDemuxRandomAccessEntry *best_entry = NULL;
5593 GST_OBJECT_LOCK (qtdemux);
5595 g_assert (qtdemux->n_streams > 0);
5597 for (i = 0; i < qtdemux->n_streams; i++) {
5598 const QtDemuxRandomAccessEntry *entry;
5599 QtDemuxStream *stream;
5600 gboolean is_audio_or_video;
5602 stream = qtdemux->streams[i];
5604 g_free (stream->samples);
5605 stream->samples = NULL;
5606 stream->n_samples = 0;
5607 stream->stbl_index = -1; /* no samples have yet been parsed */
5608 stream->sample_index = -1;
5610 if (stream->protection_scheme_info) {
5611 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5612 if (stream->protection_scheme_type == FOURCC_cenc) {
5613 QtDemuxCencSampleSetInfo *info =
5614 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5615 if (info->crypto_info) {
5616 g_ptr_array_free (info->crypto_info, TRUE);
5617 info->crypto_info = NULL;
5622 if (stream->ra_entries == NULL)
5625 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5626 is_audio_or_video = TRUE;
5628 is_audio_or_video = FALSE;
5631 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5632 stream->time_position, !is_audio_or_video);
5634 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5635 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5637 stream->pending_seek = entry;
5639 /* decide position to jump to just based on audio/video tracks, not subs */
5640 if (!is_audio_or_video)
5643 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5647 if (best_entry == NULL) {
5648 GST_OBJECT_UNLOCK (qtdemux);
5652 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5653 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5654 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5655 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5657 qtdemux->moof_offset = best_entry->moof_offset;
5659 qtdemux_add_fragmented_samples (qtdemux);
5661 GST_OBJECT_UNLOCK (qtdemux);
5665 static GstFlowReturn
5666 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5668 GstFlowReturn ret = GST_FLOW_OK;
5669 GstBuffer *buf = NULL;
5670 QtDemuxStream *stream;
5671 GstClockTime min_time;
5673 GstClockTime dts = GST_CLOCK_TIME_NONE;
5674 GstClockTime pts = GST_CLOCK_TIME_NONE;
5675 GstClockTime duration = 0;
5676 gboolean keyframe = FALSE;
5677 guint sample_size = 0;
5683 gst_qtdemux_push_pending_newsegment (qtdemux);
5685 if (qtdemux->fragmented_seek_pending) {
5686 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5687 gst_qtdemux_do_fragmented_seek (qtdemux);
5688 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5689 qtdemux->fragmented_seek_pending = FALSE;
5692 /* Figure out the next stream sample to output, min_time is expressed in
5693 * global time and runs over the edit list segments. */
5694 min_time = G_MAXUINT64;
5696 for (i = 0; i < qtdemux->n_streams; i++) {
5697 GstClockTime position;
5699 stream = qtdemux->streams[i];
5700 position = stream->time_position;
5702 /* position of -1 is EOS */
5703 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5704 min_time = position;
5709 if (G_UNLIKELY (index == -1)) {
5710 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5714 /* check for segment end */
5715 if (G_UNLIKELY (qtdemux->segment.stop != -1
5716 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5717 || (qtdemux->segment.rate < 0
5718 && qtdemux->segment.start > min_time))
5719 && qtdemux->streams[index]->on_keyframe)) {
5720 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5721 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5725 /* gap events for subtitle streams */
5726 for (i = 0; i < qtdemux->n_streams; i++) {
5727 stream = qtdemux->streams[i];
5728 if (stream->pad && (stream->subtype == FOURCC_subp
5729 || stream->subtype == FOURCC_text
5730 || stream->subtype == FOURCC_sbtl)) {
5731 /* send one second gap events until the stream catches up */
5732 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5733 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5734 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5735 stream->segment.position + GST_SECOND < min_time) {
5737 gst_event_new_gap (stream->segment.position, GST_SECOND);
5738 gst_pad_push_event (stream->pad, gap);
5739 stream->segment.position += GST_SECOND;
5744 stream = qtdemux->streams[index];
5745 /* fetch info for the current sample of this stream */
5746 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5747 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5750 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
5751 if (stream->new_caps) {
5752 gst_qtdemux_configure_stream (qtdemux, stream);
5753 qtdemux_do_allocation (qtdemux, stream);
5756 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5757 if (G_UNLIKELY (qtdemux->
5758 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5759 if (stream->subtype == FOURCC_vide && !keyframe) {
5760 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5765 GST_DEBUG_OBJECT (qtdemux,
5766 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5767 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5768 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5769 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5771 if (G_UNLIKELY (empty)) {
5772 /* empty segment, push a gap and move to the next one */
5773 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5774 stream->segment.position = pts + duration;
5778 /* hmm, empty sample, skip and move to next sample */
5779 if (G_UNLIKELY (sample_size <= 0))
5782 /* last pushed sample was out of boundary, goto next sample */
5783 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5786 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5789 GST_DEBUG_OBJECT (qtdemux,
5790 "size %d larger than stream max_buffer_size %d, trimming",
5791 sample_size, stream->max_buffer_size);
5793 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5796 if (qtdemux->cenc_aux_info_offset > 0) {
5799 GstBuffer *aux_info = NULL;
5801 /* pull the data stored before the sample */
5803 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5804 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5805 if (G_UNLIKELY (ret != GST_FLOW_OK))
5807 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5808 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5809 gst_byte_reader_init (&br, map.data + 8, map.size);
5810 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5811 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5812 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5813 gst_buffer_unmap (aux_info, &map);
5814 gst_buffer_unref (aux_info);
5815 ret = GST_FLOW_ERROR;
5818 gst_buffer_unmap (aux_info, &map);
5819 gst_buffer_unref (aux_info);
5822 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5825 if (stream->use_allocator) {
5826 /* if we have a per-stream allocator, use it */
5827 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5830 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5832 if (G_UNLIKELY (ret != GST_FLOW_OK))
5835 if (size != sample_size) {
5836 pts += gst_util_uint64_scale_int (GST_SECOND,
5837 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5840 gst_util_uint64_scale_int (GST_SECOND,
5841 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5844 gst_util_uint64_scale_int (GST_SECOND,
5845 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
5848 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5849 dts, pts, duration, keyframe, min_time, offset);
5851 if (size != sample_size) {
5852 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5853 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5855 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5857 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
5858 if (time_position >= segment->media_start) {
5859 /* inside the segment, update time_position, looks very familiar to
5860 * GStreamer segments, doesn't it? */
5861 stream->time_position = (time_position - segment->media_start) +
5864 /* not yet in segment, time does not yet increment. This means
5865 * that we are still prerolling keyframes to the decoder so it can
5866 * decode the first sample of the segment. */
5867 stream->time_position = segment->time;
5872 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5873 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5874 * we have no more data for the pad to push */
5875 if (ret == GST_FLOW_EOS)
5878 stream->offset_in_sample += size;
5879 if (stream->offset_in_sample >= sample_size) {
5880 gst_qtdemux_advance_sample (qtdemux, stream);
5885 gst_qtdemux_advance_sample (qtdemux, stream);
5893 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5899 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5900 /* EOS will be raised if all are EOS */
5907 gst_qtdemux_loop (GstPad * pad)
5909 GstQTDemux *qtdemux;
5913 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5915 cur_offset = qtdemux->offset;
5916 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5917 cur_offset, qt_demux_state_string (qtdemux->state));
5919 switch (qtdemux->state) {
5920 case QTDEMUX_STATE_INITIAL:
5921 case QTDEMUX_STATE_HEADER:
5922 ret = gst_qtdemux_loop_state_header (qtdemux);
5924 case QTDEMUX_STATE_MOVIE:
5925 ret = gst_qtdemux_loop_state_movie (qtdemux);
5926 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5927 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5935 /* if something went wrong, pause */
5936 if (ret != GST_FLOW_OK)
5940 gst_object_unref (qtdemux);
5946 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5947 (NULL), ("streaming stopped, invalid state"));
5948 gst_pad_pause_task (pad);
5949 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5954 const gchar *reason = gst_flow_get_name (ret);
5956 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5958 gst_pad_pause_task (pad);
5960 /* fatal errors need special actions */
5962 if (ret == GST_FLOW_EOS) {
5963 if (qtdemux->n_streams == 0) {
5964 /* we have no streams, post an error */
5965 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5967 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5970 if ((stop = qtdemux->segment.stop) == -1)
5971 stop = qtdemux->segment.duration;
5973 if (qtdemux->segment.rate >= 0) {
5974 GstMessage *message;
5977 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5978 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5979 GST_FORMAT_TIME, stop);
5980 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5981 if (qtdemux->segment_seqnum) {
5982 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5983 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5985 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5986 gst_qtdemux_push_event (qtdemux, event);
5988 GstMessage *message;
5991 /* For Reverse Playback */
5992 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5993 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5994 GST_FORMAT_TIME, qtdemux->segment.start);
5995 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5996 qtdemux->segment.start);
5997 if (qtdemux->segment_seqnum) {
5998 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5999 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6001 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6002 gst_qtdemux_push_event (qtdemux, event);
6007 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6008 event = gst_event_new_eos ();
6009 if (qtdemux->segment_seqnum)
6010 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6011 gst_qtdemux_push_event (qtdemux, event);
6013 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6014 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6015 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6024 * Returns if there are samples to be played.
6027 has_next_entry (GstQTDemux * demux)
6029 QtDemuxStream *stream;
6032 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6034 for (i = 0; i < demux->n_streams; i++) {
6035 stream = demux->streams[i];
6037 if (stream->sample_index == -1) {
6038 stream->sample_index = 0;
6039 stream->offset_in_sample = 0;
6042 if (stream->sample_index >= stream->n_samples) {
6043 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6046 GST_DEBUG_OBJECT (demux, "Found a sample");
6050 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6057 * Returns the size of the first entry at the current offset.
6058 * If -1, there are none (which means EOS or empty file).
6061 next_entry_size (GstQTDemux * demux)
6063 QtDemuxStream *stream;
6066 guint64 smalloffs = (guint64) - 1;
6067 QtDemuxSample *sample;
6069 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6072 for (i = 0; i < demux->n_streams; i++) {
6073 stream = demux->streams[i];
6075 if (stream->sample_index == -1) {
6076 stream->sample_index = 0;
6077 stream->offset_in_sample = 0;
6080 if (stream->sample_index >= stream->n_samples) {
6081 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6085 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6086 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6087 stream->sample_index);
6091 sample = &stream->samples[stream->sample_index];
6093 GST_LOG_OBJECT (demux,
6094 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6095 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6096 sample->offset, sample->size);
6098 if (((smalloffs == -1)
6099 || (sample->offset < smalloffs)) && (sample->size)) {
6101 smalloffs = sample->offset;
6105 GST_LOG_OBJECT (demux,
6106 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6107 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6112 stream = demux->streams[smallidx];
6113 sample = &stream->samples[stream->sample_index];
6115 if (sample->offset >= demux->offset) {
6116 demux->todrop = sample->offset - demux->offset;
6117 return sample->size + demux->todrop;
6120 GST_DEBUG_OBJECT (demux,
6121 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6126 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6128 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6130 gst_element_post_message (GST_ELEMENT_CAST (demux),
6131 gst_message_new_element (GST_OBJECT_CAST (demux),
6132 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6136 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6141 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6144 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6145 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6146 GST_SEEK_TYPE_NONE, -1);
6148 /* store seqnum to drop flush events, they don't need to reach downstream */
6149 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6150 res = gst_pad_push_event (demux->sinkpad, event);
6151 demux->offset_seek_seqnum = 0;
6156 /* check for seekable upstream, above and beyond a mere query */
6158 gst_qtdemux_check_seekability (GstQTDemux * demux)
6161 gboolean seekable = FALSE;
6162 gint64 start = -1, stop = -1;
6164 if (demux->upstream_size)
6167 if (demux->upstream_format_is_time)
6170 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6171 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6172 GST_DEBUG_OBJECT (demux, "seeking query failed");
6176 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6178 /* try harder to query upstream size if we didn't get it the first time */
6179 if (seekable && stop == -1) {
6180 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6181 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6184 /* if upstream doesn't know the size, it's likely that it's not seekable in
6185 * practice even if it technically may be seekable */
6186 if (seekable && (start != 0 || stop <= start)) {
6187 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6192 gst_query_unref (query);
6194 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6195 G_GUINT64_FORMAT ")", seekable, start, stop);
6196 demux->upstream_seekable = seekable;
6197 demux->upstream_size = seekable ? stop : -1;
6201 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6203 g_return_if_fail (bytes <= demux->todrop);
6205 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6206 gst_adapter_flush (demux->adapter, bytes);
6207 demux->neededbytes -= bytes;
6208 demux->offset += bytes;
6209 demux->todrop -= bytes;
6213 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6215 if (G_UNLIKELY (demux->pending_newsegment)) {
6218 gst_qtdemux_push_pending_newsegment (demux);
6219 /* clear to send tags on all streams */
6220 for (i = 0; i < demux->n_streams; i++) {
6221 QtDemuxStream *stream;
6222 stream = demux->streams[i];
6223 gst_qtdemux_push_tags (demux, stream);
6224 if (CUR_STREAM (stream)->sparse) {
6225 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6226 gst_pad_push_event (stream->pad,
6227 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6234 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6235 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6237 GstClockTime ts, dur;
6242 stream->segments[segment_index].duration - (pos -
6243 stream->segments[segment_index].time);
6244 gap = gst_event_new_gap (ts, dur);
6245 stream->time_position += dur;
6247 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6248 "segment: %" GST_PTR_FORMAT, gap);
6249 gst_pad_push_event (stream->pad, gap);
6253 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6254 QtDemuxStream * stream)
6258 /* Push any initial gap segments before proceeding to the
6260 for (i = 0; i < stream->n_segments; i++) {
6261 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6263 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6264 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6265 stream->time_position);
6267 /* Only support empty segment at the beginning followed by
6268 * one non-empty segment, this was checked when parsing the
6269 * edts atom, arriving here is unexpected */
6270 g_assert (i + 1 == stream->n_segments);
6276 static GstFlowReturn
6277 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6281 demux = GST_QTDEMUX (parent);
6283 GST_DEBUG_OBJECT (demux,
6284 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6285 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6286 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6287 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6288 gst_buffer_get_size (inbuf), demux->offset);
6290 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6291 gboolean is_gap_input = FALSE;
6294 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6296 for (i = 0; i < demux->n_streams; i++) {
6297 demux->streams[i]->discont = TRUE;
6300 /* Check if we can land back on our feet in the case where upstream is
6301 * handling the seeking/pushing of samples with gaps in between (like
6302 * in the case of trick-mode DASH for example) */
6303 if (demux->upstream_format_is_time
6304 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6306 for (i = 0; i < demux->n_streams; i++) {
6308 GST_LOG_OBJECT (demux,
6309 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6310 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6312 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6313 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6315 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6316 GST_LOG_OBJECT (demux,
6317 "Checking if sample %d from stream %d is valid (offset:%"
6318 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6319 sample->offset, sample->size);
6320 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6321 GST_LOG_OBJECT (demux,
6322 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6324 is_gap_input = TRUE;
6325 /* We can go back to standard playback mode */
6326 demux->state = QTDEMUX_STATE_MOVIE;
6327 /* Remember which sample this stream is at */
6328 demux->streams[i]->sample_index = res;
6329 /* Finally update all push-based values to the expected values */
6330 demux->neededbytes = demux->streams[i]->samples[res].size;
6331 demux->offset = GST_BUFFER_OFFSET (inbuf);
6333 demux->mdatsize - demux->offset + demux->mdatoffset;
6338 if (!is_gap_input) {
6339 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6340 /* Reset state if it's a real discont */
6341 demux->neededbytes = 16;
6342 demux->state = QTDEMUX_STATE_INITIAL;
6343 demux->offset = GST_BUFFER_OFFSET (inbuf);
6344 gst_adapter_clear (demux->adapter);
6347 /* Reverse fragmented playback, need to flush all we have before
6348 * consuming a new fragment.
6349 * The samples array have the timestamps calculated by accumulating the
6350 * durations but this won't work for reverse playback of fragments as
6351 * the timestamps of a subsequent fragment should be smaller than the
6352 * previously received one. */
6353 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6354 gst_qtdemux_process_adapter (demux, TRUE);
6355 for (i = 0; i < demux->n_streams; i++)
6356 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6360 gst_adapter_push (demux->adapter, inbuf);
6362 GST_DEBUG_OBJECT (demux,
6363 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6364 demux->neededbytes, gst_adapter_available (demux->adapter));
6366 return gst_qtdemux_process_adapter (demux, FALSE);
6369 static GstFlowReturn
6370 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6372 GstFlowReturn ret = GST_FLOW_OK;
6374 /* we never really mean to buffer that much */
6375 if (demux->neededbytes == -1) {
6379 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6380 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6382 #ifndef GST_DISABLE_GST_DEBUG
6384 guint64 discont_offset, distance_from_discont;
6386 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6387 distance_from_discont =
6388 gst_adapter_distance_from_discont (demux->adapter);
6390 GST_DEBUG_OBJECT (demux,
6391 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6392 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6393 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6394 demux->offset, discont_offset, distance_from_discont);
6398 switch (demux->state) {
6399 case QTDEMUX_STATE_INITIAL:{
6404 gst_qtdemux_check_seekability (demux);
6406 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6408 /* get fourcc/length, set neededbytes */
6409 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6411 gst_adapter_unmap (demux->adapter);
6413 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6414 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6416 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6417 (_("This file is invalid and cannot be played.")),
6418 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6419 GST_FOURCC_ARGS (fourcc)));
6420 ret = GST_FLOW_ERROR;
6423 if (fourcc == FOURCC_mdat) {
6424 gint next_entry = next_entry_size (demux);
6425 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6426 /* we have the headers, start playback */
6427 demux->state = QTDEMUX_STATE_MOVIE;
6428 demux->neededbytes = next_entry;
6429 demux->mdatleft = size;
6430 demux->mdatsize = demux->mdatleft;
6432 /* no headers yet, try to get them */
6435 guint64 old, target;
6438 old = demux->offset;
6439 target = old + size;
6441 /* try to jump over the atom with a seek */
6442 /* only bother if it seems worth doing so,
6443 * and avoids possible upstream/server problems */
6444 if (demux->upstream_seekable &&
6445 demux->upstream_size > 4 * (1 << 20)) {
6446 res = qtdemux_seek_offset (demux, target);
6448 GST_DEBUG_OBJECT (demux, "skipping seek");
6453 GST_DEBUG_OBJECT (demux, "seek success");
6454 /* remember the offset fo the first mdat so we can seek back to it
6455 * after we have the headers */
6456 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6457 demux->first_mdat = old;
6458 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6461 /* seek worked, continue reading */
6462 demux->offset = target;
6463 demux->neededbytes = 16;
6464 demux->state = QTDEMUX_STATE_INITIAL;
6466 /* seek failed, need to buffer */
6467 demux->offset = old;
6468 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6469 /* there may be multiple mdat (or alike) buffers */
6471 if (demux->mdatbuffer)
6472 bs = gst_buffer_get_size (demux->mdatbuffer);
6475 if (size + bs > 10 * (1 << 20))
6477 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6478 demux->neededbytes = size;
6479 if (!demux->mdatbuffer)
6480 demux->mdatoffset = demux->offset;
6483 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6484 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6485 (_("This file is invalid and cannot be played.")),
6486 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6487 GST_FOURCC_ARGS (fourcc), size));
6488 ret = GST_FLOW_ERROR;
6491 /* this means we already started buffering and still no moov header,
6492 * let's continue buffering everything till we get moov */
6493 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6494 || fourcc == FOURCC_moof))
6496 demux->neededbytes = size;
6497 demux->state = QTDEMUX_STATE_HEADER;
6501 case QTDEMUX_STATE_HEADER:{
6505 GST_DEBUG_OBJECT (demux, "In header");
6507 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6509 /* parse the header */
6510 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6512 if (fourcc == FOURCC_moov) {
6515 /* in usual fragmented setup we could try to scan for more
6516 * and end up at the the moov (after mdat) again */
6517 if (demux->got_moov && demux->n_streams > 0 &&
6519 || demux->last_moov_offset == demux->offset)) {
6520 GST_DEBUG_OBJECT (demux,
6521 "Skipping moov atom as we have (this) one already");
6523 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6525 if (demux->got_moov && demux->fragmented) {
6526 GST_DEBUG_OBJECT (demux,
6527 "Got a second moov, clean up data from old one");
6528 if (demux->moov_node_compressed) {
6529 g_node_destroy (demux->moov_node_compressed);
6530 if (demux->moov_node)
6531 g_free (demux->moov_node->data);
6533 demux->moov_node_compressed = NULL;
6534 if (demux->moov_node)
6535 g_node_destroy (demux->moov_node);
6536 demux->moov_node = NULL;
6538 /* prepare newsegment to send when streaming actually starts */
6539 if (!demux->pending_newsegment) {
6540 demux->pending_newsegment =
6541 gst_event_new_segment (&demux->segment);
6542 if (demux->segment_seqnum)
6543 gst_event_set_seqnum (demux->pending_newsegment,
6544 demux->segment_seqnum);
6548 demux->last_moov_offset = demux->offset;
6550 qtdemux_parse_moov (demux, data, demux->neededbytes);
6551 qtdemux_node_dump (demux, demux->moov_node);
6552 qtdemux_parse_tree (demux);
6553 qtdemux_prepare_streams (demux);
6554 if (!demux->got_moov)
6555 qtdemux_expose_streams (demux);
6558 for (n = 0; n < demux->n_streams; n++) {
6559 QtDemuxStream *stream = demux->streams[n];
6561 gst_qtdemux_configure_stream (demux, stream);
6565 demux->got_moov = TRUE;
6566 gst_qtdemux_check_send_pending_segment (demux);
6568 /* fragmented streams headers shouldn't contain edts atoms */
6569 if (!demux->fragmented) {
6570 for (n = 0; n < demux->n_streams; n++) {
6571 gst_qtdemux_stream_send_initial_gap_segments (demux,
6576 if (demux->moov_node_compressed) {
6577 g_node_destroy (demux->moov_node_compressed);
6578 g_free (demux->moov_node->data);
6580 demux->moov_node_compressed = NULL;
6581 g_node_destroy (demux->moov_node);
6582 demux->moov_node = NULL;
6583 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6585 } else if (fourcc == FOURCC_moof) {
6586 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6588 GstClockTime prev_pts;
6589 guint64 prev_offset;
6590 guint64 adapter_discont_offset, adapter_discont_dist;
6592 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6595 * The timestamp of the moof buffer is relevant as some scenarios
6596 * won't have the initial timestamp in the atoms. Whenever a new
6597 * buffer has started, we get that buffer's PTS and use it as a base
6598 * timestamp for the trun entries.
6600 * To keep track of the current buffer timestamp and starting point
6601 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6602 * from the beggining of the buffer, with the distance and demux->offset
6603 * we know if it is still the same buffer or not.
6605 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6606 prev_offset = demux->offset - dist;
6607 if (demux->fragment_start_offset == -1
6608 || prev_offset > demux->fragment_start_offset) {
6609 demux->fragment_start_offset = prev_offset;
6610 demux->fragment_start = prev_pts;
6611 GST_DEBUG_OBJECT (demux,
6612 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6613 GST_TIME_FORMAT, demux->fragment_start_offset,
6614 GST_TIME_ARGS (demux->fragment_start));
6617 /* We can't use prev_offset() here because this would require
6618 * upstream to set consistent and correct offsets on all buffers
6619 * since the discont. Nothing ever did that in the past and we
6620 * would break backwards compatibility here then.
6621 * Instead take the offset we had at the last discont and count
6622 * the bytes from there. This works with old code as there would
6623 * be no discont between moov and moof, and also works with
6624 * adaptivedemux which correctly sets offset and will set the
6625 * DISCONT flag accordingly when needed.
6627 * We also only do this for upstream TIME segments as otherwise
6628 * there are potential backwards compatibility problems with
6629 * seeking in PUSH mode and upstream providing inconsistent
6631 adapter_discont_offset =
6632 gst_adapter_offset_at_discont (demux->adapter);
6633 adapter_discont_dist =
6634 gst_adapter_distance_from_discont (demux->adapter);
6636 GST_DEBUG_OBJECT (demux,
6637 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6638 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6639 demux->offset, adapter_discont_offset, adapter_discont_dist);
6641 if (demux->upstream_format_is_time) {
6642 demux->moof_offset = adapter_discont_offset;
6643 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6644 demux->moof_offset += adapter_discont_dist;
6645 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6646 demux->moof_offset = demux->offset;
6648 demux->moof_offset = demux->offset;
6651 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6652 demux->moof_offset, NULL)) {
6653 gst_adapter_unmap (demux->adapter);
6654 ret = GST_FLOW_ERROR;
6657 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6658 if (demux->mss_mode && !demux->exposed) {
6659 if (!demux->pending_newsegment) {
6660 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6661 demux->pending_newsegment =
6662 gst_event_new_segment (&demux->segment);
6663 if (demux->segment_seqnum)
6664 gst_event_set_seqnum (demux->pending_newsegment,
6665 demux->segment_seqnum);
6667 qtdemux_expose_streams (demux);
6670 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6672 } else if (fourcc == FOURCC_ftyp) {
6673 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6674 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6675 } else if (fourcc == FOURCC_uuid) {
6676 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6677 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6678 } else if (fourcc == FOURCC_sidx) {
6679 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6680 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6684 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6687 /* [free] is a padding atom */
6688 GST_DEBUG_OBJECT (demux,
6689 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6690 GST_FOURCC_ARGS (fourcc));
6693 GST_WARNING_OBJECT (demux,
6694 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6695 GST_FOURCC_ARGS (fourcc));
6696 /* Let's jump that one and go back to initial state */
6700 gst_adapter_unmap (demux->adapter);
6703 if (demux->mdatbuffer && demux->n_streams) {
6704 gsize remaining_data_size = 0;
6706 /* the mdat was before the header */
6707 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6708 demux->n_streams, demux->mdatbuffer);
6709 /* restore our adapter/offset view of things with upstream;
6710 * put preceding buffered data ahead of current moov data.
6711 * This should also handle evil mdat, moov, mdat cases and alike */
6712 gst_adapter_flush (demux->adapter, demux->neededbytes);
6714 /* Store any remaining data after the mdat for later usage */
6715 remaining_data_size = gst_adapter_available (demux->adapter);
6716 if (remaining_data_size > 0) {
6717 g_assert (demux->restoredata_buffer == NULL);
6718 demux->restoredata_buffer =
6719 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6720 demux->restoredata_offset = demux->offset + demux->neededbytes;
6721 GST_DEBUG_OBJECT (demux,
6722 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6723 G_GUINT64_FORMAT, remaining_data_size,
6724 demux->restoredata_offset);
6727 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6728 demux->mdatbuffer = NULL;
6729 demux->offset = demux->mdatoffset;
6730 demux->neededbytes = next_entry_size (demux);
6731 demux->state = QTDEMUX_STATE_MOVIE;
6732 demux->mdatleft = gst_adapter_available (demux->adapter);
6733 demux->mdatsize = demux->mdatleft;
6735 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6736 gst_adapter_flush (demux->adapter, demux->neededbytes);
6738 /* only go back to the mdat if there are samples to play */
6739 if (demux->got_moov && demux->first_mdat != -1
6740 && has_next_entry (demux)) {
6743 /* we need to seek back */
6744 res = qtdemux_seek_offset (demux, demux->first_mdat);
6746 demux->offset = demux->first_mdat;
6748 GST_DEBUG_OBJECT (demux, "Seek back failed");
6751 demux->offset += demux->neededbytes;
6753 demux->neededbytes = 16;
6754 demux->state = QTDEMUX_STATE_INITIAL;
6759 case QTDEMUX_STATE_BUFFER_MDAT:{
6763 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6765 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6766 gst_buffer_extract (buf, 0, fourcc, 4);
6767 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6768 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6769 if (demux->mdatbuffer)
6770 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6772 demux->mdatbuffer = buf;
6773 demux->offset += demux->neededbytes;
6774 demux->neededbytes = 16;
6775 demux->state = QTDEMUX_STATE_INITIAL;
6776 gst_qtdemux_post_progress (demux, 1, 1);
6780 case QTDEMUX_STATE_MOVIE:{
6781 QtDemuxStream *stream = NULL;
6782 QtDemuxSample *sample;
6784 GstClockTime dts, pts, duration;
6787 GST_DEBUG_OBJECT (demux,
6788 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6790 if (demux->fragmented) {
6791 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6793 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6794 /* if needed data starts within this atom,
6795 * then it should not exceed this atom */
6796 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6797 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6798 (_("This file is invalid and cannot be played.")),
6799 ("sample data crosses atom boundary"));
6800 ret = GST_FLOW_ERROR;
6803 demux->mdatleft -= demux->neededbytes;
6805 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6806 /* so we are dropping more than left in this atom */
6807 gst_qtdemux_drop_data (demux, demux->mdatleft);
6808 demux->mdatleft = 0;
6810 /* need to resume atom parsing so we do not miss any other pieces */
6811 demux->state = QTDEMUX_STATE_INITIAL;
6812 demux->neededbytes = 16;
6814 /* check if there was any stored post mdat data from previous buffers */
6815 if (demux->restoredata_buffer) {
6816 g_assert (gst_adapter_available (demux->adapter) == 0);
6818 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6819 demux->restoredata_buffer = NULL;
6820 demux->offset = demux->restoredata_offset;
6827 if (demux->todrop) {
6828 if (demux->cenc_aux_info_offset > 0) {
6832 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6833 data = gst_adapter_map (demux->adapter, demux->todrop);
6834 gst_byte_reader_init (&br, data + 8, demux->todrop);
6835 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6836 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6837 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6838 ret = GST_FLOW_ERROR;
6839 gst_adapter_unmap (demux->adapter);
6840 g_free (demux->cenc_aux_info_sizes);
6841 demux->cenc_aux_info_sizes = NULL;
6844 demux->cenc_aux_info_offset = 0;
6845 g_free (demux->cenc_aux_info_sizes);
6846 demux->cenc_aux_info_sizes = NULL;
6847 gst_adapter_unmap (demux->adapter);
6849 gst_qtdemux_drop_data (demux, demux->todrop);
6853 /* initial newsegment sent here after having added pads,
6854 * possible others in sink_event */
6855 gst_qtdemux_check_send_pending_segment (demux);
6857 /* Figure out which stream this packet belongs to */
6858 for (i = 0; i < demux->n_streams; i++) {
6859 stream = demux->streams[i];
6860 if (stream->sample_index >= stream->n_samples)
6862 GST_LOG_OBJECT (demux,
6863 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6864 " / size:%d)", i, stream->sample_index,
6865 stream->samples[stream->sample_index].offset,
6866 stream->samples[stream->sample_index].size);
6868 if (stream->samples[stream->sample_index].offset == demux->offset)
6872 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6873 goto unknown_stream;
6875 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
6877 if (stream->new_caps) {
6878 gst_qtdemux_configure_stream (demux, stream);
6881 /* Put data in a buffer, set timestamps, caps, ... */
6882 sample = &stream->samples[stream->sample_index];
6884 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6885 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6886 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
6888 dts = QTSAMPLE_DTS (stream, sample);
6889 pts = QTSAMPLE_PTS (stream, sample);
6890 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6891 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6893 /* check for segment end */
6894 if (G_UNLIKELY (demux->segment.stop != -1
6895 && demux->segment.stop <= pts && stream->on_keyframe)) {
6896 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6897 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6899 /* skip this data, stream is EOS */
6900 gst_adapter_flush (demux->adapter, demux->neededbytes);
6901 demux->offset += demux->neededbytes;
6903 /* check if all streams are eos */
6905 for (i = 0; i < demux->n_streams; i++) {
6906 if (!STREAM_IS_EOS (demux->streams[i])) {
6915 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6917 /* FIXME: should either be an assert or a plain check */
6918 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6920 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6921 dts, pts, duration, keyframe, dts, demux->offset);
6925 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6927 /* skip this data, stream is EOS */
6928 gst_adapter_flush (demux->adapter, demux->neededbytes);
6931 stream->sample_index++;
6932 stream->offset_in_sample = 0;
6934 /* update current offset and figure out size of next buffer */
6935 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6936 demux->offset, demux->neededbytes);
6937 demux->offset += demux->neededbytes;
6938 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6942 if (ret == GST_FLOW_EOS) {
6943 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6944 demux->neededbytes = -1;
6948 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6949 if (demux->fragmented) {
6950 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6951 /* there may be more to follow, only finish this atom */
6952 demux->todrop = demux->mdatleft;
6953 demux->neededbytes = demux->todrop;
6958 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
6959 goto non_ok_unlinked_flow;
6968 /* when buffering movie data, at least show user something is happening */
6969 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6970 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6971 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6972 demux->neededbytes);
6979 non_ok_unlinked_flow:
6981 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6982 gst_flow_get_name (ret));
6987 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6988 ret = GST_FLOW_ERROR;
6993 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6999 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7000 (NULL), ("qtdemuxer invalid state %d", demux->state));
7001 ret = GST_FLOW_ERROR;
7006 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7007 (NULL), ("no 'moov' atom within the first 10 MB"));
7008 ret = GST_FLOW_ERROR;
7014 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7019 query = gst_query_new_scheduling ();
7021 if (!gst_pad_peer_query (sinkpad, query)) {
7022 gst_query_unref (query);
7026 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7027 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7028 gst_query_unref (query);
7033 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7034 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7038 GST_DEBUG_OBJECT (sinkpad, "activating push");
7039 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7044 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7045 GstPadMode mode, gboolean active)
7048 GstQTDemux *demux = GST_QTDEMUX (parent);
7051 case GST_PAD_MODE_PUSH:
7052 demux->pullbased = FALSE;
7055 case GST_PAD_MODE_PULL:
7057 demux->pullbased = TRUE;
7058 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7061 res = gst_pad_stop_task (sinkpad);
7073 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7079 memset (&z, 0, sizeof (z));
7084 if ((ret = inflateInit (&z)) != Z_OK) {
7085 GST_ERROR ("inflateInit() returned %d", ret);
7089 z.next_in = z_buffer;
7090 z.avail_in = z_length;
7092 buffer = (guint8 *) g_malloc (*length);
7093 z.avail_out = *length;
7094 z.next_out = (Bytef *) buffer;
7096 ret = inflate (&z, Z_NO_FLUSH);
7097 if (ret == Z_STREAM_END) {
7099 } else if (ret != Z_OK) {
7100 GST_WARNING ("inflate() returned %d", ret);
7105 buffer = (guint8 *) g_realloc (buffer, *length);
7106 z.next_out = (Bytef *) (buffer + z.total_out);
7107 z.avail_out += 4096;
7108 } while (z.avail_in > 0);
7110 if (ret != Z_STREAM_END) {
7115 *length = z.total_out;
7122 #endif /* HAVE_ZLIB */
7125 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7129 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7131 /* counts as header data */
7132 qtdemux->header_size += length;
7134 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7135 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7137 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7144 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7145 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7146 if (dcom == NULL || cmvd == NULL)
7147 goto invalid_compression;
7149 dcom_len = QT_UINT32 (dcom->data);
7151 goto invalid_compression;
7153 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7157 guint uncompressed_length;
7158 guint compressed_length;
7162 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7164 goto invalid_compression;
7166 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7167 compressed_length = cmvd_len - 12;
7168 GST_LOG ("length = %u", uncompressed_length);
7171 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7172 compressed_length, &uncompressed_length);
7175 qtdemux->moov_node_compressed = qtdemux->moov_node;
7176 qtdemux->moov_node = g_node_new (buf);
7178 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7179 uncompressed_length);
7183 #endif /* HAVE_ZLIB */
7185 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7186 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7193 invalid_compression:
7195 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7201 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7204 while (G_UNLIKELY (buf < end)) {
7208 if (G_UNLIKELY (buf + 4 > end)) {
7209 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7212 len = QT_UINT32 (buf);
7213 if (G_UNLIKELY (len == 0)) {
7214 GST_LOG_OBJECT (qtdemux, "empty container");
7217 if (G_UNLIKELY (len < 8)) {
7218 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7221 if (G_UNLIKELY (len > (end - buf))) {
7222 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7223 (gint) (end - buf));
7227 child = g_node_new ((guint8 *) buf);
7228 g_node_append (node, child);
7229 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7230 qtdemux_parse_node (qtdemux, child, buf, len);
7238 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7241 int len = QT_UINT32 (xdxt->data);
7242 guint8 *buf = xdxt->data;
7243 guint8 *end = buf + len;
7246 /* skip size and type */
7254 size = QT_UINT32 (buf);
7255 type = QT_FOURCC (buf + 4);
7257 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7259 if (buf + size > end || size <= 0)
7265 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7266 GST_FOURCC_ARGS (type));
7270 buffer = gst_buffer_new_and_alloc (size);
7271 gst_buffer_fill (buffer, 0, buf, size);
7272 stream->buffers = g_slist_append (stream->buffers, buffer);
7273 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7276 buffer = gst_buffer_new_and_alloc (size);
7277 gst_buffer_fill (buffer, 0, buf, size);
7278 stream->buffers = g_slist_append (stream->buffers, buffer);
7279 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7282 buffer = gst_buffer_new_and_alloc (size);
7283 gst_buffer_fill (buffer, 0, buf, size);
7284 stream->buffers = g_slist_append (stream->buffers, buffer);
7285 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7288 GST_WARNING_OBJECT (qtdemux,
7289 "unknown theora cookie %" GST_FOURCC_FORMAT,
7290 GST_FOURCC_ARGS (type));
7299 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7303 guint32 node_length = 0;
7304 const QtNodeType *type;
7307 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7309 if (G_UNLIKELY (length < 8))
7310 goto not_enough_data;
7312 node_length = QT_UINT32 (buffer);
7313 fourcc = QT_FOURCC (buffer + 4);
7315 /* ignore empty nodes */
7316 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7319 type = qtdemux_type_get (fourcc);
7321 end = buffer + length;
7323 GST_LOG_OBJECT (qtdemux,
7324 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7325 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7327 if (node_length > length)
7328 goto broken_atom_size;
7330 if (type->flags & QT_FLAG_CONTAINER) {
7331 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7336 if (node_length < 20) {
7337 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7340 GST_DEBUG_OBJECT (qtdemux,
7341 "parsing stsd (sample table, sample description) atom");
7342 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7343 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7354 /* also read alac (or whatever) in stead of mp4a in the following,
7355 * since a similar layout is used in other cases as well */
7356 if (fourcc == FOURCC_mp4a)
7358 else if (fourcc == FOURCC_fLaC)
7363 /* There are two things we might encounter here: a true mp4a atom, and
7364 an mp4a entry in an stsd atom. The latter is what we're interested
7365 in, and it looks like an atom, but isn't really one. The true mp4a
7366 atom is short, so we detect it based on length here. */
7367 if (length < min_size) {
7368 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7369 GST_FOURCC_ARGS (fourcc));
7373 /* 'version' here is the sound sample description version. Types 0 and
7374 1 are documented in the QTFF reference, but type 2 is not: it's
7375 described in Apple header files instead (struct SoundDescriptionV2
7377 version = QT_UINT16 (buffer + 16);
7379 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7380 GST_FOURCC_ARGS (fourcc), version);
7382 /* parse any esds descriptors */
7394 GST_WARNING_OBJECT (qtdemux,
7395 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7396 GST_FOURCC_ARGS (fourcc), version);
7401 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7427 /* codec_data is contained inside these atoms, which all have
7428 * the same format. */
7429 /* video sample description size is 86 bytes without extension.
7430 * node_length have to be bigger than 86 bytes because video sample
7431 * description can include extenstions such as esds, fiel, glbl, etc. */
7432 if (node_length < 86) {
7433 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7434 " sample description length too short (%u < 86)",
7435 GST_FOURCC_ARGS (fourcc), node_length);
7439 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7440 GST_FOURCC_ARGS (fourcc));
7442 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7444 * revision level (2 bytes) : must be set to 0. */
7445 version = QT_UINT32 (buffer + 16);
7446 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7448 /* compressor name : PASCAL string and informative purposes
7449 * first byte : the number of bytes to be displayed.
7450 * it has to be less than 32 because it is reserved
7451 * space of 32 bytes total including itself. */
7452 str_len = QT_UINT8 (buffer + 50);
7454 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7455 (char *) buffer + 51);
7457 GST_WARNING_OBJECT (qtdemux,
7458 "compressorname length too big (%u > 31)", str_len);
7460 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7462 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7467 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7468 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7473 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7474 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7475 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7484 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7485 GST_FOURCC_ARGS (fourcc));
7489 version = QT_UINT32 (buffer + 12);
7490 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7497 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7502 if (length < offset) {
7503 GST_WARNING_OBJECT (qtdemux,
7504 "skipping too small %" GST_FOURCC_FORMAT " box",
7505 GST_FOURCC_ARGS (fourcc));
7508 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7514 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7519 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7524 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7528 if (!strcmp (type->name, "unknown"))
7529 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7533 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7534 GST_FOURCC_ARGS (fourcc));
7540 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7541 (_("This file is corrupt and cannot be played.")),
7542 ("Not enough data for an atom header, got only %u bytes", length));
7547 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7548 (_("This file is corrupt and cannot be played.")),
7549 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7550 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7557 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7561 guint32 child_fourcc;
7563 for (child = g_node_first_child (node); child;
7564 child = g_node_next_sibling (child)) {
7565 buffer = (guint8 *) child->data;
7567 child_fourcc = QT_FOURCC (buffer + 4);
7569 if (G_UNLIKELY (child_fourcc == fourcc)) {
7577 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7578 GstByteReader * parser)
7582 guint32 child_fourcc, child_len;
7584 for (child = g_node_first_child (node); child;
7585 child = g_node_next_sibling (child)) {
7586 buffer = (guint8 *) child->data;
7588 child_len = QT_UINT32 (buffer);
7589 child_fourcc = QT_FOURCC (buffer + 4);
7591 if (G_UNLIKELY (child_fourcc == fourcc)) {
7592 if (G_UNLIKELY (child_len < (4 + 4)))
7594 /* FIXME: must verify if atom length < parent atom length */
7595 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7603 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7605 return g_node_nth_child (node, index);
7609 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7610 GstByteReader * parser)
7614 guint32 child_fourcc, child_len;
7616 for (child = g_node_next_sibling (node); child;
7617 child = g_node_next_sibling (child)) {
7618 buffer = (guint8 *) child->data;
7620 child_fourcc = QT_FOURCC (buffer + 4);
7622 if (child_fourcc == fourcc) {
7624 child_len = QT_UINT32 (buffer);
7625 if (G_UNLIKELY (child_len < (4 + 4)))
7627 /* FIXME: must verify if atom length < parent atom length */
7628 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7637 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7639 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7643 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7645 /* FIXME: This can only reliably work if demuxers have a
7646 * separate streaming thread per srcpad. This should be
7647 * done in a demuxer base class, which integrates parts
7650 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7655 query = gst_query_new_allocation (stream->caps, FALSE);
7657 if (!gst_pad_peer_query (stream->pad, query)) {
7658 /* not a problem, just debug a little */
7659 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7662 if (stream->allocator)
7663 gst_object_unref (stream->allocator);
7665 if (gst_query_get_n_allocation_params (query) > 0) {
7666 /* try the allocator */
7667 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7669 stream->use_allocator = TRUE;
7671 stream->allocator = NULL;
7672 gst_allocation_params_init (&stream->params);
7673 stream->use_allocator = FALSE;
7675 gst_query_unref (query);
7680 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7681 QtDemuxStream * stream)
7684 const gchar *selected_system;
7686 g_return_val_if_fail (qtdemux != NULL, FALSE);
7687 g_return_val_if_fail (stream != NULL, FALSE);
7688 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
7691 if (stream->protection_scheme_type != FOURCC_cenc) {
7692 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7695 if (qtdemux->protection_system_ids == NULL) {
7696 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7697 "cenc protection system information has been found");
7700 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7701 selected_system = gst_protection_select_system ((const gchar **)
7702 qtdemux->protection_system_ids->pdata);
7703 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7704 qtdemux->protection_system_ids->len - 1);
7705 if (!selected_system) {
7706 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7707 "suitable decryptor element has been found");
7711 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
7712 if (!gst_structure_has_name (s, "application/x-cenc")) {
7713 gst_structure_set (s,
7714 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7715 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7717 gst_structure_set_name (s, "application/x-cenc");
7723 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7725 if (stream->subtype == FOURCC_vide) {
7726 /* fps is calculated base on the duration of the average framerate since
7727 * qt does not have a fixed framerate. */
7728 gboolean fps_available = TRUE;
7730 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7732 CUR_STREAM (stream)->fps_n = 0;
7733 CUR_STREAM (stream)->fps_d = 1;
7735 if (stream->duration == 0 || stream->n_samples < 2) {
7736 CUR_STREAM (stream)->fps_n = stream->timescale;
7737 CUR_STREAM (stream)->fps_d = 1;
7738 fps_available = FALSE;
7740 GstClockTime avg_duration;
7744 /* duration and n_samples can be updated for fragmented format
7745 * so, framerate of fragmented format is calculated using data in a moof */
7746 if (qtdemux->fragmented && stream->n_samples_moof > 0
7747 && stream->duration_moof > 0) {
7748 n_samples = stream->n_samples_moof;
7749 duration = stream->duration_moof;
7751 n_samples = stream->n_samples;
7752 duration = stream->duration;
7755 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7756 /* stream->duration is guint64, timescale, n_samples are guint32 */
7758 gst_util_uint64_scale_round (duration -
7759 stream->first_duration, GST_SECOND,
7760 (guint64) (stream->timescale) * (n_samples - 1));
7762 GST_LOG_OBJECT (qtdemux,
7763 "Calculating avg sample duration based on stream (or moof) duration %"
7765 " minus first sample %u, leaving %d samples gives %"
7766 GST_TIME_FORMAT, duration, stream->first_duration,
7767 n_samples - 1, GST_TIME_ARGS (avg_duration));
7769 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
7770 &CUR_STREAM (stream)->fps_d);
7772 GST_DEBUG_OBJECT (qtdemux,
7773 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7774 stream->timescale, CUR_STREAM (stream)->fps_n,
7775 CUR_STREAM (stream)->fps_d);
7779 if (CUR_STREAM (stream)->caps) {
7780 CUR_STREAM (stream)->caps =
7781 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7783 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7784 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
7785 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
7787 /* set framerate if calculated framerate is reliable */
7788 if (fps_available) {
7789 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7790 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
7791 CUR_STREAM (stream)->fps_d, NULL);
7794 /* calculate pixel-aspect-ratio using display width and height */
7795 GST_DEBUG_OBJECT (qtdemux,
7796 "video size %dx%d, target display size %dx%d",
7797 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
7798 stream->display_width, stream->display_height);
7799 /* qt file might have pasp atom */
7800 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7801 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
7802 CUR_STREAM (stream)->par_h);
7803 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7804 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7805 CUR_STREAM (stream)->par_h, NULL);
7806 } else if (stream->display_width > 0 && stream->display_height > 0
7807 && CUR_STREAM (stream)->width > 0
7808 && CUR_STREAM (stream)->height > 0) {
7811 /* calculate the pixel aspect ratio using the display and pixel w/h */
7812 n = stream->display_width * CUR_STREAM (stream)->height;
7813 d = stream->display_height * CUR_STREAM (stream)->width;
7816 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7817 CUR_STREAM (stream)->par_w = n;
7818 CUR_STREAM (stream)->par_h = d;
7819 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7820 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7821 CUR_STREAM (stream)->par_h, NULL);
7824 if (CUR_STREAM (stream)->interlace_mode > 0) {
7825 if (CUR_STREAM (stream)->interlace_mode == 1) {
7826 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7827 G_TYPE_STRING, "progressive", NULL);
7828 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
7829 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7830 G_TYPE_STRING, "interleaved", NULL);
7831 if (CUR_STREAM (stream)->field_order == 9) {
7832 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7833 G_TYPE_STRING, "top-field-first", NULL);
7834 } else if (CUR_STREAM (stream)->field_order == 14) {
7835 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7836 G_TYPE_STRING, "bottom-field-first", NULL);
7841 /* Create incomplete colorimetry here if needed */
7842 if (CUR_STREAM (stream)->colorimetry.range ||
7843 CUR_STREAM (stream)->colorimetry.matrix ||
7844 CUR_STREAM (stream)->colorimetry.transfer
7845 || CUR_STREAM (stream)->colorimetry.primaries) {
7846 gchar *colorimetry =
7847 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
7848 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
7849 G_TYPE_STRING, colorimetry, NULL);
7850 g_free (colorimetry);
7853 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7854 guint par_w = 1, par_h = 1;
7856 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7857 par_w = CUR_STREAM (stream)->par_w;
7858 par_h = CUR_STREAM (stream)->par_h;
7861 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7862 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
7864 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7867 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7868 "multiview-mode", G_TYPE_STRING,
7869 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7870 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7871 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7876 else if (stream->subtype == FOURCC_soun) {
7877 if (CUR_STREAM (stream)->caps) {
7878 CUR_STREAM (stream)->caps =
7879 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7880 if (CUR_STREAM (stream)->rate > 0)
7881 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7882 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
7883 if (CUR_STREAM (stream)->n_channels > 0)
7884 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7885 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
7886 if (CUR_STREAM (stream)->n_channels > 2) {
7887 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7888 * correctly; this is just the minimum we can do - assume
7889 * we don't actually have any channel positions. */
7890 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7891 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7897 GstCaps *prev_caps = NULL;
7899 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7900 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7901 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7902 gst_pad_set_active (stream->pad, TRUE);
7904 gst_pad_use_fixed_caps (stream->pad);
7906 if (stream->protected) {
7907 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7908 GST_ERROR_OBJECT (qtdemux,
7909 "Failed to configure protected stream caps.");
7914 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7915 CUR_STREAM (stream)->caps);
7916 if (stream->new_stream) {
7919 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
7922 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7925 gst_event_parse_stream_flags (event, &stream_flags);
7926 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7927 qtdemux->have_group_id = TRUE;
7929 qtdemux->have_group_id = FALSE;
7930 gst_event_unref (event);
7931 } else if (!qtdemux->have_group_id) {
7932 qtdemux->have_group_id = TRUE;
7933 qtdemux->group_id = gst_util_group_id_next ();
7936 stream->new_stream = FALSE;
7938 gst_pad_create_stream_id_printf (stream->pad,
7939 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7940 event = gst_event_new_stream_start (stream_id);
7941 if (qtdemux->have_group_id)
7942 gst_event_set_group_id (event, qtdemux->group_id);
7943 if (stream->disabled)
7944 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7945 if (CUR_STREAM (stream)->sparse) {
7946 stream_flags |= GST_STREAM_FLAG_SPARSE;
7948 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
7950 gst_event_set_stream_flags (event, stream_flags);
7951 gst_pad_push_event (stream->pad, event);
7955 prev_caps = gst_pad_get_current_caps (stream->pad);
7957 if (CUR_STREAM (stream)->caps) {
7959 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
7960 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7961 CUR_STREAM (stream)->caps);
7962 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
7964 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7967 GST_WARNING_OBJECT (qtdemux, "stream without caps");
7971 gst_caps_unref (prev_caps);
7972 stream->new_caps = FALSE;
7978 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
7979 QtDemuxStream * stream)
7981 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
7984 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
7985 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
7986 if (G_UNLIKELY (stream->stsd_sample_description_id >=
7987 stream->stsd_entries_length)) {
7988 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7989 (_("This file is invalid and cannot be played.")),
7990 ("New sample description id is out of bounds (%d >= %d)",
7991 stream->stsd_sample_description_id, stream->stsd_entries_length));
7993 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
7994 stream->new_caps = TRUE;
7999 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8000 QtDemuxStream * stream, GstTagList * list)
8002 gboolean ret = TRUE;
8003 /* consistent default for push based mode */
8004 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8006 if (stream->subtype == FOURCC_vide) {
8007 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8010 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8013 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8014 gst_object_unref (stream->pad);
8020 qtdemux->n_video_streams++;
8021 } else if (stream->subtype == FOURCC_soun) {
8022 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8025 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8027 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8028 gst_object_unref (stream->pad);
8033 qtdemux->n_audio_streams++;
8034 } else if (stream->subtype == FOURCC_strm) {
8035 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8036 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8037 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8038 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8041 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8043 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8044 gst_object_unref (stream->pad);
8049 qtdemux->n_sub_streams++;
8050 } else if (CUR_STREAM (stream)->caps) {
8051 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8054 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8056 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8057 gst_object_unref (stream->pad);
8062 qtdemux->n_video_streams++;
8064 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8071 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8072 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8073 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8074 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8076 if (stream->stream_tags)
8077 gst_tag_list_unref (stream->stream_tags);
8078 stream->stream_tags = list;
8080 /* global tags go on each pad anyway */
8081 stream->send_global_tags = TRUE;
8082 /* send upstream GST_EVENT_PROTECTION events that were received before
8083 this source pad was created */
8084 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8085 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8089 gst_tag_list_unref (list);
8093 /* find next atom with @fourcc starting at @offset */
8094 static GstFlowReturn
8095 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8096 guint64 * length, guint32 fourcc)
8102 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8103 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8109 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8110 if (G_UNLIKELY (ret != GST_FLOW_OK))
8112 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8115 gst_buffer_unref (buf);
8118 gst_buffer_map (buf, &map, GST_MAP_READ);
8119 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8120 gst_buffer_unmap (buf, &map);
8121 gst_buffer_unref (buf);
8123 if (G_UNLIKELY (*length == 0)) {
8124 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8125 ret = GST_FLOW_ERROR;
8129 if (lfourcc == fourcc) {
8130 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8134 GST_LOG_OBJECT (qtdemux,
8135 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8136 GST_FOURCC_ARGS (fourcc), *offset);
8145 /* might simply have had last one */
8146 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8151 /* should only do something in pull mode */
8152 /* call with OBJECT lock */
8153 static GstFlowReturn
8154 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8156 guint64 length, offset;
8157 GstBuffer *buf = NULL;
8158 GstFlowReturn ret = GST_FLOW_OK;
8159 GstFlowReturn res = GST_FLOW_OK;
8162 offset = qtdemux->moof_offset;
8163 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8166 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8167 return GST_FLOW_EOS;
8170 /* best not do pull etc with lock held */
8171 GST_OBJECT_UNLOCK (qtdemux);
8173 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8174 if (ret != GST_FLOW_OK)
8177 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8178 if (G_UNLIKELY (ret != GST_FLOW_OK))
8180 gst_buffer_map (buf, &map, GST_MAP_READ);
8181 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8182 gst_buffer_unmap (buf, &map);
8183 gst_buffer_unref (buf);
8188 gst_buffer_unmap (buf, &map);
8189 gst_buffer_unref (buf);
8193 /* look for next moof */
8194 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8195 if (G_UNLIKELY (ret != GST_FLOW_OK))
8199 GST_OBJECT_LOCK (qtdemux);
8201 qtdemux->moof_offset = offset;
8207 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8209 res = GST_FLOW_ERROR;
8214 /* maybe upstream temporarily flushing */
8215 if (ret != GST_FLOW_FLUSHING) {
8216 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8219 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8220 /* resume at current position next time */
8227 /* initialise bytereaders for stbl sub-atoms */
8229 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8231 stream->stbl_index = -1; /* no samples have yet been parsed */
8232 stream->sample_index = -1;
8234 /* time-to-sample atom */
8235 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8238 /* copy atom data into a new buffer for later use */
8239 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8241 /* skip version + flags */
8242 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8243 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8245 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8247 /* make sure there's enough data */
8248 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8249 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8250 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8251 stream->n_sample_times);
8252 if (!stream->n_sample_times)
8256 /* sync sample atom */
8257 stream->stps_present = FALSE;
8258 if ((stream->stss_present =
8259 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8260 &stream->stss) ? TRUE : FALSE) == TRUE) {
8261 /* copy atom data into a new buffer for later use */
8262 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8264 /* skip version + flags */
8265 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8266 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8269 if (stream->n_sample_syncs) {
8270 /* make sure there's enough data */
8271 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8275 /* partial sync sample atom */
8276 if ((stream->stps_present =
8277 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8278 &stream->stps) ? TRUE : FALSE) == TRUE) {
8279 /* copy atom data into a new buffer for later use */
8280 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8282 /* skip version + flags */
8283 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8284 !gst_byte_reader_get_uint32_be (&stream->stps,
8285 &stream->n_sample_partial_syncs))
8288 /* if there are no entries, the stss table contains the real
8290 if (stream->n_sample_partial_syncs) {
8291 /* make sure there's enough data */
8292 if (!qt_atom_parser_has_chunks (&stream->stps,
8293 stream->n_sample_partial_syncs, 4))
8300 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8303 /* copy atom data into a new buffer for later use */
8304 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8306 /* skip version + flags */
8307 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8308 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8311 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8314 if (!stream->n_samples)
8317 /* sample-to-chunk atom */
8318 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8321 /* copy atom data into a new buffer for later use */
8322 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8324 /* skip version + flags */
8325 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8326 !gst_byte_reader_get_uint32_be (&stream->stsc,
8327 &stream->n_samples_per_chunk))
8330 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8331 stream->n_samples_per_chunk);
8333 /* make sure there's enough data */
8334 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8340 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8341 stream->co_size = sizeof (guint32);
8342 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8344 stream->co_size = sizeof (guint64);
8348 /* copy atom data into a new buffer for later use */
8349 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8351 /* skip version + flags */
8352 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8355 /* chunks_are_samples == TRUE means treat chunks as samples */
8356 stream->chunks_are_samples = stream->sample_size
8357 && !CUR_STREAM (stream)->sampled;
8358 if (stream->chunks_are_samples) {
8359 /* treat chunks as samples */
8360 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8363 /* skip number of entries */
8364 if (!gst_byte_reader_skip (&stream->stco, 4))
8367 /* make sure there are enough data in the stsz atom */
8368 if (!stream->sample_size) {
8369 /* different sizes for each sample */
8370 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8375 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8376 stream->n_samples, (guint) sizeof (QtDemuxSample),
8377 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8379 if (stream->n_samples >=
8380 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8381 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8382 "be larger than %uMB (broken file?)", stream->n_samples,
8383 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8387 g_assert (stream->samples == NULL);
8388 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8389 if (!stream->samples) {
8390 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8395 /* composition time-to-sample */
8396 if ((stream->ctts_present =
8397 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8398 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8399 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8401 /* copy atom data into a new buffer for later use */
8402 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8404 /* skip version + flags */
8405 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8406 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8407 &stream->n_composition_times))
8410 /* make sure there's enough data */
8411 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8415 /* This is optional, if missing we iterate the ctts */
8416 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8417 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8418 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8419 g_free ((gpointer) cslg.data);
8423 gint32 cslg_least = 0;
8424 guint num_entries, pos;
8427 pos = gst_byte_reader_get_pos (&stream->ctts);
8428 num_entries = stream->n_composition_times;
8430 stream->cslg_shift = 0;
8432 for (i = 0; i < num_entries; i++) {
8435 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8436 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8438 if (offset < cslg_least)
8439 cslg_least = offset;
8443 stream->cslg_shift = ABS (cslg_least);
8445 stream->cslg_shift = 0;
8447 /* reset the reader so we can generate sample table */
8448 gst_byte_reader_set_pos (&stream->ctts, pos);
8451 /* Ensure the cslg_shift value is consistent so we can use it
8452 * unconditionnally to produce TS and Segment */
8453 stream->cslg_shift = 0;
8460 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8461 (_("This file is corrupt and cannot be played.")), (NULL));
8466 gst_qtdemux_stbl_free (stream);
8467 if (!qtdemux->fragmented) {
8468 /* not quite good */
8469 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8472 /* may pick up samples elsewhere */
8478 /* collect samples from the next sample to be parsed up to sample @n for @stream
8479 * by reading the info from @stbl
8481 * This code can be executed from both the streaming thread and the seeking
8482 * thread so it takes the object lock to protect itself
8485 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8488 QtDemuxSample *samples, *first, *cur, *last;
8489 guint32 n_samples_per_chunk;
8492 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8493 GST_FOURCC_FORMAT ", pad %s",
8494 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8495 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8497 n_samples = stream->n_samples;
8500 goto out_of_samples;
8502 GST_OBJECT_LOCK (qtdemux);
8503 if (n <= stream->stbl_index)
8504 goto already_parsed;
8506 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8508 if (!stream->stsz.data) {
8509 /* so we already parsed and passed all the moov samples;
8510 * onto fragmented ones */
8511 g_assert (qtdemux->fragmented);
8515 /* pointer to the sample table */
8516 samples = stream->samples;
8518 /* starts from -1, moves to the next sample index to parse */
8519 stream->stbl_index++;
8521 /* keep track of the first and last sample to fill */
8522 first = &samples[stream->stbl_index];
8525 if (!stream->chunks_are_samples) {
8526 /* set the sample sizes */
8527 if (stream->sample_size == 0) {
8528 /* different sizes for each sample */
8529 for (cur = first; cur <= last; cur++) {
8530 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8531 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8532 (guint) (cur - samples), cur->size);
8535 /* samples have the same size */
8536 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8537 for (cur = first; cur <= last; cur++)
8538 cur->size = stream->sample_size;
8542 n_samples_per_chunk = stream->n_samples_per_chunk;
8545 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8548 if (stream->stsc_chunk_index >= stream->last_chunk
8549 || stream->stsc_chunk_index < stream->first_chunk) {
8550 stream->first_chunk =
8551 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8552 stream->samples_per_chunk =
8553 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8555 stream->stsd_sample_description_id =
8556 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
8558 /* chunk numbers are counted from 1 it seems */
8559 if (G_UNLIKELY (stream->first_chunk == 0))
8562 --stream->first_chunk;
8564 /* the last chunk of each entry is calculated by taking the first chunk
8565 * of the next entry; except if there is no next, where we fake it with
8567 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8568 stream->last_chunk = G_MAXUINT32;
8570 stream->last_chunk =
8571 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8572 if (G_UNLIKELY (stream->last_chunk == 0))
8575 --stream->last_chunk;
8578 GST_LOG_OBJECT (qtdemux,
8579 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
8580 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
8581 stream->samples_per_chunk, stream->stsd_sample_description_id);
8583 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8586 if (stream->last_chunk != G_MAXUINT32) {
8587 if (!qt_atom_parser_peek_sub (&stream->stco,
8588 stream->first_chunk * stream->co_size,
8589 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8594 stream->co_chunk = stream->stco;
8595 if (!gst_byte_reader_skip (&stream->co_chunk,
8596 stream->first_chunk * stream->co_size))
8600 stream->stsc_chunk_index = stream->first_chunk;
8603 last_chunk = stream->last_chunk;
8605 if (stream->chunks_are_samples) {
8606 cur = &samples[stream->stsc_chunk_index];
8608 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8611 stream->stsc_chunk_index = j;
8616 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8619 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8620 "%" G_GUINT64_FORMAT, j, cur->offset);
8622 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
8623 CUR_STREAM (stream)->bytes_per_frame > 0) {
8625 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
8626 CUR_STREAM (stream)->samples_per_frame *
8627 CUR_STREAM (stream)->bytes_per_frame;
8629 cur->size = stream->samples_per_chunk;
8632 GST_DEBUG_OBJECT (qtdemux,
8633 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8634 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8635 stream->stco_sample_index)), cur->size);
8637 cur->timestamp = stream->stco_sample_index;
8638 cur->duration = stream->samples_per_chunk;
8639 cur->keyframe = TRUE;
8642 stream->stco_sample_index += stream->samples_per_chunk;
8644 stream->stsc_chunk_index = j;
8646 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8647 guint32 samples_per_chunk;
8648 guint64 chunk_offset;
8650 if (!stream->stsc_sample_index
8651 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8652 &stream->chunk_offset))
8655 samples_per_chunk = stream->samples_per_chunk;
8656 chunk_offset = stream->chunk_offset;
8658 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8659 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8660 G_GUINT64_FORMAT " and size %d",
8661 (guint) (cur - samples), chunk_offset, cur->size);
8663 cur->offset = chunk_offset;
8664 chunk_offset += cur->size;
8667 if (G_UNLIKELY (cur > last)) {
8669 stream->stsc_sample_index = k + 1;
8670 stream->chunk_offset = chunk_offset;
8671 stream->stsc_chunk_index = j;
8675 stream->stsc_sample_index = 0;
8677 stream->stsc_chunk_index = j;
8679 stream->stsc_index++;
8682 if (stream->chunks_are_samples)
8686 guint32 n_sample_times;
8688 n_sample_times = stream->n_sample_times;
8691 for (i = stream->stts_index; i < n_sample_times; i++) {
8692 guint32 stts_samples;
8693 gint32 stts_duration;
8696 if (stream->stts_sample_index >= stream->stts_samples
8697 || !stream->stts_sample_index) {
8699 stream->stts_samples =
8700 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8701 stream->stts_duration =
8702 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8704 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8705 i, stream->stts_samples, stream->stts_duration);
8707 stream->stts_sample_index = 0;
8710 stts_samples = stream->stts_samples;
8711 stts_duration = stream->stts_duration;
8712 stts_time = stream->stts_time;
8714 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8715 GST_DEBUG_OBJECT (qtdemux,
8716 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8717 (guint) (cur - samples), j,
8718 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8720 cur->timestamp = stts_time;
8721 cur->duration = stts_duration;
8723 /* avoid 32-bit wrap-around,
8724 * but still mind possible 'negative' duration */
8725 stts_time += (gint64) stts_duration;
8728 if (G_UNLIKELY (cur > last)) {
8730 stream->stts_time = stts_time;
8731 stream->stts_sample_index = j + 1;
8732 if (stream->stts_sample_index >= stream->stts_samples)
8733 stream->stts_index++;
8737 stream->stts_sample_index = 0;
8738 stream->stts_time = stts_time;
8739 stream->stts_index++;
8741 /* fill up empty timestamps with the last timestamp, this can happen when
8742 * the last samples do not decode and so we don't have timestamps for them.
8743 * We however look at the last timestamp to estimate the track length so we
8744 * need something in here. */
8745 for (; cur < last; cur++) {
8746 GST_DEBUG_OBJECT (qtdemux,
8747 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8748 (guint) (cur - samples),
8749 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8750 cur->timestamp = stream->stts_time;
8756 /* sample sync, can be NULL */
8757 if (stream->stss_present == TRUE) {
8758 guint32 n_sample_syncs;
8760 n_sample_syncs = stream->n_sample_syncs;
8762 if (!n_sample_syncs) {
8763 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8764 stream->all_keyframe = TRUE;
8766 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8767 /* note that the first sample is index 1, not 0 */
8770 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8772 if (G_LIKELY (index > 0 && index <= n_samples)) {
8774 samples[index].keyframe = TRUE;
8775 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8776 /* and exit if we have enough samples */
8777 if (G_UNLIKELY (index >= n)) {
8784 stream->stss_index = i;
8787 /* stps marks partial sync frames like open GOP I-Frames */
8788 if (stream->stps_present == TRUE) {
8789 guint32 n_sample_partial_syncs;
8791 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8793 /* if there are no entries, the stss table contains the real
8795 if (n_sample_partial_syncs) {
8796 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8797 /* note that the first sample is index 1, not 0 */
8800 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8802 if (G_LIKELY (index > 0 && index <= n_samples)) {
8804 samples[index].keyframe = TRUE;
8805 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8806 /* and exit if we have enough samples */
8807 if (G_UNLIKELY (index >= n)) {
8814 stream->stps_index = i;
8818 /* no stss, all samples are keyframes */
8819 stream->all_keyframe = TRUE;
8820 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8825 /* composition time to sample */
8826 if (stream->ctts_present == TRUE) {
8827 guint32 n_composition_times;
8829 gint32 ctts_soffset;
8831 /* Fill in the pts_offsets */
8833 n_composition_times = stream->n_composition_times;
8835 for (i = stream->ctts_index; i < n_composition_times; i++) {
8836 if (stream->ctts_sample_index >= stream->ctts_count
8837 || !stream->ctts_sample_index) {
8838 stream->ctts_count =
8839 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8840 stream->ctts_soffset =
8841 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8842 stream->ctts_sample_index = 0;
8845 ctts_count = stream->ctts_count;
8846 ctts_soffset = stream->ctts_soffset;
8848 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8849 cur->pts_offset = ctts_soffset;
8852 if (G_UNLIKELY (cur > last)) {
8854 stream->ctts_sample_index = j + 1;
8858 stream->ctts_sample_index = 0;
8859 stream->ctts_index++;
8863 stream->stbl_index = n;
8864 /* if index has been completely parsed, free data that is no-longer needed */
8865 if (n + 1 == stream->n_samples) {
8866 gst_qtdemux_stbl_free (stream);
8867 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8868 if (qtdemux->pullbased) {
8869 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8870 while (n + 1 == stream->n_samples)
8871 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8875 GST_OBJECT_UNLOCK (qtdemux);
8882 GST_LOG_OBJECT (qtdemux,
8883 "Tried to parse up to sample %u but this sample has already been parsed",
8885 /* if fragmented, there may be more */
8886 if (qtdemux->fragmented && n == stream->stbl_index)
8888 GST_OBJECT_UNLOCK (qtdemux);
8894 GST_LOG_OBJECT (qtdemux,
8895 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8897 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8898 (_("This file is corrupt and cannot be played.")), (NULL));
8903 GST_OBJECT_UNLOCK (qtdemux);
8904 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8905 (_("This file is corrupt and cannot be played.")), (NULL));
8910 /* collect all segment info for @stream.
8913 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8917 /* accept edts if they contain gaps at start and there is only
8918 * one media segment */
8919 gboolean allow_pushbased_edts = TRUE;
8920 gint media_segments_count = 0;
8922 /* parse and prepare segment info from the edit list */
8923 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8924 stream->n_segments = 0;
8925 stream->segments = NULL;
8926 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8929 gint i, count, entry_size;
8932 const guint8 *buffer;
8936 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8937 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8940 buffer = elst->data;
8942 size = QT_UINT32 (buffer);
8943 /* version, flags, n_segments */
8945 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8948 version = QT_UINT8 (buffer + 8);
8949 entry_size = (version == 1) ? 20 : 12;
8951 n_segments = QT_UINT32 (buffer + 12);
8953 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
8954 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8958 /* we might allocate a bit too much, at least allocate 1 segment */
8959 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8961 /* segments always start from 0 */
8966 for (i = 0; i < n_segments; i++) {
8969 gboolean time_valid = TRUE;
8970 QtDemuxSegment *segment;
8972 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8975 media_time = QT_UINT64 (buffer + 8);
8976 duration = QT_UINT64 (buffer);
8977 if (media_time == G_MAXUINT64)
8980 media_time = QT_UINT32 (buffer + 4);
8981 duration = QT_UINT32 (buffer);
8982 if (media_time == G_MAXUINT32)
8987 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8989 segment = &stream->segments[count++];
8991 /* time and duration expressed in global timescale */
8992 segment->time = stime;
8993 /* add non scaled values so we don't cause roundoff errors */
8994 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8996 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8997 segment->duration = stime - segment->time;
8999 /* zero duration does not imply media_start == media_stop
9000 * but, only specify media_start.*/
9001 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
9002 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
9003 && stime >= media_start) {
9004 segment->duration = stime - media_start;
9006 segment->duration = GST_CLOCK_TIME_NONE;
9009 segment->stop_time = stime;
9011 segment->trak_media_start = media_time;
9012 /* media_time expressed in stream timescale */
9014 segment->media_start = media_start;
9015 segment->media_stop = segment->media_start + segment->duration;
9016 media_segments_count++;
9018 segment->media_start = GST_CLOCK_TIME_NONE;
9019 segment->media_stop = GST_CLOCK_TIME_NONE;
9021 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9023 if (rate_int <= 1) {
9024 /* 0 is not allowed, some programs write 1 instead of the floating point
9026 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9030 segment->rate = rate_int / 65536.0;
9033 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9034 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9035 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9036 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9037 i, GST_TIME_ARGS (segment->time),
9038 GST_TIME_ARGS (segment->duration),
9039 GST_TIME_ARGS (segment->media_start), media_time,
9040 GST_TIME_ARGS (segment->media_stop),
9041 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9043 if (segment->stop_time > qtdemux->segment.stop) {
9044 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9045 " extends to %" GST_TIME_FORMAT
9046 " past the end of the file duration %" GST_TIME_FORMAT
9047 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9048 GST_TIME_ARGS (qtdemux->segment.stop));
9049 qtdemux->segment.stop = segment->stop_time;
9052 buffer += entry_size;
9054 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9055 stream->n_segments = count;
9056 if (media_segments_count != 1)
9057 allow_pushbased_edts = FALSE;
9061 /* push based does not handle segments, so act accordingly here,
9062 * and warn if applicable */
9063 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9064 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9065 /* remove and use default one below, we stream like it anyway */
9066 g_free (stream->segments);
9067 stream->segments = NULL;
9068 stream->n_segments = 0;
9071 /* no segments, create one to play the complete trak */
9072 if (stream->n_segments == 0) {
9073 GstClockTime stream_duration =
9074 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9076 if (stream->segments == NULL)
9077 stream->segments = g_new (QtDemuxSegment, 1);
9079 /* represent unknown our way */
9080 if (stream_duration == 0)
9081 stream_duration = GST_CLOCK_TIME_NONE;
9083 stream->segments[0].time = 0;
9084 stream->segments[0].stop_time = stream_duration;
9085 stream->segments[0].duration = stream_duration;
9086 stream->segments[0].media_start = 0;
9087 stream->segments[0].media_stop = stream_duration;
9088 stream->segments[0].rate = 1.0;
9089 stream->segments[0].trak_media_start = 0;
9091 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9092 GST_TIME_ARGS (stream_duration));
9093 stream->n_segments = 1;
9094 stream->dummy_segment = TRUE;
9096 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9102 * Parses the stsd atom of a svq3 trak looking for
9103 * the SMI and gama atoms.
9106 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9107 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9109 const guint8 *_gamma = NULL;
9110 GstBuffer *_seqh = NULL;
9111 const guint8 *stsd_data = stsd_entry_data;
9112 guint32 length = QT_UINT32 (stsd_data);
9116 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9122 version = QT_UINT16 (stsd_data);
9127 while (length > 8) {
9128 guint32 fourcc, size;
9130 size = QT_UINT32 (stsd_data);
9131 fourcc = QT_FOURCC (stsd_data + 4);
9132 data = stsd_data + 8;
9135 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9136 "svq3 atom parsing");
9145 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9146 " for gama atom, expected 12", size);
9151 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9153 if (_seqh != NULL) {
9154 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9155 " found, ignoring");
9157 seqh_size = QT_UINT32 (data + 4);
9158 if (seqh_size > 0) {
9159 _seqh = gst_buffer_new_and_alloc (seqh_size);
9160 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9167 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9168 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9172 if (size <= length) {
9178 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9181 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9182 G_GUINT16_FORMAT, version);
9193 gst_buffer_unref (_seqh);
9198 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9205 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9206 * atom that might contain a 'data' atom with the rtsp uri.
9207 * This case was reported in bug #597497, some info about
9208 * the hndl atom can be found in TN1195
9210 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9211 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9214 guint32 dref_num_entries = 0;
9215 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9216 gst_byte_reader_skip (&dref, 4) &&
9217 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9220 /* search dref entries for hndl atom */
9221 for (i = 0; i < dref_num_entries; i++) {
9222 guint32 size = 0, type;
9223 guint8 string_len = 0;
9224 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9225 qt_atom_parser_get_fourcc (&dref, &type)) {
9226 if (type == FOURCC_hndl) {
9227 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9229 /* skip data reference handle bytes and the
9230 * following pascal string and some extra 4
9231 * bytes I have no idea what are */
9232 if (!gst_byte_reader_skip (&dref, 4) ||
9233 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9234 !gst_byte_reader_skip (&dref, string_len + 4)) {
9235 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9239 /* iterate over the atoms to find the data atom */
9240 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9244 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9245 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9246 if (atom_type == FOURCC_data) {
9247 const guint8 *uri_aux = NULL;
9249 /* found the data atom that might contain the rtsp uri */
9250 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9251 "hndl atom, interpreting it as an URI");
9252 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9254 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9255 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9257 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9258 "didn't contain a rtsp address");
9260 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9265 /* skipping to the next entry */
9266 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9269 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9276 /* skip to the next entry */
9277 if (!gst_byte_reader_skip (&dref, size - 8))
9280 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9283 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9289 #define AMR_NB_ALL_MODES 0x81ff
9290 #define AMR_WB_ALL_MODES 0x83ff
9292 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9294 /* The 'damr' atom is of the form:
9296 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9297 * 32 b 8 b 16 b 8 b 8 b
9299 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9300 * represents the highest mode used in the stream (and thus the maximum
9301 * bitrate), with a couple of special cases as seen below.
9304 /* Map of frame type ID -> bitrate */
9305 static const guint nb_bitrates[] = {
9306 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9308 static const guint wb_bitrates[] = {
9309 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9315 gst_buffer_map (buf, &map, GST_MAP_READ);
9317 if (map.size != 0x11) {
9318 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9322 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9323 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9324 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9328 mode_set = QT_UINT16 (map.data + 13);
9330 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9331 max_mode = 7 + (wb ? 1 : 0);
9333 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9334 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9336 if (max_mode == -1) {
9337 GST_DEBUG ("No mode indication was found (mode set) = %x",
9342 gst_buffer_unmap (buf, &map);
9343 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9346 gst_buffer_unmap (buf, &map);
9351 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9352 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9355 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9361 if (gst_byte_reader_get_remaining (reader) < 36)
9364 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9365 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9366 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9367 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9368 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9369 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9370 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9371 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9372 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9374 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9375 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9376 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9378 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9379 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9381 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9382 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9389 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9390 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9397 * This macro will only compare value abdegh, it expects cfi to have already
9400 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9401 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9403 /* only handle the cases where the last column has standard values */
9404 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9405 const gchar *rotation_tag = NULL;
9407 /* no rotation needed */
9408 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9410 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9411 rotation_tag = "rotate-90";
9412 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9413 rotation_tag = "rotate-180";
9414 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9415 rotation_tag = "rotate-270";
9417 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9420 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9422 if (rotation_tag != NULL) {
9423 if (*taglist == NULL)
9424 *taglist = gst_tag_list_new_empty ();
9425 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9426 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9429 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9433 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9434 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9435 * Common Encryption (cenc), the function will also parse the tenc box (defined
9436 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9437 * (typically an enc[v|a|t|s] sample entry); the function will set
9438 * @original_fmt to the fourcc of the original unencrypted stream format.
9439 * Returns TRUE if successful; FALSE otherwise. */
9441 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9442 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9449 g_return_val_if_fail (qtdemux != NULL, FALSE);
9450 g_return_val_if_fail (stream != NULL, FALSE);
9451 g_return_val_if_fail (container != NULL, FALSE);
9452 g_return_val_if_fail (original_fmt != NULL, FALSE);
9454 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9455 if (G_UNLIKELY (!sinf)) {
9456 if (stream->protection_scheme_type == FOURCC_cenc) {
9457 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9458 "mandatory for Common Encryption");
9464 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9465 if (G_UNLIKELY (!frma)) {
9466 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9470 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9471 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9472 GST_FOURCC_ARGS (*original_fmt));
9474 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9476 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9479 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9480 stream->protection_scheme_version =
9481 QT_UINT32 ((const guint8 *) schm->data + 16);
9483 GST_DEBUG_OBJECT (qtdemux,
9484 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9485 "protection_scheme_version: %#010x",
9486 GST_FOURCC_ARGS (stream->protection_scheme_type),
9487 stream->protection_scheme_version);
9489 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9491 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9494 if (stream->protection_scheme_type == FOURCC_cenc) {
9495 QtDemuxCencSampleSetInfo *info;
9497 const guint8 *tenc_data;
9498 guint32 isEncrypted;
9500 const guint8 *default_kid;
9503 if (G_UNLIKELY (!stream->protection_scheme_info))
9504 stream->protection_scheme_info =
9505 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9507 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9509 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9511 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9512 "which is mandatory for Common Encryption");
9515 tenc_data = (const guint8 *) tenc->data + 12;
9516 isEncrypted = QT_UINT24 (tenc_data);
9517 iv_size = QT_UINT8 (tenc_data + 3);
9518 default_kid = (tenc_data + 4);
9519 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9520 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9521 if (info->default_properties)
9522 gst_structure_free (info->default_properties);
9523 info->default_properties =
9524 gst_structure_new ("application/x-cenc",
9525 "iv_size", G_TYPE_UINT, iv_size,
9526 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9527 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9528 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9529 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9530 gst_buffer_unref (kid_buf);
9536 * With each track we associate a new QtDemuxStream that contains all the info
9538 * traks that do not decode to something (like strm traks) will not have a pad.
9541 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9562 QtDemuxStream *stream = NULL;
9563 gboolean new_stream = FALSE;
9564 gchar *codec = NULL;
9565 const guint8 *stsd_data;
9566 const guint8 *stsd_entry_data;
9567 guint remaining_stsd_len;
9568 guint stsd_entry_count;
9570 guint16 lang_code; /* quicktime lang code or packed iso code */
9572 guint32 tkhd_flags = 0;
9573 guint8 tkhd_version = 0;
9574 guint32 w = 0, h = 0;
9576 guint value_size, stsd_len, len;
9580 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9582 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9583 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9584 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9587 /* pick between 64 or 32 bits */
9588 value_size = tkhd_version == 1 ? 8 : 4;
9589 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9590 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9593 if (!qtdemux->got_moov) {
9594 if (qtdemux_find_stream (qtdemux, track_id))
9595 goto existing_stream;
9596 stream = _create_stream ();
9597 stream->track_id = track_id;
9600 stream = qtdemux_find_stream (qtdemux, track_id);
9602 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9606 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
9608 /* flush samples data from this track from previous moov */
9609 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9610 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9612 /* need defaults for fragments */
9613 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9615 if ((tkhd_flags & 1) == 0)
9616 stream->disabled = TRUE;
9618 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9619 tkhd_version, tkhd_flags, stream->track_id);
9621 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9624 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9625 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9626 if (qtdemux->major_brand != FOURCC_mjp2 ||
9627 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9631 len = QT_UINT32 ((guint8 *) mdhd->data);
9632 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9633 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9634 if (version == 0x01000000) {
9637 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9638 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9639 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9643 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9644 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9645 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9648 if (lang_code < 0x400) {
9649 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9650 } else if (lang_code == 0x7fff) {
9651 stream->lang_id[0] = 0; /* unspecified */
9653 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9654 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9655 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9656 stream->lang_id[3] = 0;
9659 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9661 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9663 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9664 lang_code, stream->lang_id);
9666 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9669 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9670 /* chapters track reference */
9671 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9673 gsize length = GST_READ_UINT32_BE (chap->data);
9674 if (qtdemux->chapters_track_id)
9675 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9678 qtdemux->chapters_track_id =
9679 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9684 /* fragmented files may have bogus duration in moov */
9685 if (!qtdemux->fragmented &&
9686 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9687 guint64 tdur1, tdur2;
9689 /* don't overflow */
9690 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9691 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9694 * some of those trailers, nowadays, have prologue images that are
9695 * themselves video tracks as well. I haven't really found a way to
9696 * identify those yet, except for just looking at their duration. */
9697 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9698 GST_WARNING_OBJECT (qtdemux,
9699 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9700 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9701 "found, assuming preview image or something; skipping track",
9702 stream->duration, stream->timescale, qtdemux->duration,
9703 qtdemux->timescale);
9705 gst_qtdemux_stream_free (qtdemux, stream);
9710 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9713 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9714 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9716 len = QT_UINT32 ((guint8 *) hdlr->data);
9718 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9719 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9720 GST_FOURCC_ARGS (stream->subtype));
9722 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9725 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9728 /*parse svmi header if existing */
9729 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9731 len = QT_UINT32 ((guint8 *) svmi->data);
9732 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9734 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9735 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9736 guint8 frame_type, frame_layout;
9738 /* MPEG-A stereo video */
9739 if (qtdemux->major_brand == FOURCC_ss02)
9740 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9742 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9743 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9744 switch (frame_type) {
9746 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9749 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9752 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9755 /* mode 3 is primary/secondary view sequence, ie
9756 * left/right views in separate tracks. See section 7.2
9757 * of ISO/IEC 23000-11:2009 */
9758 GST_FIXME_OBJECT (qtdemux,
9759 "Implement stereo video in separate streams");
9762 if ((frame_layout & 0x1) == 0)
9763 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9765 GST_LOG_OBJECT (qtdemux,
9766 "StereoVideo: composition type: %u, is_left_first: %u",
9767 frame_type, frame_layout);
9768 stream->multiview_mode = mode;
9769 stream->multiview_flags = flags;
9773 /* parse rest of tkhd */
9774 if (stream->subtype == FOURCC_vide) {
9777 /* version 1 uses some 64-bit ints */
9778 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9781 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9784 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9785 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9788 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9789 &stream->stream_tags);
9793 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9795 stsd_data = (const guint8 *) stsd->data;
9797 /* stsd should at least have one entry */
9798 stsd_len = QT_UINT32 (stsd_data);
9799 if (stsd_len < 24) {
9800 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9801 if (stream->subtype == FOURCC_vivo) {
9803 gst_qtdemux_stream_free (qtdemux, stream);
9810 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
9811 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
9812 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9813 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
9815 stsd_entry_data = stsd_data + 16;
9816 remaining_stsd_len = stsd_len - 16;
9817 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
9818 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
9820 /* and that entry should fit within stsd */
9821 len = QT_UINT32 (stsd_entry_data);
9822 if (len > remaining_stsd_len)
9825 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
9826 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9827 GST_FOURCC_ARGS (entry->fourcc));
9828 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9830 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9831 goto error_encrypted;
9833 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9834 /* FIXME this looks wrong, there might be multiple children
9835 * with the same type */
9836 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9837 stream->protected = TRUE;
9838 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9839 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9842 if (stream->subtype == FOURCC_vide) {
9844 gint depth, palette_size, palette_count;
9845 guint32 *palette_data = NULL;
9847 entry->sampled = TRUE;
9849 stream->display_width = w >> 16;
9850 stream->display_height = h >> 16;
9853 if (len < 86) /* TODO verify */
9856 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
9857 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
9858 entry->fps_n = 0; /* this is filled in later */
9859 entry->fps_d = 0; /* this is filled in later */
9860 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
9861 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
9863 /* if color_table_id is 0, ctab atom must follow; however some files
9864 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9865 * if color table is not present we'll correct the value */
9866 if (entry->color_table_id == 0 &&
9868 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
9869 entry->color_table_id = -1;
9872 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9873 entry->width, entry->height, entry->bits_per_sample,
9874 entry->color_table_id);
9876 depth = entry->bits_per_sample;
9878 /* more than 32 bits means grayscale */
9879 gray = (depth > 32);
9880 /* low 32 bits specify the depth */
9883 /* different number of palette entries is determined by depth. */
9885 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9886 palette_count = (1 << depth);
9887 palette_size = palette_count * 4;
9889 if (entry->color_table_id) {
9890 switch (palette_count) {
9894 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9897 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9902 g_memdup (ff_qt_grayscale_palette_16, palette_size);
9904 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9909 g_memdup (ff_qt_grayscale_palette_256, palette_size);
9911 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9914 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9915 (_("The video in this file might not play correctly.")),
9916 ("unsupported palette depth %d", depth));
9920 gint i, j, start, end;
9926 start = QT_UINT32 (stsd_entry_data + offset + 70);
9927 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
9928 end = QT_UINT16 (stsd_entry_data + offset + 76);
9930 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9931 start, end, palette_count);
9938 if (len < 94 + (end - start) * 8)
9941 /* palette is always the same size */
9942 palette_data = g_malloc0 (256 * 4);
9943 palette_size = 256 * 4;
9945 for (j = 0, i = start; i <= end; j++, i++) {
9948 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
9949 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
9950 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
9951 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
9953 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9954 (g & 0xff00) | (b >> 8);
9959 gst_caps_unref (entry->caps);
9962 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
9964 if (G_UNLIKELY (!entry->caps)) {
9965 g_free (palette_data);
9966 goto unknown_stream;
9970 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
9971 GST_TAG_VIDEO_CODEC, codec, NULL);
9979 if (entry->rgb8_palette)
9980 gst_memory_unref (entry->rgb8_palette);
9981 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9982 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9984 s = gst_caps_get_structure (entry->caps, 0);
9986 /* non-raw video has a palette_data property. raw video has the palette as
9987 * an extra plane that we append to the output buffers before we push
9989 if (!gst_structure_has_name (s, "video/x-raw")) {
9992 palette = gst_buffer_new ();
9993 gst_buffer_append_memory (palette, entry->rgb8_palette);
9994 entry->rgb8_palette = NULL;
9996 gst_caps_set_simple (entry->caps, "palette_data",
9997 GST_TYPE_BUFFER, palette, NULL);
9998 gst_buffer_unref (palette);
10000 } else if (palette_count != 0) {
10001 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10002 (NULL), ("Unsupported palette depth %d", depth));
10005 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10006 QT_UINT16 (stsd_entry_data + offset + 32));
10012 /* pick 'the' stsd child */
10013 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10014 if (!stream->protected) {
10015 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10019 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10025 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10026 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10027 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10028 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10032 const guint8 *pasp_data = (const guint8 *) pasp->data;
10033 gint len = QT_UINT32 (pasp_data);
10036 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10037 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10039 CUR_STREAM (stream)->par_w = 0;
10040 CUR_STREAM (stream)->par_h = 0;
10043 CUR_STREAM (stream)->par_w = 0;
10044 CUR_STREAM (stream)->par_h = 0;
10048 const guint8 *fiel_data = (const guint8 *) fiel->data;
10049 gint len = QT_UINT32 (fiel_data);
10052 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10053 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10058 const guint8 *colr_data = (const guint8 *) colr->data;
10059 gint len = QT_UINT32 (colr_data);
10061 if (len == 19 || len == 18) {
10062 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10064 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10065 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10066 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10067 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10068 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10070 switch (primaries) {
10072 CUR_STREAM (stream)->colorimetry.primaries =
10073 GST_VIDEO_COLOR_PRIMARIES_BT709;
10076 CUR_STREAM (stream)->colorimetry.primaries =
10077 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10080 CUR_STREAM (stream)->colorimetry.primaries =
10081 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10084 CUR_STREAM (stream)->colorimetry.primaries =
10085 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10091 switch (transfer_function) {
10093 CUR_STREAM (stream)->colorimetry.transfer =
10094 GST_VIDEO_TRANSFER_BT709;
10097 CUR_STREAM (stream)->colorimetry.transfer =
10098 GST_VIDEO_TRANSFER_SMPTE240M;
10106 CUR_STREAM (stream)->colorimetry.matrix =
10107 GST_VIDEO_COLOR_MATRIX_BT709;
10110 CUR_STREAM (stream)->colorimetry.matrix =
10111 GST_VIDEO_COLOR_MATRIX_BT601;
10114 CUR_STREAM (stream)->colorimetry.matrix =
10115 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10118 CUR_STREAM (stream)->colorimetry.matrix =
10119 GST_VIDEO_COLOR_MATRIX_BT2020;
10125 CUR_STREAM (stream)->colorimetry.range =
10126 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10127 GST_VIDEO_COLOR_RANGE_16_235;
10129 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10132 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10137 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10138 stream->stream_tags);
10145 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10146 const guint8 *avc_data = stsd_entry_data + 0x56;
10149 while (len >= 0x8) {
10152 if (QT_UINT32 (avc_data) <= len)
10153 size = QT_UINT32 (avc_data) - 0x8;
10158 /* No real data, so break out */
10161 switch (QT_FOURCC (avc_data + 0x4)) {
10164 /* parse, if found */
10167 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10169 /* First 4 bytes are the length of the atom, the next 4 bytes
10170 * are the fourcc, the next 1 byte is the version, and the
10171 * subsequent bytes are profile_tier_level structure like data. */
10172 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10173 avc_data + 8 + 1, size - 1);
10174 buf = gst_buffer_new_and_alloc (size);
10175 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10176 gst_caps_set_simple (entry->caps,
10177 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10178 gst_buffer_unref (buf);
10186 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10188 /* First 4 bytes are the length of the atom, the next 4 bytes
10189 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10190 * next 1 byte is the version, and the
10191 * subsequent bytes are sequence parameter set like data. */
10193 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10195 gst_codec_utils_h264_caps_set_level_and_profile
10196 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10198 buf = gst_buffer_new_and_alloc (size);
10199 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10200 gst_caps_set_simple (entry->caps,
10201 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10202 gst_buffer_unref (buf);
10208 guint avg_bitrate, max_bitrate;
10210 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10214 max_bitrate = QT_UINT32 (avc_data + 0xc);
10215 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10217 if (!max_bitrate && !avg_bitrate)
10220 /* Some muxers seem to swap the average and maximum bitrates
10221 * (I'm looking at you, YouTube), so we swap for sanity. */
10222 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10223 guint temp = avg_bitrate;
10225 avg_bitrate = max_bitrate;
10226 max_bitrate = temp;
10229 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10230 gst_tag_list_add (stream->stream_tags,
10231 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10232 max_bitrate, NULL);
10234 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10235 gst_tag_list_add (stream->stream_tags,
10236 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10248 avc_data += size + 8;
10257 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10258 const guint8 *hevc_data = stsd_entry_data + 0x56;
10261 while (len >= 0x8) {
10264 if (QT_UINT32 (hevc_data) <= len)
10265 size = QT_UINT32 (hevc_data) - 0x8;
10270 /* No real data, so break out */
10273 switch (QT_FOURCC (hevc_data + 0x4)) {
10276 /* parse, if found */
10279 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10281 /* First 4 bytes are the length of the atom, the next 4 bytes
10282 * are the fourcc, the next 1 byte is the version, and the
10283 * subsequent bytes are sequence parameter set like data. */
10284 gst_codec_utils_h265_caps_set_level_tier_and_profile
10285 (entry->caps, hevc_data + 8 + 1, size - 1);
10287 buf = gst_buffer_new_and_alloc (size);
10288 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10289 gst_caps_set_simple (entry->caps,
10290 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10291 gst_buffer_unref (buf);
10298 hevc_data += size + 8;
10311 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10312 GST_FOURCC_ARGS (fourcc));
10314 /* codec data might be in glbl extension atom */
10316 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10322 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10324 len = QT_UINT32 (data);
10327 buf = gst_buffer_new_and_alloc (len);
10328 gst_buffer_fill (buf, 0, data + 8, len);
10329 gst_caps_set_simple (entry->caps,
10330 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10331 gst_buffer_unref (buf);
10338 /* see annex I of the jpeg2000 spec */
10339 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10340 const guint8 *data;
10341 const gchar *colorspace = NULL;
10343 guint32 ncomp_map = 0;
10344 gint32 *comp_map = NULL;
10345 guint32 nchan_def = 0;
10346 gint32 *chan_def = NULL;
10348 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10349 /* some required atoms */
10350 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10353 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10357 /* number of components; redundant with info in codestream, but useful
10359 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10360 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10362 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10364 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10367 GST_DEBUG_OBJECT (qtdemux, "found colr");
10368 /* extract colour space info */
10369 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10370 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10372 colorspace = "sRGB";
10375 colorspace = "GRAY";
10378 colorspace = "sYUV";
10386 /* colr is required, and only values 16, 17, and 18 are specified,
10387 so error if we have no colorspace */
10390 /* extract component mapping */
10391 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10393 guint32 cmap_len = 0;
10395 cmap_len = QT_UINT32 (cmap->data);
10396 if (cmap_len >= 8) {
10397 /* normal box, subtract off header */
10399 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10400 if (cmap_len % 4 == 0) {
10401 ncomp_map = (cmap_len / 4);
10402 comp_map = g_new0 (gint32, ncomp_map);
10403 for (i = 0; i < ncomp_map; i++) {
10406 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10407 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10408 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10409 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10414 /* extract channel definitions */
10415 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10417 guint32 cdef_len = 0;
10419 cdef_len = QT_UINT32 (cdef->data);
10420 if (cdef_len >= 10) {
10421 /* normal box, subtract off header and len */
10423 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10424 if (cdef_len % 6 == 0) {
10425 nchan_def = (cdef_len / 6);
10426 chan_def = g_new0 (gint32, nchan_def);
10427 for (i = 0; i < nchan_def; i++)
10429 for (i = 0; i < nchan_def; i++) {
10430 guint16 cn, typ, asoc;
10431 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10432 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10433 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10434 if (cn < nchan_def) {
10437 chan_def[cn] = asoc;
10440 chan_def[cn] = 0; /* alpha */
10443 chan_def[cn] = -typ;
10451 gst_caps_set_simple (entry->caps,
10452 "num-components", G_TYPE_INT, ncomp, NULL);
10453 gst_caps_set_simple (entry->caps,
10454 "colorspace", G_TYPE_STRING, colorspace, NULL);
10457 GValue arr = { 0, };
10458 GValue elt = { 0, };
10460 g_value_init (&arr, GST_TYPE_ARRAY);
10461 g_value_init (&elt, G_TYPE_INT);
10462 for (i = 0; i < ncomp_map; i++) {
10463 g_value_set_int (&elt, comp_map[i]);
10464 gst_value_array_append_value (&arr, &elt);
10466 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10467 "component-map", &arr);
10468 g_value_unset (&elt);
10469 g_value_unset (&arr);
10474 GValue arr = { 0, };
10475 GValue elt = { 0, };
10477 g_value_init (&arr, GST_TYPE_ARRAY);
10478 g_value_init (&elt, G_TYPE_INT);
10479 for (i = 0; i < nchan_def; i++) {
10480 g_value_set_int (&elt, chan_def[i]);
10481 gst_value_array_append_value (&arr, &elt);
10483 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10484 "channel-definitions", &arr);
10485 g_value_unset (&elt);
10486 g_value_unset (&arr);
10490 /* some optional atoms */
10491 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10492 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10494 /* indicate possible fields in caps */
10496 data = (guint8 *) field->data + 8;
10498 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10499 (gint) * data, NULL);
10501 /* add codec_data if provided */
10506 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10507 data = prefix->data;
10508 len = QT_UINT32 (data);
10511 buf = gst_buffer_new_and_alloc (len);
10512 gst_buffer_fill (buf, 0, data + 8, len);
10513 gst_caps_set_simple (entry->caps,
10514 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10515 gst_buffer_unref (buf);
10524 GstBuffer *seqh = NULL;
10525 const guint8 *gamma_data = NULL;
10526 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
10528 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
10531 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
10532 QT_FP32 (gamma_data), NULL);
10535 /* sorry for the bad name, but we don't know what this is, other
10536 * than its own fourcc */
10537 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
10539 gst_buffer_unref (seqh);
10542 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10543 buf = gst_buffer_new_and_alloc (len);
10544 gst_buffer_fill (buf, 0, stsd_data, len);
10545 gst_caps_set_simple (entry->caps,
10546 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10547 gst_buffer_unref (buf);
10552 /* https://developer.apple.com/standards/qtff-2001.pdf,
10553 * page 92, "Video Sample Description", under table 3.1 */
10556 const gint compressor_offset =
10557 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10558 const gint min_size = compressor_offset + 32 + 2 + 2;
10561 guint16 color_table_id = 0;
10564 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10566 /* recover information on interlaced/progressive */
10567 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10571 len = QT_UINT32 (jpeg->data);
10572 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10574 if (len >= min_size) {
10575 gst_byte_reader_init (&br, jpeg->data, len);
10577 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10578 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10579 if (color_table_id != 0) {
10580 /* the spec says there can be concatenated chunks in the data, and we want
10581 * to find one called field. Walk through them. */
10582 gint offset = min_size;
10583 while (offset + 8 < len) {
10584 guint32 size = 0, tag;
10585 ok = gst_byte_reader_get_uint32_le (&br, &size);
10586 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10587 if (!ok || size < 8) {
10588 GST_WARNING_OBJECT (qtdemux,
10589 "Failed to walk optional chunk list");
10592 GST_DEBUG_OBJECT (qtdemux,
10593 "Found optional %4.4s chunk, size %u",
10594 (const char *) &tag, size);
10595 if (tag == FOURCC_fiel) {
10596 guint8 n_fields = 0, ordering = 0;
10597 gst_byte_reader_get_uint8 (&br, &n_fields);
10598 gst_byte_reader_get_uint8 (&br, &ordering);
10599 if (n_fields == 1 || n_fields == 2) {
10600 GST_DEBUG_OBJECT (qtdemux,
10601 "Found fiel tag with %u fields, ordering %u",
10602 n_fields, ordering);
10604 gst_caps_set_simple (CUR_STREAM (stream)->caps,
10605 "interlace-mode", G_TYPE_STRING, "interleaved",
10608 GST_WARNING_OBJECT (qtdemux,
10609 "Found fiel tag with invalid fields (%u)", n_fields);
10615 GST_DEBUG_OBJECT (qtdemux,
10616 "Color table ID is 0, not trying to get interlacedness");
10619 GST_WARNING_OBJECT (qtdemux,
10620 "Length of jpeg chunk is too small, not trying to get interlacedness");
10628 gst_caps_set_simple (entry->caps,
10629 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 82),
10635 GNode *xith, *xdxt;
10637 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10638 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10642 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10646 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10647 /* collect the headers and store them in a stream list so that we can
10648 * send them out first */
10649 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10659 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10660 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10663 ovc1_data = ovc1->data;
10664 ovc1_len = QT_UINT32 (ovc1_data);
10665 if (ovc1_len <= 198) {
10666 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10669 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10670 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10671 gst_caps_set_simple (entry->caps,
10672 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10673 gst_buffer_unref (buf);
10678 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10679 const guint8 *vc1_data = stsd_entry_data + 0x56;
10685 if (QT_UINT32 (vc1_data) <= len)
10686 size = QT_UINT32 (vc1_data) - 8;
10691 /* No real data, so break out */
10694 switch (QT_FOURCC (vc1_data + 0x4)) {
10695 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10699 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10700 buf = gst_buffer_new_and_alloc (size);
10701 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10702 gst_caps_set_simple (entry->caps,
10703 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10704 gst_buffer_unref (buf);
10711 vc1_data += size + 8;
10720 GST_INFO_OBJECT (qtdemux,
10721 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10722 GST_FOURCC_ARGS (fourcc), entry->caps);
10724 } else if (stream->subtype == FOURCC_soun) {
10725 int version, samplesize;
10726 guint16 compression_id;
10727 gboolean amrwb = FALSE;
10730 /* sample description entry (16) + sound sample description v0 (20) */
10734 version = QT_UINT32 (stsd_entry_data + offset);
10735 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
10736 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
10737 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
10738 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
10740 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10741 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10742 QT_UINT32 (stsd_entry_data + offset + 4));
10743 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10744 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10745 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10746 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10747 QT_UINT16 (stsd_entry_data + offset + 14));
10748 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10750 if (compression_id == 0xfffe)
10751 entry->sampled = TRUE;
10753 /* first assume uncompressed audio */
10754 entry->bytes_per_sample = samplesize / 8;
10755 entry->samples_per_frame = entry->n_channels;
10756 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
10757 entry->samples_per_packet = entry->samples_per_frame;
10758 entry->bytes_per_packet = entry->bytes_per_sample;
10762 /* Yes, these have to be hard-coded */
10765 entry->samples_per_packet = 6;
10766 entry->bytes_per_packet = 1;
10767 entry->bytes_per_frame = 1 * entry->n_channels;
10768 entry->bytes_per_sample = 1;
10769 entry->samples_per_frame = 6 * entry->n_channels;
10774 entry->samples_per_packet = 3;
10775 entry->bytes_per_packet = 1;
10776 entry->bytes_per_frame = 1 * entry->n_channels;
10777 entry->bytes_per_sample = 1;
10778 entry->samples_per_frame = 3 * entry->n_channels;
10783 entry->samples_per_packet = 64;
10784 entry->bytes_per_packet = 34;
10785 entry->bytes_per_frame = 34 * entry->n_channels;
10786 entry->bytes_per_sample = 2;
10787 entry->samples_per_frame = 64 * entry->n_channels;
10793 entry->samples_per_packet = 1;
10794 entry->bytes_per_packet = 1;
10795 entry->bytes_per_frame = 1 * entry->n_channels;
10796 entry->bytes_per_sample = 1;
10797 entry->samples_per_frame = 1 * entry->n_channels;
10802 entry->samples_per_packet = 160;
10803 entry->bytes_per_packet = 33;
10804 entry->bytes_per_frame = 33 * entry->n_channels;
10805 entry->bytes_per_sample = 2;
10806 entry->samples_per_frame = 160 * entry->n_channels;
10813 if (version == 0x00010000) {
10814 /* sample description entry (16) + sound sample description v1 (20+16) */
10825 /* only parse extra decoding config for non-pcm audio */
10826 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
10827 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
10828 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
10829 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
10831 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10832 entry->samples_per_packet);
10833 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10834 entry->bytes_per_packet);
10835 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10836 entry->bytes_per_frame);
10837 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10838 entry->bytes_per_sample);
10840 if (!entry->sampled && entry->bytes_per_packet) {
10841 entry->samples_per_frame = (entry->bytes_per_frame /
10842 entry->bytes_per_packet) * entry->samples_per_packet;
10843 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10844 entry->samples_per_frame);
10849 } else if (version == 0x00020000) {
10856 /* sample description entry (16) + sound sample description v2 (56) */
10860 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
10861 entry->rate = qtfp.fp;
10862 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
10864 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10865 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10866 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10867 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10868 QT_UINT32 (stsd_entry_data + offset + 20));
10869 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10870 QT_UINT32 (stsd_entry_data + offset + 24));
10871 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10872 QT_UINT32 (stsd_entry_data + offset + 28));
10873 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10874 QT_UINT32 (stsd_entry_data + offset + 32));
10875 } else if (version != 0x00000) {
10876 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
10881 gst_caps_unref (entry->caps);
10883 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
10884 stsd_entry_data + 32, len - 16, &codec);
10892 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10894 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10896 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10898 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10901 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10902 gst_caps_set_simple (entry->caps,
10903 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
10910 const guint8 *owma_data;
10911 const gchar *codec_name = NULL;
10915 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10916 /* FIXME this should also be gst_riff_strf_auds,
10917 * but the latter one is actually missing bits-per-sample :( */
10922 gint32 nSamplesPerSec;
10923 gint32 nAvgBytesPerSec;
10924 gint16 nBlockAlign;
10925 gint16 wBitsPerSample;
10928 WAVEFORMATEX *wfex;
10930 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10931 owma_data = stsd_entry_data;
10932 owma_len = QT_UINT32 (owma_data);
10933 if (owma_len <= 54) {
10934 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10937 wfex = (WAVEFORMATEX *) (owma_data + 36);
10938 buf = gst_buffer_new_and_alloc (owma_len - 54);
10939 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10940 if (wfex->wFormatTag == 0x0161) {
10941 codec_name = "Windows Media Audio";
10943 } else if (wfex->wFormatTag == 0x0162) {
10944 codec_name = "Windows Media Audio 9 Pro";
10946 } else if (wfex->wFormatTag == 0x0163) {
10947 codec_name = "Windows Media Audio 9 Lossless";
10948 /* is that correct? gstffmpegcodecmap.c is missing it, but
10949 * fluendo codec seems to support it */
10953 gst_caps_set_simple (entry->caps,
10954 "codec_data", GST_TYPE_BUFFER, buf,
10955 "wmaversion", G_TYPE_INT, version,
10956 "block_align", G_TYPE_INT,
10957 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
10958 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
10959 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
10960 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
10961 gst_buffer_unref (buf);
10965 codec = g_strdup (codec_name);
10971 gint len = QT_UINT32 (stsd_entry_data) - offset;
10972 const guint8 *wfex_data = stsd_entry_data + offset;
10973 const gchar *codec_name = NULL;
10975 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10976 /* FIXME this should also be gst_riff_strf_auds,
10977 * but the latter one is actually missing bits-per-sample :( */
10982 gint32 nSamplesPerSec;
10983 gint32 nAvgBytesPerSec;
10984 gint16 nBlockAlign;
10985 gint16 wBitsPerSample;
10990 /* FIXME: unify with similar wavformatex parsing code above */
10991 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10997 if (QT_UINT32 (wfex_data) <= len)
10998 size = QT_UINT32 (wfex_data) - 8;
11003 /* No real data, so break out */
11006 switch (QT_FOURCC (wfex_data + 4)) {
11007 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11009 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11014 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11015 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11016 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11017 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11018 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11019 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11020 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11022 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11023 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11024 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11025 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11026 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11027 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11029 if (wfex.wFormatTag == 0x0161) {
11030 codec_name = "Windows Media Audio";
11032 } else if (wfex.wFormatTag == 0x0162) {
11033 codec_name = "Windows Media Audio 9 Pro";
11035 } else if (wfex.wFormatTag == 0x0163) {
11036 codec_name = "Windows Media Audio 9 Lossless";
11037 /* is that correct? gstffmpegcodecmap.c is missing it, but
11038 * fluendo codec seems to support it */
11042 gst_caps_set_simple (entry->caps,
11043 "wmaversion", G_TYPE_INT, version,
11044 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11045 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11046 "width", G_TYPE_INT, wfex.wBitsPerSample,
11047 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11049 if (size > wfex.cbSize) {
11052 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11053 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11054 size - wfex.cbSize);
11055 gst_caps_set_simple (entry->caps,
11056 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11057 gst_buffer_unref (buf);
11059 GST_WARNING_OBJECT (qtdemux, "no codec data");
11064 codec = g_strdup (codec_name);
11072 wfex_data += size + 8;
11078 const guint8 *opus_data;
11079 guint8 *channel_mapping = NULL;
11082 guint8 channel_mapping_family;
11083 guint8 stream_count;
11084 guint8 coupled_count;
11087 opus_data = stsd_entry_data;
11089 channels = GST_READ_UINT8 (opus_data + 45);
11090 rate = GST_READ_UINT32_LE (opus_data + 48);
11091 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11092 stream_count = GST_READ_UINT8 (opus_data + 55);
11093 coupled_count = GST_READ_UINT8 (opus_data + 56);
11095 if (channels > 0) {
11096 channel_mapping = g_malloc (channels * sizeof (guint8));
11097 for (i = 0; i < channels; i++)
11098 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11101 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11102 channel_mapping_family, stream_count, coupled_count,
11114 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11115 GST_TAG_AUDIO_CODEC, codec, NULL);
11119 /* some bitrate info may have ended up in caps */
11120 s = gst_caps_get_structure (entry->caps, 0);
11121 gst_structure_get_int (s, "bitrate", &bitrate);
11123 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11124 GST_TAG_BITRATE, bitrate, NULL);
11127 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11128 if (!stream->protected) {
11130 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11134 if (stream->protected && fourcc == FOURCC_mp4a) {
11135 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11139 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11147 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11149 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11151 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11155 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11156 16 bits is a byte-swapped wave-style codec identifier,
11157 and we can find a WAVE header internally to a 'wave' atom here.
11158 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11159 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11162 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11163 if (len < offset + 20) {
11164 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11166 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11167 const guint8 *data = stsd_entry_data + offset + 16;
11169 GNode *waveheadernode;
11171 wavenode = g_node_new ((guint8 *) data);
11172 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11173 const guint8 *waveheader;
11176 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11177 if (waveheadernode) {
11178 waveheader = (const guint8 *) waveheadernode->data;
11179 headerlen = QT_UINT32 (waveheader);
11181 if (headerlen > 8) {
11182 gst_riff_strf_auds *header = NULL;
11183 GstBuffer *headerbuf;
11189 headerbuf = gst_buffer_new_and_alloc (headerlen);
11190 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11192 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11193 headerbuf, &header, &extra)) {
11194 gst_caps_unref (entry->caps);
11195 /* FIXME: Need to do something with the channel reorder map */
11197 gst_riff_create_audio_caps (header->format, NULL, header,
11198 extra, NULL, NULL, NULL);
11201 gst_buffer_unref (extra);
11206 GST_DEBUG ("Didn't find waveheadernode for this codec");
11208 g_node_destroy (wavenode);
11211 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11212 stream->stream_tags);
11216 /* FIXME: what is in the chunk? */
11219 gint len = QT_UINT32 (stsd_data);
11221 /* seems to be always = 116 = 0x74 */
11227 gint len = QT_UINT32 (stsd_entry_data);
11230 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11232 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11233 gst_caps_set_simple (entry->caps,
11234 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11235 gst_buffer_unref (buf);
11237 gst_caps_set_simple (entry->caps,
11238 "samplesize", G_TYPE_INT, samplesize, NULL);
11243 GNode *alac, *wave = NULL;
11245 /* apparently, m4a has this atom appended directly in the stsd entry,
11246 * while mov has it in a wave atom */
11247 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11249 /* alac now refers to stsd entry atom */
11250 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11252 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11254 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11257 const guint8 *alac_data = alac->data;
11258 gint len = QT_UINT32 (alac->data);
11262 GST_DEBUG_OBJECT (qtdemux,
11263 "discarding alac atom with unexpected len %d", len);
11265 /* codec-data contains alac atom size and prefix,
11266 * ffmpeg likes it that way, not quite gst-ish though ...*/
11267 buf = gst_buffer_new_and_alloc (len);
11268 gst_buffer_fill (buf, 0, alac->data, len);
11269 gst_caps_set_simple (entry->caps,
11270 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11271 gst_buffer_unref (buf);
11273 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11274 entry->n_channels = QT_UINT8 (alac_data + 21);
11275 entry->rate = QT_UINT32 (alac_data + 32);
11278 gst_caps_set_simple (entry->caps,
11279 "samplesize", G_TYPE_INT, samplesize, NULL);
11284 /* The codingname of the sample entry is 'fLaC' */
11285 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11288 /* The 'dfLa' box is added to the sample entry to convey
11289 initializing information for the decoder. */
11290 const GNode *dfla =
11291 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11294 const guint32 len = QT_UINT32 (dfla->data);
11296 /* Must contain at least dfLa box header (12),
11297 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11299 GST_DEBUG_OBJECT (qtdemux,
11300 "discarding dfla atom with unexpected len %d", len);
11302 /* skip dfLa header to get the METADATA_BLOCKs */
11303 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11304 const guint32 metadata_blocks_len = len - 12;
11306 gchar *stream_marker = g_strdup ("fLaC");
11307 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11308 strlen (stream_marker));
11311 guint32 remainder = 0;
11312 guint32 block_size = 0;
11313 gboolean is_last = FALSE;
11315 GValue array = G_VALUE_INIT;
11316 GValue value = G_VALUE_INIT;
11318 g_value_init (&array, GST_TYPE_ARRAY);
11319 g_value_init (&value, GST_TYPE_BUFFER);
11321 gst_value_set_buffer (&value, block);
11322 gst_value_array_append_value (&array, &value);
11323 g_value_reset (&value);
11325 gst_buffer_unref (block);
11327 /* check there's at least one METADATA_BLOCK_HEADER's worth
11328 * of data, and we haven't already finished parsing */
11329 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11330 remainder = metadata_blocks_len - index;
11332 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11334 (metadata_blocks[index + 1] << 16) +
11335 (metadata_blocks[index + 2] << 8) +
11336 metadata_blocks[index + 3];
11338 /* be careful not to read off end of box */
11339 if (block_size > remainder) {
11343 is_last = metadata_blocks[index] >> 7;
11345 block = gst_buffer_new_and_alloc (block_size);
11347 gst_buffer_fill (block, 0, &metadata_blocks[index],
11350 gst_value_set_buffer (&value, block);
11351 gst_value_array_append_value (&array, &value);
11352 g_value_reset (&value);
11354 gst_buffer_unref (block);
11356 index += block_size;
11359 /* only append the metadata if we successfully read all of it */
11361 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11362 (stream)->caps, 0), "streamheader", &array);
11364 GST_WARNING_OBJECT (qtdemux,
11365 "discarding all METADATA_BLOCKs due to invalid "
11366 "block_size %d at idx %d, rem %d", block_size, index,
11370 g_value_unset (&value);
11371 g_value_unset (&array);
11373 /* The sample rate obtained from the stsd may not be accurate
11374 * since it cannot represent rates greater than 65535Hz, so
11375 * override that value with the sample rate from the
11376 * METADATA_BLOCK_STREAMINFO block */
11377 CUR_STREAM (stream)->rate =
11378 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11389 gint len = QT_UINT32 (stsd_entry_data);
11392 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11395 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11397 /* If we have enough data, let's try to get the 'damr' atom. See
11398 * the 3GPP container spec (26.244) for more details. */
11399 if ((len - 0x34) > 8 &&
11400 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11401 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11402 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11405 gst_caps_set_simple (entry->caps,
11406 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11407 gst_buffer_unref (buf);
11413 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11414 gint len = QT_UINT32 (stsd_entry_data);
11417 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11419 if (sound_version == 1) {
11420 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11421 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11422 guint8 codec_data[2];
11424 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11426 gint sample_rate_index =
11427 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11429 /* build AAC codec data */
11430 codec_data[0] = profile << 3;
11431 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11432 codec_data[1] = (sample_rate_index & 0x01) << 7;
11433 codec_data[1] |= (channels & 0xF) << 3;
11435 buf = gst_buffer_new_and_alloc (2);
11436 gst_buffer_fill (buf, 0, codec_data, 2);
11437 gst_caps_set_simple (entry->caps,
11438 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11439 gst_buffer_unref (buf);
11445 GST_INFO_OBJECT (qtdemux,
11446 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11450 GST_INFO_OBJECT (qtdemux,
11451 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11452 GST_FOURCC_ARGS (fourcc), entry->caps);
11454 } else if (stream->subtype == FOURCC_strm) {
11455 if (fourcc == FOURCC_rtsp) {
11456 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11458 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11459 GST_FOURCC_ARGS (fourcc));
11460 goto unknown_stream;
11462 entry->sampled = TRUE;
11463 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11464 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11466 entry->sampled = TRUE;
11467 entry->sparse = TRUE;
11470 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11473 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11474 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11479 /* hunt for sort-of codec data */
11483 GNode *mp4s = NULL;
11484 GNode *esds = NULL;
11486 /* look for palette in a stsd->mp4s->esds sub-atom */
11487 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11489 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11490 if (esds == NULL) {
11492 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11496 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11497 stream->stream_tags);
11501 GST_INFO_OBJECT (qtdemux,
11502 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11505 GST_INFO_OBJECT (qtdemux,
11506 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11507 GST_FOURCC_ARGS (fourcc), entry->caps);
11509 /* everything in 1 sample */
11510 entry->sampled = TRUE;
11513 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11516 if (entry->caps == NULL)
11517 goto unknown_stream;
11520 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11521 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11527 /* promote to sampled format */
11528 if (entry->fourcc == FOURCC_samr) {
11529 /* force mono 8000 Hz for AMR */
11530 entry->sampled = TRUE;
11531 entry->n_channels = 1;
11532 entry->rate = 8000;
11533 } else if (entry->fourcc == FOURCC_sawb) {
11534 /* force mono 16000 Hz for AMR-WB */
11535 entry->sampled = TRUE;
11536 entry->n_channels = 1;
11537 entry->rate = 16000;
11538 } else if (entry->fourcc == FOURCC_mp4a) {
11539 entry->sampled = TRUE;
11543 stsd_entry_data += len;
11544 remaining_stsd_len -= len;
11548 /* collect sample information */
11549 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11550 goto samples_failed;
11552 if (qtdemux->fragmented) {
11555 /* need all moov samples as basis; probably not many if any at all */
11556 /* prevent moof parsing taking of at this time */
11557 offset = qtdemux->moof_offset;
11558 qtdemux->moof_offset = 0;
11559 if (stream->n_samples &&
11560 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11561 qtdemux->moof_offset = offset;
11562 goto samples_failed;
11564 qtdemux->moof_offset = 0;
11565 /* movie duration more reliable in this case (e.g. mehd) */
11566 if (qtdemux->segment.duration &&
11567 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11569 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11572 /* configure segments */
11573 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11574 goto segments_failed;
11576 /* add some language tag, if useful */
11577 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11578 strcmp (stream->lang_id, "und")) {
11579 const gchar *lang_code;
11581 /* convert ISO 639-2 code to ISO 639-1 */
11582 lang_code = gst_tag_get_language_code (stream->lang_id);
11583 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11584 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11587 /* Check for UDTA tags */
11588 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11589 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11592 /* now we are ready to add the stream */
11593 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11594 goto too_many_streams;
11596 if (!qtdemux->got_moov) {
11597 qtdemux->streams[qtdemux->n_streams] = stream;
11598 qtdemux->n_streams++;
11599 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11607 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11609 gst_qtdemux_stream_free (qtdemux, stream);
11614 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11615 (_("This file is corrupt and cannot be played.")), (NULL));
11617 gst_qtdemux_stream_free (qtdemux, stream);
11622 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11624 gst_qtdemux_stream_free (qtdemux, stream);
11630 /* we posted an error already */
11631 /* free stbl sub-atoms */
11632 gst_qtdemux_stbl_free (stream);
11634 gst_qtdemux_stream_free (qtdemux, stream);
11639 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11642 gst_qtdemux_stream_free (qtdemux, stream);
11647 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11648 GST_FOURCC_ARGS (stream->subtype));
11650 gst_qtdemux_stream_free (qtdemux, stream);
11655 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11656 (_("This file contains too many streams. Only playing first %d"),
11657 GST_QTDEMUX_MAX_STREAMS), (NULL));
11662 /* If we can estimate the overall bitrate, and don't have information about the
11663 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11664 * the overall bitrate minus the sum of the bitrates of all other streams. This
11665 * should be useful for the common case where we have one audio and one video
11666 * stream and can estimate the bitrate of one, but not the other. */
11668 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11670 QtDemuxStream *stream = NULL;
11671 gint64 size, sys_bitrate, sum_bitrate = 0;
11672 GstClockTime duration;
11676 if (qtdemux->fragmented)
11679 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11681 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11683 GST_DEBUG_OBJECT (qtdemux,
11684 "Size in bytes of the stream not known - bailing");
11688 /* Subtract the header size */
11689 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11690 size, qtdemux->header_size);
11692 if (size < qtdemux->header_size)
11695 size = size - qtdemux->header_size;
11697 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11698 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11702 for (i = 0; i < qtdemux->n_streams; i++) {
11703 switch (qtdemux->streams[i]->subtype) {
11706 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11707 CUR_STREAM (qtdemux->streams[i])->caps);
11708 /* retrieve bitrate, prefer avg then max */
11710 if (qtdemux->streams[i]->stream_tags) {
11711 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11712 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11713 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11714 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11715 GST_TAG_NOMINAL_BITRATE, &bitrate);
11716 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11717 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11718 GST_TAG_BITRATE, &bitrate);
11719 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11722 sum_bitrate += bitrate;
11725 GST_DEBUG_OBJECT (qtdemux,
11726 ">1 stream with unknown bitrate - bailing");
11729 stream = qtdemux->streams[i];
11733 /* For other subtypes, we assume no significant impact on bitrate */
11739 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11743 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11745 if (sys_bitrate < sum_bitrate) {
11746 /* This can happen, since sum_bitrate might be derived from maximum
11747 * bitrates and not average bitrates */
11748 GST_DEBUG_OBJECT (qtdemux,
11749 "System bitrate less than sum bitrate - bailing");
11753 bitrate = sys_bitrate - sum_bitrate;
11754 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11755 ", Stream bitrate = %u", sys_bitrate, bitrate);
11757 if (!stream->stream_tags)
11758 stream->stream_tags = gst_tag_list_new_empty ();
11760 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11762 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11763 GST_TAG_BITRATE, bitrate, NULL);
11766 static GstFlowReturn
11767 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11770 GstFlowReturn ret = GST_FLOW_OK;
11772 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11774 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11775 QtDemuxStream *stream = qtdemux->streams[i];
11776 guint32 sample_num = 0;
11778 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11779 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11781 if (qtdemux->fragmented) {
11782 /* need all moov samples first */
11783 GST_OBJECT_LOCK (qtdemux);
11784 while (stream->n_samples == 0)
11785 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11787 GST_OBJECT_UNLOCK (qtdemux);
11789 /* discard any stray moof */
11790 qtdemux->moof_offset = 0;
11793 /* prepare braking */
11794 if (ret != GST_FLOW_ERROR)
11797 /* in pull mode, we should have parsed some sample info by now;
11798 * and quite some code will not handle no samples.
11799 * in push mode, we'll just have to deal with it */
11800 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11801 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11802 gst_qtdemux_remove_stream (qtdemux, i);
11807 /* parse the initial sample for use in setting the frame rate cap */
11808 while (sample_num == 0 && sample_num < stream->n_samples) {
11809 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11813 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11814 stream->first_duration = stream->samples[0].duration;
11815 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11816 stream->track_id, stream->first_duration);
11823 static GstFlowReturn
11824 qtdemux_expose_streams (GstQTDemux * qtdemux)
11827 GSList *oldpads = NULL;
11830 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11832 for (i = 0; i < qtdemux->n_streams; i++) {
11833 QtDemuxStream *stream = qtdemux->streams[i];
11834 GstPad *oldpad = stream->pad;
11837 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11838 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11840 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11841 stream->track_id == qtdemux->chapters_track_id) {
11842 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11843 so that it doesn't look like a subtitle track */
11844 gst_qtdemux_remove_stream (qtdemux, i);
11849 /* now we have all info and can expose */
11850 list = stream->stream_tags;
11851 stream->stream_tags = NULL;
11853 oldpads = g_slist_prepend (oldpads, oldpad);
11854 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11855 return GST_FLOW_ERROR;
11858 gst_qtdemux_guess_bitrate (qtdemux);
11860 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11862 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11863 GstPad *oldpad = iter->data;
11866 event = gst_event_new_eos ();
11867 if (qtdemux->segment_seqnum)
11868 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11870 gst_pad_push_event (oldpad, event);
11871 gst_pad_set_active (oldpad, FALSE);
11872 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11873 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11874 gst_object_unref (oldpad);
11877 /* check if we should post a redirect in case there is a single trak
11878 * and it is a redirecting trak */
11879 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11882 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11883 "an external content");
11884 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11885 gst_structure_new ("redirect",
11886 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11888 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11889 qtdemux->posted_redirect = TRUE;
11892 for (i = 0; i < qtdemux->n_streams; i++) {
11893 QtDemuxStream *stream = qtdemux->streams[i];
11895 qtdemux_do_allocation (qtdemux, stream);
11898 qtdemux->exposed = TRUE;
11899 return GST_FLOW_OK;
11902 /* check if major or compatible brand is 3GP */
11903 static inline gboolean
11904 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11907 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11909 } else if (qtdemux->comp_brands != NULL) {
11913 gboolean res = FALSE;
11915 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11918 while (size >= 4) {
11919 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11924 gst_buffer_unmap (qtdemux->comp_brands, &map);
11931 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11932 static inline gboolean
11933 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11935 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11936 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11937 || fourcc == FOURCC_albm;
11941 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11942 const char *tag, const char *dummy, GNode * node)
11944 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11948 gdouble longitude, latitude, altitude;
11951 len = QT_UINT32 (node->data);
11958 /* TODO: language code skipped */
11960 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11963 /* do not alarm in trivial case, but bail out otherwise */
11964 if (*(data + offset) != 0) {
11965 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11969 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11970 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11971 offset += strlen (name);
11975 if (len < offset + 2 + 4 + 4 + 4)
11978 /* +1 +1 = skip null-terminator and location role byte */
11980 /* table in spec says unsigned, semantics say negative has meaning ... */
11981 longitude = QT_SFP32 (data + offset);
11984 latitude = QT_SFP32 (data + offset);
11987 altitude = QT_SFP32 (data + offset);
11989 /* one invalid means all are invalid */
11990 if (longitude >= -180.0 && longitude <= 180.0 &&
11991 latitude >= -90.0 && latitude <= 90.0) {
11992 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11993 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11994 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11995 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11998 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12005 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12012 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12013 const char *tag, const char *dummy, GNode * node)
12019 len = QT_UINT32 (node->data);
12023 y = QT_UINT16 ((guint8 *) node->data + 12);
12025 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12028 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12030 date = g_date_new_dmy (1, 1, y);
12031 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12032 g_date_free (date);
12036 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12037 const char *tag, const char *dummy, GNode * node)
12040 char *tag_str = NULL;
12045 len = QT_UINT32 (node->data);
12050 entity = (guint8 *) node->data + offset;
12051 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12052 GST_DEBUG_OBJECT (qtdemux,
12053 "classification info: %c%c%c%c invalid classification entity",
12054 entity[0], entity[1], entity[2], entity[3]);
12059 table = QT_UINT16 ((guint8 *) node->data + offset);
12061 /* Language code skipped */
12065 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12066 * XXXX: classification entity, fixed length 4 chars.
12067 * Y[YYYY]: classification table, max 5 chars.
12069 tag_str = g_strdup_printf ("----://%u/%s",
12070 table, (char *) node->data + offset);
12072 /* memcpy To be sure we're preserving byte order */
12073 memcpy (tag_str, entity, 4);
12074 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12076 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12085 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12091 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12092 const char *tag, const char *dummy, GNode * node)
12094 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12100 gboolean ret = TRUE;
12101 const gchar *charset = NULL;
12103 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12105 len = QT_UINT32 (data->data);
12106 type = QT_UINT32 ((guint8 *) data->data + 8);
12107 if (type == 0x00000001 && len > 16) {
12108 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12111 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12112 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12115 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12119 len = QT_UINT32 (node->data);
12120 type = QT_UINT32 ((guint8 *) node->data + 4);
12121 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12125 /* Type starts with the (C) symbol, so the next data is a list
12126 * of (string size(16), language code(16), string) */
12128 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12129 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12131 /* the string + fourcc + size + 2 16bit fields,
12132 * means that there are more tags in this atom */
12133 if (len > str_len + 8 + 4) {
12134 /* TODO how to represent the same tag in different languages? */
12135 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12136 "text alternatives, reading only first one");
12140 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12141 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12143 if (lang_code < 0x800) { /* MAC encoded string */
12146 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12147 QT_FOURCC ((guint8 *) node->data + 4))) {
12148 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12150 /* we go for 3GP style encoding if major brands claims so,
12151 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12152 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12153 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12154 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12156 /* 16-bit Language code is ignored here as well */
12157 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12164 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12165 ret = FALSE; /* may have to fallback */
12168 GError *err = NULL;
12170 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12171 charset, NULL, NULL, &err);
12173 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12174 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12176 g_error_free (err);
12179 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12180 len - offset, env_vars);
12183 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12184 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12188 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12195 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12196 const char *tag, const char *dummy, GNode * node)
12198 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12202 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12203 const char *tag, const char *dummy, GNode * node)
12205 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12207 char *s, *t, *k = NULL;
12212 /* first try normal string tag if major brand not 3GP */
12213 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12214 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12215 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12216 * let's try it 3gpp way after minor safety check */
12218 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12224 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12228 len = QT_UINT32 (data);
12232 count = QT_UINT8 (data + 14);
12234 for (; count; count--) {
12237 if (offset + 1 > len)
12239 slen = QT_UINT8 (data + offset);
12241 if (offset + slen > len)
12243 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12246 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12248 t = g_strjoin (",", k, s, NULL);
12256 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12263 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12264 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12273 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12279 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12280 const char *tag1, const char *tag2, GNode * node)
12287 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12289 len = QT_UINT32 (data->data);
12290 type = QT_UINT32 ((guint8 *) data->data + 8);
12291 if (type == 0x00000000 && len >= 22) {
12292 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12293 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12295 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12296 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12299 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12300 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12307 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12308 const char *tag1, const char *dummy, GNode * node)
12315 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12317 len = QT_UINT32 (data->data);
12318 type = QT_UINT32 ((guint8 *) data->data + 8);
12319 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12320 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12321 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12322 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12324 /* do not add bpm=0 */
12325 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12326 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12334 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12335 const char *tag1, const char *dummy, GNode * node)
12342 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12344 len = QT_UINT32 (data->data);
12345 type = QT_UINT32 ((guint8 *) data->data + 8);
12346 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12347 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12348 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12349 num = QT_UINT32 ((guint8 *) data->data + 16);
12351 /* do not add num=0 */
12352 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12353 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12360 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12361 const char *tag1, const char *dummy, GNode * node)
12368 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12370 len = QT_UINT32 (data->data);
12371 type = QT_UINT32 ((guint8 *) data->data + 8);
12372 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12373 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12374 GstTagImageType image_type;
12376 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12377 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12379 image_type = GST_TAG_IMAGE_TYPE_NONE;
12382 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12383 len - 16, image_type))) {
12384 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12385 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12386 gst_sample_unref (sample);
12393 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12394 const char *tag, const char *dummy, GNode * node)
12401 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12403 len = QT_UINT32 (data->data);
12404 type = QT_UINT32 ((guint8 *) data->data + 8);
12405 if (type == 0x00000001 && len > 16) {
12406 guint y, m = 1, d = 1;
12409 s = g_strndup ((char *) data->data + 16, len - 16);
12410 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12411 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12412 if (ret >= 1 && y > 1500 && y < 3000) {
12415 date = g_date_new_dmy (d, m, y);
12416 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12417 g_date_free (date);
12419 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12427 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12428 const char *tag, const char *dummy, GNode * node)
12432 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12434 /* re-route to normal string tag if major brand says so
12435 * or no data atom and compatible brand suggests so */
12436 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12437 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12438 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12443 guint len, type, n;
12445 len = QT_UINT32 (data->data);
12446 type = QT_UINT32 ((guint8 *) data->data + 8);
12447 if (type == 0x00000000 && len >= 18) {
12448 n = QT_UINT16 ((guint8 *) data->data + 16);
12450 const gchar *genre;
12452 genre = gst_tag_id3_genre_get (n - 1);
12453 if (genre != NULL) {
12454 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12455 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12463 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12464 const gchar * tag, guint8 * data, guint32 datasize)
12469 /* make a copy to have \0 at the end */
12470 datacopy = g_strndup ((gchar *) data, datasize);
12472 /* convert the str to double */
12473 if (sscanf (datacopy, "%lf", &value) == 1) {
12474 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12475 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12477 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12485 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12486 const char *tag, const char *tag_bis, GNode * node)
12495 const gchar *meanstr;
12496 const gchar *namestr;
12498 /* checking the whole ---- atom size for consistency */
12499 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12500 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12504 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12506 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12510 meansize = QT_UINT32 (mean->data);
12511 if (meansize <= 12) {
12512 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12515 meanstr = ((gchar *) mean->data) + 12;
12518 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12520 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12524 namesize = QT_UINT32 (name->data);
12525 if (namesize <= 12) {
12526 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12529 namestr = ((gchar *) name->data) + 12;
12537 * uint24 - data type
12541 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12543 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12546 datasize = QT_UINT32 (data->data);
12547 if (datasize <= 16) {
12548 GST_WARNING_OBJECT (demux, "Data atom too small");
12551 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12553 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12554 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12555 static const struct
12557 const gchar name[28];
12558 const gchar tag[28];
12561 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12562 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12563 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12564 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12565 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12566 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12567 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12568 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12572 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12573 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12574 switch (gst_tag_get_type (tags[i].tag)) {
12575 case G_TYPE_DOUBLE:
12576 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12577 ((guint8 *) data->data) + 16, datasize - 16);
12579 case G_TYPE_STRING:
12580 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12589 if (i == G_N_ELEMENTS (tags))
12599 #ifndef GST_DISABLE_GST_DEBUG
12601 gchar *namestr_dbg;
12602 gchar *meanstr_dbg;
12604 meanstr_dbg = g_strndup (meanstr, meansize);
12605 namestr_dbg = g_strndup (namestr, namesize);
12607 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12608 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12610 g_free (namestr_dbg);
12611 g_free (meanstr_dbg);
12618 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12619 const char *tag_bis, GNode * node)
12624 GstTagList *id32_taglist = NULL;
12626 GST_LOG_OBJECT (demux, "parsing ID32");
12629 len = GST_READ_UINT32_BE (data);
12631 /* need at least full box and language tag */
12635 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12636 gst_buffer_fill (buf, 0, data + 14, len - 14);
12638 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12639 if (id32_taglist) {
12640 GST_LOG_OBJECT (demux, "parsing ok");
12641 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12642 gst_tag_list_unref (id32_taglist);
12644 GST_LOG_OBJECT (demux, "parsing failed");
12647 gst_buffer_unref (buf);
12650 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12651 const char *tag, const char *tag_bis, GNode * node);
12654 FOURCC_pcst -> if media is a podcast -> bool
12655 FOURCC_cpil -> if media is part of a compilation -> bool
12656 FOURCC_pgap -> if media is part of a gapless context -> bool
12657 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12660 static const struct
12663 const gchar *gst_tag;
12664 const gchar *gst_tag_bis;
12665 const GstQTDemuxAddTagFunc func;
12668 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12669 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12670 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12671 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12672 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12673 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12674 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12675 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12676 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12677 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12678 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12679 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12680 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12681 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12682 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12683 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12684 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12685 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12686 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12687 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12688 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12689 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12690 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12691 qtdemux_tag_add_num}, {
12692 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12693 qtdemux_tag_add_num}, {
12694 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12695 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12696 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12697 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12698 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12699 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12700 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12701 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12702 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12703 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12704 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12705 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12706 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12707 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12708 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12709 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12710 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12711 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12712 qtdemux_tag_add_classification}, {
12713 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12714 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12715 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12717 /* This is a special case, some tags are stored in this
12718 * 'reverse dns naming', according to:
12719 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12722 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12723 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12724 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12727 struct _GstQtDemuxTagList
12730 GstTagList *taglist;
12732 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12735 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12741 const gchar *style;
12746 GstQTDemux *demux = qtdemuxtaglist->demux;
12747 GstTagList *taglist = qtdemuxtaglist->taglist;
12750 len = QT_UINT32 (data);
12751 buf = gst_buffer_new_and_alloc (len);
12752 gst_buffer_fill (buf, 0, data, len);
12754 /* heuristic to determine style of tag */
12755 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12756 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12758 else if (demux->major_brand == FOURCC_qt__)
12759 style = "quicktime";
12760 /* fall back to assuming iso/3gp tag style */
12764 /* santize the name for the caps. */
12765 for (i = 0; i < 4; i++) {
12766 guint8 d = data[4 + i];
12767 if (g_ascii_isalnum (d))
12768 ndata[i] = g_ascii_tolower (d);
12773 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12774 ndata[0], ndata[1], ndata[2], ndata[3]);
12775 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12777 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12778 sample = gst_sample_new (buf, NULL, NULL, s);
12779 gst_buffer_unref (buf);
12780 g_free (media_type);
12782 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12785 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12786 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12788 gst_sample_unref (sample);
12792 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12799 GstQtDemuxTagList demuxtaglist;
12801 demuxtaglist.demux = qtdemux;
12802 demuxtaglist.taglist = taglist;
12804 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12805 if (meta != NULL) {
12806 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12807 if (ilst == NULL) {
12808 GST_LOG_OBJECT (qtdemux, "no ilst");
12813 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12817 while (i < G_N_ELEMENTS (add_funcs)) {
12818 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12822 len = QT_UINT32 (node->data);
12824 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12825 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12827 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12828 add_funcs[i].gst_tag_bis, node);
12830 g_node_destroy (node);
12836 /* parsed nodes have been removed, pass along remainder as blob */
12837 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12838 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12840 /* parse up XMP_ node if existing */
12841 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12842 if (xmp_ != NULL) {
12844 GstTagList *xmptaglist;
12846 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12847 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12848 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12849 gst_buffer_unref (buf);
12851 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12853 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12859 GstStructure *structure; /* helper for sort function */
12861 guint min_req_bitrate;
12862 guint min_req_qt_version;
12866 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12868 GstQtReference *ref_a = (GstQtReference *) a;
12869 GstQtReference *ref_b = (GstQtReference *) b;
12871 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12872 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12874 /* known bitrates go before unknown; higher bitrates go first */
12875 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12878 /* sort the redirects and post a message for the application.
12881 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12883 GstQtReference *best;
12886 GValue list_val = { 0, };
12889 g_assert (references != NULL);
12891 references = g_list_sort (references, qtdemux_redirects_sort_func);
12893 best = (GstQtReference *) references->data;
12895 g_value_init (&list_val, GST_TYPE_LIST);
12897 for (l = references; l != NULL; l = l->next) {
12898 GstQtReference *ref = (GstQtReference *) l->data;
12899 GValue struct_val = { 0, };
12901 ref->structure = gst_structure_new ("redirect",
12902 "new-location", G_TYPE_STRING, ref->location, NULL);
12904 if (ref->min_req_bitrate > 0) {
12905 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12906 ref->min_req_bitrate, NULL);
12909 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12910 g_value_set_boxed (&struct_val, ref->structure);
12911 gst_value_list_append_value (&list_val, &struct_val);
12912 g_value_unset (&struct_val);
12913 /* don't free anything here yet, since we need best->structure below */
12916 g_assert (best != NULL);
12917 s = gst_structure_copy (best->structure);
12919 if (g_list_length (references) > 1) {
12920 gst_structure_set_value (s, "locations", &list_val);
12923 g_value_unset (&list_val);
12925 for (l = references; l != NULL; l = l->next) {
12926 GstQtReference *ref = (GstQtReference *) l->data;
12928 gst_structure_free (ref->structure);
12929 g_free (ref->location);
12932 g_list_free (references);
12934 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12935 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12936 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12937 qtdemux->posted_redirect = TRUE;
12940 /* look for redirect nodes, collect all redirect information and
12944 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12946 GNode *rmra, *rmda, *rdrf;
12948 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12950 GList *redirects = NULL;
12952 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12954 GstQtReference ref = { NULL, NULL, 0, 0 };
12955 GNode *rmdr, *rmvc;
12957 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12958 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12959 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12960 ref.min_req_bitrate);
12963 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12964 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12965 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12967 #ifndef GST_DISABLE_GST_DEBUG
12968 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12970 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12972 GST_LOG_OBJECT (qtdemux,
12973 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12974 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12975 bitmask, check_type);
12976 if (package == FOURCC_qtim && check_type == 0) {
12977 ref.min_req_qt_version = version;
12981 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12987 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12988 if (ref_len > 20) {
12989 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12990 ref_data = (guint8 *) rdrf->data + 20;
12991 if (ref_type == FOURCC_alis) {
12992 guint record_len, record_version, fn_len;
12994 if (ref_len > 70) {
12995 /* MacOSX alias record, google for alias-layout.txt */
12996 record_len = QT_UINT16 (ref_data + 4);
12997 record_version = QT_UINT16 (ref_data + 4 + 2);
12998 fn_len = QT_UINT8 (ref_data + 50);
12999 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13000 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13003 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13006 } else if (ref_type == FOURCC_url_) {
13007 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13009 GST_DEBUG_OBJECT (qtdemux,
13010 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13011 GST_FOURCC_ARGS (ref_type));
13013 if (ref.location != NULL) {
13014 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13016 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13018 GST_WARNING_OBJECT (qtdemux,
13019 "Failed to extract redirect location from rdrf atom");
13022 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13026 /* look for others */
13027 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13030 if (redirects != NULL) {
13031 qtdemux_process_redirects (qtdemux, redirects);
13037 static GstTagList *
13038 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13042 if (tags == NULL) {
13043 tags = gst_tag_list_new_empty ();
13044 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13047 if (qtdemux->major_brand == FOURCC_mjp2)
13048 fmt = "Motion JPEG 2000";
13049 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13051 else if (qtdemux->major_brand == FOURCC_qt__)
13053 else if (qtdemux->fragmented)
13056 fmt = "ISO MP4/M4A";
13058 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13059 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13061 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13067 /* we have read the complete moov node now.
13068 * This function parses all of the relevant info, creates the traks and
13069 * prepares all data structures for playback
13072 qtdemux_parse_tree (GstQTDemux * qtdemux)
13078 GstClockTime duration;
13080 guint64 creation_time;
13081 GstDateTime *datetime = NULL;
13084 /* make sure we have a usable taglist */
13085 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13087 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13088 if (mvhd == NULL) {
13089 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13090 return qtdemux_parse_redirects (qtdemux);
13093 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13094 if (version == 1) {
13095 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13096 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13097 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13098 } else if (version == 0) {
13099 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13100 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13101 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13103 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13107 /* Moving qt creation time (secs since 1904) to unix time */
13108 if (creation_time != 0) {
13109 /* Try to use epoch first as it should be faster and more commonly found */
13110 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13113 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13114 /* some data cleansing sanity */
13115 g_get_current_time (&now);
13116 if (now.tv_sec + 24 * 3600 < creation_time) {
13117 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13119 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13122 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13123 GDateTime *dt, *dt_local;
13125 dt = g_date_time_add_seconds (base_dt, creation_time);
13126 dt_local = g_date_time_to_local (dt);
13127 datetime = gst_date_time_new_from_g_date_time (dt_local);
13129 g_date_time_unref (base_dt);
13130 g_date_time_unref (dt);
13134 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13135 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13137 gst_date_time_unref (datetime);
13140 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13141 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13143 /* check for fragmented file and get some (default) data */
13144 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13147 GstByteReader mehd_data;
13149 /* let track parsing or anyone know weird stuff might happen ... */
13150 qtdemux->fragmented = TRUE;
13152 /* compensate for total duration */
13153 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13155 qtdemux_parse_mehd (qtdemux, &mehd_data);
13158 /* set duration in the segment info */
13159 gst_qtdemux_get_duration (qtdemux, &duration);
13161 qtdemux->segment.duration = duration;
13162 /* also do not exceed duration; stop is set that way post seek anyway,
13163 * and segment activation falls back to duration,
13164 * whereas loop only checks stop, so let's align this here as well */
13165 qtdemux->segment.stop = duration;
13168 /* parse all traks */
13169 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13171 qtdemux_parse_trak (qtdemux, trak);
13172 /* iterate all siblings */
13173 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13176 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13179 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13181 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13183 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13186 /* maybe also some tags in meta box */
13187 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13189 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13190 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13192 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13195 /* parse any protection system info */
13196 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13198 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13199 qtdemux_parse_pssh (qtdemux, pssh);
13200 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13203 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13208 /* taken from ffmpeg */
13210 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13222 len = (len << 7) | (c & 0x7f);
13230 /* this can change the codec originally present in @list */
13232 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13233 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13235 int len = QT_UINT32 (esds->data);
13236 guint8 *ptr = esds->data;
13237 guint8 *end = ptr + len;
13239 guint8 *data_ptr = NULL;
13241 guint8 object_type_id = 0;
13242 const char *codec_name = NULL;
13243 GstCaps *caps = NULL;
13245 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13247 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13249 while (ptr + 1 < end) {
13250 tag = QT_UINT8 (ptr);
13251 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13253 len = read_descr_size (ptr, end, &ptr);
13254 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13256 /* Check the stated amount of data is available for reading */
13257 if (len < 0 || ptr + len > end)
13261 case ES_DESCRIPTOR_TAG:
13262 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13263 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13266 case DECODER_CONFIG_DESC_TAG:{
13267 guint max_bitrate, avg_bitrate;
13269 object_type_id = QT_UINT8 (ptr);
13270 max_bitrate = QT_UINT32 (ptr + 5);
13271 avg_bitrate = QT_UINT32 (ptr + 9);
13272 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13273 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13274 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13275 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13276 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13277 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13278 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13279 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13281 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13282 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13283 avg_bitrate, NULL);
13288 case DECODER_SPECIFIC_INFO_TAG:
13289 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13290 if (object_type_id == 0xe0 && len == 0x40) {
13296 GST_DEBUG_OBJECT (qtdemux,
13297 "Have VOBSUB palette. Creating palette event");
13298 /* move to decConfigDescr data and read palette */
13300 for (i = 0; i < 16; i++) {
13301 clut[i] = QT_UINT32 (data);
13305 s = gst_structure_new ("application/x-gst-dvd", "event",
13306 G_TYPE_STRING, "dvd-spu-clut-change",
13307 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13308 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13309 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13310 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13311 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13312 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13313 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13314 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13317 /* store event and trigger custom processing */
13318 stream->pending_event =
13319 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13321 /* Generic codec_data handler puts it on the caps */
13328 case SL_CONFIG_DESC_TAG:
13329 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13333 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13335 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13341 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13342 * in use, and should also be used to override some other parameters for some
13344 switch (object_type_id) {
13345 case 0x20: /* MPEG-4 */
13346 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13347 * profile_and_level_indication */
13348 if (data_ptr != NULL && data_len >= 5 &&
13349 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13350 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13351 data_ptr + 4, data_len - 4);
13353 break; /* Nothing special needed here */
13354 case 0x21: /* H.264 */
13355 codec_name = "H.264 / AVC";
13356 caps = gst_caps_new_simple ("video/x-h264",
13357 "stream-format", G_TYPE_STRING, "avc",
13358 "alignment", G_TYPE_STRING, "au", NULL);
13360 case 0x40: /* AAC (any) */
13361 case 0x66: /* AAC Main */
13362 case 0x67: /* AAC LC */
13363 case 0x68: /* AAC SSR */
13364 /* Override channels and rate based on the codec_data, as it's often
13366 /* Only do so for basic setup without HE-AAC extension */
13367 if (data_ptr && data_len == 2) {
13368 guint channels, rate;
13370 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13372 entry->n_channels = channels;
13374 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13376 entry->rate = rate;
13379 /* Set level and profile if possible */
13380 if (data_ptr != NULL && data_len >= 2) {
13381 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13382 data_ptr, data_len);
13384 const gchar *profile_str = NULL;
13387 guint8 *codec_data;
13388 gint rate_idx, profile;
13390 /* No codec_data, let's invent something.
13391 * FIXME: This is wrong for SBR! */
13393 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13395 buffer = gst_buffer_new_and_alloc (2);
13396 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13397 codec_data = map.data;
13400 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13403 switch (object_type_id) {
13405 profile_str = "main";
13409 profile_str = "lc";
13413 profile_str = "ssr";
13421 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13423 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13425 gst_buffer_unmap (buffer, &map);
13426 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13427 GST_TYPE_BUFFER, buffer, NULL);
13428 gst_buffer_unref (buffer);
13431 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13432 G_TYPE_STRING, profile_str, NULL);
13436 case 0x60: /* MPEG-2, various profiles */
13442 codec_name = "MPEG-2 video";
13443 caps = gst_caps_new_simple ("video/mpeg",
13444 "mpegversion", G_TYPE_INT, 2,
13445 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13447 case 0x69: /* MPEG-2 BC audio */
13448 case 0x6B: /* MPEG-1 audio */
13449 caps = gst_caps_new_simple ("audio/mpeg",
13450 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13451 codec_name = "MPEG-1 audio";
13453 case 0x6A: /* MPEG-1 */
13454 codec_name = "MPEG-1 video";
13455 caps = gst_caps_new_simple ("video/mpeg",
13456 "mpegversion", G_TYPE_INT, 1,
13457 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13459 case 0x6C: /* MJPEG */
13461 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13463 codec_name = "Motion-JPEG";
13465 case 0x6D: /* PNG */
13467 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13469 codec_name = "PNG still images";
13471 case 0x6E: /* JPEG2000 */
13472 codec_name = "JPEG-2000";
13473 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13475 case 0xA4: /* Dirac */
13476 codec_name = "Dirac";
13477 caps = gst_caps_new_empty_simple ("video/x-dirac");
13479 case 0xA5: /* AC3 */
13480 codec_name = "AC-3 audio";
13481 caps = gst_caps_new_simple ("audio/x-ac3",
13482 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13484 case 0xA9: /* AC3 */
13485 codec_name = "DTS audio";
13486 caps = gst_caps_new_simple ("audio/x-dts",
13487 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13489 case 0xE1: /* QCELP */
13490 /* QCELP, the codec_data is a riff tag (little endian) with
13491 * 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). */
13492 caps = gst_caps_new_empty_simple ("audio/qcelp");
13493 codec_name = "QCELP";
13499 /* If we have a replacement caps, then change our caps for this stream */
13501 gst_caps_unref (entry->caps);
13502 entry->caps = caps;
13505 if (codec_name && list)
13506 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13507 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13509 /* Add the codec_data attribute to caps, if we have it */
13513 buffer = gst_buffer_new_and_alloc (data_len);
13514 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13516 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13517 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13519 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13521 gst_buffer_unref (buffer);
13526 static inline GstCaps *
13527 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13531 char *s, fourstr[5];
13533 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13534 for (i = 0; i < 4; i++) {
13535 if (!g_ascii_isalnum (fourstr[i]))
13538 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13539 caps = gst_caps_new_empty_simple (s);
13544 #define _codec(name) \
13546 if (codec_name) { \
13547 *codec_name = g_strdup (name); \
13552 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13553 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
13554 const guint8 * stsd_entry_data, gchar ** codec_name)
13556 GstCaps *caps = NULL;
13557 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13560 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
13561 _codec ("PNG still images");
13562 caps = gst_caps_new_empty_simple ("image/png");
13565 _codec ("JPEG still images");
13567 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13570 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13571 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13572 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13573 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13574 _codec ("Motion-JPEG");
13576 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13579 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13580 _codec ("Motion-JPEG format B");
13581 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13584 _codec ("JPEG-2000");
13585 /* override to what it should be according to spec, avoid palette_data */
13586 entry->bits_per_sample = 24;
13587 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13590 _codec ("Sorensen video v.3");
13591 caps = gst_caps_new_simple ("video/x-svq",
13592 "svqversion", G_TYPE_INT, 3, NULL);
13594 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13595 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13596 _codec ("Sorensen video v.1");
13597 caps = gst_caps_new_simple ("video/x-svq",
13598 "svqversion", G_TYPE_INT, 1, NULL);
13600 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13601 caps = gst_caps_new_empty_simple ("video/x-raw");
13602 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13603 _codec ("Windows Raw RGB");
13604 stream->alignment = 32;
13610 bps = QT_UINT16 (stsd_entry_data + 82);
13613 format = GST_VIDEO_FORMAT_RGB15;
13616 format = GST_VIDEO_FORMAT_RGB16;
13619 format = GST_VIDEO_FORMAT_RGB;
13622 format = GST_VIDEO_FORMAT_ARGB;
13630 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13631 format = GST_VIDEO_FORMAT_I420;
13633 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13634 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13635 format = GST_VIDEO_FORMAT_I420;
13638 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13639 format = GST_VIDEO_FORMAT_UYVY;
13641 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13642 format = GST_VIDEO_FORMAT_v308;
13644 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13645 format = GST_VIDEO_FORMAT_v216;
13648 format = GST_VIDEO_FORMAT_v210;
13650 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13651 format = GST_VIDEO_FORMAT_r210;
13653 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13654 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13655 format = GST_VIDEO_FORMAT_v410;
13658 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13659 * but different order than AYUV
13660 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13661 format = GST_VIDEO_FORMAT_v408;
13664 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13665 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13666 _codec ("MPEG-1 video");
13667 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13668 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13670 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13671 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13672 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13673 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13674 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13675 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13676 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13677 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13678 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13679 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13680 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13681 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13682 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13683 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13684 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13685 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13686 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13687 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13688 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13689 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13690 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13691 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13692 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13693 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13694 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13695 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13696 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13697 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13698 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13699 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13700 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13701 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13702 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13703 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13704 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13705 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13706 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13707 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13708 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13709 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13710 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13711 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13712 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13713 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13714 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13715 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13716 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13717 _codec ("MPEG-2 video");
13718 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13719 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13721 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13722 _codec ("GIF still images");
13723 caps = gst_caps_new_empty_simple ("image/gif");
13726 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13728 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13730 /* ffmpeg uses the height/width props, don't know why */
13731 caps = gst_caps_new_simple ("video/x-h263",
13732 "variant", G_TYPE_STRING, "itu", NULL);
13736 _codec ("MPEG-4 video");
13737 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13738 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13740 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13741 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13742 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13743 caps = gst_caps_new_simple ("video/x-msmpeg",
13744 "msmpegversion", G_TYPE_INT, 43, NULL);
13746 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13748 caps = gst_caps_new_simple ("video/x-divx",
13749 "divxversion", G_TYPE_INT, 3, NULL);
13751 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13752 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13754 caps = gst_caps_new_simple ("video/x-divx",
13755 "divxversion", G_TYPE_INT, 4, NULL);
13757 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13759 caps = gst_caps_new_simple ("video/x-divx",
13760 "divxversion", G_TYPE_INT, 5, NULL);
13763 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13765 caps = gst_caps_new_simple ("video/x-ffv",
13766 "ffvversion", G_TYPE_INT, 1, NULL);
13769 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13770 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13775 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13776 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13777 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13781 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13782 _codec ("Cinepak");
13783 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13785 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13786 _codec ("Apple QuickDraw");
13787 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13789 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13790 _codec ("Apple video");
13791 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13795 _codec ("H.264 / AVC");
13796 caps = gst_caps_new_simple ("video/x-h264",
13797 "stream-format", G_TYPE_STRING, "avc",
13798 "alignment", G_TYPE_STRING, "au", NULL);
13801 _codec ("H.264 / AVC");
13802 caps = gst_caps_new_simple ("video/x-h264",
13803 "stream-format", G_TYPE_STRING, "avc3",
13804 "alignment", G_TYPE_STRING, "au", NULL);
13808 _codec ("H.265 / HEVC");
13809 caps = gst_caps_new_simple ("video/x-h265",
13810 "stream-format", G_TYPE_STRING, "hvc1",
13811 "alignment", G_TYPE_STRING, "au", NULL);
13814 _codec ("H.265 / HEVC");
13815 caps = gst_caps_new_simple ("video/x-h265",
13816 "stream-format", G_TYPE_STRING, "hev1",
13817 "alignment", G_TYPE_STRING, "au", NULL);
13820 _codec ("Run-length encoding");
13821 caps = gst_caps_new_simple ("video/x-rle",
13822 "layout", G_TYPE_STRING, "quicktime", NULL);
13825 _codec ("Run-length encoding");
13826 caps = gst_caps_new_simple ("video/x-rle",
13827 "layout", G_TYPE_STRING, "microsoft", NULL);
13829 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13830 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13831 _codec ("Indeo Video 3");
13832 caps = gst_caps_new_simple ("video/x-indeo",
13833 "indeoversion", G_TYPE_INT, 3, NULL);
13835 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13836 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13837 _codec ("Intel Video 4");
13838 caps = gst_caps_new_simple ("video/x-indeo",
13839 "indeoversion", G_TYPE_INT, 4, NULL);
13843 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13844 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13845 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13846 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13847 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13848 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13849 _codec ("DV Video");
13850 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13851 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13853 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13854 case FOURCC_dv5p: /* DVCPRO50 PAL */
13855 _codec ("DVCPro50 Video");
13856 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13857 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13859 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13860 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13861 _codec ("DVCProHD Video");
13862 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13863 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13865 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13866 _codec ("Apple Graphics (SMC)");
13867 caps = gst_caps_new_empty_simple ("video/x-smc");
13869 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13871 caps = gst_caps_new_empty_simple ("video/x-vp3");
13873 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13874 _codec ("VP6 Flash");
13875 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13879 caps = gst_caps_new_empty_simple ("video/x-theora");
13880 /* theora uses one byte of padding in the data stream because it does not
13881 * allow 0 sized packets while theora does */
13882 entry->padding = 1;
13886 caps = gst_caps_new_empty_simple ("video/x-dirac");
13888 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13889 _codec ("TIFF still images");
13890 caps = gst_caps_new_empty_simple ("image/tiff");
13892 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13893 _codec ("Apple Intermediate Codec");
13894 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13896 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13897 _codec ("AVID DNxHD");
13898 caps = gst_caps_from_string ("video/x-dnxhd");
13901 _codec ("On2 VP8");
13902 caps = gst_caps_from_string ("video/x-vp8");
13905 _codec ("Apple ProRes LT");
13907 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13911 _codec ("Apple ProRes HQ");
13913 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13917 _codec ("Apple ProRes");
13919 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13923 _codec ("Apple ProRes Proxy");
13925 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13929 _codec ("Apple ProRes 4444");
13931 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13935 _codec ("Apple ProRes 4444 XQ");
13937 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13941 _codec ("GoPro CineForm");
13942 caps = gst_caps_from_string ("video/x-cineform");
13947 caps = gst_caps_new_simple ("video/x-wmv",
13948 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13950 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13953 caps = _get_unknown_codec_name ("video", fourcc);
13958 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13961 gst_video_info_init (&info);
13962 gst_video_info_set_format (&info, format, entry->width, entry->height);
13964 caps = gst_video_info_to_caps (&info);
13965 *codec_name = gst_pb_utils_get_codec_description (caps);
13967 /* enable clipping for raw video streams */
13968 stream->need_clip = TRUE;
13969 stream->alignment = 32;
13976 round_up_pow2 (guint n)
13988 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13989 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
13990 int len, gchar ** codec_name)
13993 const GstStructure *s;
13996 GstAudioFormat format = 0;
13999 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14001 depth = entry->bytes_per_packet * 8;
14004 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14006 /* 8-bit audio is unsigned */
14008 format = GST_AUDIO_FORMAT_U8;
14009 /* otherwise it's signed and big-endian just like 'twos' */
14011 endian = G_BIG_ENDIAN;
14018 endian = G_LITTLE_ENDIAN;
14021 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14023 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14027 caps = gst_caps_new_simple ("audio/x-raw",
14028 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14029 "layout", G_TYPE_STRING, "interleaved", NULL);
14030 stream->alignment = GST_ROUND_UP_8 (depth);
14031 stream->alignment = round_up_pow2 (stream->alignment);
14034 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14035 _codec ("Raw 64-bit floating-point audio");
14036 caps = gst_caps_new_simple ("audio/x-raw",
14037 "format", G_TYPE_STRING, "F64BE",
14038 "layout", G_TYPE_STRING, "interleaved", NULL);
14039 stream->alignment = 8;
14041 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14042 _codec ("Raw 32-bit floating-point audio");
14043 caps = gst_caps_new_simple ("audio/x-raw",
14044 "format", G_TYPE_STRING, "F32BE",
14045 "layout", G_TYPE_STRING, "interleaved", NULL);
14046 stream->alignment = 4;
14049 _codec ("Raw 24-bit PCM audio");
14050 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14052 caps = gst_caps_new_simple ("audio/x-raw",
14053 "format", G_TYPE_STRING, "S24BE",
14054 "layout", G_TYPE_STRING, "interleaved", NULL);
14055 stream->alignment = 4;
14057 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14058 _codec ("Raw 32-bit PCM audio");
14059 caps = gst_caps_new_simple ("audio/x-raw",
14060 "format", G_TYPE_STRING, "S32BE",
14061 "layout", G_TYPE_STRING, "interleaved", NULL);
14062 stream->alignment = 4;
14064 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14065 _codec ("Raw 16-bit PCM audio");
14066 caps = gst_caps_new_simple ("audio/x-raw",
14067 "format", G_TYPE_STRING, "S16LE",
14068 "layout", G_TYPE_STRING, "interleaved", NULL);
14069 stream->alignment = 2;
14072 _codec ("Mu-law audio");
14073 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14076 _codec ("A-law audio");
14077 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14081 _codec ("Microsoft ADPCM");
14082 /* Microsoft ADPCM-ACM code 2 */
14083 caps = gst_caps_new_simple ("audio/x-adpcm",
14084 "layout", G_TYPE_STRING, "microsoft", NULL);
14088 _codec ("DVI/IMA ADPCM");
14089 caps = gst_caps_new_simple ("audio/x-adpcm",
14090 "layout", G_TYPE_STRING, "dvi", NULL);
14094 _codec ("DVI/Intel IMA ADPCM");
14095 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14096 caps = gst_caps_new_simple ("audio/x-adpcm",
14097 "layout", G_TYPE_STRING, "quicktime", NULL);
14101 /* MPEG layer 3, CBR only (pre QT4.1) */
14103 _codec ("MPEG-1 layer 3");
14104 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14105 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14106 "mpegversion", G_TYPE_INT, 1, NULL);
14108 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14109 _codec ("MPEG-1 layer 2");
14111 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14112 "mpegversion", G_TYPE_INT, 1, NULL);
14115 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14116 _codec ("EAC-3 audio");
14117 caps = gst_caps_new_simple ("audio/x-eac3",
14118 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14119 entry->sampled = TRUE;
14121 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14123 _codec ("AC-3 audio");
14124 caps = gst_caps_new_simple ("audio/x-ac3",
14125 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14126 entry->sampled = TRUE;
14128 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14129 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14130 _codec ("DTS audio");
14131 caps = gst_caps_new_simple ("audio/x-dts",
14132 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14133 entry->sampled = TRUE;
14135 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14136 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14137 _codec ("DTS-HD audio");
14138 caps = gst_caps_new_simple ("audio/x-dts",
14139 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14140 entry->sampled = TRUE;
14144 caps = gst_caps_new_simple ("audio/x-mace",
14145 "maceversion", G_TYPE_INT, 3, NULL);
14149 caps = gst_caps_new_simple ("audio/x-mace",
14150 "maceversion", G_TYPE_INT, 6, NULL);
14152 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14154 caps = gst_caps_new_empty_simple ("application/ogg");
14156 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14157 _codec ("DV audio");
14158 caps = gst_caps_new_empty_simple ("audio/x-dv");
14161 _codec ("MPEG-4 AAC audio");
14162 caps = gst_caps_new_simple ("audio/mpeg",
14163 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14164 "stream-format", G_TYPE_STRING, "raw", NULL);
14166 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14167 _codec ("QDesign Music");
14168 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14171 _codec ("QDesign Music v.2");
14172 /* FIXME: QDesign music version 2 (no constant) */
14173 if (FALSE && data) {
14174 caps = gst_caps_new_simple ("audio/x-qdm2",
14175 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14176 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14177 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14179 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14183 _codec ("GSM audio");
14184 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14187 _codec ("AMR audio");
14188 caps = gst_caps_new_empty_simple ("audio/AMR");
14191 _codec ("AMR-WB audio");
14192 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14195 _codec ("Quicktime IMA ADPCM");
14196 caps = gst_caps_new_simple ("audio/x-adpcm",
14197 "layout", G_TYPE_STRING, "quicktime", NULL);
14200 _codec ("Apple lossless audio");
14201 caps = gst_caps_new_empty_simple ("audio/x-alac");
14204 _codec ("Free Lossless Audio Codec");
14205 caps = gst_caps_new_simple ("audio/x-flac",
14206 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14208 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14209 _codec ("QualComm PureVoice");
14210 caps = gst_caps_from_string ("audio/qcelp");
14215 caps = gst_caps_new_empty_simple ("audio/x-wma");
14219 caps = gst_caps_new_empty_simple ("audio/x-opus");
14221 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
14226 GstAudioFormat format;
14229 FLAG_IS_FLOAT = 0x1,
14230 FLAG_IS_BIG_ENDIAN = 0x2,
14231 FLAG_IS_SIGNED = 0x4,
14232 FLAG_IS_PACKED = 0x8,
14233 FLAG_IS_ALIGNED_HIGH = 0x10,
14234 FLAG_IS_NON_INTERLEAVED = 0x20
14236 _codec ("Raw LPCM audio");
14238 if (data && len >= 56) {
14239 depth = QT_UINT32 (data + 40);
14240 flags = QT_UINT32 (data + 44);
14241 width = QT_UINT32 (data + 48) * 8 / entry->n_channels;
14243 if ((flags & FLAG_IS_FLOAT) == 0) {
14248 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14249 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14250 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14251 caps = gst_caps_new_simple ("audio/x-raw",
14252 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14253 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14254 "non-interleaved" : "interleaved", NULL);
14255 stream->alignment = GST_ROUND_UP_8 (depth);
14256 stream->alignment = round_up_pow2 (stream->alignment);
14261 if (flags & FLAG_IS_BIG_ENDIAN)
14262 format = GST_AUDIO_FORMAT_F64BE;
14264 format = GST_AUDIO_FORMAT_F64LE;
14266 if (flags & FLAG_IS_BIG_ENDIAN)
14267 format = GST_AUDIO_FORMAT_F32BE;
14269 format = GST_AUDIO_FORMAT_F32LE;
14271 caps = gst_caps_new_simple ("audio/x-raw",
14272 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14273 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14274 "non-interleaved" : "interleaved", NULL);
14275 stream->alignment = width / 8;
14279 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14283 caps = _get_unknown_codec_name ("audio", fourcc);
14289 GstCaps *templ_caps =
14290 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14291 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14292 gst_caps_unref (caps);
14293 gst_caps_unref (templ_caps);
14294 caps = intersection;
14297 /* enable clipping for raw audio streams */
14298 s = gst_caps_get_structure (caps, 0);
14299 name = gst_structure_get_name (s);
14300 if (g_str_has_prefix (name, "audio/x-raw")) {
14301 stream->need_clip = TRUE;
14302 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14303 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14309 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14310 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14311 const guint8 * stsd_entry_data, gchar ** codec_name)
14315 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14319 _codec ("DVD subtitle");
14320 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14321 stream->need_process = TRUE;
14324 _codec ("Quicktime timed text");
14327 _codec ("3GPP timed text");
14329 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14331 /* actual text piece needs to be extracted */
14332 stream->need_process = TRUE;
14335 _codec ("XML subtitles");
14336 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14340 caps = _get_unknown_codec_name ("text", fourcc);
14348 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14349 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14350 const guint8 * stsd_entry_data, gchar ** codec_name)
14356 _codec ("MPEG 1 video");
14357 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14358 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14368 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14369 const gchar * system_id)
14373 if (!qtdemux->protection_system_ids)
14374 qtdemux->protection_system_ids =
14375 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14376 /* Check whether we already have an entry for this system ID. */
14377 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14378 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14379 if (g_ascii_strcasecmp (system_id, id) == 0) {
14383 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14384 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,