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 (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
3937 decode_time) : GST_CLOCK_TIME_NONE));
3939 /* Discard the fragment buffer timestamp info to avoid using it.
3940 * Rely on tfdt instead as it is more accurate than the timestamp
3941 * that is fetched from a manifest/playlist and is usually
3943 qtdemux->fragment_start = -1;
3946 if (G_UNLIKELY (!stream)) {
3947 /* we lost track of offset, we'll need to regain it,
3948 * but can delay complaining until later or avoid doing so altogether */
3952 if (G_UNLIKELY (base_offset < -1))
3955 if (qtdemux->upstream_format_is_time)
3956 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3958 /* initialise moof sample data */
3959 stream->n_samples_moof = 0;
3960 stream->duration_last_moof = stream->duration_moof;
3961 stream->duration_moof = 0;
3963 /* Track Run node */
3965 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3968 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3969 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3970 &running_offset, decode_time, (tfdt_node != NULL));
3971 /* iterate all siblings */
3972 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3976 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3978 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3979 guint32 box_length = QT_UINT32 (uuid_buffer);
3981 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3984 /* if no new base_offset provided for next traf,
3985 * base is end of current traf */
3986 base_offset = running_offset;
3987 running_offset = -1;
3989 if (stream->n_samples_moof && stream->duration_moof)
3990 stream->new_caps = TRUE;
3993 /* iterate all siblings */
3994 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3997 /* parse any protection system info */
3998 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4000 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4001 qtdemux_parse_pssh (qtdemux, pssh_node);
4002 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4005 g_node_destroy (moof_node);
4010 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4015 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4020 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4025 g_node_destroy (moof_node);
4026 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4027 (_("This file is corrupt and cannot be played.")), (NULL));
4033 /* might be used if some day we actually use mfra & co
4034 * for random access to fragments,
4035 * but that will require quite some modifications and much less relying
4036 * on a sample array */
4040 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4042 QtDemuxStream *stream;
4043 guint32 ver_flags, track_id, len, num_entries, i;
4044 guint value_size, traf_size, trun_size, sample_size;
4045 guint64 time = 0, moof_offset = 0;
4047 GstBuffer *buf = NULL;
4052 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4054 if (!gst_byte_reader_skip (&tfra, 8))
4057 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4060 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4061 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4062 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4065 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4067 stream = qtdemux_find_stream (qtdemux, track_id);
4069 goto unknown_trackid;
4071 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4072 sample_size = (len & 3) + 1;
4073 trun_size = ((len & 12) >> 2) + 1;
4074 traf_size = ((len & 48) >> 4) + 1;
4076 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4077 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4079 if (num_entries == 0)
4082 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4083 value_size + value_size + traf_size + trun_size + sample_size))
4086 g_free (stream->ra_entries);
4087 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4088 stream->n_ra_entries = num_entries;
4090 for (i = 0; i < num_entries; i++) {
4091 qt_atom_parser_get_offset (&tfra, value_size, &time);
4092 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4093 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4094 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4095 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4097 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4099 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4100 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4102 stream->ra_entries[i].ts = time;
4103 stream->ra_entries[i].moof_offset = moof_offset;
4105 /* don't want to go through the entire file and read all moofs at startup */
4107 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4108 if (ret != GST_FLOW_OK)
4110 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4111 moof_offset, stream);
4112 gst_buffer_unref (buf);
4116 check_update_duration (qtdemux, time);
4123 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4128 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4133 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4139 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4141 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4142 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4143 GstBuffer *mfro = NULL, *mfra = NULL;
4145 gboolean ret = FALSE;
4146 GNode *mfra_node, *tfra_node;
4147 guint64 mfra_offset = 0;
4148 guint32 fourcc, mfra_size;
4151 /* query upstream size in bytes */
4152 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4153 goto size_query_failed;
4155 /* mfro box should be at the very end of the file */
4156 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4157 if (flow != GST_FLOW_OK)
4160 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4162 fourcc = QT_FOURCC (mfro_map.data + 4);
4163 if (fourcc != FOURCC_mfro)
4166 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4167 if (mfro_map.size < 16)
4168 goto invalid_mfro_size;
4170 mfra_size = QT_UINT32 (mfro_map.data + 12);
4171 if (mfra_size >= len)
4172 goto invalid_mfra_size;
4174 mfra_offset = len - mfra_size;
4176 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4177 mfra_offset, mfra_size);
4179 /* now get and parse mfra box */
4180 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4181 if (flow != GST_FLOW_OK)
4184 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4186 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4187 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4189 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4192 qtdemux_parse_tfra (qtdemux, tfra_node);
4193 /* iterate all siblings */
4194 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4196 g_node_destroy (mfra_node);
4198 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4204 if (mfro_map.memory != NULL)
4205 gst_buffer_unmap (mfro, &mfro_map);
4206 gst_buffer_unref (mfro);
4209 if (mfra_map.memory != NULL)
4210 gst_buffer_unmap (mfra, &mfra_map);
4211 gst_buffer_unref (mfra);
4218 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4223 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4228 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4233 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4239 add_offset (guint64 offset, guint64 advance)
4241 /* Avoid 64-bit overflow by clamping */
4242 if (offset > G_MAXUINT64 - advance)
4244 return offset + advance;
4247 static GstFlowReturn
4248 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4252 GstBuffer *buf = NULL;
4253 GstFlowReturn ret = GST_FLOW_OK;
4254 guint64 cur_offset = qtdemux->offset;
4257 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4258 if (G_UNLIKELY (ret != GST_FLOW_OK))
4260 gst_buffer_map (buf, &map, GST_MAP_READ);
4261 if (G_LIKELY (map.size >= 8))
4262 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4263 gst_buffer_unmap (buf, &map);
4264 gst_buffer_unref (buf);
4266 /* maybe we already got most we needed, so only consider this eof */
4267 if (G_UNLIKELY (length == 0)) {
4268 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4269 (_("Invalid atom size.")),
4270 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4271 GST_FOURCC_ARGS (fourcc)));
4278 /* record for later parsing when needed */
4279 if (!qtdemux->moof_offset) {
4280 qtdemux->moof_offset = qtdemux->offset;
4282 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4285 qtdemux->offset += length; /* skip moof and keep going */
4287 if (qtdemux->got_moov) {
4288 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4299 GST_LOG_OBJECT (qtdemux,
4300 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4301 GST_FOURCC_ARGS (fourcc), cur_offset);
4302 qtdemux->offset = add_offset (qtdemux->offset, length);
4307 GstBuffer *moov = NULL;
4309 if (qtdemux->got_moov) {
4310 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4311 qtdemux->offset = add_offset (qtdemux->offset, length);
4315 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4316 if (ret != GST_FLOW_OK)
4318 gst_buffer_map (moov, &map, GST_MAP_READ);
4320 if (length != map.size) {
4321 /* Some files have a 'moov' atom at the end of the file which contains
4322 * a terminal 'free' atom where the body of the atom is missing.
4323 * Check for, and permit, this special case.
4325 if (map.size >= 8) {
4326 guint8 *final_data = map.data + (map.size - 8);
4327 guint32 final_length = QT_UINT32 (final_data);
4328 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4330 if (final_fourcc == FOURCC_free
4331 && map.size + final_length - 8 == length) {
4332 /* Ok, we've found that special case. Allocate a new buffer with
4333 * that free atom actually present. */
4334 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4335 gst_buffer_fill (newmoov, 0, map.data, map.size);
4336 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4337 gst_buffer_unmap (moov, &map);
4338 gst_buffer_unref (moov);
4340 gst_buffer_map (moov, &map, GST_MAP_READ);
4345 if (length != map.size) {
4346 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4347 (_("This file is incomplete and cannot be played.")),
4348 ("We got less than expected (received %" G_GSIZE_FORMAT
4349 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4350 (guint) length, cur_offset));
4351 gst_buffer_unmap (moov, &map);
4352 gst_buffer_unref (moov);
4353 ret = GST_FLOW_ERROR;
4356 qtdemux->offset += length;
4358 qtdemux_parse_moov (qtdemux, map.data, length);
4359 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4361 qtdemux_parse_tree (qtdemux);
4362 if (qtdemux->moov_node_compressed) {
4363 g_node_destroy (qtdemux->moov_node_compressed);
4364 g_free (qtdemux->moov_node->data);
4366 qtdemux->moov_node_compressed = NULL;
4367 g_node_destroy (qtdemux->moov_node);
4368 qtdemux->moov_node = NULL;
4369 gst_buffer_unmap (moov, &map);
4370 gst_buffer_unref (moov);
4371 qtdemux->got_moov = TRUE;
4377 GstBuffer *ftyp = NULL;
4379 /* extract major brand; might come in handy for ISO vs QT issues */
4380 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4381 if (ret != GST_FLOW_OK)
4383 qtdemux->offset += length;
4384 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4385 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4386 gst_buffer_unmap (ftyp, &map);
4387 gst_buffer_unref (ftyp);
4392 GstBuffer *uuid = NULL;
4394 /* uuid are extension atoms */
4395 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4396 if (ret != GST_FLOW_OK)
4398 qtdemux->offset += length;
4399 gst_buffer_map (uuid, &map, GST_MAP_READ);
4400 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4401 gst_buffer_unmap (uuid, &map);
4402 gst_buffer_unref (uuid);
4407 GstBuffer *sidx = NULL;
4408 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4409 if (ret != GST_FLOW_OK)
4411 qtdemux->offset += length;
4412 gst_buffer_map (sidx, &map, GST_MAP_READ);
4413 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4414 gst_buffer_unmap (sidx, &map);
4415 gst_buffer_unref (sidx);
4420 GstBuffer *unknown = NULL;
4422 GST_LOG_OBJECT (qtdemux,
4423 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4424 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4426 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4427 if (ret != GST_FLOW_OK)
4429 gst_buffer_map (unknown, &map, GST_MAP_READ);
4430 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4431 gst_buffer_unmap (unknown, &map);
4432 gst_buffer_unref (unknown);
4433 qtdemux->offset += length;
4439 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4440 /* digested all data, show what we have */
4441 qtdemux_prepare_streams (qtdemux);
4442 ret = qtdemux_expose_streams (qtdemux);
4444 qtdemux->state = QTDEMUX_STATE_MOVIE;
4445 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4452 /* Seeks to the previous keyframe of the indexed stream and
4453 * aligns other streams with respect to the keyframe timestamp
4454 * of indexed stream. Only called in case of Reverse Playback
4456 static GstFlowReturn
4457 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4460 guint32 seg_idx = 0, k_index = 0;
4461 guint32 ref_seg_idx, ref_k_index;
4462 GstClockTime k_pos = 0, last_stop = 0;
4463 QtDemuxSegment *seg = NULL;
4464 QtDemuxStream *ref_str = NULL;
4465 guint64 seg_media_start_mov; /* segment media start time in mov format */
4468 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4469 * and finally align all the other streams on that timestamp with their
4470 * respective keyframes */
4471 for (n = 0; n < qtdemux->n_streams; n++) {
4472 QtDemuxStream *str = qtdemux->streams[n];
4474 /* No candidate yet, take the first stream */
4480 /* So that stream has a segment, we prefer video streams */
4481 if (str->subtype == FOURCC_vide) {
4487 if (G_UNLIKELY (!ref_str)) {
4488 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4492 if (G_UNLIKELY (!ref_str->from_sample)) {
4493 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4497 /* So that stream has been playing from from_sample to to_sample. We will
4498 * get the timestamp of the previous sample and search for a keyframe before
4499 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4500 if (ref_str->subtype == FOURCC_vide) {
4501 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4502 ref_str->from_sample - 1, FALSE);
4504 if (ref_str->from_sample >= 10)
4505 k_index = ref_str->from_sample - 10;
4511 ref_str->samples[k_index].timestamp +
4512 ref_str->samples[k_index].pts_offset;
4514 /* get current segment for that stream */
4515 seg = &ref_str->segments[ref_str->segment_index];
4516 /* Use segment start in original timescale for comparisons */
4517 seg_media_start_mov = seg->trak_media_start;
4519 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4520 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4521 k_index, target_ts, seg_media_start_mov,
4522 GST_TIME_ARGS (seg->media_start));
4524 /* Crawl back through segments to find the one containing this I frame */
4525 while (target_ts < seg_media_start_mov) {
4526 GST_DEBUG_OBJECT (qtdemux,
4527 "keyframe position (sample %u) is out of segment %u " " target %"
4528 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4529 ref_str->segment_index, target_ts, seg_media_start_mov);
4531 if (G_UNLIKELY (!ref_str->segment_index)) {
4532 /* Reached first segment, let's consider it's EOS */
4535 ref_str->segment_index--;
4536 seg = &ref_str->segments[ref_str->segment_index];
4537 /* Use segment start in original timescale for comparisons */
4538 seg_media_start_mov = seg->trak_media_start;
4540 /* Calculate time position of the keyframe and where we should stop */
4542 QTSTREAMTIME_TO_GSTTIME (ref_str,
4543 target_ts - seg->trak_media_start) + seg->time;
4545 QTSTREAMTIME_TO_GSTTIME (ref_str,
4546 ref_str->samples[ref_str->from_sample].timestamp -
4547 seg->trak_media_start) + seg->time;
4549 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4550 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4551 k_index, GST_TIME_ARGS (k_pos));
4553 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4554 qtdemux->segment.position = last_stop;
4555 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4556 GST_TIME_ARGS (last_stop));
4558 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4559 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4563 ref_seg_idx = ref_str->segment_index;
4564 ref_k_index = k_index;
4566 /* Align them all on this */
4567 for (n = 0; n < qtdemux->n_streams; n++) {
4569 GstClockTime seg_time = 0;
4570 QtDemuxStream *str = qtdemux->streams[n];
4572 /* aligning reference stream again might lead to backing up to yet another
4573 * keyframe (due to timestamp rounding issues),
4574 * potentially putting more load on downstream; so let's try to avoid */
4575 if (str == ref_str) {
4576 seg_idx = ref_seg_idx;
4577 seg = &str->segments[seg_idx];
4578 k_index = ref_k_index;
4579 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4580 "sample at index %d", n, ref_str->segment_index, k_index);
4582 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4583 GST_DEBUG_OBJECT (qtdemux,
4584 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4585 seg_idx, GST_TIME_ARGS (k_pos));
4587 /* get segment and time in the segment */
4588 seg = &str->segments[seg_idx];
4589 seg_time = k_pos - seg->time;
4591 /* get the media time in the segment.
4592 * No adjustment for empty "filler" segments */
4593 if (seg->media_start != GST_CLOCK_TIME_NONE)
4594 seg_time += seg->media_start;
4596 /* get the index of the sample with media time */
4597 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4598 GST_DEBUG_OBJECT (qtdemux,
4599 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4600 GST_TIME_ARGS (seg_time), index);
4602 /* find previous keyframe */
4603 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4606 /* Remember until where we want to go */
4607 str->to_sample = str->from_sample - 1;
4608 /* Define our time position */
4610 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4611 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4612 if (seg->media_start != GST_CLOCK_TIME_NONE)
4613 str->time_position -= seg->media_start;
4615 /* Now seek back in time */
4616 gst_qtdemux_move_stream (qtdemux, str, k_index);
4617 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4618 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4619 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4625 return GST_FLOW_EOS;
4629 * Gets the current qt segment start, stop and position for the
4630 * given time offset. This is used in update_segment()
4633 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4634 QtDemuxStream * stream, GstClockTime offset,
4635 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4637 GstClockTime seg_time;
4638 GstClockTime start, stop, time;
4639 QtDemuxSegment *segment;
4641 segment = &stream->segments[stream->segment_index];
4643 /* get time in this segment */
4644 seg_time = (offset - segment->time) * segment->rate;
4646 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4647 GST_TIME_ARGS (seg_time));
4649 if (G_UNLIKELY (seg_time > segment->duration)) {
4650 GST_LOG_OBJECT (stream->pad,
4651 "seg_time > segment->duration %" GST_TIME_FORMAT,
4652 GST_TIME_ARGS (segment->duration));
4653 seg_time = segment->duration;
4656 /* qtdemux->segment.stop is in outside-time-realm, whereas
4657 * segment->media_stop is in track-time-realm.
4659 * In order to compare the two, we need to bring segment.stop
4660 * into the track-time-realm
4662 * FIXME - does this comment still hold? Don't see any conversion here */
4664 stop = qtdemux->segment.stop;
4665 if (stop == GST_CLOCK_TIME_NONE)
4666 stop = qtdemux->segment.duration;
4667 if (stop == GST_CLOCK_TIME_NONE)
4668 stop = segment->media_stop;
4671 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4673 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4674 start = segment->time + seg_time;
4676 stop = start - seg_time + segment->duration;
4677 } else if (qtdemux->segment.rate >= 0) {
4678 start = MIN (segment->media_start + seg_time, stop);
4681 if (segment->media_start >= qtdemux->segment.start) {
4682 time = segment->time;
4684 time = segment->time + (qtdemux->segment.start - segment->media_start);
4687 start = MAX (segment->media_start, qtdemux->segment.start);
4688 stop = MIN (segment->media_start + seg_time, stop);
4697 * Updates the qt segment used for the stream and pushes a new segment event
4698 * downstream on this stream's pad.
4701 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4702 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4703 GstClockTime * _stop)
4705 QtDemuxSegment *segment;
4706 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4710 /* update the current segment */
4711 stream->segment_index = seg_idx;
4713 /* get the segment */
4714 segment = &stream->segments[seg_idx];
4716 if (G_UNLIKELY (offset < segment->time)) {
4717 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4718 GST_TIME_ARGS (segment->time));
4722 /* segment lies beyond total indicated duration */
4723 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4724 segment->time > qtdemux->segment.duration)) {
4725 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4726 " < segment->time %" GST_TIME_FORMAT,
4727 GST_TIME_ARGS (qtdemux->segment.duration),
4728 GST_TIME_ARGS (segment->time));
4732 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4733 &start, &stop, &time);
4735 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4736 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4737 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4739 /* combine global rate with that of the segment */
4740 rate = segment->rate * qtdemux->segment.rate;
4742 /* Copy flags from main segment */
4743 stream->segment.flags = qtdemux->segment.flags;
4745 /* update the segment values used for clipping */
4746 stream->segment.offset = qtdemux->segment.offset;
4747 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4748 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4749 stream->segment.rate = rate;
4750 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4751 stream->cslg_shift);
4752 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4753 stream->cslg_shift);
4754 stream->segment.time = time;
4755 stream->segment.position = stream->segment.start;
4757 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4760 /* now prepare and send the segment */
4762 event = gst_event_new_segment (&stream->segment);
4763 if (qtdemux->segment_seqnum) {
4764 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4766 gst_pad_push_event (stream->pad, event);
4767 /* assume we can send more data now */
4768 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4769 /* clear to send tags on this pad now */
4770 gst_qtdemux_push_tags (qtdemux, stream);
4781 /* activate the given segment number @seg_idx of @stream at time @offset.
4782 * @offset is an absolute global position over all the segments.
4784 * This will push out a NEWSEGMENT event with the right values and
4785 * position the stream index to the first decodable sample before
4789 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4790 guint32 seg_idx, GstClockTime offset)
4792 QtDemuxSegment *segment;
4793 guint32 index, kf_index;
4794 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4796 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4797 seg_idx, GST_TIME_ARGS (offset));
4799 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4803 segment = &stream->segments[stream->segment_index];
4805 /* in the fragmented case, we pick a fragment that starts before our
4806 * desired position and rely on downstream to wait for a keyframe
4807 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4808 * tfra entries tells us which trun/sample the key unit is in, but we don't
4809 * make use of this additional information at the moment) */
4810 if (qtdemux->fragmented) {
4811 stream->to_sample = G_MAXUINT32;
4815 /* We don't need to look for a sample in push-based */
4816 if (!qtdemux->pullbased)
4819 /* and move to the keyframe before the indicated media time of the
4821 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4822 if (qtdemux->segment.rate >= 0) {
4823 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4824 stream->to_sample = G_MAXUINT32;
4825 GST_DEBUG_OBJECT (stream->pad,
4826 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4827 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4828 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4830 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4831 stream->to_sample = index;
4832 GST_DEBUG_OBJECT (stream->pad,
4833 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4834 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4835 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4838 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4839 "this is an empty segment");
4843 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4844 * encountered an error and printed a message so we return appropriately */
4848 /* we're at the right spot */
4849 if (index == stream->sample_index) {
4850 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4854 /* find keyframe of the target index */
4855 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4858 /* indent does stupid stuff with stream->samples[].timestamp */
4860 /* if we move forwards, we don't have to go back to the previous
4861 * keyframe since we already sent that. We can also just jump to
4862 * the keyframe right before the target index if there is one. */
4863 if (index > stream->sample_index) {
4864 /* moving forwards check if we move past a keyframe */
4865 if (kf_index > stream->sample_index) {
4866 GST_DEBUG_OBJECT (stream->pad,
4867 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4868 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4869 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4870 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4872 GST_DEBUG_OBJECT (stream->pad,
4873 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4874 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4875 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4878 GST_DEBUG_OBJECT (stream->pad,
4879 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4880 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4881 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4882 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4890 /* prepare to get the current sample of @stream, getting essential values.
4892 * This function will also prepare and send the segment when needed.
4894 * Return FALSE if the stream is EOS.
4899 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4900 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4901 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4902 gboolean * keyframe)
4904 QtDemuxSample *sample;
4905 GstClockTime time_position;
4908 g_return_val_if_fail (stream != NULL, FALSE);
4910 time_position = stream->time_position;
4911 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4914 seg_idx = stream->segment_index;
4915 if (G_UNLIKELY (seg_idx == -1)) {
4916 /* find segment corresponding to time_position if we are looking
4918 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4921 /* different segment, activate it, sample_index will be set. */
4922 if (G_UNLIKELY (stream->segment_index != seg_idx))
4923 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4925 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4927 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4929 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4930 " prepare empty sample");
4933 *pts = *dts = time_position;
4934 *duration = seg->duration - (time_position - seg->time);
4941 if (stream->sample_index == -1)
4942 stream->sample_index = 0;
4944 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4945 stream->sample_index, stream->n_samples);
4947 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4948 if (!qtdemux->fragmented)
4951 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4955 GST_OBJECT_LOCK (qtdemux);
4956 flow = qtdemux_add_fragmented_samples (qtdemux);
4957 GST_OBJECT_UNLOCK (qtdemux);
4959 if (flow != GST_FLOW_OK)
4962 while (stream->sample_index >= stream->n_samples);
4965 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4966 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4967 stream->sample_index);
4971 /* now get the info for the sample we're at */
4972 sample = &stream->samples[stream->sample_index];
4974 *dts = QTSAMPLE_DTS (stream, sample);
4975 *pts = QTSAMPLE_PTS (stream, sample);
4976 *offset = sample->offset;
4977 *size = sample->size;
4978 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4979 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4986 stream->time_position = GST_CLOCK_TIME_NONE;
4991 /* move to the next sample in @stream.
4993 * Moves to the next segment when needed.
4996 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4998 QtDemuxSample *sample;
4999 QtDemuxSegment *segment;
5001 /* get current segment */
5002 segment = &stream->segments[stream->segment_index];
5004 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5005 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5009 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5010 /* Mark the stream as EOS */
5011 GST_DEBUG_OBJECT (qtdemux,
5012 "reached max allowed sample %u, mark EOS", stream->to_sample);
5013 stream->time_position = GST_CLOCK_TIME_NONE;
5017 /* move to next sample */
5018 stream->sample_index++;
5019 stream->offset_in_sample = 0;
5021 /* reached the last sample, we need the next segment */
5022 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5025 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5026 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5027 stream->sample_index);
5031 /* get next sample */
5032 sample = &stream->samples[stream->sample_index];
5034 /* see if we are past the segment */
5035 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5038 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5039 /* inside the segment, update time_position, looks very familiar to
5040 * GStreamer segments, doesn't it? */
5041 stream->time_position =
5042 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5044 /* not yet in segment, time does not yet increment. This means
5045 * that we are still prerolling keyframes to the decoder so it can
5046 * decode the first sample of the segment. */
5047 stream->time_position = segment->time;
5051 /* move to the next segment */
5054 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5056 if (stream->segment_index == stream->n_segments - 1) {
5057 /* are we at the end of the last segment, we're EOS */
5058 stream->time_position = GST_CLOCK_TIME_NONE;
5060 /* else we're only at the end of the current segment */
5061 stream->time_position = segment->stop_time;
5063 /* make sure we select a new segment */
5065 /* accumulate previous segments */
5066 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5067 stream->accumulated_base +=
5068 (stream->segment.stop -
5069 stream->segment.start) / ABS (stream->segment.rate);
5071 stream->segment_index = -1;
5076 gst_qtdemux_sync_streams (GstQTDemux * demux)
5080 if (demux->n_streams <= 1)
5083 for (i = 0; i < demux->n_streams; i++) {
5084 QtDemuxStream *stream;
5085 GstClockTime end_time;
5087 stream = demux->streams[i];
5092 /* TODO advance time on subtitle streams here, if any some day */
5094 /* some clips/trailers may have unbalanced streams at the end,
5095 * so send EOS on shorter stream to prevent stalling others */
5097 /* do not mess with EOS if SEGMENT seeking */
5098 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5101 if (demux->pullbased) {
5102 /* loop mode is sample time based */
5103 if (!STREAM_IS_EOS (stream))
5106 /* push mode is byte position based */
5107 if (stream->n_samples &&
5108 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5112 if (stream->sent_eos)
5115 /* only act if some gap */
5116 end_time = stream->segments[stream->n_segments - 1].stop_time;
5117 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5118 ", stream end: %" GST_TIME_FORMAT,
5119 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5120 if (GST_CLOCK_TIME_IS_VALID (end_time)
5121 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5124 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5125 GST_PAD_NAME (stream->pad));
5126 stream->sent_eos = TRUE;
5127 event = gst_event_new_eos ();
5128 if (demux->segment_seqnum)
5129 gst_event_set_seqnum (event, demux->segment_seqnum);
5130 gst_pad_push_event (stream->pad, event);
5135 /* EOS and NOT_LINKED need to be combined. This means that we return:
5137 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5138 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5140 static GstFlowReturn
5141 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5144 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5147 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5150 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5152 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5156 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5157 * completely clipped
5159 * Should be used only with raw buffers */
5161 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5164 guint64 start, stop, cstart, cstop, diff;
5165 GstClockTime pts, duration;
5167 gint num_rate, denom_rate;
5172 osize = size = gst_buffer_get_size (buf);
5175 /* depending on the type, setup the clip parameters */
5176 if (stream->subtype == FOURCC_soun) {
5177 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5178 num_rate = GST_SECOND;
5179 denom_rate = (gint) CUR_STREAM (stream)->rate;
5181 } else if (stream->subtype == FOURCC_vide) {
5183 num_rate = CUR_STREAM (stream)->fps_n;
5184 denom_rate = CUR_STREAM (stream)->fps_d;
5189 if (frame_size <= 0)
5190 goto bad_frame_size;
5192 /* we can only clip if we have a valid pts */
5193 pts = GST_BUFFER_PTS (buf);
5194 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5197 duration = GST_BUFFER_DURATION (buf);
5199 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5201 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5205 stop = start + duration;
5207 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5208 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5211 /* see if some clipping happened */
5212 diff = cstart - start;
5218 /* bring clipped time to samples and to bytes */
5219 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5222 GST_DEBUG_OBJECT (qtdemux,
5223 "clipping start to %" GST_TIME_FORMAT " %"
5224 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5230 diff = stop - cstop;
5235 /* bring clipped time to samples and then to bytes */
5236 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5238 GST_DEBUG_OBJECT (qtdemux,
5239 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5240 " bytes", GST_TIME_ARGS (cstop), diff);
5245 if (offset != 0 || size != osize)
5246 gst_buffer_resize (buf, offset, size);
5248 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5249 GST_BUFFER_PTS (buf) = pts;
5250 GST_BUFFER_DURATION (buf) = duration;
5254 /* dropped buffer */
5257 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5262 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5267 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5272 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5273 gst_buffer_unref (buf);
5279 gst_qtdemux_align_buffer (GstQTDemux * demux,
5280 GstBuffer * buffer, gsize alignment)
5284 gst_buffer_map (buffer, &map, GST_MAP_READ);
5286 if (map.size < sizeof (guintptr)) {
5287 gst_buffer_unmap (buffer, &map);
5291 if (((guintptr) map.data) & (alignment - 1)) {
5292 GstBuffer *new_buffer;
5293 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5295 new_buffer = gst_buffer_new_allocate (NULL,
5296 gst_buffer_get_size (buffer), ¶ms);
5298 /* Copy data "by hand", so ensure alignment is kept: */
5299 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5301 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5302 GST_DEBUG_OBJECT (demux,
5303 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5306 gst_buffer_unmap (buffer, &map);
5307 gst_buffer_unref (buffer);
5312 gst_buffer_unmap (buffer, &map);
5316 /* the input buffer metadata must be writable,
5317 * but time/duration etc not yet set and need not be preserved */
5319 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5326 /* not many cases for now */
5327 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5328 /* send a one time dvd clut event */
5329 if (stream->pending_event && stream->pad)
5330 gst_pad_push_event (stream->pad, stream->pending_event);
5331 stream->pending_event = NULL;
5334 if (G_UNLIKELY (stream->subtype != FOURCC_text
5335 && stream->subtype != FOURCC_sbtl &&
5336 stream->subtype != FOURCC_subp)) {
5340 gst_buffer_map (buf, &map, GST_MAP_READ);
5342 /* empty buffer is sent to terminate previous subtitle */
5343 if (map.size <= 2) {
5344 gst_buffer_unmap (buf, &map);
5345 gst_buffer_unref (buf);
5348 if (stream->subtype == FOURCC_subp) {
5349 /* That's all the processing needed for subpictures */
5350 gst_buffer_unmap (buf, &map);
5354 nsize = GST_READ_UINT16_BE (map.data);
5355 nsize = MIN (nsize, map.size - 2);
5357 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5360 /* takes care of UTF-8 validation or UTF-16 recognition,
5361 * no other encoding expected */
5362 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5363 gst_buffer_unmap (buf, &map);
5365 gst_buffer_unref (buf);
5366 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5368 /* this should not really happen unless the subtitle is corrupted */
5369 gst_buffer_unref (buf);
5373 /* FIXME ? convert optional subsequent style info to markup */
5378 /* Sets a buffer's attributes properly and pushes it downstream.
5379 * Also checks for additional actions and custom processing that may
5380 * need to be done first.
5382 static GstFlowReturn
5383 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5384 QtDemuxStream * stream, GstBuffer * buf,
5385 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5386 gboolean keyframe, GstClockTime position, guint64 byte_position)
5388 GstFlowReturn ret = GST_FLOW_OK;
5390 /* offset the timestamps according to the edit list */
5392 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5396 gst_buffer_map (buf, &map, GST_MAP_READ);
5397 url = g_strndup ((gchar *) map.data, map.size);
5398 gst_buffer_unmap (buf, &map);
5399 if (url != NULL && strlen (url) != 0) {
5400 /* we have RTSP redirect now */
5401 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5402 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5403 gst_structure_new ("redirect",
5404 "new-location", G_TYPE_STRING, url, NULL)));
5405 qtdemux->posted_redirect = TRUE;
5407 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5413 /* position reporting */
5414 if (qtdemux->segment.rate >= 0) {
5415 qtdemux->segment.position = position;
5416 gst_qtdemux_sync_streams (qtdemux);
5419 if (G_UNLIKELY (!stream->pad)) {
5420 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5421 gst_buffer_unref (buf);
5425 /* send out pending buffers */
5426 while (stream->buffers) {
5427 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5429 if (G_UNLIKELY (stream->discont)) {
5430 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5431 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5432 stream->discont = FALSE;
5434 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5437 if (stream->alignment > 1)
5438 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5439 gst_pad_push (stream->pad, buffer);
5441 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5444 /* we're going to modify the metadata */
5445 buf = gst_buffer_make_writable (buf);
5447 if (G_UNLIKELY (stream->need_process))
5448 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5454 GST_BUFFER_DTS (buf) = dts;
5455 GST_BUFFER_PTS (buf) = pts;
5456 GST_BUFFER_DURATION (buf) = duration;
5457 GST_BUFFER_OFFSET (buf) = -1;
5458 GST_BUFFER_OFFSET_END (buf) = -1;
5460 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5461 gst_buffer_append_memory (buf,
5462 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5464 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5465 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5468 if (G_UNLIKELY (qtdemux->element_index)) {
5469 GstClockTime stream_time;
5472 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5474 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5475 GST_LOG_OBJECT (qtdemux,
5476 "adding association %" GST_TIME_FORMAT "-> %"
5477 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5478 gst_index_add_association (qtdemux->element_index,
5480 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5481 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5482 GST_FORMAT_BYTES, byte_position, NULL);
5487 if (stream->need_clip)
5488 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5490 if (G_UNLIKELY (buf == NULL))
5493 if (G_UNLIKELY (stream->discont)) {
5494 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5495 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5496 stream->discont = FALSE;
5498 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5502 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5503 stream->on_keyframe = FALSE;
5505 stream->on_keyframe = TRUE;
5509 GST_LOG_OBJECT (qtdemux,
5510 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5511 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5512 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5513 GST_PAD_NAME (stream->pad));
5515 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5516 GstStructure *crypto_info;
5517 QtDemuxCencSampleSetInfo *info =
5518 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5522 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5523 gst_pad_push_event (stream->pad, event);
5526 if (info->crypto_info == NULL) {
5527 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5528 gst_buffer_unref (buf);
5532 /* The end of the crypto_info array matches our n_samples position,
5533 * so count backward from there */
5534 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5535 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5536 /* steal structure from array */
5537 crypto_info = g_ptr_array_index (info->crypto_info, index);
5538 g_ptr_array_index (info->crypto_info, index) = NULL;
5539 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5540 info->crypto_info->len);
5541 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5542 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5544 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5545 index, stream->sample_index);
5549 if (stream->alignment > 1)
5550 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5552 ret = gst_pad_push (stream->pad, buf);
5554 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5555 /* mark position in stream, we'll need this to know when to send GAP event */
5556 stream->segment.position = pts + duration;
5563 static const QtDemuxRandomAccessEntry *
5564 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5565 GstClockTime pos, gboolean after)
5567 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5568 guint n_entries = stream->n_ra_entries;
5571 /* we assume the table is sorted */
5572 for (i = 0; i < n_entries; ++i) {
5573 if (entries[i].ts > pos)
5577 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5578 * probably okay to assume that the index lists the very first fragment */
5585 return &entries[i - 1];
5589 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5591 const QtDemuxRandomAccessEntry *best_entry = NULL;
5594 GST_OBJECT_LOCK (qtdemux);
5596 g_assert (qtdemux->n_streams > 0);
5598 for (i = 0; i < qtdemux->n_streams; i++) {
5599 const QtDemuxRandomAccessEntry *entry;
5600 QtDemuxStream *stream;
5601 gboolean is_audio_or_video;
5603 stream = qtdemux->streams[i];
5605 g_free (stream->samples);
5606 stream->samples = NULL;
5607 stream->n_samples = 0;
5608 stream->stbl_index = -1; /* no samples have yet been parsed */
5609 stream->sample_index = -1;
5611 if (stream->protection_scheme_info) {
5612 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5613 if (stream->protection_scheme_type == FOURCC_cenc) {
5614 QtDemuxCencSampleSetInfo *info =
5615 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5616 if (info->crypto_info) {
5617 g_ptr_array_free (info->crypto_info, TRUE);
5618 info->crypto_info = NULL;
5623 if (stream->ra_entries == NULL)
5626 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5627 is_audio_or_video = TRUE;
5629 is_audio_or_video = FALSE;
5632 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5633 stream->time_position, !is_audio_or_video);
5635 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5636 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5638 stream->pending_seek = entry;
5640 /* decide position to jump to just based on audio/video tracks, not subs */
5641 if (!is_audio_or_video)
5644 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5648 if (best_entry == NULL) {
5649 GST_OBJECT_UNLOCK (qtdemux);
5653 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5654 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5655 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5656 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5658 qtdemux->moof_offset = best_entry->moof_offset;
5660 qtdemux_add_fragmented_samples (qtdemux);
5662 GST_OBJECT_UNLOCK (qtdemux);
5666 static GstFlowReturn
5667 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5669 GstFlowReturn ret = GST_FLOW_OK;
5670 GstBuffer *buf = NULL;
5671 QtDemuxStream *stream;
5672 GstClockTime min_time;
5674 GstClockTime dts = GST_CLOCK_TIME_NONE;
5675 GstClockTime pts = GST_CLOCK_TIME_NONE;
5676 GstClockTime duration = 0;
5677 gboolean keyframe = FALSE;
5678 guint sample_size = 0;
5684 gst_qtdemux_push_pending_newsegment (qtdemux);
5686 if (qtdemux->fragmented_seek_pending) {
5687 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5688 gst_qtdemux_do_fragmented_seek (qtdemux);
5689 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5690 qtdemux->fragmented_seek_pending = FALSE;
5693 /* Figure out the next stream sample to output, min_time is expressed in
5694 * global time and runs over the edit list segments. */
5695 min_time = G_MAXUINT64;
5697 for (i = 0; i < qtdemux->n_streams; i++) {
5698 GstClockTime position;
5700 stream = qtdemux->streams[i];
5701 position = stream->time_position;
5703 /* position of -1 is EOS */
5704 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5705 min_time = position;
5710 if (G_UNLIKELY (index == -1)) {
5711 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5715 /* check for segment end */
5716 if (G_UNLIKELY (qtdemux->segment.stop != -1
5717 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5718 || (qtdemux->segment.rate < 0
5719 && qtdemux->segment.start > min_time))
5720 && qtdemux->streams[index]->on_keyframe)) {
5721 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5722 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5726 /* gap events for subtitle streams */
5727 for (i = 0; i < qtdemux->n_streams; i++) {
5728 stream = qtdemux->streams[i];
5729 if (stream->pad && (stream->subtype == FOURCC_subp
5730 || stream->subtype == FOURCC_text
5731 || stream->subtype == FOURCC_sbtl)) {
5732 /* send one second gap events until the stream catches up */
5733 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5734 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5735 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5736 stream->segment.position + GST_SECOND < min_time) {
5738 gst_event_new_gap (stream->segment.position, GST_SECOND);
5739 gst_pad_push_event (stream->pad, gap);
5740 stream->segment.position += GST_SECOND;
5745 stream = qtdemux->streams[index];
5746 /* fetch info for the current sample of this stream */
5747 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5748 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5751 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
5752 if (stream->new_caps) {
5753 gst_qtdemux_configure_stream (qtdemux, stream);
5754 qtdemux_do_allocation (qtdemux, stream);
5757 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5758 if (G_UNLIKELY (qtdemux->
5759 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5760 if (stream->subtype == FOURCC_vide && !keyframe) {
5761 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5766 GST_DEBUG_OBJECT (qtdemux,
5767 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5768 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5769 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5770 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5772 if (G_UNLIKELY (empty)) {
5773 /* empty segment, push a gap and move to the next one */
5774 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5775 stream->segment.position = pts + duration;
5779 /* hmm, empty sample, skip and move to next sample */
5780 if (G_UNLIKELY (sample_size <= 0))
5783 /* last pushed sample was out of boundary, goto next sample */
5784 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5787 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5790 GST_DEBUG_OBJECT (qtdemux,
5791 "size %d larger than stream max_buffer_size %d, trimming",
5792 sample_size, stream->max_buffer_size);
5794 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5797 if (qtdemux->cenc_aux_info_offset > 0) {
5800 GstBuffer *aux_info = NULL;
5802 /* pull the data stored before the sample */
5804 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5805 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5806 if (G_UNLIKELY (ret != GST_FLOW_OK))
5808 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5809 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5810 gst_byte_reader_init (&br, map.data + 8, map.size);
5811 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5812 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5813 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5814 gst_buffer_unmap (aux_info, &map);
5815 gst_buffer_unref (aux_info);
5816 ret = GST_FLOW_ERROR;
5819 gst_buffer_unmap (aux_info, &map);
5820 gst_buffer_unref (aux_info);
5823 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5826 if (stream->use_allocator) {
5827 /* if we have a per-stream allocator, use it */
5828 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5831 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5833 if (G_UNLIKELY (ret != GST_FLOW_OK))
5836 if (size != sample_size) {
5837 pts += gst_util_uint64_scale_int (GST_SECOND,
5838 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5841 gst_util_uint64_scale_int (GST_SECOND,
5842 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5845 gst_util_uint64_scale_int (GST_SECOND,
5846 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
5849 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5850 dts, pts, duration, keyframe, min_time, offset);
5852 if (size != sample_size) {
5853 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5854 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5856 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5858 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
5859 if (time_position >= segment->media_start) {
5860 /* inside the segment, update time_position, looks very familiar to
5861 * GStreamer segments, doesn't it? */
5862 stream->time_position = (time_position - segment->media_start) +
5865 /* not yet in segment, time does not yet increment. This means
5866 * that we are still prerolling keyframes to the decoder so it can
5867 * decode the first sample of the segment. */
5868 stream->time_position = segment->time;
5873 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5874 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5875 * we have no more data for the pad to push */
5876 if (ret == GST_FLOW_EOS)
5879 stream->offset_in_sample += size;
5880 if (stream->offset_in_sample >= sample_size) {
5881 gst_qtdemux_advance_sample (qtdemux, stream);
5886 gst_qtdemux_advance_sample (qtdemux, stream);
5894 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5900 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5901 /* EOS will be raised if all are EOS */
5908 gst_qtdemux_loop (GstPad * pad)
5910 GstQTDemux *qtdemux;
5914 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5916 cur_offset = qtdemux->offset;
5917 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5918 cur_offset, qt_demux_state_string (qtdemux->state));
5920 switch (qtdemux->state) {
5921 case QTDEMUX_STATE_INITIAL:
5922 case QTDEMUX_STATE_HEADER:
5923 ret = gst_qtdemux_loop_state_header (qtdemux);
5925 case QTDEMUX_STATE_MOVIE:
5926 ret = gst_qtdemux_loop_state_movie (qtdemux);
5927 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5928 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5936 /* if something went wrong, pause */
5937 if (ret != GST_FLOW_OK)
5941 gst_object_unref (qtdemux);
5947 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5948 (NULL), ("streaming stopped, invalid state"));
5949 gst_pad_pause_task (pad);
5950 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5955 const gchar *reason = gst_flow_get_name (ret);
5957 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5959 gst_pad_pause_task (pad);
5961 /* fatal errors need special actions */
5963 if (ret == GST_FLOW_EOS) {
5964 if (qtdemux->n_streams == 0) {
5965 /* we have no streams, post an error */
5966 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5968 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5971 if ((stop = qtdemux->segment.stop) == -1)
5972 stop = qtdemux->segment.duration;
5974 if (qtdemux->segment.rate >= 0) {
5975 GstMessage *message;
5978 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5979 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5980 GST_FORMAT_TIME, stop);
5981 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5982 if (qtdemux->segment_seqnum) {
5983 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5984 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5986 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5987 gst_qtdemux_push_event (qtdemux, event);
5989 GstMessage *message;
5992 /* For Reverse Playback */
5993 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5994 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5995 GST_FORMAT_TIME, qtdemux->segment.start);
5996 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5997 qtdemux->segment.start);
5998 if (qtdemux->segment_seqnum) {
5999 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6000 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6002 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6003 gst_qtdemux_push_event (qtdemux, event);
6008 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6009 event = gst_event_new_eos ();
6010 if (qtdemux->segment_seqnum)
6011 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6012 gst_qtdemux_push_event (qtdemux, event);
6014 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6015 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6016 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6025 * Returns if there are samples to be played.
6028 has_next_entry (GstQTDemux * demux)
6030 QtDemuxStream *stream;
6033 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6035 for (i = 0; i < demux->n_streams; i++) {
6036 stream = demux->streams[i];
6038 if (stream->sample_index == -1) {
6039 stream->sample_index = 0;
6040 stream->offset_in_sample = 0;
6043 if (stream->sample_index >= stream->n_samples) {
6044 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6047 GST_DEBUG_OBJECT (demux, "Found a sample");
6051 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6058 * Returns the size of the first entry at the current offset.
6059 * If -1, there are none (which means EOS or empty file).
6062 next_entry_size (GstQTDemux * demux)
6064 QtDemuxStream *stream;
6067 guint64 smalloffs = (guint64) - 1;
6068 QtDemuxSample *sample;
6070 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6073 for (i = 0; i < demux->n_streams; i++) {
6074 stream = demux->streams[i];
6076 if (stream->sample_index == -1) {
6077 stream->sample_index = 0;
6078 stream->offset_in_sample = 0;
6081 if (stream->sample_index >= stream->n_samples) {
6082 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6086 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6087 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6088 stream->sample_index);
6092 sample = &stream->samples[stream->sample_index];
6094 GST_LOG_OBJECT (demux,
6095 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6096 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6097 sample->offset, sample->size);
6099 if (((smalloffs == -1)
6100 || (sample->offset < smalloffs)) && (sample->size)) {
6102 smalloffs = sample->offset;
6106 GST_LOG_OBJECT (demux,
6107 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6108 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6113 stream = demux->streams[smallidx];
6114 sample = &stream->samples[stream->sample_index];
6116 if (sample->offset >= demux->offset) {
6117 demux->todrop = sample->offset - demux->offset;
6118 return sample->size + demux->todrop;
6121 GST_DEBUG_OBJECT (demux,
6122 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6127 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6129 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6131 gst_element_post_message (GST_ELEMENT_CAST (demux),
6132 gst_message_new_element (GST_OBJECT_CAST (demux),
6133 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6137 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6142 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6145 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6146 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6147 GST_SEEK_TYPE_NONE, -1);
6149 /* store seqnum to drop flush events, they don't need to reach downstream */
6150 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6151 res = gst_pad_push_event (demux->sinkpad, event);
6152 demux->offset_seek_seqnum = 0;
6157 /* check for seekable upstream, above and beyond a mere query */
6159 gst_qtdemux_check_seekability (GstQTDemux * demux)
6162 gboolean seekable = FALSE;
6163 gint64 start = -1, stop = -1;
6165 if (demux->upstream_size)
6168 if (demux->upstream_format_is_time)
6171 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6172 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6173 GST_DEBUG_OBJECT (demux, "seeking query failed");
6177 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6179 /* try harder to query upstream size if we didn't get it the first time */
6180 if (seekable && stop == -1) {
6181 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6182 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6185 /* if upstream doesn't know the size, it's likely that it's not seekable in
6186 * practice even if it technically may be seekable */
6187 if (seekable && (start != 0 || stop <= start)) {
6188 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6193 gst_query_unref (query);
6195 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6196 G_GUINT64_FORMAT ")", seekable, start, stop);
6197 demux->upstream_seekable = seekable;
6198 demux->upstream_size = seekable ? stop : -1;
6202 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6204 g_return_if_fail (bytes <= demux->todrop);
6206 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6207 gst_adapter_flush (demux->adapter, bytes);
6208 demux->neededbytes -= bytes;
6209 demux->offset += bytes;
6210 demux->todrop -= bytes;
6214 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6216 if (G_UNLIKELY (demux->pending_newsegment)) {
6219 gst_qtdemux_push_pending_newsegment (demux);
6220 /* clear to send tags on all streams */
6221 for (i = 0; i < demux->n_streams; i++) {
6222 QtDemuxStream *stream;
6223 stream = demux->streams[i];
6224 gst_qtdemux_push_tags (demux, stream);
6225 if (CUR_STREAM (stream)->sparse) {
6226 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6227 gst_pad_push_event (stream->pad,
6228 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6235 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6236 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6238 GstClockTime ts, dur;
6243 stream->segments[segment_index].duration - (pos -
6244 stream->segments[segment_index].time);
6245 gap = gst_event_new_gap (ts, dur);
6246 stream->time_position += dur;
6248 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6249 "segment: %" GST_PTR_FORMAT, gap);
6250 gst_pad_push_event (stream->pad, gap);
6254 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6255 QtDemuxStream * stream)
6259 /* Push any initial gap segments before proceeding to the
6261 for (i = 0; i < stream->n_segments; i++) {
6262 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6264 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6265 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6266 stream->time_position);
6268 /* Only support empty segment at the beginning followed by
6269 * one non-empty segment, this was checked when parsing the
6270 * edts atom, arriving here is unexpected */
6271 g_assert (i + 1 == stream->n_segments);
6277 static GstFlowReturn
6278 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6282 demux = GST_QTDEMUX (parent);
6284 GST_DEBUG_OBJECT (demux,
6285 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6286 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6287 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6288 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6289 gst_buffer_get_size (inbuf), demux->offset);
6291 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6292 gboolean is_gap_input = FALSE;
6295 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6297 for (i = 0; i < demux->n_streams; i++) {
6298 demux->streams[i]->discont = TRUE;
6301 /* Check if we can land back on our feet in the case where upstream is
6302 * handling the seeking/pushing of samples with gaps in between (like
6303 * in the case of trick-mode DASH for example) */
6304 if (demux->upstream_format_is_time
6305 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6307 for (i = 0; i < demux->n_streams; i++) {
6309 GST_LOG_OBJECT (demux,
6310 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6311 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6313 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6314 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6316 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6317 GST_LOG_OBJECT (demux,
6318 "Checking if sample %d from stream %d is valid (offset:%"
6319 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6320 sample->offset, sample->size);
6321 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6322 GST_LOG_OBJECT (demux,
6323 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6325 is_gap_input = TRUE;
6326 /* We can go back to standard playback mode */
6327 demux->state = QTDEMUX_STATE_MOVIE;
6328 /* Remember which sample this stream is at */
6329 demux->streams[i]->sample_index = res;
6330 /* Finally update all push-based values to the expected values */
6331 demux->neededbytes = demux->streams[i]->samples[res].size;
6332 demux->offset = GST_BUFFER_OFFSET (inbuf);
6334 demux->mdatsize - demux->offset + demux->mdatoffset;
6339 if (!is_gap_input) {
6340 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6341 /* Reset state if it's a real discont */
6342 demux->neededbytes = 16;
6343 demux->state = QTDEMUX_STATE_INITIAL;
6344 demux->offset = GST_BUFFER_OFFSET (inbuf);
6345 gst_adapter_clear (demux->adapter);
6348 /* Reverse fragmented playback, need to flush all we have before
6349 * consuming a new fragment.
6350 * The samples array have the timestamps calculated by accumulating the
6351 * durations but this won't work for reverse playback of fragments as
6352 * the timestamps of a subsequent fragment should be smaller than the
6353 * previously received one. */
6354 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6355 gst_qtdemux_process_adapter (demux, TRUE);
6356 for (i = 0; i < demux->n_streams; i++)
6357 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6361 gst_adapter_push (demux->adapter, inbuf);
6363 GST_DEBUG_OBJECT (demux,
6364 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6365 demux->neededbytes, gst_adapter_available (demux->adapter));
6367 return gst_qtdemux_process_adapter (demux, FALSE);
6370 static GstFlowReturn
6371 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6373 GstFlowReturn ret = GST_FLOW_OK;
6375 /* we never really mean to buffer that much */
6376 if (demux->neededbytes == -1) {
6380 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6381 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6383 #ifndef GST_DISABLE_GST_DEBUG
6385 guint64 discont_offset, distance_from_discont;
6387 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6388 distance_from_discont =
6389 gst_adapter_distance_from_discont (demux->adapter);
6391 GST_DEBUG_OBJECT (demux,
6392 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6393 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6394 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6395 demux->offset, discont_offset, distance_from_discont);
6399 switch (demux->state) {
6400 case QTDEMUX_STATE_INITIAL:{
6405 gst_qtdemux_check_seekability (demux);
6407 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6409 /* get fourcc/length, set neededbytes */
6410 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6412 gst_adapter_unmap (demux->adapter);
6414 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6415 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6417 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6418 (_("This file is invalid and cannot be played.")),
6419 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6420 GST_FOURCC_ARGS (fourcc)));
6421 ret = GST_FLOW_ERROR;
6424 if (fourcc == FOURCC_mdat) {
6425 gint next_entry = next_entry_size (demux);
6426 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6427 /* we have the headers, start playback */
6428 demux->state = QTDEMUX_STATE_MOVIE;
6429 demux->neededbytes = next_entry;
6430 demux->mdatleft = size;
6431 demux->mdatsize = demux->mdatleft;
6433 /* no headers yet, try to get them */
6436 guint64 old, target;
6439 old = demux->offset;
6440 target = old + size;
6442 /* try to jump over the atom with a seek */
6443 /* only bother if it seems worth doing so,
6444 * and avoids possible upstream/server problems */
6445 if (demux->upstream_seekable &&
6446 demux->upstream_size > 4 * (1 << 20)) {
6447 res = qtdemux_seek_offset (demux, target);
6449 GST_DEBUG_OBJECT (demux, "skipping seek");
6454 GST_DEBUG_OBJECT (demux, "seek success");
6455 /* remember the offset fo the first mdat so we can seek back to it
6456 * after we have the headers */
6457 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6458 demux->first_mdat = old;
6459 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6462 /* seek worked, continue reading */
6463 demux->offset = target;
6464 demux->neededbytes = 16;
6465 demux->state = QTDEMUX_STATE_INITIAL;
6467 /* seek failed, need to buffer */
6468 demux->offset = old;
6469 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6470 /* there may be multiple mdat (or alike) buffers */
6472 if (demux->mdatbuffer)
6473 bs = gst_buffer_get_size (demux->mdatbuffer);
6476 if (size + bs > 10 * (1 << 20))
6478 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6479 demux->neededbytes = size;
6480 if (!demux->mdatbuffer)
6481 demux->mdatoffset = demux->offset;
6484 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6485 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6486 (_("This file is invalid and cannot be played.")),
6487 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6488 GST_FOURCC_ARGS (fourcc), size));
6489 ret = GST_FLOW_ERROR;
6492 /* this means we already started buffering and still no moov header,
6493 * let's continue buffering everything till we get moov */
6494 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6495 || fourcc == FOURCC_moof))
6497 demux->neededbytes = size;
6498 demux->state = QTDEMUX_STATE_HEADER;
6502 case QTDEMUX_STATE_HEADER:{
6506 GST_DEBUG_OBJECT (demux, "In header");
6508 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6510 /* parse the header */
6511 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6513 if (fourcc == FOURCC_moov) {
6516 /* in usual fragmented setup we could try to scan for more
6517 * and end up at the the moov (after mdat) again */
6518 if (demux->got_moov && demux->n_streams > 0 &&
6520 || demux->last_moov_offset == demux->offset)) {
6521 GST_DEBUG_OBJECT (demux,
6522 "Skipping moov atom as we have (this) one already");
6524 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6526 if (demux->got_moov && demux->fragmented) {
6527 GST_DEBUG_OBJECT (demux,
6528 "Got a second moov, clean up data from old one");
6529 if (demux->moov_node_compressed) {
6530 g_node_destroy (demux->moov_node_compressed);
6531 if (demux->moov_node)
6532 g_free (demux->moov_node->data);
6534 demux->moov_node_compressed = NULL;
6535 if (demux->moov_node)
6536 g_node_destroy (demux->moov_node);
6537 demux->moov_node = NULL;
6539 /* prepare newsegment to send when streaming actually starts */
6540 if (!demux->pending_newsegment) {
6541 demux->pending_newsegment =
6542 gst_event_new_segment (&demux->segment);
6543 if (demux->segment_seqnum)
6544 gst_event_set_seqnum (demux->pending_newsegment,
6545 demux->segment_seqnum);
6549 demux->last_moov_offset = demux->offset;
6551 qtdemux_parse_moov (demux, data, demux->neededbytes);
6552 qtdemux_node_dump (demux, demux->moov_node);
6553 qtdemux_parse_tree (demux);
6554 qtdemux_prepare_streams (demux);
6555 if (!demux->got_moov)
6556 qtdemux_expose_streams (demux);
6559 for (n = 0; n < demux->n_streams; n++) {
6560 QtDemuxStream *stream = demux->streams[n];
6562 gst_qtdemux_configure_stream (demux, stream);
6566 demux->got_moov = TRUE;
6567 gst_qtdemux_check_send_pending_segment (demux);
6569 /* fragmented streams headers shouldn't contain edts atoms */
6570 if (!demux->fragmented) {
6571 for (n = 0; n < demux->n_streams; n++) {
6572 gst_qtdemux_stream_send_initial_gap_segments (demux,
6577 if (demux->moov_node_compressed) {
6578 g_node_destroy (demux->moov_node_compressed);
6579 g_free (demux->moov_node->data);
6581 demux->moov_node_compressed = NULL;
6582 g_node_destroy (demux->moov_node);
6583 demux->moov_node = NULL;
6584 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6586 } else if (fourcc == FOURCC_moof) {
6587 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6589 GstClockTime prev_pts;
6590 guint64 prev_offset;
6591 guint64 adapter_discont_offset, adapter_discont_dist;
6593 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6596 * The timestamp of the moof buffer is relevant as some scenarios
6597 * won't have the initial timestamp in the atoms. Whenever a new
6598 * buffer has started, we get that buffer's PTS and use it as a base
6599 * timestamp for the trun entries.
6601 * To keep track of the current buffer timestamp and starting point
6602 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6603 * from the beggining of the buffer, with the distance and demux->offset
6604 * we know if it is still the same buffer or not.
6606 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6607 prev_offset = demux->offset - dist;
6608 if (demux->fragment_start_offset == -1
6609 || prev_offset > demux->fragment_start_offset) {
6610 demux->fragment_start_offset = prev_offset;
6611 demux->fragment_start = prev_pts;
6612 GST_DEBUG_OBJECT (demux,
6613 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6614 GST_TIME_FORMAT, demux->fragment_start_offset,
6615 GST_TIME_ARGS (demux->fragment_start));
6618 /* We can't use prev_offset() here because this would require
6619 * upstream to set consistent and correct offsets on all buffers
6620 * since the discont. Nothing ever did that in the past and we
6621 * would break backwards compatibility here then.
6622 * Instead take the offset we had at the last discont and count
6623 * the bytes from there. This works with old code as there would
6624 * be no discont between moov and moof, and also works with
6625 * adaptivedemux which correctly sets offset and will set the
6626 * DISCONT flag accordingly when needed.
6628 * We also only do this for upstream TIME segments as otherwise
6629 * there are potential backwards compatibility problems with
6630 * seeking in PUSH mode and upstream providing inconsistent
6632 adapter_discont_offset =
6633 gst_adapter_offset_at_discont (demux->adapter);
6634 adapter_discont_dist =
6635 gst_adapter_distance_from_discont (demux->adapter);
6637 GST_DEBUG_OBJECT (demux,
6638 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6639 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6640 demux->offset, adapter_discont_offset, adapter_discont_dist);
6642 if (demux->upstream_format_is_time) {
6643 demux->moof_offset = adapter_discont_offset;
6644 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6645 demux->moof_offset += adapter_discont_dist;
6646 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6647 demux->moof_offset = demux->offset;
6649 demux->moof_offset = demux->offset;
6652 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6653 demux->moof_offset, NULL)) {
6654 gst_adapter_unmap (demux->adapter);
6655 ret = GST_FLOW_ERROR;
6658 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6659 if (demux->mss_mode && !demux->exposed) {
6660 if (!demux->pending_newsegment) {
6661 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6662 demux->pending_newsegment =
6663 gst_event_new_segment (&demux->segment);
6664 if (demux->segment_seqnum)
6665 gst_event_set_seqnum (demux->pending_newsegment,
6666 demux->segment_seqnum);
6668 qtdemux_expose_streams (demux);
6671 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6673 } else if (fourcc == FOURCC_ftyp) {
6674 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6675 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6676 } else if (fourcc == FOURCC_uuid) {
6677 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6678 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6679 } else if (fourcc == FOURCC_sidx) {
6680 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6681 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6685 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6688 /* [free] is a padding atom */
6689 GST_DEBUG_OBJECT (demux,
6690 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6691 GST_FOURCC_ARGS (fourcc));
6694 GST_WARNING_OBJECT (demux,
6695 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6696 GST_FOURCC_ARGS (fourcc));
6697 /* Let's jump that one and go back to initial state */
6701 gst_adapter_unmap (demux->adapter);
6704 if (demux->mdatbuffer && demux->n_streams) {
6705 gsize remaining_data_size = 0;
6707 /* the mdat was before the header */
6708 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6709 demux->n_streams, demux->mdatbuffer);
6710 /* restore our adapter/offset view of things with upstream;
6711 * put preceding buffered data ahead of current moov data.
6712 * This should also handle evil mdat, moov, mdat cases and alike */
6713 gst_adapter_flush (demux->adapter, demux->neededbytes);
6715 /* Store any remaining data after the mdat for later usage */
6716 remaining_data_size = gst_adapter_available (demux->adapter);
6717 if (remaining_data_size > 0) {
6718 g_assert (demux->restoredata_buffer == NULL);
6719 demux->restoredata_buffer =
6720 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6721 demux->restoredata_offset = demux->offset + demux->neededbytes;
6722 GST_DEBUG_OBJECT (demux,
6723 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6724 G_GUINT64_FORMAT, remaining_data_size,
6725 demux->restoredata_offset);
6728 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6729 demux->mdatbuffer = NULL;
6730 demux->offset = demux->mdatoffset;
6731 demux->neededbytes = next_entry_size (demux);
6732 demux->state = QTDEMUX_STATE_MOVIE;
6733 demux->mdatleft = gst_adapter_available (demux->adapter);
6734 demux->mdatsize = demux->mdatleft;
6736 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6737 gst_adapter_flush (demux->adapter, demux->neededbytes);
6739 /* only go back to the mdat if there are samples to play */
6740 if (demux->got_moov && demux->first_mdat != -1
6741 && has_next_entry (demux)) {
6744 /* we need to seek back */
6745 res = qtdemux_seek_offset (demux, demux->first_mdat);
6747 demux->offset = demux->first_mdat;
6749 GST_DEBUG_OBJECT (demux, "Seek back failed");
6752 demux->offset += demux->neededbytes;
6754 demux->neededbytes = 16;
6755 demux->state = QTDEMUX_STATE_INITIAL;
6760 case QTDEMUX_STATE_BUFFER_MDAT:{
6764 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6766 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6767 gst_buffer_extract (buf, 0, fourcc, 4);
6768 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6769 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6770 if (demux->mdatbuffer)
6771 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6773 demux->mdatbuffer = buf;
6774 demux->offset += demux->neededbytes;
6775 demux->neededbytes = 16;
6776 demux->state = QTDEMUX_STATE_INITIAL;
6777 gst_qtdemux_post_progress (demux, 1, 1);
6781 case QTDEMUX_STATE_MOVIE:{
6782 QtDemuxStream *stream = NULL;
6783 QtDemuxSample *sample;
6785 GstClockTime dts, pts, duration;
6788 GST_DEBUG_OBJECT (demux,
6789 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6791 if (demux->fragmented) {
6792 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6794 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6795 /* if needed data starts within this atom,
6796 * then it should not exceed this atom */
6797 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6798 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6799 (_("This file is invalid and cannot be played.")),
6800 ("sample data crosses atom boundary"));
6801 ret = GST_FLOW_ERROR;
6804 demux->mdatleft -= demux->neededbytes;
6806 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6807 /* so we are dropping more than left in this atom */
6808 gst_qtdemux_drop_data (demux, demux->mdatleft);
6809 demux->mdatleft = 0;
6811 /* need to resume atom parsing so we do not miss any other pieces */
6812 demux->state = QTDEMUX_STATE_INITIAL;
6813 demux->neededbytes = 16;
6815 /* check if there was any stored post mdat data from previous buffers */
6816 if (demux->restoredata_buffer) {
6817 g_assert (gst_adapter_available (demux->adapter) == 0);
6819 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6820 demux->restoredata_buffer = NULL;
6821 demux->offset = demux->restoredata_offset;
6828 if (demux->todrop) {
6829 if (demux->cenc_aux_info_offset > 0) {
6833 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6834 data = gst_adapter_map (demux->adapter, demux->todrop);
6835 gst_byte_reader_init (&br, data + 8, demux->todrop);
6836 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6837 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6838 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6839 ret = GST_FLOW_ERROR;
6840 gst_adapter_unmap (demux->adapter);
6841 g_free (demux->cenc_aux_info_sizes);
6842 demux->cenc_aux_info_sizes = NULL;
6845 demux->cenc_aux_info_offset = 0;
6846 g_free (demux->cenc_aux_info_sizes);
6847 demux->cenc_aux_info_sizes = NULL;
6848 gst_adapter_unmap (demux->adapter);
6850 gst_qtdemux_drop_data (demux, demux->todrop);
6854 /* initial newsegment sent here after having added pads,
6855 * possible others in sink_event */
6856 gst_qtdemux_check_send_pending_segment (demux);
6858 /* Figure out which stream this packet belongs to */
6859 for (i = 0; i < demux->n_streams; i++) {
6860 stream = demux->streams[i];
6861 if (stream->sample_index >= stream->n_samples)
6863 GST_LOG_OBJECT (demux,
6864 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6865 " / size:%d)", i, stream->sample_index,
6866 stream->samples[stream->sample_index].offset,
6867 stream->samples[stream->sample_index].size);
6869 if (stream->samples[stream->sample_index].offset == demux->offset)
6873 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6874 goto unknown_stream;
6876 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
6878 if (stream->new_caps) {
6879 gst_qtdemux_configure_stream (demux, stream);
6882 /* Put data in a buffer, set timestamps, caps, ... */
6883 sample = &stream->samples[stream->sample_index];
6885 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6886 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6887 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
6889 dts = QTSAMPLE_DTS (stream, sample);
6890 pts = QTSAMPLE_PTS (stream, sample);
6891 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6892 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6894 /* check for segment end */
6895 if (G_UNLIKELY (demux->segment.stop != -1
6896 && demux->segment.stop <= pts && stream->on_keyframe)) {
6897 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6898 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6900 /* skip this data, stream is EOS */
6901 gst_adapter_flush (demux->adapter, demux->neededbytes);
6902 demux->offset += demux->neededbytes;
6904 /* check if all streams are eos */
6906 for (i = 0; i < demux->n_streams; i++) {
6907 if (!STREAM_IS_EOS (demux->streams[i])) {
6916 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6918 /* FIXME: should either be an assert or a plain check */
6919 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6921 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6922 dts, pts, duration, keyframe, dts, demux->offset);
6926 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6928 /* skip this data, stream is EOS */
6929 gst_adapter_flush (demux->adapter, demux->neededbytes);
6932 stream->sample_index++;
6933 stream->offset_in_sample = 0;
6935 /* update current offset and figure out size of next buffer */
6936 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6937 demux->offset, demux->neededbytes);
6938 demux->offset += demux->neededbytes;
6939 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6943 if (ret == GST_FLOW_EOS) {
6944 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6945 demux->neededbytes = -1;
6949 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6950 if (demux->fragmented) {
6951 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6952 /* there may be more to follow, only finish this atom */
6953 demux->todrop = demux->mdatleft;
6954 demux->neededbytes = demux->todrop;
6959 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
6960 goto non_ok_unlinked_flow;
6969 /* when buffering movie data, at least show user something is happening */
6970 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6971 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6972 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6973 demux->neededbytes);
6980 non_ok_unlinked_flow:
6982 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6983 gst_flow_get_name (ret));
6988 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6989 ret = GST_FLOW_ERROR;
6994 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7000 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7001 (NULL), ("qtdemuxer invalid state %d", demux->state));
7002 ret = GST_FLOW_ERROR;
7007 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7008 (NULL), ("no 'moov' atom within the first 10 MB"));
7009 ret = GST_FLOW_ERROR;
7015 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7020 query = gst_query_new_scheduling ();
7022 if (!gst_pad_peer_query (sinkpad, query)) {
7023 gst_query_unref (query);
7027 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7028 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7029 gst_query_unref (query);
7034 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7035 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7039 GST_DEBUG_OBJECT (sinkpad, "activating push");
7040 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7045 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7046 GstPadMode mode, gboolean active)
7049 GstQTDemux *demux = GST_QTDEMUX (parent);
7052 case GST_PAD_MODE_PUSH:
7053 demux->pullbased = FALSE;
7056 case GST_PAD_MODE_PULL:
7058 demux->pullbased = TRUE;
7059 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7062 res = gst_pad_stop_task (sinkpad);
7074 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7080 memset (&z, 0, sizeof (z));
7085 if ((ret = inflateInit (&z)) != Z_OK) {
7086 GST_ERROR ("inflateInit() returned %d", ret);
7090 z.next_in = z_buffer;
7091 z.avail_in = z_length;
7093 buffer = (guint8 *) g_malloc (*length);
7094 z.avail_out = *length;
7095 z.next_out = (Bytef *) buffer;
7097 ret = inflate (&z, Z_NO_FLUSH);
7098 if (ret == Z_STREAM_END) {
7100 } else if (ret != Z_OK) {
7101 GST_WARNING ("inflate() returned %d", ret);
7106 buffer = (guint8 *) g_realloc (buffer, *length);
7107 z.next_out = (Bytef *) (buffer + z.total_out);
7108 z.avail_out += 4096;
7109 } while (z.avail_in > 0);
7111 if (ret != Z_STREAM_END) {
7116 *length = z.total_out;
7123 #endif /* HAVE_ZLIB */
7126 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7130 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7132 /* counts as header data */
7133 qtdemux->header_size += length;
7135 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7136 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7138 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7145 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7146 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7147 if (dcom == NULL || cmvd == NULL)
7148 goto invalid_compression;
7150 dcom_len = QT_UINT32 (dcom->data);
7152 goto invalid_compression;
7154 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7158 guint uncompressed_length;
7159 guint compressed_length;
7163 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7165 goto invalid_compression;
7167 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7168 compressed_length = cmvd_len - 12;
7169 GST_LOG ("length = %u", uncompressed_length);
7172 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7173 compressed_length, &uncompressed_length);
7176 qtdemux->moov_node_compressed = qtdemux->moov_node;
7177 qtdemux->moov_node = g_node_new (buf);
7179 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7180 uncompressed_length);
7184 #endif /* HAVE_ZLIB */
7186 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7187 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7194 invalid_compression:
7196 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7202 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7205 while (G_UNLIKELY (buf < end)) {
7209 if (G_UNLIKELY (buf + 4 > end)) {
7210 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7213 len = QT_UINT32 (buf);
7214 if (G_UNLIKELY (len == 0)) {
7215 GST_LOG_OBJECT (qtdemux, "empty container");
7218 if (G_UNLIKELY (len < 8)) {
7219 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7222 if (G_UNLIKELY (len > (end - buf))) {
7223 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7224 (gint) (end - buf));
7228 child = g_node_new ((guint8 *) buf);
7229 g_node_append (node, child);
7230 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7231 qtdemux_parse_node (qtdemux, child, buf, len);
7239 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7242 int len = QT_UINT32 (xdxt->data);
7243 guint8 *buf = xdxt->data;
7244 guint8 *end = buf + len;
7247 /* skip size and type */
7255 size = QT_UINT32 (buf);
7256 type = QT_FOURCC (buf + 4);
7258 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7260 if (buf + size > end || size <= 0)
7266 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7267 GST_FOURCC_ARGS (type));
7271 buffer = gst_buffer_new_and_alloc (size);
7272 gst_buffer_fill (buffer, 0, buf, size);
7273 stream->buffers = g_slist_append (stream->buffers, buffer);
7274 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7277 buffer = gst_buffer_new_and_alloc (size);
7278 gst_buffer_fill (buffer, 0, buf, size);
7279 stream->buffers = g_slist_append (stream->buffers, buffer);
7280 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7283 buffer = gst_buffer_new_and_alloc (size);
7284 gst_buffer_fill (buffer, 0, buf, size);
7285 stream->buffers = g_slist_append (stream->buffers, buffer);
7286 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7289 GST_WARNING_OBJECT (qtdemux,
7290 "unknown theora cookie %" GST_FOURCC_FORMAT,
7291 GST_FOURCC_ARGS (type));
7300 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7304 guint32 node_length = 0;
7305 const QtNodeType *type;
7308 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7310 if (G_UNLIKELY (length < 8))
7311 goto not_enough_data;
7313 node_length = QT_UINT32 (buffer);
7314 fourcc = QT_FOURCC (buffer + 4);
7316 /* ignore empty nodes */
7317 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7320 type = qtdemux_type_get (fourcc);
7322 end = buffer + length;
7324 GST_LOG_OBJECT (qtdemux,
7325 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7326 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7328 if (node_length > length)
7329 goto broken_atom_size;
7331 if (type->flags & QT_FLAG_CONTAINER) {
7332 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7337 if (node_length < 20) {
7338 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7341 GST_DEBUG_OBJECT (qtdemux,
7342 "parsing stsd (sample table, sample description) atom");
7343 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7344 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7355 /* also read alac (or whatever) in stead of mp4a in the following,
7356 * since a similar layout is used in other cases as well */
7357 if (fourcc == FOURCC_mp4a)
7359 else if (fourcc == FOURCC_fLaC)
7364 /* There are two things we might encounter here: a true mp4a atom, and
7365 an mp4a entry in an stsd atom. The latter is what we're interested
7366 in, and it looks like an atom, but isn't really one. The true mp4a
7367 atom is short, so we detect it based on length here. */
7368 if (length < min_size) {
7369 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7370 GST_FOURCC_ARGS (fourcc));
7374 /* 'version' here is the sound sample description version. Types 0 and
7375 1 are documented in the QTFF reference, but type 2 is not: it's
7376 described in Apple header files instead (struct SoundDescriptionV2
7378 version = QT_UINT16 (buffer + 16);
7380 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7381 GST_FOURCC_ARGS (fourcc), version);
7383 /* parse any esds descriptors */
7395 GST_WARNING_OBJECT (qtdemux,
7396 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7397 GST_FOURCC_ARGS (fourcc), version);
7402 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7428 /* codec_data is contained inside these atoms, which all have
7429 * the same format. */
7430 /* video sample description size is 86 bytes without extension.
7431 * node_length have to be bigger than 86 bytes because video sample
7432 * description can include extenstions such as esds, fiel, glbl, etc. */
7433 if (node_length < 86) {
7434 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7435 " sample description length too short (%u < 86)",
7436 GST_FOURCC_ARGS (fourcc), node_length);
7440 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7441 GST_FOURCC_ARGS (fourcc));
7443 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7445 * revision level (2 bytes) : must be set to 0. */
7446 version = QT_UINT32 (buffer + 16);
7447 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7449 /* compressor name : PASCAL string and informative purposes
7450 * first byte : the number of bytes to be displayed.
7451 * it has to be less than 32 because it is reserved
7452 * space of 32 bytes total including itself. */
7453 str_len = QT_UINT8 (buffer + 50);
7455 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7456 (char *) buffer + 51);
7458 GST_WARNING_OBJECT (qtdemux,
7459 "compressorname length too big (%u > 31)", str_len);
7461 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7463 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7468 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7469 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7474 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7475 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7476 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7485 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7486 GST_FOURCC_ARGS (fourcc));
7490 version = QT_UINT32 (buffer + 12);
7491 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7498 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7503 if (length < offset) {
7504 GST_WARNING_OBJECT (qtdemux,
7505 "skipping too small %" GST_FOURCC_FORMAT " box",
7506 GST_FOURCC_ARGS (fourcc));
7509 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7515 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7520 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7525 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7529 if (!strcmp (type->name, "unknown"))
7530 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7534 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7535 GST_FOURCC_ARGS (fourcc));
7541 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7542 (_("This file is corrupt and cannot be played.")),
7543 ("Not enough data for an atom header, got only %u bytes", length));
7548 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7549 (_("This file is corrupt and cannot be played.")),
7550 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7551 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7558 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7562 guint32 child_fourcc;
7564 for (child = g_node_first_child (node); child;
7565 child = g_node_next_sibling (child)) {
7566 buffer = (guint8 *) child->data;
7568 child_fourcc = QT_FOURCC (buffer + 4);
7570 if (G_UNLIKELY (child_fourcc == fourcc)) {
7578 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7579 GstByteReader * parser)
7583 guint32 child_fourcc, child_len;
7585 for (child = g_node_first_child (node); child;
7586 child = g_node_next_sibling (child)) {
7587 buffer = (guint8 *) child->data;
7589 child_len = QT_UINT32 (buffer);
7590 child_fourcc = QT_FOURCC (buffer + 4);
7592 if (G_UNLIKELY (child_fourcc == fourcc)) {
7593 if (G_UNLIKELY (child_len < (4 + 4)))
7595 /* FIXME: must verify if atom length < parent atom length */
7596 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7604 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7606 return g_node_nth_child (node, index);
7610 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7611 GstByteReader * parser)
7615 guint32 child_fourcc, child_len;
7617 for (child = g_node_next_sibling (node); child;
7618 child = g_node_next_sibling (child)) {
7619 buffer = (guint8 *) child->data;
7621 child_fourcc = QT_FOURCC (buffer + 4);
7623 if (child_fourcc == fourcc) {
7625 child_len = QT_UINT32 (buffer);
7626 if (G_UNLIKELY (child_len < (4 + 4)))
7628 /* FIXME: must verify if atom length < parent atom length */
7629 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7638 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7640 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7644 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7646 /* FIXME: This can only reliably work if demuxers have a
7647 * separate streaming thread per srcpad. This should be
7648 * done in a demuxer base class, which integrates parts
7651 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7656 query = gst_query_new_allocation (stream->caps, FALSE);
7658 if (!gst_pad_peer_query (stream->pad, query)) {
7659 /* not a problem, just debug a little */
7660 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7663 if (stream->allocator)
7664 gst_object_unref (stream->allocator);
7666 if (gst_query_get_n_allocation_params (query) > 0) {
7667 /* try the allocator */
7668 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7670 stream->use_allocator = TRUE;
7672 stream->allocator = NULL;
7673 gst_allocation_params_init (&stream->params);
7674 stream->use_allocator = FALSE;
7676 gst_query_unref (query);
7681 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7682 QtDemuxStream * stream)
7685 const gchar *selected_system;
7687 g_return_val_if_fail (qtdemux != NULL, FALSE);
7688 g_return_val_if_fail (stream != NULL, FALSE);
7689 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
7692 if (stream->protection_scheme_type != FOURCC_cenc) {
7693 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7696 if (qtdemux->protection_system_ids == NULL) {
7697 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7698 "cenc protection system information has been found");
7701 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7702 selected_system = gst_protection_select_system ((const gchar **)
7703 qtdemux->protection_system_ids->pdata);
7704 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7705 qtdemux->protection_system_ids->len - 1);
7706 if (!selected_system) {
7707 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7708 "suitable decryptor element has been found");
7712 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
7713 if (!gst_structure_has_name (s, "application/x-cenc")) {
7714 gst_structure_set (s,
7715 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7716 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7718 gst_structure_set_name (s, "application/x-cenc");
7724 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7726 if (stream->subtype == FOURCC_vide) {
7727 /* fps is calculated base on the duration of the average framerate since
7728 * qt does not have a fixed framerate. */
7729 gboolean fps_available = TRUE;
7731 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7733 CUR_STREAM (stream)->fps_n = 0;
7734 CUR_STREAM (stream)->fps_d = 1;
7736 if (stream->duration == 0 || stream->n_samples < 2) {
7737 CUR_STREAM (stream)->fps_n = stream->timescale;
7738 CUR_STREAM (stream)->fps_d = 1;
7739 fps_available = FALSE;
7741 GstClockTime avg_duration;
7745 /* duration and n_samples can be updated for fragmented format
7746 * so, framerate of fragmented format is calculated using data in a moof */
7747 if (qtdemux->fragmented && stream->n_samples_moof > 0
7748 && stream->duration_moof > 0) {
7749 n_samples = stream->n_samples_moof;
7750 duration = stream->duration_moof;
7752 n_samples = stream->n_samples;
7753 duration = stream->duration;
7756 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7757 /* stream->duration is guint64, timescale, n_samples are guint32 */
7759 gst_util_uint64_scale_round (duration -
7760 stream->first_duration, GST_SECOND,
7761 (guint64) (stream->timescale) * (n_samples - 1));
7763 GST_LOG_OBJECT (qtdemux,
7764 "Calculating avg sample duration based on stream (or moof) duration %"
7766 " minus first sample %u, leaving %d samples gives %"
7767 GST_TIME_FORMAT, duration, stream->first_duration,
7768 n_samples - 1, GST_TIME_ARGS (avg_duration));
7770 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
7771 &CUR_STREAM (stream)->fps_d);
7773 GST_DEBUG_OBJECT (qtdemux,
7774 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7775 stream->timescale, CUR_STREAM (stream)->fps_n,
7776 CUR_STREAM (stream)->fps_d);
7780 if (CUR_STREAM (stream)->caps) {
7781 CUR_STREAM (stream)->caps =
7782 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7784 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7785 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
7786 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
7788 /* set framerate if calculated framerate is reliable */
7789 if (fps_available) {
7790 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7791 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
7792 CUR_STREAM (stream)->fps_d, NULL);
7795 /* calculate pixel-aspect-ratio using display width and height */
7796 GST_DEBUG_OBJECT (qtdemux,
7797 "video size %dx%d, target display size %dx%d",
7798 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
7799 stream->display_width, stream->display_height);
7800 /* qt file might have pasp atom */
7801 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7802 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
7803 CUR_STREAM (stream)->par_h);
7804 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7805 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7806 CUR_STREAM (stream)->par_h, NULL);
7807 } else if (stream->display_width > 0 && stream->display_height > 0
7808 && CUR_STREAM (stream)->width > 0
7809 && CUR_STREAM (stream)->height > 0) {
7812 /* calculate the pixel aspect ratio using the display and pixel w/h */
7813 n = stream->display_width * CUR_STREAM (stream)->height;
7814 d = stream->display_height * CUR_STREAM (stream)->width;
7817 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7818 CUR_STREAM (stream)->par_w = n;
7819 CUR_STREAM (stream)->par_h = d;
7820 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7821 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7822 CUR_STREAM (stream)->par_h, NULL);
7825 if (CUR_STREAM (stream)->interlace_mode > 0) {
7826 if (CUR_STREAM (stream)->interlace_mode == 1) {
7827 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7828 G_TYPE_STRING, "progressive", NULL);
7829 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
7830 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7831 G_TYPE_STRING, "interleaved", NULL);
7832 if (CUR_STREAM (stream)->field_order == 9) {
7833 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7834 G_TYPE_STRING, "top-field-first", NULL);
7835 } else if (CUR_STREAM (stream)->field_order == 14) {
7836 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7837 G_TYPE_STRING, "bottom-field-first", NULL);
7842 /* Create incomplete colorimetry here if needed */
7843 if (CUR_STREAM (stream)->colorimetry.range ||
7844 CUR_STREAM (stream)->colorimetry.matrix ||
7845 CUR_STREAM (stream)->colorimetry.transfer
7846 || CUR_STREAM (stream)->colorimetry.primaries) {
7847 gchar *colorimetry =
7848 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
7849 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
7850 G_TYPE_STRING, colorimetry, NULL);
7851 g_free (colorimetry);
7854 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7855 guint par_w = 1, par_h = 1;
7857 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7858 par_w = CUR_STREAM (stream)->par_w;
7859 par_h = CUR_STREAM (stream)->par_h;
7862 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7863 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
7865 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7868 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7869 "multiview-mode", G_TYPE_STRING,
7870 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7871 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7872 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7877 else if (stream->subtype == FOURCC_soun) {
7878 if (CUR_STREAM (stream)->caps) {
7879 CUR_STREAM (stream)->caps =
7880 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7881 if (CUR_STREAM (stream)->rate > 0)
7882 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7883 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
7884 if (CUR_STREAM (stream)->n_channels > 0)
7885 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7886 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
7887 if (CUR_STREAM (stream)->n_channels > 2) {
7888 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7889 * correctly; this is just the minimum we can do - assume
7890 * we don't actually have any channel positions. */
7891 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7892 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7898 GstCaps *prev_caps = NULL;
7900 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7901 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7902 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7903 gst_pad_set_active (stream->pad, TRUE);
7905 gst_pad_use_fixed_caps (stream->pad);
7907 if (stream->protected) {
7908 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7909 GST_ERROR_OBJECT (qtdemux,
7910 "Failed to configure protected stream caps.");
7915 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7916 CUR_STREAM (stream)->caps);
7917 if (stream->new_stream) {
7920 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
7923 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7926 gst_event_parse_stream_flags (event, &stream_flags);
7927 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7928 qtdemux->have_group_id = TRUE;
7930 qtdemux->have_group_id = FALSE;
7931 gst_event_unref (event);
7932 } else if (!qtdemux->have_group_id) {
7933 qtdemux->have_group_id = TRUE;
7934 qtdemux->group_id = gst_util_group_id_next ();
7937 stream->new_stream = FALSE;
7939 gst_pad_create_stream_id_printf (stream->pad,
7940 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7941 event = gst_event_new_stream_start (stream_id);
7942 if (qtdemux->have_group_id)
7943 gst_event_set_group_id (event, qtdemux->group_id);
7944 if (stream->disabled)
7945 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7946 if (CUR_STREAM (stream)->sparse) {
7947 stream_flags |= GST_STREAM_FLAG_SPARSE;
7949 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
7951 gst_event_set_stream_flags (event, stream_flags);
7952 gst_pad_push_event (stream->pad, event);
7956 prev_caps = gst_pad_get_current_caps (stream->pad);
7958 if (CUR_STREAM (stream)->caps) {
7960 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
7961 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7962 CUR_STREAM (stream)->caps);
7963 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
7965 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7968 GST_WARNING_OBJECT (qtdemux, "stream without caps");
7972 gst_caps_unref (prev_caps);
7973 stream->new_caps = FALSE;
7979 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
7980 QtDemuxStream * stream)
7982 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
7985 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
7986 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
7987 if (G_UNLIKELY (stream->stsd_sample_description_id >=
7988 stream->stsd_entries_length)) {
7989 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7990 (_("This file is invalid and cannot be played.")),
7991 ("New sample description id is out of bounds (%d >= %d)",
7992 stream->stsd_sample_description_id, stream->stsd_entries_length));
7994 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
7995 stream->new_caps = TRUE;
8000 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8001 QtDemuxStream * stream, GstTagList * list)
8003 gboolean ret = TRUE;
8004 /* consistent default for push based mode */
8005 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8007 if (stream->subtype == FOURCC_vide) {
8008 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8011 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8014 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8015 gst_object_unref (stream->pad);
8021 qtdemux->n_video_streams++;
8022 } else if (stream->subtype == FOURCC_soun) {
8023 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8026 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8028 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8029 gst_object_unref (stream->pad);
8034 qtdemux->n_audio_streams++;
8035 } else if (stream->subtype == FOURCC_strm) {
8036 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8037 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8038 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8039 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8042 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8044 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8045 gst_object_unref (stream->pad);
8050 qtdemux->n_sub_streams++;
8051 } else if (CUR_STREAM (stream)->caps) {
8052 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8055 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8057 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8058 gst_object_unref (stream->pad);
8063 qtdemux->n_video_streams++;
8065 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8072 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8073 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8074 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8075 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8077 if (stream->stream_tags)
8078 gst_tag_list_unref (stream->stream_tags);
8079 stream->stream_tags = list;
8081 /* global tags go on each pad anyway */
8082 stream->send_global_tags = TRUE;
8083 /* send upstream GST_EVENT_PROTECTION events that were received before
8084 this source pad was created */
8085 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8086 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8090 gst_tag_list_unref (list);
8094 /* find next atom with @fourcc starting at @offset */
8095 static GstFlowReturn
8096 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8097 guint64 * length, guint32 fourcc)
8103 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8104 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8110 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8111 if (G_UNLIKELY (ret != GST_FLOW_OK))
8113 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8116 gst_buffer_unref (buf);
8119 gst_buffer_map (buf, &map, GST_MAP_READ);
8120 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8121 gst_buffer_unmap (buf, &map);
8122 gst_buffer_unref (buf);
8124 if (G_UNLIKELY (*length == 0)) {
8125 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8126 ret = GST_FLOW_ERROR;
8130 if (lfourcc == fourcc) {
8131 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8135 GST_LOG_OBJECT (qtdemux,
8136 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8137 GST_FOURCC_ARGS (fourcc), *offset);
8146 /* might simply have had last one */
8147 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8152 /* should only do something in pull mode */
8153 /* call with OBJECT lock */
8154 static GstFlowReturn
8155 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8157 guint64 length, offset;
8158 GstBuffer *buf = NULL;
8159 GstFlowReturn ret = GST_FLOW_OK;
8160 GstFlowReturn res = GST_FLOW_OK;
8163 offset = qtdemux->moof_offset;
8164 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8167 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8168 return GST_FLOW_EOS;
8171 /* best not do pull etc with lock held */
8172 GST_OBJECT_UNLOCK (qtdemux);
8174 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8175 if (ret != GST_FLOW_OK)
8178 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8179 if (G_UNLIKELY (ret != GST_FLOW_OK))
8181 gst_buffer_map (buf, &map, GST_MAP_READ);
8182 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8183 gst_buffer_unmap (buf, &map);
8184 gst_buffer_unref (buf);
8189 gst_buffer_unmap (buf, &map);
8190 gst_buffer_unref (buf);
8194 /* look for next moof */
8195 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8196 if (G_UNLIKELY (ret != GST_FLOW_OK))
8200 GST_OBJECT_LOCK (qtdemux);
8202 qtdemux->moof_offset = offset;
8208 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8210 res = GST_FLOW_ERROR;
8215 /* maybe upstream temporarily flushing */
8216 if (ret != GST_FLOW_FLUSHING) {
8217 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8220 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8221 /* resume at current position next time */
8228 /* initialise bytereaders for stbl sub-atoms */
8230 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8232 stream->stbl_index = -1; /* no samples have yet been parsed */
8233 stream->sample_index = -1;
8235 /* time-to-sample atom */
8236 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8239 /* copy atom data into a new buffer for later use */
8240 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8242 /* skip version + flags */
8243 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8244 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8246 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8248 /* make sure there's enough data */
8249 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8250 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8251 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8252 stream->n_sample_times);
8253 if (!stream->n_sample_times)
8257 /* sync sample atom */
8258 stream->stps_present = FALSE;
8259 if ((stream->stss_present =
8260 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8261 &stream->stss) ? TRUE : FALSE) == TRUE) {
8262 /* copy atom data into a new buffer for later use */
8263 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8265 /* skip version + flags */
8266 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8267 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8270 if (stream->n_sample_syncs) {
8271 /* make sure there's enough data */
8272 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8276 /* partial sync sample atom */
8277 if ((stream->stps_present =
8278 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8279 &stream->stps) ? TRUE : FALSE) == TRUE) {
8280 /* copy atom data into a new buffer for later use */
8281 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8283 /* skip version + flags */
8284 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8285 !gst_byte_reader_get_uint32_be (&stream->stps,
8286 &stream->n_sample_partial_syncs))
8289 /* if there are no entries, the stss table contains the real
8291 if (stream->n_sample_partial_syncs) {
8292 /* make sure there's enough data */
8293 if (!qt_atom_parser_has_chunks (&stream->stps,
8294 stream->n_sample_partial_syncs, 4))
8301 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8304 /* copy atom data into a new buffer for later use */
8305 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8307 /* skip version + flags */
8308 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8309 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8312 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8315 if (!stream->n_samples)
8318 /* sample-to-chunk atom */
8319 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8322 /* copy atom data into a new buffer for later use */
8323 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8325 /* skip version + flags */
8326 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8327 !gst_byte_reader_get_uint32_be (&stream->stsc,
8328 &stream->n_samples_per_chunk))
8331 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8332 stream->n_samples_per_chunk);
8334 /* make sure there's enough data */
8335 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8341 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8342 stream->co_size = sizeof (guint32);
8343 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8345 stream->co_size = sizeof (guint64);
8349 /* copy atom data into a new buffer for later use */
8350 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8352 /* skip version + flags */
8353 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8356 /* chunks_are_samples == TRUE means treat chunks as samples */
8357 stream->chunks_are_samples = stream->sample_size
8358 && !CUR_STREAM (stream)->sampled;
8359 if (stream->chunks_are_samples) {
8360 /* treat chunks as samples */
8361 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8364 /* skip number of entries */
8365 if (!gst_byte_reader_skip (&stream->stco, 4))
8368 /* make sure there are enough data in the stsz atom */
8369 if (!stream->sample_size) {
8370 /* different sizes for each sample */
8371 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8376 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8377 stream->n_samples, (guint) sizeof (QtDemuxSample),
8378 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8380 if (stream->n_samples >=
8381 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8382 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8383 "be larger than %uMB (broken file?)", stream->n_samples,
8384 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8388 g_assert (stream->samples == NULL);
8389 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8390 if (!stream->samples) {
8391 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8396 /* composition time-to-sample */
8397 if ((stream->ctts_present =
8398 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8399 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8400 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8402 /* copy atom data into a new buffer for later use */
8403 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8405 /* skip version + flags */
8406 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8407 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8408 &stream->n_composition_times))
8411 /* make sure there's enough data */
8412 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8416 /* This is optional, if missing we iterate the ctts */
8417 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8418 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8419 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8420 g_free ((gpointer) cslg.data);
8424 gint32 cslg_least = 0;
8425 guint num_entries, pos;
8428 pos = gst_byte_reader_get_pos (&stream->ctts);
8429 num_entries = stream->n_composition_times;
8431 stream->cslg_shift = 0;
8433 for (i = 0; i < num_entries; i++) {
8436 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8437 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8439 if (offset < cslg_least)
8440 cslg_least = offset;
8444 stream->cslg_shift = ABS (cslg_least);
8446 stream->cslg_shift = 0;
8448 /* reset the reader so we can generate sample table */
8449 gst_byte_reader_set_pos (&stream->ctts, pos);
8452 /* Ensure the cslg_shift value is consistent so we can use it
8453 * unconditionnally to produce TS and Segment */
8454 stream->cslg_shift = 0;
8461 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8462 (_("This file is corrupt and cannot be played.")), (NULL));
8467 gst_qtdemux_stbl_free (stream);
8468 if (!qtdemux->fragmented) {
8469 /* not quite good */
8470 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8473 /* may pick up samples elsewhere */
8479 /* collect samples from the next sample to be parsed up to sample @n for @stream
8480 * by reading the info from @stbl
8482 * This code can be executed from both the streaming thread and the seeking
8483 * thread so it takes the object lock to protect itself
8486 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8489 QtDemuxSample *samples, *first, *cur, *last;
8490 guint32 n_samples_per_chunk;
8493 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8494 GST_FOURCC_FORMAT ", pad %s",
8495 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8496 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8498 n_samples = stream->n_samples;
8501 goto out_of_samples;
8503 GST_OBJECT_LOCK (qtdemux);
8504 if (n <= stream->stbl_index)
8505 goto already_parsed;
8507 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8509 if (!stream->stsz.data) {
8510 /* so we already parsed and passed all the moov samples;
8511 * onto fragmented ones */
8512 g_assert (qtdemux->fragmented);
8516 /* pointer to the sample table */
8517 samples = stream->samples;
8519 /* starts from -1, moves to the next sample index to parse */
8520 stream->stbl_index++;
8522 /* keep track of the first and last sample to fill */
8523 first = &samples[stream->stbl_index];
8526 if (!stream->chunks_are_samples) {
8527 /* set the sample sizes */
8528 if (stream->sample_size == 0) {
8529 /* different sizes for each sample */
8530 for (cur = first; cur <= last; cur++) {
8531 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8532 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8533 (guint) (cur - samples), cur->size);
8536 /* samples have the same size */
8537 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8538 for (cur = first; cur <= last; cur++)
8539 cur->size = stream->sample_size;
8543 n_samples_per_chunk = stream->n_samples_per_chunk;
8546 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8549 if (stream->stsc_chunk_index >= stream->last_chunk
8550 || stream->stsc_chunk_index < stream->first_chunk) {
8551 stream->first_chunk =
8552 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8553 stream->samples_per_chunk =
8554 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8556 stream->stsd_sample_description_id =
8557 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
8559 /* chunk numbers are counted from 1 it seems */
8560 if (G_UNLIKELY (stream->first_chunk == 0))
8563 --stream->first_chunk;
8565 /* the last chunk of each entry is calculated by taking the first chunk
8566 * of the next entry; except if there is no next, where we fake it with
8568 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8569 stream->last_chunk = G_MAXUINT32;
8571 stream->last_chunk =
8572 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8573 if (G_UNLIKELY (stream->last_chunk == 0))
8576 --stream->last_chunk;
8579 GST_LOG_OBJECT (qtdemux,
8580 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
8581 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
8582 stream->samples_per_chunk, stream->stsd_sample_description_id);
8584 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8587 if (stream->last_chunk != G_MAXUINT32) {
8588 if (!qt_atom_parser_peek_sub (&stream->stco,
8589 stream->first_chunk * stream->co_size,
8590 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8595 stream->co_chunk = stream->stco;
8596 if (!gst_byte_reader_skip (&stream->co_chunk,
8597 stream->first_chunk * stream->co_size))
8601 stream->stsc_chunk_index = stream->first_chunk;
8604 last_chunk = stream->last_chunk;
8606 if (stream->chunks_are_samples) {
8607 cur = &samples[stream->stsc_chunk_index];
8609 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8612 stream->stsc_chunk_index = j;
8617 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8620 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8621 "%" G_GUINT64_FORMAT, j, cur->offset);
8623 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
8624 CUR_STREAM (stream)->bytes_per_frame > 0) {
8626 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
8627 CUR_STREAM (stream)->samples_per_frame *
8628 CUR_STREAM (stream)->bytes_per_frame;
8630 cur->size = stream->samples_per_chunk;
8633 GST_DEBUG_OBJECT (qtdemux,
8634 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8635 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8636 stream->stco_sample_index)), cur->size);
8638 cur->timestamp = stream->stco_sample_index;
8639 cur->duration = stream->samples_per_chunk;
8640 cur->keyframe = TRUE;
8643 stream->stco_sample_index += stream->samples_per_chunk;
8645 stream->stsc_chunk_index = j;
8647 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8648 guint32 samples_per_chunk;
8649 guint64 chunk_offset;
8651 if (!stream->stsc_sample_index
8652 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8653 &stream->chunk_offset))
8656 samples_per_chunk = stream->samples_per_chunk;
8657 chunk_offset = stream->chunk_offset;
8659 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8660 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8661 G_GUINT64_FORMAT " and size %d",
8662 (guint) (cur - samples), chunk_offset, cur->size);
8664 cur->offset = chunk_offset;
8665 chunk_offset += cur->size;
8668 if (G_UNLIKELY (cur > last)) {
8670 stream->stsc_sample_index = k + 1;
8671 stream->chunk_offset = chunk_offset;
8672 stream->stsc_chunk_index = j;
8676 stream->stsc_sample_index = 0;
8678 stream->stsc_chunk_index = j;
8680 stream->stsc_index++;
8683 if (stream->chunks_are_samples)
8687 guint32 n_sample_times;
8689 n_sample_times = stream->n_sample_times;
8692 for (i = stream->stts_index; i < n_sample_times; i++) {
8693 guint32 stts_samples;
8694 gint32 stts_duration;
8697 if (stream->stts_sample_index >= stream->stts_samples
8698 || !stream->stts_sample_index) {
8700 stream->stts_samples =
8701 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8702 stream->stts_duration =
8703 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8705 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8706 i, stream->stts_samples, stream->stts_duration);
8708 stream->stts_sample_index = 0;
8711 stts_samples = stream->stts_samples;
8712 stts_duration = stream->stts_duration;
8713 stts_time = stream->stts_time;
8715 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8716 GST_DEBUG_OBJECT (qtdemux,
8717 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8718 (guint) (cur - samples), j,
8719 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8721 cur->timestamp = stts_time;
8722 cur->duration = stts_duration;
8724 /* avoid 32-bit wrap-around,
8725 * but still mind possible 'negative' duration */
8726 stts_time += (gint64) stts_duration;
8729 if (G_UNLIKELY (cur > last)) {
8731 stream->stts_time = stts_time;
8732 stream->stts_sample_index = j + 1;
8733 if (stream->stts_sample_index >= stream->stts_samples)
8734 stream->stts_index++;
8738 stream->stts_sample_index = 0;
8739 stream->stts_time = stts_time;
8740 stream->stts_index++;
8742 /* fill up empty timestamps with the last timestamp, this can happen when
8743 * the last samples do not decode and so we don't have timestamps for them.
8744 * We however look at the last timestamp to estimate the track length so we
8745 * need something in here. */
8746 for (; cur < last; cur++) {
8747 GST_DEBUG_OBJECT (qtdemux,
8748 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8749 (guint) (cur - samples),
8750 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8751 cur->timestamp = stream->stts_time;
8757 /* sample sync, can be NULL */
8758 if (stream->stss_present == TRUE) {
8759 guint32 n_sample_syncs;
8761 n_sample_syncs = stream->n_sample_syncs;
8763 if (!n_sample_syncs) {
8764 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8765 stream->all_keyframe = TRUE;
8767 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8768 /* note that the first sample is index 1, not 0 */
8771 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8773 if (G_LIKELY (index > 0 && index <= n_samples)) {
8775 samples[index].keyframe = TRUE;
8776 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8777 /* and exit if we have enough samples */
8778 if (G_UNLIKELY (index >= n)) {
8785 stream->stss_index = i;
8788 /* stps marks partial sync frames like open GOP I-Frames */
8789 if (stream->stps_present == TRUE) {
8790 guint32 n_sample_partial_syncs;
8792 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8794 /* if there are no entries, the stss table contains the real
8796 if (n_sample_partial_syncs) {
8797 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8798 /* note that the first sample is index 1, not 0 */
8801 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8803 if (G_LIKELY (index > 0 && index <= n_samples)) {
8805 samples[index].keyframe = TRUE;
8806 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8807 /* and exit if we have enough samples */
8808 if (G_UNLIKELY (index >= n)) {
8815 stream->stps_index = i;
8819 /* no stss, all samples are keyframes */
8820 stream->all_keyframe = TRUE;
8821 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8826 /* composition time to sample */
8827 if (stream->ctts_present == TRUE) {
8828 guint32 n_composition_times;
8830 gint32 ctts_soffset;
8832 /* Fill in the pts_offsets */
8834 n_composition_times = stream->n_composition_times;
8836 for (i = stream->ctts_index; i < n_composition_times; i++) {
8837 if (stream->ctts_sample_index >= stream->ctts_count
8838 || !stream->ctts_sample_index) {
8839 stream->ctts_count =
8840 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8841 stream->ctts_soffset =
8842 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8843 stream->ctts_sample_index = 0;
8846 ctts_count = stream->ctts_count;
8847 ctts_soffset = stream->ctts_soffset;
8849 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8850 cur->pts_offset = ctts_soffset;
8853 if (G_UNLIKELY (cur > last)) {
8855 stream->ctts_sample_index = j + 1;
8859 stream->ctts_sample_index = 0;
8860 stream->ctts_index++;
8864 stream->stbl_index = n;
8865 /* if index has been completely parsed, free data that is no-longer needed */
8866 if (n + 1 == stream->n_samples) {
8867 gst_qtdemux_stbl_free (stream);
8868 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8869 if (qtdemux->pullbased) {
8870 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8871 while (n + 1 == stream->n_samples)
8872 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8876 GST_OBJECT_UNLOCK (qtdemux);
8883 GST_LOG_OBJECT (qtdemux,
8884 "Tried to parse up to sample %u but this sample has already been parsed",
8886 /* if fragmented, there may be more */
8887 if (qtdemux->fragmented && n == stream->stbl_index)
8889 GST_OBJECT_UNLOCK (qtdemux);
8895 GST_LOG_OBJECT (qtdemux,
8896 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8898 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8899 (_("This file is corrupt and cannot be played.")), (NULL));
8904 GST_OBJECT_UNLOCK (qtdemux);
8905 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8906 (_("This file is corrupt and cannot be played.")), (NULL));
8911 /* collect all segment info for @stream.
8914 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8918 /* accept edts if they contain gaps at start and there is only
8919 * one media segment */
8920 gboolean allow_pushbased_edts = TRUE;
8921 gint media_segments_count = 0;
8923 /* parse and prepare segment info from the edit list */
8924 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8925 stream->n_segments = 0;
8926 stream->segments = NULL;
8927 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8930 gint i, count, entry_size;
8933 const guint8 *buffer;
8937 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8938 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8941 buffer = elst->data;
8943 size = QT_UINT32 (buffer);
8944 /* version, flags, n_segments */
8946 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8949 version = QT_UINT8 (buffer + 8);
8950 entry_size = (version == 1) ? 20 : 12;
8952 n_segments = QT_UINT32 (buffer + 12);
8954 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
8955 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8959 /* we might allocate a bit too much, at least allocate 1 segment */
8960 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8962 /* segments always start from 0 */
8967 for (i = 0; i < n_segments; i++) {
8970 gboolean time_valid = TRUE;
8971 QtDemuxSegment *segment;
8973 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8976 media_time = QT_UINT64 (buffer + 8);
8977 duration = QT_UINT64 (buffer);
8978 if (media_time == G_MAXUINT64)
8981 media_time = QT_UINT32 (buffer + 4);
8982 duration = QT_UINT32 (buffer);
8983 if (media_time == G_MAXUINT32)
8988 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8990 segment = &stream->segments[count++];
8992 /* time and duration expressed in global timescale */
8993 segment->time = stime;
8994 /* add non scaled values so we don't cause roundoff errors */
8995 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8997 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8998 segment->duration = stime - segment->time;
9000 /* zero duration does not imply media_start == media_stop
9001 * but, only specify media_start.*/
9002 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
9003 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
9004 && stime >= media_start) {
9005 segment->duration = stime - media_start;
9007 segment->duration = GST_CLOCK_TIME_NONE;
9010 segment->stop_time = stime;
9012 segment->trak_media_start = media_time;
9013 /* media_time expressed in stream timescale */
9015 segment->media_start = media_start;
9016 segment->media_stop = segment->media_start + segment->duration;
9017 media_segments_count++;
9019 segment->media_start = GST_CLOCK_TIME_NONE;
9020 segment->media_stop = GST_CLOCK_TIME_NONE;
9022 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9024 if (rate_int <= 1) {
9025 /* 0 is not allowed, some programs write 1 instead of the floating point
9027 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9031 segment->rate = rate_int / 65536.0;
9034 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9035 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9036 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9037 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9038 i, GST_TIME_ARGS (segment->time),
9039 GST_TIME_ARGS (segment->duration),
9040 GST_TIME_ARGS (segment->media_start), media_time,
9041 GST_TIME_ARGS (segment->media_stop),
9042 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9044 if (segment->stop_time > qtdemux->segment.stop) {
9045 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9046 " extends to %" GST_TIME_FORMAT
9047 " past the end of the file duration %" GST_TIME_FORMAT
9048 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9049 GST_TIME_ARGS (qtdemux->segment.stop));
9050 qtdemux->segment.stop = segment->stop_time;
9053 buffer += entry_size;
9055 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9056 stream->n_segments = count;
9057 if (media_segments_count != 1)
9058 allow_pushbased_edts = FALSE;
9062 /* push based does not handle segments, so act accordingly here,
9063 * and warn if applicable */
9064 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9065 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9066 /* remove and use default one below, we stream like it anyway */
9067 g_free (stream->segments);
9068 stream->segments = NULL;
9069 stream->n_segments = 0;
9072 /* no segments, create one to play the complete trak */
9073 if (stream->n_segments == 0) {
9074 GstClockTime stream_duration =
9075 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9077 if (stream->segments == NULL)
9078 stream->segments = g_new (QtDemuxSegment, 1);
9080 /* represent unknown our way */
9081 if (stream_duration == 0)
9082 stream_duration = GST_CLOCK_TIME_NONE;
9084 stream->segments[0].time = 0;
9085 stream->segments[0].stop_time = stream_duration;
9086 stream->segments[0].duration = stream_duration;
9087 stream->segments[0].media_start = 0;
9088 stream->segments[0].media_stop = stream_duration;
9089 stream->segments[0].rate = 1.0;
9090 stream->segments[0].trak_media_start = 0;
9092 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9093 GST_TIME_ARGS (stream_duration));
9094 stream->n_segments = 1;
9095 stream->dummy_segment = TRUE;
9097 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9103 * Parses the stsd atom of a svq3 trak looking for
9104 * the SMI and gama atoms.
9107 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9108 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9110 const guint8 *_gamma = NULL;
9111 GstBuffer *_seqh = NULL;
9112 const guint8 *stsd_data = stsd_entry_data;
9113 guint32 length = QT_UINT32 (stsd_data);
9117 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9123 version = QT_UINT16 (stsd_data);
9128 while (length > 8) {
9129 guint32 fourcc, size;
9131 size = QT_UINT32 (stsd_data);
9132 fourcc = QT_FOURCC (stsd_data + 4);
9133 data = stsd_data + 8;
9136 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9137 "svq3 atom parsing");
9146 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9147 " for gama atom, expected 12", size);
9152 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9154 if (_seqh != NULL) {
9155 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9156 " found, ignoring");
9158 seqh_size = QT_UINT32 (data + 4);
9159 if (seqh_size > 0) {
9160 _seqh = gst_buffer_new_and_alloc (seqh_size);
9161 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9168 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9169 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9173 if (size <= length) {
9179 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9182 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9183 G_GUINT16_FORMAT, version);
9194 gst_buffer_unref (_seqh);
9199 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9206 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9207 * atom that might contain a 'data' atom with the rtsp uri.
9208 * This case was reported in bug #597497, some info about
9209 * the hndl atom can be found in TN1195
9211 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9212 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9215 guint32 dref_num_entries = 0;
9216 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9217 gst_byte_reader_skip (&dref, 4) &&
9218 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9221 /* search dref entries for hndl atom */
9222 for (i = 0; i < dref_num_entries; i++) {
9223 guint32 size = 0, type;
9224 guint8 string_len = 0;
9225 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9226 qt_atom_parser_get_fourcc (&dref, &type)) {
9227 if (type == FOURCC_hndl) {
9228 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9230 /* skip data reference handle bytes and the
9231 * following pascal string and some extra 4
9232 * bytes I have no idea what are */
9233 if (!gst_byte_reader_skip (&dref, 4) ||
9234 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9235 !gst_byte_reader_skip (&dref, string_len + 4)) {
9236 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9240 /* iterate over the atoms to find the data atom */
9241 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9245 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9246 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9247 if (atom_type == FOURCC_data) {
9248 const guint8 *uri_aux = NULL;
9250 /* found the data atom that might contain the rtsp uri */
9251 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9252 "hndl atom, interpreting it as an URI");
9253 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9255 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9256 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9258 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9259 "didn't contain a rtsp address");
9261 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9266 /* skipping to the next entry */
9267 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9270 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9277 /* skip to the next entry */
9278 if (!gst_byte_reader_skip (&dref, size - 8))
9281 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9284 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9290 #define AMR_NB_ALL_MODES 0x81ff
9291 #define AMR_WB_ALL_MODES 0x83ff
9293 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9295 /* The 'damr' atom is of the form:
9297 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9298 * 32 b 8 b 16 b 8 b 8 b
9300 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9301 * represents the highest mode used in the stream (and thus the maximum
9302 * bitrate), with a couple of special cases as seen below.
9305 /* Map of frame type ID -> bitrate */
9306 static const guint nb_bitrates[] = {
9307 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9309 static const guint wb_bitrates[] = {
9310 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9316 gst_buffer_map (buf, &map, GST_MAP_READ);
9318 if (map.size != 0x11) {
9319 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9323 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9324 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9325 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9329 mode_set = QT_UINT16 (map.data + 13);
9331 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9332 max_mode = 7 + (wb ? 1 : 0);
9334 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9335 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9337 if (max_mode == -1) {
9338 GST_DEBUG ("No mode indication was found (mode set) = %x",
9343 gst_buffer_unmap (buf, &map);
9344 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9347 gst_buffer_unmap (buf, &map);
9352 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9353 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9356 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9362 if (gst_byte_reader_get_remaining (reader) < 36)
9365 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9366 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9367 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9368 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9369 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9370 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9371 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9372 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9373 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9375 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9376 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9377 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9379 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9380 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9382 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9383 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9390 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9391 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9398 * This macro will only compare value abdegh, it expects cfi to have already
9401 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9402 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9404 /* only handle the cases where the last column has standard values */
9405 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9406 const gchar *rotation_tag = NULL;
9408 /* no rotation needed */
9409 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9411 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9412 rotation_tag = "rotate-90";
9413 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9414 rotation_tag = "rotate-180";
9415 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9416 rotation_tag = "rotate-270";
9418 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9421 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9423 if (rotation_tag != NULL) {
9424 if (*taglist == NULL)
9425 *taglist = gst_tag_list_new_empty ();
9426 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9427 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9430 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9434 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9435 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9436 * Common Encryption (cenc), the function will also parse the tenc box (defined
9437 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9438 * (typically an enc[v|a|t|s] sample entry); the function will set
9439 * @original_fmt to the fourcc of the original unencrypted stream format.
9440 * Returns TRUE if successful; FALSE otherwise. */
9442 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9443 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9450 g_return_val_if_fail (qtdemux != NULL, FALSE);
9451 g_return_val_if_fail (stream != NULL, FALSE);
9452 g_return_val_if_fail (container != NULL, FALSE);
9453 g_return_val_if_fail (original_fmt != NULL, FALSE);
9455 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9456 if (G_UNLIKELY (!sinf)) {
9457 if (stream->protection_scheme_type == FOURCC_cenc) {
9458 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9459 "mandatory for Common Encryption");
9465 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9466 if (G_UNLIKELY (!frma)) {
9467 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9471 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9472 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9473 GST_FOURCC_ARGS (*original_fmt));
9475 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9477 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9480 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9481 stream->protection_scheme_version =
9482 QT_UINT32 ((const guint8 *) schm->data + 16);
9484 GST_DEBUG_OBJECT (qtdemux,
9485 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9486 "protection_scheme_version: %#010x",
9487 GST_FOURCC_ARGS (stream->protection_scheme_type),
9488 stream->protection_scheme_version);
9490 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9492 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9495 if (stream->protection_scheme_type == FOURCC_cenc) {
9496 QtDemuxCencSampleSetInfo *info;
9498 const guint8 *tenc_data;
9499 guint32 isEncrypted;
9501 const guint8 *default_kid;
9504 if (G_UNLIKELY (!stream->protection_scheme_info))
9505 stream->protection_scheme_info =
9506 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9508 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9510 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9512 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9513 "which is mandatory for Common Encryption");
9516 tenc_data = (const guint8 *) tenc->data + 12;
9517 isEncrypted = QT_UINT24 (tenc_data);
9518 iv_size = QT_UINT8 (tenc_data + 3);
9519 default_kid = (tenc_data + 4);
9520 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9521 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9522 if (info->default_properties)
9523 gst_structure_free (info->default_properties);
9524 info->default_properties =
9525 gst_structure_new ("application/x-cenc",
9526 "iv_size", G_TYPE_UINT, iv_size,
9527 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9528 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9529 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9530 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9531 gst_buffer_unref (kid_buf);
9537 * With each track we associate a new QtDemuxStream that contains all the info
9539 * traks that do not decode to something (like strm traks) will not have a pad.
9542 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9563 QtDemuxStream *stream = NULL;
9564 gboolean new_stream = FALSE;
9565 gchar *codec = NULL;
9566 const guint8 *stsd_data;
9567 const guint8 *stsd_entry_data;
9568 guint remaining_stsd_len;
9569 guint stsd_entry_count;
9571 guint16 lang_code; /* quicktime lang code or packed iso code */
9573 guint32 tkhd_flags = 0;
9574 guint8 tkhd_version = 0;
9575 guint32 w = 0, h = 0;
9577 guint value_size, stsd_len, len;
9581 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9583 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9584 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9585 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9588 /* pick between 64 or 32 bits */
9589 value_size = tkhd_version == 1 ? 8 : 4;
9590 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9591 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9594 if (!qtdemux->got_moov) {
9595 if (qtdemux_find_stream (qtdemux, track_id))
9596 goto existing_stream;
9597 stream = _create_stream ();
9598 stream->track_id = track_id;
9601 stream = qtdemux_find_stream (qtdemux, track_id);
9603 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9607 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
9609 /* flush samples data from this track from previous moov */
9610 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9611 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9613 /* need defaults for fragments */
9614 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9616 if ((tkhd_flags & 1) == 0)
9617 stream->disabled = TRUE;
9619 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9620 tkhd_version, tkhd_flags, stream->track_id);
9622 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9625 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9626 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9627 if (qtdemux->major_brand != FOURCC_mjp2 ||
9628 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9632 len = QT_UINT32 ((guint8 *) mdhd->data);
9633 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9634 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9635 if (version == 0x01000000) {
9638 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9639 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9640 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9644 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9645 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9646 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9649 if (lang_code < 0x400) {
9650 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9651 } else if (lang_code == 0x7fff) {
9652 stream->lang_id[0] = 0; /* unspecified */
9654 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9655 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9656 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9657 stream->lang_id[3] = 0;
9660 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9662 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9664 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9665 lang_code, stream->lang_id);
9667 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9670 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9671 /* chapters track reference */
9672 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9674 gsize length = GST_READ_UINT32_BE (chap->data);
9675 if (qtdemux->chapters_track_id)
9676 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9679 qtdemux->chapters_track_id =
9680 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9685 /* fragmented files may have bogus duration in moov */
9686 if (!qtdemux->fragmented &&
9687 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9688 guint64 tdur1, tdur2;
9690 /* don't overflow */
9691 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9692 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9695 * some of those trailers, nowadays, have prologue images that are
9696 * themselves video tracks as well. I haven't really found a way to
9697 * identify those yet, except for just looking at their duration. */
9698 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9699 GST_WARNING_OBJECT (qtdemux,
9700 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9701 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9702 "found, assuming preview image or something; skipping track",
9703 stream->duration, stream->timescale, qtdemux->duration,
9704 qtdemux->timescale);
9706 gst_qtdemux_stream_free (qtdemux, stream);
9711 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9714 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9715 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9717 len = QT_UINT32 ((guint8 *) hdlr->data);
9719 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9720 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9721 GST_FOURCC_ARGS (stream->subtype));
9723 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9726 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9729 /*parse svmi header if existing */
9730 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9732 len = QT_UINT32 ((guint8 *) svmi->data);
9733 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9735 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9736 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9737 guint8 frame_type, frame_layout;
9739 /* MPEG-A stereo video */
9740 if (qtdemux->major_brand == FOURCC_ss02)
9741 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9743 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9744 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9745 switch (frame_type) {
9747 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9750 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9753 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9756 /* mode 3 is primary/secondary view sequence, ie
9757 * left/right views in separate tracks. See section 7.2
9758 * of ISO/IEC 23000-11:2009 */
9759 GST_FIXME_OBJECT (qtdemux,
9760 "Implement stereo video in separate streams");
9763 if ((frame_layout & 0x1) == 0)
9764 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9766 GST_LOG_OBJECT (qtdemux,
9767 "StereoVideo: composition type: %u, is_left_first: %u",
9768 frame_type, frame_layout);
9769 stream->multiview_mode = mode;
9770 stream->multiview_flags = flags;
9774 /* parse rest of tkhd */
9775 if (stream->subtype == FOURCC_vide) {
9778 /* version 1 uses some 64-bit ints */
9779 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9782 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9785 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9786 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9789 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9790 &stream->stream_tags);
9794 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9796 stsd_data = (const guint8 *) stsd->data;
9798 /* stsd should at least have one entry */
9799 stsd_len = QT_UINT32 (stsd_data);
9800 if (stsd_len < 24) {
9801 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9802 if (stream->subtype == FOURCC_vivo) {
9804 gst_qtdemux_stream_free (qtdemux, stream);
9811 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
9812 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
9813 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9814 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
9816 stsd_entry_data = stsd_data + 16;
9817 remaining_stsd_len = stsd_len - 16;
9818 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
9819 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
9821 /* and that entry should fit within stsd */
9822 len = QT_UINT32 (stsd_entry_data);
9823 if (len > remaining_stsd_len)
9826 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
9827 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9828 GST_FOURCC_ARGS (entry->fourcc));
9829 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9831 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9832 goto error_encrypted;
9834 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9835 /* FIXME this looks wrong, there might be multiple children
9836 * with the same type */
9837 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9838 stream->protected = TRUE;
9839 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9840 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9843 if (stream->subtype == FOURCC_vide) {
9845 gint depth, palette_size, palette_count;
9846 guint32 *palette_data = NULL;
9848 entry->sampled = TRUE;
9850 stream->display_width = w >> 16;
9851 stream->display_height = h >> 16;
9854 if (len < 86) /* TODO verify */
9857 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
9858 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
9859 entry->fps_n = 0; /* this is filled in later */
9860 entry->fps_d = 0; /* this is filled in later */
9861 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
9862 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
9864 /* if color_table_id is 0, ctab atom must follow; however some files
9865 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9866 * if color table is not present we'll correct the value */
9867 if (entry->color_table_id == 0 &&
9869 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
9870 entry->color_table_id = -1;
9873 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9874 entry->width, entry->height, entry->bits_per_sample,
9875 entry->color_table_id);
9877 depth = entry->bits_per_sample;
9879 /* more than 32 bits means grayscale */
9880 gray = (depth > 32);
9881 /* low 32 bits specify the depth */
9884 /* different number of palette entries is determined by depth. */
9886 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9887 palette_count = (1 << depth);
9888 palette_size = palette_count * 4;
9890 if (entry->color_table_id) {
9891 switch (palette_count) {
9895 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9898 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9903 g_memdup (ff_qt_grayscale_palette_16, palette_size);
9905 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9910 g_memdup (ff_qt_grayscale_palette_256, palette_size);
9912 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9915 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9916 (_("The video in this file might not play correctly.")),
9917 ("unsupported palette depth %d", depth));
9921 gint i, j, start, end;
9927 start = QT_UINT32 (stsd_entry_data + offset + 70);
9928 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
9929 end = QT_UINT16 (stsd_entry_data + offset + 76);
9931 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9932 start, end, palette_count);
9939 if (len < 94 + (end - start) * 8)
9942 /* palette is always the same size */
9943 palette_data = g_malloc0 (256 * 4);
9944 palette_size = 256 * 4;
9946 for (j = 0, i = start; i <= end; j++, i++) {
9949 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
9950 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
9951 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
9952 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
9954 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9955 (g & 0xff00) | (b >> 8);
9960 gst_caps_unref (entry->caps);
9963 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
9965 if (G_UNLIKELY (!entry->caps)) {
9966 g_free (palette_data);
9967 goto unknown_stream;
9971 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
9972 GST_TAG_VIDEO_CODEC, codec, NULL);
9980 if (entry->rgb8_palette)
9981 gst_memory_unref (entry->rgb8_palette);
9982 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9983 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9985 s = gst_caps_get_structure (entry->caps, 0);
9987 /* non-raw video has a palette_data property. raw video has the palette as
9988 * an extra plane that we append to the output buffers before we push
9990 if (!gst_structure_has_name (s, "video/x-raw")) {
9993 palette = gst_buffer_new ();
9994 gst_buffer_append_memory (palette, entry->rgb8_palette);
9995 entry->rgb8_palette = NULL;
9997 gst_caps_set_simple (entry->caps, "palette_data",
9998 GST_TYPE_BUFFER, palette, NULL);
9999 gst_buffer_unref (palette);
10001 } else if (palette_count != 0) {
10002 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10003 (NULL), ("Unsupported palette depth %d", depth));
10006 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10007 QT_UINT16 (stsd_entry_data + offset + 32));
10013 /* pick 'the' stsd child */
10014 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10015 if (!stream->protected) {
10016 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10020 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10026 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10027 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10028 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10029 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10033 const guint8 *pasp_data = (const guint8 *) pasp->data;
10034 gint len = QT_UINT32 (pasp_data);
10037 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10038 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10040 CUR_STREAM (stream)->par_w = 0;
10041 CUR_STREAM (stream)->par_h = 0;
10044 CUR_STREAM (stream)->par_w = 0;
10045 CUR_STREAM (stream)->par_h = 0;
10049 const guint8 *fiel_data = (const guint8 *) fiel->data;
10050 gint len = QT_UINT32 (fiel_data);
10053 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10054 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10059 const guint8 *colr_data = (const guint8 *) colr->data;
10060 gint len = QT_UINT32 (colr_data);
10062 if (len == 19 || len == 18) {
10063 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10065 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10066 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10067 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10068 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10069 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10071 switch (primaries) {
10073 CUR_STREAM (stream)->colorimetry.primaries =
10074 GST_VIDEO_COLOR_PRIMARIES_BT709;
10077 CUR_STREAM (stream)->colorimetry.primaries =
10078 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10081 CUR_STREAM (stream)->colorimetry.primaries =
10082 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10085 CUR_STREAM (stream)->colorimetry.primaries =
10086 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10092 switch (transfer_function) {
10094 CUR_STREAM (stream)->colorimetry.transfer =
10095 GST_VIDEO_TRANSFER_BT709;
10098 CUR_STREAM (stream)->colorimetry.transfer =
10099 GST_VIDEO_TRANSFER_SMPTE240M;
10107 CUR_STREAM (stream)->colorimetry.matrix =
10108 GST_VIDEO_COLOR_MATRIX_BT709;
10111 CUR_STREAM (stream)->colorimetry.matrix =
10112 GST_VIDEO_COLOR_MATRIX_BT601;
10115 CUR_STREAM (stream)->colorimetry.matrix =
10116 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10119 CUR_STREAM (stream)->colorimetry.matrix =
10120 GST_VIDEO_COLOR_MATRIX_BT2020;
10126 CUR_STREAM (stream)->colorimetry.range =
10127 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10128 GST_VIDEO_COLOR_RANGE_16_235;
10130 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10133 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10138 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10139 stream->stream_tags);
10146 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10147 const guint8 *avc_data = stsd_entry_data + 0x56;
10150 while (len >= 0x8) {
10153 if (QT_UINT32 (avc_data) <= len)
10154 size = QT_UINT32 (avc_data) - 0x8;
10159 /* No real data, so break out */
10162 switch (QT_FOURCC (avc_data + 0x4)) {
10165 /* parse, if found */
10168 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10170 /* First 4 bytes are the length of the atom, the next 4 bytes
10171 * are the fourcc, the next 1 byte is the version, and the
10172 * subsequent bytes are profile_tier_level structure like data. */
10173 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10174 avc_data + 8 + 1, size - 1);
10175 buf = gst_buffer_new_and_alloc (size);
10176 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10177 gst_caps_set_simple (entry->caps,
10178 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10179 gst_buffer_unref (buf);
10187 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10189 /* First 4 bytes are the length of the atom, the next 4 bytes
10190 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10191 * next 1 byte is the version, and the
10192 * subsequent bytes are sequence parameter set like data. */
10194 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10196 gst_codec_utils_h264_caps_set_level_and_profile
10197 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10199 buf = gst_buffer_new_and_alloc (size);
10200 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10201 gst_caps_set_simple (entry->caps,
10202 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10203 gst_buffer_unref (buf);
10209 guint avg_bitrate, max_bitrate;
10211 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10215 max_bitrate = QT_UINT32 (avc_data + 0xc);
10216 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10218 if (!max_bitrate && !avg_bitrate)
10221 /* Some muxers seem to swap the average and maximum bitrates
10222 * (I'm looking at you, YouTube), so we swap for sanity. */
10223 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10224 guint temp = avg_bitrate;
10226 avg_bitrate = max_bitrate;
10227 max_bitrate = temp;
10230 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10231 gst_tag_list_add (stream->stream_tags,
10232 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10233 max_bitrate, NULL);
10235 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10236 gst_tag_list_add (stream->stream_tags,
10237 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10249 avc_data += size + 8;
10258 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10259 const guint8 *hevc_data = stsd_entry_data + 0x56;
10262 while (len >= 0x8) {
10265 if (QT_UINT32 (hevc_data) <= len)
10266 size = QT_UINT32 (hevc_data) - 0x8;
10271 /* No real data, so break out */
10274 switch (QT_FOURCC (hevc_data + 0x4)) {
10277 /* parse, if found */
10280 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10282 /* First 4 bytes are the length of the atom, the next 4 bytes
10283 * are the fourcc, the next 1 byte is the version, and the
10284 * subsequent bytes are sequence parameter set like data. */
10285 gst_codec_utils_h265_caps_set_level_tier_and_profile
10286 (entry->caps, hevc_data + 8 + 1, size - 1);
10288 buf = gst_buffer_new_and_alloc (size);
10289 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10290 gst_caps_set_simple (entry->caps,
10291 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10292 gst_buffer_unref (buf);
10299 hevc_data += size + 8;
10312 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10313 GST_FOURCC_ARGS (fourcc));
10315 /* codec data might be in glbl extension atom */
10317 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10323 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10325 len = QT_UINT32 (data);
10328 buf = gst_buffer_new_and_alloc (len);
10329 gst_buffer_fill (buf, 0, data + 8, len);
10330 gst_caps_set_simple (entry->caps,
10331 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10332 gst_buffer_unref (buf);
10339 /* see annex I of the jpeg2000 spec */
10340 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10341 const guint8 *data;
10342 const gchar *colorspace = NULL;
10344 guint32 ncomp_map = 0;
10345 gint32 *comp_map = NULL;
10346 guint32 nchan_def = 0;
10347 gint32 *chan_def = NULL;
10349 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10350 /* some required atoms */
10351 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10354 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10358 /* number of components; redundant with info in codestream, but useful
10360 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10361 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10363 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10365 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10368 GST_DEBUG_OBJECT (qtdemux, "found colr");
10369 /* extract colour space info */
10370 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10371 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10373 colorspace = "sRGB";
10376 colorspace = "GRAY";
10379 colorspace = "sYUV";
10387 /* colr is required, and only values 16, 17, and 18 are specified,
10388 so error if we have no colorspace */
10391 /* extract component mapping */
10392 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10394 guint32 cmap_len = 0;
10396 cmap_len = QT_UINT32 (cmap->data);
10397 if (cmap_len >= 8) {
10398 /* normal box, subtract off header */
10400 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10401 if (cmap_len % 4 == 0) {
10402 ncomp_map = (cmap_len / 4);
10403 comp_map = g_new0 (gint32, ncomp_map);
10404 for (i = 0; i < ncomp_map; i++) {
10407 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10408 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10409 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10410 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10415 /* extract channel definitions */
10416 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10418 guint32 cdef_len = 0;
10420 cdef_len = QT_UINT32 (cdef->data);
10421 if (cdef_len >= 10) {
10422 /* normal box, subtract off header and len */
10424 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10425 if (cdef_len % 6 == 0) {
10426 nchan_def = (cdef_len / 6);
10427 chan_def = g_new0 (gint32, nchan_def);
10428 for (i = 0; i < nchan_def; i++)
10430 for (i = 0; i < nchan_def; i++) {
10431 guint16 cn, typ, asoc;
10432 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10433 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10434 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10435 if (cn < nchan_def) {
10438 chan_def[cn] = asoc;
10441 chan_def[cn] = 0; /* alpha */
10444 chan_def[cn] = -typ;
10452 gst_caps_set_simple (entry->caps,
10453 "num-components", G_TYPE_INT, ncomp, NULL);
10454 gst_caps_set_simple (entry->caps,
10455 "colorspace", G_TYPE_STRING, colorspace, NULL);
10458 GValue arr = { 0, };
10459 GValue elt = { 0, };
10461 g_value_init (&arr, GST_TYPE_ARRAY);
10462 g_value_init (&elt, G_TYPE_INT);
10463 for (i = 0; i < ncomp_map; i++) {
10464 g_value_set_int (&elt, comp_map[i]);
10465 gst_value_array_append_value (&arr, &elt);
10467 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10468 "component-map", &arr);
10469 g_value_unset (&elt);
10470 g_value_unset (&arr);
10475 GValue arr = { 0, };
10476 GValue elt = { 0, };
10478 g_value_init (&arr, GST_TYPE_ARRAY);
10479 g_value_init (&elt, G_TYPE_INT);
10480 for (i = 0; i < nchan_def; i++) {
10481 g_value_set_int (&elt, chan_def[i]);
10482 gst_value_array_append_value (&arr, &elt);
10484 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10485 "channel-definitions", &arr);
10486 g_value_unset (&elt);
10487 g_value_unset (&arr);
10491 /* some optional atoms */
10492 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10493 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10495 /* indicate possible fields in caps */
10497 data = (guint8 *) field->data + 8;
10499 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10500 (gint) * data, NULL);
10502 /* add codec_data if provided */
10507 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10508 data = prefix->data;
10509 len = QT_UINT32 (data);
10512 buf = gst_buffer_new_and_alloc (len);
10513 gst_buffer_fill (buf, 0, data + 8, len);
10514 gst_caps_set_simple (entry->caps,
10515 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10516 gst_buffer_unref (buf);
10525 GstBuffer *seqh = NULL;
10526 const guint8 *gamma_data = NULL;
10527 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
10529 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
10532 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
10533 QT_FP32 (gamma_data), NULL);
10536 /* sorry for the bad name, but we don't know what this is, other
10537 * than its own fourcc */
10538 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
10540 gst_buffer_unref (seqh);
10543 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10544 buf = gst_buffer_new_and_alloc (len);
10545 gst_buffer_fill (buf, 0, stsd_data, len);
10546 gst_caps_set_simple (entry->caps,
10547 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10548 gst_buffer_unref (buf);
10553 /* https://developer.apple.com/standards/qtff-2001.pdf,
10554 * page 92, "Video Sample Description", under table 3.1 */
10557 const gint compressor_offset =
10558 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10559 const gint min_size = compressor_offset + 32 + 2 + 2;
10562 guint16 color_table_id = 0;
10565 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10567 /* recover information on interlaced/progressive */
10568 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10572 len = QT_UINT32 (jpeg->data);
10573 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10575 if (len >= min_size) {
10576 gst_byte_reader_init (&br, jpeg->data, len);
10578 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10579 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10580 if (color_table_id != 0) {
10581 /* the spec says there can be concatenated chunks in the data, and we want
10582 * to find one called field. Walk through them. */
10583 gint offset = min_size;
10584 while (offset + 8 < len) {
10585 guint32 size = 0, tag;
10586 ok = gst_byte_reader_get_uint32_le (&br, &size);
10587 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10588 if (!ok || size < 8) {
10589 GST_WARNING_OBJECT (qtdemux,
10590 "Failed to walk optional chunk list");
10593 GST_DEBUG_OBJECT (qtdemux,
10594 "Found optional %4.4s chunk, size %u",
10595 (const char *) &tag, size);
10596 if (tag == FOURCC_fiel) {
10597 guint8 n_fields = 0, ordering = 0;
10598 gst_byte_reader_get_uint8 (&br, &n_fields);
10599 gst_byte_reader_get_uint8 (&br, &ordering);
10600 if (n_fields == 1 || n_fields == 2) {
10601 GST_DEBUG_OBJECT (qtdemux,
10602 "Found fiel tag with %u fields, ordering %u",
10603 n_fields, ordering);
10605 gst_caps_set_simple (CUR_STREAM (stream)->caps,
10606 "interlace-mode", G_TYPE_STRING, "interleaved",
10609 GST_WARNING_OBJECT (qtdemux,
10610 "Found fiel tag with invalid fields (%u)", n_fields);
10616 GST_DEBUG_OBJECT (qtdemux,
10617 "Color table ID is 0, not trying to get interlacedness");
10620 GST_WARNING_OBJECT (qtdemux,
10621 "Length of jpeg chunk is too small, not trying to get interlacedness");
10629 gst_caps_set_simple (entry->caps,
10630 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 82),
10636 GNode *xith, *xdxt;
10638 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10639 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10643 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10647 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10648 /* collect the headers and store them in a stream list so that we can
10649 * send them out first */
10650 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10660 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10661 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10664 ovc1_data = ovc1->data;
10665 ovc1_len = QT_UINT32 (ovc1_data);
10666 if (ovc1_len <= 198) {
10667 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10670 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10671 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10672 gst_caps_set_simple (entry->caps,
10673 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10674 gst_buffer_unref (buf);
10679 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10680 const guint8 *vc1_data = stsd_entry_data + 0x56;
10686 if (QT_UINT32 (vc1_data) <= len)
10687 size = QT_UINT32 (vc1_data) - 8;
10692 /* No real data, so break out */
10695 switch (QT_FOURCC (vc1_data + 0x4)) {
10696 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10700 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10701 buf = gst_buffer_new_and_alloc (size);
10702 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10703 gst_caps_set_simple (entry->caps,
10704 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10705 gst_buffer_unref (buf);
10712 vc1_data += size + 8;
10721 GST_INFO_OBJECT (qtdemux,
10722 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10723 GST_FOURCC_ARGS (fourcc), entry->caps);
10725 } else if (stream->subtype == FOURCC_soun) {
10726 int version, samplesize;
10727 guint16 compression_id;
10728 gboolean amrwb = FALSE;
10731 /* sample description entry (16) + sound sample description v0 (20) */
10735 version = QT_UINT32 (stsd_entry_data + offset);
10736 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
10737 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
10738 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
10739 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
10741 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10742 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10743 QT_UINT32 (stsd_entry_data + offset + 4));
10744 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10745 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10746 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10747 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10748 QT_UINT16 (stsd_entry_data + offset + 14));
10749 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10751 if (compression_id == 0xfffe)
10752 entry->sampled = TRUE;
10754 /* first assume uncompressed audio */
10755 entry->bytes_per_sample = samplesize / 8;
10756 entry->samples_per_frame = entry->n_channels;
10757 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
10758 entry->samples_per_packet = entry->samples_per_frame;
10759 entry->bytes_per_packet = entry->bytes_per_sample;
10763 /* Yes, these have to be hard-coded */
10766 entry->samples_per_packet = 6;
10767 entry->bytes_per_packet = 1;
10768 entry->bytes_per_frame = 1 * entry->n_channels;
10769 entry->bytes_per_sample = 1;
10770 entry->samples_per_frame = 6 * entry->n_channels;
10775 entry->samples_per_packet = 3;
10776 entry->bytes_per_packet = 1;
10777 entry->bytes_per_frame = 1 * entry->n_channels;
10778 entry->bytes_per_sample = 1;
10779 entry->samples_per_frame = 3 * entry->n_channels;
10784 entry->samples_per_packet = 64;
10785 entry->bytes_per_packet = 34;
10786 entry->bytes_per_frame = 34 * entry->n_channels;
10787 entry->bytes_per_sample = 2;
10788 entry->samples_per_frame = 64 * entry->n_channels;
10794 entry->samples_per_packet = 1;
10795 entry->bytes_per_packet = 1;
10796 entry->bytes_per_frame = 1 * entry->n_channels;
10797 entry->bytes_per_sample = 1;
10798 entry->samples_per_frame = 1 * entry->n_channels;
10803 entry->samples_per_packet = 160;
10804 entry->bytes_per_packet = 33;
10805 entry->bytes_per_frame = 33 * entry->n_channels;
10806 entry->bytes_per_sample = 2;
10807 entry->samples_per_frame = 160 * entry->n_channels;
10814 if (version == 0x00010000) {
10815 /* sample description entry (16) + sound sample description v1 (20+16) */
10826 /* only parse extra decoding config for non-pcm audio */
10827 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
10828 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
10829 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
10830 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
10832 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10833 entry->samples_per_packet);
10834 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10835 entry->bytes_per_packet);
10836 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10837 entry->bytes_per_frame);
10838 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10839 entry->bytes_per_sample);
10841 if (!entry->sampled && entry->bytes_per_packet) {
10842 entry->samples_per_frame = (entry->bytes_per_frame /
10843 entry->bytes_per_packet) * entry->samples_per_packet;
10844 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10845 entry->samples_per_frame);
10850 } else if (version == 0x00020000) {
10857 /* sample description entry (16) + sound sample description v2 (56) */
10861 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
10862 entry->rate = qtfp.fp;
10863 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
10865 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10866 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10867 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10868 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10869 QT_UINT32 (stsd_entry_data + offset + 20));
10870 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10871 QT_UINT32 (stsd_entry_data + offset + 24));
10872 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10873 QT_UINT32 (stsd_entry_data + offset + 28));
10874 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10875 QT_UINT32 (stsd_entry_data + offset + 32));
10876 } else if (version != 0x00000) {
10877 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
10882 gst_caps_unref (entry->caps);
10884 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
10885 stsd_entry_data + 32, len - 16, &codec);
10893 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10895 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10897 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10899 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10902 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10903 gst_caps_set_simple (entry->caps,
10904 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
10911 const guint8 *owma_data;
10912 const gchar *codec_name = NULL;
10916 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10917 /* FIXME this should also be gst_riff_strf_auds,
10918 * but the latter one is actually missing bits-per-sample :( */
10923 gint32 nSamplesPerSec;
10924 gint32 nAvgBytesPerSec;
10925 gint16 nBlockAlign;
10926 gint16 wBitsPerSample;
10929 WAVEFORMATEX *wfex;
10931 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10932 owma_data = stsd_entry_data;
10933 owma_len = QT_UINT32 (owma_data);
10934 if (owma_len <= 54) {
10935 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10938 wfex = (WAVEFORMATEX *) (owma_data + 36);
10939 buf = gst_buffer_new_and_alloc (owma_len - 54);
10940 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10941 if (wfex->wFormatTag == 0x0161) {
10942 codec_name = "Windows Media Audio";
10944 } else if (wfex->wFormatTag == 0x0162) {
10945 codec_name = "Windows Media Audio 9 Pro";
10947 } else if (wfex->wFormatTag == 0x0163) {
10948 codec_name = "Windows Media Audio 9 Lossless";
10949 /* is that correct? gstffmpegcodecmap.c is missing it, but
10950 * fluendo codec seems to support it */
10954 gst_caps_set_simple (entry->caps,
10955 "codec_data", GST_TYPE_BUFFER, buf,
10956 "wmaversion", G_TYPE_INT, version,
10957 "block_align", G_TYPE_INT,
10958 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
10959 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
10960 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
10961 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
10962 gst_buffer_unref (buf);
10966 codec = g_strdup (codec_name);
10972 gint len = QT_UINT32 (stsd_entry_data) - offset;
10973 const guint8 *wfex_data = stsd_entry_data + offset;
10974 const gchar *codec_name = NULL;
10976 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10977 /* FIXME this should also be gst_riff_strf_auds,
10978 * but the latter one is actually missing bits-per-sample :( */
10983 gint32 nSamplesPerSec;
10984 gint32 nAvgBytesPerSec;
10985 gint16 nBlockAlign;
10986 gint16 wBitsPerSample;
10991 /* FIXME: unify with similar wavformatex parsing code above */
10992 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10998 if (QT_UINT32 (wfex_data) <= len)
10999 size = QT_UINT32 (wfex_data) - 8;
11004 /* No real data, so break out */
11007 switch (QT_FOURCC (wfex_data + 4)) {
11008 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11010 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11015 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11016 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11017 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11018 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11019 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11020 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11021 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11023 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11024 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11025 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11026 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11027 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11028 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11030 if (wfex.wFormatTag == 0x0161) {
11031 codec_name = "Windows Media Audio";
11033 } else if (wfex.wFormatTag == 0x0162) {
11034 codec_name = "Windows Media Audio 9 Pro";
11036 } else if (wfex.wFormatTag == 0x0163) {
11037 codec_name = "Windows Media Audio 9 Lossless";
11038 /* is that correct? gstffmpegcodecmap.c is missing it, but
11039 * fluendo codec seems to support it */
11043 gst_caps_set_simple (entry->caps,
11044 "wmaversion", G_TYPE_INT, version,
11045 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11046 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11047 "width", G_TYPE_INT, wfex.wBitsPerSample,
11048 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11050 if (size > wfex.cbSize) {
11053 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11054 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11055 size - wfex.cbSize);
11056 gst_caps_set_simple (entry->caps,
11057 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11058 gst_buffer_unref (buf);
11060 GST_WARNING_OBJECT (qtdemux, "no codec data");
11065 codec = g_strdup (codec_name);
11073 wfex_data += size + 8;
11079 const guint8 *opus_data;
11080 guint8 *channel_mapping = NULL;
11083 guint8 channel_mapping_family;
11084 guint8 stream_count;
11085 guint8 coupled_count;
11088 opus_data = stsd_entry_data;
11090 channels = GST_READ_UINT8 (opus_data + 45);
11091 rate = GST_READ_UINT32_LE (opus_data + 48);
11092 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11093 stream_count = GST_READ_UINT8 (opus_data + 55);
11094 coupled_count = GST_READ_UINT8 (opus_data + 56);
11096 if (channels > 0) {
11097 channel_mapping = g_malloc (channels * sizeof (guint8));
11098 for (i = 0; i < channels; i++)
11099 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11102 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11103 channel_mapping_family, stream_count, coupled_count,
11115 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11116 GST_TAG_AUDIO_CODEC, codec, NULL);
11120 /* some bitrate info may have ended up in caps */
11121 s = gst_caps_get_structure (entry->caps, 0);
11122 gst_structure_get_int (s, "bitrate", &bitrate);
11124 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11125 GST_TAG_BITRATE, bitrate, NULL);
11128 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11129 if (!stream->protected) {
11131 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11135 if (stream->protected && fourcc == FOURCC_mp4a) {
11136 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11140 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11148 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11150 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11152 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11156 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11157 16 bits is a byte-swapped wave-style codec identifier,
11158 and we can find a WAVE header internally to a 'wave' atom here.
11159 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11160 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11163 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11164 if (len < offset + 20) {
11165 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11167 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11168 const guint8 *data = stsd_entry_data + offset + 16;
11170 GNode *waveheadernode;
11172 wavenode = g_node_new ((guint8 *) data);
11173 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11174 const guint8 *waveheader;
11177 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11178 if (waveheadernode) {
11179 waveheader = (const guint8 *) waveheadernode->data;
11180 headerlen = QT_UINT32 (waveheader);
11182 if (headerlen > 8) {
11183 gst_riff_strf_auds *header = NULL;
11184 GstBuffer *headerbuf;
11190 headerbuf = gst_buffer_new_and_alloc (headerlen);
11191 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11193 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11194 headerbuf, &header, &extra)) {
11195 gst_caps_unref (entry->caps);
11196 /* FIXME: Need to do something with the channel reorder map */
11198 gst_riff_create_audio_caps (header->format, NULL, header,
11199 extra, NULL, NULL, NULL);
11202 gst_buffer_unref (extra);
11207 GST_DEBUG ("Didn't find waveheadernode for this codec");
11209 g_node_destroy (wavenode);
11212 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11213 stream->stream_tags);
11217 /* FIXME: what is in the chunk? */
11220 gint len = QT_UINT32 (stsd_data);
11222 /* seems to be always = 116 = 0x74 */
11228 gint len = QT_UINT32 (stsd_entry_data);
11231 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11233 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11234 gst_caps_set_simple (entry->caps,
11235 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11236 gst_buffer_unref (buf);
11238 gst_caps_set_simple (entry->caps,
11239 "samplesize", G_TYPE_INT, samplesize, NULL);
11244 GNode *alac, *wave = NULL;
11246 /* apparently, m4a has this atom appended directly in the stsd entry,
11247 * while mov has it in a wave atom */
11248 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11250 /* alac now refers to stsd entry atom */
11251 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11253 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11255 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11258 const guint8 *alac_data = alac->data;
11259 gint len = QT_UINT32 (alac->data);
11263 GST_DEBUG_OBJECT (qtdemux,
11264 "discarding alac atom with unexpected len %d", len);
11266 /* codec-data contains alac atom size and prefix,
11267 * ffmpeg likes it that way, not quite gst-ish though ...*/
11268 buf = gst_buffer_new_and_alloc (len);
11269 gst_buffer_fill (buf, 0, alac->data, len);
11270 gst_caps_set_simple (entry->caps,
11271 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11272 gst_buffer_unref (buf);
11274 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11275 entry->n_channels = QT_UINT8 (alac_data + 21);
11276 entry->rate = QT_UINT32 (alac_data + 32);
11279 gst_caps_set_simple (entry->caps,
11280 "samplesize", G_TYPE_INT, samplesize, NULL);
11285 /* The codingname of the sample entry is 'fLaC' */
11286 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11289 /* The 'dfLa' box is added to the sample entry to convey
11290 initializing information for the decoder. */
11291 const GNode *dfla =
11292 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11295 const guint32 len = QT_UINT32 (dfla->data);
11297 /* Must contain at least dfLa box header (12),
11298 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11300 GST_DEBUG_OBJECT (qtdemux,
11301 "discarding dfla atom with unexpected len %d", len);
11303 /* skip dfLa header to get the METADATA_BLOCKs */
11304 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11305 const guint32 metadata_blocks_len = len - 12;
11307 gchar *stream_marker = g_strdup ("fLaC");
11308 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11309 strlen (stream_marker));
11312 guint32 remainder = 0;
11313 guint32 block_size = 0;
11314 gboolean is_last = FALSE;
11316 GValue array = G_VALUE_INIT;
11317 GValue value = G_VALUE_INIT;
11319 g_value_init (&array, GST_TYPE_ARRAY);
11320 g_value_init (&value, GST_TYPE_BUFFER);
11322 gst_value_set_buffer (&value, block);
11323 gst_value_array_append_value (&array, &value);
11324 g_value_reset (&value);
11326 gst_buffer_unref (block);
11328 /* check there's at least one METADATA_BLOCK_HEADER's worth
11329 * of data, and we haven't already finished parsing */
11330 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11331 remainder = metadata_blocks_len - index;
11333 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11335 (metadata_blocks[index + 1] << 16) +
11336 (metadata_blocks[index + 2] << 8) +
11337 metadata_blocks[index + 3];
11339 /* be careful not to read off end of box */
11340 if (block_size > remainder) {
11344 is_last = metadata_blocks[index] >> 7;
11346 block = gst_buffer_new_and_alloc (block_size);
11348 gst_buffer_fill (block, 0, &metadata_blocks[index],
11351 gst_value_set_buffer (&value, block);
11352 gst_value_array_append_value (&array, &value);
11353 g_value_reset (&value);
11355 gst_buffer_unref (block);
11357 index += block_size;
11360 /* only append the metadata if we successfully read all of it */
11362 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11363 (stream)->caps, 0), "streamheader", &array);
11365 GST_WARNING_OBJECT (qtdemux,
11366 "discarding all METADATA_BLOCKs due to invalid "
11367 "block_size %d at idx %d, rem %d", block_size, index,
11371 g_value_unset (&value);
11372 g_value_unset (&array);
11374 /* The sample rate obtained from the stsd may not be accurate
11375 * since it cannot represent rates greater than 65535Hz, so
11376 * override that value with the sample rate from the
11377 * METADATA_BLOCK_STREAMINFO block */
11378 CUR_STREAM (stream)->rate =
11379 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11390 gint len = QT_UINT32 (stsd_entry_data);
11393 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11396 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11398 /* If we have enough data, let's try to get the 'damr' atom. See
11399 * the 3GPP container spec (26.244) for more details. */
11400 if ((len - 0x34) > 8 &&
11401 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11402 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11403 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11406 gst_caps_set_simple (entry->caps,
11407 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11408 gst_buffer_unref (buf);
11414 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11415 gint len = QT_UINT32 (stsd_entry_data);
11418 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11420 if (sound_version == 1) {
11421 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11422 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11423 guint8 codec_data[2];
11425 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11427 gint sample_rate_index =
11428 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11430 /* build AAC codec data */
11431 codec_data[0] = profile << 3;
11432 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11433 codec_data[1] = (sample_rate_index & 0x01) << 7;
11434 codec_data[1] |= (channels & 0xF) << 3;
11436 buf = gst_buffer_new_and_alloc (2);
11437 gst_buffer_fill (buf, 0, codec_data, 2);
11438 gst_caps_set_simple (entry->caps,
11439 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11440 gst_buffer_unref (buf);
11446 GST_INFO_OBJECT (qtdemux,
11447 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11451 GST_INFO_OBJECT (qtdemux,
11452 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11453 GST_FOURCC_ARGS (fourcc), entry->caps);
11455 } else if (stream->subtype == FOURCC_strm) {
11456 if (fourcc == FOURCC_rtsp) {
11457 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11459 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11460 GST_FOURCC_ARGS (fourcc));
11461 goto unknown_stream;
11463 entry->sampled = TRUE;
11464 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11465 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11467 entry->sampled = TRUE;
11468 entry->sparse = TRUE;
11471 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11474 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11475 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11480 /* hunt for sort-of codec data */
11484 GNode *mp4s = NULL;
11485 GNode *esds = NULL;
11487 /* look for palette in a stsd->mp4s->esds sub-atom */
11488 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11490 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11491 if (esds == NULL) {
11493 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11497 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11498 stream->stream_tags);
11502 GST_INFO_OBJECT (qtdemux,
11503 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11506 GST_INFO_OBJECT (qtdemux,
11507 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11508 GST_FOURCC_ARGS (fourcc), entry->caps);
11510 /* everything in 1 sample */
11511 entry->sampled = TRUE;
11514 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11517 if (entry->caps == NULL)
11518 goto unknown_stream;
11521 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11522 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11528 /* promote to sampled format */
11529 if (entry->fourcc == FOURCC_samr) {
11530 /* force mono 8000 Hz for AMR */
11531 entry->sampled = TRUE;
11532 entry->n_channels = 1;
11533 entry->rate = 8000;
11534 } else if (entry->fourcc == FOURCC_sawb) {
11535 /* force mono 16000 Hz for AMR-WB */
11536 entry->sampled = TRUE;
11537 entry->n_channels = 1;
11538 entry->rate = 16000;
11539 } else if (entry->fourcc == FOURCC_mp4a) {
11540 entry->sampled = TRUE;
11544 stsd_entry_data += len;
11545 remaining_stsd_len -= len;
11549 /* collect sample information */
11550 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11551 goto samples_failed;
11553 if (qtdemux->fragmented) {
11556 /* need all moov samples as basis; probably not many if any at all */
11557 /* prevent moof parsing taking of at this time */
11558 offset = qtdemux->moof_offset;
11559 qtdemux->moof_offset = 0;
11560 if (stream->n_samples &&
11561 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11562 qtdemux->moof_offset = offset;
11563 goto samples_failed;
11565 qtdemux->moof_offset = 0;
11566 /* movie duration more reliable in this case (e.g. mehd) */
11567 if (qtdemux->segment.duration &&
11568 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11570 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11573 /* configure segments */
11574 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11575 goto segments_failed;
11577 /* add some language tag, if useful */
11578 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11579 strcmp (stream->lang_id, "und")) {
11580 const gchar *lang_code;
11582 /* convert ISO 639-2 code to ISO 639-1 */
11583 lang_code = gst_tag_get_language_code (stream->lang_id);
11584 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11585 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11588 /* Check for UDTA tags */
11589 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11590 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11593 /* now we are ready to add the stream */
11594 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11595 goto too_many_streams;
11597 if (!qtdemux->got_moov) {
11598 qtdemux->streams[qtdemux->n_streams] = stream;
11599 qtdemux->n_streams++;
11600 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11608 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11610 gst_qtdemux_stream_free (qtdemux, stream);
11615 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11616 (_("This file is corrupt and cannot be played.")), (NULL));
11618 gst_qtdemux_stream_free (qtdemux, stream);
11623 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11625 gst_qtdemux_stream_free (qtdemux, stream);
11631 /* we posted an error already */
11632 /* free stbl sub-atoms */
11633 gst_qtdemux_stbl_free (stream);
11635 gst_qtdemux_stream_free (qtdemux, stream);
11640 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11643 gst_qtdemux_stream_free (qtdemux, stream);
11648 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11649 GST_FOURCC_ARGS (stream->subtype));
11651 gst_qtdemux_stream_free (qtdemux, stream);
11656 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11657 (_("This file contains too many streams. Only playing first %d"),
11658 GST_QTDEMUX_MAX_STREAMS), (NULL));
11663 /* If we can estimate the overall bitrate, and don't have information about the
11664 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11665 * the overall bitrate minus the sum of the bitrates of all other streams. This
11666 * should be useful for the common case where we have one audio and one video
11667 * stream and can estimate the bitrate of one, but not the other. */
11669 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11671 QtDemuxStream *stream = NULL;
11672 gint64 size, sys_bitrate, sum_bitrate = 0;
11673 GstClockTime duration;
11677 if (qtdemux->fragmented)
11680 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11682 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11684 GST_DEBUG_OBJECT (qtdemux,
11685 "Size in bytes of the stream not known - bailing");
11689 /* Subtract the header size */
11690 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11691 size, qtdemux->header_size);
11693 if (size < qtdemux->header_size)
11696 size = size - qtdemux->header_size;
11698 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11699 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11703 for (i = 0; i < qtdemux->n_streams; i++) {
11704 switch (qtdemux->streams[i]->subtype) {
11707 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11708 CUR_STREAM (qtdemux->streams[i])->caps);
11709 /* retrieve bitrate, prefer avg then max */
11711 if (qtdemux->streams[i]->stream_tags) {
11712 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11713 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11714 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11715 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11716 GST_TAG_NOMINAL_BITRATE, &bitrate);
11717 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11718 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11719 GST_TAG_BITRATE, &bitrate);
11720 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11723 sum_bitrate += bitrate;
11726 GST_DEBUG_OBJECT (qtdemux,
11727 ">1 stream with unknown bitrate - bailing");
11730 stream = qtdemux->streams[i];
11734 /* For other subtypes, we assume no significant impact on bitrate */
11740 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11744 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11746 if (sys_bitrate < sum_bitrate) {
11747 /* This can happen, since sum_bitrate might be derived from maximum
11748 * bitrates and not average bitrates */
11749 GST_DEBUG_OBJECT (qtdemux,
11750 "System bitrate less than sum bitrate - bailing");
11754 bitrate = sys_bitrate - sum_bitrate;
11755 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11756 ", Stream bitrate = %u", sys_bitrate, bitrate);
11758 if (!stream->stream_tags)
11759 stream->stream_tags = gst_tag_list_new_empty ();
11761 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11763 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11764 GST_TAG_BITRATE, bitrate, NULL);
11767 static GstFlowReturn
11768 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11771 GstFlowReturn ret = GST_FLOW_OK;
11773 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11775 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11776 QtDemuxStream *stream = qtdemux->streams[i];
11777 guint32 sample_num = 0;
11779 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11780 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11782 if (qtdemux->fragmented) {
11783 /* need all moov samples first */
11784 GST_OBJECT_LOCK (qtdemux);
11785 while (stream->n_samples == 0)
11786 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11788 GST_OBJECT_UNLOCK (qtdemux);
11790 /* discard any stray moof */
11791 qtdemux->moof_offset = 0;
11794 /* prepare braking */
11795 if (ret != GST_FLOW_ERROR)
11798 /* in pull mode, we should have parsed some sample info by now;
11799 * and quite some code will not handle no samples.
11800 * in push mode, we'll just have to deal with it */
11801 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11802 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11803 gst_qtdemux_remove_stream (qtdemux, i);
11808 /* parse the initial sample for use in setting the frame rate cap */
11809 while (sample_num == 0 && sample_num < stream->n_samples) {
11810 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11814 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11815 stream->first_duration = stream->samples[0].duration;
11816 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11817 stream->track_id, stream->first_duration);
11824 static GstFlowReturn
11825 qtdemux_expose_streams (GstQTDemux * qtdemux)
11828 GSList *oldpads = NULL;
11831 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11833 for (i = 0; i < qtdemux->n_streams; i++) {
11834 QtDemuxStream *stream = qtdemux->streams[i];
11835 GstPad *oldpad = stream->pad;
11838 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11839 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11841 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11842 stream->track_id == qtdemux->chapters_track_id) {
11843 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11844 so that it doesn't look like a subtitle track */
11845 gst_qtdemux_remove_stream (qtdemux, i);
11850 /* now we have all info and can expose */
11851 list = stream->stream_tags;
11852 stream->stream_tags = NULL;
11854 oldpads = g_slist_prepend (oldpads, oldpad);
11855 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11856 return GST_FLOW_ERROR;
11859 gst_qtdemux_guess_bitrate (qtdemux);
11861 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11863 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11864 GstPad *oldpad = iter->data;
11867 event = gst_event_new_eos ();
11868 if (qtdemux->segment_seqnum)
11869 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11871 gst_pad_push_event (oldpad, event);
11872 gst_pad_set_active (oldpad, FALSE);
11873 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11874 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11875 gst_object_unref (oldpad);
11878 /* check if we should post a redirect in case there is a single trak
11879 * and it is a redirecting trak */
11880 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11883 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11884 "an external content");
11885 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11886 gst_structure_new ("redirect",
11887 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11889 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11890 qtdemux->posted_redirect = TRUE;
11893 for (i = 0; i < qtdemux->n_streams; i++) {
11894 QtDemuxStream *stream = qtdemux->streams[i];
11896 qtdemux_do_allocation (qtdemux, stream);
11899 qtdemux->exposed = TRUE;
11900 return GST_FLOW_OK;
11903 /* check if major or compatible brand is 3GP */
11904 static inline gboolean
11905 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11908 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11910 } else if (qtdemux->comp_brands != NULL) {
11914 gboolean res = FALSE;
11916 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11919 while (size >= 4) {
11920 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11925 gst_buffer_unmap (qtdemux->comp_brands, &map);
11932 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11933 static inline gboolean
11934 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11936 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11937 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11938 || fourcc == FOURCC_albm;
11942 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11943 const char *tag, const char *dummy, GNode * node)
11945 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11949 gdouble longitude, latitude, altitude;
11952 len = QT_UINT32 (node->data);
11959 /* TODO: language code skipped */
11961 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11964 /* do not alarm in trivial case, but bail out otherwise */
11965 if (*(data + offset) != 0) {
11966 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11970 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11971 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11972 offset += strlen (name);
11976 if (len < offset + 2 + 4 + 4 + 4)
11979 /* +1 +1 = skip null-terminator and location role byte */
11981 /* table in spec says unsigned, semantics say negative has meaning ... */
11982 longitude = QT_SFP32 (data + offset);
11985 latitude = QT_SFP32 (data + offset);
11988 altitude = QT_SFP32 (data + offset);
11990 /* one invalid means all are invalid */
11991 if (longitude >= -180.0 && longitude <= 180.0 &&
11992 latitude >= -90.0 && latitude <= 90.0) {
11993 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11994 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11995 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11996 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11999 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12006 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12013 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12014 const char *tag, const char *dummy, GNode * node)
12020 len = QT_UINT32 (node->data);
12024 y = QT_UINT16 ((guint8 *) node->data + 12);
12026 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12029 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12031 date = g_date_new_dmy (1, 1, y);
12032 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12033 g_date_free (date);
12037 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12038 const char *tag, const char *dummy, GNode * node)
12041 char *tag_str = NULL;
12046 len = QT_UINT32 (node->data);
12051 entity = (guint8 *) node->data + offset;
12052 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12053 GST_DEBUG_OBJECT (qtdemux,
12054 "classification info: %c%c%c%c invalid classification entity",
12055 entity[0], entity[1], entity[2], entity[3]);
12060 table = QT_UINT16 ((guint8 *) node->data + offset);
12062 /* Language code skipped */
12066 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12067 * XXXX: classification entity, fixed length 4 chars.
12068 * Y[YYYY]: classification table, max 5 chars.
12070 tag_str = g_strdup_printf ("----://%u/%s",
12071 table, (char *) node->data + offset);
12073 /* memcpy To be sure we're preserving byte order */
12074 memcpy (tag_str, entity, 4);
12075 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12077 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12086 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12092 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12093 const char *tag, const char *dummy, GNode * node)
12095 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12101 gboolean ret = TRUE;
12102 const gchar *charset = NULL;
12104 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12106 len = QT_UINT32 (data->data);
12107 type = QT_UINT32 ((guint8 *) data->data + 8);
12108 if (type == 0x00000001 && len > 16) {
12109 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12112 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12113 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12116 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12120 len = QT_UINT32 (node->data);
12121 type = QT_UINT32 ((guint8 *) node->data + 4);
12122 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12126 /* Type starts with the (C) symbol, so the next data is a list
12127 * of (string size(16), language code(16), string) */
12129 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12130 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12132 /* the string + fourcc + size + 2 16bit fields,
12133 * means that there are more tags in this atom */
12134 if (len > str_len + 8 + 4) {
12135 /* TODO how to represent the same tag in different languages? */
12136 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12137 "text alternatives, reading only first one");
12141 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12142 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12144 if (lang_code < 0x800) { /* MAC encoded string */
12147 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12148 QT_FOURCC ((guint8 *) node->data + 4))) {
12149 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12151 /* we go for 3GP style encoding if major brands claims so,
12152 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12153 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12154 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12155 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12157 /* 16-bit Language code is ignored here as well */
12158 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12165 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12166 ret = FALSE; /* may have to fallback */
12169 GError *err = NULL;
12171 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12172 charset, NULL, NULL, &err);
12174 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12175 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12177 g_error_free (err);
12180 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12181 len - offset, env_vars);
12184 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12185 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12189 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12196 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12197 const char *tag, const char *dummy, GNode * node)
12199 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12203 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12204 const char *tag, const char *dummy, GNode * node)
12206 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12208 char *s, *t, *k = NULL;
12213 /* first try normal string tag if major brand not 3GP */
12214 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12215 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12216 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12217 * let's try it 3gpp way after minor safety check */
12219 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12225 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12229 len = QT_UINT32 (data);
12233 count = QT_UINT8 (data + 14);
12235 for (; count; count--) {
12238 if (offset + 1 > len)
12240 slen = QT_UINT8 (data + offset);
12242 if (offset + slen > len)
12244 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12247 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12249 t = g_strjoin (",", k, s, NULL);
12257 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12264 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12265 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12274 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12280 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12281 const char *tag1, const char *tag2, GNode * node)
12288 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12290 len = QT_UINT32 (data->data);
12291 type = QT_UINT32 ((guint8 *) data->data + 8);
12292 if (type == 0x00000000 && len >= 22) {
12293 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12294 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12296 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12297 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12300 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12301 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12308 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12309 const char *tag1, const char *dummy, GNode * node)
12316 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12318 len = QT_UINT32 (data->data);
12319 type = QT_UINT32 ((guint8 *) data->data + 8);
12320 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12321 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12322 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12323 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12325 /* do not add bpm=0 */
12326 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12327 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12335 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12336 const char *tag1, const char *dummy, GNode * node)
12343 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12345 len = QT_UINT32 (data->data);
12346 type = QT_UINT32 ((guint8 *) data->data + 8);
12347 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12348 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12349 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12350 num = QT_UINT32 ((guint8 *) data->data + 16);
12352 /* do not add num=0 */
12353 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12354 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12361 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12362 const char *tag1, const char *dummy, GNode * node)
12369 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12371 len = QT_UINT32 (data->data);
12372 type = QT_UINT32 ((guint8 *) data->data + 8);
12373 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12374 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12375 GstTagImageType image_type;
12377 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12378 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12380 image_type = GST_TAG_IMAGE_TYPE_NONE;
12383 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12384 len - 16, image_type))) {
12385 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12386 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12387 gst_sample_unref (sample);
12394 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12395 const char *tag, const char *dummy, GNode * node)
12402 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12404 len = QT_UINT32 (data->data);
12405 type = QT_UINT32 ((guint8 *) data->data + 8);
12406 if (type == 0x00000001 && len > 16) {
12407 guint y, m = 1, d = 1;
12410 s = g_strndup ((char *) data->data + 16, len - 16);
12411 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12412 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12413 if (ret >= 1 && y > 1500 && y < 3000) {
12416 date = g_date_new_dmy (d, m, y);
12417 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12418 g_date_free (date);
12420 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12428 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12429 const char *tag, const char *dummy, GNode * node)
12433 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12435 /* re-route to normal string tag if major brand says so
12436 * or no data atom and compatible brand suggests so */
12437 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12438 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12439 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12444 guint len, type, n;
12446 len = QT_UINT32 (data->data);
12447 type = QT_UINT32 ((guint8 *) data->data + 8);
12448 if (type == 0x00000000 && len >= 18) {
12449 n = QT_UINT16 ((guint8 *) data->data + 16);
12451 const gchar *genre;
12453 genre = gst_tag_id3_genre_get (n - 1);
12454 if (genre != NULL) {
12455 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12456 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12464 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12465 const gchar * tag, guint8 * data, guint32 datasize)
12470 /* make a copy to have \0 at the end */
12471 datacopy = g_strndup ((gchar *) data, datasize);
12473 /* convert the str to double */
12474 if (sscanf (datacopy, "%lf", &value) == 1) {
12475 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12476 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12478 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12486 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12487 const char *tag, const char *tag_bis, GNode * node)
12496 const gchar *meanstr;
12497 const gchar *namestr;
12499 /* checking the whole ---- atom size for consistency */
12500 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12501 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12505 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12507 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12511 meansize = QT_UINT32 (mean->data);
12512 if (meansize <= 12) {
12513 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12516 meanstr = ((gchar *) mean->data) + 12;
12519 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12521 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12525 namesize = QT_UINT32 (name->data);
12526 if (namesize <= 12) {
12527 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12530 namestr = ((gchar *) name->data) + 12;
12538 * uint24 - data type
12542 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12544 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12547 datasize = QT_UINT32 (data->data);
12548 if (datasize <= 16) {
12549 GST_WARNING_OBJECT (demux, "Data atom too small");
12552 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12554 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12555 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12556 static const struct
12558 const gchar name[28];
12559 const gchar tag[28];
12562 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12563 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12564 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12565 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12566 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12567 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12568 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12569 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12573 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12574 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12575 switch (gst_tag_get_type (tags[i].tag)) {
12576 case G_TYPE_DOUBLE:
12577 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12578 ((guint8 *) data->data) + 16, datasize - 16);
12580 case G_TYPE_STRING:
12581 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12590 if (i == G_N_ELEMENTS (tags))
12600 #ifndef GST_DISABLE_GST_DEBUG
12602 gchar *namestr_dbg;
12603 gchar *meanstr_dbg;
12605 meanstr_dbg = g_strndup (meanstr, meansize);
12606 namestr_dbg = g_strndup (namestr, namesize);
12608 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12609 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12611 g_free (namestr_dbg);
12612 g_free (meanstr_dbg);
12619 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12620 const char *tag_bis, GNode * node)
12625 GstTagList *id32_taglist = NULL;
12627 GST_LOG_OBJECT (demux, "parsing ID32");
12630 len = GST_READ_UINT32_BE (data);
12632 /* need at least full box and language tag */
12636 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12637 gst_buffer_fill (buf, 0, data + 14, len - 14);
12639 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12640 if (id32_taglist) {
12641 GST_LOG_OBJECT (demux, "parsing ok");
12642 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12643 gst_tag_list_unref (id32_taglist);
12645 GST_LOG_OBJECT (demux, "parsing failed");
12648 gst_buffer_unref (buf);
12651 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12652 const char *tag, const char *tag_bis, GNode * node);
12655 FOURCC_pcst -> if media is a podcast -> bool
12656 FOURCC_cpil -> if media is part of a compilation -> bool
12657 FOURCC_pgap -> if media is part of a gapless context -> bool
12658 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12661 static const struct
12664 const gchar *gst_tag;
12665 const gchar *gst_tag_bis;
12666 const GstQTDemuxAddTagFunc func;
12669 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12670 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12671 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12672 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12673 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12674 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12675 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12676 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12677 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12678 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12679 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12680 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12681 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12682 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12683 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12684 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12685 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12686 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12687 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12688 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12689 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12690 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12691 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12692 qtdemux_tag_add_num}, {
12693 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12694 qtdemux_tag_add_num}, {
12695 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12696 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12697 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12698 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12699 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12700 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12701 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12702 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12703 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12704 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12705 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12706 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12707 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12708 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12709 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12710 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12711 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12712 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12713 qtdemux_tag_add_classification}, {
12714 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12715 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12716 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12718 /* This is a special case, some tags are stored in this
12719 * 'reverse dns naming', according to:
12720 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12723 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12724 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12725 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12728 struct _GstQtDemuxTagList
12731 GstTagList *taglist;
12733 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12736 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12742 const gchar *style;
12747 GstQTDemux *demux = qtdemuxtaglist->demux;
12748 GstTagList *taglist = qtdemuxtaglist->taglist;
12751 len = QT_UINT32 (data);
12752 buf = gst_buffer_new_and_alloc (len);
12753 gst_buffer_fill (buf, 0, data, len);
12755 /* heuristic to determine style of tag */
12756 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12757 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12759 else if (demux->major_brand == FOURCC_qt__)
12760 style = "quicktime";
12761 /* fall back to assuming iso/3gp tag style */
12765 /* santize the name for the caps. */
12766 for (i = 0; i < 4; i++) {
12767 guint8 d = data[4 + i];
12768 if (g_ascii_isalnum (d))
12769 ndata[i] = g_ascii_tolower (d);
12774 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12775 ndata[0], ndata[1], ndata[2], ndata[3]);
12776 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12778 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12779 sample = gst_sample_new (buf, NULL, NULL, s);
12780 gst_buffer_unref (buf);
12781 g_free (media_type);
12783 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12786 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12787 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12789 gst_sample_unref (sample);
12793 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12800 GstQtDemuxTagList demuxtaglist;
12802 demuxtaglist.demux = qtdemux;
12803 demuxtaglist.taglist = taglist;
12805 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12806 if (meta != NULL) {
12807 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12808 if (ilst == NULL) {
12809 GST_LOG_OBJECT (qtdemux, "no ilst");
12814 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12818 while (i < G_N_ELEMENTS (add_funcs)) {
12819 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12823 len = QT_UINT32 (node->data);
12825 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12826 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12828 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12829 add_funcs[i].gst_tag_bis, node);
12831 g_node_destroy (node);
12837 /* parsed nodes have been removed, pass along remainder as blob */
12838 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12839 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12841 /* parse up XMP_ node if existing */
12842 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12843 if (xmp_ != NULL) {
12845 GstTagList *xmptaglist;
12847 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12848 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12849 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12850 gst_buffer_unref (buf);
12852 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12854 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12860 GstStructure *structure; /* helper for sort function */
12862 guint min_req_bitrate;
12863 guint min_req_qt_version;
12867 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12869 GstQtReference *ref_a = (GstQtReference *) a;
12870 GstQtReference *ref_b = (GstQtReference *) b;
12872 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12873 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12875 /* known bitrates go before unknown; higher bitrates go first */
12876 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12879 /* sort the redirects and post a message for the application.
12882 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12884 GstQtReference *best;
12887 GValue list_val = { 0, };
12890 g_assert (references != NULL);
12892 references = g_list_sort (references, qtdemux_redirects_sort_func);
12894 best = (GstQtReference *) references->data;
12896 g_value_init (&list_val, GST_TYPE_LIST);
12898 for (l = references; l != NULL; l = l->next) {
12899 GstQtReference *ref = (GstQtReference *) l->data;
12900 GValue struct_val = { 0, };
12902 ref->structure = gst_structure_new ("redirect",
12903 "new-location", G_TYPE_STRING, ref->location, NULL);
12905 if (ref->min_req_bitrate > 0) {
12906 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12907 ref->min_req_bitrate, NULL);
12910 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12911 g_value_set_boxed (&struct_val, ref->structure);
12912 gst_value_list_append_value (&list_val, &struct_val);
12913 g_value_unset (&struct_val);
12914 /* don't free anything here yet, since we need best->structure below */
12917 g_assert (best != NULL);
12918 s = gst_structure_copy (best->structure);
12920 if (g_list_length (references) > 1) {
12921 gst_structure_set_value (s, "locations", &list_val);
12924 g_value_unset (&list_val);
12926 for (l = references; l != NULL; l = l->next) {
12927 GstQtReference *ref = (GstQtReference *) l->data;
12929 gst_structure_free (ref->structure);
12930 g_free (ref->location);
12933 g_list_free (references);
12935 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12936 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12937 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12938 qtdemux->posted_redirect = TRUE;
12941 /* look for redirect nodes, collect all redirect information and
12945 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12947 GNode *rmra, *rmda, *rdrf;
12949 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12951 GList *redirects = NULL;
12953 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12955 GstQtReference ref = { NULL, NULL, 0, 0 };
12956 GNode *rmdr, *rmvc;
12958 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12959 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12960 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12961 ref.min_req_bitrate);
12964 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12965 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12966 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12968 #ifndef GST_DISABLE_GST_DEBUG
12969 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12971 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12973 GST_LOG_OBJECT (qtdemux,
12974 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12975 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12976 bitmask, check_type);
12977 if (package == FOURCC_qtim && check_type == 0) {
12978 ref.min_req_qt_version = version;
12982 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12988 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12989 if (ref_len > 20) {
12990 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12991 ref_data = (guint8 *) rdrf->data + 20;
12992 if (ref_type == FOURCC_alis) {
12993 guint record_len, record_version, fn_len;
12995 if (ref_len > 70) {
12996 /* MacOSX alias record, google for alias-layout.txt */
12997 record_len = QT_UINT16 (ref_data + 4);
12998 record_version = QT_UINT16 (ref_data + 4 + 2);
12999 fn_len = QT_UINT8 (ref_data + 50);
13000 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13001 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13004 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13007 } else if (ref_type == FOURCC_url_) {
13008 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13010 GST_DEBUG_OBJECT (qtdemux,
13011 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13012 GST_FOURCC_ARGS (ref_type));
13014 if (ref.location != NULL) {
13015 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13017 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13019 GST_WARNING_OBJECT (qtdemux,
13020 "Failed to extract redirect location from rdrf atom");
13023 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13027 /* look for others */
13028 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13031 if (redirects != NULL) {
13032 qtdemux_process_redirects (qtdemux, redirects);
13038 static GstTagList *
13039 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13043 if (tags == NULL) {
13044 tags = gst_tag_list_new_empty ();
13045 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13048 if (qtdemux->major_brand == FOURCC_mjp2)
13049 fmt = "Motion JPEG 2000";
13050 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13052 else if (qtdemux->major_brand == FOURCC_qt__)
13054 else if (qtdemux->fragmented)
13057 fmt = "ISO MP4/M4A";
13059 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13060 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13062 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13068 /* we have read the complete moov node now.
13069 * This function parses all of the relevant info, creates the traks and
13070 * prepares all data structures for playback
13073 qtdemux_parse_tree (GstQTDemux * qtdemux)
13079 GstClockTime duration;
13081 guint64 creation_time;
13082 GstDateTime *datetime = NULL;
13085 /* make sure we have a usable taglist */
13086 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13088 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13089 if (mvhd == NULL) {
13090 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13091 return qtdemux_parse_redirects (qtdemux);
13094 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13095 if (version == 1) {
13096 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13097 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13098 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13099 } else if (version == 0) {
13100 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13101 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13102 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13104 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13108 /* Moving qt creation time (secs since 1904) to unix time */
13109 if (creation_time != 0) {
13110 /* Try to use epoch first as it should be faster and more commonly found */
13111 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13114 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13115 /* some data cleansing sanity */
13116 g_get_current_time (&now);
13117 if (now.tv_sec + 24 * 3600 < creation_time) {
13118 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13120 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13123 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13124 GDateTime *dt, *dt_local;
13126 dt = g_date_time_add_seconds (base_dt, creation_time);
13127 dt_local = g_date_time_to_local (dt);
13128 datetime = gst_date_time_new_from_g_date_time (dt_local);
13130 g_date_time_unref (base_dt);
13131 g_date_time_unref (dt);
13135 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13136 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13138 gst_date_time_unref (datetime);
13141 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13142 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13144 /* check for fragmented file and get some (default) data */
13145 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13148 GstByteReader mehd_data;
13150 /* let track parsing or anyone know weird stuff might happen ... */
13151 qtdemux->fragmented = TRUE;
13153 /* compensate for total duration */
13154 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13156 qtdemux_parse_mehd (qtdemux, &mehd_data);
13159 /* set duration in the segment info */
13160 gst_qtdemux_get_duration (qtdemux, &duration);
13162 qtdemux->segment.duration = duration;
13163 /* also do not exceed duration; stop is set that way post seek anyway,
13164 * and segment activation falls back to duration,
13165 * whereas loop only checks stop, so let's align this here as well */
13166 qtdemux->segment.stop = duration;
13169 /* parse all traks */
13170 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13172 qtdemux_parse_trak (qtdemux, trak);
13173 /* iterate all siblings */
13174 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13177 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13180 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13182 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13184 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13187 /* maybe also some tags in meta box */
13188 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13190 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13191 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13193 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13196 /* parse any protection system info */
13197 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13199 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13200 qtdemux_parse_pssh (qtdemux, pssh);
13201 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13204 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13209 /* taken from ffmpeg */
13211 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13223 len = (len << 7) | (c & 0x7f);
13231 /* this can change the codec originally present in @list */
13233 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13234 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13236 int len = QT_UINT32 (esds->data);
13237 guint8 *ptr = esds->data;
13238 guint8 *end = ptr + len;
13240 guint8 *data_ptr = NULL;
13242 guint8 object_type_id = 0;
13243 const char *codec_name = NULL;
13244 GstCaps *caps = NULL;
13246 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13248 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13250 while (ptr + 1 < end) {
13251 tag = QT_UINT8 (ptr);
13252 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13254 len = read_descr_size (ptr, end, &ptr);
13255 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13257 /* Check the stated amount of data is available for reading */
13258 if (len < 0 || ptr + len > end)
13262 case ES_DESCRIPTOR_TAG:
13263 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13264 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13267 case DECODER_CONFIG_DESC_TAG:{
13268 guint max_bitrate, avg_bitrate;
13270 object_type_id = QT_UINT8 (ptr);
13271 max_bitrate = QT_UINT32 (ptr + 5);
13272 avg_bitrate = QT_UINT32 (ptr + 9);
13273 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13274 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13275 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13276 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13277 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13278 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13279 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13280 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13282 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13283 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13284 avg_bitrate, NULL);
13289 case DECODER_SPECIFIC_INFO_TAG:
13290 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13291 if (object_type_id == 0xe0 && len == 0x40) {
13297 GST_DEBUG_OBJECT (qtdemux,
13298 "Have VOBSUB palette. Creating palette event");
13299 /* move to decConfigDescr data and read palette */
13301 for (i = 0; i < 16; i++) {
13302 clut[i] = QT_UINT32 (data);
13306 s = gst_structure_new ("application/x-gst-dvd", "event",
13307 G_TYPE_STRING, "dvd-spu-clut-change",
13308 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13309 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13310 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13311 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13312 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13313 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13314 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13315 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13318 /* store event and trigger custom processing */
13319 stream->pending_event =
13320 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13322 /* Generic codec_data handler puts it on the caps */
13329 case SL_CONFIG_DESC_TAG:
13330 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13334 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13336 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13342 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13343 * in use, and should also be used to override some other parameters for some
13345 switch (object_type_id) {
13346 case 0x20: /* MPEG-4 */
13347 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13348 * profile_and_level_indication */
13349 if (data_ptr != NULL && data_len >= 5 &&
13350 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13351 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13352 data_ptr + 4, data_len - 4);
13354 break; /* Nothing special needed here */
13355 case 0x21: /* H.264 */
13356 codec_name = "H.264 / AVC";
13357 caps = gst_caps_new_simple ("video/x-h264",
13358 "stream-format", G_TYPE_STRING, "avc",
13359 "alignment", G_TYPE_STRING, "au", NULL);
13361 case 0x40: /* AAC (any) */
13362 case 0x66: /* AAC Main */
13363 case 0x67: /* AAC LC */
13364 case 0x68: /* AAC SSR */
13365 /* Override channels and rate based on the codec_data, as it's often
13367 /* Only do so for basic setup without HE-AAC extension */
13368 if (data_ptr && data_len == 2) {
13369 guint channels, rate;
13371 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13373 entry->n_channels = channels;
13375 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13377 entry->rate = rate;
13380 /* Set level and profile if possible */
13381 if (data_ptr != NULL && data_len >= 2) {
13382 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13383 data_ptr, data_len);
13385 const gchar *profile_str = NULL;
13388 guint8 *codec_data;
13389 gint rate_idx, profile;
13391 /* No codec_data, let's invent something.
13392 * FIXME: This is wrong for SBR! */
13394 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13396 buffer = gst_buffer_new_and_alloc (2);
13397 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13398 codec_data = map.data;
13401 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13404 switch (object_type_id) {
13406 profile_str = "main";
13410 profile_str = "lc";
13414 profile_str = "ssr";
13422 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13424 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13426 gst_buffer_unmap (buffer, &map);
13427 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13428 GST_TYPE_BUFFER, buffer, NULL);
13429 gst_buffer_unref (buffer);
13432 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13433 G_TYPE_STRING, profile_str, NULL);
13437 case 0x60: /* MPEG-2, various profiles */
13443 codec_name = "MPEG-2 video";
13444 caps = gst_caps_new_simple ("video/mpeg",
13445 "mpegversion", G_TYPE_INT, 2,
13446 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13448 case 0x69: /* MPEG-2 BC audio */
13449 case 0x6B: /* MPEG-1 audio */
13450 caps = gst_caps_new_simple ("audio/mpeg",
13451 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13452 codec_name = "MPEG-1 audio";
13454 case 0x6A: /* MPEG-1 */
13455 codec_name = "MPEG-1 video";
13456 caps = gst_caps_new_simple ("video/mpeg",
13457 "mpegversion", G_TYPE_INT, 1,
13458 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13460 case 0x6C: /* MJPEG */
13462 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13464 codec_name = "Motion-JPEG";
13466 case 0x6D: /* PNG */
13468 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13470 codec_name = "PNG still images";
13472 case 0x6E: /* JPEG2000 */
13473 codec_name = "JPEG-2000";
13474 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13476 case 0xA4: /* Dirac */
13477 codec_name = "Dirac";
13478 caps = gst_caps_new_empty_simple ("video/x-dirac");
13480 case 0xA5: /* AC3 */
13481 codec_name = "AC-3 audio";
13482 caps = gst_caps_new_simple ("audio/x-ac3",
13483 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13485 case 0xA9: /* AC3 */
13486 codec_name = "DTS audio";
13487 caps = gst_caps_new_simple ("audio/x-dts",
13488 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13490 case 0xE1: /* QCELP */
13491 /* QCELP, the codec_data is a riff tag (little endian) with
13492 * 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). */
13493 caps = gst_caps_new_empty_simple ("audio/qcelp");
13494 codec_name = "QCELP";
13500 /* If we have a replacement caps, then change our caps for this stream */
13502 gst_caps_unref (entry->caps);
13503 entry->caps = caps;
13506 if (codec_name && list)
13507 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13508 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13510 /* Add the codec_data attribute to caps, if we have it */
13514 buffer = gst_buffer_new_and_alloc (data_len);
13515 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13517 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13518 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13520 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13522 gst_buffer_unref (buffer);
13527 static inline GstCaps *
13528 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13532 char *s, fourstr[5];
13534 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13535 for (i = 0; i < 4; i++) {
13536 if (!g_ascii_isalnum (fourstr[i]))
13539 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13540 caps = gst_caps_new_empty_simple (s);
13545 #define _codec(name) \
13547 if (codec_name) { \
13548 *codec_name = g_strdup (name); \
13553 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13554 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
13555 const guint8 * stsd_entry_data, gchar ** codec_name)
13557 GstCaps *caps = NULL;
13558 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13561 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
13562 _codec ("PNG still images");
13563 caps = gst_caps_new_empty_simple ("image/png");
13566 _codec ("JPEG still images");
13568 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13571 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13572 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13573 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13574 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13575 _codec ("Motion-JPEG");
13577 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13580 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13581 _codec ("Motion-JPEG format B");
13582 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13585 _codec ("JPEG-2000");
13586 /* override to what it should be according to spec, avoid palette_data */
13587 entry->bits_per_sample = 24;
13588 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13591 _codec ("Sorensen video v.3");
13592 caps = gst_caps_new_simple ("video/x-svq",
13593 "svqversion", G_TYPE_INT, 3, NULL);
13595 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13596 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13597 _codec ("Sorensen video v.1");
13598 caps = gst_caps_new_simple ("video/x-svq",
13599 "svqversion", G_TYPE_INT, 1, NULL);
13601 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13602 caps = gst_caps_new_empty_simple ("video/x-raw");
13603 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13604 _codec ("Windows Raw RGB");
13605 stream->alignment = 32;
13611 bps = QT_UINT16 (stsd_entry_data + 82);
13614 format = GST_VIDEO_FORMAT_RGB15;
13617 format = GST_VIDEO_FORMAT_RGB16;
13620 format = GST_VIDEO_FORMAT_RGB;
13623 format = GST_VIDEO_FORMAT_ARGB;
13631 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13632 format = GST_VIDEO_FORMAT_I420;
13634 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13635 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13636 format = GST_VIDEO_FORMAT_I420;
13639 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13640 format = GST_VIDEO_FORMAT_UYVY;
13642 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13643 format = GST_VIDEO_FORMAT_v308;
13645 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13646 format = GST_VIDEO_FORMAT_v216;
13649 format = GST_VIDEO_FORMAT_v210;
13651 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13652 format = GST_VIDEO_FORMAT_r210;
13654 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13655 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13656 format = GST_VIDEO_FORMAT_v410;
13659 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13660 * but different order than AYUV
13661 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13662 format = GST_VIDEO_FORMAT_v408;
13665 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13666 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13667 _codec ("MPEG-1 video");
13668 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13669 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13671 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13672 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13673 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13674 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13675 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13676 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13677 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13678 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13679 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13680 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13681 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13682 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13683 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13684 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13685 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13686 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13687 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13688 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13689 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13690 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13691 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13692 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13693 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13694 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13695 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13696 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13697 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13698 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13699 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13700 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13701 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13702 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13703 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13704 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13705 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13706 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13707 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13708 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13709 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13710 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13711 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13712 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13713 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13714 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13715 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13716 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13717 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13718 _codec ("MPEG-2 video");
13719 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13720 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13722 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13723 _codec ("GIF still images");
13724 caps = gst_caps_new_empty_simple ("image/gif");
13727 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13729 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13731 /* ffmpeg uses the height/width props, don't know why */
13732 caps = gst_caps_new_simple ("video/x-h263",
13733 "variant", G_TYPE_STRING, "itu", NULL);
13737 _codec ("MPEG-4 video");
13738 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13739 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13741 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13742 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13743 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13744 caps = gst_caps_new_simple ("video/x-msmpeg",
13745 "msmpegversion", G_TYPE_INT, 43, NULL);
13747 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13749 caps = gst_caps_new_simple ("video/x-divx",
13750 "divxversion", G_TYPE_INT, 3, NULL);
13752 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13753 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13755 caps = gst_caps_new_simple ("video/x-divx",
13756 "divxversion", G_TYPE_INT, 4, NULL);
13758 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13760 caps = gst_caps_new_simple ("video/x-divx",
13761 "divxversion", G_TYPE_INT, 5, NULL);
13764 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13766 caps = gst_caps_new_simple ("video/x-ffv",
13767 "ffvversion", G_TYPE_INT, 1, NULL);
13770 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13771 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13776 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13777 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13778 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13782 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13783 _codec ("Cinepak");
13784 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13786 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13787 _codec ("Apple QuickDraw");
13788 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13790 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13791 _codec ("Apple video");
13792 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13796 _codec ("H.264 / AVC");
13797 caps = gst_caps_new_simple ("video/x-h264",
13798 "stream-format", G_TYPE_STRING, "avc",
13799 "alignment", G_TYPE_STRING, "au", NULL);
13802 _codec ("H.264 / AVC");
13803 caps = gst_caps_new_simple ("video/x-h264",
13804 "stream-format", G_TYPE_STRING, "avc3",
13805 "alignment", G_TYPE_STRING, "au", NULL);
13809 _codec ("H.265 / HEVC");
13810 caps = gst_caps_new_simple ("video/x-h265",
13811 "stream-format", G_TYPE_STRING, "hvc1",
13812 "alignment", G_TYPE_STRING, "au", NULL);
13815 _codec ("H.265 / HEVC");
13816 caps = gst_caps_new_simple ("video/x-h265",
13817 "stream-format", G_TYPE_STRING, "hev1",
13818 "alignment", G_TYPE_STRING, "au", NULL);
13821 _codec ("Run-length encoding");
13822 caps = gst_caps_new_simple ("video/x-rle",
13823 "layout", G_TYPE_STRING, "quicktime", NULL);
13826 _codec ("Run-length encoding");
13827 caps = gst_caps_new_simple ("video/x-rle",
13828 "layout", G_TYPE_STRING, "microsoft", NULL);
13830 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13831 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13832 _codec ("Indeo Video 3");
13833 caps = gst_caps_new_simple ("video/x-indeo",
13834 "indeoversion", G_TYPE_INT, 3, NULL);
13836 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13837 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13838 _codec ("Intel Video 4");
13839 caps = gst_caps_new_simple ("video/x-indeo",
13840 "indeoversion", G_TYPE_INT, 4, NULL);
13844 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13845 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13846 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13847 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13848 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13849 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13850 _codec ("DV Video");
13851 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13852 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13854 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13855 case FOURCC_dv5p: /* DVCPRO50 PAL */
13856 _codec ("DVCPro50 Video");
13857 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13858 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13860 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13861 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13862 _codec ("DVCProHD Video");
13863 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13864 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13866 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13867 _codec ("Apple Graphics (SMC)");
13868 caps = gst_caps_new_empty_simple ("video/x-smc");
13870 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13872 caps = gst_caps_new_empty_simple ("video/x-vp3");
13874 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13875 _codec ("VP6 Flash");
13876 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13880 caps = gst_caps_new_empty_simple ("video/x-theora");
13881 /* theora uses one byte of padding in the data stream because it does not
13882 * allow 0 sized packets while theora does */
13883 entry->padding = 1;
13887 caps = gst_caps_new_empty_simple ("video/x-dirac");
13889 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13890 _codec ("TIFF still images");
13891 caps = gst_caps_new_empty_simple ("image/tiff");
13893 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13894 _codec ("Apple Intermediate Codec");
13895 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13897 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13898 _codec ("AVID DNxHD");
13899 caps = gst_caps_from_string ("video/x-dnxhd");
13902 _codec ("On2 VP8");
13903 caps = gst_caps_from_string ("video/x-vp8");
13906 _codec ("Apple ProRes LT");
13908 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13912 _codec ("Apple ProRes HQ");
13914 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13918 _codec ("Apple ProRes");
13920 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13924 _codec ("Apple ProRes Proxy");
13926 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13930 _codec ("Apple ProRes 4444");
13932 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13936 _codec ("Apple ProRes 4444 XQ");
13938 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13942 _codec ("GoPro CineForm");
13943 caps = gst_caps_from_string ("video/x-cineform");
13948 caps = gst_caps_new_simple ("video/x-wmv",
13949 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13951 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13954 caps = _get_unknown_codec_name ("video", fourcc);
13959 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13962 gst_video_info_init (&info);
13963 gst_video_info_set_format (&info, format, entry->width, entry->height);
13965 caps = gst_video_info_to_caps (&info);
13966 *codec_name = gst_pb_utils_get_codec_description (caps);
13968 /* enable clipping for raw video streams */
13969 stream->need_clip = TRUE;
13970 stream->alignment = 32;
13977 round_up_pow2 (guint n)
13989 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13990 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
13991 int len, gchar ** codec_name)
13994 const GstStructure *s;
13997 GstAudioFormat format = 0;
14000 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14002 depth = entry->bytes_per_packet * 8;
14005 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14007 /* 8-bit audio is unsigned */
14009 format = GST_AUDIO_FORMAT_U8;
14010 /* otherwise it's signed and big-endian just like 'twos' */
14012 endian = G_BIG_ENDIAN;
14019 endian = G_LITTLE_ENDIAN;
14022 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14024 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14028 caps = gst_caps_new_simple ("audio/x-raw",
14029 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14030 "layout", G_TYPE_STRING, "interleaved", NULL);
14031 stream->alignment = GST_ROUND_UP_8 (depth);
14032 stream->alignment = round_up_pow2 (stream->alignment);
14035 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14036 _codec ("Raw 64-bit floating-point audio");
14037 caps = gst_caps_new_simple ("audio/x-raw",
14038 "format", G_TYPE_STRING, "F64BE",
14039 "layout", G_TYPE_STRING, "interleaved", NULL);
14040 stream->alignment = 8;
14042 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14043 _codec ("Raw 32-bit floating-point audio");
14044 caps = gst_caps_new_simple ("audio/x-raw",
14045 "format", G_TYPE_STRING, "F32BE",
14046 "layout", G_TYPE_STRING, "interleaved", NULL);
14047 stream->alignment = 4;
14050 _codec ("Raw 24-bit PCM audio");
14051 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14053 caps = gst_caps_new_simple ("audio/x-raw",
14054 "format", G_TYPE_STRING, "S24BE",
14055 "layout", G_TYPE_STRING, "interleaved", NULL);
14056 stream->alignment = 4;
14058 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14059 _codec ("Raw 32-bit PCM audio");
14060 caps = gst_caps_new_simple ("audio/x-raw",
14061 "format", G_TYPE_STRING, "S32BE",
14062 "layout", G_TYPE_STRING, "interleaved", NULL);
14063 stream->alignment = 4;
14065 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14066 _codec ("Raw 16-bit PCM audio");
14067 caps = gst_caps_new_simple ("audio/x-raw",
14068 "format", G_TYPE_STRING, "S16LE",
14069 "layout", G_TYPE_STRING, "interleaved", NULL);
14070 stream->alignment = 2;
14073 _codec ("Mu-law audio");
14074 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14077 _codec ("A-law audio");
14078 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14082 _codec ("Microsoft ADPCM");
14083 /* Microsoft ADPCM-ACM code 2 */
14084 caps = gst_caps_new_simple ("audio/x-adpcm",
14085 "layout", G_TYPE_STRING, "microsoft", NULL);
14089 _codec ("DVI/IMA ADPCM");
14090 caps = gst_caps_new_simple ("audio/x-adpcm",
14091 "layout", G_TYPE_STRING, "dvi", NULL);
14095 _codec ("DVI/Intel IMA ADPCM");
14096 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14097 caps = gst_caps_new_simple ("audio/x-adpcm",
14098 "layout", G_TYPE_STRING, "quicktime", NULL);
14102 /* MPEG layer 3, CBR only (pre QT4.1) */
14104 _codec ("MPEG-1 layer 3");
14105 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14106 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14107 "mpegversion", G_TYPE_INT, 1, NULL);
14109 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14110 _codec ("MPEG-1 layer 2");
14112 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14113 "mpegversion", G_TYPE_INT, 1, NULL);
14116 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14117 _codec ("EAC-3 audio");
14118 caps = gst_caps_new_simple ("audio/x-eac3",
14119 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14120 entry->sampled = TRUE;
14122 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14124 _codec ("AC-3 audio");
14125 caps = gst_caps_new_simple ("audio/x-ac3",
14126 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14127 entry->sampled = TRUE;
14129 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14130 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14131 _codec ("DTS audio");
14132 caps = gst_caps_new_simple ("audio/x-dts",
14133 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14134 entry->sampled = TRUE;
14136 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14137 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14138 _codec ("DTS-HD audio");
14139 caps = gst_caps_new_simple ("audio/x-dts",
14140 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14141 entry->sampled = TRUE;
14145 caps = gst_caps_new_simple ("audio/x-mace",
14146 "maceversion", G_TYPE_INT, 3, NULL);
14150 caps = gst_caps_new_simple ("audio/x-mace",
14151 "maceversion", G_TYPE_INT, 6, NULL);
14153 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14155 caps = gst_caps_new_empty_simple ("application/ogg");
14157 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14158 _codec ("DV audio");
14159 caps = gst_caps_new_empty_simple ("audio/x-dv");
14162 _codec ("MPEG-4 AAC audio");
14163 caps = gst_caps_new_simple ("audio/mpeg",
14164 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14165 "stream-format", G_TYPE_STRING, "raw", NULL);
14167 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14168 _codec ("QDesign Music");
14169 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14172 _codec ("QDesign Music v.2");
14173 /* FIXME: QDesign music version 2 (no constant) */
14174 if (FALSE && data) {
14175 caps = gst_caps_new_simple ("audio/x-qdm2",
14176 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14177 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14178 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14180 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14184 _codec ("GSM audio");
14185 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14188 _codec ("AMR audio");
14189 caps = gst_caps_new_empty_simple ("audio/AMR");
14192 _codec ("AMR-WB audio");
14193 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14196 _codec ("Quicktime IMA ADPCM");
14197 caps = gst_caps_new_simple ("audio/x-adpcm",
14198 "layout", G_TYPE_STRING, "quicktime", NULL);
14201 _codec ("Apple lossless audio");
14202 caps = gst_caps_new_empty_simple ("audio/x-alac");
14205 _codec ("Free Lossless Audio Codec");
14206 caps = gst_caps_new_simple ("audio/x-flac",
14207 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14209 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14210 _codec ("QualComm PureVoice");
14211 caps = gst_caps_from_string ("audio/qcelp");
14216 caps = gst_caps_new_empty_simple ("audio/x-wma");
14220 caps = gst_caps_new_empty_simple ("audio/x-opus");
14222 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
14227 GstAudioFormat format;
14230 FLAG_IS_FLOAT = 0x1,
14231 FLAG_IS_BIG_ENDIAN = 0x2,
14232 FLAG_IS_SIGNED = 0x4,
14233 FLAG_IS_PACKED = 0x8,
14234 FLAG_IS_ALIGNED_HIGH = 0x10,
14235 FLAG_IS_NON_INTERLEAVED = 0x20
14237 _codec ("Raw LPCM audio");
14239 if (data && len >= 56) {
14240 depth = QT_UINT32 (data + 40);
14241 flags = QT_UINT32 (data + 44);
14242 width = QT_UINT32 (data + 48) * 8 / entry->n_channels;
14244 if ((flags & FLAG_IS_FLOAT) == 0) {
14249 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14250 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14251 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14252 caps = gst_caps_new_simple ("audio/x-raw",
14253 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14254 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14255 "non-interleaved" : "interleaved", NULL);
14256 stream->alignment = GST_ROUND_UP_8 (depth);
14257 stream->alignment = round_up_pow2 (stream->alignment);
14262 if (flags & FLAG_IS_BIG_ENDIAN)
14263 format = GST_AUDIO_FORMAT_F64BE;
14265 format = GST_AUDIO_FORMAT_F64LE;
14267 if (flags & FLAG_IS_BIG_ENDIAN)
14268 format = GST_AUDIO_FORMAT_F32BE;
14270 format = GST_AUDIO_FORMAT_F32LE;
14272 caps = gst_caps_new_simple ("audio/x-raw",
14273 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14274 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14275 "non-interleaved" : "interleaved", NULL);
14276 stream->alignment = width / 8;
14280 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14284 caps = _get_unknown_codec_name ("audio", fourcc);
14290 GstCaps *templ_caps =
14291 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14292 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14293 gst_caps_unref (caps);
14294 gst_caps_unref (templ_caps);
14295 caps = intersection;
14298 /* enable clipping for raw audio streams */
14299 s = gst_caps_get_structure (caps, 0);
14300 name = gst_structure_get_name (s);
14301 if (g_str_has_prefix (name, "audio/x-raw")) {
14302 stream->need_clip = TRUE;
14303 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14304 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14310 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14311 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14312 const guint8 * stsd_entry_data, gchar ** codec_name)
14316 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14320 _codec ("DVD subtitle");
14321 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14322 stream->need_process = TRUE;
14325 _codec ("Quicktime timed text");
14328 _codec ("3GPP timed text");
14330 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14332 /* actual text piece needs to be extracted */
14333 stream->need_process = TRUE;
14336 _codec ("XML subtitles");
14337 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14341 caps = _get_unknown_codec_name ("text", fourcc);
14349 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14350 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14351 const guint8 * stsd_entry_data, gchar ** codec_name)
14357 _codec ("MPEG 1 video");
14358 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14359 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14369 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14370 const gchar * system_id)
14374 if (!qtdemux->protection_system_ids)
14375 qtdemux->protection_system_ids =
14376 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14377 /* Check whether we already have an entry for this system ID. */
14378 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14379 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14380 if (g_ascii_strcasecmp (system_id, id) == 0) {
14384 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14385 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,