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 (200*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);
104 #define GST_CAT_DEFAULT qtdemux_debug
106 typedef struct _QtDemuxSegment QtDemuxSegment;
107 typedef struct _QtDemuxSample QtDemuxSample;
109 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
111 struct _QtDemuxSample
114 gint32 pts_offset; /* Add this value to timestamp to get the pts */
116 guint64 timestamp; /* DTS In mov time */
117 guint32 duration; /* In mov time */
118 gboolean keyframe; /* TRUE when this packet is a keyframe */
121 /* Macros for converting to/from timescale */
122 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
123 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
125 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
126 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
128 /* timestamp is the DTS */
129 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
130 /* timestamp + offset + cslg_shift is the outgoing PTS */
131 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
132 /* timestamp + offset is the PTS used for internal seek calcuations */
133 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
134 /* timestamp + duration - dts is the duration */
135 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
137 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
140 * Quicktime has tracks and segments. A track is a continuous piece of
141 * multimedia content. The track is not always played from start to finish but
142 * instead, pieces of the track are 'cut out' and played in sequence. This is
143 * what the segments do.
145 * Inside the track we have keyframes (K) and delta frames. The track has its
146 * own timing, which starts from 0 and extends to end. The position in the track
147 * is called the media_time.
149 * The segments now describe the pieces that should be played from this track
150 * and are basically tuples of media_time/duration/rate entries. We can have
151 * multiple segments and they are all played after one another. An example:
153 * segment 1: media_time: 1 second, duration: 1 second, rate 1
154 * segment 2: media_time: 3 second, duration: 2 second, rate 2
156 * To correctly play back this track, one must play: 1 second of media starting
157 * from media_time 1 followed by 2 seconds of media starting from media_time 3
160 * Each of the segments will be played at a specific time, the first segment at
161 * time 0, the second one after the duration of the first one, etc.. Note that
162 * the time in resulting playback is not identical to the media_time of the
165 * Visually, assuming the track has 4 second of media_time:
168 * .-----------------------------------------------------------.
169 * track: | K.....K.........K........K.......K.......K...........K... |
170 * '-----------------------------------------------------------'
172 * .------------^ ^ .----------^ ^
173 * / .-------------' / .------------------'
175 * .--------------. .--------------.
176 * | segment 1 | | segment 2 |
177 * '--------------' '--------------'
179 * The challenge here is to cut out the right pieces of the track for each of
180 * the playback segments. This fortunately can easily be done with the SEGMENT
181 * events of GStreamer.
183 * For playback of segment 1, we need to provide the decoder with the keyframe
184 * (a), in the above figure, but we must instruct it only to output the decoded
185 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
186 * position set to the time of the segment: 0.
188 * We then proceed to push data from keyframe (a) to frame (b). The decoder
189 * decodes but clips all before media_time 1.
191 * After finishing a segment, we push out a new SEGMENT event with the clipping
192 * boundaries of the new data.
194 * This is a good usecase for the GStreamer accumulated SEGMENT events.
197 struct _QtDemuxSegment
199 /* global time and duration, all gst time */
201 GstClockTime stop_time;
202 GstClockTime duration;
203 /* media time of trak, all gst time */
204 GstClockTime media_start;
205 GstClockTime media_stop;
207 /* Media start time in trak timescale units */
208 guint32 trak_media_start;
211 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
213 /* Used with fragmented MP4 files (mfra atom) */
218 } QtDemuxRandomAccessEntry;
220 typedef struct _QtDemuxStreamStsdEntry
231 /* Numerator/denominator framerate */
234 GstVideoColorimetry colorimetry;
235 guint16 bits_per_sample;
236 guint16 color_table_id;
237 GstMemory *rgb8_palette;
238 guint interlace_mode;
244 guint samples_per_packet;
245 guint samples_per_frame;
246 guint bytes_per_packet;
247 guint bytes_per_sample;
248 guint bytes_per_frame;
251 /* if we use chunks or samples */
255 } QtDemuxStreamStsdEntry;
257 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
259 struct _QtDemuxStream
263 QtDemuxStreamStsdEntry *stsd_entries;
264 guint stsd_entries_length;
265 guint cur_stsd_entry_index;
270 gboolean new_caps; /* If TRUE, caps need to be generated (by
271 * calling _configure_stream()) This happens
272 * for MSS and fragmented streams */
274 gboolean new_stream; /* signals that a stream_start is required */
275 gboolean on_keyframe; /* if this stream last pushed buffer was a
276 * keyframe. This is important to identify
277 * where to stop pushing buffers after a
278 * segment stop time */
280 /* if the stream has a redirect URI in its headers, we store it here */
287 guint64 duration; /* in timescale units */
291 gchar lang_id[4]; /* ISO 639-2T language code */
295 QtDemuxSample *samples;
296 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
297 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
299 guint32 n_samples_moof; /* sample count in a moof */
300 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
301 * the framerate of fragmented format stream */
302 guint64 duration_last_moof;
304 guint32 offset_in_sample; /* Offset in the current sample, used for
305 * streams which have got exceedingly big
306 * sample size (such as 24s of raw audio).
307 * Only used when max_buffer_size is non-NULL */
308 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
309 * Currently only set for raw audio streams*/
317 gboolean use_allocator;
318 GstAllocator *allocator;
319 GstAllocationParams params;
323 /* when a discontinuity is pending */
326 /* list of buffers to push first */
329 /* if we need to clip this buffer. This is only needed for uncompressed
333 /* buffer needs some custom processing, e.g. subtitles */
334 gboolean need_process;
336 /* current position */
337 guint32 segment_index;
338 guint32 sample_index;
339 GstClockTime time_position; /* in gst time */
340 guint64 accumulated_base;
342 /* the Gst segment we are processing out, used for clipping */
345 /* quicktime segments */
347 QtDemuxSegment *segments;
348 gboolean dummy_segment;
353 GstTagList *stream_tags;
354 gboolean send_global_tags;
356 GstEvent *pending_event;
366 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
370 GstByteReader co_chunk;
372 guint32 current_chunk;
374 guint32 samples_per_chunk;
375 guint32 stsd_sample_description_id;
376 guint32 stco_sample_index;
378 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
381 guint32 n_samples_per_chunk;
382 guint32 stsc_chunk_index;
383 guint32 stsc_sample_index;
384 guint64 chunk_offset;
387 guint32 stts_samples;
388 guint32 n_sample_times;
389 guint32 stts_sample_index;
391 guint32 stts_duration;
393 gboolean stss_present;
394 guint32 n_sample_syncs;
397 gboolean stps_present;
398 guint32 n_sample_partial_syncs;
400 QtDemuxRandomAccessEntry *ra_entries;
403 const QtDemuxRandomAccessEntry *pending_seek;
406 gboolean ctts_present;
407 guint32 n_composition_times;
409 guint32 ctts_sample_index;
417 gboolean parsed_trex;
418 guint32 def_sample_description_index; /* index is 1-based */
419 guint32 def_sample_duration;
420 guint32 def_sample_size;
421 guint32 def_sample_flags;
425 /* stereoscopic video streams */
426 GstVideoMultiviewMode multiview_mode;
427 GstVideoMultiviewFlags multiview_flags;
429 /* protected streams */
431 guint32 protection_scheme_type;
432 guint32 protection_scheme_version;
433 gpointer protection_scheme_info; /* specific to the protection scheme */
434 GQueue protection_scheme_event_queue;
437 /* Contains properties and cryptographic info for a set of samples from a
438 * track protected using Common Encryption (cenc) */
439 struct _QtDemuxCencSampleSetInfo
441 GstStructure *default_properties;
443 /* @crypto_info holds one GstStructure per sample */
444 GPtrArray *crypto_info;
448 qt_demux_state_string (enum QtDemuxState state)
451 case QTDEMUX_STATE_INITIAL:
453 case QTDEMUX_STATE_HEADER:
455 case QTDEMUX_STATE_MOVIE:
457 case QTDEMUX_STATE_BUFFER_MDAT:
458 return "<BUFFER_MDAT>";
464 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
465 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
466 guint32 fourcc, GstByteReader * parser);
467 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
468 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
469 guint32 fourcc, GstByteReader * parser);
471 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
473 static GstStaticPadTemplate gst_qtdemux_sink_template =
474 GST_STATIC_PAD_TEMPLATE ("sink",
477 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
481 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
482 GST_STATIC_PAD_TEMPLATE ("video_%u",
485 GST_STATIC_CAPS_ANY);
487 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
488 GST_STATIC_PAD_TEMPLATE ("audio_%u",
491 GST_STATIC_CAPS_ANY);
493 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
494 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
497 GST_STATIC_CAPS_ANY);
499 #define gst_qtdemux_parent_class parent_class
500 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
502 static void gst_qtdemux_dispose (GObject * object);
505 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
506 GstClockTime media_time);
508 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
509 QtDemuxStream * str, gint64 media_offset);
512 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
513 static GstIndex *gst_qtdemux_get_index (GstElement * element);
515 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
516 GstStateChange transition);
517 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
518 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
519 GstObject * parent, GstPadMode mode, gboolean active);
521 static void gst_qtdemux_loop (GstPad * pad);
522 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
524 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
526 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
527 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
528 QtDemuxStream * stream);
529 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
530 QtDemuxStream * stream);
531 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
534 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
535 const guint8 * buffer, guint length);
536 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
537 const guint8 * buffer, guint length);
538 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
539 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
542 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
543 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
545 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
546 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
547 const guint8 * stsd_entry_data, gchar ** codec_name);
548 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
549 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
550 const guint8 * data, int len, gchar ** codec_name);
551 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
552 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
553 gchar ** codec_name);
554 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
555 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
556 const guint8 * stsd_entry_data, gchar ** codec_name);
558 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
559 QtDemuxStream * stream, guint32 n);
560 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
561 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
562 QtDemuxStream * stream);
563 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
564 QtDemuxStream * stream);
565 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
566 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
567 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
568 QtDemuxStream * stream);
569 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
570 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
571 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
572 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
573 GstClockTime * _start, GstClockTime * _stop);
574 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
575 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
577 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
578 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
580 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
582 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
583 QtDemuxStream * stream, guint sample_index);
584 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
586 static void qtdemux_gst_structure_free (GstStructure * gststructure);
589 gst_qtdemux_class_init (GstQTDemuxClass * klass)
591 GObjectClass *gobject_class;
592 GstElementClass *gstelement_class;
594 gobject_class = (GObjectClass *) klass;
595 gstelement_class = (GstElementClass *) klass;
597 parent_class = g_type_class_peek_parent (klass);
599 gobject_class->dispose = gst_qtdemux_dispose;
601 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
603 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
604 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
607 gst_tag_register_musicbrainz_tags ();
609 gst_element_class_add_static_pad_template (gstelement_class,
610 &gst_qtdemux_sink_template);
611 gst_element_class_add_static_pad_template (gstelement_class,
612 &gst_qtdemux_videosrc_template);
613 gst_element_class_add_static_pad_template (gstelement_class,
614 &gst_qtdemux_audiosrc_template);
615 gst_element_class_add_static_pad_template (gstelement_class,
616 &gst_qtdemux_subsrc_template);
617 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
619 "Demultiplex a QuickTime file into audio and video streams",
620 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
622 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
627 gst_qtdemux_init (GstQTDemux * qtdemux)
630 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
631 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
632 gst_pad_set_activatemode_function (qtdemux->sinkpad,
633 qtdemux_sink_activate_mode);
634 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
635 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
636 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
638 qtdemux->state = QTDEMUX_STATE_INITIAL;
639 qtdemux->pullbased = FALSE;
640 qtdemux->posted_redirect = FALSE;
641 qtdemux->neededbytes = 16;
643 qtdemux->adapter = gst_adapter_new ();
645 qtdemux->first_mdat = -1;
646 qtdemux->got_moov = FALSE;
647 qtdemux->mdatoffset = -1;
648 qtdemux->mdatbuffer = NULL;
649 qtdemux->restoredata_buffer = NULL;
650 qtdemux->restoredata_offset = -1;
651 qtdemux->fragment_start = -1;
652 qtdemux->fragment_start_offset = -1;
653 qtdemux->media_caps = NULL;
654 qtdemux->exposed = FALSE;
655 qtdemux->mss_mode = FALSE;
656 qtdemux->pending_newsegment = NULL;
657 qtdemux->upstream_format_is_time = FALSE;
658 qtdemux->have_group_id = FALSE;
659 qtdemux->group_id = G_MAXUINT;
660 qtdemux->cenc_aux_info_offset = 0;
661 qtdemux->cenc_aux_info_sizes = NULL;
662 qtdemux->cenc_aux_sample_count = 0;
663 qtdemux->protection_system_ids = NULL;
664 g_queue_init (&qtdemux->protection_event_queue);
665 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
666 qtdemux->tag_list = gst_tag_list_new_empty ();
667 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
668 qtdemux->flowcombiner = gst_flow_combiner_new ();
670 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
674 gst_qtdemux_dispose (GObject * object)
676 GstQTDemux *qtdemux = GST_QTDEMUX (object);
678 if (qtdemux->adapter) {
679 g_object_unref (G_OBJECT (qtdemux->adapter));
680 qtdemux->adapter = NULL;
682 gst_tag_list_unref (qtdemux->tag_list);
683 gst_flow_combiner_free (qtdemux->flowcombiner);
684 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
686 g_queue_clear (&qtdemux->protection_event_queue);
688 g_free (qtdemux->cenc_aux_info_sizes);
689 qtdemux->cenc_aux_info_sizes = NULL;
691 G_OBJECT_CLASS (parent_class)->dispose (object);
695 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
697 if (qtdemux->posted_redirect) {
698 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
699 (_("This file contains no playable streams.")),
700 ("no known streams found, a redirect message has been posted"));
702 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
703 (_("This file contains no playable streams.")),
704 ("no known streams found"));
709 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
711 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
712 mem, size, 0, size, mem, free_func);
716 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
723 if (G_UNLIKELY (size == 0)) {
725 GstBuffer *tmp = NULL;
727 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
728 if (ret != GST_FLOW_OK)
731 gst_buffer_map (tmp, &map, GST_MAP_READ);
732 size = QT_UINT32 (map.data);
733 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
735 gst_buffer_unmap (tmp, &map);
736 gst_buffer_unref (tmp);
739 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
740 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
741 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
742 /* we're pulling header but already got most interesting bits,
743 * so never mind the rest (e.g. tags) (that much) */
744 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
748 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
749 (_("This file is invalid and cannot be played.")),
750 ("atom has bogus size %" G_GUINT64_FORMAT, size));
751 return GST_FLOW_ERROR;
755 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
757 if (G_UNLIKELY (flow != GST_FLOW_OK))
760 bsize = gst_buffer_get_size (*buf);
761 /* Catch short reads - we don't want any partial atoms */
762 if (G_UNLIKELY (bsize < size)) {
763 GST_WARNING_OBJECT (qtdemux,
764 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
765 gst_buffer_unref (*buf);
775 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
776 GstFormat src_format, gint64 src_value, GstFormat dest_format,
780 QtDemuxStream *stream = gst_pad_get_element_private (pad);
783 if (stream->subtype != FOURCC_vide) {
788 switch (src_format) {
789 case GST_FORMAT_TIME:
790 switch (dest_format) {
791 case GST_FORMAT_BYTES:{
792 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
798 *dest_value = stream->samples[index].offset;
800 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
801 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
802 GST_TIME_ARGS (src_value), *dest_value);
810 case GST_FORMAT_BYTES:
811 switch (dest_format) {
812 case GST_FORMAT_TIME:{
814 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
823 QTSTREAMTIME_TO_GSTTIME (stream,
824 stream->samples[index].timestamp);
825 GST_DEBUG_OBJECT (qtdemux,
826 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
827 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
846 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
848 gboolean res = FALSE;
850 *duration = GST_CLOCK_TIME_NONE;
852 if (qtdemux->duration != 0 &&
853 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
854 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
857 *duration = GST_CLOCK_TIME_NONE;
864 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
867 gboolean res = FALSE;
868 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
870 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
872 switch (GST_QUERY_TYPE (query)) {
873 case GST_QUERY_POSITION:{
876 gst_query_parse_position (query, &fmt, NULL);
877 if (fmt == GST_FORMAT_TIME
878 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
879 gst_query_set_position (query, GST_FORMAT_TIME,
880 qtdemux->segment.position);
885 case GST_QUERY_DURATION:{
888 gst_query_parse_duration (query, &fmt, NULL);
889 if (fmt == GST_FORMAT_TIME) {
890 /* First try to query upstream */
891 res = gst_pad_query_default (pad, parent, query);
893 GstClockTime duration;
894 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
895 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
902 case GST_QUERY_CONVERT:{
903 GstFormat src_fmt, dest_fmt;
904 gint64 src_value, dest_value = 0;
906 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
908 res = gst_qtdemux_src_convert (qtdemux, pad,
909 src_fmt, src_value, dest_fmt, &dest_value);
911 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;
1629 guint32 seqnum = GST_SEQNUM_INVALID;
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 ();
1657 if (seqnum != GST_SEQNUM_INVALID)
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);
1694 if (seqnum != GST_SEQNUM_INVALID)
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);
1707 if (seqnum != GST_SEQNUM_INVALID)
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 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1829 * If @fw is false, the coding order is explored backwards.
1831 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1832 * sample is found for that track.
1834 * The stream and sample index of the sample with the minimum offset in the direction explored
1835 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1837 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1838 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1839 * @_stream and @_index. */
1841 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1842 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1845 gint64 time, min_time;
1846 QtDemuxStream *stream;
1852 for (n = 0; n < qtdemux->n_streams; ++n) {
1855 gboolean set_sample;
1857 str = qtdemux->streams[n];
1864 i = str->n_samples - 1;
1868 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1869 if (str->samples[i].size == 0)
1872 if (fw && (str->samples[i].offset < byte_pos))
1875 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1878 /* move stream to first available sample */
1880 gst_qtdemux_move_stream (qtdemux, str, i);
1884 /* avoid index from sparse streams since they might be far away */
1885 if (!CUR_STREAM (str)->sparse) {
1886 /* determine min/max time */
1887 time = QTSAMPLE_PTS (str, &str->samples[i]);
1888 if (min_time == -1 || (!fw && time > min_time) ||
1889 (fw && time < min_time)) {
1893 /* determine stream with leading sample, to get its position */
1895 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1896 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1904 /* no sample for this stream, mark eos */
1906 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1917 static QtDemuxStream *
1918 _create_stream (void)
1920 QtDemuxStream *stream;
1922 stream = g_new0 (QtDemuxStream, 1);
1923 /* new streams always need a discont */
1924 stream->discont = TRUE;
1925 /* we enable clipping for raw audio/video streams */
1926 stream->need_clip = FALSE;
1927 stream->need_process = FALSE;
1928 stream->segment_index = -1;
1929 stream->time_position = 0;
1930 stream->sample_index = -1;
1931 stream->offset_in_sample = 0;
1932 stream->new_stream = TRUE;
1933 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1934 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1935 stream->protected = FALSE;
1936 stream->protection_scheme_type = 0;
1937 stream->protection_scheme_version = 0;
1938 stream->protection_scheme_info = NULL;
1939 stream->n_samples_moof = 0;
1940 stream->duration_moof = 0;
1941 stream->duration_last_moof = 0;
1942 stream->alignment = 1;
1943 stream->stream_tags = gst_tag_list_new_empty ();
1944 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1945 g_queue_init (&stream->protection_scheme_event_queue);
1950 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1952 GstStructure *structure;
1953 const gchar *variant;
1954 const GstCaps *mediacaps = NULL;
1956 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1958 structure = gst_caps_get_structure (caps, 0);
1959 variant = gst_structure_get_string (structure, "variant");
1961 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1962 QtDemuxStream *stream;
1963 const GValue *value;
1965 demux->fragmented = TRUE;
1966 demux->mss_mode = TRUE;
1968 if (demux->n_streams > 1) {
1969 /* can't do this, we can only renegotiate for another mss format */
1973 value = gst_structure_get_value (structure, "media-caps");
1976 const GValue *timescale_v;
1978 /* TODO update when stream changes during playback */
1980 if (demux->n_streams == 0) {
1981 stream = _create_stream ();
1982 demux->streams[demux->n_streams] = stream;
1983 demux->n_streams = 1;
1984 /* mss has no stsd/stsd entry, use id 0 as default */
1985 stream->stsd_entries_length = 1;
1986 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1987 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1989 stream = demux->streams[0];
1992 timescale_v = gst_structure_get_value (structure, "timescale");
1994 stream->timescale = g_value_get_uint64 (timescale_v);
1996 /* default mss timescale */
1997 stream->timescale = 10000000;
1999 demux->timescale = stream->timescale;
2001 mediacaps = gst_value_get_caps (value);
2002 if (!CUR_STREAM (stream)->caps
2003 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2004 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2006 stream->new_caps = TRUE;
2008 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2009 structure = gst_caps_get_structure (mediacaps, 0);
2010 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2011 stream->subtype = FOURCC_vide;
2013 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2014 gst_structure_get_int (structure, "height",
2015 &CUR_STREAM (stream)->height);
2016 gst_structure_get_fraction (structure, "framerate",
2017 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2018 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2020 stream->subtype = FOURCC_soun;
2021 gst_structure_get_int (structure, "channels",
2022 &CUR_STREAM (stream)->n_channels);
2023 gst_structure_get_int (structure, "rate", &rate);
2024 CUR_STREAM (stream)->rate = rate;
2027 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2029 demux->mss_mode = FALSE;
2036 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2040 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2041 gst_pad_stop_task (qtdemux->sinkpad);
2043 if (hard || qtdemux->upstream_format_is_time) {
2044 qtdemux->state = QTDEMUX_STATE_INITIAL;
2045 qtdemux->neededbytes = 16;
2046 qtdemux->todrop = 0;
2047 qtdemux->pullbased = FALSE;
2048 qtdemux->posted_redirect = FALSE;
2049 qtdemux->first_mdat = -1;
2050 qtdemux->header_size = 0;
2051 qtdemux->mdatoffset = -1;
2052 qtdemux->restoredata_offset = -1;
2053 if (qtdemux->mdatbuffer)
2054 gst_buffer_unref (qtdemux->mdatbuffer);
2055 if (qtdemux->restoredata_buffer)
2056 gst_buffer_unref (qtdemux->restoredata_buffer);
2057 qtdemux->mdatbuffer = NULL;
2058 qtdemux->restoredata_buffer = NULL;
2059 qtdemux->mdatleft = 0;
2060 qtdemux->mdatsize = 0;
2061 if (qtdemux->comp_brands)
2062 gst_buffer_unref (qtdemux->comp_brands);
2063 qtdemux->comp_brands = NULL;
2064 qtdemux->last_moov_offset = -1;
2065 if (qtdemux->moov_node_compressed) {
2066 g_node_destroy (qtdemux->moov_node_compressed);
2067 if (qtdemux->moov_node)
2068 g_free (qtdemux->moov_node->data);
2070 qtdemux->moov_node_compressed = NULL;
2071 if (qtdemux->moov_node)
2072 g_node_destroy (qtdemux->moov_node);
2073 qtdemux->moov_node = NULL;
2074 if (qtdemux->tag_list)
2075 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2076 qtdemux->tag_list = gst_tag_list_new_empty ();
2077 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2079 if (qtdemux->element_index)
2080 gst_object_unref (qtdemux->element_index);
2081 qtdemux->element_index = NULL;
2083 qtdemux->major_brand = 0;
2084 if (qtdemux->pending_newsegment)
2085 gst_event_unref (qtdemux->pending_newsegment);
2086 qtdemux->pending_newsegment = NULL;
2087 qtdemux->upstream_format_is_time = FALSE;
2088 qtdemux->upstream_seekable = FALSE;
2089 qtdemux->upstream_size = 0;
2091 qtdemux->fragment_start = -1;
2092 qtdemux->fragment_start_offset = -1;
2093 qtdemux->duration = 0;
2094 qtdemux->moof_offset = 0;
2095 qtdemux->chapters_track_id = 0;
2096 qtdemux->have_group_id = FALSE;
2097 qtdemux->group_id = G_MAXUINT;
2099 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2101 g_queue_clear (&qtdemux->protection_event_queue);
2103 qtdemux->offset = 0;
2104 gst_adapter_clear (qtdemux->adapter);
2105 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2106 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2109 for (n = 0; n < qtdemux->n_streams; n++) {
2110 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2111 qtdemux->streams[n] = NULL;
2113 qtdemux->n_streams = 0;
2114 qtdemux->n_video_streams = 0;
2115 qtdemux->n_audio_streams = 0;
2116 qtdemux->n_sub_streams = 0;
2117 qtdemux->exposed = FALSE;
2118 qtdemux->fragmented = FALSE;
2119 qtdemux->mss_mode = FALSE;
2120 gst_caps_replace (&qtdemux->media_caps, NULL);
2121 qtdemux->timescale = 0;
2122 qtdemux->got_moov = FALSE;
2123 if (qtdemux->protection_system_ids) {
2124 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2125 qtdemux->protection_system_ids = NULL;
2127 } else if (qtdemux->mss_mode) {
2128 gst_flow_combiner_reset (qtdemux->flowcombiner);
2129 for (n = 0; n < qtdemux->n_streams; n++)
2130 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2132 gst_flow_combiner_reset (qtdemux->flowcombiner);
2133 for (n = 0; n < qtdemux->n_streams; n++) {
2134 qtdemux->streams[n]->sent_eos = FALSE;
2135 qtdemux->streams[n]->time_position = 0;
2136 qtdemux->streams[n]->accumulated_base = 0;
2138 if (!qtdemux->pending_newsegment) {
2139 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2140 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
2141 gst_event_set_seqnum (qtdemux->pending_newsegment,
2142 qtdemux->segment_seqnum);
2148 /* Maps the @segment to the qt edts internal segments and pushes
2149 * the correspnding segment event.
2151 * If it ends up being at a empty segment, a gap will be pushed and the next
2152 * edts segment will be activated in sequence.
2154 * To be used in push-mode only */
2156 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2160 for (n = 0; n < qtdemux->n_streams; n++) {
2161 QtDemuxStream *stream = qtdemux->streams[n];
2163 stream->time_position = segment->start;
2165 /* in push mode we should be guaranteed that we will have empty segments
2166 * at the beginning and then one segment after, other scenarios are not
2167 * supported and are discarded when parsing the edts */
2168 for (i = 0; i < stream->n_segments; i++) {
2169 if (stream->segments[i].stop_time > segment->start) {
2170 gst_qtdemux_activate_segment (qtdemux, stream, i,
2171 stream->time_position);
2172 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2173 /* push the empty segment and move to the next one */
2174 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2175 stream->time_position);
2179 g_assert (i == stream->n_segments - 1);
2186 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2189 GstQTDemux *demux = GST_QTDEMUX (parent);
2190 gboolean res = TRUE;
2192 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2194 switch (GST_EVENT_TYPE (event)) {
2195 case GST_EVENT_SEGMENT:
2198 QtDemuxStream *stream;
2202 /* some debug output */
2203 gst_event_copy_segment (event, &segment);
2204 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2207 /* erase any previously set segment */
2208 gst_event_replace (&demux->pending_newsegment, NULL);
2210 if (segment.format == GST_FORMAT_TIME) {
2211 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2212 gst_event_replace (&demux->pending_newsegment, event);
2213 demux->upstream_format_is_time = TRUE;
2215 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2216 "not in time format");
2218 /* chain will send initial newsegment after pads have been added */
2219 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2220 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2225 /* check if this matches a time seek we received previously
2226 * FIXME for backwards compatibility reasons we use the
2227 * seek_offset here to compare. In the future we might want to
2228 * change this to use the seqnum as it uniquely should identify
2229 * the segment that corresponds to the seek. */
2230 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2231 ", received segment offset %" G_GINT64_FORMAT,
2232 demux->seek_offset, segment.start);
2233 if (segment.format == GST_FORMAT_BYTES
2234 && demux->seek_offset == segment.start) {
2235 GST_OBJECT_LOCK (demux);
2236 offset = segment.start;
2238 segment.format = GST_FORMAT_TIME;
2239 segment.start = demux->push_seek_start;
2240 segment.stop = demux->push_seek_stop;
2241 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2242 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2243 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2244 GST_OBJECT_UNLOCK (demux);
2247 /* we only expect a BYTE segment, e.g. following a seek */
2248 if (segment.format == GST_FORMAT_BYTES) {
2249 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2250 offset = segment.start;
2252 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2253 NULL, (gint64 *) & segment.start);
2254 if ((gint64) segment.start < 0)
2257 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2258 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2259 NULL, (gint64 *) & segment.stop);
2260 /* keyframe seeking should already arrange for start >= stop,
2261 * but make sure in other rare cases */
2262 segment.stop = MAX (segment.stop, segment.start);
2264 } else if (segment.format == GST_FORMAT_TIME) {
2265 /* push all data on the adapter before starting this
2267 gst_qtdemux_process_adapter (demux, TRUE);
2269 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2273 /* We shouldn't modify upstream driven TIME FORMAT segment */
2274 if (!demux->upstream_format_is_time) {
2275 /* accept upstream's notion of segment and distribute along */
2276 segment.format = GST_FORMAT_TIME;
2277 segment.position = segment.time = segment.start;
2278 segment.duration = demux->segment.duration;
2279 segment.base = gst_segment_to_running_time (&demux->segment,
2280 GST_FORMAT_TIME, demux->segment.position);
2283 gst_segment_copy_into (&segment, &demux->segment);
2284 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2286 /* map segment to internal qt segments and push on each stream */
2287 if (demux->n_streams) {
2288 if (demux->fragmented) {
2289 GstEvent *segment_event = gst_event_new_segment (&segment);
2291 gst_event_replace (&demux->pending_newsegment, NULL);
2292 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2293 gst_qtdemux_push_event (demux, segment_event);
2295 gst_event_replace (&demux->pending_newsegment, NULL);
2296 gst_qtdemux_map_and_push_segments (demux, &segment);
2300 /* clear leftover in current segment, if any */
2301 gst_adapter_clear (demux->adapter);
2303 /* set up streaming thread */
2304 demux->offset = offset;
2305 if (demux->upstream_format_is_time) {
2306 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2307 "set values to restart reading from a new atom");
2308 demux->neededbytes = 16;
2311 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2314 demux->todrop = stream->samples[idx].offset - offset;
2315 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2317 /* set up for EOS */
2318 demux->neededbytes = -1;
2323 gst_event_unref (event);
2327 case GST_EVENT_FLUSH_START:
2329 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2330 gst_event_unref (event);
2335 case GST_EVENT_FLUSH_STOP:
2339 dur = demux->segment.duration;
2340 gst_qtdemux_reset (demux, FALSE);
2341 demux->segment.duration = dur;
2343 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2344 gst_event_unref (event);
2350 /* If we are in push mode, and get an EOS before we've seen any streams,
2351 * then error out - we have nowhere to send the EOS */
2352 if (!demux->pullbased) {
2354 gboolean has_valid_stream = FALSE;
2355 for (i = 0; i < demux->n_streams; i++) {
2356 if (demux->streams[i]->pad != NULL) {
2357 has_valid_stream = TRUE;
2361 if (!has_valid_stream)
2362 gst_qtdemux_post_no_playable_stream_error (demux);
2364 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2365 (guint) gst_adapter_available (demux->adapter));
2366 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2372 case GST_EVENT_CAPS:{
2373 GstCaps *caps = NULL;
2375 gst_event_parse_caps (event, &caps);
2376 gst_qtdemux_setcaps (demux, caps);
2378 gst_event_unref (event);
2381 case GST_EVENT_PROTECTION:
2383 const gchar *system_id = NULL;
2385 gst_event_parse_protection (event, &system_id, NULL, NULL);
2386 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2388 gst_qtdemux_append_protection_system_id (demux, system_id);
2389 /* save the event for later, for source pads that have not been created */
2390 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2391 /* send it to all pads that already exist */
2392 gst_qtdemux_push_event (demux, event);
2400 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2408 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2410 GstQTDemux *demux = GST_QTDEMUX (element);
2412 GST_OBJECT_LOCK (demux);
2413 if (demux->element_index)
2414 gst_object_unref (demux->element_index);
2416 demux->element_index = gst_object_ref (index);
2418 demux->element_index = NULL;
2420 GST_OBJECT_UNLOCK (demux);
2421 /* object lock might be taken again */
2423 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2424 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2425 demux->element_index, demux->index_id);
2429 gst_qtdemux_get_index (GstElement * element)
2431 GstIndex *result = NULL;
2432 GstQTDemux *demux = GST_QTDEMUX (element);
2434 GST_OBJECT_LOCK (demux);
2435 if (demux->element_index)
2436 result = gst_object_ref (demux->element_index);
2437 GST_OBJECT_UNLOCK (demux);
2439 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2446 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2448 g_free ((gpointer) stream->stco.data);
2449 stream->stco.data = NULL;
2450 g_free ((gpointer) stream->stsz.data);
2451 stream->stsz.data = NULL;
2452 g_free ((gpointer) stream->stsc.data);
2453 stream->stsc.data = NULL;
2454 g_free ((gpointer) stream->stts.data);
2455 stream->stts.data = NULL;
2456 g_free ((gpointer) stream->stss.data);
2457 stream->stss.data = NULL;
2458 g_free ((gpointer) stream->stps.data);
2459 stream->stps.data = NULL;
2460 g_free ((gpointer) stream->ctts.data);
2461 stream->ctts.data = NULL;
2465 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2466 QtDemuxStream * stream)
2468 g_free (stream->segments);
2469 stream->segments = NULL;
2470 stream->segment_index = -1;
2471 stream->accumulated_base = 0;
2475 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2476 QtDemuxStream * stream)
2478 g_free (stream->samples);
2479 stream->samples = NULL;
2480 gst_qtdemux_stbl_free (stream);
2483 g_free (stream->ra_entries);
2484 stream->ra_entries = NULL;
2485 stream->n_ra_entries = 0;
2487 stream->sample_index = -1;
2488 stream->stbl_index = -1;
2489 stream->n_samples = 0;
2490 stream->time_position = 0;
2492 stream->n_samples_moof = 0;
2493 stream->duration_moof = 0;
2494 stream->duration_last_moof = 0;
2498 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2501 if (stream->allocator)
2502 gst_object_unref (stream->allocator);
2503 while (stream->buffers) {
2504 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2505 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2507 for (i = 0; i < stream->stsd_entries_length; i++) {
2508 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2509 if (entry->rgb8_palette) {
2510 gst_memory_unref (entry->rgb8_palette);
2511 entry->rgb8_palette = NULL;
2513 entry->sparse = FALSE;
2516 gst_tag_list_unref (stream->stream_tags);
2517 stream->stream_tags = gst_tag_list_new_empty ();
2518 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2519 g_free (stream->redirect_uri);
2520 stream->redirect_uri = NULL;
2521 stream->sent_eos = FALSE;
2522 stream->protected = FALSE;
2523 if (stream->protection_scheme_info) {
2524 if (stream->protection_scheme_type == FOURCC_cenc) {
2525 QtDemuxCencSampleSetInfo *info =
2526 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2527 if (info->default_properties)
2528 gst_structure_free (info->default_properties);
2529 if (info->crypto_info)
2530 g_ptr_array_free (info->crypto_info, TRUE);
2532 g_free (stream->protection_scheme_info);
2533 stream->protection_scheme_info = NULL;
2535 stream->protection_scheme_type = 0;
2536 stream->protection_scheme_version = 0;
2537 g_queue_foreach (&stream->protection_scheme_event_queue,
2538 (GFunc) gst_event_unref, NULL);
2539 g_queue_clear (&stream->protection_scheme_event_queue);
2540 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2541 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2545 gst_qtdemux_stream_reset (GstQTDemux * qtdemux, QtDemuxStream * stream)
2548 gst_qtdemux_stream_clear (qtdemux, stream);
2549 for (i = 0; i < stream->stsd_entries_length; i++) {
2550 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2552 gst_caps_unref (entry->caps);
2556 g_free (stream->stsd_entries);
2557 stream->stsd_entries = NULL;
2558 stream->stsd_entries_length = 0;
2563 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2565 gst_qtdemux_stream_reset (qtdemux, stream);
2566 gst_tag_list_unref (stream->stream_tags);
2568 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2569 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2575 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2577 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2579 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2580 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2581 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2582 qtdemux->n_streams--;
2585 static GstStateChangeReturn
2586 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2588 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2589 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2591 switch (transition) {
2592 case GST_STATE_CHANGE_PAUSED_TO_READY:
2598 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2600 switch (transition) {
2601 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2602 gst_qtdemux_reset (qtdemux, TRUE);
2613 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2615 /* counts as header data */
2616 qtdemux->header_size += length;
2618 /* only consider at least a sufficiently complete ftyp atom */
2622 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2623 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2624 GST_FOURCC_ARGS (qtdemux->major_brand));
2625 if (qtdemux->comp_brands)
2626 gst_buffer_unref (qtdemux->comp_brands);
2627 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2628 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2633 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2634 GstTagList * xmptaglist)
2636 /* Strip out bogus fields */
2638 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2639 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2640 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2642 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2645 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2647 /* prioritize native tags using _KEEP mode */
2648 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2649 gst_tag_list_unref (xmptaglist);
2654 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2662 QtDemuxStream *stream;
2663 GstStructure *structure;
2664 QtDemuxCencSampleSetInfo *ss_info = NULL;
2665 const gchar *system_id;
2666 gboolean uses_sub_sample_encryption = FALSE;
2668 if (qtdemux->n_streams == 0)
2671 stream = qtdemux->streams[0];
2673 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2674 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2675 GST_WARNING_OBJECT (qtdemux,
2676 "Attempting PIFF box parsing on an unencrypted stream.");
2680 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2681 G_TYPE_STRING, &system_id, NULL);
2682 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2684 stream->protected = TRUE;
2685 stream->protection_scheme_type = FOURCC_cenc;
2687 if (!stream->protection_scheme_info)
2688 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2690 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2692 if (ss_info->default_properties)
2693 gst_structure_free (ss_info->default_properties);
2695 ss_info->default_properties =
2696 gst_structure_new ("application/x-cenc",
2697 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2699 if (ss_info->crypto_info) {
2700 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2701 g_ptr_array_free (ss_info->crypto_info, TRUE);
2702 ss_info->crypto_info = NULL;
2706 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2708 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2709 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2713 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2714 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2718 if ((flags & 0x000001)) {
2719 guint32 algorithm_id = 0;
2722 gboolean is_encrypted = TRUE;
2724 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2725 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2730 if (algorithm_id == 0) {
2731 is_encrypted = FALSE;
2732 } else if (algorithm_id == 1) {
2733 /* FIXME: maybe store this in properties? */
2734 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2735 } else if (algorithm_id == 2) {
2736 /* FIXME: maybe store this in properties? */
2737 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2740 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2743 if (!gst_byte_reader_get_data (&br, 16, &kid))
2746 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2747 gst_buffer_fill (kid_buf, 0, kid, 16);
2748 if (ss_info->default_properties)
2749 gst_structure_free (ss_info->default_properties);
2750 ss_info->default_properties =
2751 gst_structure_new ("application/x-cenc",
2752 "iv_size", G_TYPE_UINT, iv_size,
2753 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2754 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2755 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2756 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2757 gst_buffer_unref (kid_buf);
2758 } else if ((flags & 0x000002)) {
2759 uses_sub_sample_encryption = TRUE;
2762 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2763 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2767 ss_info->crypto_info =
2768 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2769 (GDestroyNotify) qtdemux_gst_structure_free);
2771 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2772 GstStructure *properties;
2776 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2777 if (properties == NULL) {
2778 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2782 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2783 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2784 gst_structure_free (properties);
2787 buf = gst_buffer_new_wrapped (data, iv_size);
2788 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2789 gst_buffer_unref (buf);
2791 if (uses_sub_sample_encryption) {
2792 guint16 n_subsamples;
2794 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2795 || n_subsamples == 0) {
2796 GST_ERROR_OBJECT (qtdemux,
2797 "failed to get subsample count for sample %u", i);
2798 gst_structure_free (properties);
2801 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2802 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2803 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2805 gst_structure_free (properties);
2808 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2809 gst_structure_set (properties,
2810 "subsample_count", G_TYPE_UINT, n_subsamples,
2811 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2812 gst_buffer_unref (buf);
2814 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2817 g_ptr_array_add (ss_info->crypto_info, properties);
2822 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2824 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2825 0x97, 0xA9, 0x42, 0xE8,
2826 0x9C, 0x71, 0x99, 0x94,
2827 0x91, 0xE3, 0xAF, 0xAC
2829 static const guint8 playready_uuid[] = {
2830 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2831 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2834 static const guint8 piff_sample_encryption_uuid[] = {
2835 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2836 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2841 /* counts as header data */
2842 qtdemux->header_size += length;
2844 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2846 if (length <= offset + 16) {
2847 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2851 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2853 GstTagList *taglist;
2855 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2856 length - offset - 16, NULL);
2857 taglist = gst_tag_list_from_xmp_buffer (buf);
2858 gst_buffer_unref (buf);
2860 /* make sure we have a usable taglist */
2861 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2863 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2865 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2867 const gunichar2 *s_utf16;
2870 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2871 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2872 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2873 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2877 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2878 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2880 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2881 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2883 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2884 GST_READ_UINT32_LE (buffer + offset),
2885 GST_READ_UINT32_LE (buffer + offset + 4),
2886 GST_READ_UINT32_LE (buffer + offset + 8),
2887 GST_READ_UINT32_LE (buffer + offset + 12));
2892 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2894 GstSidxParser sidx_parser;
2895 GstIsoffParserResult res;
2898 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2901 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2903 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2904 if (res == GST_ISOFF_QT_PARSER_DONE) {
2905 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2907 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2910 /* caller verifies at least 8 bytes in buf */
2912 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2913 guint64 * plength, guint32 * pfourcc)
2918 length = QT_UINT32 (data);
2919 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2920 fourcc = QT_FOURCC (data + 4);
2921 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2924 length = G_MAXUINT64;
2925 } else if (length == 1 && size >= 16) {
2926 /* this means we have an extended size, which is the 64 bit value of
2927 * the next 8 bytes */
2928 length = QT_UINT64 (data + 8);
2929 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2939 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2941 guint32 version = 0;
2942 GstClockTime duration = 0;
2944 if (!gst_byte_reader_get_uint32_be (br, &version))
2949 if (!gst_byte_reader_get_uint64_be (br, &duration))
2954 if (!gst_byte_reader_get_uint32_be (br, &dur))
2959 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2960 qtdemux->duration = duration;
2966 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2972 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2973 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2975 if (!stream->parsed_trex && qtdemux->moov_node) {
2977 GstByteReader trex_data;
2979 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2981 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2984 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
2986 /* skip version/flags */
2987 if (!gst_byte_reader_skip (&trex_data, 4))
2989 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2991 if (id != stream->track_id)
2993 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
2995 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2997 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2999 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3002 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3003 "duration %d, size %d, flags 0x%x", stream->track_id,
3006 stream->parsed_trex = TRUE;
3007 stream->def_sample_description_index = sdi;
3008 stream->def_sample_duration = dur;
3009 stream->def_sample_size = size;
3010 stream->def_sample_flags = flags;
3013 /* iterate all siblings */
3014 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3020 *ds_duration = stream->def_sample_duration;
3021 *ds_size = stream->def_sample_size;
3022 *ds_flags = stream->def_sample_flags;
3024 /* even then, above values are better than random ... */
3025 if (G_UNLIKELY (!stream->parsed_trex)) {
3026 GST_WARNING_OBJECT (qtdemux,
3027 "failed to find fragment defaults for stream %d", stream->track_id);
3034 /* This method should be called whenever a more accurate duration might
3035 * have been found. It will update all relevant variables if/where needed
3038 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3042 GstClockTime prevdur;
3044 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3046 if (movdur > qtdemux->duration) {
3047 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3048 GST_DEBUG_OBJECT (qtdemux,
3049 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3050 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3051 qtdemux->duration = movdur;
3052 GST_DEBUG_OBJECT (qtdemux,
3053 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3054 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3055 GST_TIME_ARGS (qtdemux->segment.stop));
3056 if (qtdemux->segment.duration == prevdur) {
3057 /* If the current segment has duration/stop identical to previous duration
3058 * update them also (because they were set at that point in time with
3059 * the wrong duration */
3060 /* We convert the value *from* the timescale version to avoid rounding errors */
3061 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3062 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3063 qtdemux->segment.duration = fixeddur;
3064 qtdemux->segment.stop = fixeddur;
3067 for (i = 0; i < qtdemux->n_streams; i++) {
3068 QtDemuxStream *stream = qtdemux->streams[i];
3070 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3071 if (movdur > stream->duration) {
3072 GST_DEBUG_OBJECT (qtdemux,
3073 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3074 GST_TIME_ARGS (duration));
3075 stream->duration = movdur;
3076 /* internal duration tracking state has been updated above, so */
3077 /* preserve an open-ended dummy segment rather than repeatedly updating
3078 * it and spamming downstream accordingly with segment events */
3079 if (stream->dummy_segment &&
3080 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3081 /* Update all dummy values to new duration */
3082 stream->segments[0].stop_time = duration;
3083 stream->segments[0].duration = duration;
3084 stream->segments[0].media_stop = duration;
3086 /* let downstream know we possibly have a new stop time */
3087 if (stream->segment_index != -1) {
3090 if (qtdemux->segment.rate >= 0) {
3091 pos = stream->segment.start;
3093 pos = stream->segment.stop;
3096 gst_qtdemux_stream_update_segment (qtdemux, stream,
3097 stream->segment_index, pos, NULL, NULL);
3106 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3107 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3108 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3109 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3112 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3114 gint32 data_offset = 0;
3115 guint32 flags = 0, first_flags = 0, samples_count = 0;
3118 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3119 QtDemuxSample *sample;
3120 gboolean ismv = FALSE;
3121 gint64 initial_offset;
3123 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3124 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3125 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3126 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3128 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3129 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3133 /* presence of stss or not can't really tell us much,
3134 * and flags and so on tend to be marginally reliable in these files */
3135 if (stream->subtype == FOURCC_soun) {
3136 GST_DEBUG_OBJECT (qtdemux,
3137 "sound track in fragmented file; marking all keyframes");
3138 stream->all_keyframe = TRUE;
3141 if (!gst_byte_reader_skip (trun, 1) ||
3142 !gst_byte_reader_get_uint24_be (trun, &flags))
3145 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3148 if (flags & TR_DATA_OFFSET) {
3149 /* note this is really signed */
3150 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3152 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3153 /* default base offset = first byte of moof */
3154 if (*base_offset == -1) {
3155 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3156 *base_offset = moof_offset;
3158 *running_offset = *base_offset + data_offset;
3160 /* if no offset at all, that would mean data starts at moof start,
3161 * which is a bit wrong and is ismv crappy way, so compensate
3162 * assuming data is in mdat following moof */
3163 if (*base_offset == -1) {
3164 *base_offset = moof_offset + moof_length + 8;
3165 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3168 if (*running_offset == -1)
3169 *running_offset = *base_offset;
3172 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3174 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3175 data_offset, flags, samples_count);
3177 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3178 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3179 GST_DEBUG_OBJECT (qtdemux,
3180 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3181 flags ^= TR_FIRST_SAMPLE_FLAGS;
3183 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3185 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3189 /* FIXME ? spec says other bits should also be checked to determine
3190 * entry size (and prefix size for that matter) */
3192 dur_offset = size_offset = 0;
3193 if (flags & TR_SAMPLE_DURATION) {
3194 GST_LOG_OBJECT (qtdemux, "entry duration present");
3195 dur_offset = entry_size;
3198 if (flags & TR_SAMPLE_SIZE) {
3199 GST_LOG_OBJECT (qtdemux, "entry size present");
3200 size_offset = entry_size;
3203 if (flags & TR_SAMPLE_FLAGS) {
3204 GST_LOG_OBJECT (qtdemux, "entry flags present");
3205 flags_offset = entry_size;
3208 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3209 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3210 ct_offset = entry_size;
3214 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3216 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3218 if (stream->n_samples + samples_count >=
3219 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3222 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3223 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3224 (stream->n_samples + samples_count) *
3225 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3227 /* create a new array of samples if it's the first sample parsed */
3228 if (stream->n_samples == 0) {
3229 g_assert (stream->samples == NULL);
3230 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3231 /* or try to reallocate it with space enough to insert the new samples */
3233 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3234 stream->n_samples + samples_count);
3235 if (stream->samples == NULL)
3238 if (qtdemux->fragment_start != -1) {
3239 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3240 qtdemux->fragment_start = -1;
3242 if (stream->n_samples == 0) {
3243 if (decode_ts > 0) {
3244 timestamp = decode_ts;
3245 } else if (stream->pending_seek != NULL) {
3246 /* if we don't have a timestamp from a tfdt box, we'll use the one
3247 * from the mfra seek table */
3248 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3249 GST_TIME_ARGS (stream->pending_seek->ts));
3251 /* FIXME: this is not fully correct, the timestamp refers to the random
3252 * access sample refered to in the tfra entry, which may not necessarily
3253 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3254 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3259 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3260 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3261 GST_TIME_ARGS (gst_ts));
3263 /* subsequent fragments extend stream */
3265 stream->samples[stream->n_samples - 1].timestamp +
3266 stream->samples[stream->n_samples - 1].duration;
3268 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3269 * difference (1 sec.) between decode_ts and timestamp, prefer the
3271 if (has_tfdt && !qtdemux->upstream_format_is_time
3272 && ABSDIFF (decode_ts, timestamp) >
3273 MAX (stream->duration_last_moof / 2,
3274 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3275 GST_INFO_OBJECT (qtdemux,
3276 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3277 ") are significantly different (more than %" GST_TIME_FORMAT
3278 "), using decode_ts",
3279 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3280 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3281 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3282 MAX (stream->duration_last_moof / 2,
3283 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3284 timestamp = decode_ts;
3287 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3288 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3289 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3293 initial_offset = *running_offset;
3295 sample = stream->samples + stream->n_samples;
3296 for (i = 0; i < samples_count; i++) {
3297 guint32 dur, size, sflags, ct;
3299 /* first read sample data */
3300 if (flags & TR_SAMPLE_DURATION) {
3301 dur = QT_UINT32 (data + dur_offset);
3303 dur = d_sample_duration;
3305 if (flags & TR_SAMPLE_SIZE) {
3306 size = QT_UINT32 (data + size_offset);
3308 size = d_sample_size;
3310 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3312 sflags = first_flags;
3314 sflags = d_sample_flags;
3316 } else if (flags & TR_SAMPLE_FLAGS) {
3317 sflags = QT_UINT32 (data + flags_offset);
3319 sflags = d_sample_flags;
3321 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3322 ct = QT_UINT32 (data + ct_offset);
3328 /* fill the sample information */
3329 sample->offset = *running_offset;
3330 sample->pts_offset = ct;
3331 sample->size = size;
3332 sample->timestamp = timestamp;
3333 sample->duration = dur;
3334 /* sample-is-difference-sample */
3335 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3336 * now idea how it relates to bitfield other than massive LE/BE confusion */
3337 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3338 *running_offset += size;
3340 stream->duration_moof += dur;
3344 /* Update total duration if needed */
3345 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3347 /* Pre-emptively figure out size of mdat based on trun information.
3348 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3349 * size, else we will still be able to use this when dealing with gap'ed
3351 qtdemux->mdatleft = *running_offset - initial_offset;
3352 qtdemux->mdatoffset = initial_offset;
3353 qtdemux->mdatsize = qtdemux->mdatleft;
3355 stream->n_samples += samples_count;
3356 stream->n_samples_moof += samples_count;
3358 if (stream->pending_seek != NULL)
3359 stream->pending_seek = NULL;
3365 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3370 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3376 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3377 "be larger than %uMB (broken file?)", stream->n_samples,
3378 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3383 /* find stream with @id */
3384 static inline QtDemuxStream *
3385 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3387 QtDemuxStream *stream;
3391 if (G_UNLIKELY (!id)) {
3392 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3396 /* try to get it fast and simple */
3397 if (G_LIKELY (id <= qtdemux->n_streams)) {
3398 stream = qtdemux->streams[id - 1];
3399 if (G_LIKELY (stream->track_id == id))
3403 /* linear search otherwise */
3404 for (i = 0; i < qtdemux->n_streams; i++) {
3405 stream = qtdemux->streams[i];
3406 if (stream->track_id == id)
3409 if (qtdemux->mss_mode) {
3410 /* mss should have only 1 stream anyway */
3411 return qtdemux->streams[0];
3418 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3419 guint32 * fragment_number)
3421 if (!gst_byte_reader_skip (mfhd, 4))
3423 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3428 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3434 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3435 QtDemuxStream ** stream, guint32 * default_sample_duration,
3436 guint32 * default_sample_size, guint32 * default_sample_flags,
3437 gint64 * base_offset)
3440 guint32 track_id = 0;
3442 if (!gst_byte_reader_skip (tfhd, 1) ||
3443 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3446 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3449 *stream = qtdemux_find_stream (qtdemux, track_id);
3450 if (G_UNLIKELY (!*stream))
3451 goto unknown_stream;
3453 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3454 *base_offset = qtdemux->moof_offset;
3456 if (flags & TF_BASE_DATA_OFFSET)
3457 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3460 /* obtain stream defaults */
3461 qtdemux_parse_trex (qtdemux, *stream,
3462 default_sample_duration, default_sample_size, default_sample_flags);
3464 (*stream)->stsd_sample_description_id =
3465 (*stream)->def_sample_description_index - 1;
3467 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3468 guint32 sample_description_index;
3469 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3471 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3474 if (qtdemux->mss_mode) {
3475 /* mss has no stsd entry */
3476 (*stream)->stsd_sample_description_id = 0;
3479 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3480 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3483 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3484 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3487 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3488 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3495 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3500 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3506 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3507 guint64 * decode_time)
3509 guint32 version = 0;
3511 if (!gst_byte_reader_get_uint32_be (br, &version))
3516 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3519 guint32 dec_time = 0;
3520 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3522 *decode_time = dec_time;
3525 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3532 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3537 /* Returns a pointer to a GstStructure containing the properties of
3538 * the stream sample identified by @sample_index. The caller must unref
3539 * the returned object after use. Returns NULL if unsuccessful. */
3540 static GstStructure *
3541 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3542 QtDemuxStream * stream, guint sample_index)
3544 QtDemuxCencSampleSetInfo *info = NULL;
3546 g_return_val_if_fail (stream != NULL, NULL);
3547 g_return_val_if_fail (stream->protected, NULL);
3548 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3550 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3552 /* Currently, cenc properties for groups of samples are not supported, so
3553 * simply return a copy of the default sample properties */
3554 return gst_structure_copy (info->default_properties);
3557 /* Parses the sizes of sample auxiliary information contained within a stream,
3558 * as given in a saiz box. Returns array of sample_count guint8 size values,
3559 * or NULL on failure */
3561 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3562 GstByteReader * br, guint32 * sample_count)
3566 guint8 default_info_size;
3568 g_return_val_if_fail (qtdemux != NULL, NULL);
3569 g_return_val_if_fail (stream != NULL, NULL);
3570 g_return_val_if_fail (br != NULL, NULL);
3571 g_return_val_if_fail (sample_count != NULL, NULL);
3573 if (!gst_byte_reader_get_uint32_be (br, &flags))
3577 /* aux_info_type and aux_info_type_parameter are ignored */
3578 if (!gst_byte_reader_skip (br, 8))
3582 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3584 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3586 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3588 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3591 if (default_info_size == 0) {
3592 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3596 info_sizes = g_new (guint8, *sample_count);
3597 memset (info_sizes, default_info_size, *sample_count);
3603 /* Parses the offset of sample auxiliary information contained within a stream,
3604 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3606 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3607 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3612 guint32 aux_info_type = 0;
3613 guint32 aux_info_type_parameter = 0;
3614 guint32 entry_count;
3617 const guint8 *aux_info_type_data = NULL;
3619 g_return_val_if_fail (qtdemux != NULL, FALSE);
3620 g_return_val_if_fail (stream != NULL, FALSE);
3621 g_return_val_if_fail (br != NULL, FALSE);
3622 g_return_val_if_fail (offset != NULL, FALSE);
3624 if (!gst_byte_reader_get_uint8 (br, &version))
3627 if (!gst_byte_reader_get_uint24_be (br, &flags))
3632 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3634 aux_info_type = QT_FOURCC (aux_info_type_data);
3636 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3638 } else if (stream->protected) {
3639 aux_info_type = stream->protection_scheme_type;
3641 aux_info_type = CUR_STREAM (stream)->fourcc;
3645 *info_type = aux_info_type;
3646 if (info_type_parameter)
3647 *info_type_parameter = aux_info_type_parameter;
3649 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3650 "aux_info_type_parameter: %#06x",
3651 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3653 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3656 if (entry_count != 1) {
3657 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3662 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3664 *offset = (guint64) off_32;
3666 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3671 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3676 qtdemux_gst_structure_free (GstStructure * gststructure)
3679 gst_structure_free (gststructure);
3683 /* Parses auxiliary information relating to samples protected using Common
3684 * Encryption (cenc); the format of this information is defined in
3685 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3687 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3688 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3690 QtDemuxCencSampleSetInfo *ss_info = NULL;
3693 GPtrArray *old_crypto_info = NULL;
3694 guint old_entries = 0;
3696 g_return_val_if_fail (qtdemux != NULL, FALSE);
3697 g_return_val_if_fail (stream != NULL, FALSE);
3698 g_return_val_if_fail (br != NULL, FALSE);
3699 g_return_val_if_fail (stream->protected, FALSE);
3700 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3702 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3704 if (ss_info->crypto_info) {
3705 old_crypto_info = ss_info->crypto_info;
3706 /* Count number of non-null entries remaining at the tail end */
3707 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3708 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3714 ss_info->crypto_info =
3715 g_ptr_array_new_full (sample_count + old_entries,
3716 (GDestroyNotify) qtdemux_gst_structure_free);
3718 /* We preserve old entries because we parse the next moof in advance
3719 * of consuming all samples from the previous moof, and otherwise
3720 * we'd discard the corresponding crypto info for the samples
3721 * from the previous fragment. */
3723 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3725 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3726 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3728 g_ptr_array_index (old_crypto_info, i) = NULL;
3732 if (old_crypto_info) {
3733 /* Everything now belongs to the new array */
3734 g_ptr_array_free (old_crypto_info, TRUE);
3737 for (i = 0; i < sample_count; ++i) {
3738 GstStructure *properties;
3739 guint16 n_subsamples = 0;
3744 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3745 if (properties == NULL) {
3746 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3749 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3750 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3751 gst_structure_free (properties);
3754 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3755 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3756 gst_structure_free (properties);
3759 buf = gst_buffer_new_wrapped (data, iv_size);
3760 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3761 gst_buffer_unref (buf);
3762 size = info_sizes[i];
3763 if (size > iv_size) {
3764 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3765 || !(n_subsamples > 0)) {
3766 gst_structure_free (properties);
3767 GST_ERROR_OBJECT (qtdemux,
3768 "failed to get subsample count for sample %u", i);
3771 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3772 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3773 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3775 gst_structure_free (properties);
3778 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3780 gst_structure_free (properties);
3783 gst_structure_set (properties,
3784 "subsample_count", G_TYPE_UINT, n_subsamples,
3785 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3786 gst_buffer_unref (buf);
3788 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3790 g_ptr_array_add (ss_info->crypto_info, properties);
3795 /* Converts a UUID in raw byte form to a string representation, as defined in
3796 * RFC 4122. The caller takes ownership of the returned string and is
3797 * responsible for freeing it after use. */
3799 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3801 const guint8 *uuid = (const guint8 *) uuid_bytes;
3803 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3804 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3805 uuid[0], uuid[1], uuid[2], uuid[3],
3806 uuid[4], uuid[5], uuid[6], uuid[7],
3807 uuid[8], uuid[9], uuid[10], uuid[11],
3808 uuid[12], uuid[13], uuid[14], uuid[15]);
3811 /* Parses a Protection System Specific Header box (pssh), as defined in the
3812 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3813 * information needed by a specific content protection system in order to
3814 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3817 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3819 gchar *sysid_string;
3820 guint32 pssh_size = QT_UINT32 (node->data);
3821 GstBuffer *pssh = NULL;
3822 GstEvent *event = NULL;
3823 guint32 parent_box_type;
3826 if (G_UNLIKELY (pssh_size < 32U)) {
3827 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3832 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3834 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3836 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3837 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3838 gst_buffer_get_size (pssh));
3840 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3842 /* Push an event containing the pssh box onto the queues of all streams. */
3843 event = gst_event_new_protection (sysid_string, pssh,
3844 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3845 for (i = 0; i < qtdemux->n_streams; ++i) {
3846 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3847 gst_event_ref (event));
3849 g_free (sysid_string);
3850 gst_event_unref (event);
3851 gst_buffer_unref (pssh);
3856 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3857 guint64 moof_offset, QtDemuxStream * stream)
3859 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3861 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3862 GNode *saiz_node, *saio_node, *pssh_node;
3863 GstByteReader saiz_data, saio_data;
3864 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3865 gint64 base_offset, running_offset;
3868 /* NOTE @stream ignored */
3870 moof_node = g_node_new ((guint8 *) buffer);
3871 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3872 qtdemux_node_dump (qtdemux, moof_node);
3874 /* Get fragment number from mfhd and check it's valid */
3876 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3877 if (mfhd_node == NULL)
3879 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3881 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3883 /* unknown base_offset to start with */
3884 base_offset = running_offset = -1;
3885 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3887 guint64 decode_time = 0;
3889 /* Fragment Header node */
3891 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3895 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3896 &ds_size, &ds_flags, &base_offset))
3899 /* The following code assumes at most a single set of sample auxiliary
3900 * data in the fragment (consisting of a saiz box and a corresponding saio
3901 * box); in theory, however, there could be multiple sets of sample
3902 * auxiliary data in a fragment. */
3904 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3907 guint32 info_type = 0;
3909 guint32 info_type_parameter = 0;
3911 g_free (qtdemux->cenc_aux_info_sizes);
3913 qtdemux->cenc_aux_info_sizes =
3914 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3915 &qtdemux->cenc_aux_sample_count);
3916 if (qtdemux->cenc_aux_info_sizes == NULL) {
3917 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3921 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3924 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3925 g_free (qtdemux->cenc_aux_info_sizes);
3926 qtdemux->cenc_aux_info_sizes = NULL;
3930 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3931 &info_type, &info_type_parameter, &offset))) {
3932 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3933 g_free (qtdemux->cenc_aux_info_sizes);
3934 qtdemux->cenc_aux_info_sizes = NULL;
3937 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3938 offset += (guint64) (base_offset - qtdemux->moof_offset);
3939 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3941 if (offset > length) {
3942 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3943 qtdemux->cenc_aux_info_offset = offset;
3945 gst_byte_reader_init (&br, buffer + offset, length - offset);
3946 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3947 qtdemux->cenc_aux_info_sizes,
3948 qtdemux->cenc_aux_sample_count)) {
3949 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3950 g_free (qtdemux->cenc_aux_info_sizes);
3951 qtdemux->cenc_aux_info_sizes = NULL;
3959 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3962 /* We'll use decode_time to interpolate timestamps
3963 * in case the input timestamps are missing */
3964 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3966 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3967 " (%" GST_TIME_FORMAT ")", decode_time,
3968 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
3969 decode_time) : GST_CLOCK_TIME_NONE));
3971 /* Discard the fragment buffer timestamp info to avoid using it.
3972 * Rely on tfdt instead as it is more accurate than the timestamp
3973 * that is fetched from a manifest/playlist and is usually
3975 qtdemux->fragment_start = -1;
3978 if (G_UNLIKELY (!stream)) {
3979 /* we lost track of offset, we'll need to regain it,
3980 * but can delay complaining until later or avoid doing so altogether */
3984 if (G_UNLIKELY (base_offset < -1))
3987 if (qtdemux->upstream_format_is_time)
3988 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3990 /* initialise moof sample data */
3991 stream->n_samples_moof = 0;
3992 stream->duration_last_moof = stream->duration_moof;
3993 stream->duration_moof = 0;
3995 /* Track Run node */
3997 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4000 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4001 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4002 &running_offset, decode_time, (tfdt_node != NULL));
4003 /* iterate all siblings */
4004 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4008 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4010 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4011 guint32 box_length = QT_UINT32 (uuid_buffer);
4013 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4016 /* if no new base_offset provided for next traf,
4017 * base is end of current traf */
4018 base_offset = running_offset;
4019 running_offset = -1;
4021 if (stream->n_samples_moof && stream->duration_moof)
4022 stream->new_caps = TRUE;
4025 /* iterate all siblings */
4026 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4029 /* parse any protection system info */
4030 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4032 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4033 qtdemux_parse_pssh (qtdemux, pssh_node);
4034 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4037 g_node_destroy (moof_node);
4042 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4047 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4052 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4057 g_node_destroy (moof_node);
4058 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4059 (_("This file is corrupt and cannot be played.")), (NULL));
4065 /* might be used if some day we actually use mfra & co
4066 * for random access to fragments,
4067 * but that will require quite some modifications and much less relying
4068 * on a sample array */
4072 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4074 QtDemuxStream *stream;
4075 guint32 ver_flags, track_id, len, num_entries, i;
4076 guint value_size, traf_size, trun_size, sample_size;
4077 guint64 time = 0, moof_offset = 0;
4079 GstBuffer *buf = NULL;
4084 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4086 if (!gst_byte_reader_skip (&tfra, 8))
4089 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4092 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4093 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4094 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4097 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4099 stream = qtdemux_find_stream (qtdemux, track_id);
4101 goto unknown_trackid;
4103 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4104 sample_size = (len & 3) + 1;
4105 trun_size = ((len & 12) >> 2) + 1;
4106 traf_size = ((len & 48) >> 4) + 1;
4108 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4109 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4111 if (num_entries == 0)
4114 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4115 value_size + value_size + traf_size + trun_size + sample_size))
4118 g_free (stream->ra_entries);
4119 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4120 stream->n_ra_entries = num_entries;
4122 for (i = 0; i < num_entries; i++) {
4123 qt_atom_parser_get_offset (&tfra, value_size, &time);
4124 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4125 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4126 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4127 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4129 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4131 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4132 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4134 stream->ra_entries[i].ts = time;
4135 stream->ra_entries[i].moof_offset = moof_offset;
4137 /* don't want to go through the entire file and read all moofs at startup */
4139 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4140 if (ret != GST_FLOW_OK)
4142 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4143 moof_offset, stream);
4144 gst_buffer_unref (buf);
4148 check_update_duration (qtdemux, time);
4155 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4160 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4165 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4171 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4173 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4174 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4175 GstBuffer *mfro = NULL, *mfra = NULL;
4177 gboolean ret = FALSE;
4178 GNode *mfra_node, *tfra_node;
4179 guint64 mfra_offset = 0;
4180 guint32 fourcc, mfra_size;
4183 /* query upstream size in bytes */
4184 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4185 goto size_query_failed;
4187 /* mfro box should be at the very end of the file */
4188 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4189 if (flow != GST_FLOW_OK)
4192 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4194 fourcc = QT_FOURCC (mfro_map.data + 4);
4195 if (fourcc != FOURCC_mfro)
4198 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4199 if (mfro_map.size < 16)
4200 goto invalid_mfro_size;
4202 mfra_size = QT_UINT32 (mfro_map.data + 12);
4203 if (mfra_size >= len)
4204 goto invalid_mfra_size;
4206 mfra_offset = len - mfra_size;
4208 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4209 mfra_offset, mfra_size);
4211 /* now get and parse mfra box */
4212 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4213 if (flow != GST_FLOW_OK)
4216 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4218 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4219 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4221 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4224 qtdemux_parse_tfra (qtdemux, tfra_node);
4225 /* iterate all siblings */
4226 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4228 g_node_destroy (mfra_node);
4230 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4236 if (mfro_map.memory != NULL)
4237 gst_buffer_unmap (mfro, &mfro_map);
4238 gst_buffer_unref (mfro);
4241 if (mfra_map.memory != NULL)
4242 gst_buffer_unmap (mfra, &mfra_map);
4243 gst_buffer_unref (mfra);
4250 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4255 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4260 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4265 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4271 add_offset (guint64 offset, guint64 advance)
4273 /* Avoid 64-bit overflow by clamping */
4274 if (offset > G_MAXUINT64 - advance)
4276 return offset + advance;
4279 static GstFlowReturn
4280 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4284 GstBuffer *buf = NULL;
4285 GstFlowReturn ret = GST_FLOW_OK;
4286 guint64 cur_offset = qtdemux->offset;
4289 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4290 if (G_UNLIKELY (ret != GST_FLOW_OK))
4292 gst_buffer_map (buf, &map, GST_MAP_READ);
4293 if (G_LIKELY (map.size >= 8))
4294 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4295 gst_buffer_unmap (buf, &map);
4296 gst_buffer_unref (buf);
4298 /* maybe we already got most we needed, so only consider this eof */
4299 if (G_UNLIKELY (length == 0)) {
4300 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4301 (_("Invalid atom size.")),
4302 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4303 GST_FOURCC_ARGS (fourcc)));
4310 /* record for later parsing when needed */
4311 if (!qtdemux->moof_offset) {
4312 qtdemux->moof_offset = qtdemux->offset;
4314 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4317 qtdemux->offset += length; /* skip moof and keep going */
4319 if (qtdemux->got_moov) {
4320 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4332 GST_LOG_OBJECT (qtdemux,
4333 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4334 GST_FOURCC_ARGS (fourcc), cur_offset);
4335 qtdemux->offset = add_offset (qtdemux->offset, length);
4340 GstBuffer *moov = NULL;
4342 if (qtdemux->got_moov) {
4343 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4344 qtdemux->offset = add_offset (qtdemux->offset, length);
4348 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4349 if (ret != GST_FLOW_OK)
4351 gst_buffer_map (moov, &map, GST_MAP_READ);
4353 if (length != map.size) {
4354 /* Some files have a 'moov' atom at the end of the file which contains
4355 * a terminal 'free' atom where the body of the atom is missing.
4356 * Check for, and permit, this special case.
4358 if (map.size >= 8) {
4359 guint8 *final_data = map.data + (map.size - 8);
4360 guint32 final_length = QT_UINT32 (final_data);
4361 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4363 if (final_fourcc == FOURCC_free
4364 && map.size + final_length - 8 == length) {
4365 /* Ok, we've found that special case. Allocate a new buffer with
4366 * that free atom actually present. */
4367 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4368 gst_buffer_fill (newmoov, 0, map.data, map.size);
4369 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4370 gst_buffer_unmap (moov, &map);
4371 gst_buffer_unref (moov);
4373 gst_buffer_map (moov, &map, GST_MAP_READ);
4378 if (length != map.size) {
4379 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4380 (_("This file is incomplete and cannot be played.")),
4381 ("We got less than expected (received %" G_GSIZE_FORMAT
4382 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4383 (guint) length, cur_offset));
4384 gst_buffer_unmap (moov, &map);
4385 gst_buffer_unref (moov);
4386 ret = GST_FLOW_ERROR;
4389 qtdemux->offset += length;
4391 qtdemux_parse_moov (qtdemux, map.data, length);
4392 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4394 qtdemux_parse_tree (qtdemux);
4395 if (qtdemux->moov_node_compressed) {
4396 g_node_destroy (qtdemux->moov_node_compressed);
4397 g_free (qtdemux->moov_node->data);
4399 qtdemux->moov_node_compressed = NULL;
4400 g_node_destroy (qtdemux->moov_node);
4401 qtdemux->moov_node = NULL;
4402 gst_buffer_unmap (moov, &map);
4403 gst_buffer_unref (moov);
4404 qtdemux->got_moov = TRUE;
4410 GstBuffer *ftyp = NULL;
4412 /* extract major brand; might come in handy for ISO vs QT issues */
4413 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4414 if (ret != GST_FLOW_OK)
4416 qtdemux->offset += length;
4417 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4418 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4419 gst_buffer_unmap (ftyp, &map);
4420 gst_buffer_unref (ftyp);
4425 GstBuffer *uuid = NULL;
4427 /* uuid are extension atoms */
4428 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4429 if (ret != GST_FLOW_OK)
4431 qtdemux->offset += length;
4432 gst_buffer_map (uuid, &map, GST_MAP_READ);
4433 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4434 gst_buffer_unmap (uuid, &map);
4435 gst_buffer_unref (uuid);
4440 GstBuffer *sidx = NULL;
4441 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4442 if (ret != GST_FLOW_OK)
4444 qtdemux->offset += length;
4445 gst_buffer_map (sidx, &map, GST_MAP_READ);
4446 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4447 gst_buffer_unmap (sidx, &map);
4448 gst_buffer_unref (sidx);
4453 GstBuffer *unknown = NULL;
4455 GST_LOG_OBJECT (qtdemux,
4456 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4457 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4459 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4460 if (ret != GST_FLOW_OK)
4462 gst_buffer_map (unknown, &map, GST_MAP_READ);
4463 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4464 gst_buffer_unmap (unknown, &map);
4465 gst_buffer_unref (unknown);
4466 qtdemux->offset += length;
4472 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4473 /* digested all data, show what we have */
4474 qtdemux_prepare_streams (qtdemux);
4475 ret = qtdemux_expose_streams (qtdemux);
4477 qtdemux->state = QTDEMUX_STATE_MOVIE;
4478 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4485 /* Seeks to the previous keyframe of the indexed stream and
4486 * aligns other streams with respect to the keyframe timestamp
4487 * of indexed stream. Only called in case of Reverse Playback
4489 static GstFlowReturn
4490 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4493 guint32 seg_idx = 0, k_index = 0;
4494 guint32 ref_seg_idx, ref_k_index;
4495 GstClockTime k_pos = 0, last_stop = 0;
4496 QtDemuxSegment *seg = NULL;
4497 QtDemuxStream *ref_str = NULL;
4498 guint64 seg_media_start_mov; /* segment media start time in mov format */
4501 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4502 * and finally align all the other streams on that timestamp with their
4503 * respective keyframes */
4504 for (n = 0; n < qtdemux->n_streams; n++) {
4505 QtDemuxStream *str = qtdemux->streams[n];
4507 /* No candidate yet, take the first stream */
4513 /* So that stream has a segment, we prefer video streams */
4514 if (str->subtype == FOURCC_vide) {
4520 if (G_UNLIKELY (!ref_str)) {
4521 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4525 if (G_UNLIKELY (!ref_str->from_sample)) {
4526 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4530 /* So that stream has been playing from from_sample to to_sample. We will
4531 * get the timestamp of the previous sample and search for a keyframe before
4532 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4533 if (ref_str->subtype == FOURCC_vide) {
4534 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4535 ref_str->from_sample - 1, FALSE);
4537 if (ref_str->from_sample >= 10)
4538 k_index = ref_str->from_sample - 10;
4544 ref_str->samples[k_index].timestamp +
4545 ref_str->samples[k_index].pts_offset;
4547 /* get current segment for that stream */
4548 seg = &ref_str->segments[ref_str->segment_index];
4549 /* Use segment start in original timescale for comparisons */
4550 seg_media_start_mov = seg->trak_media_start;
4552 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4553 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4554 k_index, target_ts, seg_media_start_mov,
4555 GST_TIME_ARGS (seg->media_start));
4557 /* Crawl back through segments to find the one containing this I frame */
4558 while (target_ts < seg_media_start_mov) {
4559 GST_DEBUG_OBJECT (qtdemux,
4560 "keyframe position (sample %u) is out of segment %u " " target %"
4561 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4562 ref_str->segment_index, target_ts, seg_media_start_mov);
4564 if (G_UNLIKELY (!ref_str->segment_index)) {
4565 /* Reached first segment, let's consider it's EOS */
4568 ref_str->segment_index--;
4569 seg = &ref_str->segments[ref_str->segment_index];
4570 /* Use segment start in original timescale for comparisons */
4571 seg_media_start_mov = seg->trak_media_start;
4573 /* Calculate time position of the keyframe and where we should stop */
4575 QTSTREAMTIME_TO_GSTTIME (ref_str,
4576 target_ts - seg->trak_media_start) + seg->time;
4578 QTSTREAMTIME_TO_GSTTIME (ref_str,
4579 ref_str->samples[ref_str->from_sample].timestamp -
4580 seg->trak_media_start) + seg->time;
4582 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4583 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4584 k_index, GST_TIME_ARGS (k_pos));
4586 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4587 qtdemux->segment.position = last_stop;
4588 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4589 GST_TIME_ARGS (last_stop));
4591 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4592 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4596 ref_seg_idx = ref_str->segment_index;
4597 ref_k_index = k_index;
4599 /* Align them all on this */
4600 for (n = 0; n < qtdemux->n_streams; n++) {
4602 GstClockTime seg_time = 0;
4603 QtDemuxStream *str = qtdemux->streams[n];
4605 /* aligning reference stream again might lead to backing up to yet another
4606 * keyframe (due to timestamp rounding issues),
4607 * potentially putting more load on downstream; so let's try to avoid */
4608 if (str == ref_str) {
4609 seg_idx = ref_seg_idx;
4610 seg = &str->segments[seg_idx];
4611 k_index = ref_k_index;
4612 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4613 "sample at index %d", n, ref_str->segment_index, k_index);
4615 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4616 GST_DEBUG_OBJECT (qtdemux,
4617 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4618 seg_idx, GST_TIME_ARGS (k_pos));
4620 /* get segment and time in the segment */
4621 seg = &str->segments[seg_idx];
4622 seg_time = k_pos - seg->time;
4624 /* get the media time in the segment.
4625 * No adjustment for empty "filler" segments */
4626 if (seg->media_start != GST_CLOCK_TIME_NONE)
4627 seg_time += seg->media_start;
4629 /* get the index of the sample with media time */
4630 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4631 GST_DEBUG_OBJECT (qtdemux,
4632 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4633 GST_TIME_ARGS (seg_time), index);
4635 /* find previous keyframe */
4636 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4639 /* Remember until where we want to go */
4640 str->to_sample = str->from_sample - 1;
4641 /* Define our time position */
4643 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4644 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4645 if (seg->media_start != GST_CLOCK_TIME_NONE)
4646 str->time_position -= seg->media_start;
4648 /* Now seek back in time */
4649 gst_qtdemux_move_stream (qtdemux, str, k_index);
4650 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4651 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4652 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4658 return GST_FLOW_EOS;
4662 * Gets the current qt segment start, stop and position for the
4663 * given time offset. This is used in update_segment()
4666 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4667 QtDemuxStream * stream, GstClockTime offset,
4668 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4670 GstClockTime seg_time;
4671 GstClockTime start, stop, time;
4672 QtDemuxSegment *segment;
4674 segment = &stream->segments[stream->segment_index];
4676 /* get time in this segment */
4677 seg_time = (offset - segment->time) * segment->rate;
4679 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4680 GST_TIME_ARGS (seg_time));
4682 if (G_UNLIKELY (seg_time > segment->duration)) {
4683 GST_LOG_OBJECT (stream->pad,
4684 "seg_time > segment->duration %" GST_TIME_FORMAT,
4685 GST_TIME_ARGS (segment->duration));
4686 seg_time = segment->duration;
4689 /* qtdemux->segment.stop is in outside-time-realm, whereas
4690 * segment->media_stop is in track-time-realm.
4692 * In order to compare the two, we need to bring segment.stop
4693 * into the track-time-realm
4695 * FIXME - does this comment still hold? Don't see any conversion here */
4697 stop = qtdemux->segment.stop;
4698 if (stop == GST_CLOCK_TIME_NONE)
4699 stop = qtdemux->segment.duration;
4700 if (stop == GST_CLOCK_TIME_NONE)
4701 stop = segment->media_stop;
4704 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4706 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4707 start = segment->time + seg_time;
4709 stop = start - seg_time + segment->duration;
4710 } else if (qtdemux->segment.rate >= 0) {
4711 start = MIN (segment->media_start + seg_time, stop);
4714 if (segment->media_start >= qtdemux->segment.start) {
4715 time = segment->time;
4717 time = segment->time + (qtdemux->segment.start - segment->media_start);
4720 start = MAX (segment->media_start, qtdemux->segment.start);
4721 stop = MIN (segment->media_start + seg_time, stop);
4730 * Updates the qt segment used for the stream and pushes a new segment event
4731 * downstream on this stream's pad.
4734 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4735 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4736 GstClockTime * _stop)
4738 QtDemuxSegment *segment;
4739 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4743 /* update the current segment */
4744 stream->segment_index = seg_idx;
4746 /* get the segment */
4747 segment = &stream->segments[seg_idx];
4749 if (G_UNLIKELY (offset < segment->time)) {
4750 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4751 GST_TIME_ARGS (segment->time));
4755 /* segment lies beyond total indicated duration */
4756 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4757 segment->time > qtdemux->segment.duration)) {
4758 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4759 " < segment->time %" GST_TIME_FORMAT,
4760 GST_TIME_ARGS (qtdemux->segment.duration),
4761 GST_TIME_ARGS (segment->time));
4765 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4766 &start, &stop, &time);
4768 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4769 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4770 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4772 /* combine global rate with that of the segment */
4773 rate = segment->rate * qtdemux->segment.rate;
4775 /* Copy flags from main segment */
4776 stream->segment.flags = qtdemux->segment.flags;
4778 /* update the segment values used for clipping */
4779 stream->segment.offset = qtdemux->segment.offset;
4780 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4781 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4782 stream->segment.rate = rate;
4783 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4784 stream->cslg_shift);
4785 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4786 stream->cslg_shift);
4787 stream->segment.time = time;
4788 stream->segment.position = stream->segment.start;
4790 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4793 /* now prepare and send the segment */
4795 event = gst_event_new_segment (&stream->segment);
4796 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4797 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4799 gst_pad_push_event (stream->pad, event);
4800 /* assume we can send more data now */
4801 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4802 /* clear to send tags on this pad now */
4803 gst_qtdemux_push_tags (qtdemux, stream);
4814 /* activate the given segment number @seg_idx of @stream at time @offset.
4815 * @offset is an absolute global position over all the segments.
4817 * This will push out a NEWSEGMENT event with the right values and
4818 * position the stream index to the first decodable sample before
4822 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4823 guint32 seg_idx, GstClockTime offset)
4825 QtDemuxSegment *segment;
4826 guint32 index, kf_index;
4827 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4829 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4830 seg_idx, GST_TIME_ARGS (offset));
4832 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4836 segment = &stream->segments[stream->segment_index];
4838 /* in the fragmented case, we pick a fragment that starts before our
4839 * desired position and rely on downstream to wait for a keyframe
4840 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4841 * tfra entries tells us which trun/sample the key unit is in, but we don't
4842 * make use of this additional information at the moment) */
4843 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4844 stream->to_sample = G_MAXUINT32;
4847 /* well, it will be taken care of below */
4848 qtdemux->fragmented_seek_pending = FALSE;
4849 /* FIXME ideally the do_fragmented_seek can be done right here,
4850 * rather than at loop level
4851 * (which might even allow handling edit lists in a fragmented file) */
4854 /* We don't need to look for a sample in push-based */
4855 if (!qtdemux->pullbased)
4858 /* and move to the keyframe before the indicated media time of the
4860 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4861 if (qtdemux->segment.rate >= 0) {
4862 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4863 stream->to_sample = G_MAXUINT32;
4864 GST_DEBUG_OBJECT (stream->pad,
4865 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4866 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4867 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4869 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4870 stream->to_sample = index;
4871 GST_DEBUG_OBJECT (stream->pad,
4872 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4873 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4874 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4877 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4878 "this is an empty segment");
4882 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4883 * encountered an error and printed a message so we return appropriately */
4887 /* we're at the right spot */
4888 if (index == stream->sample_index) {
4889 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4893 /* find keyframe of the target index */
4894 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4897 /* indent does stupid stuff with stream->samples[].timestamp */
4899 /* if we move forwards, we don't have to go back to the previous
4900 * keyframe since we already sent that. We can also just jump to
4901 * the keyframe right before the target index if there is one. */
4902 if (index > stream->sample_index) {
4903 /* moving forwards check if we move past a keyframe */
4904 if (kf_index > stream->sample_index) {
4905 GST_DEBUG_OBJECT (stream->pad,
4906 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4907 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4908 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4909 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4911 GST_DEBUG_OBJECT (stream->pad,
4912 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4913 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4914 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4917 GST_DEBUG_OBJECT (stream->pad,
4918 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4919 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4920 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4921 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4929 /* prepare to get the current sample of @stream, getting essential values.
4931 * This function will also prepare and send the segment when needed.
4933 * Return FALSE if the stream is EOS.
4938 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4939 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4940 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4941 gboolean * keyframe)
4943 QtDemuxSample *sample;
4944 GstClockTime time_position;
4947 g_return_val_if_fail (stream != NULL, FALSE);
4949 time_position = stream->time_position;
4950 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4953 seg_idx = stream->segment_index;
4954 if (G_UNLIKELY (seg_idx == -1)) {
4955 /* find segment corresponding to time_position if we are looking
4957 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4960 /* different segment, activate it, sample_index will be set. */
4961 if (G_UNLIKELY (stream->segment_index != seg_idx))
4962 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4964 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4966 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4968 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4969 " prepare empty sample");
4972 *pts = *dts = time_position;
4973 *duration = seg->duration - (time_position - seg->time);
4980 if (stream->sample_index == -1)
4981 stream->sample_index = 0;
4983 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4984 stream->sample_index, stream->n_samples);
4986 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4987 if (!qtdemux->fragmented)
4990 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4994 GST_OBJECT_LOCK (qtdemux);
4995 flow = qtdemux_add_fragmented_samples (qtdemux);
4996 GST_OBJECT_UNLOCK (qtdemux);
4998 if (flow != GST_FLOW_OK)
5001 while (stream->sample_index >= stream->n_samples);
5004 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5005 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5006 stream->sample_index);
5010 /* now get the info for the sample we're at */
5011 sample = &stream->samples[stream->sample_index];
5013 *dts = QTSAMPLE_DTS (stream, sample);
5014 *pts = QTSAMPLE_PTS (stream, sample);
5015 *offset = sample->offset;
5016 *size = sample->size;
5017 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5018 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5025 stream->time_position = GST_CLOCK_TIME_NONE;
5030 /* move to the next sample in @stream.
5032 * Moves to the next segment when needed.
5035 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5037 QtDemuxSample *sample;
5038 QtDemuxSegment *segment;
5040 /* get current segment */
5041 segment = &stream->segments[stream->segment_index];
5043 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5044 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5048 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5049 /* Mark the stream as EOS */
5050 GST_DEBUG_OBJECT (qtdemux,
5051 "reached max allowed sample %u, mark EOS", stream->to_sample);
5052 stream->time_position = GST_CLOCK_TIME_NONE;
5056 /* move to next sample */
5057 stream->sample_index++;
5058 stream->offset_in_sample = 0;
5060 /* reached the last sample, we need the next segment */
5061 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5064 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5065 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5066 stream->sample_index);
5070 /* get next sample */
5071 sample = &stream->samples[stream->sample_index];
5073 /* see if we are past the segment */
5074 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5077 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5078 /* inside the segment, update time_position, looks very familiar to
5079 * GStreamer segments, doesn't it? */
5080 stream->time_position =
5081 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5083 /* not yet in segment, time does not yet increment. This means
5084 * that we are still prerolling keyframes to the decoder so it can
5085 * decode the first sample of the segment. */
5086 stream->time_position = segment->time;
5090 /* move to the next segment */
5093 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5095 if (stream->segment_index == stream->n_segments - 1) {
5096 /* are we at the end of the last segment, we're EOS */
5097 stream->time_position = GST_CLOCK_TIME_NONE;
5099 /* else we're only at the end of the current segment */
5100 stream->time_position = segment->stop_time;
5102 /* make sure we select a new segment */
5104 /* accumulate previous segments */
5105 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5106 stream->accumulated_base +=
5107 (stream->segment.stop -
5108 stream->segment.start) / ABS (stream->segment.rate);
5110 stream->segment_index = -1;
5115 gst_qtdemux_sync_streams (GstQTDemux * demux)
5119 if (demux->n_streams <= 1)
5122 for (i = 0; i < demux->n_streams; i++) {
5123 QtDemuxStream *stream;
5124 GstClockTime end_time;
5126 stream = demux->streams[i];
5131 /* TODO advance time on subtitle streams here, if any some day */
5133 /* some clips/trailers may have unbalanced streams at the end,
5134 * so send EOS on shorter stream to prevent stalling others */
5136 /* do not mess with EOS if SEGMENT seeking */
5137 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5140 if (demux->pullbased) {
5141 /* loop mode is sample time based */
5142 if (!STREAM_IS_EOS (stream))
5145 /* push mode is byte position based */
5146 if (stream->n_samples &&
5147 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5151 if (stream->sent_eos)
5154 /* only act if some gap */
5155 end_time = stream->segments[stream->n_segments - 1].stop_time;
5156 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5157 ", stream end: %" GST_TIME_FORMAT,
5158 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5159 if (GST_CLOCK_TIME_IS_VALID (end_time)
5160 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5163 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5164 GST_PAD_NAME (stream->pad));
5165 stream->sent_eos = TRUE;
5166 event = gst_event_new_eos ();
5167 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5168 gst_event_set_seqnum (event, demux->segment_seqnum);
5169 gst_pad_push_event (stream->pad, event);
5174 /* EOS and NOT_LINKED need to be combined. This means that we return:
5176 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5177 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5179 static GstFlowReturn
5180 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5183 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5186 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5189 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5191 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5195 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5196 * completely clipped
5198 * Should be used only with raw buffers */
5200 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5203 guint64 start, stop, cstart, cstop, diff;
5204 GstClockTime pts, duration;
5206 gint num_rate, denom_rate;
5211 osize = size = gst_buffer_get_size (buf);
5214 /* depending on the type, setup the clip parameters */
5215 if (stream->subtype == FOURCC_soun) {
5216 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5217 num_rate = GST_SECOND;
5218 denom_rate = (gint) CUR_STREAM (stream)->rate;
5220 } else if (stream->subtype == FOURCC_vide) {
5222 num_rate = CUR_STREAM (stream)->fps_n;
5223 denom_rate = CUR_STREAM (stream)->fps_d;
5228 if (frame_size <= 0)
5229 goto bad_frame_size;
5231 /* we can only clip if we have a valid pts */
5232 pts = GST_BUFFER_PTS (buf);
5233 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5236 duration = GST_BUFFER_DURATION (buf);
5238 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5240 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5244 stop = start + duration;
5246 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5247 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5250 /* see if some clipping happened */
5251 diff = cstart - start;
5257 /* bring clipped time to samples and to bytes */
5258 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5261 GST_DEBUG_OBJECT (qtdemux,
5262 "clipping start to %" GST_TIME_FORMAT " %"
5263 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5269 diff = stop - cstop;
5274 /* bring clipped time to samples and then to bytes */
5275 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5277 GST_DEBUG_OBJECT (qtdemux,
5278 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5279 " bytes", GST_TIME_ARGS (cstop), diff);
5284 if (offset != 0 || size != osize)
5285 gst_buffer_resize (buf, offset, size);
5287 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5288 GST_BUFFER_PTS (buf) = pts;
5289 GST_BUFFER_DURATION (buf) = duration;
5293 /* dropped buffer */
5296 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5301 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5306 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5311 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5312 gst_buffer_unref (buf);
5318 gst_qtdemux_align_buffer (GstQTDemux * demux,
5319 GstBuffer * buffer, gsize alignment)
5323 gst_buffer_map (buffer, &map, GST_MAP_READ);
5325 if (map.size < sizeof (guintptr)) {
5326 gst_buffer_unmap (buffer, &map);
5330 if (((guintptr) map.data) & (alignment - 1)) {
5331 GstBuffer *new_buffer;
5332 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5334 new_buffer = gst_buffer_new_allocate (NULL,
5335 gst_buffer_get_size (buffer), ¶ms);
5337 /* Copy data "by hand", so ensure alignment is kept: */
5338 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5340 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5341 GST_DEBUG_OBJECT (demux,
5342 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5345 gst_buffer_unmap (buffer, &map);
5346 gst_buffer_unref (buffer);
5351 gst_buffer_unmap (buffer, &map);
5355 /* the input buffer metadata must be writable,
5356 * but time/duration etc not yet set and need not be preserved */
5358 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5365 /* not many cases for now */
5366 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5367 /* send a one time dvd clut event */
5368 if (stream->pending_event && stream->pad)
5369 gst_pad_push_event (stream->pad, stream->pending_event);
5370 stream->pending_event = NULL;
5373 if (G_UNLIKELY (stream->subtype != FOURCC_text
5374 && stream->subtype != FOURCC_sbtl &&
5375 stream->subtype != FOURCC_subp)) {
5379 gst_buffer_map (buf, &map, GST_MAP_READ);
5381 /* empty buffer is sent to terminate previous subtitle */
5382 if (map.size <= 2) {
5383 gst_buffer_unmap (buf, &map);
5384 gst_buffer_unref (buf);
5387 if (stream->subtype == FOURCC_subp) {
5388 /* That's all the processing needed for subpictures */
5389 gst_buffer_unmap (buf, &map);
5393 nsize = GST_READ_UINT16_BE (map.data);
5394 nsize = MIN (nsize, map.size - 2);
5396 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5399 /* takes care of UTF-8 validation or UTF-16 recognition,
5400 * no other encoding expected */
5401 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5402 gst_buffer_unmap (buf, &map);
5404 gst_buffer_unref (buf);
5405 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5407 /* this should not really happen unless the subtitle is corrupted */
5408 gst_buffer_unref (buf);
5412 /* FIXME ? convert optional subsequent style info to markup */
5417 /* Sets a buffer's attributes properly and pushes it downstream.
5418 * Also checks for additional actions and custom processing that may
5419 * need to be done first.
5421 static GstFlowReturn
5422 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5423 QtDemuxStream * stream, GstBuffer * buf,
5424 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5425 gboolean keyframe, GstClockTime position, guint64 byte_position)
5427 GstFlowReturn ret = GST_FLOW_OK;
5429 /* offset the timestamps according to the edit list */
5431 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5435 gst_buffer_map (buf, &map, GST_MAP_READ);
5436 url = g_strndup ((gchar *) map.data, map.size);
5437 gst_buffer_unmap (buf, &map);
5438 if (url != NULL && strlen (url) != 0) {
5439 /* we have RTSP redirect now */
5440 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5441 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5442 gst_structure_new ("redirect",
5443 "new-location", G_TYPE_STRING, url, NULL)));
5444 qtdemux->posted_redirect = TRUE;
5446 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5452 /* position reporting */
5453 if (qtdemux->segment.rate >= 0) {
5454 qtdemux->segment.position = position;
5455 gst_qtdemux_sync_streams (qtdemux);
5458 if (G_UNLIKELY (!stream->pad)) {
5459 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5460 gst_buffer_unref (buf);
5464 /* send out pending buffers */
5465 while (stream->buffers) {
5466 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5468 if (G_UNLIKELY (stream->discont)) {
5469 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5470 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5471 stream->discont = FALSE;
5473 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5476 if (stream->alignment > 1)
5477 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5478 gst_pad_push (stream->pad, buffer);
5480 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5483 /* we're going to modify the metadata */
5484 buf = gst_buffer_make_writable (buf);
5486 if (G_UNLIKELY (stream->need_process))
5487 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5493 GST_BUFFER_DTS (buf) = dts;
5494 GST_BUFFER_PTS (buf) = pts;
5495 GST_BUFFER_DURATION (buf) = duration;
5496 GST_BUFFER_OFFSET (buf) = -1;
5497 GST_BUFFER_OFFSET_END (buf) = -1;
5499 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5500 gst_buffer_append_memory (buf,
5501 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5503 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5504 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5507 if (G_UNLIKELY (qtdemux->element_index)) {
5508 GstClockTime stream_time;
5511 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5513 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5514 GST_LOG_OBJECT (qtdemux,
5515 "adding association %" GST_TIME_FORMAT "-> %"
5516 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5517 gst_index_add_association (qtdemux->element_index,
5519 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5520 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5521 GST_FORMAT_BYTES, byte_position, NULL);
5526 if (stream->need_clip)
5527 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5529 if (G_UNLIKELY (buf == NULL))
5532 if (G_UNLIKELY (stream->discont)) {
5533 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5534 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5535 stream->discont = FALSE;
5537 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5541 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5542 stream->on_keyframe = FALSE;
5544 stream->on_keyframe = TRUE;
5548 GST_LOG_OBJECT (qtdemux,
5549 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5550 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5551 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5552 GST_PAD_NAME (stream->pad));
5554 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5555 GstStructure *crypto_info;
5556 QtDemuxCencSampleSetInfo *info =
5557 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5561 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5562 gst_pad_push_event (stream->pad, event);
5565 if (info->crypto_info == NULL) {
5566 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5567 gst_buffer_unref (buf);
5571 /* The end of the crypto_info array matches our n_samples position,
5572 * so count backward from there */
5573 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5574 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5575 /* steal structure from array */
5576 crypto_info = g_ptr_array_index (info->crypto_info, index);
5577 g_ptr_array_index (info->crypto_info, index) = NULL;
5578 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5579 info->crypto_info->len);
5580 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5581 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5583 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5584 index, stream->sample_index);
5588 if (stream->alignment > 1)
5589 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5591 ret = gst_pad_push (stream->pad, buf);
5593 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5594 /* mark position in stream, we'll need this to know when to send GAP event */
5595 stream->segment.position = pts + duration;
5602 static const QtDemuxRandomAccessEntry *
5603 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5604 GstClockTime pos, gboolean after)
5606 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5607 guint n_entries = stream->n_ra_entries;
5610 /* we assume the table is sorted */
5611 for (i = 0; i < n_entries; ++i) {
5612 if (entries[i].ts > pos)
5616 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5617 * probably okay to assume that the index lists the very first fragment */
5624 return &entries[i - 1];
5628 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5630 const QtDemuxRandomAccessEntry *best_entry = NULL;
5633 GST_OBJECT_LOCK (qtdemux);
5635 g_assert (qtdemux->n_streams > 0);
5637 /* first see if we can determine where to go to using mfra,
5638 * before we start clearing things */
5639 for (i = 0; i < qtdemux->n_streams; i++) {
5640 const QtDemuxRandomAccessEntry *entry;
5641 QtDemuxStream *stream;
5642 gboolean is_audio_or_video;
5644 stream = qtdemux->streams[i];
5646 if (stream->ra_entries == NULL)
5649 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5650 is_audio_or_video = TRUE;
5652 is_audio_or_video = FALSE;
5655 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5656 stream->time_position, !is_audio_or_video);
5658 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5659 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5661 stream->pending_seek = entry;
5663 /* decide position to jump to just based on audio/video tracks, not subs */
5664 if (!is_audio_or_video)
5667 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5671 /* no luck, will handle seek otherwise */
5672 if (best_entry == NULL) {
5673 GST_OBJECT_UNLOCK (qtdemux);
5677 /* ok, now we can prepare for processing as of located moof */
5678 for (i = 0; i < qtdemux->n_streams; i++) {
5679 QtDemuxStream *stream;
5681 stream = qtdemux->streams[i];
5683 g_free (stream->samples);
5684 stream->samples = NULL;
5685 stream->n_samples = 0;
5686 stream->stbl_index = -1; /* no samples have yet been parsed */
5687 stream->sample_index = -1;
5689 if (stream->protection_scheme_info) {
5690 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5691 if (stream->protection_scheme_type == FOURCC_cenc) {
5692 QtDemuxCencSampleSetInfo *info =
5693 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5694 if (info->crypto_info) {
5695 g_ptr_array_free (info->crypto_info, TRUE);
5696 info->crypto_info = NULL;
5702 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5703 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5704 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5705 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5707 qtdemux->moof_offset = best_entry->moof_offset;
5709 qtdemux_add_fragmented_samples (qtdemux);
5711 GST_OBJECT_UNLOCK (qtdemux);
5715 static GstFlowReturn
5716 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5718 GstFlowReturn ret = GST_FLOW_OK;
5719 GstBuffer *buf = NULL;
5720 QtDemuxStream *stream;
5721 GstClockTime min_time;
5723 GstClockTime dts = GST_CLOCK_TIME_NONE;
5724 GstClockTime pts = GST_CLOCK_TIME_NONE;
5725 GstClockTime duration = 0;
5726 gboolean keyframe = FALSE;
5727 guint sample_size = 0;
5733 gst_qtdemux_push_pending_newsegment (qtdemux);
5735 if (qtdemux->fragmented_seek_pending) {
5736 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5737 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
5738 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5739 qtdemux->fragmented_seek_pending = FALSE;
5741 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
5745 /* Figure out the next stream sample to output, min_time is expressed in
5746 * global time and runs over the edit list segments. */
5747 min_time = G_MAXUINT64;
5749 for (i = 0; i < qtdemux->n_streams; i++) {
5750 GstClockTime position;
5752 stream = qtdemux->streams[i];
5753 position = stream->time_position;
5755 /* position of -1 is EOS */
5756 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5757 min_time = position;
5762 if (G_UNLIKELY (index == -1)) {
5763 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5767 /* check for segment end */
5768 if (G_UNLIKELY (qtdemux->segment.stop != -1
5769 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5770 || (qtdemux->segment.rate < 0
5771 && qtdemux->segment.start > min_time))
5772 && qtdemux->streams[index]->on_keyframe)) {
5773 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5774 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5778 /* gap events for subtitle streams */
5779 for (i = 0; i < qtdemux->n_streams; i++) {
5780 stream = qtdemux->streams[i];
5781 if (stream->pad && (stream->subtype == FOURCC_subp
5782 || stream->subtype == FOURCC_text
5783 || stream->subtype == FOURCC_sbtl)) {
5784 /* send one second gap events until the stream catches up */
5785 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5786 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5787 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5788 stream->segment.position + GST_SECOND < min_time) {
5790 gst_event_new_gap (stream->segment.position, GST_SECOND);
5791 gst_pad_push_event (stream->pad, gap);
5792 stream->segment.position += GST_SECOND;
5797 stream = qtdemux->streams[index];
5798 /* fetch info for the current sample of this stream */
5799 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5800 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5803 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
5804 if (stream->new_caps) {
5805 gst_qtdemux_configure_stream (qtdemux, stream);
5806 qtdemux_do_allocation (qtdemux, stream);
5809 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5810 if (G_UNLIKELY (qtdemux->
5811 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5812 if (stream->subtype == FOURCC_vide && !keyframe) {
5813 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5818 GST_DEBUG_OBJECT (qtdemux,
5819 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5820 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5821 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5822 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5824 if (G_UNLIKELY (empty)) {
5825 /* empty segment, push a gap if there's a second or more
5826 * difference and move to the next one */
5827 if ((pts + duration - stream->segment.position) >= GST_SECOND)
5828 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5829 stream->segment.position = pts + duration;
5833 /* hmm, empty sample, skip and move to next sample */
5834 if (G_UNLIKELY (sample_size <= 0))
5837 /* last pushed sample was out of boundary, goto next sample */
5838 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5841 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5844 GST_DEBUG_OBJECT (qtdemux,
5845 "size %d larger than stream max_buffer_size %d, trimming",
5846 sample_size, stream->max_buffer_size);
5848 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5851 if (qtdemux->cenc_aux_info_offset > 0) {
5854 GstBuffer *aux_info = NULL;
5856 /* pull the data stored before the sample */
5858 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5859 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5860 if (G_UNLIKELY (ret != GST_FLOW_OK))
5862 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5863 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5864 gst_byte_reader_init (&br, map.data + 8, map.size);
5865 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5866 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5867 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5868 gst_buffer_unmap (aux_info, &map);
5869 gst_buffer_unref (aux_info);
5870 ret = GST_FLOW_ERROR;
5873 gst_buffer_unmap (aux_info, &map);
5874 gst_buffer_unref (aux_info);
5877 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5880 if (stream->use_allocator) {
5881 /* if we have a per-stream allocator, use it */
5882 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5885 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5887 if (G_UNLIKELY (ret != GST_FLOW_OK))
5890 if (size != sample_size) {
5891 pts += gst_util_uint64_scale_int (GST_SECOND,
5892 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5895 gst_util_uint64_scale_int (GST_SECOND,
5896 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5899 gst_util_uint64_scale_int (GST_SECOND,
5900 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
5903 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5904 dts, pts, duration, keyframe, min_time, offset);
5906 if (size != sample_size) {
5907 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5908 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5910 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5912 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
5913 if (time_position >= segment->media_start) {
5914 /* inside the segment, update time_position, looks very familiar to
5915 * GStreamer segments, doesn't it? */
5916 stream->time_position = (time_position - segment->media_start) +
5919 /* not yet in segment, time does not yet increment. This means
5920 * that we are still prerolling keyframes to the decoder so it can
5921 * decode the first sample of the segment. */
5922 stream->time_position = segment->time;
5927 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5928 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5929 * we have no more data for the pad to push */
5930 if (ret == GST_FLOW_EOS)
5933 stream->offset_in_sample += size;
5934 if (stream->offset_in_sample >= sample_size) {
5935 gst_qtdemux_advance_sample (qtdemux, stream);
5940 gst_qtdemux_advance_sample (qtdemux, stream);
5948 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5954 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5955 /* EOS will be raised if all are EOS */
5962 gst_qtdemux_loop (GstPad * pad)
5964 GstQTDemux *qtdemux;
5968 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5970 cur_offset = qtdemux->offset;
5971 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5972 cur_offset, qt_demux_state_string (qtdemux->state));
5974 switch (qtdemux->state) {
5975 case QTDEMUX_STATE_INITIAL:
5976 case QTDEMUX_STATE_HEADER:
5977 ret = gst_qtdemux_loop_state_header (qtdemux);
5979 case QTDEMUX_STATE_MOVIE:
5980 ret = gst_qtdemux_loop_state_movie (qtdemux);
5981 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5982 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5990 /* if something went wrong, pause */
5991 if (ret != GST_FLOW_OK)
5995 gst_object_unref (qtdemux);
6001 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6002 (NULL), ("streaming stopped, invalid state"));
6003 gst_pad_pause_task (pad);
6004 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6009 const gchar *reason = gst_flow_get_name (ret);
6011 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6013 gst_pad_pause_task (pad);
6015 /* fatal errors need special actions */
6017 if (ret == GST_FLOW_EOS) {
6018 if (qtdemux->n_streams == 0) {
6019 /* we have no streams, post an error */
6020 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6022 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6025 if ((stop = qtdemux->segment.stop) == -1)
6026 stop = qtdemux->segment.duration;
6028 if (qtdemux->segment.rate >= 0) {
6029 GstMessage *message;
6032 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6033 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6034 GST_FORMAT_TIME, stop);
6035 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6036 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6037 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6038 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6040 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6041 gst_qtdemux_push_event (qtdemux, event);
6043 GstMessage *message;
6046 /* For Reverse Playback */
6047 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6048 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6049 GST_FORMAT_TIME, qtdemux->segment.start);
6050 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6051 qtdemux->segment.start);
6052 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6053 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6054 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6056 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6057 gst_qtdemux_push_event (qtdemux, event);
6062 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6063 event = gst_event_new_eos ();
6064 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6065 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6066 gst_qtdemux_push_event (qtdemux, event);
6068 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6069 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6070 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6079 * Returns if there are samples to be played.
6082 has_next_entry (GstQTDemux * demux)
6084 QtDemuxStream *stream;
6087 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6089 for (i = 0; i < demux->n_streams; i++) {
6090 stream = demux->streams[i];
6092 if (stream->sample_index == -1) {
6093 stream->sample_index = 0;
6094 stream->offset_in_sample = 0;
6097 if (stream->sample_index >= stream->n_samples) {
6098 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6101 GST_DEBUG_OBJECT (demux, "Found a sample");
6105 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6112 * Returns the size of the first entry at the current offset.
6113 * If -1, there are none (which means EOS or empty file).
6116 next_entry_size (GstQTDemux * demux)
6118 QtDemuxStream *stream;
6121 guint64 smalloffs = (guint64) - 1;
6122 QtDemuxSample *sample;
6124 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6127 for (i = 0; i < demux->n_streams; i++) {
6128 stream = demux->streams[i];
6130 if (stream->sample_index == -1) {
6131 stream->sample_index = 0;
6132 stream->offset_in_sample = 0;
6135 if (stream->sample_index >= stream->n_samples) {
6136 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6140 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6141 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6142 stream->sample_index);
6146 sample = &stream->samples[stream->sample_index];
6148 GST_LOG_OBJECT (demux,
6149 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6150 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6151 sample->offset, sample->size);
6153 if (((smalloffs == -1)
6154 || (sample->offset < smalloffs)) && (sample->size)) {
6156 smalloffs = sample->offset;
6160 GST_LOG_OBJECT (demux,
6161 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6162 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6167 stream = demux->streams[smallidx];
6168 sample = &stream->samples[stream->sample_index];
6170 if (sample->offset >= demux->offset) {
6171 demux->todrop = sample->offset - demux->offset;
6172 return sample->size + demux->todrop;
6175 GST_DEBUG_OBJECT (demux,
6176 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6181 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6183 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6185 gst_element_post_message (GST_ELEMENT_CAST (demux),
6186 gst_message_new_element (GST_OBJECT_CAST (demux),
6187 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6191 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6196 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6199 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6200 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6201 GST_SEEK_TYPE_NONE, -1);
6203 /* store seqnum to drop flush events, they don't need to reach downstream */
6204 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6205 res = gst_pad_push_event (demux->sinkpad, event);
6206 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6211 /* check for seekable upstream, above and beyond a mere query */
6213 gst_qtdemux_check_seekability (GstQTDemux * demux)
6216 gboolean seekable = FALSE;
6217 gint64 start = -1, stop = -1;
6219 if (demux->upstream_size)
6222 if (demux->upstream_format_is_time)
6225 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6226 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6227 GST_DEBUG_OBJECT (demux, "seeking query failed");
6231 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6233 /* try harder to query upstream size if we didn't get it the first time */
6234 if (seekable && stop == -1) {
6235 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6236 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6239 /* if upstream doesn't know the size, it's likely that it's not seekable in
6240 * practice even if it technically may be seekable */
6241 if (seekable && (start != 0 || stop <= start)) {
6242 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6247 gst_query_unref (query);
6249 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6250 G_GUINT64_FORMAT ")", seekable, start, stop);
6251 demux->upstream_seekable = seekable;
6252 demux->upstream_size = seekable ? stop : -1;
6256 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6258 g_return_if_fail (bytes <= demux->todrop);
6260 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6261 gst_adapter_flush (demux->adapter, bytes);
6262 demux->neededbytes -= bytes;
6263 demux->offset += bytes;
6264 demux->todrop -= bytes;
6268 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6270 if (G_UNLIKELY (demux->pending_newsegment)) {
6273 gst_qtdemux_push_pending_newsegment (demux);
6274 /* clear to send tags on all streams */
6275 for (i = 0; i < demux->n_streams; i++) {
6276 QtDemuxStream *stream;
6277 stream = demux->streams[i];
6278 gst_qtdemux_push_tags (demux, stream);
6279 if (CUR_STREAM (stream)->sparse) {
6280 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6281 gst_pad_push_event (stream->pad,
6282 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6289 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6290 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6292 GstClockTime ts, dur;
6297 stream->segments[segment_index].duration - (pos -
6298 stream->segments[segment_index].time);
6299 gap = gst_event_new_gap (ts, dur);
6300 stream->time_position += dur;
6302 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6303 "segment: %" GST_PTR_FORMAT, gap);
6304 gst_pad_push_event (stream->pad, gap);
6308 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6309 QtDemuxStream * stream)
6313 /* Push any initial gap segments before proceeding to the
6315 for (i = 0; i < stream->n_segments; i++) {
6316 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6318 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6319 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6320 stream->time_position);
6322 /* Only support empty segment at the beginning followed by
6323 * one non-empty segment, this was checked when parsing the
6324 * edts atom, arriving here is unexpected */
6325 g_assert (i + 1 == stream->n_segments);
6331 static GstFlowReturn
6332 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6336 demux = GST_QTDEMUX (parent);
6338 GST_DEBUG_OBJECT (demux,
6339 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6340 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6341 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6342 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6343 gst_buffer_get_size (inbuf), demux->offset);
6345 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6346 gboolean is_gap_input = FALSE;
6349 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6351 for (i = 0; i < demux->n_streams; i++) {
6352 demux->streams[i]->discont = TRUE;
6355 /* Check if we can land back on our feet in the case where upstream is
6356 * handling the seeking/pushing of samples with gaps in between (like
6357 * in the case of trick-mode DASH for example) */
6358 if (demux->upstream_format_is_time
6359 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6361 for (i = 0; i < demux->n_streams; i++) {
6363 GST_LOG_OBJECT (demux,
6364 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6365 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6367 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6368 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6370 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6371 GST_LOG_OBJECT (demux,
6372 "Checking if sample %d from stream %d is valid (offset:%"
6373 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6374 sample->offset, sample->size);
6375 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6376 GST_LOG_OBJECT (demux,
6377 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6379 is_gap_input = TRUE;
6380 /* We can go back to standard playback mode */
6381 demux->state = QTDEMUX_STATE_MOVIE;
6382 /* Remember which sample this stream is at */
6383 demux->streams[i]->sample_index = res;
6384 /* Finally update all push-based values to the expected values */
6385 demux->neededbytes = demux->streams[i]->samples[res].size;
6386 demux->offset = GST_BUFFER_OFFSET (inbuf);
6388 demux->mdatsize - demux->offset + demux->mdatoffset;
6393 if (!is_gap_input) {
6394 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6395 /* Reset state if it's a real discont */
6396 demux->neededbytes = 16;
6397 demux->state = QTDEMUX_STATE_INITIAL;
6398 demux->offset = GST_BUFFER_OFFSET (inbuf);
6399 gst_adapter_clear (demux->adapter);
6402 /* Reverse fragmented playback, need to flush all we have before
6403 * consuming a new fragment.
6404 * The samples array have the timestamps calculated by accumulating the
6405 * durations but this won't work for reverse playback of fragments as
6406 * the timestamps of a subsequent fragment should be smaller than the
6407 * previously received one. */
6408 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6409 gst_qtdemux_process_adapter (demux, TRUE);
6410 for (i = 0; i < demux->n_streams; i++)
6411 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6415 gst_adapter_push (demux->adapter, inbuf);
6417 GST_DEBUG_OBJECT (demux,
6418 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6419 demux->neededbytes, gst_adapter_available (demux->adapter));
6421 return gst_qtdemux_process_adapter (demux, FALSE);
6424 static GstFlowReturn
6425 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6427 GstFlowReturn ret = GST_FLOW_OK;
6429 /* we never really mean to buffer that much */
6430 if (demux->neededbytes == -1) {
6434 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6435 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6437 #ifndef GST_DISABLE_GST_DEBUG
6439 guint64 discont_offset, distance_from_discont;
6441 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6442 distance_from_discont =
6443 gst_adapter_distance_from_discont (demux->adapter);
6445 GST_DEBUG_OBJECT (demux,
6446 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6447 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6448 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6449 demux->offset, discont_offset, distance_from_discont);
6453 switch (demux->state) {
6454 case QTDEMUX_STATE_INITIAL:{
6459 gst_qtdemux_check_seekability (demux);
6461 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6463 /* get fourcc/length, set neededbytes */
6464 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6466 gst_adapter_unmap (demux->adapter);
6468 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6469 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6471 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6472 (_("This file is invalid and cannot be played.")),
6473 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6474 GST_FOURCC_ARGS (fourcc)));
6475 ret = GST_FLOW_ERROR;
6478 if (fourcc == FOURCC_mdat) {
6479 gint next_entry = next_entry_size (demux);
6480 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6481 /* we have the headers, start playback */
6482 demux->state = QTDEMUX_STATE_MOVIE;
6483 demux->neededbytes = next_entry;
6484 demux->mdatleft = size;
6485 demux->mdatsize = demux->mdatleft;
6487 /* no headers yet, try to get them */
6490 guint64 old, target;
6493 old = demux->offset;
6494 target = old + size;
6496 /* try to jump over the atom with a seek */
6497 /* only bother if it seems worth doing so,
6498 * and avoids possible upstream/server problems */
6499 if (demux->upstream_seekable &&
6500 demux->upstream_size > 4 * (1 << 20)) {
6501 res = qtdemux_seek_offset (demux, target);
6503 GST_DEBUG_OBJECT (demux, "skipping seek");
6508 GST_DEBUG_OBJECT (demux, "seek success");
6509 /* remember the offset fo the first mdat so we can seek back to it
6510 * after we have the headers */
6511 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6512 demux->first_mdat = old;
6513 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6516 /* seek worked, continue reading */
6517 demux->offset = target;
6518 demux->neededbytes = 16;
6519 demux->state = QTDEMUX_STATE_INITIAL;
6521 /* seek failed, need to buffer */
6522 demux->offset = old;
6523 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6524 /* there may be multiple mdat (or alike) buffers */
6526 if (demux->mdatbuffer)
6527 bs = gst_buffer_get_size (demux->mdatbuffer);
6530 if (size + bs > 10 * (1 << 20))
6532 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6533 demux->neededbytes = size;
6534 if (!demux->mdatbuffer)
6535 demux->mdatoffset = demux->offset;
6538 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6539 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6540 (_("This file is invalid and cannot be played.")),
6541 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6542 GST_FOURCC_ARGS (fourcc), size));
6543 ret = GST_FLOW_ERROR;
6546 /* this means we already started buffering and still no moov header,
6547 * let's continue buffering everything till we get moov */
6548 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6549 || fourcc == FOURCC_moof))
6551 demux->neededbytes = size;
6552 demux->state = QTDEMUX_STATE_HEADER;
6556 case QTDEMUX_STATE_HEADER:{
6560 GST_DEBUG_OBJECT (demux, "In header");
6562 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6564 /* parse the header */
6565 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6567 if (fourcc == FOURCC_moov) {
6570 /* in usual fragmented setup we could try to scan for more
6571 * and end up at the the moov (after mdat) again */
6572 if (demux->got_moov && demux->n_streams > 0 &&
6574 || demux->last_moov_offset == demux->offset)) {
6575 GST_DEBUG_OBJECT (demux,
6576 "Skipping moov atom as we have (this) one already");
6578 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6580 if (demux->got_moov && demux->fragmented) {
6581 GST_DEBUG_OBJECT (demux,
6582 "Got a second moov, clean up data from old one");
6583 if (demux->moov_node_compressed) {
6584 g_node_destroy (demux->moov_node_compressed);
6585 if (demux->moov_node)
6586 g_free (demux->moov_node->data);
6588 demux->moov_node_compressed = NULL;
6589 if (demux->moov_node)
6590 g_node_destroy (demux->moov_node);
6591 demux->moov_node = NULL;
6593 /* prepare newsegment to send when streaming actually starts */
6594 if (!demux->pending_newsegment) {
6595 demux->pending_newsegment =
6596 gst_event_new_segment (&demux->segment);
6597 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6598 gst_event_set_seqnum (demux->pending_newsegment,
6599 demux->segment_seqnum);
6603 demux->last_moov_offset = demux->offset;
6605 qtdemux_parse_moov (demux, data, demux->neededbytes);
6606 qtdemux_node_dump (demux, demux->moov_node);
6607 qtdemux_parse_tree (demux);
6608 qtdemux_prepare_streams (demux);
6609 if (!demux->got_moov)
6610 qtdemux_expose_streams (demux);
6613 for (n = 0; n < demux->n_streams; n++) {
6614 QtDemuxStream *stream = demux->streams[n];
6616 gst_qtdemux_configure_stream (demux, stream);
6620 demux->got_moov = TRUE;
6621 gst_qtdemux_check_send_pending_segment (demux);
6623 /* fragmented streams headers shouldn't contain edts atoms */
6624 if (!demux->fragmented) {
6625 for (n = 0; n < demux->n_streams; n++) {
6626 gst_qtdemux_stream_send_initial_gap_segments (demux,
6631 if (demux->moov_node_compressed) {
6632 g_node_destroy (demux->moov_node_compressed);
6633 g_free (demux->moov_node->data);
6635 demux->moov_node_compressed = NULL;
6636 g_node_destroy (demux->moov_node);
6637 demux->moov_node = NULL;
6638 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6640 } else if (fourcc == FOURCC_moof) {
6641 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6643 GstClockTime prev_pts;
6644 guint64 prev_offset;
6645 guint64 adapter_discont_offset, adapter_discont_dist;
6647 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6650 * The timestamp of the moof buffer is relevant as some scenarios
6651 * won't have the initial timestamp in the atoms. Whenever a new
6652 * buffer has started, we get that buffer's PTS and use it as a base
6653 * timestamp for the trun entries.
6655 * To keep track of the current buffer timestamp and starting point
6656 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6657 * from the beggining of the buffer, with the distance and demux->offset
6658 * we know if it is still the same buffer or not.
6660 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6661 prev_offset = demux->offset - dist;
6662 if (demux->fragment_start_offset == -1
6663 || prev_offset > demux->fragment_start_offset) {
6664 demux->fragment_start_offset = prev_offset;
6665 demux->fragment_start = prev_pts;
6666 GST_DEBUG_OBJECT (demux,
6667 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6668 GST_TIME_FORMAT, demux->fragment_start_offset,
6669 GST_TIME_ARGS (demux->fragment_start));
6672 /* We can't use prev_offset() here because this would require
6673 * upstream to set consistent and correct offsets on all buffers
6674 * since the discont. Nothing ever did that in the past and we
6675 * would break backwards compatibility here then.
6676 * Instead take the offset we had at the last discont and count
6677 * the bytes from there. This works with old code as there would
6678 * be no discont between moov and moof, and also works with
6679 * adaptivedemux which correctly sets offset and will set the
6680 * DISCONT flag accordingly when needed.
6682 * We also only do this for upstream TIME segments as otherwise
6683 * there are potential backwards compatibility problems with
6684 * seeking in PUSH mode and upstream providing inconsistent
6686 adapter_discont_offset =
6687 gst_adapter_offset_at_discont (demux->adapter);
6688 adapter_discont_dist =
6689 gst_adapter_distance_from_discont (demux->adapter);
6691 GST_DEBUG_OBJECT (demux,
6692 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6693 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6694 demux->offset, adapter_discont_offset, adapter_discont_dist);
6696 if (demux->upstream_format_is_time) {
6697 demux->moof_offset = adapter_discont_offset;
6698 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6699 demux->moof_offset += adapter_discont_dist;
6700 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6701 demux->moof_offset = demux->offset;
6703 demux->moof_offset = demux->offset;
6706 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6707 demux->moof_offset, NULL)) {
6708 gst_adapter_unmap (demux->adapter);
6709 ret = GST_FLOW_ERROR;
6712 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6713 if (demux->mss_mode && !demux->exposed) {
6714 if (!demux->pending_newsegment) {
6715 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6716 demux->pending_newsegment =
6717 gst_event_new_segment (&demux->segment);
6718 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6719 gst_event_set_seqnum (demux->pending_newsegment,
6720 demux->segment_seqnum);
6722 qtdemux_expose_streams (demux);
6725 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6727 } else if (fourcc == FOURCC_ftyp) {
6728 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6729 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6730 } else if (fourcc == FOURCC_uuid) {
6731 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6732 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6733 } else if (fourcc == FOURCC_sidx) {
6734 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6735 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6739 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6743 /* [free] and [skip] are padding atoms */
6744 GST_DEBUG_OBJECT (demux,
6745 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6746 GST_FOURCC_ARGS (fourcc));
6749 GST_WARNING_OBJECT (demux,
6750 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6751 GST_FOURCC_ARGS (fourcc));
6752 /* Let's jump that one and go back to initial state */
6756 gst_adapter_unmap (demux->adapter);
6759 if (demux->mdatbuffer && demux->n_streams) {
6760 gsize remaining_data_size = 0;
6762 /* the mdat was before the header */
6763 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6764 demux->n_streams, demux->mdatbuffer);
6765 /* restore our adapter/offset view of things with upstream;
6766 * put preceding buffered data ahead of current moov data.
6767 * This should also handle evil mdat, moov, mdat cases and alike */
6768 gst_adapter_flush (demux->adapter, demux->neededbytes);
6770 /* Store any remaining data after the mdat for later usage */
6771 remaining_data_size = gst_adapter_available (demux->adapter);
6772 if (remaining_data_size > 0) {
6773 g_assert (demux->restoredata_buffer == NULL);
6774 demux->restoredata_buffer =
6775 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6776 demux->restoredata_offset = demux->offset + demux->neededbytes;
6777 GST_DEBUG_OBJECT (demux,
6778 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6779 G_GUINT64_FORMAT, remaining_data_size,
6780 demux->restoredata_offset);
6783 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6784 demux->mdatbuffer = NULL;
6785 demux->offset = demux->mdatoffset;
6786 demux->neededbytes = next_entry_size (demux);
6787 demux->state = QTDEMUX_STATE_MOVIE;
6788 demux->mdatleft = gst_adapter_available (demux->adapter);
6789 demux->mdatsize = demux->mdatleft;
6791 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6792 gst_adapter_flush (demux->adapter, demux->neededbytes);
6794 /* only go back to the mdat if there are samples to play */
6795 if (demux->got_moov && demux->first_mdat != -1
6796 && has_next_entry (demux)) {
6799 /* we need to seek back */
6800 res = qtdemux_seek_offset (demux, demux->first_mdat);
6802 demux->offset = demux->first_mdat;
6804 GST_DEBUG_OBJECT (demux, "Seek back failed");
6807 demux->offset += demux->neededbytes;
6809 demux->neededbytes = 16;
6810 demux->state = QTDEMUX_STATE_INITIAL;
6815 case QTDEMUX_STATE_BUFFER_MDAT:{
6819 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6821 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6822 gst_buffer_extract (buf, 0, fourcc, 4);
6823 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6824 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6825 if (demux->mdatbuffer)
6826 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6828 demux->mdatbuffer = buf;
6829 demux->offset += demux->neededbytes;
6830 demux->neededbytes = 16;
6831 demux->state = QTDEMUX_STATE_INITIAL;
6832 gst_qtdemux_post_progress (demux, 1, 1);
6836 case QTDEMUX_STATE_MOVIE:{
6837 QtDemuxStream *stream = NULL;
6838 QtDemuxSample *sample;
6840 GstClockTime dts, pts, duration;
6843 GST_DEBUG_OBJECT (demux,
6844 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6846 if (demux->fragmented) {
6847 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6849 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6850 /* if needed data starts within this atom,
6851 * then it should not exceed this atom */
6852 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6853 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6854 (_("This file is invalid and cannot be played.")),
6855 ("sample data crosses atom boundary"));
6856 ret = GST_FLOW_ERROR;
6859 demux->mdatleft -= demux->neededbytes;
6861 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6862 /* so we are dropping more than left in this atom */
6863 gst_qtdemux_drop_data (demux, demux->mdatleft);
6864 demux->mdatleft = 0;
6866 /* need to resume atom parsing so we do not miss any other pieces */
6867 demux->state = QTDEMUX_STATE_INITIAL;
6868 demux->neededbytes = 16;
6870 /* check if there was any stored post mdat data from previous buffers */
6871 if (demux->restoredata_buffer) {
6872 g_assert (gst_adapter_available (demux->adapter) == 0);
6874 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6875 demux->restoredata_buffer = NULL;
6876 demux->offset = demux->restoredata_offset;
6883 if (demux->todrop) {
6884 if (demux->cenc_aux_info_offset > 0) {
6888 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6889 data = gst_adapter_map (demux->adapter, demux->todrop);
6890 gst_byte_reader_init (&br, data + 8, demux->todrop);
6891 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6892 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6893 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6894 ret = GST_FLOW_ERROR;
6895 gst_adapter_unmap (demux->adapter);
6896 g_free (demux->cenc_aux_info_sizes);
6897 demux->cenc_aux_info_sizes = NULL;
6900 demux->cenc_aux_info_offset = 0;
6901 g_free (demux->cenc_aux_info_sizes);
6902 demux->cenc_aux_info_sizes = NULL;
6903 gst_adapter_unmap (demux->adapter);
6905 gst_qtdemux_drop_data (demux, demux->todrop);
6909 /* initial newsegment sent here after having added pads,
6910 * possible others in sink_event */
6911 gst_qtdemux_check_send_pending_segment (demux);
6913 /* Figure out which stream this packet belongs to */
6914 for (i = 0; i < demux->n_streams; i++) {
6915 stream = demux->streams[i];
6916 if (stream->sample_index >= stream->n_samples)
6918 GST_LOG_OBJECT (demux,
6919 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6920 " / size:%d)", i, stream->sample_index,
6921 stream->samples[stream->sample_index].offset,
6922 stream->samples[stream->sample_index].size);
6924 if (stream->samples[stream->sample_index].offset == demux->offset)
6928 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6929 goto unknown_stream;
6931 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
6933 if (stream->new_caps) {
6934 gst_qtdemux_configure_stream (demux, stream);
6937 /* Put data in a buffer, set timestamps, caps, ... */
6938 sample = &stream->samples[stream->sample_index];
6940 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6941 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6942 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
6944 dts = QTSAMPLE_DTS (stream, sample);
6945 pts = QTSAMPLE_PTS (stream, sample);
6946 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6947 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6949 /* check for segment end */
6950 if (G_UNLIKELY (demux->segment.stop != -1
6951 && demux->segment.stop <= pts && stream->on_keyframe)) {
6952 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6953 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6955 /* skip this data, stream is EOS */
6956 gst_adapter_flush (demux->adapter, demux->neededbytes);
6957 demux->offset += demux->neededbytes;
6959 /* check if all streams are eos */
6961 for (i = 0; i < demux->n_streams; i++) {
6962 if (!STREAM_IS_EOS (demux->streams[i])) {
6971 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6973 /* FIXME: should either be an assert or a plain check */
6974 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6976 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6977 dts, pts, duration, keyframe, dts, demux->offset);
6981 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6983 /* skip this data, stream is EOS */
6984 gst_adapter_flush (demux->adapter, demux->neededbytes);
6987 stream->sample_index++;
6988 stream->offset_in_sample = 0;
6990 /* update current offset and figure out size of next buffer */
6991 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6992 demux->offset, demux->neededbytes);
6993 demux->offset += demux->neededbytes;
6994 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6998 if (ret == GST_FLOW_EOS) {
6999 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7000 demux->neededbytes = -1;
7004 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7005 if (demux->fragmented) {
7006 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7007 /* there may be more to follow, only finish this atom */
7008 demux->todrop = demux->mdatleft;
7009 demux->neededbytes = demux->todrop;
7014 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7015 goto non_ok_unlinked_flow;
7024 /* when buffering movie data, at least show user something is happening */
7025 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7026 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7027 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7028 demux->neededbytes);
7035 non_ok_unlinked_flow:
7037 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7038 gst_flow_get_name (ret));
7043 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7044 ret = GST_FLOW_ERROR;
7049 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7055 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7056 (NULL), ("qtdemuxer invalid state %d", demux->state));
7057 ret = GST_FLOW_ERROR;
7062 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7063 (NULL), ("no 'moov' atom within the first 10 MB"));
7064 ret = GST_FLOW_ERROR;
7070 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7075 query = gst_query_new_scheduling ();
7077 if (!gst_pad_peer_query (sinkpad, query)) {
7078 gst_query_unref (query);
7082 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7083 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7084 gst_query_unref (query);
7089 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7090 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7094 GST_DEBUG_OBJECT (sinkpad, "activating push");
7095 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7100 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7101 GstPadMode mode, gboolean active)
7104 GstQTDemux *demux = GST_QTDEMUX (parent);
7107 case GST_PAD_MODE_PUSH:
7108 demux->pullbased = FALSE;
7111 case GST_PAD_MODE_PULL:
7113 demux->pullbased = TRUE;
7114 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7117 res = gst_pad_stop_task (sinkpad);
7129 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7135 memset (&z, 0, sizeof (z));
7140 if ((ret = inflateInit (&z)) != Z_OK) {
7141 GST_ERROR ("inflateInit() returned %d", ret);
7145 z.next_in = z_buffer;
7146 z.avail_in = z_length;
7148 buffer = (guint8 *) g_malloc (*length);
7149 z.avail_out = *length;
7150 z.next_out = (Bytef *) buffer;
7152 ret = inflate (&z, Z_NO_FLUSH);
7153 if (ret == Z_STREAM_END) {
7155 } else if (ret != Z_OK) {
7156 GST_WARNING ("inflate() returned %d", ret);
7161 buffer = (guint8 *) g_realloc (buffer, *length);
7162 z.next_out = (Bytef *) (buffer + z.total_out);
7163 z.avail_out += 4096;
7164 } while (z.avail_in > 0);
7166 if (ret != Z_STREAM_END) {
7171 *length = z.total_out;
7178 #endif /* HAVE_ZLIB */
7181 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7185 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7187 /* counts as header data */
7188 qtdemux->header_size += length;
7190 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7191 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7193 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7200 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7201 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7202 if (dcom == NULL || cmvd == NULL)
7203 goto invalid_compression;
7205 dcom_len = QT_UINT32 (dcom->data);
7207 goto invalid_compression;
7209 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7213 guint uncompressed_length;
7214 guint compressed_length;
7218 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7220 goto invalid_compression;
7222 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7223 compressed_length = cmvd_len - 12;
7224 GST_LOG ("length = %u", uncompressed_length);
7227 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7228 compressed_length, &uncompressed_length);
7231 qtdemux->moov_node_compressed = qtdemux->moov_node;
7232 qtdemux->moov_node = g_node_new (buf);
7234 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7235 uncompressed_length);
7239 #endif /* HAVE_ZLIB */
7241 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7242 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7249 invalid_compression:
7251 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7257 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7260 while (G_UNLIKELY (buf < end)) {
7264 if (G_UNLIKELY (buf + 4 > end)) {
7265 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7268 len = QT_UINT32 (buf);
7269 if (G_UNLIKELY (len == 0)) {
7270 GST_LOG_OBJECT (qtdemux, "empty container");
7273 if (G_UNLIKELY (len < 8)) {
7274 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7277 if (G_UNLIKELY (len > (end - buf))) {
7278 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7279 (gint) (end - buf));
7283 child = g_node_new ((guint8 *) buf);
7284 g_node_append (node, child);
7285 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7286 qtdemux_parse_node (qtdemux, child, buf, len);
7294 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7297 int len = QT_UINT32 (xdxt->data);
7298 guint8 *buf = xdxt->data;
7299 guint8 *end = buf + len;
7302 /* skip size and type */
7310 size = QT_UINT32 (buf);
7311 type = QT_FOURCC (buf + 4);
7313 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7315 if (buf + size > end || size <= 0)
7321 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7322 GST_FOURCC_ARGS (type));
7326 buffer = gst_buffer_new_and_alloc (size);
7327 gst_buffer_fill (buffer, 0, buf, size);
7328 stream->buffers = g_slist_append (stream->buffers, buffer);
7329 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7332 buffer = gst_buffer_new_and_alloc (size);
7333 gst_buffer_fill (buffer, 0, buf, size);
7334 stream->buffers = g_slist_append (stream->buffers, buffer);
7335 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7338 buffer = gst_buffer_new_and_alloc (size);
7339 gst_buffer_fill (buffer, 0, buf, size);
7340 stream->buffers = g_slist_append (stream->buffers, buffer);
7341 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7344 GST_WARNING_OBJECT (qtdemux,
7345 "unknown theora cookie %" GST_FOURCC_FORMAT,
7346 GST_FOURCC_ARGS (type));
7355 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7359 guint32 node_length = 0;
7360 const QtNodeType *type;
7363 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7365 if (G_UNLIKELY (length < 8))
7366 goto not_enough_data;
7368 node_length = QT_UINT32 (buffer);
7369 fourcc = QT_FOURCC (buffer + 4);
7371 /* ignore empty nodes */
7372 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7375 type = qtdemux_type_get (fourcc);
7377 end = buffer + length;
7379 GST_LOG_OBJECT (qtdemux,
7380 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7381 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7383 if (node_length > length)
7384 goto broken_atom_size;
7386 if (type->flags & QT_FLAG_CONTAINER) {
7387 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7392 if (node_length < 20) {
7393 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7396 GST_DEBUG_OBJECT (qtdemux,
7397 "parsing stsd (sample table, sample description) atom");
7398 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7399 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7410 /* also read alac (or whatever) in stead of mp4a in the following,
7411 * since a similar layout is used in other cases as well */
7412 if (fourcc == FOURCC_mp4a)
7414 else if (fourcc == FOURCC_fLaC)
7419 /* There are two things we might encounter here: a true mp4a atom, and
7420 an mp4a entry in an stsd atom. The latter is what we're interested
7421 in, and it looks like an atom, but isn't really one. The true mp4a
7422 atom is short, so we detect it based on length here. */
7423 if (length < min_size) {
7424 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7425 GST_FOURCC_ARGS (fourcc));
7429 /* 'version' here is the sound sample description version. Types 0 and
7430 1 are documented in the QTFF reference, but type 2 is not: it's
7431 described in Apple header files instead (struct SoundDescriptionV2
7433 version = QT_UINT16 (buffer + 16);
7435 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7436 GST_FOURCC_ARGS (fourcc), version);
7438 /* parse any esds descriptors */
7450 GST_WARNING_OBJECT (qtdemux,
7451 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7452 GST_FOURCC_ARGS (fourcc), version);
7457 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7483 /* codec_data is contained inside these atoms, which all have
7484 * the same format. */
7485 /* video sample description size is 86 bytes without extension.
7486 * node_length have to be bigger than 86 bytes because video sample
7487 * description can include extenstions such as esds, fiel, glbl, etc. */
7488 if (node_length < 86) {
7489 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7490 " sample description length too short (%u < 86)",
7491 GST_FOURCC_ARGS (fourcc), node_length);
7495 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7496 GST_FOURCC_ARGS (fourcc));
7498 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7500 * revision level (2 bytes) : must be set to 0. */
7501 version = QT_UINT32 (buffer + 16);
7502 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7504 /* compressor name : PASCAL string and informative purposes
7505 * first byte : the number of bytes to be displayed.
7506 * it has to be less than 32 because it is reserved
7507 * space of 32 bytes total including itself. */
7508 str_len = QT_UINT8 (buffer + 50);
7510 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7511 (char *) buffer + 51);
7513 GST_WARNING_OBJECT (qtdemux,
7514 "compressorname length too big (%u > 31)", str_len);
7516 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7518 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7523 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7524 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7529 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7530 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7531 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7540 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7541 GST_FOURCC_ARGS (fourcc));
7545 version = QT_UINT32 (buffer + 12);
7546 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7553 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7558 if (length < offset) {
7559 GST_WARNING_OBJECT (qtdemux,
7560 "skipping too small %" GST_FOURCC_FORMAT " box",
7561 GST_FOURCC_ARGS (fourcc));
7564 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7570 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7575 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7580 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7584 if (!strcmp (type->name, "unknown"))
7585 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7589 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7590 GST_FOURCC_ARGS (fourcc));
7596 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7597 (_("This file is corrupt and cannot be played.")),
7598 ("Not enough data for an atom header, got only %u bytes", length));
7603 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7604 (_("This file is corrupt and cannot be played.")),
7605 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7606 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7613 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7617 guint32 child_fourcc;
7619 for (child = g_node_first_child (node); child;
7620 child = g_node_next_sibling (child)) {
7621 buffer = (guint8 *) child->data;
7623 child_fourcc = QT_FOURCC (buffer + 4);
7625 if (G_UNLIKELY (child_fourcc == fourcc)) {
7633 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7634 GstByteReader * parser)
7638 guint32 child_fourcc, child_len;
7640 for (child = g_node_first_child (node); child;
7641 child = g_node_next_sibling (child)) {
7642 buffer = (guint8 *) child->data;
7644 child_len = QT_UINT32 (buffer);
7645 child_fourcc = QT_FOURCC (buffer + 4);
7647 if (G_UNLIKELY (child_fourcc == fourcc)) {
7648 if (G_UNLIKELY (child_len < (4 + 4)))
7650 /* FIXME: must verify if atom length < parent atom length */
7651 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7659 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7661 return g_node_nth_child (node, index);
7665 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7666 GstByteReader * parser)
7670 guint32 child_fourcc, child_len;
7672 for (child = g_node_next_sibling (node); child;
7673 child = g_node_next_sibling (child)) {
7674 buffer = (guint8 *) child->data;
7676 child_fourcc = QT_FOURCC (buffer + 4);
7678 if (child_fourcc == fourcc) {
7680 child_len = QT_UINT32 (buffer);
7681 if (G_UNLIKELY (child_len < (4 + 4)))
7683 /* FIXME: must verify if atom length < parent atom length */
7684 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7693 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7695 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7699 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7701 /* FIXME: This can only reliably work if demuxers have a
7702 * separate streaming thread per srcpad. This should be
7703 * done in a demuxer base class, which integrates parts
7706 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7711 query = gst_query_new_allocation (stream->caps, FALSE);
7713 if (!gst_pad_peer_query (stream->pad, query)) {
7714 /* not a problem, just debug a little */
7715 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7718 if (stream->allocator)
7719 gst_object_unref (stream->allocator);
7721 if (gst_query_get_n_allocation_params (query) > 0) {
7722 /* try the allocator */
7723 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7725 stream->use_allocator = TRUE;
7727 stream->allocator = NULL;
7728 gst_allocation_params_init (&stream->params);
7729 stream->use_allocator = FALSE;
7731 gst_query_unref (query);
7736 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7737 QtDemuxStream * stream)
7740 const gchar *selected_system;
7742 g_return_val_if_fail (qtdemux != NULL, FALSE);
7743 g_return_val_if_fail (stream != NULL, FALSE);
7744 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
7747 if (stream->protection_scheme_type != FOURCC_cenc) {
7748 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7751 if (qtdemux->protection_system_ids == NULL) {
7752 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7753 "cenc protection system information has been found");
7756 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7757 selected_system = gst_protection_select_system ((const gchar **)
7758 qtdemux->protection_system_ids->pdata);
7759 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7760 qtdemux->protection_system_ids->len - 1);
7761 if (!selected_system) {
7762 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7763 "suitable decryptor element has been found");
7767 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
7768 if (!gst_structure_has_name (s, "application/x-cenc")) {
7769 gst_structure_set (s,
7770 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7771 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7773 gst_structure_set_name (s, "application/x-cenc");
7779 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7781 if (stream->subtype == FOURCC_vide) {
7782 /* fps is calculated base on the duration of the average framerate since
7783 * qt does not have a fixed framerate. */
7784 gboolean fps_available = TRUE;
7786 if ((stream->n_samples == 1 && stream->first_duration == 0)
7787 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
7789 CUR_STREAM (stream)->fps_n = 0;
7790 CUR_STREAM (stream)->fps_d = 1;
7792 if (stream->duration == 0 || stream->n_samples < 2) {
7793 CUR_STREAM (stream)->fps_n = stream->timescale;
7794 CUR_STREAM (stream)->fps_d = 1;
7795 fps_available = FALSE;
7797 GstClockTime avg_duration;
7801 /* duration and n_samples can be updated for fragmented format
7802 * so, framerate of fragmented format is calculated using data in a moof */
7803 if (qtdemux->fragmented && stream->n_samples_moof > 0
7804 && stream->duration_moof > 0) {
7805 n_samples = stream->n_samples_moof;
7806 duration = stream->duration_moof;
7808 n_samples = stream->n_samples;
7809 duration = stream->duration;
7812 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7813 /* stream->duration is guint64, timescale, n_samples are guint32 */
7815 gst_util_uint64_scale_round (duration -
7816 stream->first_duration, GST_SECOND,
7817 (guint64) (stream->timescale) * (n_samples - 1));
7819 GST_LOG_OBJECT (qtdemux,
7820 "Calculating avg sample duration based on stream (or moof) duration %"
7822 " minus first sample %u, leaving %d samples gives %"
7823 GST_TIME_FORMAT, duration, stream->first_duration,
7824 n_samples - 1, GST_TIME_ARGS (avg_duration));
7826 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
7827 &CUR_STREAM (stream)->fps_d);
7829 GST_DEBUG_OBJECT (qtdemux,
7830 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7831 stream->timescale, CUR_STREAM (stream)->fps_n,
7832 CUR_STREAM (stream)->fps_d);
7836 if (CUR_STREAM (stream)->caps) {
7837 CUR_STREAM (stream)->caps =
7838 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7840 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7841 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
7842 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
7844 /* set framerate if calculated framerate is reliable */
7845 if (fps_available) {
7846 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7847 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
7848 CUR_STREAM (stream)->fps_d, NULL);
7851 /* calculate pixel-aspect-ratio using display width and height */
7852 GST_DEBUG_OBJECT (qtdemux,
7853 "video size %dx%d, target display size %dx%d",
7854 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
7855 stream->display_width, stream->display_height);
7856 /* qt file might have pasp atom */
7857 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7858 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
7859 CUR_STREAM (stream)->par_h);
7860 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7861 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7862 CUR_STREAM (stream)->par_h, NULL);
7863 } else if (stream->display_width > 0 && stream->display_height > 0
7864 && CUR_STREAM (stream)->width > 0
7865 && CUR_STREAM (stream)->height > 0) {
7868 /* calculate the pixel aspect ratio using the display and pixel w/h */
7869 n = stream->display_width * CUR_STREAM (stream)->height;
7870 d = stream->display_height * CUR_STREAM (stream)->width;
7873 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7874 CUR_STREAM (stream)->par_w = n;
7875 CUR_STREAM (stream)->par_h = d;
7876 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7877 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7878 CUR_STREAM (stream)->par_h, NULL);
7881 if (CUR_STREAM (stream)->interlace_mode > 0) {
7882 if (CUR_STREAM (stream)->interlace_mode == 1) {
7883 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7884 G_TYPE_STRING, "progressive", NULL);
7885 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
7886 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7887 G_TYPE_STRING, "interleaved", NULL);
7888 if (CUR_STREAM (stream)->field_order == 9) {
7889 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7890 G_TYPE_STRING, "top-field-first", NULL);
7891 } else if (CUR_STREAM (stream)->field_order == 14) {
7892 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7893 G_TYPE_STRING, "bottom-field-first", NULL);
7898 /* Create incomplete colorimetry here if needed */
7899 if (CUR_STREAM (stream)->colorimetry.range ||
7900 CUR_STREAM (stream)->colorimetry.matrix ||
7901 CUR_STREAM (stream)->colorimetry.transfer
7902 || CUR_STREAM (stream)->colorimetry.primaries) {
7903 gchar *colorimetry =
7904 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
7905 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
7906 G_TYPE_STRING, colorimetry, NULL);
7907 g_free (colorimetry);
7910 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7911 guint par_w = 1, par_h = 1;
7913 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7914 par_w = CUR_STREAM (stream)->par_w;
7915 par_h = CUR_STREAM (stream)->par_h;
7918 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7919 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
7921 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7924 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7925 "multiview-mode", G_TYPE_STRING,
7926 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7927 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7928 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7933 else if (stream->subtype == FOURCC_soun) {
7934 if (CUR_STREAM (stream)->caps) {
7935 CUR_STREAM (stream)->caps =
7936 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7937 if (CUR_STREAM (stream)->rate > 0)
7938 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7939 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
7940 if (CUR_STREAM (stream)->n_channels > 0)
7941 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7942 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
7943 if (CUR_STREAM (stream)->n_channels > 2) {
7944 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7945 * correctly; this is just the minimum we can do - assume
7946 * we don't actually have any channel positions. */
7947 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7948 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7954 GstCaps *prev_caps = NULL;
7956 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7957 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7958 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7959 gst_pad_set_active (stream->pad, TRUE);
7961 gst_pad_use_fixed_caps (stream->pad);
7963 if (stream->protected) {
7964 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7965 GST_ERROR_OBJECT (qtdemux,
7966 "Failed to configure protected stream caps.");
7971 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7972 CUR_STREAM (stream)->caps);
7973 if (stream->new_stream) {
7976 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
7979 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7982 gst_event_parse_stream_flags (event, &stream_flags);
7983 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7984 qtdemux->have_group_id = TRUE;
7986 qtdemux->have_group_id = FALSE;
7987 gst_event_unref (event);
7988 } else if (!qtdemux->have_group_id) {
7989 qtdemux->have_group_id = TRUE;
7990 qtdemux->group_id = gst_util_group_id_next ();
7993 stream->new_stream = FALSE;
7995 gst_pad_create_stream_id_printf (stream->pad,
7996 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7997 event = gst_event_new_stream_start (stream_id);
7998 if (qtdemux->have_group_id)
7999 gst_event_set_group_id (event, qtdemux->group_id);
8000 if (stream->disabled)
8001 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8002 if (CUR_STREAM (stream)->sparse) {
8003 stream_flags |= GST_STREAM_FLAG_SPARSE;
8005 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8007 gst_event_set_stream_flags (event, stream_flags);
8008 gst_pad_push_event (stream->pad, event);
8012 prev_caps = gst_pad_get_current_caps (stream->pad);
8014 if (CUR_STREAM (stream)->caps) {
8016 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8017 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8018 CUR_STREAM (stream)->caps);
8019 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8021 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8024 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8028 gst_caps_unref (prev_caps);
8029 stream->new_caps = FALSE;
8035 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8036 QtDemuxStream * stream)
8038 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8041 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8042 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8043 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8044 stream->stsd_entries_length)) {
8045 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8046 (_("This file is invalid and cannot be played.")),
8047 ("New sample description id is out of bounds (%d >= %d)",
8048 stream->stsd_sample_description_id, stream->stsd_entries_length));
8050 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8051 stream->new_caps = TRUE;
8056 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8057 QtDemuxStream * stream, GstTagList * list)
8059 gboolean ret = TRUE;
8060 /* consistent default for push based mode */
8061 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8063 if (stream->subtype == FOURCC_vide) {
8064 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8067 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8070 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8071 gst_object_unref (stream->pad);
8077 qtdemux->n_video_streams++;
8078 } else if (stream->subtype == FOURCC_soun) {
8079 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8082 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8084 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8085 gst_object_unref (stream->pad);
8090 qtdemux->n_audio_streams++;
8091 } else if (stream->subtype == FOURCC_strm) {
8092 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8093 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8094 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8095 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8098 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8100 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8101 gst_object_unref (stream->pad);
8106 qtdemux->n_sub_streams++;
8107 } else if (CUR_STREAM (stream)->caps) {
8108 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8111 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8113 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8114 gst_object_unref (stream->pad);
8119 qtdemux->n_video_streams++;
8121 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8128 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8129 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8130 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8131 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8133 if (stream->stream_tags)
8134 gst_tag_list_unref (stream->stream_tags);
8135 stream->stream_tags = list;
8137 /* global tags go on each pad anyway */
8138 stream->send_global_tags = TRUE;
8139 /* send upstream GST_EVENT_PROTECTION events that were received before
8140 this source pad was created */
8141 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8142 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8146 gst_tag_list_unref (list);
8150 /* find next atom with @fourcc starting at @offset */
8151 static GstFlowReturn
8152 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8153 guint64 * length, guint32 fourcc)
8159 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8160 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8166 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8167 if (G_UNLIKELY (ret != GST_FLOW_OK))
8169 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8172 gst_buffer_unref (buf);
8175 gst_buffer_map (buf, &map, GST_MAP_READ);
8176 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8177 gst_buffer_unmap (buf, &map);
8178 gst_buffer_unref (buf);
8180 if (G_UNLIKELY (*length == 0)) {
8181 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8182 ret = GST_FLOW_ERROR;
8186 if (lfourcc == fourcc) {
8187 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8191 GST_LOG_OBJECT (qtdemux,
8192 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8193 GST_FOURCC_ARGS (fourcc), *offset);
8202 /* might simply have had last one */
8203 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8208 /* should only do something in pull mode */
8209 /* call with OBJECT lock */
8210 static GstFlowReturn
8211 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8213 guint64 length, offset;
8214 GstBuffer *buf = NULL;
8215 GstFlowReturn ret = GST_FLOW_OK;
8216 GstFlowReturn res = GST_FLOW_OK;
8219 offset = qtdemux->moof_offset;
8220 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8223 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8224 return GST_FLOW_EOS;
8227 /* best not do pull etc with lock held */
8228 GST_OBJECT_UNLOCK (qtdemux);
8230 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8231 if (ret != GST_FLOW_OK)
8234 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8235 if (G_UNLIKELY (ret != GST_FLOW_OK))
8237 gst_buffer_map (buf, &map, GST_MAP_READ);
8238 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8239 gst_buffer_unmap (buf, &map);
8240 gst_buffer_unref (buf);
8245 gst_buffer_unmap (buf, &map);
8246 gst_buffer_unref (buf);
8250 /* look for next moof */
8251 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8252 if (G_UNLIKELY (ret != GST_FLOW_OK))
8256 GST_OBJECT_LOCK (qtdemux);
8258 qtdemux->moof_offset = offset;
8264 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8266 res = GST_FLOW_ERROR;
8271 /* maybe upstream temporarily flushing */
8272 if (ret != GST_FLOW_FLUSHING) {
8273 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8276 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8277 /* resume at current position next time */
8284 /* initialise bytereaders for stbl sub-atoms */
8286 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8288 stream->stbl_index = -1; /* no samples have yet been parsed */
8289 stream->sample_index = -1;
8291 /* time-to-sample atom */
8292 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8295 /* copy atom data into a new buffer for later use */
8296 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8298 /* skip version + flags */
8299 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8300 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8302 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8304 /* make sure there's enough data */
8305 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8306 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8307 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8308 stream->n_sample_times);
8309 if (!stream->n_sample_times)
8313 /* sync sample atom */
8314 stream->stps_present = FALSE;
8315 if ((stream->stss_present =
8316 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8317 &stream->stss) ? TRUE : FALSE) == TRUE) {
8318 /* copy atom data into a new buffer for later use */
8319 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8321 /* skip version + flags */
8322 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8323 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8326 if (stream->n_sample_syncs) {
8327 /* make sure there's enough data */
8328 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8332 /* partial sync sample atom */
8333 if ((stream->stps_present =
8334 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8335 &stream->stps) ? TRUE : FALSE) == TRUE) {
8336 /* copy atom data into a new buffer for later use */
8337 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8339 /* skip version + flags */
8340 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8341 !gst_byte_reader_get_uint32_be (&stream->stps,
8342 &stream->n_sample_partial_syncs))
8345 /* if there are no entries, the stss table contains the real
8347 if (stream->n_sample_partial_syncs) {
8348 /* make sure there's enough data */
8349 if (!qt_atom_parser_has_chunks (&stream->stps,
8350 stream->n_sample_partial_syncs, 4))
8357 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8360 /* copy atom data into a new buffer for later use */
8361 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8363 /* skip version + flags */
8364 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8365 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8368 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8371 if (!stream->n_samples)
8374 /* sample-to-chunk atom */
8375 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8378 /* copy atom data into a new buffer for later use */
8379 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8381 /* skip version + flags */
8382 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8383 !gst_byte_reader_get_uint32_be (&stream->stsc,
8384 &stream->n_samples_per_chunk))
8387 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8388 stream->n_samples_per_chunk);
8390 /* make sure there's enough data */
8391 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8397 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8398 stream->co_size = sizeof (guint32);
8399 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8401 stream->co_size = sizeof (guint64);
8405 /* copy atom data into a new buffer for later use */
8406 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8408 /* skip version + flags */
8409 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8412 /* chunks_are_samples == TRUE means treat chunks as samples */
8413 stream->chunks_are_samples = stream->sample_size
8414 && !CUR_STREAM (stream)->sampled;
8415 if (stream->chunks_are_samples) {
8416 /* treat chunks as samples */
8417 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8420 /* skip number of entries */
8421 if (!gst_byte_reader_skip (&stream->stco, 4))
8424 /* make sure there are enough data in the stsz atom */
8425 if (!stream->sample_size) {
8426 /* different sizes for each sample */
8427 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8432 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8433 stream->n_samples, (guint) sizeof (QtDemuxSample),
8434 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8436 if (stream->n_samples >=
8437 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8438 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8439 "be larger than %uMB (broken file?)", stream->n_samples,
8440 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8444 g_assert (stream->samples == NULL);
8445 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8446 if (!stream->samples) {
8447 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8452 /* composition time-to-sample */
8453 if ((stream->ctts_present =
8454 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8455 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8456 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8458 /* copy atom data into a new buffer for later use */
8459 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8461 /* skip version + flags */
8462 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8463 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8464 &stream->n_composition_times))
8467 /* make sure there's enough data */
8468 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8472 /* This is optional, if missing we iterate the ctts */
8473 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8474 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8475 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8476 g_free ((gpointer) cslg.data);
8480 gint32 cslg_least = 0;
8481 guint num_entries, pos;
8484 pos = gst_byte_reader_get_pos (&stream->ctts);
8485 num_entries = stream->n_composition_times;
8487 stream->cslg_shift = 0;
8489 for (i = 0; i < num_entries; i++) {
8492 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8493 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8495 if (offset < cslg_least)
8496 cslg_least = offset;
8500 stream->cslg_shift = ABS (cslg_least);
8502 stream->cslg_shift = 0;
8504 /* reset the reader so we can generate sample table */
8505 gst_byte_reader_set_pos (&stream->ctts, pos);
8508 /* Ensure the cslg_shift value is consistent so we can use it
8509 * unconditionnally to produce TS and Segment */
8510 stream->cslg_shift = 0;
8517 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8518 (_("This file is corrupt and cannot be played.")), (NULL));
8523 gst_qtdemux_stbl_free (stream);
8524 if (!qtdemux->fragmented) {
8525 /* not quite good */
8526 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8529 /* may pick up samples elsewhere */
8535 /* collect samples from the next sample to be parsed up to sample @n for @stream
8536 * by reading the info from @stbl
8538 * This code can be executed from both the streaming thread and the seeking
8539 * thread so it takes the object lock to protect itself
8542 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8545 QtDemuxSample *samples, *first, *cur, *last;
8546 guint32 n_samples_per_chunk;
8549 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8550 GST_FOURCC_FORMAT ", pad %s",
8551 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8552 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8554 n_samples = stream->n_samples;
8557 goto out_of_samples;
8559 GST_OBJECT_LOCK (qtdemux);
8560 if (n <= stream->stbl_index)
8561 goto already_parsed;
8563 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8565 if (!stream->stsz.data) {
8566 /* so we already parsed and passed all the moov samples;
8567 * onto fragmented ones */
8568 g_assert (qtdemux->fragmented);
8572 /* pointer to the sample table */
8573 samples = stream->samples;
8575 /* starts from -1, moves to the next sample index to parse */
8576 stream->stbl_index++;
8578 /* keep track of the first and last sample to fill */
8579 first = &samples[stream->stbl_index];
8582 if (!stream->chunks_are_samples) {
8583 /* set the sample sizes */
8584 if (stream->sample_size == 0) {
8585 /* different sizes for each sample */
8586 for (cur = first; cur <= last; cur++) {
8587 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8588 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8589 (guint) (cur - samples), cur->size);
8592 /* samples have the same size */
8593 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8594 for (cur = first; cur <= last; cur++)
8595 cur->size = stream->sample_size;
8599 n_samples_per_chunk = stream->n_samples_per_chunk;
8602 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8605 if (stream->stsc_chunk_index >= stream->last_chunk
8606 || stream->stsc_chunk_index < stream->first_chunk) {
8607 stream->first_chunk =
8608 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8609 stream->samples_per_chunk =
8610 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8612 stream->stsd_sample_description_id =
8613 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
8615 /* chunk numbers are counted from 1 it seems */
8616 if (G_UNLIKELY (stream->first_chunk == 0))
8619 --stream->first_chunk;
8621 /* the last chunk of each entry is calculated by taking the first chunk
8622 * of the next entry; except if there is no next, where we fake it with
8624 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8625 stream->last_chunk = G_MAXUINT32;
8627 stream->last_chunk =
8628 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8629 if (G_UNLIKELY (stream->last_chunk == 0))
8632 --stream->last_chunk;
8635 GST_LOG_OBJECT (qtdemux,
8636 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
8637 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
8638 stream->samples_per_chunk, stream->stsd_sample_description_id);
8640 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8643 if (stream->last_chunk != G_MAXUINT32) {
8644 if (!qt_atom_parser_peek_sub (&stream->stco,
8645 stream->first_chunk * stream->co_size,
8646 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8651 stream->co_chunk = stream->stco;
8652 if (!gst_byte_reader_skip (&stream->co_chunk,
8653 stream->first_chunk * stream->co_size))
8657 stream->stsc_chunk_index = stream->first_chunk;
8660 last_chunk = stream->last_chunk;
8662 if (stream->chunks_are_samples) {
8663 cur = &samples[stream->stsc_chunk_index];
8665 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8668 stream->stsc_chunk_index = j;
8673 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8676 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8677 "%" G_GUINT64_FORMAT, j, cur->offset);
8679 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
8680 CUR_STREAM (stream)->bytes_per_frame > 0) {
8682 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
8683 CUR_STREAM (stream)->samples_per_frame *
8684 CUR_STREAM (stream)->bytes_per_frame;
8686 cur->size = stream->samples_per_chunk;
8689 GST_DEBUG_OBJECT (qtdemux,
8690 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8691 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8692 stream->stco_sample_index)), cur->size);
8694 cur->timestamp = stream->stco_sample_index;
8695 cur->duration = stream->samples_per_chunk;
8696 cur->keyframe = TRUE;
8699 stream->stco_sample_index += stream->samples_per_chunk;
8701 stream->stsc_chunk_index = j;
8703 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8704 guint32 samples_per_chunk;
8705 guint64 chunk_offset;
8707 if (!stream->stsc_sample_index
8708 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8709 &stream->chunk_offset))
8712 samples_per_chunk = stream->samples_per_chunk;
8713 chunk_offset = stream->chunk_offset;
8715 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8716 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8717 G_GUINT64_FORMAT " and size %d",
8718 (guint) (cur - samples), chunk_offset, cur->size);
8720 cur->offset = chunk_offset;
8721 chunk_offset += cur->size;
8724 if (G_UNLIKELY (cur > last)) {
8726 stream->stsc_sample_index = k + 1;
8727 stream->chunk_offset = chunk_offset;
8728 stream->stsc_chunk_index = j;
8732 stream->stsc_sample_index = 0;
8734 stream->stsc_chunk_index = j;
8736 stream->stsc_index++;
8739 if (stream->chunks_are_samples)
8743 guint32 n_sample_times;
8745 n_sample_times = stream->n_sample_times;
8748 for (i = stream->stts_index; i < n_sample_times; i++) {
8749 guint32 stts_samples;
8750 gint32 stts_duration;
8753 if (stream->stts_sample_index >= stream->stts_samples
8754 || !stream->stts_sample_index) {
8756 stream->stts_samples =
8757 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8758 stream->stts_duration =
8759 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8761 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8762 i, stream->stts_samples, stream->stts_duration);
8764 stream->stts_sample_index = 0;
8767 stts_samples = stream->stts_samples;
8768 stts_duration = stream->stts_duration;
8769 stts_time = stream->stts_time;
8771 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8772 GST_DEBUG_OBJECT (qtdemux,
8773 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8774 (guint) (cur - samples), j,
8775 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8777 cur->timestamp = stts_time;
8778 cur->duration = stts_duration;
8780 /* avoid 32-bit wrap-around,
8781 * but still mind possible 'negative' duration */
8782 stts_time += (gint64) stts_duration;
8785 if (G_UNLIKELY (cur > last)) {
8787 stream->stts_time = stts_time;
8788 stream->stts_sample_index = j + 1;
8789 if (stream->stts_sample_index >= stream->stts_samples)
8790 stream->stts_index++;
8794 stream->stts_sample_index = 0;
8795 stream->stts_time = stts_time;
8796 stream->stts_index++;
8798 /* fill up empty timestamps with the last timestamp, this can happen when
8799 * the last samples do not decode and so we don't have timestamps for them.
8800 * We however look at the last timestamp to estimate the track length so we
8801 * need something in here. */
8802 for (; cur < last; cur++) {
8803 GST_DEBUG_OBJECT (qtdemux,
8804 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8805 (guint) (cur - samples),
8806 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8807 cur->timestamp = stream->stts_time;
8813 /* sample sync, can be NULL */
8814 if (stream->stss_present == TRUE) {
8815 guint32 n_sample_syncs;
8817 n_sample_syncs = stream->n_sample_syncs;
8819 if (!n_sample_syncs) {
8820 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8821 stream->all_keyframe = TRUE;
8823 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8824 /* note that the first sample is index 1, not 0 */
8827 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8829 if (G_LIKELY (index > 0 && index <= n_samples)) {
8831 samples[index].keyframe = TRUE;
8832 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8833 /* and exit if we have enough samples */
8834 if (G_UNLIKELY (index >= n)) {
8841 stream->stss_index = i;
8844 /* stps marks partial sync frames like open GOP I-Frames */
8845 if (stream->stps_present == TRUE) {
8846 guint32 n_sample_partial_syncs;
8848 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8850 /* if there are no entries, the stss table contains the real
8852 if (n_sample_partial_syncs) {
8853 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8854 /* note that the first sample is index 1, not 0 */
8857 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8859 if (G_LIKELY (index > 0 && index <= n_samples)) {
8861 samples[index].keyframe = TRUE;
8862 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8863 /* and exit if we have enough samples */
8864 if (G_UNLIKELY (index >= n)) {
8871 stream->stps_index = i;
8875 /* no stss, all samples are keyframes */
8876 stream->all_keyframe = TRUE;
8877 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8882 /* composition time to sample */
8883 if (stream->ctts_present == TRUE) {
8884 guint32 n_composition_times;
8886 gint32 ctts_soffset;
8888 /* Fill in the pts_offsets */
8890 n_composition_times = stream->n_composition_times;
8892 for (i = stream->ctts_index; i < n_composition_times; i++) {
8893 if (stream->ctts_sample_index >= stream->ctts_count
8894 || !stream->ctts_sample_index) {
8895 stream->ctts_count =
8896 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8897 stream->ctts_soffset =
8898 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8899 stream->ctts_sample_index = 0;
8902 ctts_count = stream->ctts_count;
8903 ctts_soffset = stream->ctts_soffset;
8905 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8906 cur->pts_offset = ctts_soffset;
8909 if (G_UNLIKELY (cur > last)) {
8911 stream->ctts_sample_index = j + 1;
8915 stream->ctts_sample_index = 0;
8916 stream->ctts_index++;
8920 stream->stbl_index = n;
8921 /* if index has been completely parsed, free data that is no-longer needed */
8922 if (n + 1 == stream->n_samples) {
8923 gst_qtdemux_stbl_free (stream);
8924 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8925 if (qtdemux->pullbased) {
8926 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8927 while (n + 1 == stream->n_samples)
8928 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8932 GST_OBJECT_UNLOCK (qtdemux);
8939 GST_LOG_OBJECT (qtdemux,
8940 "Tried to parse up to sample %u but this sample has already been parsed",
8942 /* if fragmented, there may be more */
8943 if (qtdemux->fragmented && n == stream->stbl_index)
8945 GST_OBJECT_UNLOCK (qtdemux);
8951 GST_LOG_OBJECT (qtdemux,
8952 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8954 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8955 (_("This file is corrupt and cannot be played.")), (NULL));
8960 GST_OBJECT_UNLOCK (qtdemux);
8961 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8962 (_("This file is corrupt and cannot be played.")), (NULL));
8967 /* collect all segment info for @stream.
8970 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8974 /* accept edts if they contain gaps at start and there is only
8975 * one media segment */
8976 gboolean allow_pushbased_edts = TRUE;
8977 gint media_segments_count = 0;
8979 /* parse and prepare segment info from the edit list */
8980 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8981 stream->n_segments = 0;
8982 stream->segments = NULL;
8983 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8986 gint i, count, entry_size;
8989 const guint8 *buffer;
8993 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8994 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8997 buffer = elst->data;
8999 size = QT_UINT32 (buffer);
9000 /* version, flags, n_segments */
9002 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9005 version = QT_UINT8 (buffer + 8);
9006 entry_size = (version == 1) ? 20 : 12;
9008 n_segments = QT_UINT32 (buffer + 12);
9010 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9011 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9015 /* we might allocate a bit too much, at least allocate 1 segment */
9016 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9018 /* segments always start from 0 */
9023 for (i = 0; i < n_segments; i++) {
9026 gboolean time_valid = TRUE;
9027 QtDemuxSegment *segment;
9029 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9032 media_time = QT_UINT64 (buffer + 8);
9033 duration = QT_UINT64 (buffer);
9034 if (media_time == G_MAXUINT64)
9037 media_time = QT_UINT32 (buffer + 4);
9038 duration = QT_UINT32 (buffer);
9039 if (media_time == G_MAXUINT32)
9044 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9046 segment = &stream->segments[count++];
9048 /* time and duration expressed in global timescale */
9049 segment->time = stime;
9050 /* add non scaled values so we don't cause roundoff errors */
9051 if (duration || media_start == GST_CLOCK_TIME_NONE) {
9053 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9054 segment->duration = stime - segment->time;
9056 /* zero duration does not imply media_start == media_stop
9057 * but, only specify media_start.*/
9058 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
9059 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
9060 && stime >= media_start) {
9061 segment->duration = stime - media_start;
9063 segment->duration = GST_CLOCK_TIME_NONE;
9066 segment->stop_time = stime;
9068 segment->trak_media_start = media_time;
9069 /* media_time expressed in stream timescale */
9071 segment->media_start = media_start;
9072 segment->media_stop = segment->media_start + segment->duration;
9073 media_segments_count++;
9075 segment->media_start = GST_CLOCK_TIME_NONE;
9076 segment->media_stop = GST_CLOCK_TIME_NONE;
9078 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9080 if (rate_int <= 1) {
9081 /* 0 is not allowed, some programs write 1 instead of the floating point
9083 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9087 segment->rate = rate_int / 65536.0;
9090 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9091 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9092 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9093 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9094 i, GST_TIME_ARGS (segment->time),
9095 GST_TIME_ARGS (segment->duration),
9096 GST_TIME_ARGS (segment->media_start), media_time,
9097 GST_TIME_ARGS (segment->media_stop),
9098 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9100 if (segment->stop_time > qtdemux->segment.stop) {
9101 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9102 " extends to %" GST_TIME_FORMAT
9103 " past the end of the file duration %" GST_TIME_FORMAT
9104 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9105 GST_TIME_ARGS (qtdemux->segment.stop));
9106 qtdemux->segment.stop = segment->stop_time;
9109 buffer += entry_size;
9111 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9112 stream->n_segments = count;
9113 if (media_segments_count != 1)
9114 allow_pushbased_edts = FALSE;
9118 /* push based does not handle segments, so act accordingly here,
9119 * and warn if applicable */
9120 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9121 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9122 /* remove and use default one below, we stream like it anyway */
9123 g_free (stream->segments);
9124 stream->segments = NULL;
9125 stream->n_segments = 0;
9128 /* no segments, create one to play the complete trak */
9129 if (stream->n_segments == 0) {
9130 GstClockTime stream_duration =
9131 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9133 if (stream->segments == NULL)
9134 stream->segments = g_new (QtDemuxSegment, 1);
9136 /* represent unknown our way */
9137 if (stream_duration == 0)
9138 stream_duration = GST_CLOCK_TIME_NONE;
9140 stream->segments[0].time = 0;
9141 stream->segments[0].stop_time = stream_duration;
9142 stream->segments[0].duration = stream_duration;
9143 stream->segments[0].media_start = 0;
9144 stream->segments[0].media_stop = stream_duration;
9145 stream->segments[0].rate = 1.0;
9146 stream->segments[0].trak_media_start = 0;
9148 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9149 GST_TIME_ARGS (stream_duration));
9150 stream->n_segments = 1;
9151 stream->dummy_segment = TRUE;
9153 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9159 * Parses the stsd atom of a svq3 trak looking for
9160 * the SMI and gama atoms.
9163 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9164 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9166 const guint8 *_gamma = NULL;
9167 GstBuffer *_seqh = NULL;
9168 const guint8 *stsd_data = stsd_entry_data;
9169 guint32 length = QT_UINT32 (stsd_data);
9173 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9179 version = QT_UINT16 (stsd_data);
9184 while (length > 8) {
9185 guint32 fourcc, size;
9187 size = QT_UINT32 (stsd_data);
9188 fourcc = QT_FOURCC (stsd_data + 4);
9189 data = stsd_data + 8;
9192 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9193 "svq3 atom parsing");
9202 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9203 " for gama atom, expected 12", size);
9208 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9210 if (_seqh != NULL) {
9211 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9212 " found, ignoring");
9214 seqh_size = QT_UINT32 (data + 4);
9215 if (seqh_size > 0) {
9216 _seqh = gst_buffer_new_and_alloc (seqh_size);
9217 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9224 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9225 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9229 if (size <= length) {
9235 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9238 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9239 G_GUINT16_FORMAT, version);
9250 gst_buffer_unref (_seqh);
9255 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9262 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9263 * atom that might contain a 'data' atom with the rtsp uri.
9264 * This case was reported in bug #597497, some info about
9265 * the hndl atom can be found in TN1195
9267 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9268 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9271 guint32 dref_num_entries = 0;
9272 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9273 gst_byte_reader_skip (&dref, 4) &&
9274 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9277 /* search dref entries for hndl atom */
9278 for (i = 0; i < dref_num_entries; i++) {
9279 guint32 size = 0, type;
9280 guint8 string_len = 0;
9281 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9282 qt_atom_parser_get_fourcc (&dref, &type)) {
9283 if (type == FOURCC_hndl) {
9284 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9286 /* skip data reference handle bytes and the
9287 * following pascal string and some extra 4
9288 * bytes I have no idea what are */
9289 if (!gst_byte_reader_skip (&dref, 4) ||
9290 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9291 !gst_byte_reader_skip (&dref, string_len + 4)) {
9292 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9296 /* iterate over the atoms to find the data atom */
9297 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9301 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9302 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9303 if (atom_type == FOURCC_data) {
9304 const guint8 *uri_aux = NULL;
9306 /* found the data atom that might contain the rtsp uri */
9307 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9308 "hndl atom, interpreting it as an URI");
9309 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9311 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9312 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9314 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9315 "didn't contain a rtsp address");
9317 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9322 /* skipping to the next entry */
9323 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9326 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9333 /* skip to the next entry */
9334 if (!gst_byte_reader_skip (&dref, size - 8))
9337 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9340 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9346 #define AMR_NB_ALL_MODES 0x81ff
9347 #define AMR_WB_ALL_MODES 0x83ff
9349 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9351 /* The 'damr' atom is of the form:
9353 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9354 * 32 b 8 b 16 b 8 b 8 b
9356 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9357 * represents the highest mode used in the stream (and thus the maximum
9358 * bitrate), with a couple of special cases as seen below.
9361 /* Map of frame type ID -> bitrate */
9362 static const guint nb_bitrates[] = {
9363 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9365 static const guint wb_bitrates[] = {
9366 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9372 gst_buffer_map (buf, &map, GST_MAP_READ);
9374 if (map.size != 0x11) {
9375 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9379 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9380 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9381 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9385 mode_set = QT_UINT16 (map.data + 13);
9387 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9388 max_mode = 7 + (wb ? 1 : 0);
9390 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9391 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9393 if (max_mode == -1) {
9394 GST_DEBUG ("No mode indication was found (mode set) = %x",
9399 gst_buffer_unmap (buf, &map);
9400 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9403 gst_buffer_unmap (buf, &map);
9408 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9409 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9412 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9418 if (gst_byte_reader_get_remaining (reader) < 36)
9421 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9422 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9423 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9424 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9425 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9426 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9427 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9428 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9429 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9431 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9432 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9433 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9435 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9436 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9438 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9439 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9446 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9447 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9454 * This macro will only compare value abdegh, it expects cfi to have already
9457 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9458 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9460 /* only handle the cases where the last column has standard values */
9461 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9462 const gchar *rotation_tag = NULL;
9464 /* no rotation needed */
9465 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9467 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9468 rotation_tag = "rotate-90";
9469 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9470 rotation_tag = "rotate-180";
9471 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9472 rotation_tag = "rotate-270";
9474 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9477 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9479 if (rotation_tag != NULL) {
9480 if (*taglist == NULL)
9481 *taglist = gst_tag_list_new_empty ();
9482 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9483 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9486 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9490 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9491 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9492 * Common Encryption (cenc), the function will also parse the tenc box (defined
9493 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9494 * (typically an enc[v|a|t|s] sample entry); the function will set
9495 * @original_fmt to the fourcc of the original unencrypted stream format.
9496 * Returns TRUE if successful; FALSE otherwise. */
9498 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9499 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9506 g_return_val_if_fail (qtdemux != NULL, FALSE);
9507 g_return_val_if_fail (stream != NULL, FALSE);
9508 g_return_val_if_fail (container != NULL, FALSE);
9509 g_return_val_if_fail (original_fmt != NULL, FALSE);
9511 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9512 if (G_UNLIKELY (!sinf)) {
9513 if (stream->protection_scheme_type == FOURCC_cenc) {
9514 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9515 "mandatory for Common Encryption");
9521 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9522 if (G_UNLIKELY (!frma)) {
9523 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9527 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9528 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9529 GST_FOURCC_ARGS (*original_fmt));
9531 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9533 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9536 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9537 stream->protection_scheme_version =
9538 QT_UINT32 ((const guint8 *) schm->data + 16);
9540 GST_DEBUG_OBJECT (qtdemux,
9541 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9542 "protection_scheme_version: %#010x",
9543 GST_FOURCC_ARGS (stream->protection_scheme_type),
9544 stream->protection_scheme_version);
9546 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9548 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9551 if (stream->protection_scheme_type == FOURCC_cenc) {
9552 QtDemuxCencSampleSetInfo *info;
9554 const guint8 *tenc_data;
9555 guint32 isEncrypted;
9557 const guint8 *default_kid;
9560 if (G_UNLIKELY (!stream->protection_scheme_info))
9561 stream->protection_scheme_info =
9562 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9564 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9566 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9568 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9569 "which is mandatory for Common Encryption");
9572 tenc_data = (const guint8 *) tenc->data + 12;
9573 isEncrypted = QT_UINT24 (tenc_data);
9574 iv_size = QT_UINT8 (tenc_data + 3);
9575 default_kid = (tenc_data + 4);
9576 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9577 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9578 if (info->default_properties)
9579 gst_structure_free (info->default_properties);
9580 info->default_properties =
9581 gst_structure_new ("application/x-cenc",
9582 "iv_size", G_TYPE_UINT, iv_size,
9583 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9584 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9585 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9586 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9587 gst_buffer_unref (kid_buf);
9593 * With each track we associate a new QtDemuxStream that contains all the info
9595 * traks that do not decode to something (like strm traks) will not have a pad.
9598 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9619 QtDemuxStream *stream = NULL;
9620 gboolean new_stream = FALSE;
9621 gchar *codec = NULL;
9622 const guint8 *stsd_data;
9623 const guint8 *stsd_entry_data;
9624 guint remaining_stsd_len;
9625 guint stsd_entry_count;
9627 guint16 lang_code; /* quicktime lang code or packed iso code */
9629 guint32 tkhd_flags = 0;
9630 guint8 tkhd_version = 0;
9631 guint32 w = 0, h = 0;
9633 guint value_size, stsd_len, len;
9637 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9639 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9640 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9641 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9644 /* pick between 64 or 32 bits */
9645 value_size = tkhd_version == 1 ? 8 : 4;
9646 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9647 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9650 if (!qtdemux->got_moov) {
9651 if (qtdemux_find_stream (qtdemux, track_id))
9652 goto existing_stream;
9653 stream = _create_stream ();
9654 stream->track_id = track_id;
9657 stream = qtdemux_find_stream (qtdemux, track_id);
9659 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9663 /* reset reused stream */
9664 gst_qtdemux_stream_reset (qtdemux, stream);
9666 /* need defaults for fragments */
9667 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9669 if ((tkhd_flags & 1) == 0)
9670 stream->disabled = TRUE;
9672 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9673 tkhd_version, tkhd_flags, stream->track_id);
9675 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9678 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9679 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9680 if (qtdemux->major_brand != FOURCC_mjp2 ||
9681 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9685 len = QT_UINT32 ((guint8 *) mdhd->data);
9686 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9687 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9688 if (version == 0x01000000) {
9691 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9692 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9693 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9697 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9698 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9699 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9702 if (lang_code < 0x400) {
9703 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9704 } else if (lang_code == 0x7fff) {
9705 stream->lang_id[0] = 0; /* unspecified */
9707 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9708 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9709 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9710 stream->lang_id[3] = 0;
9713 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9715 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9717 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9718 lang_code, stream->lang_id);
9720 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9723 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9724 /* chapters track reference */
9725 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9727 gsize length = GST_READ_UINT32_BE (chap->data);
9728 if (qtdemux->chapters_track_id)
9729 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9732 qtdemux->chapters_track_id =
9733 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9738 /* fragmented files may have bogus duration in moov */
9739 if (!qtdemux->fragmented &&
9740 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9741 guint64 tdur1, tdur2;
9743 /* don't overflow */
9744 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9745 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9748 * some of those trailers, nowadays, have prologue images that are
9749 * themselves video tracks as well. I haven't really found a way to
9750 * identify those yet, except for just looking at their duration. */
9751 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9752 GST_WARNING_OBJECT (qtdemux,
9753 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9754 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9755 "found, assuming preview image or something; skipping track",
9756 stream->duration, stream->timescale, qtdemux->duration,
9757 qtdemux->timescale);
9759 gst_qtdemux_stream_free (qtdemux, stream);
9764 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9767 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9768 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9770 len = QT_UINT32 ((guint8 *) hdlr->data);
9772 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9773 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9774 GST_FOURCC_ARGS (stream->subtype));
9776 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9779 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9782 /*parse svmi header if existing */
9783 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9785 len = QT_UINT32 ((guint8 *) svmi->data);
9786 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9788 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9789 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9790 guint8 frame_type, frame_layout;
9792 /* MPEG-A stereo video */
9793 if (qtdemux->major_brand == FOURCC_ss02)
9794 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9796 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9797 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9798 switch (frame_type) {
9800 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9803 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9806 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9809 /* mode 3 is primary/secondary view sequence, ie
9810 * left/right views in separate tracks. See section 7.2
9811 * of ISO/IEC 23000-11:2009 */
9812 GST_FIXME_OBJECT (qtdemux,
9813 "Implement stereo video in separate streams");
9816 if ((frame_layout & 0x1) == 0)
9817 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9819 GST_LOG_OBJECT (qtdemux,
9820 "StereoVideo: composition type: %u, is_left_first: %u",
9821 frame_type, frame_layout);
9822 stream->multiview_mode = mode;
9823 stream->multiview_flags = flags;
9827 /* parse rest of tkhd */
9828 if (stream->subtype == FOURCC_vide) {
9831 /* version 1 uses some 64-bit ints */
9832 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9835 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9838 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9839 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9842 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9843 &stream->stream_tags);
9847 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9849 stsd_data = (const guint8 *) stsd->data;
9851 /* stsd should at least have one entry */
9852 stsd_len = QT_UINT32 (stsd_data);
9853 if (stsd_len < 24) {
9854 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9855 if (stream->subtype == FOURCC_vivo) {
9857 gst_qtdemux_stream_free (qtdemux, stream);
9864 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
9865 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
9866 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9867 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
9869 stsd_entry_data = stsd_data + 16;
9870 remaining_stsd_len = stsd_len - 16;
9871 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
9872 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
9874 /* and that entry should fit within stsd */
9875 len = QT_UINT32 (stsd_entry_data);
9876 if (len > remaining_stsd_len)
9879 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
9880 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9881 GST_FOURCC_ARGS (entry->fourcc));
9882 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9884 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9885 goto error_encrypted;
9887 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9888 /* FIXME this looks wrong, there might be multiple children
9889 * with the same type */
9890 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9891 stream->protected = TRUE;
9892 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9893 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9896 if (stream->subtype == FOURCC_vide) {
9898 gint depth, palette_size, palette_count;
9899 guint32 *palette_data = NULL;
9901 entry->sampled = TRUE;
9903 stream->display_width = w >> 16;
9904 stream->display_height = h >> 16;
9907 if (len < 86) /* TODO verify */
9910 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
9911 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
9912 entry->fps_n = 0; /* this is filled in later */
9913 entry->fps_d = 0; /* this is filled in later */
9914 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
9915 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
9917 /* if color_table_id is 0, ctab atom must follow; however some files
9918 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9919 * if color table is not present we'll correct the value */
9920 if (entry->color_table_id == 0 &&
9922 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
9923 entry->color_table_id = -1;
9926 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9927 entry->width, entry->height, entry->bits_per_sample,
9928 entry->color_table_id);
9930 depth = entry->bits_per_sample;
9932 /* more than 32 bits means grayscale */
9933 gray = (depth > 32);
9934 /* low 32 bits specify the depth */
9937 /* different number of palette entries is determined by depth. */
9939 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9940 palette_count = (1 << depth);
9941 palette_size = palette_count * 4;
9943 if (entry->color_table_id) {
9944 switch (palette_count) {
9948 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9951 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9956 g_memdup (ff_qt_grayscale_palette_16, palette_size);
9958 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9963 g_memdup (ff_qt_grayscale_palette_256, palette_size);
9965 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9968 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9969 (_("The video in this file might not play correctly.")),
9970 ("unsupported palette depth %d", depth));
9974 gint i, j, start, end;
9980 start = QT_UINT32 (stsd_entry_data + offset + 70);
9981 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
9982 end = QT_UINT16 (stsd_entry_data + offset + 76);
9984 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9985 start, end, palette_count);
9992 if (len < 94 + (end - start) * 8)
9995 /* palette is always the same size */
9996 palette_data = g_malloc0 (256 * 4);
9997 palette_size = 256 * 4;
9999 for (j = 0, i = start; i <= end; j++, i++) {
10000 guint32 a, r, g, b;
10002 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10003 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10004 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10005 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10007 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10008 (g & 0xff00) | (b >> 8);
10013 gst_caps_unref (entry->caps);
10016 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10018 if (G_UNLIKELY (!entry->caps)) {
10019 g_free (palette_data);
10020 goto unknown_stream;
10024 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10025 GST_TAG_VIDEO_CODEC, codec, NULL);
10030 if (palette_data) {
10033 if (entry->rgb8_palette)
10034 gst_memory_unref (entry->rgb8_palette);
10035 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10036 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10038 s = gst_caps_get_structure (entry->caps, 0);
10040 /* non-raw video has a palette_data property. raw video has the palette as
10041 * an extra plane that we append to the output buffers before we push
10043 if (!gst_structure_has_name (s, "video/x-raw")) {
10044 GstBuffer *palette;
10046 palette = gst_buffer_new ();
10047 gst_buffer_append_memory (palette, entry->rgb8_palette);
10048 entry->rgb8_palette = NULL;
10050 gst_caps_set_simple (entry->caps, "palette_data",
10051 GST_TYPE_BUFFER, palette, NULL);
10052 gst_buffer_unref (palette);
10054 } else if (palette_count != 0) {
10055 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10056 (NULL), ("Unsupported palette depth %d", depth));
10059 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10060 QT_UINT16 (stsd_entry_data + offset + 32));
10066 /* pick 'the' stsd child */
10067 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10068 if (!stream->protected) {
10069 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10073 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10079 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10080 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10081 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10082 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10086 const guint8 *pasp_data = (const guint8 *) pasp->data;
10087 gint len = QT_UINT32 (pasp_data);
10090 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10091 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10093 CUR_STREAM (stream)->par_w = 0;
10094 CUR_STREAM (stream)->par_h = 0;
10097 CUR_STREAM (stream)->par_w = 0;
10098 CUR_STREAM (stream)->par_h = 0;
10102 const guint8 *fiel_data = (const guint8 *) fiel->data;
10103 gint len = QT_UINT32 (fiel_data);
10106 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10107 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10112 const guint8 *colr_data = (const guint8 *) colr->data;
10113 gint len = QT_UINT32 (colr_data);
10115 if (len == 19 || len == 18) {
10116 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10118 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10119 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10120 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10121 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10122 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10124 switch (primaries) {
10126 CUR_STREAM (stream)->colorimetry.primaries =
10127 GST_VIDEO_COLOR_PRIMARIES_BT709;
10130 CUR_STREAM (stream)->colorimetry.primaries =
10131 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10134 CUR_STREAM (stream)->colorimetry.primaries =
10135 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10138 CUR_STREAM (stream)->colorimetry.primaries =
10139 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10145 switch (transfer_function) {
10147 CUR_STREAM (stream)->colorimetry.transfer =
10148 GST_VIDEO_TRANSFER_BT709;
10151 CUR_STREAM (stream)->colorimetry.transfer =
10152 GST_VIDEO_TRANSFER_SMPTE240M;
10160 CUR_STREAM (stream)->colorimetry.matrix =
10161 GST_VIDEO_COLOR_MATRIX_BT709;
10164 CUR_STREAM (stream)->colorimetry.matrix =
10165 GST_VIDEO_COLOR_MATRIX_BT601;
10168 CUR_STREAM (stream)->colorimetry.matrix =
10169 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10172 CUR_STREAM (stream)->colorimetry.matrix =
10173 GST_VIDEO_COLOR_MATRIX_BT2020;
10179 CUR_STREAM (stream)->colorimetry.range =
10180 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10181 GST_VIDEO_COLOR_RANGE_16_235;
10183 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10186 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10191 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10192 stream->stream_tags);
10199 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10200 const guint8 *avc_data = stsd_entry_data + 0x56;
10203 while (len >= 0x8) {
10206 if (QT_UINT32 (avc_data) <= len)
10207 size = QT_UINT32 (avc_data) - 0x8;
10212 /* No real data, so break out */
10215 switch (QT_FOURCC (avc_data + 0x4)) {
10218 /* parse, if found */
10221 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10223 /* First 4 bytes are the length of the atom, the next 4 bytes
10224 * are the fourcc, the next 1 byte is the version, and the
10225 * subsequent bytes are profile_tier_level structure like data. */
10226 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10227 avc_data + 8 + 1, size - 1);
10228 buf = gst_buffer_new_and_alloc (size);
10229 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10230 gst_caps_set_simple (entry->caps,
10231 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10232 gst_buffer_unref (buf);
10240 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10242 /* First 4 bytes are the length of the atom, the next 4 bytes
10243 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10244 * next 1 byte is the version, and the
10245 * subsequent bytes are sequence parameter set like data. */
10247 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10249 gst_codec_utils_h264_caps_set_level_and_profile
10250 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10252 buf = gst_buffer_new_and_alloc (size);
10253 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10254 gst_caps_set_simple (entry->caps,
10255 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10256 gst_buffer_unref (buf);
10262 guint avg_bitrate, max_bitrate;
10264 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10268 max_bitrate = QT_UINT32 (avc_data + 0xc);
10269 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10271 if (!max_bitrate && !avg_bitrate)
10274 /* Some muxers seem to swap the average and maximum bitrates
10275 * (I'm looking at you, YouTube), so we swap for sanity. */
10276 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10277 guint temp = avg_bitrate;
10279 avg_bitrate = max_bitrate;
10280 max_bitrate = temp;
10283 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10284 gst_tag_list_add (stream->stream_tags,
10285 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10286 max_bitrate, NULL);
10288 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10289 gst_tag_list_add (stream->stream_tags,
10290 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10302 avc_data += size + 8;
10311 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10312 const guint8 *hevc_data = stsd_entry_data + 0x56;
10315 while (len >= 0x8) {
10318 if (QT_UINT32 (hevc_data) <= len)
10319 size = QT_UINT32 (hevc_data) - 0x8;
10324 /* No real data, so break out */
10327 switch (QT_FOURCC (hevc_data + 0x4)) {
10330 /* parse, if found */
10333 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
10335 /* First 4 bytes are the length of the atom, the next 4 bytes
10336 * are the fourcc, the next 1 byte is the version, and the
10337 * subsequent bytes are sequence parameter set like data. */
10338 gst_codec_utils_h265_caps_set_level_tier_and_profile
10339 (entry->caps, hevc_data + 8 + 1, size - 1);
10341 buf = gst_buffer_new_and_alloc (size);
10342 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10343 gst_caps_set_simple (entry->caps,
10344 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10345 gst_buffer_unref (buf);
10352 hevc_data += size + 8;
10365 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10366 GST_FOURCC_ARGS (fourcc));
10368 /* codec data might be in glbl extension atom */
10370 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10376 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10378 len = QT_UINT32 (data);
10381 buf = gst_buffer_new_and_alloc (len);
10382 gst_buffer_fill (buf, 0, data + 8, len);
10383 gst_caps_set_simple (entry->caps,
10384 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10385 gst_buffer_unref (buf);
10392 /* see annex I of the jpeg2000 spec */
10393 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10394 const guint8 *data;
10395 const gchar *colorspace = NULL;
10397 guint32 ncomp_map = 0;
10398 gint32 *comp_map = NULL;
10399 guint32 nchan_def = 0;
10400 gint32 *chan_def = NULL;
10402 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10403 /* some required atoms */
10404 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10407 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10411 /* number of components; redundant with info in codestream, but useful
10413 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10414 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10416 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10418 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10421 GST_DEBUG_OBJECT (qtdemux, "found colr");
10422 /* extract colour space info */
10423 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10424 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10426 colorspace = "sRGB";
10429 colorspace = "GRAY";
10432 colorspace = "sYUV";
10440 /* colr is required, and only values 16, 17, and 18 are specified,
10441 so error if we have no colorspace */
10444 /* extract component mapping */
10445 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10447 guint32 cmap_len = 0;
10449 cmap_len = QT_UINT32 (cmap->data);
10450 if (cmap_len >= 8) {
10451 /* normal box, subtract off header */
10453 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10454 if (cmap_len % 4 == 0) {
10455 ncomp_map = (cmap_len / 4);
10456 comp_map = g_new0 (gint32, ncomp_map);
10457 for (i = 0; i < ncomp_map; i++) {
10460 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10461 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10462 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10463 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10468 /* extract channel definitions */
10469 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10471 guint32 cdef_len = 0;
10473 cdef_len = QT_UINT32 (cdef->data);
10474 if (cdef_len >= 10) {
10475 /* normal box, subtract off header and len */
10477 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10478 if (cdef_len % 6 == 0) {
10479 nchan_def = (cdef_len / 6);
10480 chan_def = g_new0 (gint32, nchan_def);
10481 for (i = 0; i < nchan_def; i++)
10483 for (i = 0; i < nchan_def; i++) {
10484 guint16 cn, typ, asoc;
10485 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10486 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10487 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10488 if (cn < nchan_def) {
10491 chan_def[cn] = asoc;
10494 chan_def[cn] = 0; /* alpha */
10497 chan_def[cn] = -typ;
10505 gst_caps_set_simple (entry->caps,
10506 "num-components", G_TYPE_INT, ncomp, NULL);
10507 gst_caps_set_simple (entry->caps,
10508 "colorspace", G_TYPE_STRING, colorspace, NULL);
10511 GValue arr = { 0, };
10512 GValue elt = { 0, };
10514 g_value_init (&arr, GST_TYPE_ARRAY);
10515 g_value_init (&elt, G_TYPE_INT);
10516 for (i = 0; i < ncomp_map; i++) {
10517 g_value_set_int (&elt, comp_map[i]);
10518 gst_value_array_append_value (&arr, &elt);
10520 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10521 "component-map", &arr);
10522 g_value_unset (&elt);
10523 g_value_unset (&arr);
10528 GValue arr = { 0, };
10529 GValue elt = { 0, };
10531 g_value_init (&arr, GST_TYPE_ARRAY);
10532 g_value_init (&elt, G_TYPE_INT);
10533 for (i = 0; i < nchan_def; i++) {
10534 g_value_set_int (&elt, chan_def[i]);
10535 gst_value_array_append_value (&arr, &elt);
10537 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10538 "channel-definitions", &arr);
10539 g_value_unset (&elt);
10540 g_value_unset (&arr);
10544 /* some optional atoms */
10545 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10546 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10548 /* indicate possible fields in caps */
10550 data = (guint8 *) field->data + 8;
10552 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10553 (gint) * data, NULL);
10555 /* add codec_data if provided */
10560 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10561 data = prefix->data;
10562 len = QT_UINT32 (data);
10565 buf = gst_buffer_new_and_alloc (len);
10566 gst_buffer_fill (buf, 0, data + 8, len);
10567 gst_caps_set_simple (entry->caps,
10568 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10569 gst_buffer_unref (buf);
10578 GstBuffer *seqh = NULL;
10579 const guint8 *gamma_data = NULL;
10580 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
10582 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
10585 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
10586 QT_FP32 (gamma_data), NULL);
10589 /* sorry for the bad name, but we don't know what this is, other
10590 * than its own fourcc */
10591 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
10593 gst_buffer_unref (seqh);
10596 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10597 buf = gst_buffer_new_and_alloc (len);
10598 gst_buffer_fill (buf, 0, stsd_data, len);
10599 gst_caps_set_simple (entry->caps,
10600 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10601 gst_buffer_unref (buf);
10606 /* https://developer.apple.com/standards/qtff-2001.pdf,
10607 * page 92, "Video Sample Description", under table 3.1 */
10610 const gint compressor_offset =
10611 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10612 const gint min_size = compressor_offset + 32 + 2 + 2;
10615 guint16 color_table_id = 0;
10618 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10620 /* recover information on interlaced/progressive */
10621 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10625 len = QT_UINT32 (jpeg->data);
10626 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10628 if (len >= min_size) {
10629 gst_byte_reader_init (&br, jpeg->data, len);
10631 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10632 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10633 if (color_table_id != 0) {
10634 /* the spec says there can be concatenated chunks in the data, and we want
10635 * to find one called field. Walk through them. */
10636 gint offset = min_size;
10637 while (offset + 8 < len) {
10638 guint32 size = 0, tag;
10639 ok = gst_byte_reader_get_uint32_le (&br, &size);
10640 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10641 if (!ok || size < 8) {
10642 GST_WARNING_OBJECT (qtdemux,
10643 "Failed to walk optional chunk list");
10646 GST_DEBUG_OBJECT (qtdemux,
10647 "Found optional %4.4s chunk, size %u",
10648 (const char *) &tag, size);
10649 if (tag == FOURCC_fiel) {
10650 guint8 n_fields = 0, ordering = 0;
10651 gst_byte_reader_get_uint8 (&br, &n_fields);
10652 gst_byte_reader_get_uint8 (&br, &ordering);
10653 if (n_fields == 1 || n_fields == 2) {
10654 GST_DEBUG_OBJECT (qtdemux,
10655 "Found fiel tag with %u fields, ordering %u",
10656 n_fields, ordering);
10658 gst_caps_set_simple (CUR_STREAM (stream)->caps,
10659 "interlace-mode", G_TYPE_STRING, "interleaved",
10662 GST_WARNING_OBJECT (qtdemux,
10663 "Found fiel tag with invalid fields (%u)", n_fields);
10669 GST_DEBUG_OBJECT (qtdemux,
10670 "Color table ID is 0, not trying to get interlacedness");
10673 GST_WARNING_OBJECT (qtdemux,
10674 "Length of jpeg chunk is too small, not trying to get interlacedness");
10682 gst_caps_set_simple (entry->caps,
10683 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
10689 GNode *xith, *xdxt;
10691 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10692 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10696 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10700 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10701 /* collect the headers and store them in a stream list so that we can
10702 * send them out first */
10703 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10713 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10714 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10717 ovc1_data = ovc1->data;
10718 ovc1_len = QT_UINT32 (ovc1_data);
10719 if (ovc1_len <= 198) {
10720 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10723 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10724 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10725 gst_caps_set_simple (entry->caps,
10726 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10727 gst_buffer_unref (buf);
10732 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10733 const guint8 *vc1_data = stsd_entry_data + 0x56;
10739 if (QT_UINT32 (vc1_data) <= len)
10740 size = QT_UINT32 (vc1_data) - 8;
10745 /* No real data, so break out */
10748 switch (QT_FOURCC (vc1_data + 0x4)) {
10749 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10753 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10754 buf = gst_buffer_new_and_alloc (size);
10755 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10756 gst_caps_set_simple (entry->caps,
10757 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10758 gst_buffer_unref (buf);
10765 vc1_data += size + 8;
10774 GST_INFO_OBJECT (qtdemux,
10775 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10776 GST_FOURCC_ARGS (fourcc), entry->caps);
10778 } else if (stream->subtype == FOURCC_soun) {
10779 int version, samplesize;
10780 guint16 compression_id;
10781 gboolean amrwb = FALSE;
10784 /* sample description entry (16) + sound sample description v0 (20) */
10788 version = QT_UINT32 (stsd_entry_data + offset);
10789 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
10790 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
10791 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
10792 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
10794 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10795 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10796 QT_UINT32 (stsd_entry_data + offset + 4));
10797 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10798 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10799 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10800 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10801 QT_UINT16 (stsd_entry_data + offset + 14));
10802 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10804 if (compression_id == 0xfffe)
10805 entry->sampled = TRUE;
10807 /* first assume uncompressed audio */
10808 entry->bytes_per_sample = samplesize / 8;
10809 entry->samples_per_frame = entry->n_channels;
10810 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
10811 entry->samples_per_packet = entry->samples_per_frame;
10812 entry->bytes_per_packet = entry->bytes_per_sample;
10816 /* Yes, these have to be hard-coded */
10819 entry->samples_per_packet = 6;
10820 entry->bytes_per_packet = 1;
10821 entry->bytes_per_frame = 1 * entry->n_channels;
10822 entry->bytes_per_sample = 1;
10823 entry->samples_per_frame = 6 * entry->n_channels;
10828 entry->samples_per_packet = 3;
10829 entry->bytes_per_packet = 1;
10830 entry->bytes_per_frame = 1 * entry->n_channels;
10831 entry->bytes_per_sample = 1;
10832 entry->samples_per_frame = 3 * entry->n_channels;
10837 entry->samples_per_packet = 64;
10838 entry->bytes_per_packet = 34;
10839 entry->bytes_per_frame = 34 * entry->n_channels;
10840 entry->bytes_per_sample = 2;
10841 entry->samples_per_frame = 64 * entry->n_channels;
10847 entry->samples_per_packet = 1;
10848 entry->bytes_per_packet = 1;
10849 entry->bytes_per_frame = 1 * entry->n_channels;
10850 entry->bytes_per_sample = 1;
10851 entry->samples_per_frame = 1 * entry->n_channels;
10856 entry->samples_per_packet = 160;
10857 entry->bytes_per_packet = 33;
10858 entry->bytes_per_frame = 33 * entry->n_channels;
10859 entry->bytes_per_sample = 2;
10860 entry->samples_per_frame = 160 * entry->n_channels;
10867 if (version == 0x00010000) {
10868 /* sample description entry (16) + sound sample description v1 (20+16) */
10880 /* only parse extra decoding config for non-pcm audio */
10881 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
10882 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
10883 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
10884 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
10886 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10887 entry->samples_per_packet);
10888 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10889 entry->bytes_per_packet);
10890 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10891 entry->bytes_per_frame);
10892 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10893 entry->bytes_per_sample);
10895 if (!entry->sampled && entry->bytes_per_packet) {
10896 entry->samples_per_frame = (entry->bytes_per_frame /
10897 entry->bytes_per_packet) * entry->samples_per_packet;
10898 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10899 entry->samples_per_frame);
10904 } else if (version == 0x00020000) {
10911 /* sample description entry (16) + sound sample description v2 (56) */
10915 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
10916 entry->rate = qtfp.fp;
10917 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
10919 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10920 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10921 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10922 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10923 QT_UINT32 (stsd_entry_data + offset + 20));
10924 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10925 QT_UINT32 (stsd_entry_data + offset + 24));
10926 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10927 QT_UINT32 (stsd_entry_data + offset + 28));
10928 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10929 QT_UINT32 (stsd_entry_data + offset + 32));
10930 } else if (version != 0x00000) {
10931 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
10936 gst_caps_unref (entry->caps);
10938 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
10939 stsd_entry_data + 32, len - 16, &codec);
10947 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10949 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10951 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10953 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10956 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10957 gst_caps_set_simple (entry->caps,
10958 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
10965 const guint8 *owma_data;
10966 const gchar *codec_name = NULL;
10970 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10971 /* FIXME this should also be gst_riff_strf_auds,
10972 * but the latter one is actually missing bits-per-sample :( */
10977 gint32 nSamplesPerSec;
10978 gint32 nAvgBytesPerSec;
10979 gint16 nBlockAlign;
10980 gint16 wBitsPerSample;
10983 WAVEFORMATEX *wfex;
10985 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10986 owma_data = stsd_entry_data;
10987 owma_len = QT_UINT32 (owma_data);
10988 if (owma_len <= 54) {
10989 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10992 wfex = (WAVEFORMATEX *) (owma_data + 36);
10993 buf = gst_buffer_new_and_alloc (owma_len - 54);
10994 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10995 if (wfex->wFormatTag == 0x0161) {
10996 codec_name = "Windows Media Audio";
10998 } else if (wfex->wFormatTag == 0x0162) {
10999 codec_name = "Windows Media Audio 9 Pro";
11001 } else if (wfex->wFormatTag == 0x0163) {
11002 codec_name = "Windows Media Audio 9 Lossless";
11003 /* is that correct? gstffmpegcodecmap.c is missing it, but
11004 * fluendo codec seems to support it */
11008 gst_caps_set_simple (entry->caps,
11009 "codec_data", GST_TYPE_BUFFER, buf,
11010 "wmaversion", G_TYPE_INT, version,
11011 "block_align", G_TYPE_INT,
11012 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11013 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11014 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11015 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11016 gst_buffer_unref (buf);
11020 codec = g_strdup (codec_name);
11026 gint len = QT_UINT32 (stsd_entry_data) - offset;
11027 const guint8 *wfex_data = stsd_entry_data + offset;
11028 const gchar *codec_name = NULL;
11030 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11031 /* FIXME this should also be gst_riff_strf_auds,
11032 * but the latter one is actually missing bits-per-sample :( */
11037 gint32 nSamplesPerSec;
11038 gint32 nAvgBytesPerSec;
11039 gint16 nBlockAlign;
11040 gint16 wBitsPerSample;
11045 /* FIXME: unify with similar wavformatex parsing code above */
11046 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11052 if (QT_UINT32 (wfex_data) <= len)
11053 size = QT_UINT32 (wfex_data) - 8;
11058 /* No real data, so break out */
11061 switch (QT_FOURCC (wfex_data + 4)) {
11062 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11064 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11069 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11070 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11071 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11072 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11073 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11074 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11075 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11077 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11078 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11079 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11080 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11081 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11082 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11084 if (wfex.wFormatTag == 0x0161) {
11085 codec_name = "Windows Media Audio";
11087 } else if (wfex.wFormatTag == 0x0162) {
11088 codec_name = "Windows Media Audio 9 Pro";
11090 } else if (wfex.wFormatTag == 0x0163) {
11091 codec_name = "Windows Media Audio 9 Lossless";
11092 /* is that correct? gstffmpegcodecmap.c is missing it, but
11093 * fluendo codec seems to support it */
11097 gst_caps_set_simple (entry->caps,
11098 "wmaversion", G_TYPE_INT, version,
11099 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11100 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11101 "width", G_TYPE_INT, wfex.wBitsPerSample,
11102 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11104 if (size > wfex.cbSize) {
11107 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11108 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11109 size - wfex.cbSize);
11110 gst_caps_set_simple (entry->caps,
11111 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11112 gst_buffer_unref (buf);
11114 GST_WARNING_OBJECT (qtdemux, "no codec data");
11119 codec = g_strdup (codec_name);
11127 wfex_data += size + 8;
11133 const guint8 *opus_data;
11134 guint8 *channel_mapping = NULL;
11137 guint8 channel_mapping_family;
11138 guint8 stream_count;
11139 guint8 coupled_count;
11142 opus_data = stsd_entry_data;
11144 channels = GST_READ_UINT8 (opus_data + 45);
11145 rate = GST_READ_UINT32_LE (opus_data + 48);
11146 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11147 stream_count = GST_READ_UINT8 (opus_data + 55);
11148 coupled_count = GST_READ_UINT8 (opus_data + 56);
11150 if (channels > 0) {
11151 channel_mapping = g_malloc (channels * sizeof (guint8));
11152 for (i = 0; i < channels; i++)
11153 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11156 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11157 channel_mapping_family, stream_count, coupled_count,
11169 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11170 GST_TAG_AUDIO_CODEC, codec, NULL);
11174 /* some bitrate info may have ended up in caps */
11175 s = gst_caps_get_structure (entry->caps, 0);
11176 gst_structure_get_int (s, "bitrate", &bitrate);
11178 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11179 GST_TAG_BITRATE, bitrate, NULL);
11182 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11183 if (!stream->protected) {
11185 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11189 if (stream->protected && fourcc == FOURCC_mp4a) {
11190 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11194 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11202 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11204 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11206 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11210 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11211 16 bits is a byte-swapped wave-style codec identifier,
11212 and we can find a WAVE header internally to a 'wave' atom here.
11213 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11214 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11217 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11218 if (len < offset + 20) {
11219 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11221 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11222 const guint8 *data = stsd_entry_data + offset + 16;
11224 GNode *waveheadernode;
11226 wavenode = g_node_new ((guint8 *) data);
11227 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11228 const guint8 *waveheader;
11231 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11232 if (waveheadernode) {
11233 waveheader = (const guint8 *) waveheadernode->data;
11234 headerlen = QT_UINT32 (waveheader);
11236 if (headerlen > 8) {
11237 gst_riff_strf_auds *header = NULL;
11238 GstBuffer *headerbuf;
11244 headerbuf = gst_buffer_new_and_alloc (headerlen);
11245 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11247 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11248 headerbuf, &header, &extra)) {
11249 gst_caps_unref (entry->caps);
11250 /* FIXME: Need to do something with the channel reorder map */
11252 gst_riff_create_audio_caps (header->format, NULL, header,
11253 extra, NULL, NULL, NULL);
11256 gst_buffer_unref (extra);
11261 GST_DEBUG ("Didn't find waveheadernode for this codec");
11263 g_node_destroy (wavenode);
11266 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11267 stream->stream_tags);
11271 /* FIXME: what is in the chunk? */
11274 gint len = QT_UINT32 (stsd_data);
11276 /* seems to be always = 116 = 0x74 */
11282 gint len = QT_UINT32 (stsd_entry_data);
11285 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11287 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11288 gst_caps_set_simple (entry->caps,
11289 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11290 gst_buffer_unref (buf);
11292 gst_caps_set_simple (entry->caps,
11293 "samplesize", G_TYPE_INT, samplesize, NULL);
11298 GNode *alac, *wave = NULL;
11300 /* apparently, m4a has this atom appended directly in the stsd entry,
11301 * while mov has it in a wave atom */
11302 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11304 /* alac now refers to stsd entry atom */
11305 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11307 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11309 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11312 const guint8 *alac_data = alac->data;
11313 gint len = QT_UINT32 (alac->data);
11317 GST_DEBUG_OBJECT (qtdemux,
11318 "discarding alac atom with unexpected len %d", len);
11320 /* codec-data contains alac atom size and prefix,
11321 * ffmpeg likes it that way, not quite gst-ish though ...*/
11322 buf = gst_buffer_new_and_alloc (len);
11323 gst_buffer_fill (buf, 0, alac->data, len);
11324 gst_caps_set_simple (entry->caps,
11325 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11326 gst_buffer_unref (buf);
11328 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11329 entry->n_channels = QT_UINT8 (alac_data + 21);
11330 entry->rate = QT_UINT32 (alac_data + 32);
11333 gst_caps_set_simple (entry->caps,
11334 "samplesize", G_TYPE_INT, samplesize, NULL);
11339 /* The codingname of the sample entry is 'fLaC' */
11340 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11343 /* The 'dfLa' box is added to the sample entry to convey
11344 initializing information for the decoder. */
11345 const GNode *dfla =
11346 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11349 const guint32 len = QT_UINT32 (dfla->data);
11351 /* Must contain at least dfLa box header (12),
11352 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11354 GST_DEBUG_OBJECT (qtdemux,
11355 "discarding dfla atom with unexpected len %d", len);
11357 /* skip dfLa header to get the METADATA_BLOCKs */
11358 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11359 const guint32 metadata_blocks_len = len - 12;
11361 gchar *stream_marker = g_strdup ("fLaC");
11362 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11363 strlen (stream_marker));
11366 guint32 remainder = 0;
11367 guint32 block_size = 0;
11368 gboolean is_last = FALSE;
11370 GValue array = G_VALUE_INIT;
11371 GValue value = G_VALUE_INIT;
11373 g_value_init (&array, GST_TYPE_ARRAY);
11374 g_value_init (&value, GST_TYPE_BUFFER);
11376 gst_value_set_buffer (&value, block);
11377 gst_value_array_append_value (&array, &value);
11378 g_value_reset (&value);
11380 gst_buffer_unref (block);
11382 /* check there's at least one METADATA_BLOCK_HEADER's worth
11383 * of data, and we haven't already finished parsing */
11384 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11385 remainder = metadata_blocks_len - index;
11387 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11389 (metadata_blocks[index + 1] << 16) +
11390 (metadata_blocks[index + 2] << 8) +
11391 metadata_blocks[index + 3];
11393 /* be careful not to read off end of box */
11394 if (block_size > remainder) {
11398 is_last = metadata_blocks[index] >> 7;
11400 block = gst_buffer_new_and_alloc (block_size);
11402 gst_buffer_fill (block, 0, &metadata_blocks[index],
11405 gst_value_set_buffer (&value, block);
11406 gst_value_array_append_value (&array, &value);
11407 g_value_reset (&value);
11409 gst_buffer_unref (block);
11411 index += block_size;
11414 /* only append the metadata if we successfully read all of it */
11416 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11417 (stream)->caps, 0), "streamheader", &array);
11419 GST_WARNING_OBJECT (qtdemux,
11420 "discarding all METADATA_BLOCKs due to invalid "
11421 "block_size %d at idx %d, rem %d", block_size, index,
11425 g_value_unset (&value);
11426 g_value_unset (&array);
11428 /* The sample rate obtained from the stsd may not be accurate
11429 * since it cannot represent rates greater than 65535Hz, so
11430 * override that value with the sample rate from the
11431 * METADATA_BLOCK_STREAMINFO block */
11432 CUR_STREAM (stream)->rate =
11433 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11444 gint len = QT_UINT32 (stsd_entry_data);
11447 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11450 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11452 /* If we have enough data, let's try to get the 'damr' atom. See
11453 * the 3GPP container spec (26.244) for more details. */
11454 if ((len - 0x34) > 8 &&
11455 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11456 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11457 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11460 gst_caps_set_simple (entry->caps,
11461 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11462 gst_buffer_unref (buf);
11468 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11469 gint len = QT_UINT32 (stsd_entry_data);
11472 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11474 if (sound_version == 1) {
11475 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11476 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11477 guint8 codec_data[2];
11479 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11481 gint sample_rate_index =
11482 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11484 /* build AAC codec data */
11485 codec_data[0] = profile << 3;
11486 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11487 codec_data[1] = (sample_rate_index & 0x01) << 7;
11488 codec_data[1] |= (channels & 0xF) << 3;
11490 buf = gst_buffer_new_and_alloc (2);
11491 gst_buffer_fill (buf, 0, codec_data, 2);
11492 gst_caps_set_simple (entry->caps,
11493 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11494 gst_buffer_unref (buf);
11500 /* Fully handled elsewhere */
11503 GST_INFO_OBJECT (qtdemux,
11504 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11508 GST_INFO_OBJECT (qtdemux,
11509 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11510 GST_FOURCC_ARGS (fourcc), entry->caps);
11512 } else if (stream->subtype == FOURCC_strm) {
11513 if (fourcc == FOURCC_rtsp) {
11514 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11516 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11517 GST_FOURCC_ARGS (fourcc));
11518 goto unknown_stream;
11520 entry->sampled = TRUE;
11521 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11522 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11524 entry->sampled = TRUE;
11525 entry->sparse = TRUE;
11528 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11531 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11532 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11537 /* hunt for sort-of codec data */
11541 GNode *mp4s = NULL;
11542 GNode *esds = NULL;
11544 /* look for palette in a stsd->mp4s->esds sub-atom */
11545 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11547 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11548 if (esds == NULL) {
11550 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11554 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11555 stream->stream_tags);
11559 GST_INFO_OBJECT (qtdemux,
11560 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11563 GST_INFO_OBJECT (qtdemux,
11564 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11565 GST_FOURCC_ARGS (fourcc), entry->caps);
11567 /* everything in 1 sample */
11568 entry->sampled = TRUE;
11571 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11574 if (entry->caps == NULL)
11575 goto unknown_stream;
11578 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11579 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11585 /* promote to sampled format */
11586 if (entry->fourcc == FOURCC_samr) {
11587 /* force mono 8000 Hz for AMR */
11588 entry->sampled = TRUE;
11589 entry->n_channels = 1;
11590 entry->rate = 8000;
11591 } else if (entry->fourcc == FOURCC_sawb) {
11592 /* force mono 16000 Hz for AMR-WB */
11593 entry->sampled = TRUE;
11594 entry->n_channels = 1;
11595 entry->rate = 16000;
11596 } else if (entry->fourcc == FOURCC_mp4a) {
11597 entry->sampled = TRUE;
11601 stsd_entry_data += len;
11602 remaining_stsd_len -= len;
11606 /* collect sample information */
11607 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11608 goto samples_failed;
11610 if (qtdemux->fragmented) {
11613 /* need all moov samples as basis; probably not many if any at all */
11614 /* prevent moof parsing taking of at this time */
11615 offset = qtdemux->moof_offset;
11616 qtdemux->moof_offset = 0;
11617 if (stream->n_samples &&
11618 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11619 qtdemux->moof_offset = offset;
11620 goto samples_failed;
11622 qtdemux->moof_offset = 0;
11623 /* movie duration more reliable in this case (e.g. mehd) */
11624 if (qtdemux->segment.duration &&
11625 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11627 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11630 /* configure segments */
11631 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11632 goto segments_failed;
11634 /* add some language tag, if useful */
11635 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11636 strcmp (stream->lang_id, "und")) {
11637 const gchar *lang_code;
11639 /* convert ISO 639-2 code to ISO 639-1 */
11640 lang_code = gst_tag_get_language_code (stream->lang_id);
11641 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11642 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11645 /* Check for UDTA tags */
11646 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11647 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11650 /* now we are ready to add the stream */
11651 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11652 goto too_many_streams;
11654 if (!qtdemux->got_moov) {
11655 qtdemux->streams[qtdemux->n_streams] = stream;
11656 qtdemux->n_streams++;
11657 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11665 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11667 gst_qtdemux_stream_free (qtdemux, stream);
11672 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11673 (_("This file is corrupt and cannot be played.")), (NULL));
11675 gst_qtdemux_stream_free (qtdemux, stream);
11680 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11682 gst_qtdemux_stream_free (qtdemux, stream);
11688 /* we posted an error already */
11689 /* free stbl sub-atoms */
11690 gst_qtdemux_stbl_free (stream);
11692 gst_qtdemux_stream_free (qtdemux, stream);
11697 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11700 gst_qtdemux_stream_free (qtdemux, stream);
11705 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11706 GST_FOURCC_ARGS (stream->subtype));
11708 gst_qtdemux_stream_free (qtdemux, stream);
11713 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11714 (_("This file contains too many streams. Only playing first %d"),
11715 GST_QTDEMUX_MAX_STREAMS), (NULL));
11720 /* If we can estimate the overall bitrate, and don't have information about the
11721 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11722 * the overall bitrate minus the sum of the bitrates of all other streams. This
11723 * should be useful for the common case where we have one audio and one video
11724 * stream and can estimate the bitrate of one, but not the other. */
11726 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11728 QtDemuxStream *stream = NULL;
11729 gint64 size, sys_bitrate, sum_bitrate = 0;
11730 GstClockTime duration;
11734 if (qtdemux->fragmented)
11737 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11739 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11741 GST_DEBUG_OBJECT (qtdemux,
11742 "Size in bytes of the stream not known - bailing");
11746 /* Subtract the header size */
11747 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11748 size, qtdemux->header_size);
11750 if (size < qtdemux->header_size)
11753 size = size - qtdemux->header_size;
11755 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11756 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11760 for (i = 0; i < qtdemux->n_streams; i++) {
11761 switch (qtdemux->streams[i]->subtype) {
11764 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11765 CUR_STREAM (qtdemux->streams[i])->caps);
11766 /* retrieve bitrate, prefer avg then max */
11768 if (qtdemux->streams[i]->stream_tags) {
11769 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11770 GST_TAG_MAXIMUM_BITRATE, &bitrate))
11771 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11772 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11773 GST_TAG_NOMINAL_BITRATE, &bitrate))
11774 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11775 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11776 GST_TAG_BITRATE, &bitrate))
11777 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11780 sum_bitrate += bitrate;
11783 GST_DEBUG_OBJECT (qtdemux,
11784 ">1 stream with unknown bitrate - bailing");
11787 stream = qtdemux->streams[i];
11791 /* For other subtypes, we assume no significant impact on bitrate */
11797 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11801 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11803 if (sys_bitrate < sum_bitrate) {
11804 /* This can happen, since sum_bitrate might be derived from maximum
11805 * bitrates and not average bitrates */
11806 GST_DEBUG_OBJECT (qtdemux,
11807 "System bitrate less than sum bitrate - bailing");
11811 bitrate = sys_bitrate - sum_bitrate;
11812 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11813 ", Stream bitrate = %u", sys_bitrate, bitrate);
11815 if (!stream->stream_tags)
11816 stream->stream_tags = gst_tag_list_new_empty ();
11818 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11820 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11821 GST_TAG_BITRATE, bitrate, NULL);
11824 static GstFlowReturn
11825 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11828 GstFlowReturn ret = GST_FLOW_OK;
11830 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11832 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11833 QtDemuxStream *stream = qtdemux->streams[i];
11834 guint32 sample_num = 0;
11836 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11837 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11839 if (qtdemux->fragmented) {
11840 /* need all moov samples first */
11841 GST_OBJECT_LOCK (qtdemux);
11842 while (stream->n_samples == 0)
11843 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11845 GST_OBJECT_UNLOCK (qtdemux);
11847 /* discard any stray moof */
11848 qtdemux->moof_offset = 0;
11851 /* prepare braking */
11852 if (ret != GST_FLOW_ERROR)
11855 /* in pull mode, we should have parsed some sample info by now;
11856 * and quite some code will not handle no samples.
11857 * in push mode, we'll just have to deal with it */
11858 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11859 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11860 gst_qtdemux_remove_stream (qtdemux, i);
11865 /* parse the initial sample for use in setting the frame rate cap */
11866 while (sample_num == 0 && sample_num < stream->n_samples) {
11867 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11871 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11872 stream->first_duration = stream->samples[0].duration;
11873 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11874 stream->track_id, stream->first_duration);
11881 static GstFlowReturn
11882 qtdemux_expose_streams (GstQTDemux * qtdemux)
11885 GSList *oldpads = NULL;
11888 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11890 for (i = 0; i < qtdemux->n_streams; i++) {
11891 QtDemuxStream *stream = qtdemux->streams[i];
11892 GstPad *oldpad = stream->pad;
11895 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11896 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11898 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11899 stream->track_id == qtdemux->chapters_track_id) {
11900 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11901 so that it doesn't look like a subtitle track */
11902 gst_qtdemux_remove_stream (qtdemux, i);
11907 /* now we have all info and can expose */
11908 list = stream->stream_tags;
11909 stream->stream_tags = NULL;
11911 oldpads = g_slist_prepend (oldpads, oldpad);
11912 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11913 return GST_FLOW_ERROR;
11916 gst_qtdemux_guess_bitrate (qtdemux);
11918 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11920 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11921 GstPad *oldpad = iter->data;
11924 event = gst_event_new_eos ();
11925 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
11926 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11928 gst_pad_push_event (oldpad, event);
11929 gst_pad_set_active (oldpad, FALSE);
11930 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11931 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11932 gst_object_unref (oldpad);
11935 /* check if we should post a redirect in case there is a single trak
11936 * and it is a redirecting trak */
11937 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11940 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11941 "an external content");
11942 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11943 gst_structure_new ("redirect",
11944 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11946 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11947 qtdemux->posted_redirect = TRUE;
11950 for (i = 0; i < qtdemux->n_streams; i++) {
11951 QtDemuxStream *stream = qtdemux->streams[i];
11953 qtdemux_do_allocation (qtdemux, stream);
11956 qtdemux->exposed = TRUE;
11957 return GST_FLOW_OK;
11960 /* check if major or compatible brand is 3GP */
11961 static inline gboolean
11962 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11965 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11967 } else if (qtdemux->comp_brands != NULL) {
11971 gboolean res = FALSE;
11973 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11976 while (size >= 4) {
11977 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11982 gst_buffer_unmap (qtdemux->comp_brands, &map);
11989 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11990 static inline gboolean
11991 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11993 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11994 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11995 || fourcc == FOURCC_albm;
11999 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12000 const char *tag, const char *dummy, GNode * node)
12002 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12006 gdouble longitude, latitude, altitude;
12009 len = QT_UINT32 (node->data);
12016 /* TODO: language code skipped */
12018 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12021 /* do not alarm in trivial case, but bail out otherwise */
12022 if (*(data + offset) != 0) {
12023 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12027 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12028 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12029 offset += strlen (name);
12033 if (len < offset + 2 + 4 + 4 + 4)
12036 /* +1 +1 = skip null-terminator and location role byte */
12038 /* table in spec says unsigned, semantics say negative has meaning ... */
12039 longitude = QT_SFP32 (data + offset);
12042 latitude = QT_SFP32 (data + offset);
12045 altitude = QT_SFP32 (data + offset);
12047 /* one invalid means all are invalid */
12048 if (longitude >= -180.0 && longitude <= 180.0 &&
12049 latitude >= -90.0 && latitude <= 90.0) {
12050 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12051 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12052 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12053 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12056 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12063 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12070 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12071 const char *tag, const char *dummy, GNode * node)
12077 len = QT_UINT32 (node->data);
12081 y = QT_UINT16 ((guint8 *) node->data + 12);
12083 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12086 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12088 date = g_date_new_dmy (1, 1, y);
12089 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12090 g_date_free (date);
12094 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12095 const char *tag, const char *dummy, GNode * node)
12098 char *tag_str = NULL;
12103 len = QT_UINT32 (node->data);
12108 entity = (guint8 *) node->data + offset;
12109 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12110 GST_DEBUG_OBJECT (qtdemux,
12111 "classification info: %c%c%c%c invalid classification entity",
12112 entity[0], entity[1], entity[2], entity[3]);
12117 table = QT_UINT16 ((guint8 *) node->data + offset);
12119 /* Language code skipped */
12123 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12124 * XXXX: classification entity, fixed length 4 chars.
12125 * Y[YYYY]: classification table, max 5 chars.
12127 tag_str = g_strdup_printf ("----://%u/%s",
12128 table, (char *) node->data + offset);
12130 /* memcpy To be sure we're preserving byte order */
12131 memcpy (tag_str, entity, 4);
12132 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12134 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12143 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12149 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12150 const char *tag, const char *dummy, GNode * node)
12152 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12158 gboolean ret = TRUE;
12159 const gchar *charset = NULL;
12161 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12163 len = QT_UINT32 (data->data);
12164 type = QT_UINT32 ((guint8 *) data->data + 8);
12165 if (type == 0x00000001 && len > 16) {
12166 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12169 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12170 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12173 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12177 len = QT_UINT32 (node->data);
12178 type = QT_UINT32 ((guint8 *) node->data + 4);
12179 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12183 /* Type starts with the (C) symbol, so the next data is a list
12184 * of (string size(16), language code(16), string) */
12186 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12187 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12189 /* the string + fourcc + size + 2 16bit fields,
12190 * means that there are more tags in this atom */
12191 if (len > str_len + 8 + 4) {
12192 /* TODO how to represent the same tag in different languages? */
12193 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12194 "text alternatives, reading only first one");
12198 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12199 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12201 if (lang_code < 0x800) { /* MAC encoded string */
12204 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12205 QT_FOURCC ((guint8 *) node->data + 4))) {
12206 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12208 /* we go for 3GP style encoding if major brands claims so,
12209 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12210 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12211 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12212 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12214 /* 16-bit Language code is ignored here as well */
12215 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12222 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12223 ret = FALSE; /* may have to fallback */
12226 GError *err = NULL;
12228 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12229 charset, NULL, NULL, &err);
12231 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12232 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12234 g_error_free (err);
12237 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12238 len - offset, env_vars);
12241 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12242 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12246 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12253 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12254 const char *tag, const char *dummy, GNode * node)
12256 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12260 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12261 const char *tag, const char *dummy, GNode * node)
12263 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12265 char *s, *t, *k = NULL;
12270 /* first try normal string tag if major brand not 3GP */
12271 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12272 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12273 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12274 * let's try it 3gpp way after minor safety check */
12276 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12282 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12286 len = QT_UINT32 (data);
12290 count = QT_UINT8 (data + 14);
12292 for (; count; count--) {
12295 if (offset + 1 > len)
12297 slen = QT_UINT8 (data + offset);
12299 if (offset + slen > len)
12301 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12304 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12306 t = g_strjoin (",", k, s, NULL);
12314 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12321 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12322 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12331 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12337 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12338 const char *tag1, const char *tag2, GNode * node)
12345 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12347 len = QT_UINT32 (data->data);
12348 type = QT_UINT32 ((guint8 *) data->data + 8);
12349 if (type == 0x00000000 && len >= 22) {
12350 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12351 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12353 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12354 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12357 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12358 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12365 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12366 const char *tag1, const char *dummy, GNode * node)
12373 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12375 len = QT_UINT32 (data->data);
12376 type = QT_UINT32 ((guint8 *) data->data + 8);
12377 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12378 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12379 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12380 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12382 /* do not add bpm=0 */
12383 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12384 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12392 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12393 const char *tag1, const char *dummy, GNode * node)
12400 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12402 len = QT_UINT32 (data->data);
12403 type = QT_UINT32 ((guint8 *) data->data + 8);
12404 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12405 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12406 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12407 num = QT_UINT32 ((guint8 *) data->data + 16);
12409 /* do not add num=0 */
12410 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12411 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12418 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12419 const char *tag1, const char *dummy, GNode * node)
12426 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12428 len = QT_UINT32 (data->data);
12429 type = QT_UINT32 ((guint8 *) data->data + 8);
12430 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12431 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12432 GstTagImageType image_type;
12434 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12435 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12437 image_type = GST_TAG_IMAGE_TYPE_NONE;
12440 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12441 len - 16, image_type))) {
12442 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12443 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12444 gst_sample_unref (sample);
12451 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12452 const char *tag, const char *dummy, GNode * node)
12459 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12461 len = QT_UINT32 (data->data);
12462 type = QT_UINT32 ((guint8 *) data->data + 8);
12463 if (type == 0x00000001 && len > 16) {
12464 guint y, m = 1, d = 1;
12467 s = g_strndup ((char *) data->data + 16, len - 16);
12468 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12469 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12470 if (ret >= 1 && y > 1500 && y < 3000) {
12473 date = g_date_new_dmy (d, m, y);
12474 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12475 g_date_free (date);
12477 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12485 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12486 const char *tag, const char *dummy, GNode * node)
12490 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12492 /* re-route to normal string tag if major brand says so
12493 * or no data atom and compatible brand suggests so */
12494 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12495 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12496 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12501 guint len, type, n;
12503 len = QT_UINT32 (data->data);
12504 type = QT_UINT32 ((guint8 *) data->data + 8);
12505 if (type == 0x00000000 && len >= 18) {
12506 n = QT_UINT16 ((guint8 *) data->data + 16);
12508 const gchar *genre;
12510 genre = gst_tag_id3_genre_get (n - 1);
12511 if (genre != NULL) {
12512 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12513 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12521 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12522 const gchar * tag, guint8 * data, guint32 datasize)
12527 /* make a copy to have \0 at the end */
12528 datacopy = g_strndup ((gchar *) data, datasize);
12530 /* convert the str to double */
12531 if (sscanf (datacopy, "%lf", &value) == 1) {
12532 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12533 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12535 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12543 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12544 const char *tag, const char *tag_bis, GNode * node)
12553 const gchar *meanstr;
12554 const gchar *namestr;
12556 /* checking the whole ---- atom size for consistency */
12557 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12558 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12562 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12564 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12568 meansize = QT_UINT32 (mean->data);
12569 if (meansize <= 12) {
12570 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12573 meanstr = ((gchar *) mean->data) + 12;
12576 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12578 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12582 namesize = QT_UINT32 (name->data);
12583 if (namesize <= 12) {
12584 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12587 namestr = ((gchar *) name->data) + 12;
12595 * uint24 - data type
12599 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12601 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12604 datasize = QT_UINT32 (data->data);
12605 if (datasize <= 16) {
12606 GST_WARNING_OBJECT (demux, "Data atom too small");
12609 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12611 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12612 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12613 static const struct
12615 const gchar name[28];
12616 const gchar tag[28];
12619 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12620 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12621 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12622 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12623 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12624 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12625 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12626 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12630 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12631 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12632 switch (gst_tag_get_type (tags[i].tag)) {
12633 case G_TYPE_DOUBLE:
12634 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12635 ((guint8 *) data->data) + 16, datasize - 16);
12637 case G_TYPE_STRING:
12638 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12647 if (i == G_N_ELEMENTS (tags))
12657 #ifndef GST_DISABLE_GST_DEBUG
12659 gchar *namestr_dbg;
12660 gchar *meanstr_dbg;
12662 meanstr_dbg = g_strndup (meanstr, meansize);
12663 namestr_dbg = g_strndup (namestr, namesize);
12665 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12666 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12668 g_free (namestr_dbg);
12669 g_free (meanstr_dbg);
12676 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12677 const char *tag_bis, GNode * node)
12682 GstTagList *id32_taglist = NULL;
12684 GST_LOG_OBJECT (demux, "parsing ID32");
12687 len = GST_READ_UINT32_BE (data);
12689 /* need at least full box and language tag */
12693 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12694 gst_buffer_fill (buf, 0, data + 14, len - 14);
12696 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12697 if (id32_taglist) {
12698 GST_LOG_OBJECT (demux, "parsing ok");
12699 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12700 gst_tag_list_unref (id32_taglist);
12702 GST_LOG_OBJECT (demux, "parsing failed");
12705 gst_buffer_unref (buf);
12708 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12709 const char *tag, const char *tag_bis, GNode * node);
12712 FOURCC_pcst -> if media is a podcast -> bool
12713 FOURCC_cpil -> if media is part of a compilation -> bool
12714 FOURCC_pgap -> if media is part of a gapless context -> bool
12715 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12718 static const struct
12721 const gchar *gst_tag;
12722 const gchar *gst_tag_bis;
12723 const GstQTDemuxAddTagFunc func;
12726 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12727 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12728 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12729 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12730 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12731 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12732 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12733 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12734 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12735 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12736 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12737 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12738 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12739 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12740 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12741 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12742 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12743 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12744 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12745 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12746 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12747 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12748 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12749 qtdemux_tag_add_num}, {
12750 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12751 qtdemux_tag_add_num}, {
12752 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12753 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12754 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12755 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12756 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12757 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12758 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12759 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12760 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12761 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12762 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12763 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12764 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12765 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12766 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12767 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12768 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12769 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12770 qtdemux_tag_add_classification}, {
12771 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12772 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12773 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12775 /* This is a special case, some tags are stored in this
12776 * 'reverse dns naming', according to:
12777 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12780 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12781 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12782 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12785 struct _GstQtDemuxTagList
12788 GstTagList *taglist;
12790 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12793 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12799 const gchar *style;
12804 GstQTDemux *demux = qtdemuxtaglist->demux;
12805 GstTagList *taglist = qtdemuxtaglist->taglist;
12808 len = QT_UINT32 (data);
12809 buf = gst_buffer_new_and_alloc (len);
12810 gst_buffer_fill (buf, 0, data, len);
12812 /* heuristic to determine style of tag */
12813 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12814 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12816 else if (demux->major_brand == FOURCC_qt__)
12817 style = "quicktime";
12818 /* fall back to assuming iso/3gp tag style */
12822 /* santize the name for the caps. */
12823 for (i = 0; i < 4; i++) {
12824 guint8 d = data[4 + i];
12825 if (g_ascii_isalnum (d))
12826 ndata[i] = g_ascii_tolower (d);
12831 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12832 ndata[0], ndata[1], ndata[2], ndata[3]);
12833 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12835 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12836 sample = gst_sample_new (buf, NULL, NULL, s);
12837 gst_buffer_unref (buf);
12838 g_free (media_type);
12840 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12843 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12844 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12846 gst_sample_unref (sample);
12850 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12857 GstQtDemuxTagList demuxtaglist;
12859 demuxtaglist.demux = qtdemux;
12860 demuxtaglist.taglist = taglist;
12862 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12863 if (meta != NULL) {
12864 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12865 if (ilst == NULL) {
12866 GST_LOG_OBJECT (qtdemux, "no ilst");
12871 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12875 while (i < G_N_ELEMENTS (add_funcs)) {
12876 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12880 len = QT_UINT32 (node->data);
12882 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12883 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12885 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12886 add_funcs[i].gst_tag_bis, node);
12888 g_node_destroy (node);
12894 /* parsed nodes have been removed, pass along remainder as blob */
12895 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12896 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12898 /* parse up XMP_ node if existing */
12899 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12900 if (xmp_ != NULL) {
12902 GstTagList *xmptaglist;
12904 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12905 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12906 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12907 gst_buffer_unref (buf);
12909 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12911 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12917 GstStructure *structure; /* helper for sort function */
12919 guint min_req_bitrate;
12920 guint min_req_qt_version;
12924 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12926 GstQtReference *ref_a = (GstQtReference *) a;
12927 GstQtReference *ref_b = (GstQtReference *) b;
12929 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12930 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12932 /* known bitrates go before unknown; higher bitrates go first */
12933 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12936 /* sort the redirects and post a message for the application.
12939 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12941 GstQtReference *best;
12944 GValue list_val = { 0, };
12947 g_assert (references != NULL);
12949 references = g_list_sort (references, qtdemux_redirects_sort_func);
12951 best = (GstQtReference *) references->data;
12953 g_value_init (&list_val, GST_TYPE_LIST);
12955 for (l = references; l != NULL; l = l->next) {
12956 GstQtReference *ref = (GstQtReference *) l->data;
12957 GValue struct_val = { 0, };
12959 ref->structure = gst_structure_new ("redirect",
12960 "new-location", G_TYPE_STRING, ref->location, NULL);
12962 if (ref->min_req_bitrate > 0) {
12963 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12964 ref->min_req_bitrate, NULL);
12967 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12968 g_value_set_boxed (&struct_val, ref->structure);
12969 gst_value_list_append_value (&list_val, &struct_val);
12970 g_value_unset (&struct_val);
12971 /* don't free anything here yet, since we need best->structure below */
12974 g_assert (best != NULL);
12975 s = gst_structure_copy (best->structure);
12977 if (g_list_length (references) > 1) {
12978 gst_structure_set_value (s, "locations", &list_val);
12981 g_value_unset (&list_val);
12983 for (l = references; l != NULL; l = l->next) {
12984 GstQtReference *ref = (GstQtReference *) l->data;
12986 gst_structure_free (ref->structure);
12987 g_free (ref->location);
12990 g_list_free (references);
12992 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12993 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12994 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12995 qtdemux->posted_redirect = TRUE;
12998 /* look for redirect nodes, collect all redirect information and
13002 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13004 GNode *rmra, *rmda, *rdrf;
13006 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13008 GList *redirects = NULL;
13010 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13012 GstQtReference ref = { NULL, NULL, 0, 0 };
13013 GNode *rmdr, *rmvc;
13015 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13016 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13017 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13018 ref.min_req_bitrate);
13021 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13022 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13023 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13025 #ifndef GST_DISABLE_GST_DEBUG
13026 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13028 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13030 GST_LOG_OBJECT (qtdemux,
13031 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13032 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13033 bitmask, check_type);
13034 if (package == FOURCC_qtim && check_type == 0) {
13035 ref.min_req_qt_version = version;
13039 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13045 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13046 if (ref_len > 20) {
13047 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13048 ref_data = (guint8 *) rdrf->data + 20;
13049 if (ref_type == FOURCC_alis) {
13050 guint record_len, record_version, fn_len;
13052 if (ref_len > 70) {
13053 /* MacOSX alias record, google for alias-layout.txt */
13054 record_len = QT_UINT16 (ref_data + 4);
13055 record_version = QT_UINT16 (ref_data + 4 + 2);
13056 fn_len = QT_UINT8 (ref_data + 50);
13057 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13058 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13061 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13064 } else if (ref_type == FOURCC_url_) {
13065 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13067 GST_DEBUG_OBJECT (qtdemux,
13068 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13069 GST_FOURCC_ARGS (ref_type));
13071 if (ref.location != NULL) {
13072 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13074 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13076 GST_WARNING_OBJECT (qtdemux,
13077 "Failed to extract redirect location from rdrf atom");
13080 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13084 /* look for others */
13085 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13088 if (redirects != NULL) {
13089 qtdemux_process_redirects (qtdemux, redirects);
13095 static GstTagList *
13096 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13100 if (tags == NULL) {
13101 tags = gst_tag_list_new_empty ();
13102 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13105 if (qtdemux->major_brand == FOURCC_mjp2)
13106 fmt = "Motion JPEG 2000";
13107 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13109 else if (qtdemux->major_brand == FOURCC_qt__)
13111 else if (qtdemux->fragmented)
13114 fmt = "ISO MP4/M4A";
13116 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13117 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13119 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13125 /* we have read the complete moov node now.
13126 * This function parses all of the relevant info, creates the traks and
13127 * prepares all data structures for playback
13130 qtdemux_parse_tree (GstQTDemux * qtdemux)
13136 GstClockTime duration;
13138 guint64 creation_time;
13139 GstDateTime *datetime = NULL;
13142 /* make sure we have a usable taglist */
13143 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13145 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13146 if (mvhd == NULL) {
13147 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13148 return qtdemux_parse_redirects (qtdemux);
13151 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13152 if (version == 1) {
13153 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13154 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13155 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13156 } else if (version == 0) {
13157 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13158 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13159 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13161 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13165 /* Moving qt creation time (secs since 1904) to unix time */
13166 if (creation_time != 0) {
13167 /* Try to use epoch first as it should be faster and more commonly found */
13168 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13171 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13172 /* some data cleansing sanity */
13173 g_get_current_time (&now);
13174 if (now.tv_sec + 24 * 3600 < creation_time) {
13175 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13177 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13180 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13181 GDateTime *dt, *dt_local;
13183 dt = g_date_time_add_seconds (base_dt, creation_time);
13184 dt_local = g_date_time_to_local (dt);
13185 datetime = gst_date_time_new_from_g_date_time (dt_local);
13187 g_date_time_unref (base_dt);
13188 g_date_time_unref (dt);
13192 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13193 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13195 gst_date_time_unref (datetime);
13198 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13199 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13201 /* check for fragmented file and get some (default) data */
13202 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13205 GstByteReader mehd_data;
13207 /* let track parsing or anyone know weird stuff might happen ... */
13208 qtdemux->fragmented = TRUE;
13210 /* compensate for total duration */
13211 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13213 qtdemux_parse_mehd (qtdemux, &mehd_data);
13216 /* set duration in the segment info */
13217 gst_qtdemux_get_duration (qtdemux, &duration);
13219 qtdemux->segment.duration = duration;
13220 /* also do not exceed duration; stop is set that way post seek anyway,
13221 * and segment activation falls back to duration,
13222 * whereas loop only checks stop, so let's align this here as well */
13223 qtdemux->segment.stop = duration;
13226 /* parse all traks */
13227 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13229 qtdemux_parse_trak (qtdemux, trak);
13230 /* iterate all siblings */
13231 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13234 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13237 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13239 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13241 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13244 /* maybe also some tags in meta box */
13245 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13247 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13248 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13250 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13253 /* parse any protection system info */
13254 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13256 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13257 qtdemux_parse_pssh (qtdemux, pssh);
13258 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13261 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13266 /* taken from ffmpeg */
13268 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13280 len = (len << 7) | (c & 0x7f);
13288 /* this can change the codec originally present in @list */
13290 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13291 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13293 int len = QT_UINT32 (esds->data);
13294 guint8 *ptr = esds->data;
13295 guint8 *end = ptr + len;
13297 guint8 *data_ptr = NULL;
13299 guint8 object_type_id = 0;
13300 const char *codec_name = NULL;
13301 GstCaps *caps = NULL;
13303 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13305 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13307 while (ptr + 1 < end) {
13308 tag = QT_UINT8 (ptr);
13309 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13311 len = read_descr_size (ptr, end, &ptr);
13312 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13314 /* Check the stated amount of data is available for reading */
13315 if (len < 0 || ptr + len > end)
13319 case ES_DESCRIPTOR_TAG:
13320 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13321 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13324 case DECODER_CONFIG_DESC_TAG:{
13325 guint max_bitrate, avg_bitrate;
13327 object_type_id = QT_UINT8 (ptr);
13328 max_bitrate = QT_UINT32 (ptr + 5);
13329 avg_bitrate = QT_UINT32 (ptr + 9);
13330 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13331 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13332 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13333 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13334 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13335 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13336 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13337 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13339 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13340 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13341 avg_bitrate, NULL);
13346 case DECODER_SPECIFIC_INFO_TAG:
13347 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13348 if (object_type_id == 0xe0 && len == 0x40) {
13354 GST_DEBUG_OBJECT (qtdemux,
13355 "Have VOBSUB palette. Creating palette event");
13356 /* move to decConfigDescr data and read palette */
13358 for (i = 0; i < 16; i++) {
13359 clut[i] = QT_UINT32 (data);
13363 s = gst_structure_new ("application/x-gst-dvd", "event",
13364 G_TYPE_STRING, "dvd-spu-clut-change",
13365 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13366 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13367 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13368 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13369 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13370 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13371 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13372 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13375 /* store event and trigger custom processing */
13376 stream->pending_event =
13377 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13379 /* Generic codec_data handler puts it on the caps */
13386 case SL_CONFIG_DESC_TAG:
13387 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13391 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13393 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13399 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13400 * in use, and should also be used to override some other parameters for some
13402 switch (object_type_id) {
13403 case 0x20: /* MPEG-4 */
13404 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13405 * profile_and_level_indication */
13406 if (data_ptr != NULL && data_len >= 5 &&
13407 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13408 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13409 data_ptr + 4, data_len - 4);
13411 break; /* Nothing special needed here */
13412 case 0x21: /* H.264 */
13413 codec_name = "H.264 / AVC";
13414 caps = gst_caps_new_simple ("video/x-h264",
13415 "stream-format", G_TYPE_STRING, "avc",
13416 "alignment", G_TYPE_STRING, "au", NULL);
13418 case 0x40: /* AAC (any) */
13419 case 0x66: /* AAC Main */
13420 case 0x67: /* AAC LC */
13421 case 0x68: /* AAC SSR */
13422 /* Override channels and rate based on the codec_data, as it's often
13424 /* Only do so for basic setup without HE-AAC extension */
13425 if (data_ptr && data_len == 2) {
13426 guint channels, rate;
13428 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13430 entry->n_channels = channels;
13432 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13434 entry->rate = rate;
13437 /* Set level and profile if possible */
13438 if (data_ptr != NULL && data_len >= 2) {
13439 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13440 data_ptr, data_len);
13442 const gchar *profile_str = NULL;
13445 guint8 *codec_data;
13446 gint rate_idx, profile;
13448 /* No codec_data, let's invent something.
13449 * FIXME: This is wrong for SBR! */
13451 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13453 buffer = gst_buffer_new_and_alloc (2);
13454 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13455 codec_data = map.data;
13458 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13461 switch (object_type_id) {
13463 profile_str = "main";
13467 profile_str = "lc";
13471 profile_str = "ssr";
13479 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13481 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13483 gst_buffer_unmap (buffer, &map);
13484 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13485 GST_TYPE_BUFFER, buffer, NULL);
13486 gst_buffer_unref (buffer);
13489 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13490 G_TYPE_STRING, profile_str, NULL);
13494 case 0x60: /* MPEG-2, various profiles */
13500 codec_name = "MPEG-2 video";
13501 caps = gst_caps_new_simple ("video/mpeg",
13502 "mpegversion", G_TYPE_INT, 2,
13503 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13505 case 0x69: /* MPEG-2 BC audio */
13506 case 0x6B: /* MPEG-1 audio */
13507 caps = gst_caps_new_simple ("audio/mpeg",
13508 "mpegversion", G_TYPE_INT, 1, NULL);
13509 codec_name = "MPEG-1 audio";
13511 case 0x6A: /* MPEG-1 */
13512 codec_name = "MPEG-1 video";
13513 caps = gst_caps_new_simple ("video/mpeg",
13514 "mpegversion", G_TYPE_INT, 1,
13515 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13517 case 0x6C: /* MJPEG */
13519 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13521 codec_name = "Motion-JPEG";
13523 case 0x6D: /* PNG */
13525 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13527 codec_name = "PNG still images";
13529 case 0x6E: /* JPEG2000 */
13530 codec_name = "JPEG-2000";
13531 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13533 case 0xA4: /* Dirac */
13534 codec_name = "Dirac";
13535 caps = gst_caps_new_empty_simple ("video/x-dirac");
13537 case 0xA5: /* AC3 */
13538 codec_name = "AC-3 audio";
13539 caps = gst_caps_new_simple ("audio/x-ac3",
13540 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13542 case 0xA9: /* AC3 */
13543 codec_name = "DTS audio";
13544 caps = gst_caps_new_simple ("audio/x-dts",
13545 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13547 case 0xE1: /* QCELP */
13548 /* QCELP, the codec_data is a riff tag (little endian) with
13549 * 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). */
13550 caps = gst_caps_new_empty_simple ("audio/qcelp");
13551 codec_name = "QCELP";
13557 /* If we have a replacement caps, then change our caps for this stream */
13559 gst_caps_unref (entry->caps);
13560 entry->caps = caps;
13563 if (codec_name && list)
13564 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13565 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13567 /* Add the codec_data attribute to caps, if we have it */
13571 buffer = gst_buffer_new_and_alloc (data_len);
13572 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13574 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13575 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13577 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13579 gst_buffer_unref (buffer);
13584 static inline GstCaps *
13585 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13589 char *s, fourstr[5];
13591 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13592 for (i = 0; i < 4; i++) {
13593 if (!g_ascii_isalnum (fourstr[i]))
13596 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13597 caps = gst_caps_new_empty_simple (s);
13602 #define _codec(name) \
13604 if (codec_name) { \
13605 *codec_name = g_strdup (name); \
13610 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13611 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
13612 const guint8 * stsd_entry_data, gchar ** codec_name)
13614 GstCaps *caps = NULL;
13615 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13619 _codec ("PNG still images");
13620 caps = gst_caps_new_empty_simple ("image/png");
13623 _codec ("JPEG still images");
13625 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13628 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13629 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13630 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13631 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13632 _codec ("Motion-JPEG");
13634 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13637 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13638 _codec ("Motion-JPEG format B");
13639 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13642 _codec ("JPEG-2000");
13643 /* override to what it should be according to spec, avoid palette_data */
13644 entry->bits_per_sample = 24;
13645 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13648 _codec ("Sorensen video v.3");
13649 caps = gst_caps_new_simple ("video/x-svq",
13650 "svqversion", G_TYPE_INT, 3, NULL);
13652 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13653 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13654 _codec ("Sorensen video v.1");
13655 caps = gst_caps_new_simple ("video/x-svq",
13656 "svqversion", G_TYPE_INT, 1, NULL);
13658 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13659 caps = gst_caps_new_empty_simple ("video/x-raw");
13660 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13661 _codec ("Windows Raw RGB");
13662 stream->alignment = 32;
13668 bps = QT_UINT16 (stsd_entry_data + 82);
13671 format = GST_VIDEO_FORMAT_RGB15;
13674 format = GST_VIDEO_FORMAT_RGB16;
13677 format = GST_VIDEO_FORMAT_RGB;
13680 format = GST_VIDEO_FORMAT_ARGB;
13688 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13689 format = GST_VIDEO_FORMAT_I420;
13691 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13692 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13693 format = GST_VIDEO_FORMAT_I420;
13696 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13697 format = GST_VIDEO_FORMAT_UYVY;
13699 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13700 format = GST_VIDEO_FORMAT_v308;
13702 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13703 format = GST_VIDEO_FORMAT_v216;
13706 format = GST_VIDEO_FORMAT_v210;
13708 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13709 format = GST_VIDEO_FORMAT_r210;
13711 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13712 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13713 format = GST_VIDEO_FORMAT_v410;
13716 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13717 * but different order than AYUV
13718 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13719 format = GST_VIDEO_FORMAT_v408;
13722 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13723 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13724 _codec ("MPEG-1 video");
13725 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13726 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13728 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13729 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13730 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13731 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13732 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13733 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13734 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13735 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13736 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13737 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13738 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13739 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13740 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13741 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13742 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13743 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13744 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13745 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13746 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13747 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13748 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13749 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13750 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13751 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13752 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13753 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13754 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13755 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13756 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13757 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13758 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13759 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13760 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13761 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13762 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13763 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13764 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13765 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13766 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13767 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13768 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13769 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13770 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13771 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13772 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13773 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13774 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13775 _codec ("MPEG-2 video");
13776 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13777 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13779 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13780 _codec ("GIF still images");
13781 caps = gst_caps_new_empty_simple ("image/gif");
13784 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13786 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13788 /* ffmpeg uses the height/width props, don't know why */
13789 caps = gst_caps_new_simple ("video/x-h263",
13790 "variant", G_TYPE_STRING, "itu", NULL);
13794 _codec ("MPEG-4 video");
13795 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13796 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13798 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13799 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13800 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13801 caps = gst_caps_new_simple ("video/x-msmpeg",
13802 "msmpegversion", G_TYPE_INT, 43, NULL);
13804 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13806 caps = gst_caps_new_simple ("video/x-divx",
13807 "divxversion", G_TYPE_INT, 3, NULL);
13809 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13810 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13812 caps = gst_caps_new_simple ("video/x-divx",
13813 "divxversion", G_TYPE_INT, 4, NULL);
13815 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13817 caps = gst_caps_new_simple ("video/x-divx",
13818 "divxversion", G_TYPE_INT, 5, NULL);
13821 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13823 caps = gst_caps_new_simple ("video/x-ffv",
13824 "ffvversion", G_TYPE_INT, 1, NULL);
13827 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13828 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13833 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13834 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13835 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13839 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13840 _codec ("Cinepak");
13841 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13843 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13844 _codec ("Apple QuickDraw");
13845 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13847 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13848 _codec ("Apple video");
13849 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13853 _codec ("H.264 / AVC");
13854 caps = gst_caps_new_simple ("video/x-h264",
13855 "stream-format", G_TYPE_STRING, "avc",
13856 "alignment", G_TYPE_STRING, "au", NULL);
13859 _codec ("H.264 / AVC");
13860 caps = gst_caps_new_simple ("video/x-h264",
13861 "stream-format", G_TYPE_STRING, "avc3",
13862 "alignment", G_TYPE_STRING, "au", NULL);
13866 _codec ("H.265 / HEVC");
13867 caps = gst_caps_new_simple ("video/x-h265",
13868 "stream-format", G_TYPE_STRING, "hvc1",
13869 "alignment", G_TYPE_STRING, "au", NULL);
13872 _codec ("H.265 / HEVC");
13873 caps = gst_caps_new_simple ("video/x-h265",
13874 "stream-format", G_TYPE_STRING, "hev1",
13875 "alignment", G_TYPE_STRING, "au", NULL);
13878 _codec ("Run-length encoding");
13879 caps = gst_caps_new_simple ("video/x-rle",
13880 "layout", G_TYPE_STRING, "quicktime", NULL);
13883 _codec ("Run-length encoding");
13884 caps = gst_caps_new_simple ("video/x-rle",
13885 "layout", G_TYPE_STRING, "microsoft", NULL);
13887 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13888 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13889 _codec ("Indeo Video 3");
13890 caps = gst_caps_new_simple ("video/x-indeo",
13891 "indeoversion", G_TYPE_INT, 3, NULL);
13893 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13894 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13895 _codec ("Intel Video 4");
13896 caps = gst_caps_new_simple ("video/x-indeo",
13897 "indeoversion", G_TYPE_INT, 4, NULL);
13901 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13902 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13903 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13904 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13905 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13906 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13907 _codec ("DV Video");
13908 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13909 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13911 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13912 case FOURCC_dv5p: /* DVCPRO50 PAL */
13913 _codec ("DVCPro50 Video");
13914 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13915 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13917 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13918 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13919 _codec ("DVCProHD Video");
13920 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13921 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13923 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13924 _codec ("Apple Graphics (SMC)");
13925 caps = gst_caps_new_empty_simple ("video/x-smc");
13927 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13929 caps = gst_caps_new_empty_simple ("video/x-vp3");
13931 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13932 _codec ("VP6 Flash");
13933 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13937 caps = gst_caps_new_empty_simple ("video/x-theora");
13938 /* theora uses one byte of padding in the data stream because it does not
13939 * allow 0 sized packets while theora does */
13940 entry->padding = 1;
13944 caps = gst_caps_new_empty_simple ("video/x-dirac");
13946 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13947 _codec ("TIFF still images");
13948 caps = gst_caps_new_empty_simple ("image/tiff");
13950 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13951 _codec ("Apple Intermediate Codec");
13952 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13954 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13955 _codec ("AVID DNxHD");
13956 caps = gst_caps_from_string ("video/x-dnxhd");
13960 _codec ("On2 VP8");
13961 caps = gst_caps_from_string ("video/x-vp8");
13964 _codec ("Google VP9");
13965 caps = gst_caps_from_string ("video/x-vp9");
13968 _codec ("Apple ProRes LT");
13970 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13974 _codec ("Apple ProRes HQ");
13976 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13980 _codec ("Apple ProRes");
13982 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13986 _codec ("Apple ProRes Proxy");
13988 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13992 _codec ("Apple ProRes 4444");
13994 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13998 _codec ("Apple ProRes 4444 XQ");
14000 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14004 _codec ("GoPro CineForm");
14005 caps = gst_caps_from_string ("video/x-cineform");
14010 caps = gst_caps_new_simple ("video/x-wmv",
14011 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14013 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14016 caps = _get_unknown_codec_name ("video", fourcc);
14021 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14024 gst_video_info_init (&info);
14025 gst_video_info_set_format (&info, format, entry->width, entry->height);
14027 caps = gst_video_info_to_caps (&info);
14028 *codec_name = gst_pb_utils_get_codec_description (caps);
14030 /* enable clipping for raw video streams */
14031 stream->need_clip = TRUE;
14032 stream->alignment = 32;
14039 round_up_pow2 (guint n)
14051 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14052 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14053 int len, gchar ** codec_name)
14056 const GstStructure *s;
14059 GstAudioFormat format = 0;
14062 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14064 depth = entry->bytes_per_packet * 8;
14067 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14069 /* 8-bit audio is unsigned */
14071 format = GST_AUDIO_FORMAT_U8;
14072 /* otherwise it's signed and big-endian just like 'twos' */
14074 endian = G_BIG_ENDIAN;
14081 endian = G_LITTLE_ENDIAN;
14084 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14086 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14090 caps = gst_caps_new_simple ("audio/x-raw",
14091 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14092 "layout", G_TYPE_STRING, "interleaved", NULL);
14093 stream->alignment = GST_ROUND_UP_8 (depth);
14094 stream->alignment = round_up_pow2 (stream->alignment);
14097 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14098 _codec ("Raw 64-bit floating-point audio");
14099 caps = gst_caps_new_simple ("audio/x-raw",
14100 "format", G_TYPE_STRING, "F64BE",
14101 "layout", G_TYPE_STRING, "interleaved", NULL);
14102 stream->alignment = 8;
14104 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14105 _codec ("Raw 32-bit floating-point audio");
14106 caps = gst_caps_new_simple ("audio/x-raw",
14107 "format", G_TYPE_STRING, "F32BE",
14108 "layout", G_TYPE_STRING, "interleaved", NULL);
14109 stream->alignment = 4;
14112 _codec ("Raw 24-bit PCM audio");
14113 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14115 caps = gst_caps_new_simple ("audio/x-raw",
14116 "format", G_TYPE_STRING, "S24BE",
14117 "layout", G_TYPE_STRING, "interleaved", NULL);
14118 stream->alignment = 4;
14120 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14121 _codec ("Raw 32-bit PCM audio");
14122 caps = gst_caps_new_simple ("audio/x-raw",
14123 "format", G_TYPE_STRING, "S32BE",
14124 "layout", G_TYPE_STRING, "interleaved", NULL);
14125 stream->alignment = 4;
14127 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14128 _codec ("Raw 16-bit PCM audio");
14129 caps = gst_caps_new_simple ("audio/x-raw",
14130 "format", G_TYPE_STRING, "S16LE",
14131 "layout", G_TYPE_STRING, "interleaved", NULL);
14132 stream->alignment = 2;
14135 _codec ("Mu-law audio");
14136 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14139 _codec ("A-law audio");
14140 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14144 _codec ("Microsoft ADPCM");
14145 /* Microsoft ADPCM-ACM code 2 */
14146 caps = gst_caps_new_simple ("audio/x-adpcm",
14147 "layout", G_TYPE_STRING, "microsoft", NULL);
14151 _codec ("DVI/IMA ADPCM");
14152 caps = gst_caps_new_simple ("audio/x-adpcm",
14153 "layout", G_TYPE_STRING, "dvi", NULL);
14157 _codec ("DVI/Intel IMA ADPCM");
14158 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14159 caps = gst_caps_new_simple ("audio/x-adpcm",
14160 "layout", G_TYPE_STRING, "quicktime", NULL);
14164 /* MPEG layer 3, CBR only (pre QT4.1) */
14166 _codec ("MPEG-1 layer 3");
14167 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14168 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14169 "mpegversion", G_TYPE_INT, 1, NULL);
14171 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14172 _codec ("MPEG-1 layer 2");
14174 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14175 "mpegversion", G_TYPE_INT, 1, NULL);
14178 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14179 _codec ("EAC-3 audio");
14180 caps = gst_caps_new_simple ("audio/x-eac3",
14181 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14182 entry->sampled = TRUE;
14184 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14186 _codec ("AC-3 audio");
14187 caps = gst_caps_new_simple ("audio/x-ac3",
14188 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14189 entry->sampled = TRUE;
14191 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14192 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14193 _codec ("DTS audio");
14194 caps = gst_caps_new_simple ("audio/x-dts",
14195 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14196 entry->sampled = TRUE;
14198 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14199 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14200 _codec ("DTS-HD audio");
14201 caps = gst_caps_new_simple ("audio/x-dts",
14202 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14203 entry->sampled = TRUE;
14207 caps = gst_caps_new_simple ("audio/x-mace",
14208 "maceversion", G_TYPE_INT, 3, NULL);
14212 caps = gst_caps_new_simple ("audio/x-mace",
14213 "maceversion", G_TYPE_INT, 6, NULL);
14215 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14217 caps = gst_caps_new_empty_simple ("application/ogg");
14219 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14220 _codec ("DV audio");
14221 caps = gst_caps_new_empty_simple ("audio/x-dv");
14224 _codec ("MPEG-4 AAC audio");
14225 caps = gst_caps_new_simple ("audio/mpeg",
14226 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14227 "stream-format", G_TYPE_STRING, "raw", NULL);
14229 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14230 _codec ("QDesign Music");
14231 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14234 _codec ("QDesign Music v.2");
14235 /* FIXME: QDesign music version 2 (no constant) */
14236 if (FALSE && data) {
14237 caps = gst_caps_new_simple ("audio/x-qdm2",
14238 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14239 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14240 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14242 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14246 _codec ("GSM audio");
14247 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14250 _codec ("AMR audio");
14251 caps = gst_caps_new_empty_simple ("audio/AMR");
14254 _codec ("AMR-WB audio");
14255 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14258 _codec ("Quicktime IMA ADPCM");
14259 caps = gst_caps_new_simple ("audio/x-adpcm",
14260 "layout", G_TYPE_STRING, "quicktime", NULL);
14263 _codec ("Apple lossless audio");
14264 caps = gst_caps_new_empty_simple ("audio/x-alac");
14267 _codec ("Free Lossless Audio Codec");
14268 caps = gst_caps_new_simple ("audio/x-flac",
14269 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14271 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14272 _codec ("QualComm PureVoice");
14273 caps = gst_caps_from_string ("audio/qcelp");
14278 caps = gst_caps_new_empty_simple ("audio/x-wma");
14282 caps = gst_caps_new_empty_simple ("audio/x-opus");
14289 GstAudioFormat format;
14292 FLAG_IS_FLOAT = 0x1,
14293 FLAG_IS_BIG_ENDIAN = 0x2,
14294 FLAG_IS_SIGNED = 0x4,
14295 FLAG_IS_PACKED = 0x8,
14296 FLAG_IS_ALIGNED_HIGH = 0x10,
14297 FLAG_IS_NON_INTERLEAVED = 0x20
14299 _codec ("Raw LPCM audio");
14301 if (data && len >= 36) {
14302 depth = QT_UINT32 (data + 24);
14303 flags = QT_UINT32 (data + 28);
14304 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14306 if ((flags & FLAG_IS_FLOAT) == 0) {
14311 if ((flags & FLAG_IS_ALIGNED_HIGH))
14314 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14315 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14316 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14317 caps = gst_caps_new_simple ("audio/x-raw",
14318 "format", G_TYPE_STRING,
14320 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14321 "UNKNOWN", "layout", G_TYPE_STRING,
14322 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14323 "interleaved", NULL);
14324 stream->alignment = GST_ROUND_UP_8 (depth);
14325 stream->alignment = round_up_pow2 (stream->alignment);
14330 if (flags & FLAG_IS_BIG_ENDIAN)
14331 format = GST_AUDIO_FORMAT_F64BE;
14333 format = GST_AUDIO_FORMAT_F64LE;
14335 if (flags & FLAG_IS_BIG_ENDIAN)
14336 format = GST_AUDIO_FORMAT_F32BE;
14338 format = GST_AUDIO_FORMAT_F32LE;
14340 caps = gst_caps_new_simple ("audio/x-raw",
14341 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14342 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14343 "non-interleaved" : "interleaved", NULL);
14344 stream->alignment = width / 8;
14348 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14352 caps = _get_unknown_codec_name ("audio", fourcc);
14358 GstCaps *templ_caps =
14359 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14360 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14361 gst_caps_unref (caps);
14362 gst_caps_unref (templ_caps);
14363 caps = intersection;
14366 /* enable clipping for raw audio streams */
14367 s = gst_caps_get_structure (caps, 0);
14368 name = gst_structure_get_name (s);
14369 if (g_str_has_prefix (name, "audio/x-raw")) {
14370 stream->need_clip = TRUE;
14371 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14372 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14378 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14379 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14380 const guint8 * stsd_entry_data, gchar ** codec_name)
14384 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14388 _codec ("DVD subtitle");
14389 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14390 stream->need_process = TRUE;
14393 _codec ("Quicktime timed text");
14396 _codec ("3GPP timed text");
14398 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14400 /* actual text piece needs to be extracted */
14401 stream->need_process = TRUE;
14404 _codec ("XML subtitles");
14405 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14409 caps = _get_unknown_codec_name ("text", fourcc);
14417 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14418 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14419 const guint8 * stsd_entry_data, gchar ** codec_name)
14425 _codec ("MPEG 1 video");
14426 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14427 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14437 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14438 const gchar * system_id)
14442 if (!qtdemux->protection_system_ids)
14443 qtdemux->protection_system_ids =
14444 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14445 /* Check whether we already have an entry for this system ID. */
14446 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14447 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14448 if (g_ascii_strcasecmp (system_id, id) == 0) {
14452 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14453 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,